Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
simulator_riscv.cc
Go to the documentation of this file.
1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <setjmp.h> // NOLINT
6#include <stdlib.h>
7
8#include "vm/globals.h"
9#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
10
11// Only build the simulator if not compiling for real RISCV hardware.
12#if defined(USING_SIMULATOR)
13
14#include "vm/simulator.h"
15
17#include "vm/constants.h"
18#include "vm/image_snapshot.h"
19#include "vm/native_arguments.h"
20#include "vm/os_thread.h"
21#include "vm/stack_frame.h"
22
23namespace dart {
24
25DEFINE_FLAG(uint64_t,
26 trace_sim_after,
27 ULLONG_MAX,
28 "Trace simulator execution after instruction count reached.");
29DEFINE_FLAG(uint64_t,
30 stop_sim_at,
31 ULLONG_MAX,
32 "Instruction address or instruction count to stop simulator at.");
33
34// SimulatorSetjmpBuffer are linked together, and the last created one
35// is referenced by the Simulator. When an exception is thrown, the exception
36// runtime looks at where to jump and finds the corresponding
37// SimulatorSetjmpBuffer based on the stack pointer of the exception handler.
38// The runtime then does a Longjmp on that buffer to return to the simulator.
39class SimulatorSetjmpBuffer {
40 public:
41 void Longjmp() {
42 // "This" is now the last setjmp buffer.
43 simulator_->set_last_setjmp_buffer(this);
44 longjmp(buffer_, 1);
45 }
46
47 explicit SimulatorSetjmpBuffer(Simulator* sim) {
48 simulator_ = sim;
49 link_ = sim->last_setjmp_buffer();
50 sim->set_last_setjmp_buffer(this);
51 sp_ = static_cast<uword>(sim->get_register(SP));
52 }
53
54 ~SimulatorSetjmpBuffer() {
55 ASSERT(simulator_->last_setjmp_buffer() == this);
56 simulator_->set_last_setjmp_buffer(link_);
57 }
58
59 SimulatorSetjmpBuffer* link() { return link_; }
60
61 uword sp() { return sp_; }
62
63 private:
64 uword sp_;
65 Simulator* simulator_;
66 SimulatorSetjmpBuffer* link_;
67 jmp_buf buffer_;
68
69 friend class Simulator;
70};
71
72// When the generated code calls an external reference we need to catch that in
73// the simulator. The external reference will be a function compiled for the
74// host architecture. We need to call that function instead of trying to
75// execute it with the simulator. We do that by redirecting the external
76// reference to a svc (supervisor call) instruction that is handled by
77// the simulator. We write the original destination of the jump just at a known
78// offset from the svc instruction so the simulator knows what to call.
79class Redirection {
80 public:
81 uword address_of_ecall_instruction() {
82 return reinterpret_cast<uword>(&ecall_instruction_);
83 }
84
85 uword external_function() const { return external_function_; }
86
87 Simulator::CallKind call_kind() const { return call_kind_; }
88
89 int argument_count() const { return argument_count_; }
90
91 static Redirection* Get(uword external_function,
92 Simulator::CallKind call_kind,
93 int argument_count) {
94 MutexLocker ml(mutex_);
95
96 Redirection* old_head = list_.load(std::memory_order_relaxed);
97 for (Redirection* current = old_head; current != nullptr;
98 current = current->next_) {
99 if (current->external_function_ == external_function) return current;
100 }
101
102 Redirection* redirection =
103 new Redirection(external_function, call_kind, argument_count);
104 redirection->next_ = old_head;
105
106 // Use a memory fence to ensure all pending writes are written at the time
107 // of updating the list head, so the profiling thread always has a valid
108 // list to look at.
109 list_.store(redirection, std::memory_order_release);
110
111 return redirection;
112 }
113
114 static Redirection* FromECallInstruction(uintx_t ecall_instruction) {
115 char* addr_of_ecall = reinterpret_cast<char*>(ecall_instruction);
116 char* addr_of_redirection =
117 addr_of_ecall - OFFSET_OF(Redirection, ecall_instruction_);
118 return reinterpret_cast<Redirection*>(addr_of_redirection);
119 }
120
121 // Please note that this function is called by the signal handler of the
122 // profiling thread. It can therefore run at any point in time and is not
123 // allowed to hold any locks - which is precisely the reason why the list is
124 // prepend-only and a memory fence is used when writing the list head [list_]!
125 static uword FunctionForRedirect(uword address_of_ecall) {
126 for (Redirection* current = list_.load(std::memory_order_acquire);
127 current != nullptr; current = current->next_) {
128 if (current->address_of_ecall_instruction() == address_of_ecall) {
129 return current->external_function_;
130 }
131 }
132 return 0;
133 }
134
135 private:
136 Redirection(uword external_function,
137 Simulator::CallKind call_kind,
138 int argument_count)
139 : external_function_(external_function),
140 call_kind_(call_kind),
141 argument_count_(argument_count),
142 ecall_instruction_(Instr::kSimulatorRedirectInstruction),
143 next_(nullptr) {}
144
145 uword external_function_;
146 Simulator::CallKind call_kind_;
147 int argument_count_;
148 uint32_t ecall_instruction_;
149 Redirection* next_;
150 static std::atomic<Redirection*> list_;
151 static Mutex* mutex_;
152};
153
154std::atomic<Redirection*> Redirection::list_ = {nullptr};
155Mutex* Redirection::mutex_ = new Mutex();
156
158 CallKind call_kind,
159 int argument_count) {
160 Redirection* redirection =
161 Redirection::Get(function, call_kind, argument_count);
162 return redirection->address_of_ecall_instruction();
163}
164
166 return Redirection::FunctionForRedirect(redirect);
167}
168
169// Get the active Simulator for the current isolate.
170Simulator* Simulator::Current() {
171 Isolate* isolate = Isolate::Current();
172 Simulator* simulator = isolate->simulator();
173 if (simulator == nullptr) {
174 NoSafepointScope no_safepoint;
175 simulator = new Simulator();
176 isolate->set_simulator(simulator);
177 }
178 return simulator;
179}
180
181void Simulator::Init() {}
182
184 : pc_(0),
185 instret_(0),
186 reserved_address_(0),
187 reserved_value_(0),
188 fcsr_(0),
189 random_(),
190 last_setjmp_buffer_(nullptr) {
191 // Setup simulator support first. Some of this information is needed to
192 // setup the architecture state.
193 // We allocate the stack here, the size is computed as the sum of
194 // the size specified by the user and the buffer space needed for
195 // handling stack overflow exceptions. To be safe in potential
196 // stack underflows we also add some underflow buffer space.
197 stack_ =
198 new char[(OSThread::GetSpecifiedStackSize() +
199 OSThread::kStackSizeBufferMax + kSimulatorStackUnderflowSize)];
200 // Low address.
201 stack_limit_ = reinterpret_cast<uword>(stack_);
202 // Limit for StackOverflowError.
203 overflow_stack_limit_ = stack_limit_ + OSThread::kStackSizeBufferMax;
204 // High address.
205 stack_base_ = overflow_stack_limit_ + OSThread::GetSpecifiedStackSize();
206
207 // Setup architecture state.
208 xregs_[0] = 0;
209 for (intptr_t i = 1; i < kNumberOfCpuRegisters; i++) {
210 xregs_[i] = random_.NextUInt64();
211 }
212 for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
213 // TODO(riscv): This generates values that are very wide when printed,
214 // making it hard to read register state. Maybe generate random values in
215 // the unit interval instead?
216 // fregs_[i] = bit_cast<double>(random_.NextUInt64());
217 fregs_[i] = bit_cast<double>(kNaNBox);
218 }
219
220 // The sp is initialized to point to the bottom (high address) of the
221 // allocated stack area.
222 set_xreg(SP, stack_base());
223 // The lr and pc are initialized to a known bad value that will cause an
224 // access violation if the simulator ever tries to execute it.
225 set_xreg(RA, kBadLR);
226 pc_ = kBadLR;
227}
228
229Simulator::~Simulator() {
230 delete[] stack_;
231 Isolate* isolate = Isolate::Current();
232 if (isolate != nullptr) {
233 isolate->set_simulator(nullptr);
234 }
235}
236
237void Simulator::PrepareCall(PreservedRegisters* preserved) {
238#if defined(DEBUG)
239 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
240 preserved->xregs[i] = xregs_[i];
241 if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
242 xregs_[i] = random_.NextUInt64();
243 }
244 }
245 for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
246 preserved->fregs[i] = fregs_[i];
247 if ((kAbiVolatileFpuRegs & (1 << i)) != 0) {
248 // TODO(riscv): This generates values that are very wide when printed,
249 // making it hard to read register state. Maybe generate random values in
250 // the unit interval instead?
251 // fregs_[i] = bit_cast<double>(random_.NextUInt64());
252 fregs_[i] = bit_cast<double>(kNaNBox);
253 }
254 }
255#endif
256}
257
258void Simulator::ClobberVolatileRegisters() {
259#if defined(DEBUG)
260 reserved_address_ = reserved_value_ = 0; // Clear atomic reservation.
261 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
262 if ((kAbiVolatileCpuRegs & (1 << i)) != 0) {
263 xregs_[i] = random_.NextUInt64();
264 }
265 }
266 for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
267 if ((kAbiVolatileFpuRegs & (1 << i)) != 0) {
268 // TODO(riscv): This generates values that are very wide when printed,
269 // making it hard to read register state. Maybe generate random values in
270 // the unit interval instead?
271 // fregs_[i] = bit_cast<double>(random_.NextUInt64());
272 fregs_[i] = bit_cast<double>(kNaNBox);
273 }
274 }
275#endif
276}
277
278void Simulator::SavePreservedRegisters(PreservedRegisters* preserved) {
279#if defined(DEBUG)
280 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
281 preserved->xregs[i] = xregs_[i];
282 }
283 for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
284 preserved->fregs[i] = fregs_[i];
285 }
286#endif
287}
288
289void Simulator::CheckPreservedRegisters(PreservedRegisters* preserved) {
290#if defined(DEBUG)
291 if (preserved->xregs[SP] != xregs_[SP]) {
292 PrintRegisters();
293 PrintStack();
294 FATAL("Stack unbalanced");
295 }
296 const intptr_t kPreservedAtCall =
297 kAbiPreservedCpuRegs | (1 << TP) | (1 << GP) | (1 << SP) | (1 << FP);
298 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
299 if ((kPreservedAtCall & (1 << i)) != 0) {
300 if (preserved->xregs[i] != xregs_[i]) {
301 FATAL("%s was not preserved\n", cpu_reg_names[i]);
302 }
303 }
304 }
305 for (intptr_t i = 0; i < kNumberOfFpuRegisters; i++) {
306 if ((kAbiVolatileFpuRegs & (1 << i)) == 0) {
307 if (bit_cast<uint64_t>(preserved->fregs[i]) !=
308 bit_cast<uint64_t>(fregs_[i])) {
309 FATAL("%s was not preserved\n", fpu_reg_names[i]);
310 }
311 }
312 }
313#endif
314}
315
316void Simulator::RunCall(intx_t entry, PreservedRegisters* preserved) {
317 pc_ = entry;
318 set_xreg(RA, kEndSimulatingPC);
319 Execute();
320 CheckPreservedRegisters(preserved);
321}
322
323int64_t Simulator::Call(intx_t entry,
324 intx_t parameter0,
325 intx_t parameter1,
326 intx_t parameter2,
327 intx_t parameter3,
328 bool fp_return,
329 bool fp_args) {
330 // Save the SP register before the call so we can restore it.
331 const intptr_t sp_before_call = get_xreg(SP);
332
333 // Setup parameters.
334 if (fp_args) {
335 set_fregd(FA0, parameter0);
336 set_fregd(FA1, parameter1);
337 set_fregd(FA2, parameter2);
338 set_fregd(FA3, parameter3);
339 } else {
340 set_xreg(A0, parameter0);
341 set_xreg(A1, parameter1);
342 set_xreg(A2, parameter2);
343 set_xreg(A3, parameter3);
344 }
345
346 // Make sure the activation frames are properly aligned.
347 intptr_t stack_pointer = sp_before_call;
348 if (OS::ActivationFrameAlignment() > 1) {
349 stack_pointer =
350 Utils::RoundDown(stack_pointer, OS::ActivationFrameAlignment());
351 }
352 set_xreg(SP, stack_pointer);
353
354 // Prepare to execute the code at entry.
355 pc_ = entry;
356 // Put down marker for end of simulation. The simulator will stop simulation
357 // when the PC reaches this value. By saving the "end simulation" value into
358 // the LR the simulation stops when returning to this call point.
359 set_xreg(RA, kEndSimulatingPC);
360
361 // Remember the values of callee-saved registers, and set them up with a
362 // known value so that we are able to check that they are preserved
363 // properly across Dart execution.
364 PreservedRegisters preserved;
365 SavePreservedRegisters(&preserved);
366
367 // Start the simulation.
368 Execute();
369
370 // Check that the callee-saved registers have been preserved,
371 // and restore them with the original value.
372 CheckPreservedRegisters(&preserved);
373
374 // Restore the SP register and return R0.
375 set_xreg(SP, sp_before_call);
376 int64_t return_value;
377 if (fp_return) {
378 return_value = get_fregd(FA0);
379 } else {
380 return_value = get_xreg(A0);
381 }
382 return return_value;
383}
384
385void Simulator::Execute() {
386 if (LIKELY(FLAG_trace_sim_after == ULLONG_MAX)) {
387 ExecuteNoTrace();
388 } else {
389 ExecuteTrace();
390 }
391}
392
393void Simulator::ExecuteNoTrace() {
394 while (pc_ != kEndSimulatingPC) {
395 uint16_t parcel = *reinterpret_cast<uint16_t*>(pc_);
396 if (IsCInstruction(parcel)) {
397 CInstr instr(parcel);
398 Interpret(instr);
399 } else {
400 Instr instr(LoadUnaligned(reinterpret_cast<uint32_t*>(pc_)));
401 Interpret(instr);
402 }
403 instret_++;
404 }
405}
406
407void Simulator::ExecuteTrace() {
408 while (pc_ != kEndSimulatingPC) {
409 uint16_t parcel = *reinterpret_cast<uint16_t*>(pc_);
410 if (IsCInstruction(parcel)) {
411 CInstr instr(parcel);
412 if (IsTracingExecution()) {
413 Disassembler::Disassemble(pc_, pc_ + instr.length());
414 }
415 Interpret(instr);
416 } else {
417 Instr instr(LoadUnaligned(reinterpret_cast<uint32_t*>(pc_)));
418 if (IsTracingExecution()) {
419 Disassembler::Disassemble(pc_, pc_ + instr.length());
420 }
421 Interpret(instr);
422 }
423 instret_++;
424 }
425}
426
427bool Simulator::IsTracingExecution() const {
428 return instret_ > FLAG_trace_sim_after;
429}
430
431void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
432 // Walk over all setjmp buffers (simulated --> C++ transitions)
433 // and try to find the setjmp associated with the simulated stack pointer.
434 SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
435 while (buf->link() != nullptr && buf->link()->sp() <= sp) {
436 buf = buf->link();
437 }
438 ASSERT(buf != nullptr);
439
440 // The C++ caller has not cleaned up the stack memory of C++ frames.
441 // Prepare for unwinding frames by destroying all the stack resources
442 // in the previous C++ frames.
443 StackResource::Unwind(thread);
444
445 // Keep the following code in sync with `StubCode::JumpToFrameStub()`.
446
447 // Unwind the C++ stack and continue simulation in the target frame.
448 pc_ = pc;
449 set_xreg(SP, static_cast<uintx_t>(sp));
450 set_xreg(FP, static_cast<uintx_t>(fp));
451 set_xreg(THR, reinterpret_cast<uintx_t>(thread));
452#if defined(DART_TARGET_OS_FUCHSIA) || defined(DART_TARGET_OS_ANDROID)
453 set_xreg(GP, thread->saved_shadow_call_stack());
454#endif
455 // Set the tag.
456 thread->set_vm_tag(VMTag::kDartTagId);
457 // Clear top exit frame.
458 thread->set_top_exit_frame_info(0);
459 // Restore pool pointer.
460 uintx_t code =
461 *reinterpret_cast<uintx_t*>(fp + kPcMarkerSlotFromFp * kWordSize);
462 uintx_t pp = FLAG_precompiled_mode
463 ? static_cast<uintx_t>(thread->global_object_pool())
464 : *reinterpret_cast<uintx_t*>(
465 code + Code::object_pool_offset() - kHeapObjectTag);
466 pp -= kHeapObjectTag; // In the PP register, the pool pointer is untagged.
467 set_xreg(CODE_REG, code);
468 set_xreg(PP, pp);
469 set_xreg(WRITE_BARRIER_STATE,
470 thread->write_barrier_mask() ^
471 ((UntaggedObject::kGenerationalBarrierMask << 1) - 1));
472 set_xreg(NULL_REG, static_cast<uintx_t>(Object::null()));
473 if (FLAG_precompiled_mode) {
474 set_xreg(DISPATCH_TABLE_REG,
475 reinterpret_cast<uintx_t>(thread->dispatch_table_array()));
476 }
477
478 buf->Longjmp();
479}
480
481void Simulator::PrintRegisters() {
482 ASSERT(static_cast<intptr_t>(kNumberOfCpuRegisters) ==
483 static_cast<intptr_t>(kNumberOfFpuRegisters));
484 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) {
485#if XLEN == 32
486 OS::Print("%4s: %8x %11d", cpu_reg_names[i], xregs_[i], xregs_[i]);
487#elif XLEN == 64
488 OS::Print("%4s: %16" Px64 " %20" Pd64, cpu_reg_names[i], xregs_[i],
489 xregs_[i]);
490#endif
491 OS::Print(" %4s: %lf\n", fpu_reg_names[i], fregs_[i]);
492 }
493#if XLEN == 32
494 OS::Print(" pc: %8x\n", pc_);
495#elif XLEN == 64
496 OS::Print(" pc: %16" Px64 "\n", pc_);
497#endif
498}
499
500void Simulator::PrintStack() {
501 StackFrameIterator frames(get_register(FP), get_register(SP), get_pc(),
502 ValidationPolicy::kDontValidateFrames,
503 Thread::Current(),
504 StackFrameIterator::kNoCrossThreadIteration);
505 StackFrame* frame = frames.NextFrame();
506 while (frame != nullptr) {
507 OS::PrintErr("%s\n", frame->ToCString());
508 frame = frames.NextFrame();
509 }
510}
511
512DART_FORCE_INLINE
513void Simulator::Interpret(Instr instr) {
514 switch (instr.opcode()) {
515 case LUI:
516 InterpretLUI(instr);
517 break;
518 case AUIPC:
519 InterpretAUIPC(instr);
520 break;
521 case JAL:
522 InterpretJAL(instr);
523 break;
524 case JALR:
525 InterpretJALR(instr);
526 break;
527 case BRANCH:
528 InterpretBRANCH(instr);
529 break;
530 case LOAD:
531 InterpretLOAD(instr);
532 break;
533 case STORE:
534 InterpretSTORE(instr);
535 break;
536 case OPIMM:
537 InterpretOPIMM(instr);
538 break;
539 case OPIMM32:
540 InterpretOPIMM32(instr);
541 break;
542 case OP:
543 InterpretOP(instr);
544 break;
545 case OP32:
546 InterpretOP32(instr);
547 break;
548 case MISCMEM:
549 InterpretMISCMEM(instr);
550 break;
551 case SYSTEM:
552 InterpretSYSTEM(instr);
553 break;
554 case AMO:
555 InterpretAMO(instr);
556 break;
557 case LOADFP:
558 InterpretLOADFP(instr);
559 break;
560 case STOREFP:
561 InterpretSTOREFP(instr);
562 break;
563 case FMADD:
564 InterpretFMADD(instr);
565 break;
566 case FMSUB:
567 InterpretFMSUB(instr);
568 break;
569 case FNMADD:
570 InterpretFNMADD(instr);
571 break;
572 case FNMSUB:
573 InterpretFNMSUB(instr);
574 break;
575 case OPFP:
576 InterpretOPFP(instr);
577 break;
578 default:
579 IllegalInstruction(instr);
580 }
581}
582
583DART_FORCE_INLINE
584void Simulator::Interpret(CInstr instr) {
585 switch (instr.opcode()) {
586 case C_LWSP: {
587 uintx_t addr = get_xreg(SP) + instr.spload4_imm();
588 set_xreg(instr.rd(), MemoryRead<int32_t>(addr, SP));
589 break;
590 }
591#if XLEN == 32
592 case C_FLWSP: {
593 uintx_t addr = get_xreg(SP) + instr.spload4_imm();
594 set_fregs(instr.frd(), MemoryRead<float>(addr, SP));
595 break;
596 }
597#else
598 case C_LDSP: {
599 uintx_t addr = get_xreg(SP) + instr.spload8_imm();
600 set_xreg(instr.rd(), MemoryRead<int64_t>(addr, SP));
601 break;
602 }
603#endif
604 case C_FLDSP: {
605 uintx_t addr = get_xreg(SP) + instr.spload8_imm();
606 set_fregd(instr.frd(), MemoryRead<double>(addr, SP));
607 break;
608 }
609 case C_SWSP: {
610 uintx_t addr = get_xreg(SP) + instr.spstore4_imm();
611 MemoryWrite<uint32_t>(addr, get_xreg(instr.rs2()), SP);
612 break;
613 }
614#if XLEN == 32
615 case C_FSWSP: {
616 uintx_t addr = get_xreg(SP) + instr.spstore4_imm();
617 MemoryWrite<float>(addr, get_fregs(instr.frs2()), SP);
618 break;
619 }
620#else
621 case C_SDSP: {
622 uintx_t addr = get_xreg(SP) + instr.spstore8_imm();
623 MemoryWrite<uint64_t>(addr, get_xreg(instr.rs2()), SP);
624 break;
625 }
626#endif
627 case C_FSDSP: {
628 uintx_t addr = get_xreg(SP) + instr.spstore8_imm();
629 MemoryWrite<double>(addr, get_fregd(instr.frs2()), SP);
630 break;
631 }
632 case C_LW: {
633 uintx_t addr = get_xreg(instr.rs1p()) + instr.mem4_imm();
634 set_xreg(instr.rdp(), MemoryRead<int32_t>(addr, instr.rs1p()));
635 break;
636 }
637#if XLEN == 32
638 case C_FLW: {
639 uintx_t addr = get_xreg(instr.rs1p()) + instr.mem4_imm();
640 set_fregs(instr.frdp(), MemoryRead<float>(addr, instr.rs1p()));
641 break;
642 }
643#else
644 case C_LD: {
645 uintx_t addr = get_xreg(instr.rs1p()) + instr.mem8_imm();
646 set_xreg(instr.rdp(), MemoryRead<int64_t>(addr, instr.rs1p()));
647 break;
648 }
649#endif
650 case C_FLD: {
651 uintx_t addr = get_xreg(instr.rs1p()) + instr.mem8_imm();
652 set_fregd(instr.frdp(), MemoryRead<double>(addr, instr.rs1p()));
653 break;
654 }
655 case C_SW: {
656 uintx_t addr = get_xreg(instr.rs1p()) + instr.mem4_imm();
657 MemoryWrite<uint32_t>(addr, get_xreg(instr.rs2p()), instr.rs1p());
658 break;
659 }
660#if XLEN == 32
661 case C_FSW: {
662 uintx_t addr = get_xreg(instr.rs1p()) + instr.mem4_imm();
663 MemoryWrite<float>(addr, get_fregs(instr.frs2p()), instr.rs1p());
664 break;
665 }
666#else
667 case C_SD: {
668 uintx_t addr = get_xreg(instr.rs1p()) + instr.mem8_imm();
669 MemoryWrite<uint64_t>(addr, get_xreg(instr.rs2p()), instr.rs1p());
670 break;
671 }
672#endif
673 case C_FSD: {
674 uintx_t addr = get_xreg(instr.rs1p()) + instr.mem8_imm();
675 MemoryWrite<double>(addr, get_fregd(instr.frs2p()), instr.rs1p());
676 break;
677 }
678 case C_J: {
679 pc_ += sign_extend((int32_t)instr.j_imm());
680 return;
681 }
682#if XLEN == 32
683 case C_JAL: {
684 set_xreg(RA, pc_ + instr.length());
685 pc_ += sign_extend((int32_t)instr.j_imm());
686 return;
687 }
688#endif
689 case C_JR: {
690 if ((instr.encoding() & (C_JALR ^ C_JR)) != 0) {
691 if ((instr.rs1() == ZR) && (instr.rs2() == ZR)) {
692 InterpretEBREAK(instr);
693 } else if (instr.rs2() == ZR) {
694 // JALR
695 uintx_t target = get_xreg(instr.rs1());
696 set_xreg(RA, pc_ + instr.length());
697 pc_ = target;
698 return;
699 } else {
700 // ADD
701 set_xreg(instr.rd(), get_xreg(instr.rs1()) + get_xreg(instr.rs2()));
702 }
703 } else {
704 if ((instr.rd() != ZR) && (instr.rs2() != ZR)) {
705 // MV
706 set_xreg(instr.rd(), get_xreg(instr.rs2()));
707 } else if (instr.rs2() != ZR) {
708 IllegalInstruction(instr);
709 } else {
710 // JR
711 pc_ = get_xreg(instr.rs1());
712 return;
713 }
714 }
715 break;
716 }
717 case C_BEQZ:
718 if (get_xreg(instr.rs1p()) == 0) {
719 pc_ += instr.b_imm();
720 return;
721 }
722 break;
723 case C_BNEZ:
724 if (get_xreg(instr.rs1p()) != 0) {
725 pc_ += instr.b_imm();
726 return;
727 }
728 break;
729 case C_LI:
730 if (instr.rd() == ZR) {
731 IllegalInstruction(instr);
732 } else {
733 set_xreg(instr.rd(), sign_extend(instr.i_imm()));
734 }
735 break;
736 case C_LUI:
737 if (instr.rd() == SP) {
738 if (instr.i16_imm() == 0) {
739 IllegalInstruction(instr);
740 } else {
741 set_xreg(instr.rd(),
742 get_xreg(instr.rs1()) + sign_extend(instr.i16_imm()));
743 }
744 } else if ((instr.rd() == ZR) || (instr.u_imm() == 0)) {
745 IllegalInstruction(instr);
746 } else {
747 set_xreg(instr.rd(), sign_extend(instr.u_imm()));
748 }
749 break;
750 case C_ADDI:
751 set_xreg(instr.rd(), get_xreg(instr.rs1()) + instr.i_imm());
752 break;
753#if XLEN >= 64
754 case C_ADDIW: {
755 uint32_t a = get_xreg(instr.rs1());
756 uint32_t b = instr.i_imm();
757 set_xreg(instr.rd(), sign_extend(a + b));
758 break;
759 }
760#endif // XLEN >= 64
761 case C_ADDI4SPN:
762 if (instr.i4spn_imm() == 0) {
763 IllegalInstruction(instr);
764 } else {
765 set_xreg(instr.rdp(), get_xreg(SP) + instr.i4spn_imm());
766 }
767 break;
768 case C_SLLI:
769 if (instr.i_imm() == 0) {
770 IllegalInstruction(instr);
771 } else {
772 set_xreg(instr.rd(), get_xreg(instr.rs1())
773 << (instr.i_imm() & (XLEN - 1)));
774 }
775 break;
776 case C_MISCALU:
777 // Note MISCALU has a different notion of rsd′ than other instructions,
778 // so use rs1′ instead.
779 switch (instr.encoding() & C_MISCALU_MASK) {
780 case C_SRLI:
781 if (instr.i_imm() == 0) {
782 IllegalInstruction(instr);
783 } else {
784 set_xreg(instr.rs1p(),
785 get_xreg(instr.rs1p()) >> (instr.i_imm() & (XLEN - 1)));
786 }
787 break;
788 case C_SRAI:
789 if (instr.i_imm() == 0) {
790 IllegalInstruction(instr);
791 } else {
792 set_xreg(instr.rs1p(),
793 static_cast<intx_t>(get_xreg(instr.rs1p())) >>
794 (instr.i_imm() & (XLEN - 1)));
795 }
796 break;
797 case C_ANDI:
798 set_xreg(instr.rs1p(), get_xreg(instr.rs1p()) & instr.i_imm());
799 break;
800 case C_RR:
801 switch (instr.encoding() & C_RR_MASK) {
802 case C_AND:
803 set_xreg(instr.rs1p(),
804 get_xreg(instr.rs1p()) & get_xreg(instr.rs2p()));
805 break;
806 case C_OR:
807 set_xreg(instr.rs1p(),
808 get_xreg(instr.rs1p()) | get_xreg(instr.rs2p()));
809 break;
810 case C_XOR:
811 set_xreg(instr.rs1p(),
812 get_xreg(instr.rs1p()) ^ get_xreg(instr.rs2p()));
813 break;
814 case C_SUB:
815 set_xreg(instr.rs1p(),
816 get_xreg(instr.rs1p()) - get_xreg(instr.rs2p()));
817 break;
818 case C_ADDW: {
819 uint32_t a = get_xreg(instr.rs1p());
820 uint32_t b = get_xreg(instr.rs2p());
821 set_xreg(instr.rs1p(), sign_extend(a + b));
822 break;
823 }
824 case C_SUBW: {
825 uint32_t a = get_xreg(instr.rs1p());
826 uint32_t b = get_xreg(instr.rs2p());
827 set_xreg(instr.rs1p(), sign_extend(a - b));
828 break;
829 }
830 default:
831 IllegalInstruction(instr);
832 }
833 break;
834 default:
835 IllegalInstruction(instr);
836 }
837 break;
838 default:
839 IllegalInstruction(instr);
840 }
841 pc_ += instr.length();
842}
843
844DART_FORCE_INLINE
845void Simulator::InterpretLUI(Instr instr) {
846 set_xreg(instr.rd(), sign_extend(instr.utype_imm()));
847 pc_ += instr.length();
848}
849
850DART_FORCE_INLINE
851void Simulator::InterpretAUIPC(Instr instr) {
852 set_xreg(instr.rd(), pc_ + sign_extend(instr.utype_imm()));
853 pc_ += instr.length();
854}
855
856DART_FORCE_INLINE
857void Simulator::InterpretJAL(Instr instr) {
858 set_xreg(instr.rd(), pc_ + instr.length());
859 pc_ += sign_extend(instr.jtype_imm());
860}
861
862DART_FORCE_INLINE
863void Simulator::InterpretJALR(Instr instr) {
864 uintx_t base = get_xreg(instr.rs1());
865 uintx_t offset = static_cast<uintx_t>(instr.itype_imm());
866 set_xreg(instr.rd(), pc_ + instr.length());
867 pc_ = base + offset;
868}
869
870DART_FORCE_INLINE
871void Simulator::InterpretBRANCH(Instr instr) {
872 switch (instr.funct3()) {
873 case BEQ:
874 if (get_xreg(instr.rs1()) == get_xreg(instr.rs2())) {
875 pc_ += instr.btype_imm();
876 } else {
877 pc_ += instr.length();
878 }
879 break;
880 case BNE:
881 if (get_xreg(instr.rs1()) != get_xreg(instr.rs2())) {
882 pc_ += instr.btype_imm();
883 } else {
884 pc_ += instr.length();
885 }
886 break;
887 case BLT:
888 if (static_cast<intx_t>(get_xreg(instr.rs1())) <
889 static_cast<intx_t>(get_xreg(instr.rs2()))) {
890 pc_ += instr.btype_imm();
891 } else {
892 pc_ += instr.length();
893 }
894 break;
895 case BGE:
896 if (static_cast<intx_t>(get_xreg(instr.rs1())) >=
897 static_cast<intx_t>(get_xreg(instr.rs2()))) {
898 pc_ += instr.btype_imm();
899 } else {
900 pc_ += instr.length();
901 }
902 break;
903 case BLTU:
904 if (static_cast<uintx_t>(get_xreg(instr.rs1())) <
905 static_cast<uintx_t>(get_xreg(instr.rs2()))) {
906 pc_ += instr.btype_imm();
907 } else {
908 pc_ += instr.length();
909 }
910 break;
911 case BGEU:
912 if (static_cast<uintx_t>(get_xreg(instr.rs1())) >=
913 static_cast<uintx_t>(get_xreg(instr.rs2()))) {
914 pc_ += instr.btype_imm();
915 } else {
916 pc_ += instr.length();
917 }
918 break;
919 default:
920 IllegalInstruction(instr);
921 }
922}
923
924DART_FORCE_INLINE
925void Simulator::InterpretLOAD(Instr instr) {
926 uintx_t addr = get_xreg(instr.rs1()) + instr.itype_imm();
927 switch (instr.funct3()) {
928 case LB:
929 set_xreg(instr.rd(), MemoryRead<int8_t>(addr, instr.rs1()));
930 break;
931 case LH:
932 set_xreg(instr.rd(), MemoryRead<int16_t>(addr, instr.rs1()));
933 break;
934 case LW:
935 set_xreg(instr.rd(), MemoryRead<int32_t>(addr, instr.rs1()));
936 break;
937 case LBU:
938 set_xreg(instr.rd(), MemoryRead<uint8_t>(addr, instr.rs1()));
939 break;
940 case LHU:
941 set_xreg(instr.rd(), MemoryRead<uint16_t>(addr, instr.rs1()));
942 break;
943#if XLEN >= 64
944 case LWU:
945 set_xreg(instr.rd(), MemoryRead<uint32_t>(addr, instr.rs1()));
946 break;
947 case LD:
948 set_xreg(instr.rd(), MemoryRead<int64_t>(addr, instr.rs1()));
949 break;
950#endif // XLEN >= 64
951 default:
952 IllegalInstruction(instr);
953 }
954 pc_ += instr.length();
955}
956
957DART_FORCE_INLINE
958void Simulator::InterpretLOADFP(Instr instr) {
959 uintx_t addr = get_xreg(instr.rs1()) + instr.itype_imm();
960 switch (instr.funct3()) {
961 case S:
962 set_fregs(instr.frd(), MemoryRead<float>(addr, instr.rs1()));
963 break;
964 case D:
965 set_fregd(instr.frd(), MemoryRead<double>(addr, instr.rs1()));
966 break;
967 default:
968 IllegalInstruction(instr);
969 }
970 pc_ += instr.length();
971}
972
973DART_FORCE_INLINE
974void Simulator::InterpretSTORE(Instr instr) {
975 uintx_t addr = get_xreg(instr.rs1()) + instr.stype_imm();
976 switch (instr.funct3()) {
977 case SB:
978 MemoryWrite<uint8_t>(addr, get_xreg(instr.rs2()), instr.rs1());
979 break;
980 case SH:
981 MemoryWrite<uint16_t>(addr, get_xreg(instr.rs2()), instr.rs1());
982 break;
983 case SW:
984 MemoryWrite<uint32_t>(addr, get_xreg(instr.rs2()), instr.rs1());
985 break;
986#if XLEN >= 64
987 case SD:
988 MemoryWrite<uint64_t>(addr, get_xreg(instr.rs2()), instr.rs1());
989 break;
990#endif // XLEN >= 64
991 default:
992 IllegalInstruction(instr);
993 }
994 pc_ += instr.length();
995}
996
997DART_FORCE_INLINE
998void Simulator::InterpretSTOREFP(Instr instr) {
999 uintx_t addr = get_xreg(instr.rs1()) + instr.stype_imm();
1000 switch (instr.funct3()) {
1001 case S:
1002 MemoryWrite<float>(addr, get_fregs(instr.frs2()), instr.rs1());
1003 break;
1004 case D:
1005 MemoryWrite<double>(addr, get_fregd(instr.frs2()), instr.rs1());
1006 break;
1007 default:
1008 IllegalInstruction(instr);
1009 }
1010 pc_ += instr.length();
1011}
1012
1013static uintx_t clz(uintx_t a) {
1014 for (int bit = XLEN - 1; bit >= 0; bit--) {
1015 if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
1016 return XLEN - bit - 1;
1017 }
1018 }
1019 return XLEN;
1020}
1021
1022static uintx_t ctz(uintx_t a) {
1023 for (int bit = 0; bit < XLEN; bit++) {
1024 if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
1025 return bit;
1026 }
1027 }
1028 return XLEN;
1029}
1030
1031static uintx_t cpop(uintx_t a) {
1032 uintx_t count = 0;
1033 for (int bit = 0; bit < XLEN; bit++) {
1034 if ((a & (static_cast<uintx_t>(1) << bit)) != 0) {
1035 count++;
1036 }
1037 }
1038 return count;
1039}
1040
1041static uintx_t clzw(uint32_t a) {
1042 for (int bit = 32 - 1; bit >= 0; bit--) {
1043 if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
1044 return 32 - bit - 1;
1045 }
1046 }
1047 return 32;
1048}
1049
1050static uintx_t ctzw(uint32_t a) {
1051 for (int bit = 0; bit < 32; bit++) {
1052 if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
1053 return bit;
1054 }
1055 }
1056 return 32;
1057}
1058
1059static uintx_t cpopw(uint32_t a) {
1060 uintx_t count = 0;
1061 for (int bit = 0; bit < 32; bit++) {
1062 if ((a & (static_cast<uint32_t>(1) << bit)) != 0) {
1063 count++;
1064 }
1065 }
1066 return count;
1067}
1068
1069static intx_t max(intx_t a, intx_t b) {
1070 return a > b ? a : b;
1071}
1072static uintx_t maxu(uintx_t a, uintx_t b) {
1073 return a > b ? a : b;
1074}
1075static intx_t min(intx_t a, intx_t b) {
1076 return a < b ? a : b;
1077}
1078static uintx_t minu(uintx_t a, uintx_t b) {
1079 return a < b ? a : b;
1080}
1081static uintx_t clmul(uintx_t a, uintx_t b) {
1082 uintx_t result = 0;
1083 for (int bit = 0; bit < XLEN; bit++) {
1084 if (((b >> bit) & 1) != 0) {
1085 result ^= a << bit;
1086 }
1087 }
1088 return result;
1089}
1090static uintx_t clmulh(uintx_t a, uintx_t b) {
1091 uintx_t result = 0;
1092 for (int bit = 1; bit < XLEN; bit++) {
1093 if (((b >> bit) & 1) != 0) {
1094 result ^= a >> (XLEN - bit);
1095 }
1096 }
1097 return result;
1098}
1099static uintx_t clmulr(uintx_t a, uintx_t b) {
1100 uintx_t result = 0;
1101 for (int bit = 0; bit < XLEN; bit++) {
1102 if (((b >> bit) & 1) != 0) {
1103 result ^= a >> (XLEN - bit - 1);
1104 }
1105 }
1106 return result;
1107}
1108static uintx_t sextb(uintx_t a) {
1109 return static_cast<intx_t>(a << (XLEN - 8)) >> (XLEN - 8);
1110}
1111static uintx_t sexth(uintx_t a) {
1112 return static_cast<intx_t>(a << (XLEN - 16)) >> (XLEN - 16);
1113}
1114static uintx_t zexth(uintx_t a) {
1115 return a << (XLEN - 16) >> (XLEN - 16);
1116}
1117static uintx_t ror(uintx_t a, uintx_t b) {
1118 uintx_t r = b & (XLEN - 1);
1119 uintx_t l = (XLEN - r) & (XLEN - 1);
1120 return (a << l) | (a >> r);
1121}
1122static uintx_t rol(uintx_t a, uintx_t b) {
1123 uintx_t l = b & (XLEN - 1);
1124 uintx_t r = (XLEN - l) & (XLEN - 1);
1125 return (a << l) | (a >> r);
1126}
1127static uintx_t rorw(uintx_t a, uintx_t b) {
1128 uint32_t r = b & (XLEN - 1);
1129 uint32_t l = (XLEN - r) & (XLEN - 1);
1130 uint32_t x = a;
1131 return sign_extend((x << l) | (x >> r));
1132}
1133static uintx_t rolw(uintx_t a, uintx_t b) {
1134 uint32_t l = b & (XLEN - 1);
1135 uint32_t r = (XLEN - l) & (XLEN - 1);
1136 uint32_t x = a;
1137 return sign_extend((x << l) | (x >> r));
1138}
1139static uintx_t orcb(uintx_t a) {
1140 uintx_t result = 0;
1141 for (int shift = 0; shift < XLEN; shift += 8) {
1142 if (((a >> shift) & 0xFF) != 0) {
1143 result |= static_cast<uintx_t>(0xFF) << shift;
1144 }
1145 }
1146 return result;
1147}
1148static uintx_t rev8(uintx_t a) {
1149 uintx_t result = 0;
1150 for (int shift = 0; shift < XLEN; shift += 8) {
1151 result <<= 8;
1152 result |= (a >> shift) & 0xFF;
1153 }
1154 return result;
1155}
1156static uintx_t bclr(uintx_t a, uintx_t b) {
1157 return a & ~(static_cast<uintx_t>(1) << (b & (XLEN - 1)));
1158}
1159static uintx_t bext(uintx_t a, uintx_t b) {
1160 return (a >> (b & (XLEN - 1))) & 1;
1161}
1162static uintx_t binv(uintx_t a, uintx_t b) {
1163 return a ^ (static_cast<uintx_t>(1) << (b & (XLEN - 1)));
1164}
1165static uintx_t bset(uintx_t a, uintx_t b) {
1166 return a | (static_cast<uintx_t>(1) << (b & (XLEN - 1)));
1167}
1168
1169DART_FORCE_INLINE
1170void Simulator::InterpretOPIMM(Instr instr) {
1171 switch (instr.funct3()) {
1172 case ADDI:
1173 set_xreg(instr.rd(), get_xreg(instr.rs1()) + instr.itype_imm());
1174 break;
1175 case SLTI: {
1176 set_xreg(instr.rd(), static_cast<intx_t>(get_xreg(instr.rs1())) <
1177 static_cast<intx_t>(instr.itype_imm())
1178 ? 1
1179 : 0);
1180 break;
1181 }
1182 case SLTIU:
1183 set_xreg(instr.rd(), static_cast<uintx_t>(get_xreg(instr.rs1())) <
1184 static_cast<uintx_t>(instr.itype_imm())
1185 ? 1
1186 : 0);
1187 break;
1188 case XORI:
1189 set_xreg(instr.rd(), get_xreg(instr.rs1()) ^ instr.itype_imm());
1190 break;
1191 case ORI:
1192 set_xreg(instr.rd(), get_xreg(instr.rs1()) | instr.itype_imm());
1193 break;
1194 case ANDI:
1195 set_xreg(instr.rd(), get_xreg(instr.rs1()) & instr.itype_imm());
1196 break;
1197 case SLLI:
1198 if (instr.funct7() == COUNT) {
1199 if (instr.shamt() == 0b00000) {
1200 set_xreg(instr.rd(), clz(get_xreg(instr.rs1())));
1201 } else if (instr.shamt() == 0b00001) {
1202 set_xreg(instr.rd(), ctz(get_xreg(instr.rs1())));
1203 } else if (instr.shamt() == 0b00010) {
1204 set_xreg(instr.rd(), cpop(get_xreg(instr.rs1())));
1205 } else if (instr.shamt() == 0b00100) {
1206 set_xreg(instr.rd(), sextb(get_xreg(instr.rs1())));
1207 } else if (instr.shamt() == 0b00101) {
1208 set_xreg(instr.rd(), sexth(get_xreg(instr.rs1())));
1209 } else {
1210 IllegalInstruction(instr);
1211 }
1212 } else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
1213 set_xreg(instr.rd(), bclr(get_xreg(instr.rs1()), instr.shamt()));
1214 } else if ((instr.funct7() & 0b1111110) == BINV) {
1215 set_xreg(instr.rd(), binv(get_xreg(instr.rs1()), instr.shamt()));
1216 } else if ((instr.funct7() & 0b1111110) == BSET) {
1217 set_xreg(instr.rd(), bset(get_xreg(instr.rs1()), instr.shamt()));
1218 } else {
1219 set_xreg(instr.rd(), get_xreg(instr.rs1()) << instr.shamt());
1220 }
1221 break;
1222 case SRI:
1223 if ((instr.funct7() & 0b1111110) == SRA) {
1224 set_xreg(instr.rd(),
1225 static_cast<intx_t>(get_xreg(instr.rs1())) >> instr.shamt());
1226 } else if ((instr.funct7() & 0b1111110) == ROTATE) {
1227 set_xreg(instr.rd(), ror(get_xreg(instr.rs1()), instr.shamt()));
1228 } else if (instr.funct7() == 0b0010100) {
1229 set_xreg(instr.rd(), orcb(get_xreg(instr.rs1())));
1230#if XLEN == 32
1231 } else if (instr.funct7() == 0b0110100) {
1232#else
1233 } else if (instr.funct7() == 0b0110101) {
1234#endif
1235 set_xreg(instr.rd(), rev8(get_xreg(instr.rs1())));
1236 } else if ((instr.funct7() & 0b1111110) == BCLRBEXT) {
1237 set_xreg(instr.rd(), bext(get_xreg(instr.rs1()), instr.shamt()));
1238 } else {
1239 set_xreg(instr.rd(),
1240 static_cast<uintx_t>(get_xreg(instr.rs1())) >> instr.shamt());
1241 }
1242 break;
1243 default:
1244 IllegalInstruction(instr);
1245 }
1246 pc_ += instr.length();
1247}
1248
1249DART_FORCE_INLINE
1250void Simulator::InterpretOPIMM32(Instr instr) {
1251 switch (instr.funct3()) {
1252 case ADDI: {
1253 uint32_t a = get_xreg(instr.rs1());
1254 uint32_t b = instr.itype_imm();
1255 set_xreg(instr.rd(), sign_extend(a + b));
1256 break;
1257 }
1258 case SLLI: {
1259 if (instr.funct7() == SLLIUW) {
1260 uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
1261 uintx_t b = instr.shamt();
1262 set_xreg(instr.rd(), a << b);
1263 } else if (instr.funct7() == COUNT) {
1264 if (instr.shamt() == 0b00000) {
1265 set_xreg(instr.rd(), clzw(get_xreg(instr.rs1())));
1266 } else if (instr.shamt() == 0b00001) {
1267 set_xreg(instr.rd(), ctzw(get_xreg(instr.rs1())));
1268 } else if (instr.shamt() == 0b00010) {
1269 set_xreg(instr.rd(), cpopw(get_xreg(instr.rs1())));
1270 } else {
1271 IllegalInstruction(instr);
1272 }
1273 } else {
1274 uint32_t a = get_xreg(instr.rs1());
1275 uint32_t b = instr.shamt();
1276 set_xreg(instr.rd(), sign_extend(a << b));
1277 }
1278 break;
1279 }
1280 case SRI:
1281 if (instr.funct7() == SRA) {
1282 int32_t a = get_xreg(instr.rs1());
1283 int32_t b = instr.shamt();
1284 set_xreg(instr.rd(), sign_extend(a >> b));
1285 } else if (instr.funct7() == ROTATE) {
1286 set_xreg(instr.rd(), rorw(get_xreg(instr.rs1()), instr.shamt()));
1287 } else {
1288 uint32_t a = get_xreg(instr.rs1());
1289 uint32_t b = instr.shamt();
1290 set_xreg(instr.rd(), sign_extend(a >> b));
1291 }
1292 break;
1293 default:
1294 IllegalInstruction(instr);
1295 }
1296 pc_ += instr.length();
1297}
1298
1299DART_FORCE_INLINE
1300void Simulator::InterpretOP(Instr instr) {
1301 switch (instr.funct7()) {
1302 case 0:
1303 InterpretOP_0(instr);
1304 break;
1305 case SUB:
1306 InterpretOP_SUB(instr);
1307 break;
1308 case MULDIV:
1309 InterpretOP_MULDIV(instr);
1310 break;
1311 case SHADD:
1312 InterpretOP_SHADD(instr);
1313 break;
1314 case MINMAXCLMUL:
1315 InterpretOP_MINMAXCLMUL(instr);
1316 break;
1317 case ROTATE:
1318 InterpretOP_ROTATE(instr);
1319 break;
1320 case BCLRBEXT:
1321 InterpretOP_BCLRBEXT(instr);
1322 break;
1323 case BINV:
1324 set_xreg(instr.rd(), binv(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1325 pc_ += instr.length();
1326 break;
1327 case BSET:
1328 set_xreg(instr.rd(), bset(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1329 pc_ += instr.length();
1330 break;
1331#if XLEN == 32
1332 case 0b0000100:
1333 set_xreg(instr.rd(), zexth(get_xreg(instr.rs1())));
1334 pc_ += instr.length();
1335 break;
1336#endif
1337 default:
1338 IllegalInstruction(instr);
1339 }
1340}
1341
1342DART_FORCE_INLINE
1343void Simulator::InterpretOP_0(Instr instr) {
1344 switch (instr.funct3()) {
1345 case ADD:
1346 set_xreg(instr.rd(), get_xreg(instr.rs1()) + get_xreg(instr.rs2()));
1347 break;
1348 case SLL: {
1349 uintx_t shamt = get_xreg(instr.rs2()) & (XLEN - 1);
1350 set_xreg(instr.rd(), get_xreg(instr.rs1()) << shamt);
1351 break;
1352 }
1353 case SLT:
1354 set_xreg(instr.rd(), static_cast<intx_t>(get_xreg(instr.rs1())) <
1355 static_cast<intx_t>(get_xreg(instr.rs2()))
1356 ? 1
1357 : 0);
1358 break;
1359 case SLTU:
1360 set_xreg(instr.rd(), static_cast<uintx_t>(get_xreg(instr.rs1())) <
1361 static_cast<uintx_t>(get_xreg(instr.rs2()))
1362 ? 1
1363 : 0);
1364 break;
1365 case XOR:
1366 set_xreg(instr.rd(), get_xreg(instr.rs1()) ^ get_xreg(instr.rs2()));
1367 break;
1368 case SR: {
1369 uintx_t shamt = get_xreg(instr.rs2()) & (XLEN - 1);
1370 set_xreg(instr.rd(),
1371 static_cast<uintx_t>(get_xreg(instr.rs1())) >> shamt);
1372 break;
1373 }
1374 case OR:
1375 set_xreg(instr.rd(), get_xreg(instr.rs1()) | get_xreg(instr.rs2()));
1376 break;
1377 case AND:
1378 set_xreg(instr.rd(), get_xreg(instr.rs1()) & get_xreg(instr.rs2()));
1379 break;
1380 default:
1381 IllegalInstruction(instr);
1382 }
1383 pc_ += instr.length();
1384}
1385
1386static intx_t mul(intx_t a, intx_t b) {
1387 return static_cast<uintx_t>(a) * static_cast<uintx_t>(b);
1388}
1389
1390static intx_t mulh(intx_t a, intx_t b) {
1391 const uintx_t kLoMask = (static_cast<uintx_t>(1) << (XLEN / 2)) - 1;
1392 const uintx_t kHiShift = XLEN / 2;
1393
1394 uintx_t a_lo = a & kLoMask;
1395 intx_t a_hi = a >> kHiShift;
1396 uintx_t b_lo = b & kLoMask;
1397 intx_t b_hi = b >> kHiShift;
1398
1399 uintx_t x = a_lo * b_lo;
1400 intx_t y = a_hi * b_lo;
1401 intx_t z = a_lo * b_hi;
1402 intx_t w = a_hi * b_hi;
1403
1404 intx_t r0 = (x >> kHiShift) + y;
1405 intx_t r1 = (r0 & kLoMask) + z;
1406 return w + (r0 >> kHiShift) + (r1 >> kHiShift);
1407}
1408
1409static uintx_t mulhu(uintx_t a, uintx_t b) {
1410 const uintx_t kLoMask = (static_cast<uintx_t>(1) << (XLEN / 2)) - 1;
1411 const uintx_t kHiShift = XLEN / 2;
1412
1413 uintx_t a_lo = a & kLoMask;
1414 uintx_t a_hi = a >> kHiShift;
1415 uintx_t b_lo = b & kLoMask;
1416 uintx_t b_hi = b >> kHiShift;
1417
1418 uintx_t x = a_lo * b_lo;
1419 uintx_t y = a_hi * b_lo;
1420 uintx_t z = a_lo * b_hi;
1421 uintx_t w = a_hi * b_hi;
1422
1423 uintx_t r0 = (x >> kHiShift) + y;
1424 uintx_t r1 = (r0 & kLoMask) + z;
1425 return w + (r0 >> kHiShift) + (r1 >> kHiShift);
1426}
1427
1428static uintx_t mulhsu(intx_t a, uintx_t b) {
1429 const uintx_t kLoMask = (static_cast<uintx_t>(1) << (XLEN / 2)) - 1;
1430 const uintx_t kHiShift = XLEN / 2;
1431
1432 uintx_t a_lo = a & kLoMask;
1433 intx_t a_hi = a >> kHiShift;
1434 uintx_t b_lo = b & kLoMask;
1435 uintx_t b_hi = b >> kHiShift;
1436
1437 uintx_t x = a_lo * b_lo;
1438 intx_t y = a_hi * b_lo;
1439 uintx_t z = a_lo * b_hi;
1440 intx_t w = a_hi * b_hi;
1441
1442 intx_t r0 = (x >> kHiShift) + y;
1443 uintx_t r1 = (r0 & kLoMask) + z;
1444 return w + (r0 >> kHiShift) + (r1 >> kHiShift);
1445}
1446
1447static intx_t div(intx_t a, intx_t b) {
1448 if (b == 0) {
1449 return -1;
1450 } else if (b == -1 && a == kMinIntX) {
1451 return kMinIntX;
1452 } else {
1453 return a / b;
1454 }
1455}
1456
1457static uintx_t divu(uintx_t a, uintx_t b) {
1458 if (b == 0) {
1459 return kMaxUIntX;
1460 } else {
1461 return a / b;
1462 }
1463}
1464
1465static intx_t rem(intx_t a, intx_t b) {
1466 if (b == 0) {
1467 return a;
1468 } else if (b == -1 && a == kMinIntX) {
1469 return 0;
1470 } else {
1471 return a % b;
1472 }
1473}
1474
1475static uintx_t remu(uintx_t a, uintx_t b) {
1476 if (b == 0) {
1477 return a;
1478 } else {
1479 return a % b;
1480 }
1481}
1482
1483#if XLEN >= 64
1484static int32_t mulw(int32_t a, int32_t b) {
1485 return a * b;
1486}
1487
1488static int32_t divw(int32_t a, int32_t b) {
1489 if (b == 0) {
1490 return -1;
1491 } else if (b == -1 && a == kMinInt32) {
1492 return kMinInt32;
1493 } else {
1494 return a / b;
1495 }
1496}
1497
1498static uint32_t divuw(uint32_t a, uint32_t b) {
1499 if (b == 0) {
1500 return kMaxUint32;
1501 } else {
1502 return a / b;
1503 }
1504}
1505
1506static int32_t remw(int32_t a, int32_t b) {
1507 if (b == 0) {
1508 return a;
1509 } else if (b == -1 && a == kMinInt32) {
1510 return 0;
1511 } else {
1512 return a % b;
1513 }
1514}
1515
1516static uint32_t remuw(uint32_t a, uint32_t b) {
1517 if (b == 0) {
1518 return a;
1519 } else {
1520 return a % b;
1521 }
1522}
1523#endif // XLEN >= 64
1524
1525DART_FORCE_INLINE
1526void Simulator::InterpretOP_MULDIV(Instr instr) {
1527 switch (instr.funct3()) {
1528 case MUL:
1529 set_xreg(instr.rd(), mul(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1530 break;
1531 case MULH:
1532 set_xreg(instr.rd(), mulh(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1533 break;
1534 case MULHSU:
1535 set_xreg(instr.rd(),
1536 mulhsu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1537 break;
1538 case MULHU:
1539 set_xreg(instr.rd(), mulhu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1540 break;
1541 case DIV:
1542 set_xreg(instr.rd(), div(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1543 break;
1544 case DIVU:
1545 set_xreg(instr.rd(), divu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1546 break;
1547 case REM:
1548 set_xreg(instr.rd(), rem(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1549 break;
1550 case REMU:
1551 set_xreg(instr.rd(), remu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1552 break;
1553 default:
1554 IllegalInstruction(instr);
1555 }
1556 pc_ += instr.length();
1557}
1558
1559DART_FORCE_INLINE
1560void Simulator::InterpretOP_SUB(Instr instr) {
1561 switch (instr.funct3()) {
1562 case ADD:
1563 set_xreg(instr.rd(), get_xreg(instr.rs1()) - get_xreg(instr.rs2()));
1564 break;
1565 case SR: {
1566 uintx_t shamt = get_xreg(instr.rs2()) & (XLEN - 1);
1567 set_xreg(instr.rd(), static_cast<intx_t>(get_xreg(instr.rs1())) >> shamt);
1568 break;
1569 }
1570 case AND:
1571 set_xreg(instr.rd(), get_xreg(instr.rs1()) & ~get_xreg(instr.rs2()));
1572 break;
1573 case OR:
1574 set_xreg(instr.rd(), get_xreg(instr.rs1()) | ~get_xreg(instr.rs2()));
1575 break;
1576 case XOR:
1577 set_xreg(instr.rd(), get_xreg(instr.rs1()) ^ ~get_xreg(instr.rs2()));
1578 break;
1579 default:
1580 IllegalInstruction(instr);
1581 }
1582 pc_ += instr.length();
1583}
1584
1585DART_FORCE_INLINE
1586void Simulator::InterpretOP_SHADD(Instr instr) {
1587 switch (instr.funct3()) {
1588 case SH1ADD:
1589 set_xreg(instr.rd(),
1590 (get_xreg(instr.rs1()) << 1) + get_xreg(instr.rs2()));
1591 break;
1592 case SH2ADD:
1593 set_xreg(instr.rd(),
1594 (get_xreg(instr.rs1()) << 2) + get_xreg(instr.rs2()));
1595 break;
1596 case SH3ADD:
1597 set_xreg(instr.rd(),
1598 (get_xreg(instr.rs1()) << 3) + get_xreg(instr.rs2()));
1599 break;
1600 default:
1601 IllegalInstruction(instr);
1602 }
1603 pc_ += instr.length();
1604}
1605
1606DART_FORCE_INLINE
1607void Simulator::InterpretOP_MINMAXCLMUL(Instr instr) {
1608 switch (instr.funct3()) {
1609 case MAX:
1610 set_xreg(instr.rd(), max(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1611 break;
1612 case MAXU:
1613 set_xreg(instr.rd(), maxu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1614 break;
1615 case MIN:
1616 set_xreg(instr.rd(), min(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1617 break;
1618 case MINU:
1619 set_xreg(instr.rd(), minu(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1620 break;
1621 case CLMUL:
1622 set_xreg(instr.rd(), clmul(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1623 break;
1624 case CLMULH:
1625 set_xreg(instr.rd(),
1626 clmulh(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1627 break;
1628 case CLMULR:
1629 set_xreg(instr.rd(),
1630 clmulr(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1631 break;
1632 default:
1633 IllegalInstruction(instr);
1634 }
1635 pc_ += instr.length();
1636}
1637
1638DART_FORCE_INLINE
1639void Simulator::InterpretOP_ROTATE(Instr instr) {
1640 switch (instr.funct3()) {
1641 case ROR:
1642 set_xreg(instr.rd(), ror(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1643 break;
1644 case ROL:
1645 set_xreg(instr.rd(), rol(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1646 break;
1647 default:
1648 IllegalInstruction(instr);
1649 }
1650 pc_ += instr.length();
1651}
1652
1653DART_FORCE_INLINE
1654void Simulator::InterpretOP_BCLRBEXT(Instr instr) {
1655 switch (instr.funct3()) {
1656 case BCLR:
1657 set_xreg(instr.rd(), bclr(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1658 break;
1659 case BEXT:
1660 set_xreg(instr.rd(), bext(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1661 break;
1662 default:
1663 IllegalInstruction(instr);
1664 }
1665 pc_ += instr.length();
1666}
1667
1668DART_FORCE_INLINE
1669void Simulator::InterpretOP32(Instr instr) {
1670 switch (instr.funct7()) {
1671#if XLEN >= 64
1672 case 0:
1673 InterpretOP32_0(instr);
1674 break;
1675 case SUB:
1676 InterpretOP32_SUB(instr);
1677 break;
1678 case MULDIV:
1679 InterpretOP32_MULDIV(instr);
1680 break;
1681 case SHADD:
1682 InterpretOP32_SHADD(instr);
1683 break;
1684 case ADDUW:
1685 InterpretOP32_ADDUW(instr);
1686 break;
1687 case ROTATE:
1688 InterpretOP32_ROTATE(instr);
1689 break;
1690#endif // XLEN >= 64
1691 default:
1692 IllegalInstruction(instr);
1693 }
1694}
1695
1696DART_FORCE_INLINE
1697void Simulator::InterpretOP32_0(Instr instr) {
1698 switch (instr.funct3()) {
1699#if XLEN >= 64
1700 case ADD: {
1701 uint32_t a = get_xreg(instr.rs1());
1702 uint32_t b = get_xreg(instr.rs2());
1703 set_xreg(instr.rd(), sign_extend(a + b));
1704 break;
1705 }
1706 case SLL: {
1707 uint32_t a = get_xreg(instr.rs1());
1708 uint32_t b = get_xreg(instr.rs2()) & (32 - 1);
1709 set_xreg(instr.rd(), sign_extend(a << b));
1710 break;
1711 }
1712 case SR: {
1713 uint32_t b = get_xreg(instr.rs2()) & (32 - 1);
1714 uint32_t a = get_xreg(instr.rs1());
1715 set_xreg(instr.rd(), sign_extend(a >> b));
1716 break;
1717 }
1718#endif // XLEN >= 64
1719 default:
1720 IllegalInstruction(instr);
1721 }
1722 pc_ += instr.length();
1723}
1724
1725DART_FORCE_INLINE
1726void Simulator::InterpretOP32_SUB(Instr instr) {
1727 switch (instr.funct3()) {
1728#if XLEN >= 64
1729 case ADD: {
1730 uint32_t a = get_xreg(instr.rs1());
1731 uint32_t b = get_xreg(instr.rs2());
1732 set_xreg(instr.rd(), sign_extend(a - b));
1733 break;
1734 }
1735 case SR: {
1736 uint32_t b = get_xreg(instr.rs2()) & (32 - 1);
1737 int32_t a = get_xreg(instr.rs1());
1738 set_xreg(instr.rd(), sign_extend(a >> b));
1739 break;
1740 }
1741#endif // XLEN >= 64
1742 default:
1743 IllegalInstruction(instr);
1744 }
1745 pc_ += instr.length();
1746}
1747
1748DART_FORCE_INLINE
1749void Simulator::InterpretOP32_MULDIV(Instr instr) {
1750 switch (instr.funct3()) {
1751#if XLEN >= 64
1752 case MULW:
1753 set_xreg(instr.rd(),
1754 sign_extend(mulw(get_xreg(instr.rs1()), get_xreg(instr.rs2()))));
1755 break;
1756 case DIVW:
1757 set_xreg(instr.rd(),
1758 sign_extend(divw(get_xreg(instr.rs1()), get_xreg(instr.rs2()))));
1759 break;
1760 case DIVUW:
1761 set_xreg(instr.rd(), sign_extend(divuw(get_xreg(instr.rs1()),
1762 get_xreg(instr.rs2()))));
1763 break;
1764 case REMW:
1765 set_xreg(instr.rd(),
1766 sign_extend(remw(get_xreg(instr.rs1()), get_xreg(instr.rs2()))));
1767 break;
1768 case REMUW:
1769 set_xreg(instr.rd(), sign_extend(remuw(get_xreg(instr.rs1()),
1770 get_xreg(instr.rs2()))));
1771 break;
1772#endif // XLEN >= 64
1773 default:
1774 IllegalInstruction(instr);
1775 }
1776 pc_ += instr.length();
1777}
1778
1779DART_FORCE_INLINE
1780void Simulator::InterpretOP32_SHADD(Instr instr) {
1781 switch (instr.funct3()) {
1782 case SH1ADD: {
1783 uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
1784 uintx_t b = get_xreg(instr.rs2());
1785 set_xreg(instr.rd(), (a << 1) + b);
1786 break;
1787 }
1788 case SH2ADD: {
1789 uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
1790 uintx_t b = get_xreg(instr.rs2());
1791 set_xreg(instr.rd(), (a << 2) + b);
1792 break;
1793 }
1794 case SH3ADD: {
1795 uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
1796 uintx_t b = get_xreg(instr.rs2());
1797 set_xreg(instr.rd(), (a << 3) + b);
1798 break;
1799 }
1800 default:
1801 IllegalInstruction(instr);
1802 }
1803 pc_ += instr.length();
1804}
1805
1806DART_FORCE_INLINE
1807void Simulator::InterpretOP32_ADDUW(Instr instr) {
1808 switch (instr.funct3()) {
1809#if XLEN >= 64
1810 case F3_0: {
1811 uintx_t a = static_cast<uint32_t>(get_xreg(instr.rs1()));
1812 uintx_t b = get_xreg(instr.rs2());
1813 set_xreg(instr.rd(), a + b);
1814 break;
1815 }
1816 case ZEXT:
1817 set_xreg(instr.rd(), zexth(get_xreg(instr.rs1())));
1818 break;
1819#endif // XLEN >= 64
1820 default:
1821 IllegalInstruction(instr);
1822 }
1823 pc_ += instr.length();
1824}
1825
1826DART_FORCE_INLINE
1827void Simulator::InterpretOP32_ROTATE(Instr instr) {
1828 switch (instr.funct3()) {
1829 case ROR:
1830 set_xreg(instr.rd(), rorw(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1831 break;
1832 case ROL:
1833 set_xreg(instr.rd(), rolw(get_xreg(instr.rs1()), get_xreg(instr.rs2())));
1834 break;
1835 default:
1836 IllegalInstruction(instr);
1837 }
1838 pc_ += instr.length();
1839}
1840
1841void Simulator::InterpretMISCMEM(Instr instr) {
1842 switch (instr.funct3()) {
1843 case FENCE:
1844 std::atomic_thread_fence(std::memory_order_acq_rel);
1845 break;
1846 case FENCEI:
1847 // Nothing to do: simulated instructions are data on the host.
1848 break;
1849 default:
1850 IllegalInstruction(instr);
1851 }
1852 pc_ += instr.length();
1853}
1854
1855void Simulator::InterpretSYSTEM(Instr instr) {
1856 switch (instr.funct3()) {
1857 case 0:
1858 switch (instr.funct12()) {
1859 case ECALL:
1860 InterpretECALL(instr);
1861 return;
1862 case EBREAK:
1863 InterpretEBREAK(instr);
1864 return;
1865 default:
1866 IllegalInstruction(instr);
1867 }
1868 break;
1869 case CSRRW: {
1870 if (instr.rd() == ZR) {
1871 // No read effect.
1872 CSRWrite(instr.csr(), get_xreg(instr.rs1()));
1873 } else {
1874 intx_t result = CSRRead(instr.csr());
1875 CSRWrite(instr.csr(), get_xreg(instr.rs1()));
1876 set_xreg(instr.rd(), result);
1877 }
1878 break;
1879 }
1880 case CSRRS: {
1881 intx_t result = CSRRead(instr.csr());
1882 if (instr.rs1() == ZR) {
1883 // No write effect.
1884 } else {
1885 CSRSet(instr.csr(), get_xreg(instr.rs1()));
1886 }
1887 set_xreg(instr.rd(), result);
1888 break;
1889 }
1890 case CSRRC: {
1891 intx_t result = CSRRead(instr.csr());
1892 if (instr.rs1() == ZR) {
1893 // No write effect.
1894 } else {
1895 CSRClear(instr.csr(), get_xreg(instr.rs1()));
1896 }
1897 set_xreg(instr.rd(), result);
1898 break;
1899 }
1900 case CSRRWI: {
1901 if (instr.rd() == ZR) {
1902 // No read effect.
1903 CSRWrite(instr.csr(), instr.zimm());
1904 } else {
1905 intx_t result = CSRRead(instr.csr());
1906 CSRWrite(instr.csr(), instr.zimm());
1907 set_xreg(instr.rd(), result);
1908 }
1909 break;
1910 }
1911 case CSRRSI: {
1912 intx_t result = CSRRead(instr.csr());
1913 if (instr.zimm() == 0) {
1914 // No write effect.
1915 } else {
1916 CSRSet(instr.csr(), instr.zimm());
1917 }
1918 set_xreg(instr.rd(), result);
1919 break;
1920 }
1921 case CSRRCI: {
1922 intx_t result = CSRRead(instr.csr());
1923 if (instr.zimm() == 0) {
1924 // No write effect.
1925 } else {
1926 CSRClear(instr.csr(), instr.zimm());
1927 }
1928 set_xreg(instr.rd(), result);
1929 break;
1930 }
1931 default:
1932 IllegalInstruction(instr);
1933 }
1934 pc_ += instr.length();
1935}
1936
1937// Calls into the Dart runtime are based on this interface.
1938typedef void (*SimulatorRuntimeCall)(NativeArguments arguments);
1939
1940// Calls to leaf Dart runtime functions are based on this interface.
1941typedef intx_t (*SimulatorLeafRuntimeCall)(intx_t r0,
1942 intx_t r1,
1943 intx_t r2,
1944 intx_t r3,
1945 intx_t r4,
1946 intx_t r5,
1947 intx_t r6,
1948 intx_t r7);
1949
1950// [target] has several different signatures that differ from
1951// SimulatorLeafRuntimeCall. We can call them all from here only because in
1952// X64's calling conventions a function can be called with extra arguments
1953// and the callee will see the first arguments and won't unbalance the stack.
1954NO_SANITIZE_UNDEFINED("function")
1955static intx_t InvokeLeafRuntime(SimulatorLeafRuntimeCall target,
1956 intx_t r0,
1957 intx_t r1,
1958 intx_t r2,
1959 intx_t r3,
1960 intx_t r4,
1961 intx_t r5,
1962 intx_t r6,
1963 intx_t r7) {
1964 return target(r0, r1, r2, r3, r4, r5, r6, r7);
1965}
1966
1967// Calls to leaf float Dart runtime functions are based on this interface.
1968typedef double (*SimulatorLeafFloatRuntimeCall)(double d0,
1969 double d1,
1970 double d2,
1971 double d3,
1972 double d4,
1973 double d5,
1974 double d6,
1975 double d7);
1976
1977// [target] has several different signatures that differ from
1978// SimulatorFloatLeafRuntimeCall. We can call them all from here only because in
1979// X64's calling conventions a function can be called with extra arguments
1980// and the callee will see the first arguments and won't unbalance the stack.
1981NO_SANITIZE_UNDEFINED("function")
1982static double InvokeFloatLeafRuntime(SimulatorLeafFloatRuntimeCall target,
1983 double d0,
1984 double d1,
1985 double d2,
1986 double d3,
1987 double d4,
1988 double d5,
1989 double d6,
1990 double d7) {
1991 return target(d0, d1, d2, d3, d4, d5, d6, d7);
1992}
1993
1994// Calls to native Dart functions are based on this interface.
1995typedef void (*SimulatorNativeCallWrapper)(Dart_NativeArguments arguments,
1997
1998void Simulator::InterpretECALL(Instr instr) {
1999 if (instr.rs1() != ZR) {
2000 // Fake instruction generated by Assembler::SimulatorPrintObject.
2001 if (true || IsTracingExecution()) {
2002 Object& obj = Object::Handle(
2003 static_cast<ObjectPtr>(static_cast<uword>(get_xreg(instr.rs1()))));
2004 THR_Print("%" Px ": %s = %s\n", static_cast<uword>(pc_),
2005 cpu_reg_names[instr.rs1()], obj.ToCString());
2006 FLAG_trace_sim_after = 1;
2007 }
2008 pc_ += instr.length();
2009 return;
2010 }
2011
2012 // The C ABI stack alignment is 16 for both 32 and 64 bit.
2013 if (!Utils::IsAligned(get_xreg(SP), 16)) {
2014 PrintRegisters();
2015 PrintStack();
2016 FATAL("Stack misaligned at call to C function");
2017 }
2018
2019 SimulatorSetjmpBuffer buffer(this);
2020 if (!setjmp(buffer.buffer_)) {
2021 uintx_t saved_ra = get_xreg(RA);
2022 Redirection* redirection = Redirection::FromECallInstruction(pc_);
2023 uword external = redirection->external_function();
2024 if (IsTracingExecution()) {
2025 THR_Print("Call to host function at 0x%" Pd "\n", external);
2026 }
2027
2028 if (redirection->call_kind() == kRuntimeCall) {
2029 NativeArguments* arguments =
2030 reinterpret_cast<NativeArguments*>(get_register(A0));
2031 SimulatorRuntimeCall target =
2032 reinterpret_cast<SimulatorRuntimeCall>(external);
2033 target(*arguments);
2034 ClobberVolatileRegisters();
2035 } else if (redirection->call_kind() == kLeafRuntimeCall) {
2036 ASSERT((0 <= redirection->argument_count()) &&
2037 (redirection->argument_count() <= 8));
2038 SimulatorLeafRuntimeCall target =
2039 reinterpret_cast<SimulatorLeafRuntimeCall>(external);
2040 const intx_t r0 = get_register(A0);
2041 const intx_t r1 = get_register(A1);
2042 const intx_t r2 = get_register(A2);
2043 const intx_t r3 = get_register(A3);
2044 const intx_t r4 = get_register(A4);
2045 const intx_t r5 = get_register(A5);
2046 const intx_t r6 = get_register(A6);
2047 const intx_t r7 = get_register(A7);
2048 const intx_t res =
2049 InvokeLeafRuntime(target, r0, r1, r2, r3, r4, r5, r6, r7);
2050 ClobberVolatileRegisters();
2051 set_xreg(A0, res); // Set returned result from function.
2052 } else if (redirection->call_kind() == kLeafFloatRuntimeCall) {
2053 ASSERT((0 <= redirection->argument_count()) &&
2054 (redirection->argument_count() <= 8));
2055 SimulatorLeafFloatRuntimeCall target =
2056 reinterpret_cast<SimulatorLeafFloatRuntimeCall>(external);
2057 const double d0 = get_fregd(FA0);
2058 const double d1 = get_fregd(FA1);
2059 const double d2 = get_fregd(FA2);
2060 const double d3 = get_fregd(FA3);
2061 const double d4 = get_fregd(FA4);
2062 const double d5 = get_fregd(FA5);
2063 const double d6 = get_fregd(FA6);
2064 const double d7 = get_fregd(FA7);
2065 const double res =
2066 InvokeFloatLeafRuntime(target, d0, d1, d2, d3, d4, d5, d6, d7);
2067 ClobberVolatileRegisters();
2068 set_fregd(FA0, res);
2069 } else if (redirection->call_kind() == kNativeCallWrapper) {
2070 SimulatorNativeCallWrapper wrapper =
2071 reinterpret_cast<SimulatorNativeCallWrapper>(external);
2072 Dart_NativeArguments arguments =
2073 reinterpret_cast<Dart_NativeArguments>(get_register(A0));
2075 reinterpret_cast<Dart_NativeFunction>(get_register(A1));
2076 wrapper(arguments, target);
2077 ClobberVolatileRegisters();
2078 } else {
2079 UNREACHABLE();
2080 }
2081
2082 // Return.
2083 pc_ = saved_ra;
2084 } else {
2085 // Coming via long jump from a throw. Continue to exception handler.
2086 }
2087}
2088
2089void Simulator::InterpretAMO(Instr instr) {
2090 switch (instr.funct3()) {
2091 case WIDTH32:
2092 InterpretAMO32(instr);
2093 break;
2094 case WIDTH64:
2095 InterpretAMO64(instr);
2096 break;
2097 default:
2098 IllegalInstruction(instr);
2099 }
2100}
2101
2102// Note: This implementation does not give full LR/SC semantics because it
2103// suffers from the ABA problem.
2104
2105template <typename type>
2106void Simulator::InterpretLR(Instr instr) {
2107 uintx_t addr = get_xreg(instr.rs1());
2108 if ((addr & (sizeof(type) - 1)) != 0) {
2109 FATAL("Misaligned atomic memory operation");
2110 }
2111 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2112 reserved_address_ = addr;
2113 reserved_value_ = atomic->load(instr.memory_order());
2114 set_xreg(instr.rd(), reserved_value_);
2115}
2116
2117template <typename type>
2118void Simulator::InterpretSC(Instr instr) {
2119 uintx_t addr = get_xreg(instr.rs1());
2120 if ((addr & (sizeof(type) - 1)) != 0) {
2121 FATAL("Misaligned atomic memory operation");
2122 }
2123 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2124 if (addr != reserved_address_) {
2125 set_xreg(instr.rd(), 1);
2126 return;
2127 }
2128 type expected = reserved_value_;
2129 type desired = get_xreg(instr.rs2());
2130 bool success =
2131 atomic->compare_exchange_strong(expected, desired, instr.memory_order());
2132 set_xreg(instr.rd(), success ? 0 : 1);
2133}
2134
2135template <typename type>
2136void Simulator::InterpretAMOSWAP(Instr instr) {
2137 uintx_t addr = get_xreg(instr.rs1());
2138 if ((addr & (sizeof(type) - 1)) != 0) {
2139 FATAL("Misaligned atomic memory operation");
2140 }
2141 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2142 type desired = get_xreg(instr.rs2());
2143 type result = atomic->exchange(desired, instr.memory_order());
2144 set_xreg(instr.rd(), sign_extend(result));
2145}
2146
2147template <typename type>
2148void Simulator::InterpretAMOADD(Instr instr) {
2149 uintx_t addr = get_xreg(instr.rs1());
2150 if ((addr & (sizeof(type) - 1)) != 0) {
2151 FATAL("Misaligned atomic memory operation");
2152 }
2153 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2154 type arg = get_xreg(instr.rs2());
2155 type result = atomic->fetch_add(arg, instr.memory_order());
2156 set_xreg(instr.rd(), sign_extend(result));
2157}
2158
2159template <typename type>
2160void Simulator::InterpretAMOXOR(Instr instr) {
2161 uintx_t addr = get_xreg(instr.rs1());
2162 if ((addr & (sizeof(type) - 1)) != 0) {
2163 FATAL("Misaligned atomic memory operation");
2164 }
2165 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2166 type arg = get_xreg(instr.rs2());
2167 type result = atomic->fetch_xor(arg, instr.memory_order());
2168 set_xreg(instr.rd(), sign_extend(result));
2169}
2170
2171template <typename type>
2172void Simulator::InterpretAMOAND(Instr instr) {
2173 uintx_t addr = get_xreg(instr.rs1());
2174 if ((addr & (sizeof(type) - 1)) != 0) {
2175 FATAL("Misaligned atomic memory operation");
2176 }
2177 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2178 type arg = get_xreg(instr.rs2());
2179 type result = atomic->fetch_and(arg, instr.memory_order());
2180 set_xreg(instr.rd(), sign_extend(result));
2181}
2182
2183template <typename type>
2184void Simulator::InterpretAMOOR(Instr instr) {
2185 uintx_t addr = get_xreg(instr.rs1());
2186 if ((addr & (sizeof(type) - 1)) != 0) {
2187 FATAL("Misaligned atomic memory operation");
2188 }
2189 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2190 type arg = get_xreg(instr.rs2());
2191 type result = atomic->fetch_or(arg, instr.memory_order());
2192 set_xreg(instr.rd(), sign_extend(result));
2193}
2194
2195template <typename type>
2196void Simulator::InterpretAMOMIN(Instr instr) {
2197 uintx_t addr = get_xreg(instr.rs1());
2198 if ((addr & (sizeof(type) - 1)) != 0) {
2199 FATAL("Misaligned atomic memory operation");
2200 }
2201 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2202 type expected = atomic->load(std::memory_order_relaxed);
2203 type compare = get_xreg(instr.rs2());
2204 type desired;
2205 do {
2206 desired = expected < compare ? expected : compare;
2207 } while (
2208 !atomic->compare_exchange_weak(expected, desired, instr.memory_order()));
2209 set_xreg(instr.rd(), sign_extend(expected));
2210}
2211
2212template <typename type>
2213void Simulator::InterpretAMOMAX(Instr instr) {
2214 uintx_t addr = get_xreg(instr.rs1());
2215 if ((addr & (sizeof(type) - 1)) != 0) {
2216 FATAL("Misaligned atomic memory operation");
2217 }
2218 std::atomic<type>* atomic = reinterpret_cast<std::atomic<type>*>(addr);
2219 type expected = atomic->load(std::memory_order_relaxed);
2220 type compare = get_xreg(instr.rs2());
2221 type desired;
2222 do {
2223 desired = expected > compare ? expected : compare;
2224 } while (
2225 !atomic->compare_exchange_weak(expected, desired, instr.memory_order()));
2226 set_xreg(instr.rd(), sign_extend(expected));
2227}
2228
2229void Simulator::InterpretAMO32(Instr instr) {
2230 switch (instr.funct5()) {
2231 case LR:
2232 InterpretLR<int32_t>(instr);
2233 break;
2234 case SC:
2235 InterpretSC<int32_t>(instr);
2236 break;
2237 case AMOSWAP:
2238 InterpretAMOSWAP<int32_t>(instr);
2239 break;
2240 case AMOADD:
2241 InterpretAMOADD<int32_t>(instr);
2242 break;
2243 case AMOXOR:
2244 InterpretAMOXOR<int32_t>(instr);
2245 break;
2246 case AMOAND:
2247 InterpretAMOAND<int32_t>(instr);
2248 break;
2249 case AMOOR:
2250 InterpretAMOOR<int32_t>(instr);
2251 break;
2252 case AMOMIN:
2253 InterpretAMOMIN<int32_t>(instr);
2254 break;
2255 case AMOMAX:
2256 InterpretAMOMAX<int32_t>(instr);
2257 break;
2258 case AMOMINU:
2259 InterpretAMOMIN<uint32_t>(instr);
2260 break;
2261 case AMOMAXU:
2262 InterpretAMOMAX<uint32_t>(instr);
2263 break;
2264 default:
2265 IllegalInstruction(instr);
2266 }
2267 pc_ += instr.length();
2268}
2269
2270void Simulator::InterpretAMO64(Instr instr) {
2271 switch (instr.funct5()) {
2272#if XLEN >= 64
2273 case LR:
2274 InterpretLR<int64_t>(instr);
2275 break;
2276 case SC:
2277 InterpretSC<int64_t>(instr);
2278 break;
2279 case AMOSWAP:
2280 InterpretAMOSWAP<int64_t>(instr);
2281 break;
2282 case AMOADD:
2283 InterpretAMOADD<int64_t>(instr);
2284 break;
2285 case AMOXOR:
2286 InterpretAMOXOR<int64_t>(instr);
2287 break;
2288 case AMOAND:
2289 InterpretAMOAND<int64_t>(instr);
2290 break;
2291 case AMOOR:
2292 InterpretAMOOR<int64_t>(instr);
2293 break;
2294 case AMOMIN:
2295 InterpretAMOMIN<int64_t>(instr);
2296 break;
2297 case AMOMAX:
2298 InterpretAMOMAX<int64_t>(instr);
2299 break;
2300 case AMOMINU:
2301 InterpretAMOMIN<uint64_t>(instr);
2302 break;
2303 case AMOMAXU:
2304 InterpretAMOMAX<uint64_t>(instr);
2305 break;
2306#endif // XLEN >= 64
2307 default:
2308 IllegalInstruction(instr);
2309 }
2310 pc_ += instr.length();
2311}
2312
2313void Simulator::InterpretFMADD(Instr instr) {
2314 switch (instr.funct2()) {
2315 case F2_S: {
2316 float rs1 = get_fregs(instr.frs1());
2317 float rs2 = get_fregs(instr.frs2());
2318 float rs3 = get_fregs(instr.frs3());
2319 set_fregs(instr.frd(), (rs1 * rs2) + rs3);
2320 break;
2321 }
2322 case F2_D: {
2323 double rs1 = get_fregd(instr.frs1());
2324 double rs2 = get_fregd(instr.frs2());
2325 double rs3 = get_fregd(instr.frs3());
2326 set_fregd(instr.frd(), (rs1 * rs2) + rs3);
2327 break;
2328 }
2329 default:
2330 IllegalInstruction(instr);
2331 }
2332 pc_ += instr.length();
2333}
2334
2335void Simulator::InterpretFMSUB(Instr instr) {
2336 switch (instr.funct2()) {
2337 case F2_S: {
2338 float rs1 = get_fregs(instr.frs1());
2339 float rs2 = get_fregs(instr.frs2());
2340 float rs3 = get_fregs(instr.frs3());
2341 set_fregs(instr.frd(), (rs1 * rs2) - rs3);
2342 break;
2343 }
2344 case F2_D: {
2345 double rs1 = get_fregd(instr.frs1());
2346 double rs2 = get_fregd(instr.frs2());
2347 double rs3 = get_fregd(instr.frs3());
2348 set_fregd(instr.frd(), (rs1 * rs2) - rs3);
2349 break;
2350 }
2351 default:
2352 IllegalInstruction(instr);
2353 }
2354 pc_ += instr.length();
2355}
2356
2357void Simulator::InterpretFNMSUB(Instr instr) {
2358 switch (instr.funct2()) {
2359 case F2_S: {
2360 float rs1 = get_fregs(instr.frs1());
2361 float rs2 = get_fregs(instr.frs2());
2362 float rs3 = get_fregs(instr.frs3());
2363 set_fregs(instr.frd(), -(rs1 * rs2) + rs3);
2364 break;
2365 }
2366 case F2_D: {
2367 double rs1 = get_fregd(instr.frs1());
2368 double rs2 = get_fregd(instr.frs2());
2369 double rs3 = get_fregd(instr.frs3());
2370 set_fregd(instr.frd(), -(rs1 * rs2) + rs3);
2371 break;
2372 }
2373 default:
2374 IllegalInstruction(instr);
2375 }
2376 pc_ += instr.length();
2377}
2378
2379void Simulator::InterpretFNMADD(Instr instr) {
2380 switch (instr.funct2()) {
2381 case F2_S: {
2382 float rs1 = get_fregs(instr.frs1());
2383 float rs2 = get_fregs(instr.frs2());
2384 float rs3 = get_fregs(instr.frs3());
2385 set_fregs(instr.frd(), -(rs1 * rs2) - rs3);
2386 break;
2387 }
2388 case F2_D: {
2389 double rs1 = get_fregd(instr.frs1());
2390 double rs2 = get_fregd(instr.frs2());
2391 double rs3 = get_fregd(instr.frs3());
2392 set_fregd(instr.frd(), -(rs1 * rs2) - rs3);
2393 break;
2394 }
2395 default:
2396 IllegalInstruction(instr);
2397 }
2398 pc_ += instr.length();
2399}
2400
2401// "For the purposes of these instructions only, the value −0.0 is considered to
2402// be less than the value +0.0. If both inputs are NaNs, the result is the
2403// canonical NaN. If only one operand is a NaN, the result is the non-NaN
2404// operand."
2405static double rv_fmin(double x, double y) {
2406 if (isnan(x) && isnan(y)) return std::numeric_limits<double>::quiet_NaN();
2407 if (isnan(x)) return y;
2408 if (isnan(y)) return x;
2409 if (x == y) return signbit(x) ? x : y;
2410 return fmin(x, y);
2411}
2412
2413static double rv_fmax(double x, double y) {
2414 if (isnan(x) && isnan(y)) return std::numeric_limits<double>::quiet_NaN();
2415 if (isnan(x)) return y;
2416 if (isnan(y)) return x;
2417 if (x == y) return signbit(x) ? y : x;
2418 return fmax(x, y);
2419}
2420
2421static float rv_fminf(float x, float y) {
2422 if (isnan(x) && isnan(y)) return std::numeric_limits<float>::quiet_NaN();
2423 if (isnan(x)) return y;
2424 if (isnan(y)) return x;
2425 if (x == y) return signbit(x) ? x : y;
2426 return fminf(x, y);
2427}
2428
2429static float rv_fmaxf(float x, float y) {
2430 if (isnan(x) && isnan(y)) return std::numeric_limits<float>::quiet_NaN();
2431 if (isnan(x)) return y;
2432 if (isnan(y)) return x;
2433 if (x == y) return signbit(x) ? y : x;
2434 return fmaxf(x, y);
2435}
2436
2437static bool is_quiet(float x) {
2438 // Warning: This is true on Intel/ARM, but not everywhere.
2439 return (bit_cast<uint32_t>(x) & (static_cast<uint32_t>(1) << 22)) != 0;
2440}
2441
2442static uintx_t fclass(float x) {
2443 ASSERT(!is_quiet(std::numeric_limits<float>::signaling_NaN()));
2444 ASSERT(is_quiet(std::numeric_limits<float>::quiet_NaN()));
2445
2446 switch (fpclassify(x)) {
2447 case FP_INFINITE:
2448 return signbit(x) ? kFClassNegInfinity : kFClassPosInfinity;
2449 case FP_NAN:
2450 return is_quiet(x) ? kFClassQuietNan : kFClassSignallingNan;
2451 case FP_ZERO:
2452 return signbit(x) ? kFClassNegZero : kFClassPosZero;
2453 case FP_SUBNORMAL:
2454 return signbit(x) ? kFClassNegSubnormal : kFClassPosSubnormal;
2455 case FP_NORMAL:
2456 return signbit(x) ? kFClassNegNormal : kFClassPosNormal;
2457 default:
2458 UNREACHABLE();
2459 return 0;
2460 }
2461}
2462
2463static bool is_quiet(double x) {
2464 // Warning: This is true on Intel/ARM, but not everywhere.
2465 return (bit_cast<uint64_t>(x) & (static_cast<uint64_t>(1) << 51)) != 0;
2466}
2467
2468static uintx_t fclass(double x) {
2469 ASSERT(!is_quiet(std::numeric_limits<double>::signaling_NaN()));
2470 ASSERT(is_quiet(std::numeric_limits<double>::quiet_NaN()));
2471
2472 switch (fpclassify(x)) {
2473 case FP_INFINITE:
2474 return signbit(x) ? kFClassNegInfinity : kFClassPosInfinity;
2475 case FP_NAN:
2476 return is_quiet(x) ? kFClassQuietNan : kFClassSignallingNan;
2477 case FP_ZERO:
2478 return signbit(x) ? kFClassNegZero : kFClassPosZero;
2479 case FP_SUBNORMAL:
2480 return signbit(x) ? kFClassNegSubnormal : kFClassPosSubnormal;
2481 case FP_NORMAL:
2482 return signbit(x) ? kFClassNegNormal : kFClassPosNormal;
2483 default:
2484 UNREACHABLE();
2485 return 0;
2486 }
2487}
2488
2489static float roundevenf(float x) {
2490 float rounded = roundf(x);
2491 if (fabsf(x - rounded) == 0.5f) { // Tie
2492 if (fmodf(rounded, 2) != 0) { // Not even
2493 if (rounded > 0.0f) {
2494 rounded -= 1.0f;
2495 } else {
2496 rounded += 1.0f;
2497 }
2498 ASSERT(fmodf(rounded, 2) == 0);
2499 }
2500 }
2501 return rounded;
2502}
2503
2504static double roundeven(double x) {
2505 double rounded = round(x);
2506 if (fabs(x - rounded) == 0.5f) { // Tie
2507 if (fmod(rounded, 2) != 0) { // Not even
2508 if (rounded > 0.0f) {
2509 rounded -= 1.0f;
2510 } else {
2511 rounded += 1.0f;
2512 }
2513 ASSERT(fmod(rounded, 2) == 0);
2514 }
2515 }
2516 return rounded;
2517}
2518
2519static float Round(float x, RoundingMode rounding) {
2520 switch (rounding) {
2521 case RNE: // Round to Nearest, ties to Even
2522 return roundevenf(x);
2523 case RTZ: // Round towards Zero
2524 return truncf(x);
2525 case RDN: // Round Down (toward negative infinity)
2526 return floorf(x);
2527 case RUP: // Round Up (toward positive infinity)
2528 return ceilf(x);
2529 case RMM: // Round to nearest, ties to Max Magnitude
2530 return roundf(x);
2531 case DYN: // Dynamic rounding mode
2532 UNIMPLEMENTED();
2533 default:
2534 FATAL("Invalid rounding mode");
2535 }
2536}
2537
2538static double Round(double x, RoundingMode rounding) {
2539 switch (rounding) {
2540 case RNE: // Round to Nearest, ties to Even
2541 return roundeven(x);
2542 case RTZ: // Round towards Zero
2543 return trunc(x);
2544 case RDN: // Round Down (toward negative infinity)
2545 return floor(x);
2546 case RUP: // Round Up (toward positive infinity)
2547 return ceil(x);
2548 case RMM: // Round to nearest, ties to Max Magnitude
2549 return round(x);
2550 case DYN: // Dynamic rounding mode
2551 UNIMPLEMENTED();
2552 default:
2553 FATAL("Invalid rounding mode");
2554 }
2555}
2556
2557static int32_t fcvtws(float x, RoundingMode rounding) {
2558 if (x < static_cast<float>(kMinInt32)) {
2559 return kMinInt32; // Negative infinity.
2560 }
2561 if (x < static_cast<float>(kMaxInt32)) {
2562 return static_cast<int32_t>(Round(x, rounding));
2563 }
2564 return kMaxInt32; // Positive infinity, NaN.
2565}
2566
2567static uint32_t fcvtwus(float x, RoundingMode rounding) {
2568 if (x < static_cast<float>(0)) {
2569 return 0; // Negative infinity.
2570 }
2571 if (x < static_cast<float>(kMaxUint32)) {
2572 return static_cast<uint32_t>(Round(x, rounding));
2573 }
2574 return kMaxUint32; // Positive infinity, NaN.
2575}
2576
2577#if XLEN >= 64
2578static int64_t fcvtls(float x, RoundingMode rounding) {
2579 if (x < static_cast<float>(kMinInt64)) {
2580 return kMinInt64; // Negative infinity.
2581 }
2582 if (x < static_cast<float>(kMaxInt64)) {
2583 return static_cast<int64_t>(Round(x, rounding));
2584 }
2585 return kMaxInt64; // Positive infinity, NaN.
2586}
2587
2588static uint64_t fcvtlus(float x, RoundingMode rounding) {
2589 if (x < static_cast<float>(0.0)) {
2590 return 0; // Negative infinity.
2591 }
2592 if (x < static_cast<float>(kMaxUint64)) {
2593 return static_cast<uint64_t>(Round(x, rounding));
2594 }
2595 return kMaxUint64; // Positive infinity, NaN.
2596}
2597#endif // XLEN >= 64
2598
2599static int32_t fcvtwd(double x, RoundingMode rounding) {
2600 if (x < static_cast<double>(kMinInt32)) {
2601 return kMinInt32; // Negative infinity.
2602 }
2603 if (x < static_cast<double>(kMaxInt32)) {
2604 return static_cast<int32_t>(Round(x, rounding));
2605 }
2606 return kMaxInt32; // Positive infinity, NaN.
2607}
2608
2609static uint32_t fcvtwud(double x, RoundingMode rounding) {
2610 if (x < static_cast<double>(0)) {
2611 return 0; // Negative infinity.
2612 }
2613 if (x < static_cast<double>(kMaxUint32)) {
2614 return static_cast<uint32_t>(Round(x, rounding));
2615 }
2616 return kMaxUint32; // Positive infinity, NaN.
2617}
2618
2619#if XLEN >= 64
2620static int64_t fcvtld(double x, RoundingMode rounding) {
2621 if (x < static_cast<double>(kMinInt64)) {
2622 return kMinInt64; // Negative infinity.
2623 }
2624 if (x < static_cast<double>(kMaxInt64)) {
2625 return static_cast<int64_t>(Round(x, rounding));
2626 }
2627 return kMaxInt64; // Positive infinity, NaN.
2628}
2629
2630static uint64_t fcvtlud(double x, RoundingMode rounding) {
2631 if (x < static_cast<double>(0.0)) {
2632 return 0; // Negative infinity.
2633 }
2634 if (x < static_cast<double>(kMaxUint64)) {
2635 return static_cast<uint64_t>(Round(x, rounding));
2636 }
2637 return kMaxUint64; // Positive infinity, NaN.
2638}
2639#endif // XLEN >= 64
2640
2641void Simulator::InterpretOPFP(Instr instr) {
2642 switch (instr.funct7()) {
2643 case FADDS: {
2644 float rs1 = get_fregs(instr.frs1());
2645 float rs2 = get_fregs(instr.frs2());
2646 set_fregs(instr.frd(), rs1 + rs2);
2647 break;
2648 }
2649 case FSUBS: {
2650 float rs1 = get_fregs(instr.frs1());
2651 float rs2 = get_fregs(instr.frs2());
2652 set_fregs(instr.frd(), rs1 - rs2);
2653 break;
2654 }
2655 case FMULS: {
2656 float rs1 = get_fregs(instr.frs1());
2657 float rs2 = get_fregs(instr.frs2());
2658 set_fregs(instr.frd(), rs1 * rs2);
2659 break;
2660 }
2661 case FDIVS: {
2662 float rs1 = get_fregs(instr.frs1());
2663 float rs2 = get_fregs(instr.frs2());
2664 set_fregs(instr.frd(), rs1 / rs2);
2665 break;
2666 }
2667 case FSQRTS: {
2668 float rs1 = get_fregs(instr.frs1());
2669 set_fregs(instr.frd(), sqrtf(rs1));
2670 break;
2671 }
2672 case FSGNJS: {
2673 const uint32_t kSignMask = static_cast<uint32_t>(1) << 31;
2674 uint32_t rs1 = bit_cast<uint32_t>(get_fregs(instr.frs1()));
2675 uint32_t rs2 = bit_cast<uint32_t>(get_fregs(instr.frs2()));
2676 uint32_t result;
2677 switch (instr.funct3()) {
2678 case J:
2679 result = (rs1 & ~kSignMask) | (rs2 & kSignMask);
2680 break;
2681 case JN:
2682 result = (rs1 & ~kSignMask) | (~rs2 & kSignMask);
2683 break;
2684 case JX:
2685 result = (rs1 & ~kSignMask) | ((rs1 ^ rs2) & kSignMask);
2686 break;
2687 default:
2688 IllegalInstruction(instr);
2689 }
2690 set_fregs(instr.frd(), bit_cast<float>(result));
2691 break;
2692 }
2693 case FMINMAXS: {
2694 float rs1 = get_fregs(instr.frs1());
2695 float rs2 = get_fregs(instr.frs2());
2696 switch (instr.funct3()) {
2697 case FMIN:
2698 set_fregs(instr.frd(), rv_fminf(rs1, rs2));
2699 break;
2700 case FMAX:
2701 set_fregs(instr.frd(), rv_fmaxf(rs1, rs2));
2702 break;
2703 default:
2704 IllegalInstruction(instr);
2705 }
2706 break;
2707 }
2708 case FCMPS: {
2709 float rs1 = get_fregs(instr.frs1());
2710 float rs2 = get_fregs(instr.frs2());
2711 switch (instr.funct3()) {
2712 case FEQ:
2713 set_xreg(instr.rd(), rs1 == rs2 ? 1 : 0);
2714 break;
2715 case FLT:
2716 set_xreg(instr.rd(), rs1 < rs2 ? 1 : 0);
2717 break;
2718 case FLE:
2719 set_xreg(instr.rd(), rs1 <= rs2 ? 1 : 0);
2720 break;
2721 default:
2722 IllegalInstruction(instr);
2723 }
2724 break;
2725 }
2726 case FCLASSS: // = FMVXW
2727 switch (instr.funct3()) {
2728 case 1:
2729 // fclass.s
2730 set_xreg(instr.rd(), fclass(get_fregs(instr.frs1())));
2731 break;
2732 case 0:
2733 // fmv.x.s
2734 set_xreg(instr.rd(),
2735 sign_extend(bit_cast<int32_t>(get_fregs(instr.frs1()))));
2736 break;
2737 default:
2738 IllegalInstruction(instr);
2739 }
2740 break;
2741 case FCVTintS:
2742 switch (static_cast<FcvtRs2>(instr.rs2())) {
2743 case W:
2744 set_xreg(instr.rd(), sign_extend(fcvtws(get_fregs(instr.frs1()),
2745 instr.rounding())));
2746 break;
2747 case WU:
2748 set_xreg(instr.rd(), sign_extend(fcvtwus(get_fregs(instr.frs1()),
2749 instr.rounding())));
2750 break;
2751#if XLEN >= 64
2752 case L:
2753 set_xreg(instr.rd(), sign_extend(fcvtls(get_fregs(instr.frs1()),
2754 instr.rounding())));
2755 break;
2756 case LU:
2757 set_xreg(instr.rd(), sign_extend(fcvtlus(get_fregs(instr.frs1()),
2758 instr.rounding())));
2759 break;
2760#endif // XLEN >= 64
2761 default:
2762 IllegalInstruction(instr);
2763 }
2764 break;
2765 case FCVTSint:
2766 switch (static_cast<FcvtRs2>(instr.rs2())) {
2767 case W:
2768 set_fregs(
2769 instr.frd(),
2770 static_cast<float>(static_cast<int32_t>(get_xreg(instr.rs1()))));
2771 break;
2772 case WU:
2773 set_fregs(
2774 instr.frd(),
2775 static_cast<float>(static_cast<uint32_t>(get_xreg(instr.rs1()))));
2776 break;
2777#if XLEN >= 64
2778 case L:
2779 set_fregs(
2780 instr.frd(),
2781 static_cast<float>(static_cast<int64_t>(get_xreg(instr.rs1()))));
2782 break;
2783 case LU:
2784 set_fregs(
2785 instr.frd(),
2786 static_cast<float>(static_cast<uint64_t>(get_xreg(instr.rs1()))));
2787 break;
2788#endif // XLEN >= 64
2789 default:
2790 IllegalInstruction(instr);
2791 }
2792 break;
2793 case FMVWX:
2794 set_fregs(instr.frd(),
2795 bit_cast<float>(static_cast<int32_t>(get_xreg(instr.rs1()))));
2796 break;
2797 case FADDD: {
2798 double rs1 = get_fregd(instr.frs1());
2799 double rs2 = get_fregd(instr.frs2());
2800 set_fregd(instr.frd(), rs1 + rs2);
2801 break;
2802 }
2803 case FSUBD: {
2804 double rs1 = get_fregd(instr.frs1());
2805 double rs2 = get_fregd(instr.frs2());
2806 set_fregd(instr.frd(), rs1 - rs2);
2807 break;
2808 }
2809 case FMULD: {
2810 double rs1 = get_fregd(instr.frs1());
2811 double rs2 = get_fregd(instr.frs2());
2812 set_fregd(instr.frd(), rs1 * rs2);
2813 break;
2814 }
2815 case FDIVD: {
2816 double rs1 = get_fregd(instr.frs1());
2817 double rs2 = get_fregd(instr.frs2());
2818 set_fregd(instr.frd(), rs1 / rs2);
2819 break;
2820 }
2821 case FSQRTD: {
2822 double rs1 = get_fregd(instr.frs1());
2823 set_fregd(instr.frd(), sqrt(rs1));
2824 break;
2825 }
2826 case FSGNJD: {
2827 const uint64_t kSignMask = static_cast<uint64_t>(1) << 63;
2828 uint64_t rs1 = bit_cast<uint64_t>(get_fregd(instr.frs1()));
2829 uint64_t rs2 = bit_cast<uint64_t>(get_fregd(instr.frs2()));
2830 uint64_t result;
2831 switch (instr.funct3()) {
2832 case J:
2833 result = (rs1 & ~kSignMask) | (rs2 & kSignMask);
2834 break;
2835 case JN:
2836 result = (rs1 & ~kSignMask) | (~rs2 & kSignMask);
2837 break;
2838 case JX:
2839 result = (rs1 & ~kSignMask) | ((rs1 ^ rs2) & kSignMask);
2840 break;
2841 default:
2842 IllegalInstruction(instr);
2843 }
2844 set_fregd(instr.frd(), bit_cast<double>(result));
2845 break;
2846 }
2847 case FMINMAXD: {
2848 double rs1 = get_fregd(instr.frs1());
2849 double rs2 = get_fregd(instr.frs2());
2850 switch (instr.funct3()) {
2851 case FMIN:
2852 set_fregd(instr.frd(), rv_fmin(rs1, rs2));
2853 break;
2854 case FMAX:
2855 set_fregd(instr.frd(), rv_fmax(rs1, rs2));
2856 break;
2857 default:
2858 IllegalInstruction(instr);
2859 }
2860 break;
2861 }
2862 case FCVTS: {
2863 switch (static_cast<FcvtRs2>(instr.rs2())) {
2864 case 1:
2865 set_fregs(instr.frd(), static_cast<float>(get_fregd(instr.frs1())));
2866 break;
2867 default:
2868 IllegalInstruction(instr);
2869 }
2870 break;
2871 }
2872 case FCVTD: {
2873 switch (static_cast<FcvtRs2>(instr.rs2())) {
2874 case 0:
2875 set_fregd(instr.frd(), static_cast<double>(get_fregs(instr.frs1())));
2876 break;
2877 default:
2878 IllegalInstruction(instr);
2879 }
2880 break;
2881 }
2882
2883 case FCMPD: {
2884 double rs1 = get_fregd(instr.frs1());
2885 double rs2 = get_fregd(instr.frs2());
2886 switch (instr.funct3()) {
2887 case FEQ:
2888 set_xreg(instr.rd(), rs1 == rs2 ? 1 : 0);
2889 break;
2890 case FLT:
2891 set_xreg(instr.rd(), rs1 < rs2 ? 1 : 0);
2892 break;
2893 case FLE:
2894 set_xreg(instr.rd(), rs1 <= rs2 ? 1 : 0);
2895 break;
2896 default:
2897 IllegalInstruction(instr);
2898 }
2899 break;
2900 }
2901 case FCLASSD: // = FMVXD
2902 switch (instr.funct3()) {
2903 case 1:
2904 // fclass.d
2905 set_xreg(instr.rd(), fclass(get_fregd(instr.frs1())));
2906 break;
2907#if XLEN >= 64
2908 case 0:
2909 // fmv.x.d
2910 set_xreg(instr.rd(), bit_cast<int64_t>(get_fregd(instr.frs1())));
2911 break;
2912#endif // XLEN >= 64
2913 default:
2914 IllegalInstruction(instr);
2915 }
2916 break;
2917 case FCVTintD:
2918 switch (static_cast<FcvtRs2>(instr.rs2())) {
2919 case W:
2920 set_xreg(instr.rd(), sign_extend(fcvtwd(get_fregd(instr.frs1()),
2921 instr.rounding())));
2922 break;
2923 case WU:
2924 set_xreg(instr.rd(), sign_extend(fcvtwud(get_fregd(instr.frs1()),
2925 instr.rounding())));
2926 break;
2927#if XLEN >= 64
2928 case L:
2929 set_xreg(instr.rd(), sign_extend(fcvtld(get_fregd(instr.frs1()),
2930 instr.rounding())));
2931 break;
2932 case LU:
2933 set_xreg(instr.rd(), sign_extend(fcvtlud(get_fregd(instr.frs1()),
2934 instr.rounding())));
2935 break;
2936#endif // XLEN >= 64
2937 default:
2938 IllegalInstruction(instr);
2939 }
2940 break;
2941 case FCVTDint:
2942 switch (static_cast<FcvtRs2>(instr.rs2())) {
2943 case W:
2944 set_fregd(
2945 instr.frd(),
2946 static_cast<double>(static_cast<int32_t>(get_xreg(instr.rs1()))));
2947 break;
2948 case WU:
2949 set_fregd(instr.frd(), static_cast<double>(static_cast<uint32_t>(
2950 get_xreg(instr.rs1()))));
2951 break;
2952#if XLEN >= 64
2953 case L:
2954 set_fregd(
2955 instr.frd(),
2956 static_cast<double>(static_cast<int64_t>(get_xreg(instr.rs1()))));
2957 break;
2958 case LU:
2959 set_fregd(instr.frd(), static_cast<double>(static_cast<uint64_t>(
2960 get_xreg(instr.rs1()))));
2961 break;
2962#endif // XLEN >= 64
2963 default:
2964 IllegalInstruction(instr);
2965 }
2966 break;
2967#if XLEN >= 64
2968 case FMVDX:
2969 set_fregd(instr.frd(), bit_cast<double>(get_xreg(instr.rs1())));
2970 break;
2971#endif // XLEN >= 64
2972 default:
2973 IllegalInstruction(instr);
2974 }
2975 pc_ += instr.length();
2976}
2977
2978void Simulator::InterpretEBREAK(Instr instr) {
2979 PrintRegisters();
2980 PrintStack();
2981 FATAL("Encountered EBREAK");
2982}
2983
2984void Simulator::InterpretEBREAK(CInstr instr) {
2985 PrintRegisters();
2986 PrintStack();
2987 FATAL("Encountered EBREAK");
2988}
2989
2990void Simulator::IllegalInstruction(Instr instr) {
2991 PrintRegisters();
2992 PrintStack();
2993 FATAL("Illegal instruction: 0x%08x", instr.encoding());
2994}
2995
2996void Simulator::IllegalInstruction(CInstr instr) {
2997 PrintRegisters();
2998 PrintStack();
2999 FATAL("Illegal instruction: 0x%04x", instr.encoding());
3000}
3001
3002template <typename type>
3003type Simulator::MemoryRead(uintx_t addr, Register base) {
3004#if defined(DEBUG)
3005 if ((base == SP) || (base == FP)) {
3006 if ((addr + sizeof(type) > stack_base()) || (addr < get_xreg(SP))) {
3007 PrintRegisters();
3008 PrintStack();
3009 FATAL("Out-of-bounds stack access");
3010 }
3011 } else {
3012 const uintx_t kPageSize = 16 * KB;
3013 if ((addr < kPageSize) || (addr + sizeof(type) >= ~kPageSize)) {
3014 PrintRegisters();
3015 PrintStack();
3016 FATAL("Bad memory access");
3017 }
3018 }
3019#endif
3020 return LoadUnaligned(reinterpret_cast<type*>(addr));
3021}
3022
3023template <typename type>
3024void Simulator::MemoryWrite(uintx_t addr, type value, Register base) {
3025#if defined(DEBUG)
3026 if ((base == SP) || (base == FP)) {
3027 if ((addr + sizeof(type) > stack_base()) || (addr < get_xreg(SP))) {
3028 PrintRegisters();
3029 PrintStack();
3030 FATAL("Out-of-bounds stack access");
3031 }
3032 } else {
3033 const uintx_t kPageSize = 16 * KB;
3034 if ((addr < kPageSize) || (addr + sizeof(type) >= ~kPageSize)) {
3035 PrintRegisters();
3036 PrintStack();
3037 FATAL("Bad memory access");
3038 }
3039 }
3040#endif
3041 StoreUnaligned(reinterpret_cast<type*>(addr), value);
3042}
3043
3044enum ControlStatusRegister {
3045 fflags = 0x001,
3046 frm = 0x002,
3047 fcsr = 0x003,
3048 cycle = 0xC00,
3049 time = 0xC01,
3050 instret = 0xC02,
3051#if XLEN == 32
3052 cycleh = 0xC80,
3053 timeh = 0xC81,
3054 instreth = 0xC82,
3055#endif
3056};
3057
3058intx_t Simulator::CSRRead(uint16_t csr) {
3059 switch (csr) {
3060 case fcsr:
3061 return fcsr_;
3062 case cycle:
3063 return instret_ / 2;
3064 case time:
3065 return 0;
3066 case instret:
3067 return instret_;
3068#if XLEN == 32
3069 case cycleh:
3070 return (instret_ / 2) >> 32;
3071 case timeh:
3072 return 0;
3073 case instreth:
3074 return instret_ >> 32;
3075#endif
3076 default:
3077 FATAL("Unknown CSR: %d", csr);
3078 }
3079}
3080
3081void Simulator::CSRWrite(uint16_t csr, intx_t value) {
3082 UNIMPLEMENTED();
3083}
3084
3085void Simulator::CSRSet(uint16_t csr, intx_t mask) {
3086 UNIMPLEMENTED();
3087}
3088
3089void Simulator::CSRClear(uint16_t csr, intx_t mask) {
3090 UNIMPLEMENTED();
3091}
3092
3093} // namespace dart
3094
3095#endif // !defined(USING_SIMULATOR)
3096
3097#endif // defined TARGET_ARCH_RISCV
static bool compare(const SkBitmap &ref, const SkIRect &iref, const SkBitmap &test, const SkIRect &itest)
Definition BlurTest.cpp:100
int count
static void round(SkPoint *p)
static const double J
#define COUNT(T)
@ ROTATE
SweepLineTestingPeer TP
#define W
Definition aaa.cpp:17
#define RA(width, name,...)
#define UNREACHABLE()
Definition assert.h:248
constexpr SkScalar SH
Definition beziers.cpp:21
static Isolate * Current()
Definition isolate.h:939
static uword RedirectExternalReference(uword function, CallKind call_kind, int argument_count)
static Simulator * Current()
static void Init()
static uword FunctionForRedirect(uword redirect)
#define LR
#define THR_Print(format,...)
Definition log.h:20
struct _Dart_NativeArguments * Dart_NativeArguments
Definition dart_api.h:3010
void(* Dart_NativeFunction)(Dart_NativeArguments arguments)
Definition dart_api.h:3198
#define UNIMPLEMENTED
#define ASSERT(E)
double frame
Definition examples.cpp:31
static bool b
struct MyStruct a[10]
#define FATAL(error)
static const uint8_t buffer[]
GAsyncResult * result
uint32_t * target
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
Dart_NativeFunction function
Definition fuchsia.cc:51
int argument_count
Definition fuchsia.cc:52
static float max(float r, float g, float b)
Definition hsl.cpp:49
static float min(float r, float g, float b)
Definition hsl.cpp:48
double y
double x
const GrXPFactory * Get(SkBlendMode mode)
link(from_root, to_root)
Definition dart_pkg.py:44
constexpr int64_t kMaxInt64
Definition globals.h:486
constexpr int64_t kMinInt64
Definition globals.h:485
bool IsCInstruction(uint16_t parcel)
constexpr int32_t kMinInt32
Definition globals.h:482
constexpr uint64_t kMaxUint64
Definition globals.h:487
constexpr uint32_t kMaxUint32
Definition globals.h:484
@ kHeapObjectTag
constexpr intptr_t KB
Definition globals.h:528
uintptr_t uword
Definition globals.h:501
const uint32_t fp
@ kNumberOfCpuRegisters
const int kNumberOfFpuRegisters
const RegList kAbiPreservedCpuRegs
intx_t sign_extend(int32_t x)
@ kFClassNegSubnormal
@ kFClassPosInfinity
@ kFClassQuietNan
@ kFClassSignallingNan
@ kFClassNegNormal
@ kFClassNegInfinity
@ kFClassPosSubnormal
@ kFClassPosNormal
constexpr int32_t kMaxInt32
Definition globals.h:483
constexpr intptr_t kWordSize
Definition globals.h:509
SIN Vec< N, float > trunc(const Vec< N, float > &x)
Definition SkVx.h:704
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition SkVx.h:706
SIN Vec< N, float > floor(const Vec< N, float > &x)
Definition SkVx.h:703
SIN Vec< N, float > ceil(const Vec< N, float > &x)
Definition SkVx.h:702
SkScalar w
#define LIKELY(cond)
Definition globals.h:260
#define Px
Definition globals.h:410
#define Pd64
Definition globals.h:416
#define Px64
Definition globals.h:418
#define Pd
Definition globals.h:408
Point offset
constexpr SkScalar SW
Definition strokes.cpp:37
#define NO_SANITIZE_UNDEFINED(check)
#define LH
#define OFFSET_OF(type, field)
Definition globals.h:138