| // Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | #ifndef RUNTIME_VM_SIMULATOR_RISCV_H_ | 
 | #define RUNTIME_VM_SIMULATOR_RISCV_H_ | 
 |  | 
 | #ifndef RUNTIME_VM_SIMULATOR_H_ | 
 | #error Do not include simulator_riscv.h directly; use simulator.h. | 
 | #endif | 
 |  | 
 | #include "vm/constants.h" | 
 | #include "vm/random.h" | 
 | #include "vm/simulator_memory.h" | 
 |  | 
 | namespace dart { | 
 |  | 
 | class Isolate; | 
 | class Mutex; | 
 | class SimulatorSetjmpBuffer; | 
 | class Thread; | 
 |  | 
 | // TODO(riscv): Dynamic rounding mode and other FSCR state. | 
 | class Simulator { | 
 |  public: | 
 |   static constexpr uword kSimulatorStackUnderflowSize = 64; | 
 |  | 
 |   Simulator(); | 
 |   ~Simulator(); | 
 |  | 
 |   static Simulator* Current(); | 
 |  | 
 |   intx_t CallX(intx_t function, | 
 |                intx_t arg0 = 0, | 
 |                intx_t arg1 = 0, | 
 |                intx_t arg2 = 0, | 
 |                intx_t arg3 = 0) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_xreg(A0, arg0); | 
 |     set_xreg(A1, arg1); | 
 |     set_xreg(A2, arg2); | 
 |     set_xreg(A3, arg3); | 
 |     RunCall(function, &preserved); | 
 |     return get_xreg(A0); | 
 |   } | 
 |  | 
 |   intx_t CallI(intx_t function, double arg0, double arg1 = 0.0) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_fregd(FA0, arg0); | 
 |     set_fregd(FA1, arg1); | 
 |     RunCall(function, &preserved); | 
 |     return get_xreg(A0); | 
 |   } | 
 |   intx_t CallI(intx_t function, float arg0, float arg1 = 0.0f) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_fregs(FA0, arg0); | 
 |     set_fregs(FA1, arg1); | 
 |     RunCall(function, &preserved); | 
 |     return get_xreg(A0); | 
 |   } | 
 |  | 
 |   int64_t CallI64(intx_t function, double arg0, double arg1 = 0.0) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_fregd(FA0, arg0); | 
 |     set_fregd(FA1, arg1); | 
 |     RunCall(function, &preserved); | 
 | #if XLEN == 32 | 
 |     uint64_t hi = static_cast<uint32_t>(get_xreg(A1)); | 
 |     uint64_t lo = static_cast<uint32_t>(get_xreg(A0)); | 
 |     return (hi << 32) | lo; | 
 | #else | 
 |     return get_xreg(A0); | 
 | #endif | 
 |   } | 
 |  | 
 |   double CallD(intx_t function, intx_t arg0, intx_t arg1 = 0) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_xreg(A0, arg0); | 
 |     set_xreg(A1, arg1); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregd(FA0); | 
 |   } | 
 | #if XLEN == 32 | 
 |   double CallD(intx_t function, int64_t arg0) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_xreg(A0, static_cast<uint64_t>(arg0) & 0xFFFFFFFF); | 
 |     set_xreg(A1, static_cast<uint64_t>(arg0) >> 32); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregd(FA0); | 
 |   } | 
 | #endif | 
 |   double CallD(intx_t function, | 
 |                double arg0, | 
 |                double arg1 = 0.0, | 
 |                double arg2 = 0.0) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_fregd(FA0, arg0); | 
 |     set_fregd(FA1, arg1); | 
 |     set_fregd(FA2, arg2); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregd(FA0); | 
 |   } | 
 |   double CallD(intx_t function, intx_t arg0, double arg1) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_xreg(A0, arg0); | 
 |     set_fregd(FA0, arg1); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregd(FA0); | 
 |   } | 
 |   double CallD(intx_t function, float arg0) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_fregs(FA0, arg0); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregd(FA0); | 
 |   } | 
 |  | 
 |   float CallF(intx_t function, intx_t arg0, intx_t arg1 = 0) { | 
 |     PreservedRegisters preserved; | 
 |     SavePreservedRegisters(&preserved); | 
 |     set_xreg(A0, arg0); | 
 |     set_xreg(A1, arg1); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregs(FA0); | 
 |   } | 
 |   float CallF(intx_t function, | 
 |               float arg0, | 
 |               float arg1 = 0.0f, | 
 |               float arg2 = 0.0f) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_fregs(FA0, arg0); | 
 |     set_fregs(FA1, arg1); | 
 |     set_fregs(FA2, arg2); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregs(FA0); | 
 |   } | 
 |   float CallF(intx_t function, intx_t arg0, float arg1) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_xreg(A0, arg0); | 
 |     set_fregs(FA0, arg1); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregs(FA0); | 
 |   } | 
 |   float CallF(intx_t function, double arg0) { | 
 |     PreservedRegisters preserved; | 
 |     PrepareCall(&preserved); | 
 |     set_fregd(FA0, arg0); | 
 |     RunCall(function, &preserved); | 
 |     return get_fregs(FA0); | 
 |   } | 
 |  | 
 |   // Dart generally calls into generated code with 4 parameters. This is a | 
 |   // convenience function, which sets up the simulator state and grabs the | 
 |   // result on return. The return value is A0. The parameters are placed in | 
 |   // A0-3. | 
 |   int64_t Call(intx_t entry, | 
 |                intx_t parameter0, | 
 |                intx_t parameter1, | 
 |                intx_t parameter2, | 
 |                intx_t parameter3, | 
 |                bool fp_return = false, | 
 |                bool fp_args = false); | 
 |  | 
 |   // Runtime and native call support. | 
 |   enum CallKind { | 
 |     kRuntimeCall, | 
 |     kLeafRuntimeCall, | 
 |     kLeafFloatRuntimeCall, | 
 |     kNativeCallWrapper | 
 |   }; | 
 |   static uword RedirectExternalReference(uword function, | 
 |                                          CallKind call_kind, | 
 |                                          int argument_count); | 
 |  | 
 |   static uword FunctionForRedirect(uword redirect); | 
 |  | 
 |   void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread); | 
 |  | 
 |   uintx_t get_register(Register rs) const { return get_xreg(rs); } | 
 |   uintx_t get_pc() const { return pc_; } | 
 |   uintx_t get_sp() const { return get_xreg(SP); } | 
 |   uintx_t get_fp() const { return get_xreg(FP); } | 
 |   uintx_t get_lr() const { return get_xreg(RA); } | 
 |   void PrintRegisters(); | 
 |   void PrintStack(); | 
 |  | 
 |   // High address. | 
 |   uword stack_base() const { return stack_base_; } | 
 |   // Limit for StackOverflowError. | 
 |   uword overflow_stack_limit() const { return overflow_stack_limit_; } | 
 |   // Low address. | 
 |   uword stack_limit() const { return stack_limit_; } | 
 |  | 
 |   // Accessor to the instruction counter. | 
 |   uint64_t get_icount() const { return instret_; } | 
 |  | 
 |   // Call on program start. | 
 |   static void Init(); | 
 |  | 
 |  private: | 
 |   struct PreservedRegisters { | 
 |     uintx_t xregs[kNumberOfCpuRegisters]; | 
 |     double fregs[kNumberOfFpuRegisters]; | 
 |   }; | 
 |   void PrepareCall(PreservedRegisters* preserved); | 
 |   void ClobberVolatileRegisters(); | 
 |   void SavePreservedRegisters(PreservedRegisters* preserved); | 
 |   void CheckPreservedRegisters(PreservedRegisters* preserved); | 
 |   void RunCall(intx_t function, PreservedRegisters* preserved); | 
 |  | 
 |   void Interpret(Instr instr); | 
 |   void Interpret(CInstr instr); | 
 |   void InterpretLUI(Instr instr); | 
 |   void InterpretAUIPC(Instr instr); | 
 |   void InterpretJAL(Instr instr); | 
 |   void InterpretJALR(Instr instr); | 
 |   void InterpretBRANCH(Instr instr); | 
 |   void InterpretLOAD(Instr instr); | 
 |   void InterpretSTORE(Instr instr); | 
 |   void InterpretOPIMM(Instr instr); | 
 |   void InterpretOPIMM32(Instr instr); | 
 |   void InterpretOP(Instr instr); | 
 |   void InterpretOP_0(Instr instr); | 
 |   void InterpretOP_SUB(Instr instr); | 
 |   void InterpretOP_MULDIV(Instr instr); | 
 |   void InterpretOP_SHADD(Instr instr); | 
 |   void InterpretOP_MINMAXCLMUL(Instr instr); | 
 |   void InterpretOP_ROTATE(Instr instr); | 
 |   void InterpretOP_BCLRBEXT(Instr instr); | 
 |   void InterpretOP_CZERO(Instr instr); | 
 |   void InterpretOP32(Instr instr); | 
 |   void InterpretOP32_0(Instr instr); | 
 |   void InterpretOP32_SUB(Instr instr); | 
 |   void InterpretOP32_MULDIV(Instr instr); | 
 |   void InterpretOP32_SHADD(Instr instr); | 
 |   void InterpretOP32_ADDUW(Instr instr); | 
 |   void InterpretOP32_ROTATE(Instr instr); | 
 |   void InterpretMISCMEM(Instr instr); | 
 |   void InterpretSYSTEM(Instr instr); | 
 |   void InterpretECALL(Instr instr); | 
 |   void InterpretEBREAK(Instr instr); | 
 |   void InterpretEBREAK(CInstr instr); | 
 |   void InterpretAMO(Instr instr); | 
 |   void InterpretAMO8(Instr instr); | 
 |   void InterpretAMO16(Instr instr); | 
 |   void InterpretAMO32(Instr instr); | 
 |   void InterpretAMO64(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretLR(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretSC(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOSWAP(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOADD(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOXOR(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOAND(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOOR(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOMIN(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOMAX(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOMINU(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretAMOMAXU(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretLOADORDERED(Instr instr); | 
 |   template <typename type> | 
 |   void InterpretSTOREORDERED(Instr instr); | 
 |   void InterpretLOADFP(Instr instr); | 
 |   void InterpretSTOREFP(Instr instr); | 
 |   void InterpretFMADD(Instr instr); | 
 |   void InterpretFMSUB(Instr instr); | 
 |   void InterpretFNMADD(Instr instr); | 
 |   void InterpretFNMSUB(Instr instr); | 
 |   void InterpretOPFP(Instr instr); | 
 |   DART_NORETURN void IllegalInstruction(Instr instr); | 
 |   DART_NORETURN void IllegalInstruction(CInstr instr); | 
 |  | 
 |   template <typename type> | 
 |   type MemoryRead(uintx_t address, Register base); | 
 |   template <typename type> | 
 |   void MemoryWrite(uintx_t address, type value, Register base); | 
 |  | 
 |   intx_t CSRRead(uint16_t csr); | 
 |   void CSRWrite(uint16_t csr, intx_t value); | 
 |   void CSRSet(uint16_t csr, intx_t mask); | 
 |   void CSRClear(uint16_t csr, intx_t mask); | 
 |  | 
 |   uintx_t get_xreg(Register rs) const { return xregs_[rs]; } | 
 |   void set_xreg(Register rd, uintx_t value) { | 
 |     if (rd != ZR) { | 
 |       xregs_[rd] = value; | 
 |     } | 
 |   } | 
 |  | 
 |   double get_fregd(FRegister rs) const { return fregs_[rs]; } | 
 |   void set_fregd(FRegister rd, double value) { fregs_[rd] = value; } | 
 |  | 
 |   static constexpr uint64_t kNaNBox = 0xFFFFFFFF00000000; | 
 |  | 
 |   float get_fregs_raw(FRegister rs) const { | 
 |     uint64_t bits64 = bit_cast<uint64_t>(fregs_[rs]); | 
 |     uint32_t bits32 = static_cast<uint32_t>(bits64); | 
 |     return bit_cast<float>(bits32); | 
 |   } | 
 |   float get_fregs(FRegister rs) const { | 
 |     uint64_t bits64 = bit_cast<uint64_t>(fregs_[rs]); | 
 |     if ((bits64 & kNaNBox) != kNaNBox) { | 
 |       // When the register value isn't a valid NaN, the canonical NaN is used | 
 |       // instead. | 
 |       return bit_cast<float>(0x7fc00000); | 
 |     } | 
 |     uint32_t bits32 = static_cast<uint32_t>(bits64); | 
 |     return bit_cast<float>(bits32); | 
 |   } | 
 |   void set_fregs(FRegister rd, float value) { | 
 |     uint32_t bits32 = bit_cast<uint32_t>(value); | 
 |     uint64_t bits64 = static_cast<uint64_t>(bits32); | 
 |     bits64 |= kNaNBox; | 
 |     fregs_[rd] = bit_cast<double>(bits64); | 
 |   } | 
 |  | 
 |   // Known bad pc value to ensure that the simulator does not execute | 
 |   // without being properly setup. | 
 |   static constexpr uword kBadLR = -1; | 
 |   // A pc value used to signal the simulator to stop execution.  Generally | 
 |   // the lr is set to this value on transition from native C code to | 
 |   // simulated execution, so that the simulator can "return" to the native | 
 |   // C code. | 
 |   static constexpr uword kEndSimulatingPC = -2; | 
 |  | 
 |   // I state. | 
 |   uintx_t pc_ = 0; | 
 |   uintx_t xregs_[kNumberOfCpuRegisters]; | 
 |   uint64_t instret_ = 0;  // "Instructions retired" - mandatory counter. | 
 |  | 
 |   // A state. | 
 |   uintx_t reserved_address_ = 0; | 
 |   uintx_t reserved_value_ = 0; | 
 |  | 
 |   // F/D state. | 
 |   double fregs_[kNumberOfFpuRegisters]; | 
 |   uint32_t fcsr_ = 0; | 
 |  | 
 |   // Simulator support. | 
 |   char* stack_; | 
 |   uword stack_limit_; | 
 |   uword overflow_stack_limit_; | 
 |   uword stack_base_; | 
 |   Random random_; | 
 |   SimulatorSetjmpBuffer* last_setjmp_buffer_ = nullptr; | 
 |   SimulatorMemory memory_; | 
 |  | 
 |   static bool IsIllegalAddress(uword addr) { return addr < 64 * 1024; } | 
 |  | 
 |   // Executes RISC-V instructions until the PC reaches kEndSimulatingPC. | 
 |   void Execute(); | 
 |   void ExecuteNoTrace(); | 
 |   void ExecuteTrace(); | 
 |  | 
 |   // Returns true if tracing of executed instructions is enabled. | 
 |   bool IsTracingExecution() const; | 
 |  | 
 |   // Longjmp support for exceptions. | 
 |   SimulatorSetjmpBuffer* last_setjmp_buffer() { return last_setjmp_buffer_; } | 
 |   void set_last_setjmp_buffer(SimulatorSetjmpBuffer* buffer) { | 
 |     last_setjmp_buffer_ = buffer; | 
 |   } | 
 |  | 
 |   friend class SimulatorSetjmpBuffer; | 
 |   DISALLOW_COPY_AND_ASSIGN(Simulator); | 
 | }; | 
 |  | 
 | }  // namespace dart | 
 |  | 
 | #endif  // RUNTIME_VM_SIMULATOR_RISCV_H_ |