1 // Copyright 2021 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Copyright(c) 2010 - 2017,
6 // The Regents of the University of California(Regents).All Rights Reserved.
7 //
8 // Redistribution and use in source and binary forms,
9 // with or without modification,
10 // are permitted provided that the following
11 // conditions are met : 1. Redistributions of source code must retain the
12 // above copyright notice, this list of conditions and the following
13 // disclaimer.2. Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer in
15 // the
16 // documentation and /
17 // or
18 // other materials provided with the distribution.3. Neither the name of
19 // the Regents nor the names of its contributors may be used to endorse
20 // or
21 // promote products derived from
22 // this software without specific prior written permission.
23 //
24 // IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
25 // INDIRECT, SPECIAL,
26 // INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
27 // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
28 // EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES,
31 // INCLUDING, BUT NOT LIMITED TO,
32 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
33 // PARTICULAR PURPOSE.THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
34 // IF ANY,
35 // PROVIDED HEREUNDER IS PROVIDED
36 // "AS IS".REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
37 // SUPPORT, UPDATES, ENHANCEMENTS,
38 // OR MODIFICATIONS.
39
40 // The original source code covered by the above license above has been
41 // modified significantly by the v8 project authors.
42
43 // Declares a Simulator for RISC-V instructions if we are not generating a
44 // native RISC-V binary. This Simulator allows us to run and debug RISC-V code
45 // generation on regular desktop machines. V8 calls into generated code via the
46 // GeneratedCode wrapper, which will start execution in the Simulator or
47 // forwards to the real entry on a RISC-V HW platform.
48
49 #ifndef V8_EXECUTION_RISCV64_SIMULATOR_RISCV64_H_
50 #define V8_EXECUTION_RISCV64_SIMULATOR_RISCV64_H_
51
52 // globals.h defines USE_SIMULATOR.
53 #include "src/common/globals.h"
54
55 template <typename T>
Compare(const T & a,const T & b)56 int Compare(const T& a, const T& b) {
57 if (a == b)
58 return 0;
59 else if (a < b)
60 return -1;
61 else
62 return 1;
63 }
64
65 // Returns the negative absolute value of its argument.
66 template <typename T,
67 typename = typename std::enable_if<std::is_signed<T>::value>::type>
Nabs(T a)68 T Nabs(T a) {
69 return a < 0 ? a : -a;
70 }
71
72 #if defined(USE_SIMULATOR)
73 // Running with a simulator.
74
75 #include "src/base/hashmap.h"
76 #include "src/codegen/assembler.h"
77 #include "src/codegen/riscv64/constants-riscv64.h"
78 #include "src/execution/simulator-base.h"
79 #include "src/utils/allocation.h"
80
81 namespace v8 {
82 namespace internal {
83
84 // -----------------------------------------------------------------------------
85 // Utility types and functions for RISCV
86 #ifdef V8_TARGET_ARCH_32_BIT
87 using sreg_t = int32_t;
88 using reg_t = uint32_t;
89 #define xlen 32
90 #elif V8_TARGET_ARCH_64_BIT
91 using sreg_t = int64_t;
92 using reg_t = uint64_t;
93 #define xlen 64
94 #else
95 #error "Cannot detect Riscv's bitwidth"
96 #endif
97
98 #define sext32(x) ((sreg_t)(int32_t)(x))
99 #define zext32(x) ((reg_t)(uint32_t)(x))
100 #define sext_xlen(x) (((sreg_t)(x) << (64 - xlen)) >> (64 - xlen))
101 #define zext_xlen(x) (((reg_t)(x) << (64 - xlen)) >> (64 - xlen))
102
103 #define BIT(n) (0x1LL << n)
104 #define QUIET_BIT_S(nan) (bit_cast<int32_t>(nan) & BIT(22))
105 #define QUIET_BIT_D(nan) (bit_cast<int64_t>(nan) & BIT(51))
isSnan(float fp)106 static inline bool isSnan(float fp) { return !QUIET_BIT_S(fp); }
isSnan(double fp)107 static inline bool isSnan(double fp) { return !QUIET_BIT_D(fp); }
108 #undef QUIET_BIT_S
109 #undef QUIET_BIT_D
110
mulhu(uint64_t a,uint64_t b)111 inline uint64_t mulhu(uint64_t a, uint64_t b) {
112 __uint128_t full_result = ((__uint128_t)a) * ((__uint128_t)b);
113 return full_result >> 64;
114 }
115
mulh(int64_t a,int64_t b)116 inline int64_t mulh(int64_t a, int64_t b) {
117 __int128_t full_result = ((__int128_t)a) * ((__int128_t)b);
118 return full_result >> 64;
119 }
120
mulhsu(int64_t a,uint64_t b)121 inline int64_t mulhsu(int64_t a, uint64_t b) {
122 __int128_t full_result = ((__int128_t)a) * ((__uint128_t)b);
123 return full_result >> 64;
124 }
125
126 // Floating point helpers
127 #define F32_SIGN ((uint32_t)1 << 31)
128 union u32_f32 {
129 uint32_t u;
130 float f;
131 };
fsgnj32(float rs1,float rs2,bool n,bool x)132 inline float fsgnj32(float rs1, float rs2, bool n, bool x) {
133 u32_f32 a = {.f = rs1}, b = {.f = rs2};
134 u32_f32 res;
135 res.u = (a.u & ~F32_SIGN) | ((((x) ? a.u
136 : (n) ? F32_SIGN
137 : 0) ^
138 b.u) &
139 F32_SIGN);
140 return res.f;
141 }
142 #define F64_SIGN ((uint64_t)1 << 63)
143 union u64_f64 {
144 uint64_t u;
145 double d;
146 };
fsgnj64(double rs1,double rs2,bool n,bool x)147 inline double fsgnj64(double rs1, double rs2, bool n, bool x) {
148 u64_f64 a = {.d = rs1}, b = {.d = rs2};
149 u64_f64 res;
150 res.u = (a.u & ~F64_SIGN) | ((((x) ? a.u
151 : (n) ? F64_SIGN
152 : 0) ^
153 b.u) &
154 F64_SIGN);
155 return res.d;
156 }
157
is_boxed_float(int64_t v)158 inline bool is_boxed_float(int64_t v) { return (uint32_t)((v >> 32) + 1) == 0; }
box_float(float v)159 inline int64_t box_float(float v) {
160 return (0xFFFFFFFF00000000 | bit_cast<int32_t>(v));
161 }
162
163 // -----------------------------------------------------------------------------
164 // Utility functions
165
166 class CachePage {
167 public:
168 static const int LINE_VALID = 0;
169 static const int LINE_INVALID = 1;
170
171 static const int kPageShift = 12;
172 static const int kPageSize = 1 << kPageShift;
173 static const int kPageMask = kPageSize - 1;
174 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
175 static const int kLineLength = 1 << kLineShift;
176 static const int kLineMask = kLineLength - 1;
177
CachePage()178 CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); }
179
ValidityByte(int offset)180 char* ValidityByte(int offset) {
181 return &validity_map_[offset >> kLineShift];
182 }
183
CachedData(int offset)184 char* CachedData(int offset) { return &data_[offset]; }
185
186 private:
187 char data_[kPageSize]; // The cached data.
188 static const int kValidityMapSize = kPageSize >> kLineShift;
189 char validity_map_[kValidityMapSize]; // One byte per line.
190 };
191
192 class SimInstructionBase : public InstructionBase {
193 public:
InstructionType()194 Type InstructionType() const { return type_; }
instr()195 inline Instruction* instr() const { return instr_; }
operand()196 inline int32_t operand() const { return operand_; }
197
198 protected:
SimInstructionBase()199 SimInstructionBase() : operand_(-1), instr_(nullptr), type_(kUnsupported) {}
SimInstructionBase(Instruction * instr)200 explicit SimInstructionBase(Instruction* instr) {}
201
202 int32_t operand_;
203 Instruction* instr_;
204 Type type_;
205
206 private:
207 DISALLOW_ASSIGN(SimInstructionBase);
208 };
209
210 class SimInstruction : public InstructionGetters<SimInstructionBase> {
211 public:
SimInstruction()212 SimInstruction() {}
213
SimInstruction(Instruction * instr)214 explicit SimInstruction(Instruction* instr) { *this = instr; }
215
216 SimInstruction& operator=(Instruction* instr) {
217 operand_ = *reinterpret_cast<const int32_t*>(instr);
218 instr_ = instr;
219 type_ = InstructionBase::InstructionType();
220 DCHECK(reinterpret_cast<void*>(&operand_) == this);
221 return *this;
222 }
223 };
224
225 class Simulator : public SimulatorBase {
226 public:
227 friend class RiscvDebugger;
228
229 // Registers are declared in order. See SMRL chapter 2.
230 enum Register {
231 no_reg = -1,
232 zero_reg = 0,
233 ra,
234 sp,
235 gp,
236 tp,
237 t0,
238 t1,
239 t2,
240 s0,
241 s1,
242 a0,
243 a1,
244 a2,
245 a3,
246 a4,
247 a5,
248 a6,
249 a7,
250 s2,
251 s3,
252 s4,
253 s5,
254 s6,
255 s7,
256 s8,
257 s9,
258 s10,
259 s11,
260 t3,
261 t4,
262 t5,
263 t6,
264 pc, // pc must be the last register.
265 kNumSimuRegisters,
266 // aliases
267 fp = s0
268 };
269
270 // Coprocessor registers.
271 // Generated code will always use doubles. So we will only use even registers.
272 enum FPURegister {
273 ft0,
274 ft1,
275 ft2,
276 ft3,
277 ft4,
278 ft5,
279 ft6,
280 ft7,
281 fs0,
282 fs1,
283 fa0,
284 fa1,
285 fa2,
286 fa3,
287 fa4,
288 fa5,
289 fa6,
290 fa7,
291 fs2,
292 fs3,
293 fs4,
294 fs5,
295 fs6,
296 fs7,
297 fs8,
298 fs9,
299 fs10,
300 fs11,
301 ft8,
302 ft9,
303 ft10,
304 ft11,
305 kNumFPURegisters
306 };
307
308 enum VRegister {
309 v0,
310 v1,
311 v2,
312 v3,
313 v4,
314 v5,
315 v6,
316 v7,
317 v8,
318 v9,
319 v10,
320 v11,
321 v12,
322 v13,
323 v14,
324 v15,
325 v16,
326 v17,
327 v18,
328 v19,
329 v20,
330 v21,
331 v22,
332 v23,
333 v24,
334 v25,
335 v26,
336 v27,
337 v28,
338 v29,
339 v30,
340 v31,
341 kNumVRegisters
342 };
343
344 explicit Simulator(Isolate* isolate);
345 ~Simulator();
346
347 // The currently executing Simulator instance. Potentially there can be one
348 // for each native thread.
349 V8_EXPORT_PRIVATE static Simulator* current(v8::internal::Isolate* isolate);
350
351 // Accessors for register state. Reading the pc value adheres to the RISC-V
352 // architecture specification and is off by a 8 from the currently executing
353 // instruction.
354 void set_register(int reg, int64_t value);
355 void set_register_word(int reg, int32_t value);
356 void set_dw_register(int dreg, const int* dbl);
357 V8_EXPORT_PRIVATE int64_t get_register(int reg) const;
358 double get_double_from_register_pair(int reg);
359
360 // Same for FPURegisters.
361 void set_fpu_register(int fpureg, int64_t value);
362 void set_fpu_register_word(int fpureg, int32_t value);
363 void set_fpu_register_hi_word(int fpureg, int32_t value);
364 void set_fpu_register_float(int fpureg, float value);
365 void set_fpu_register_double(int fpureg, double value);
366
367 int64_t get_fpu_register(int fpureg) const;
368 int32_t get_fpu_register_word(int fpureg) const;
369 int32_t get_fpu_register_signed_word(int fpureg) const;
370 int32_t get_fpu_register_hi_word(int fpureg) const;
371 float get_fpu_register_float(int fpureg) const;
372 double get_fpu_register_double(int fpureg) const;
373
374 // RV CSR manipulation
375 uint32_t read_csr_value(uint32_t csr);
376 void write_csr_value(uint32_t csr, uint64_t value);
377 void set_csr_bits(uint32_t csr, uint64_t flags);
378 void clear_csr_bits(uint32_t csr, uint64_t flags);
379
set_fflags(uint32_t flags)380 void set_fflags(uint32_t flags) { set_csr_bits(csr_fflags, flags); }
clear_fflags(int32_t flags)381 void clear_fflags(int32_t flags) { clear_csr_bits(csr_fflags, flags); }
382
383 #ifdef CAN_USE_RVV_INSTRUCTIONS
384 // RVV CSR
385 __int128_t get_vregister(int vreg) const;
rvv_vlen()386 inline uint64_t rvv_vlen() const { return kRvvVLEN; }
rvv_vtype()387 inline uint64_t rvv_vtype() const { return vtype_; }
rvv_vl()388 inline uint64_t rvv_vl() const { return vl_; }
rvv_vstart()389 inline uint64_t rvv_vstart() const { return vstart_; }
rvv_vxsat()390 inline uint64_t rvv_vxsat() const { return vxsat_; }
rvv_vxrm()391 inline uint64_t rvv_vxrm() const { return vxrm_; }
rvv_vcsr()392 inline uint64_t rvv_vcsr() const { return vcsr_; }
rvv_vlenb()393 inline uint64_t rvv_vlenb() const { return vlenb_; }
rvv_zimm()394 inline uint32_t rvv_zimm() const { return instr_.Rvvzimm(); }
rvv_vlmul()395 inline uint32_t rvv_vlmul() const { return (rvv_vtype() & 0x7); }
rvv_vflmul()396 inline float rvv_vflmul() const {
397 if ((rvv_vtype() & 0b100) == 0) {
398 return static_cast<float>(0x1 << (rvv_vtype() & 0x7));
399 } else {
400 return 1.0 / static_cast<float>(0x1 << (4 - rvv_vtype() & 0x3));
401 }
402 }
rvv_vsew()403 inline uint32_t rvv_vsew() const { return ((rvv_vtype() >> 3) & 0x7); }
404
rvv_sew_s()405 inline const char* rvv_sew_s() const {
406 uint32_t vsew = rvv_vsew();
407 switch (vsew) {
408 #define CAST_VSEW(name) \
409 case name: \
410 return #name;
411 RVV_SEW(CAST_VSEW)
412 default:
413 return "unknown";
414 #undef CAST_VSEW
415 }
416 }
417
rvv_lmul_s()418 inline const char* rvv_lmul_s() const {
419 uint32_t vlmul = rvv_vlmul();
420 switch (vlmul) {
421 #define CAST_VLMUL(name) \
422 case name: \
423 return #name;
424 RVV_LMUL(CAST_VLMUL)
425 default:
426 return "unknown";
427 #undef CAST_VLMUL
428 }
429 }
430
431 // return size of lane.8 16 32 64
rvv_sew()432 inline uint32_t rvv_sew() const {
433 DCHECK_EQ(rvv_vsew() & (~0x7), 0x0);
434 return (0x1 << rvv_vsew()) * 8;
435 }
rvv_vlmax()436 inline uint64_t rvv_vlmax() const {
437 if ((rvv_vlmul() & 0b100) != 0) {
438 return (rvv_vlen() / rvv_sew()) >> (4 - (rvv_vlmul() & 0b11));
439 } else {
440 return ((rvv_vlen() << rvv_vlmul()) / rvv_sew());
441 }
442 }
443 #endif
444
445 inline uint32_t get_dynamic_rounding_mode();
446 inline bool test_fflags_bits(uint32_t mask);
447
448 float RoundF2FHelper(float input_val, int rmode);
449 double RoundF2FHelper(double input_val, int rmode);
450 template <typename I_TYPE, typename F_TYPE>
451 I_TYPE RoundF2IHelper(F_TYPE original, int rmode);
452
453 template <typename T>
454 T FMaxMinHelper(T a, T b, MaxMinKind kind);
455
456 template <typename T>
457 bool CompareFHelper(T input1, T input2, FPUCondition cc);
458
459 // Special case of set_register and get_register to access the raw PC value.
460 void set_pc(int64_t value);
461 V8_EXPORT_PRIVATE int64_t get_pc() const;
462
get_sp()463 Address get_sp() const { return static_cast<Address>(get_register(sp)); }
464
465 // Accessor to the internal simulator stack area.
466 uintptr_t StackLimit(uintptr_t c_limit) const;
467
468 // Executes RISC-V instructions until the PC reaches end_sim_pc.
469 void Execute();
470
471 template <typename Return, typename... Args>
Call(Address entry,Args...args)472 Return Call(Address entry, Args... args) {
473 return VariadicCall<Return>(this, &Simulator::CallImpl, entry, args...);
474 }
475
476 // Alternative: call a 2-argument double function.
477 double CallFP(Address entry, double d0, double d1);
478
479 // Push an address onto the JS stack.
480 uintptr_t PushAddress(uintptr_t address);
481
482 // Pop an address from the JS stack.
483 uintptr_t PopAddress();
484
485 // Debugger input.
486 void set_last_debugger_input(char* input);
last_debugger_input()487 char* last_debugger_input() { return last_debugger_input_; }
488
489 // Redirection support.
490 static void SetRedirectInstruction(Instruction* instruction);
491
492 // ICache checking.
493 static bool ICacheMatch(void* one, void* two);
494 static void FlushICache(base::CustomMatcherHashMap* i_cache, void* start,
495 size_t size);
496
497 // Returns true if pc register contains one of the 'special_values' defined
498 // below (bad_ra, end_sim_pc).
499 bool has_bad_pc() const;
500
501 private:
502 enum special_values {
503 // Known bad pc value to ensure that the simulator does not execute
504 // without being properly setup.
505 bad_ra = -1,
506 // A pc value used to signal the simulator to stop execution. Generally
507 // the ra is set to this value on transition from native C code to
508 // simulated execution, so that the simulator can "return" to the native
509 // C code.
510 end_sim_pc = -2,
511 // Unpredictable value.
512 Unpredictable = 0xbadbeaf
513 };
514
515 V8_EXPORT_PRIVATE intptr_t CallImpl(Address entry, int argument_count,
516 const intptr_t* arguments);
517
518 // Unsupported instructions use Format to print an error and stop execution.
519 void Format(Instruction* instr, const char* format);
520
521 // Helpers for data value tracing.
522 enum TraceType {
523 BYTE,
524 HALF,
525 WORD,
526 DWORD,
527 FLOAT,
528 DOUBLE,
529 // FLOAT_DOUBLE,
530 // WORD_DWORD
531 };
532
533 // RISCV Memory read/write methods
534 template <typename T>
535 T ReadMem(int64_t addr, Instruction* instr);
536 template <typename T>
537 void WriteMem(int64_t addr, T value, Instruction* instr);
538 template <typename T, typename OP>
amo(int64_t addr,OP f,Instruction * instr,TraceType t)539 T amo(int64_t addr, OP f, Instruction* instr, TraceType t) {
540 auto lhs = ReadMem<T>(addr, instr);
541 // TODO(RISCV): trace memory read for AMO
542 WriteMem<T>(addr, (T)f(lhs), instr);
543 return lhs;
544 }
545
546 // Helper for debugging memory access.
547 inline void DieOrDebug();
548
549 void TraceRegWr(int64_t value, TraceType t = DWORD);
550 void TraceMemWr(int64_t addr, int64_t value, TraceType t);
551 template <typename T>
552 void TraceMemRd(int64_t addr, T value, int64_t reg_value);
553 template <typename T>
554 void TraceMemWr(int64_t addr, T value);
555
556 SimInstruction instr_;
557
558 // RISCV utlity API to access register value
rs1_reg()559 inline int32_t rs1_reg() const { return instr_.Rs1Value(); }
rs1()560 inline int64_t rs1() const { return get_register(rs1_reg()); }
frs1()561 inline float frs1() const { return get_fpu_register_float(rs1_reg()); }
drs1()562 inline double drs1() const { return get_fpu_register_double(rs1_reg()); }
rs2_reg()563 inline int32_t rs2_reg() const { return instr_.Rs2Value(); }
rs2()564 inline int64_t rs2() const { return get_register(rs2_reg()); }
frs2()565 inline float frs2() const { return get_fpu_register_float(rs2_reg()); }
drs2()566 inline double drs2() const { return get_fpu_register_double(rs2_reg()); }
rs3_reg()567 inline int32_t rs3_reg() const { return instr_.Rs3Value(); }
rs3()568 inline int64_t rs3() const { return get_register(rs3_reg()); }
frs3()569 inline float frs3() const { return get_fpu_register_float(rs3_reg()); }
drs3()570 inline double drs3() const { return get_fpu_register_double(rs3_reg()); }
rd_reg()571 inline int32_t rd_reg() const { return instr_.RdValue(); }
frd_reg()572 inline int32_t frd_reg() const { return instr_.RdValue(); }
rvc_rs1_reg()573 inline int32_t rvc_rs1_reg() const { return instr_.RvcRs1Value(); }
rvc_rs1()574 inline int64_t rvc_rs1() const { return get_register(rvc_rs1_reg()); }
rvc_rs2_reg()575 inline int32_t rvc_rs2_reg() const { return instr_.RvcRs2Value(); }
rvc_rs2()576 inline int64_t rvc_rs2() const { return get_register(rvc_rs2_reg()); }
rvc_drs2()577 inline double rvc_drs2() const {
578 return get_fpu_register_double(rvc_rs2_reg());
579 }
rvc_rs1s_reg()580 inline int32_t rvc_rs1s_reg() const { return instr_.RvcRs1sValue(); }
rvc_rs1s()581 inline int64_t rvc_rs1s() const { return get_register(rvc_rs1s_reg()); }
rvc_rs2s_reg()582 inline int32_t rvc_rs2s_reg() const { return instr_.RvcRs2sValue(); }
rvc_rs2s()583 inline int64_t rvc_rs2s() const { return get_register(rvc_rs2s_reg()); }
rvc_drs2s()584 inline double rvc_drs2s() const {
585 return get_fpu_register_double(rvc_rs2s_reg());
586 }
rvc_rd_reg()587 inline int32_t rvc_rd_reg() const { return instr_.RvcRdValue(); }
rvc_frd_reg()588 inline int32_t rvc_frd_reg() const { return instr_.RvcRdValue(); }
boffset()589 inline int16_t boffset() const { return instr_.BranchOffset(); }
imm12()590 inline int16_t imm12() const { return instr_.Imm12Value(); }
imm20J()591 inline int32_t imm20J() const { return instr_.Imm20JValue(); }
imm5CSR()592 inline int32_t imm5CSR() const { return instr_.Rs1Value(); }
csr_reg()593 inline int16_t csr_reg() const { return instr_.CsrValue(); }
rvc_imm6()594 inline int16_t rvc_imm6() const { return instr_.RvcImm6Value(); }
rvc_imm6_addi16sp()595 inline int16_t rvc_imm6_addi16sp() const {
596 return instr_.RvcImm6Addi16spValue();
597 }
rvc_imm8_addi4spn()598 inline int16_t rvc_imm8_addi4spn() const {
599 return instr_.RvcImm8Addi4spnValue();
600 }
rvc_imm6_lwsp()601 inline int16_t rvc_imm6_lwsp() const { return instr_.RvcImm6LwspValue(); }
rvc_imm6_ldsp()602 inline int16_t rvc_imm6_ldsp() const { return instr_.RvcImm6LdspValue(); }
rvc_imm6_swsp()603 inline int16_t rvc_imm6_swsp() const { return instr_.RvcImm6SwspValue(); }
rvc_imm6_sdsp()604 inline int16_t rvc_imm6_sdsp() const { return instr_.RvcImm6SdspValue(); }
rvc_imm5_w()605 inline int16_t rvc_imm5_w() const { return instr_.RvcImm5WValue(); }
rvc_imm5_d()606 inline int16_t rvc_imm5_d() const { return instr_.RvcImm5DValue(); }
rvc_imm8_b()607 inline int16_t rvc_imm8_b() const { return instr_.RvcImm8BValue(); }
608
609 inline void set_rd(int64_t value, bool trace = true) {
610 set_register(rd_reg(), value);
611 if (trace) TraceRegWr(get_register(rd_reg()), DWORD);
612 }
613 inline void set_frd(float value, bool trace = true) {
614 set_fpu_register_float(rd_reg(), value);
615 if (trace) TraceRegWr(get_fpu_register_word(rd_reg()), FLOAT);
616 }
617 inline void set_drd(double value, bool trace = true) {
618 set_fpu_register_double(rd_reg(), value);
619 if (trace) TraceRegWr(get_fpu_register(rd_reg()), DOUBLE);
620 }
621 inline void set_rvc_rd(int64_t value, bool trace = true) {
622 set_register(rvc_rd_reg(), value);
623 if (trace) TraceRegWr(get_register(rvc_rd_reg()), DWORD);
624 }
625 inline void set_rvc_rs1s(int64_t value, bool trace = true) {
626 set_register(rvc_rs1s_reg(), value);
627 if (trace) TraceRegWr(get_register(rvc_rs1s_reg()), DWORD);
628 }
629 inline void set_rvc_rs2(int64_t value, bool trace = true) {
630 set_register(rvc_rs2_reg(), value);
631 if (trace) TraceRegWr(get_register(rvc_rs2_reg()), DWORD);
632 }
633 inline void set_rvc_drd(double value, bool trace = true) {
634 set_fpu_register_double(rvc_rd_reg(), value);
635 if (trace) TraceRegWr(get_fpu_register(rvc_rd_reg()), DOUBLE);
636 }
637 inline void set_rvc_rs2s(int64_t value, bool trace = true) {
638 set_register(rvc_rs2s_reg(), value);
639 if (trace) TraceRegWr(get_register(rvc_rs2s_reg()), DWORD);
640 }
641 inline void set_rvc_drs2s(double value, bool trace = true) {
642 set_fpu_register_double(rvc_rs2s_reg(), value);
643 if (trace) TraceRegWr(get_fpu_register(rvc_rs2s_reg()), DOUBLE);
644 }
shamt6()645 inline int16_t shamt6() const { return (imm12() & 0x3F); }
shamt5()646 inline int16_t shamt5() const { return (imm12() & 0x1F); }
rvc_shamt6()647 inline int16_t rvc_shamt6() const { return instr_.RvcShamt6(); }
s_imm12()648 inline int32_t s_imm12() const { return instr_.StoreOffset(); }
u_imm20()649 inline int32_t u_imm20() const { return instr_.Imm20UValue() << 12; }
rvc_u_imm6()650 inline int32_t rvc_u_imm6() const { return instr_.RvcImm6Value() << 12; }
require(bool check)651 inline void require(bool check) {
652 if (!check) {
653 SignalException(kIllegalInstruction);
654 }
655 }
656
657 #ifdef CAN_USE_RVV_INSTRUCTIONS
rvv_trace_vd()658 inline void rvv_trace_vd() {
659 if (::v8::internal::FLAG_trace_sim) {
660 __int128_t value = Vregister_[rvv_vd_reg()];
661 SNPrintF(trace_buf_, "%016" PRIx64 "%016" PRIx64 " (%" PRId64 ")",
662 *(reinterpret_cast<int64_t*>(&value) + 1),
663 *reinterpret_cast<int64_t*>(&value), icount_);
664 }
665 }
666
rvv_trace_vs1()667 inline void rvv_trace_vs1() {
668 if (::v8::internal::FLAG_trace_sim) {
669 PrintF("\t%s:0x%016" PRIx64 "%016" PRIx64 "\n",
670 v8::internal::VRegisters::Name(static_cast<int>(rvv_vs1_reg())),
671 (uint64_t)(get_vregister(static_cast<int>(rvv_vs1_reg())) >> 64),
672 (uint64_t)get_vregister(static_cast<int>(rvv_vs1_reg())));
673 }
674 }
675
rvv_trace_vs2()676 inline void rvv_trace_vs2() {
677 if (::v8::internal::FLAG_trace_sim) {
678 PrintF("\t%s:0x%016" PRIx64 "%016" PRIx64 "\n",
679 v8::internal::VRegisters::Name(static_cast<int>(rvv_vs2_reg())),
680 (uint64_t)(get_vregister(static_cast<int>(rvv_vs2_reg())) >> 64),
681 (uint64_t)get_vregister(static_cast<int>(rvv_vs2_reg())));
682 }
683 }
rvv_trace_v0()684 inline void rvv_trace_v0() {
685 if (::v8::internal::FLAG_trace_sim) {
686 PrintF("\t%s:0x%016" PRIx64 "%016" PRIx64 "\n",
687 v8::internal::VRegisters::Name(v0),
688 (uint64_t)(get_vregister(v0) >> 64), (uint64_t)get_vregister(v0));
689 }
690 }
691
rvv_trace_rs1()692 inline void rvv_trace_rs1() {
693 if (::v8::internal::FLAG_trace_sim) {
694 PrintF("\t%s:0x%016" PRIx64 "\n",
695 v8::internal::Registers::Name(static_cast<int>(rs1_reg())),
696 (uint64_t)(get_register(rs1_reg())));
697 }
698 }
699
rvv_trace_status()700 inline void rvv_trace_status() {
701 if (::v8::internal::FLAG_trace_sim) {
702 int i = 0;
703 for (; i < trace_buf_.length(); i++) {
704 if (trace_buf_[i] == '\0') break;
705 }
706 SNPrintF(trace_buf_.SubVector(i, trace_buf_.length()),
707 " sew:%s lmul:%s vstart:%lu vl:%lu", rvv_sew_s(), rvv_lmul_s(),
708 rvv_vstart(), rvv_vl());
709 }
710 }
711
712 template <class T>
713 T& Rvvelt(reg_t vReg, uint64_t n, bool is_write = false) {
714 CHECK_NE(rvv_sew(), 0);
715 CHECK_GT((rvv_vlen() >> 3) / sizeof(T), 0);
716 reg_t elts_per_reg = (rvv_vlen() >> 3) / (sizeof(T));
717 vReg += n / elts_per_reg;
718 n = n % elts_per_reg;
719 T* regStart = reinterpret_cast<T*>(reinterpret_cast<char*>(Vregister_) +
720 vReg * (rvv_vlen() >> 3));
721 return regStart[n];
722 }
723
rvv_vs1_reg()724 inline int32_t rvv_vs1_reg() { return instr_.Vs1Value(); }
rvv_vs1()725 inline reg_t rvv_vs1() { UNIMPLEMENTED(); }
rvv_vs2_reg()726 inline int32_t rvv_vs2_reg() { return instr_.Vs2Value(); }
rvv_vs2()727 inline reg_t rvv_vs2() { UNIMPLEMENTED(); }
rvv_vd_reg()728 inline int32_t rvv_vd_reg() { return instr_.VdValue(); }
rvv_vs3_reg()729 inline int32_t rvv_vs3_reg() { return instr_.VdValue(); }
rvv_vd()730 inline reg_t rvv_vd() { UNIMPLEMENTED(); }
rvv_nf()731 inline int32_t rvv_nf() {
732 return (instr_.InstructionBits() & kRvvNfMask) >> kRvvNfShift;
733 }
734
set_vrd()735 inline void set_vrd() { UNIMPLEMENTED(); }
736
737 inline void set_rvv_vtype(uint64_t value, bool trace = true) {
738 vtype_ = value;
739 }
740 inline void set_rvv_vl(uint64_t value, bool trace = true) { vl_ = value; }
741 inline void set_rvv_vstart(uint64_t value, bool trace = true) {
742 vstart_ = value;
743 }
744 inline void set_rvv_vxsat(uint64_t value, bool trace = true) {
745 vxsat_ = value;
746 }
747 inline void set_rvv_vxrm(uint64_t value, bool trace = true) { vxrm_ = value; }
748 inline void set_rvv_vcsr(uint64_t value, bool trace = true) { vcsr_ = value; }
749 inline void set_rvv_vlenb(uint64_t value, bool trace = true) {
750 vlenb_ = value;
751 }
752 #endif
753
754 template <typename T, typename Func>
CanonicalizeFPUOpFMA(Func fn,T dst,T src1,T src2)755 inline T CanonicalizeFPUOpFMA(Func fn, T dst, T src1, T src2) {
756 STATIC_ASSERT(std::is_floating_point<T>::value);
757 auto alu_out = fn(dst, src1, src2);
758 // if any input or result is NaN, the result is quiet_NaN
759 if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2) ||
760 std::isnan(dst)) {
761 // signaling_nan sets kInvalidOperation bit
762 if (isSnan(alu_out) || isSnan(src1) || isSnan(src2) || isSnan(dst))
763 set_fflags(kInvalidOperation);
764 alu_out = std::numeric_limits<T>::quiet_NaN();
765 }
766 return alu_out;
767 }
768
769 template <typename T, typename Func>
CanonicalizeFPUOp3(Func fn)770 inline T CanonicalizeFPUOp3(Func fn) {
771 STATIC_ASSERT(std::is_floating_point<T>::value);
772 T src1 = std::is_same<float, T>::value ? frs1() : drs1();
773 T src2 = std::is_same<float, T>::value ? frs2() : drs2();
774 T src3 = std::is_same<float, T>::value ? frs3() : drs3();
775 auto alu_out = fn(src1, src2, src3);
776 // if any input or result is NaN, the result is quiet_NaN
777 if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2) ||
778 std::isnan(src3)) {
779 // signaling_nan sets kInvalidOperation bit
780 if (isSnan(alu_out) || isSnan(src1) || isSnan(src2) || isSnan(src3))
781 set_fflags(kInvalidOperation);
782 alu_out = std::numeric_limits<T>::quiet_NaN();
783 }
784 return alu_out;
785 }
786
787 template <typename T, typename Func>
CanonicalizeFPUOp2(Func fn)788 inline T CanonicalizeFPUOp2(Func fn) {
789 STATIC_ASSERT(std::is_floating_point<T>::value);
790 T src1 = std::is_same<float, T>::value ? frs1() : drs1();
791 T src2 = std::is_same<float, T>::value ? frs2() : drs2();
792 auto alu_out = fn(src1, src2);
793 // if any input or result is NaN, the result is quiet_NaN
794 if (std::isnan(alu_out) || std::isnan(src1) || std::isnan(src2)) {
795 // signaling_nan sets kInvalidOperation bit
796 if (isSnan(alu_out) || isSnan(src1) || isSnan(src2))
797 set_fflags(kInvalidOperation);
798 alu_out = std::numeric_limits<T>::quiet_NaN();
799 }
800 return alu_out;
801 }
802
803 template <typename T, typename Func>
CanonicalizeFPUOp1(Func fn)804 inline T CanonicalizeFPUOp1(Func fn) {
805 STATIC_ASSERT(std::is_floating_point<T>::value);
806 T src1 = std::is_same<float, T>::value ? frs1() : drs1();
807 auto alu_out = fn(src1);
808 // if any input or result is NaN, the result is quiet_NaN
809 if (std::isnan(alu_out) || std::isnan(src1)) {
810 // signaling_nan sets kInvalidOperation bit
811 if (isSnan(alu_out) || isSnan(src1)) set_fflags(kInvalidOperation);
812 alu_out = std::numeric_limits<T>::quiet_NaN();
813 }
814 return alu_out;
815 }
816
817 template <typename Func>
CanonicalizeDoubleToFloatOperation(Func fn)818 inline float CanonicalizeDoubleToFloatOperation(Func fn) {
819 float alu_out = fn(drs1());
820 if (std::isnan(alu_out) || std::isnan(drs1()))
821 alu_out = std::numeric_limits<float>::quiet_NaN();
822 return alu_out;
823 }
824
825 template <typename Func>
CanonicalizeDoubleToFloatOperation(Func fn,double frs)826 inline float CanonicalizeDoubleToFloatOperation(Func fn, double frs) {
827 float alu_out = fn(frs);
828 if (std::isnan(alu_out) || std::isnan(drs1()))
829 alu_out = std::numeric_limits<float>::quiet_NaN();
830 return alu_out;
831 }
832
833 template <typename Func>
CanonicalizeFloatToDoubleOperation(Func fn,float frs)834 inline float CanonicalizeFloatToDoubleOperation(Func fn, float frs) {
835 double alu_out = fn(frs);
836 if (std::isnan(alu_out) || std::isnan(frs1()))
837 alu_out = std::numeric_limits<double>::quiet_NaN();
838 return alu_out;
839 }
840
841 template <typename Func>
CanonicalizeFloatToDoubleOperation(Func fn)842 inline float CanonicalizeFloatToDoubleOperation(Func fn) {
843 double alu_out = fn(frs1());
844 if (std::isnan(alu_out) || std::isnan(frs1()))
845 alu_out = std::numeric_limits<double>::quiet_NaN();
846 return alu_out;
847 }
848
849 Builtin LookUp(Address pc);
850 // RISCV decoding routine
851 void DecodeRVRType();
852 void DecodeRVR4Type();
853 void DecodeRVRFPType(); // Special routine for R/OP_FP type
854 void DecodeRVRAType(); // Special routine for R/AMO type
855 void DecodeRVIType();
856 void DecodeRVSType();
857 void DecodeRVBType();
858 void DecodeRVUType();
859 void DecodeRVJType();
860 void DecodeCRType();
861 void DecodeCAType();
862 void DecodeCIType();
863 void DecodeCIWType();
864 void DecodeCSSType();
865 void DecodeCLType();
866 void DecodeCSType();
867 void DecodeCJType();
868 void DecodeCBType();
869 #ifdef CAN_USE_RVV_INSTRUCTIONS
870 void DecodeVType();
871 void DecodeRvvIVV();
872 void DecodeRvvIVI();
873 void DecodeRvvIVX();
874 void DecodeRvvMVV();
875 void DecodeRvvMVX();
876 void DecodeRvvFVV();
877 void DecodeRvvFVF();
878 bool DecodeRvvVL();
879 bool DecodeRvvVS();
880 #endif
881
882 // Used for breakpoints and traps.
883 void SoftwareInterrupt();
884
885 // Debug helpers
886
887 // Simulator breakpoints.
888 struct Breakpoint {
889 Instruction* location;
890 bool enabled;
891 bool is_tbreak;
892 };
893 std::vector<Breakpoint> breakpoints_;
894 void SetBreakpoint(Instruction* breakpoint, bool is_tbreak);
895 void ListBreakpoints();
896 void CheckBreakpoints();
897
898 // Stop helper functions.
899 bool IsWatchpoint(uint64_t code);
900 void PrintWatchpoint(uint64_t code);
901 void HandleStop(uint64_t code);
902 bool IsStopInstruction(Instruction* instr);
903 bool IsEnabledStop(uint64_t code);
904 void EnableStop(uint64_t code);
905 void DisableStop(uint64_t code);
906 void IncreaseStopCounter(uint64_t code);
907 void PrintStopInfo(uint64_t code);
908
909 // Executes one instruction.
910 void InstructionDecode(Instruction* instr);
911
912 // ICache.
913 static void CheckICache(base::CustomMatcherHashMap* i_cache,
914 Instruction* instr);
915 static void FlushOnePage(base::CustomMatcherHashMap* i_cache, intptr_t start,
916 size_t size);
917 static CachePage* GetCachePage(base::CustomMatcherHashMap* i_cache,
918 void* page);
919
920 enum Exception {
921 none,
922 kIntegerOverflow,
923 kIntegerUnderflow,
924 kDivideByZero,
925 kNumExceptions,
926 // RISCV illegual instruction exception
927 kIllegalInstruction,
928 };
929
930 // Exceptions.
931 void SignalException(Exception e);
932
933 // Handle arguments and return value for runtime FP functions.
934 void GetFpArgs(double* x, double* y, int32_t* z);
935 void SetFpResult(const double& result);
936
937 void CallInternal(Address entry);
938
939 // Architecture state.
940 // Registers.
941 int64_t registers_[kNumSimuRegisters];
942 // Coprocessor Registers.
943 int64_t FPUregisters_[kNumFPURegisters];
944 // Floating-point control and status register.
945 uint32_t FCSR_;
946
947 #ifdef CAN_USE_RVV_INSTRUCTIONS
948 // RVV registers
949 __int128_t Vregister_[kNumVRegisters];
950 static_assert(sizeof(__int128_t) == kRvvVLEN / 8, "unmatch vlen");
951 uint64_t vstart_, vxsat_, vxrm_, vcsr_, vtype_, vl_, vlenb_;
952 #endif
953 // Simulator support.
954 // Allocate 1MB for stack.
955 size_t stack_size_;
956 char* stack_;
957 bool pc_modified_;
958 int64_t icount_;
959 int break_count_;
960 base::EmbeddedVector<char, 256> trace_buf_;
961
962 // Debugger input.
963 char* last_debugger_input_;
964
965 v8::internal::Isolate* isolate_;
966 v8::internal::Builtins builtins_;
967
968 // Stop is disabled if bit 31 is set.
969 static const uint32_t kStopDisabledBit = 1 << 31;
970
971 // A stop is enabled, meaning the simulator will stop when meeting the
972 // instruction, if bit 31 of watched_stops_[code].count is unset.
973 // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
974 // the breakpoint was hit or gone through.
975 struct StopCountAndDesc {
976 uint32_t count;
977 char* desc;
978 };
979 StopCountAndDesc watched_stops_[kMaxStopCode + 1];
980
981 // Synchronization primitives.
982 enum class MonitorAccess {
983 Open,
984 RMW,
985 };
986
987 enum class TransactionSize {
988 None = 0,
989 Word = 4,
990 DoubleWord = 8,
991 };
992
993 // The least-significant bits of the address are ignored. The number of bits
994 // is implementation-defined, between 3 and minimum page size.
995 static const uintptr_t kExclusiveTaggedAddrMask = ~((1 << 3) - 1);
996
997 class LocalMonitor {
998 public:
999 LocalMonitor();
1000
1001 // These functions manage the state machine for the local monitor, but do
1002 // not actually perform loads and stores. NotifyStoreConditional only
1003 // returns true if the store conditional is allowed; the global monitor will
1004 // still have to be checked to see whether the memory should be updated.
1005 void NotifyLoad();
1006 void NotifyLoadLinked(uintptr_t addr, TransactionSize size);
1007 void NotifyStore();
1008 bool NotifyStoreConditional(uintptr_t addr, TransactionSize size);
1009
1010 private:
1011 void Clear();
1012
1013 MonitorAccess access_state_;
1014 uintptr_t tagged_addr_;
1015 TransactionSize size_;
1016 };
1017
1018 class GlobalMonitor {
1019 public:
1020 class LinkedAddress {
1021 public:
1022 LinkedAddress();
1023
1024 private:
1025 friend class GlobalMonitor;
1026 // These functions manage the state machine for the global monitor, but do
1027 // not actually perform loads and stores.
1028 void Clear_Locked();
1029 void NotifyLoadLinked_Locked(uintptr_t addr);
1030 void NotifyStore_Locked();
1031 bool NotifyStoreConditional_Locked(uintptr_t addr,
1032 bool is_requesting_thread);
1033
1034 MonitorAccess access_state_;
1035 uintptr_t tagged_addr_;
1036 LinkedAddress* next_;
1037 LinkedAddress* prev_;
1038 // A scd can fail due to background cache evictions. Rather than
1039 // simulating this, we'll just occasionally introduce cases where an
1040 // store conditional fails. This will happen once after every
1041 // kMaxFailureCounter exclusive stores.
1042 static const int kMaxFailureCounter = 5;
1043 int failure_counter_;
1044 };
1045
1046 // Exposed so it can be accessed by Simulator::{Read,Write}Ex*.
1047 base::Mutex mutex;
1048
1049 void NotifyLoadLinked_Locked(uintptr_t addr, LinkedAddress* linked_address);
1050 void NotifyStore_Locked(LinkedAddress* linked_address);
1051 bool NotifyStoreConditional_Locked(uintptr_t addr,
1052 LinkedAddress* linked_address);
1053
1054 // Called when the simulator is destroyed.
1055 void RemoveLinkedAddress(LinkedAddress* linked_address);
1056
1057 static GlobalMonitor* Get();
1058
1059 private:
1060 // Private constructor. Call {GlobalMonitor::Get()} to get the singleton.
1061 GlobalMonitor() = default;
1062 friend class base::LeakyObject<GlobalMonitor>;
1063
1064 bool IsProcessorInLinkedList_Locked(LinkedAddress* linked_address) const;
1065 void PrependProcessor_Locked(LinkedAddress* linked_address);
1066
1067 LinkedAddress* head_ = nullptr;
1068 };
1069
1070 LocalMonitor local_monitor_;
1071 GlobalMonitor::LinkedAddress global_monitor_thread_;
1072 };
1073 } // namespace internal
1074 } // namespace v8
1075
1076 #endif // defined(USE_SIMULATOR)
1077 #endif // V8_EXECUTION_RISCV64_SIMULATOR_RISCV64_H_
1078