1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "berberis/interpreter/riscv64/interpreter.h"
18
19 #include <cfenv>
20 #include <cstdint>
21 #include <cstring>
22
23 #include "berberis/base/bit_util.h"
24 #include "berberis/base/checks.h"
25 #include "berberis/base/logging.h"
26 #include "berberis/base/macros.h"
27 #include "berberis/decoder/riscv64/decoder.h"
28 #include "berberis/decoder/riscv64/semantics_player.h"
29 #include "berberis/guest_state/guest_addr.h"
30 #include "berberis/guest_state/guest_state_riscv64.h"
31 #include "berberis/intrinsics/riscv64_to_x86_64/intrinsics_float.h"
32 #include "berberis/kernel_api/run_guest_syscall.h"
33
34 #include "atomics.h"
35 #include "fp_regs.h"
36
37 namespace berberis {
38
39 namespace {
40
41 class Interpreter {
42 public:
43 using Decoder = Decoder<SemanticsPlayer<Interpreter>>;
44 using Register = uint64_t;
45 using FpRegister = uint64_t;
46 using Float32 = intrinsics::Float32;
47 using Float64 = intrinsics::Float64;
48
Interpreter(ThreadState * state)49 explicit Interpreter(ThreadState* state) : state_(state), branch_taken_(false) {}
50
51 //
52 // Instruction implementations.
53 //
54
Csr(Decoder::CsrOpcode opcode,Register arg,Decoder::CsrRegister csr)55 Register Csr(Decoder::CsrOpcode opcode, Register arg, Decoder::CsrRegister csr) {
56 Register (*UpdateStatus)(Register arg, Register original_csr_value);
57 switch (opcode) {
58 case Decoder::CsrOpcode::kCsrrw:
59 UpdateStatus = [](Register arg, Register /*original_csr_value*/) { return arg; };
60 break;
61 case Decoder::CsrOpcode::kCsrrs:
62 UpdateStatus = [](Register arg, Register original_csr_value) {
63 return arg | original_csr_value;
64 };
65 break;
66 case Decoder::CsrOpcode::kCsrrc:
67 UpdateStatus = [](Register arg, Register original_csr_value) {
68 return ~arg & original_csr_value;
69 };
70 break;
71 default:
72 Unimplemented();
73 return {};
74 }
75 Register result;
76 switch (csr) {
77 case Decoder::CsrRegister::kFrm:
78 result = state_->cpu.frm;
79 arg = UpdateStatus(arg, result);
80 state_->cpu.frm = arg;
81 if (arg <= FPFlags::RM_MAX) {
82 std::fesetround(intrinsics::ToHostRoundingMode(arg));
83 }
84 break;
85 default:
86 Unimplemented();
87 return {};
88 }
89 return result;
90 }
91
Csr(Decoder::CsrImmOpcode opcode,uint8_t imm,Decoder::CsrRegister csr)92 Register Csr(Decoder::CsrImmOpcode opcode, uint8_t imm, Decoder::CsrRegister csr) {
93 return Csr(Decoder::CsrOpcode(opcode), imm, csr);
94 }
95
96 // Note: we prefer not to use C11/C++ atomic_thread_fence or even gcc/clang builtin
97 // __atomic_thread_fence because all these function rely on the fact that compiler never uses
98 // non-temporal loads and stores and only issue “mfence” when sequentially consistent ordering is
99 // requested. They never issue “lfence” or “sfence”.
100 // Instead we pull the page from Linux's kernel book and map read ordereding to “lfence”, write
101 // ordering to “sfence” and read-write ordering to “mfence”.
102 // This can be important in the future if we would start using nontemporal moves in manually
103 // created assembly code.
104 // Ordering affecting I/O devices is not relevant to user-space code thus we just ignore bits
105 // related to devices I/O.
Fence(Decoder::FenceOpcode,Register,bool sw,bool sr,bool,bool,bool pw,bool pr,bool,bool)106 void Fence(Decoder::FenceOpcode /*opcode*/,
107 Register /*src*/,
108 bool sw,
109 bool sr,
110 bool /*so*/,
111 bool /*si*/,
112 bool pw,
113 bool pr,
114 bool /*po*/,
115 bool /*pi*/) {
116 bool read_fence = sr | pr;
117 bool write_fence = sw | pw;
118 // Two types of fences (total store ordering fence and normal fence) are supposed to be
119 // processed differently, but only for the “read_fence && write_fence” case (otherwise total
120 // store ordering fence becomes normal fence for the “forward compatibility”), yet because x86
121 // doesn't distinguish between these two types of fences and since we are supposed to map all
122 // not-yet defined fences to normal fence (again, for the “forward compatibility”) it's Ok to
123 // just ignore opcode field.
124 if (read_fence) {
125 if (write_fence) {
126 asm volatile("mfence" ::: "memory");
127 } else {
128 asm volatile("lfence" ::: "memory");
129 }
130 } else if (write_fence) {
131 asm volatile("sfence" ::: "memory");
132 }
133 return;
134 }
135
FenceI(Register,int16_t)136 void FenceI(Register /*arg*/, int16_t /*imm*/) {
137 // For interpreter-only mode we don't need to do anything here, but when we will have a
138 // translator we would need to flush caches here.
139 }
140
Op(Decoder::OpOpcode opcode,Register arg1,Register arg2)141 Register Op(Decoder::OpOpcode opcode, Register arg1, Register arg2) {
142 using uint128_t = unsigned __int128;
143 switch (opcode) {
144 case Decoder::OpOpcode::kAdd:
145 return arg1 + arg2;
146 case Decoder::OpOpcode::kSub:
147 return arg1 - arg2;
148 case Decoder::OpOpcode::kAnd:
149 return arg1 & arg2;
150 case Decoder::OpOpcode::kOr:
151 return arg1 | arg2;
152 case Decoder::OpOpcode::kXor:
153 return arg1 ^ arg2;
154 case Decoder::OpOpcode::kSll:
155 return arg1 << arg2;
156 case Decoder::OpOpcode::kSrl:
157 return arg1 >> arg2;
158 case Decoder::OpOpcode::kSra:
159 return bit_cast<int64_t>(arg1) >> arg2;
160 case Decoder::OpOpcode::kSlt:
161 return bit_cast<int64_t>(arg1) < bit_cast<int64_t>(arg2) ? 1 : 0;
162 case Decoder::OpOpcode::kSltu:
163 return arg1 < arg2 ? 1 : 0;
164 case Decoder::OpOpcode::kMul:
165 return arg1 * arg2;
166 case Decoder::OpOpcode::kMulh:
167 return (__int128{bit_cast<int64_t>(arg1)} * __int128{bit_cast<int64_t>(arg2)}) >> 64;
168 case Decoder::OpOpcode::kMulhsu:
169 return (__int128{bit_cast<int64_t>(arg1)} * uint128_t{arg2}) >> 64;
170 case Decoder::OpOpcode::kMulhu:
171 return (uint128_t{arg1} * uint128_t{arg2}) >> 64;
172 case Decoder::OpOpcode::kDiv:
173 return bit_cast<int64_t>(arg1) / bit_cast<int64_t>(arg2);
174 case Decoder::OpOpcode::kDivu:
175 return arg1 / arg2;
176 case Decoder::OpOpcode::kRem:
177 return bit_cast<int64_t>(arg1) % bit_cast<int64_t>(arg2);
178 case Decoder::OpOpcode::kRemu:
179 return arg1 % arg2;
180 default:
181 Unimplemented();
182 return {};
183 }
184 }
185
Op32(Decoder::Op32Opcode opcode,Register arg1,Register arg2)186 Register Op32(Decoder::Op32Opcode opcode, Register arg1, Register arg2) {
187 switch (opcode) {
188 case Decoder::Op32Opcode::kAddw:
189 return int32_t(arg1) + int32_t(arg2);
190 case Decoder::Op32Opcode::kSubw:
191 return int32_t(arg1) - int32_t(arg2);
192 case Decoder::Op32Opcode::kSllw:
193 return int32_t(arg1) << int32_t(arg2);
194 case Decoder::Op32Opcode::kSrlw:
195 return bit_cast<int32_t>(uint32_t(arg1) >> uint32_t(arg2));
196 case Decoder::Op32Opcode::kSraw:
197 return int32_t(arg1) >> int32_t(arg2);
198 case Decoder::Op32Opcode::kMulw:
199 return int32_t(arg1) * int32_t(arg2);
200 case Decoder::Op32Opcode::kDivw:
201 return int32_t(arg1) / int32_t(arg2);
202 case Decoder::Op32Opcode::kDivuw:
203 return uint32_t(arg1) / uint32_t(arg2);
204 case Decoder::Op32Opcode::kRemw:
205 return int32_t(arg1) % int32_t(arg2);
206 case Decoder::Op32Opcode::kRemuw:
207 return uint32_t(arg1) % uint32_t(arg2);
208 default:
209 Unimplemented();
210 return {};
211 }
212 }
213
Amo(Decoder::AmoOpcode opcode,Register arg1,Register arg2,bool aq,bool rl)214 Register Amo(Decoder::AmoOpcode opcode, Register arg1, Register arg2, bool aq, bool rl) {
215 switch (opcode) {
216 case Decoder::AmoOpcode::kLrW:
217 Unimplemented();
218 return {};
219 case Decoder::AmoOpcode::kLrD:
220 Unimplemented();
221 return {};
222 case Decoder::AmoOpcode::kScW:
223 Unimplemented();
224 return {};
225 case Decoder::AmoOpcode::kScD:
226 Unimplemented();
227 return {};
228
229 case Decoder::AmoOpcode::kAmoswapW:
230 return AtomicExchange<int32_t>(arg1, arg2, aq, rl);
231 case Decoder::AmoOpcode::kAmoswapD:
232 return AtomicExchange<int64_t>(arg1, arg2, aq, rl);
233
234 case Decoder::AmoOpcode::kAmoaddW:
235 return AtomicAdd<int32_t>(arg1, arg2, aq, rl);
236 case Decoder::AmoOpcode::kAmoaddD:
237 return AtomicAdd<int64_t>(arg1, arg2, aq, rl);
238
239 case Decoder::AmoOpcode::kAmoxorW:
240 return AtomicXor<int32_t>(arg1, arg2, aq, rl);
241 case Decoder::AmoOpcode::kAmoxorD:
242 return AtomicXor<int64_t>(arg1, arg2, aq, rl);
243
244 case Decoder::AmoOpcode::kAmoandW:
245 return AtomicAnd<int32_t>(arg1, arg2, aq, rl);
246 case Decoder::AmoOpcode::kAmoandD:
247 return AtomicAnd<int64_t>(arg1, arg2, aq, rl);
248
249 case Decoder::AmoOpcode::kAmoorW:
250 return AtomicOr<int32_t>(arg1, arg2, aq, rl);
251 case Decoder::AmoOpcode::kAmoorD:
252 return AtomicOr<int64_t>(arg1, arg2, aq, rl);
253
254 case Decoder::AmoOpcode::kAmominW:
255 return AtomicMin<int32_t>(arg1, arg2, aq, rl);
256 case Decoder::AmoOpcode::kAmominD:
257 return AtomicMin<int64_t>(arg1, arg2, aq, rl);
258
259 case Decoder::AmoOpcode::kAmomaxW:
260 return AtomicMax<int32_t>(arg1, arg2, aq, rl);
261 case Decoder::AmoOpcode::kAmomaxD:
262 return AtomicMax<int64_t>(arg1, arg2, aq, rl);
263
264 case Decoder::AmoOpcode::kAmominuW:
265 return AtomicMinu<uint32_t>(arg1, arg2, aq, rl);
266 case Decoder::AmoOpcode::kAmominuD:
267 return AtomicMinu<uint64_t>(arg1, arg2, aq, rl);
268
269 case Decoder::AmoOpcode::kAmomaxuW:
270 return AtomicMaxu<uint32_t>(arg1, arg2, aq, rl);
271 case Decoder::AmoOpcode::kAmomaxuD:
272 return AtomicMaxu<uint64_t>(arg1, arg2, aq, rl);
273
274 default:
275 Unimplemented();
276 return {};
277 }
278 }
279
Load(Decoder::LoadOpcode opcode,Register arg,int16_t offset)280 Register Load(Decoder::LoadOpcode opcode, Register arg, int16_t offset) {
281 void* ptr = ToHostAddr<void>(arg + offset);
282 switch (opcode) {
283 case Decoder::LoadOpcode::kLbu:
284 return Load<uint8_t>(ptr);
285 case Decoder::LoadOpcode::kLhu:
286 return Load<uint16_t>(ptr);
287 case Decoder::LoadOpcode::kLwu:
288 return Load<uint32_t>(ptr);
289 case Decoder::LoadOpcode::kLd:
290 return Load<uint64_t>(ptr);
291 case Decoder::LoadOpcode::kLb:
292 return Load<int8_t>(ptr);
293 case Decoder::LoadOpcode::kLh:
294 return Load<int16_t>(ptr);
295 case Decoder::LoadOpcode::kLw:
296 return Load<int32_t>(ptr);
297 default:
298 Unimplemented();
299 return {};
300 }
301 }
302
LoadFp(Decoder::LoadFpOpcode opcode,Register arg,int16_t offset)303 FpRegister LoadFp(Decoder::LoadFpOpcode opcode, Register arg, int16_t offset) {
304 void* ptr = ToHostAddr<void>(arg + offset);
305 switch (opcode) {
306 case Decoder::LoadFpOpcode::kFlw:
307 return LoadFp<float>(ptr);
308 case Decoder::LoadFpOpcode::kFld:
309 return LoadFp<double>(ptr);
310 default:
311 Unimplemented();
312 return {};
313 }
314 }
315
OpImm(Decoder::OpImmOpcode opcode,Register arg,int16_t imm)316 Register OpImm(Decoder::OpImmOpcode opcode, Register arg, int16_t imm) {
317 switch (opcode) {
318 case Decoder::OpImmOpcode::kAddi:
319 return arg + int64_t{imm};
320 case Decoder::OpImmOpcode::kSlti:
321 return bit_cast<int64_t>(arg) < int64_t{imm} ? 1 : 0;
322 case Decoder::OpImmOpcode::kSltiu:
323 return arg < bit_cast<uint64_t>(int64_t{imm}) ? 1 : 0;
324 case Decoder::OpImmOpcode::kXori:
325 return arg ^ int64_t { imm };
326 case Decoder::OpImmOpcode::kOri:
327 return arg | int64_t{imm};
328 case Decoder::OpImmOpcode::kAndi:
329 return arg & int64_t{imm};
330 default:
331 Unimplemented();
332 return {};
333 }
334 }
335
Lui(int32_t imm)336 Register Lui(int32_t imm) { return int64_t{imm}; }
337
Auipc(int32_t imm)338 Register Auipc(int32_t imm) {
339 uint64_t pc = state_->cpu.insn_addr;
340 return pc + int64_t{imm};
341 }
342
OpImm32(Decoder::OpImm32Opcode opcode,Register arg,int16_t imm)343 Register OpImm32(Decoder::OpImm32Opcode opcode, Register arg, int16_t imm) {
344 switch (opcode) {
345 case Decoder::OpImm32Opcode::kAddiw:
346 return int32_t(arg) + int32_t{imm};
347 default:
348 Unimplemented();
349 return {};
350 }
351 }
352
Ecall(Register syscall_nr,Register arg0,Register arg1,Register arg2,Register arg3,Register arg4,Register arg5)353 Register Ecall(Register syscall_nr, Register arg0, Register arg1, Register arg2, Register arg3,
354 Register arg4, Register arg5) {
355 return RunGuestSyscall(syscall_nr, arg0, arg1, arg2, arg3, arg4, arg5);
356 }
357
OpFp(Decoder::OpFpOpcode opcode,Decoder::FloatSize float_size,uint8_t rm,FpRegister arg1,FpRegister arg2)358 FpRegister OpFp(Decoder::OpFpOpcode opcode,
359 Decoder::FloatSize float_size,
360 uint8_t rm,
361 FpRegister arg1,
362 FpRegister arg2) {
363 switch (float_size) {
364 case Decoder::FloatSize::kFloat:
365 return NanBoxFloatToFPReg(OpFp<Float32>(
366 opcode, rm, NanUnboxFPRegToFloat<Float32>(arg1), NanUnboxFPRegToFloat<Float32>(arg2)));
367 case Decoder::FloatSize::kDouble:
368 return NanBoxFloatToFPReg(OpFp<Float64>(
369 opcode, rm, NanUnboxFPRegToFloat<Float64>(arg1), NanUnboxFPRegToFloat<Float64>(arg2)));
370 default:
371 Unimplemented();
372 return {};
373 }
374 }
375
376 // TODO(b/278812060): switch to intrinsics when they would become available and stop using
377 // ExecuteFloatOperation directly.
378 template <typename FloatType>
OpFp(Decoder::OpFpOpcode opcode,uint8_t rm,FloatType arg1,FloatType arg2)379 FloatType OpFp(Decoder::OpFpOpcode opcode, uint8_t rm, FloatType arg1, FloatType arg2) {
380 switch (opcode) {
381 case Decoder::OpFpOpcode::kFAdd:
382 return intrinsics::ExecuteFloatOperation<FloatType>(
383 rm, state_->cpu.frm, [](auto x, auto y) { return x + y; }, arg1, arg2);
384 default:
385 Unimplemented();
386 return {};
387 }
388 }
389
ShiftImm(Decoder::ShiftImmOpcode opcode,Register arg,uint16_t imm)390 Register ShiftImm(Decoder::ShiftImmOpcode opcode, Register arg, uint16_t imm) {
391 switch (opcode) {
392 case Decoder::ShiftImmOpcode::kSlli:
393 return arg << imm;
394 case Decoder::ShiftImmOpcode::kSrli:
395 return arg >> imm;
396 case Decoder::ShiftImmOpcode::kSrai:
397 return bit_cast<int64_t>(arg) >> imm;
398 default:
399 Unimplemented();
400 return {};
401 }
402 }
403
ShiftImm32(Decoder::ShiftImm32Opcode opcode,Register arg,uint16_t imm)404 Register ShiftImm32(Decoder::ShiftImm32Opcode opcode, Register arg, uint16_t imm) {
405 switch (opcode) {
406 case Decoder::ShiftImm32Opcode::kSlliw:
407 return int32_t(arg) << int32_t{imm};
408 case Decoder::ShiftImm32Opcode::kSrliw:
409 return bit_cast<int32_t>(uint32_t(arg) >> uint32_t{imm});
410 case Decoder::ShiftImm32Opcode::kSraiw:
411 return int32_t(arg) >> int32_t{imm};
412 default:
413 Unimplemented();
414 return {};
415 }
416 }
417
Store(Decoder::StoreOpcode opcode,Register arg,int16_t offset,Register data)418 void Store(Decoder::StoreOpcode opcode, Register arg, int16_t offset, Register data) {
419 void* ptr = ToHostAddr<void>(arg + offset);
420 switch (opcode) {
421 case Decoder::StoreOpcode::kSb:
422 Store<uint8_t>(ptr, data);
423 break;
424 case Decoder::StoreOpcode::kSh:
425 Store<uint16_t>(ptr, data);
426 break;
427 case Decoder::StoreOpcode::kSw:
428 Store<uint32_t>(ptr, data);
429 break;
430 case Decoder::StoreOpcode::kSd:
431 Store<uint64_t>(ptr, data);
432 break;
433 default:
434 return Unimplemented();
435 }
436 }
437
StoreFp(Decoder::StoreFpOpcode opcode,Register arg,int16_t offset,FpRegister data)438 void StoreFp(Decoder::StoreFpOpcode opcode, Register arg, int16_t offset, FpRegister data) {
439 void* ptr = ToHostAddr<void>(arg + offset);
440 switch (opcode) {
441 case Decoder::StoreFpOpcode::kFsw:
442 StoreFp<float>(ptr, data);
443 break;
444 case Decoder::StoreFpOpcode::kFsd:
445 StoreFp<double>(ptr, data);
446 break;
447 default:
448 return Unimplemented();
449 }
450 }
451
Branch(Decoder::BranchOpcode opcode,Register arg1,Register arg2,int16_t offset)452 void Branch(Decoder::BranchOpcode opcode, Register arg1, Register arg2, int16_t offset) {
453 bool cond_value;
454 switch (opcode) {
455 case Decoder::BranchOpcode::kBeq:
456 cond_value = arg1 == arg2;
457 break;
458 case Decoder::BranchOpcode::kBne:
459 cond_value = arg1 != arg2;
460 break;
461 case Decoder::BranchOpcode::kBltu:
462 cond_value = arg1 < arg2;
463 break;
464 case Decoder::BranchOpcode::kBgeu:
465 cond_value = arg1 >= arg2;
466 break;
467 case Decoder::BranchOpcode::kBlt:
468 cond_value = bit_cast<int64_t>(arg1) < bit_cast<int64_t>(arg2);
469 break;
470 case Decoder::BranchOpcode::kBge:
471 cond_value = bit_cast<int64_t>(arg1) >= bit_cast<int64_t>(arg2);
472 break;
473 default:
474 return Unimplemented();
475 }
476
477 if (cond_value) {
478 state_->cpu.insn_addr += offset;
479 branch_taken_ = true;
480 }
481 }
482
JumpAndLink(int32_t offset,uint8_t insn_len)483 Register JumpAndLink(int32_t offset, uint8_t insn_len) {
484 uint64_t pc = state_->cpu.insn_addr;
485 state_->cpu.insn_addr += offset;
486 branch_taken_ = true;
487 return pc + insn_len;
488 }
489
JumpAndLinkRegister(Register base,int16_t offset,uint8_t insn_len)490 Register JumpAndLinkRegister(Register base, int16_t offset, uint8_t insn_len) {
491 uint64_t pc = state_->cpu.insn_addr;
492 // The lowest bit is always zeroed out.
493 state_->cpu.insn_addr = (base + offset) & ~uint64_t{1};
494 branch_taken_ = true;
495 return pc + insn_len;
496 }
497
Nop()498 void Nop() {}
499
Unimplemented()500 void Unimplemented() { FATAL("Unimplemented riscv64 instruction"); }
501
502 //
503 // Guest state getters/setters.
504 //
505
GetReg(uint8_t reg) const506 Register GetReg(uint8_t reg) const {
507 CheckRegIsValid(reg);
508 return state_->cpu.x[reg - 1];
509 }
510
SetReg(uint8_t reg,Register value)511 void SetReg(uint8_t reg, Register value) {
512 CheckRegIsValid(reg);
513 state_->cpu.x[reg - 1] = value;
514 }
515
GetFpReg(uint8_t reg) const516 FpRegister GetFpReg(uint8_t reg) const {
517 CheckFpRegIsValid(reg);
518 return state_->cpu.f[reg];
519 }
520
SetFpReg(uint8_t reg,FpRegister value)521 void SetFpReg(uint8_t reg, FpRegister value) {
522 CheckFpRegIsValid(reg);
523 state_->cpu.f[reg] = value;
524 }
525
526 //
527 // Various helper methods.
528 //
529
GetImm(uint64_t imm) const530 uint64_t GetImm(uint64_t imm) const { return imm; }
531
FinalizeInsn(uint8_t insn_len)532 void FinalizeInsn(uint8_t insn_len) {
533 if (!branch_taken_) {
534 state_->cpu.insn_addr += insn_len;
535 }
536 }
537
538 private:
539 template <typename DataType>
Load(const void * ptr) const540 Register Load(const void* ptr) const {
541 static_assert(std::is_integral_v<DataType>);
542 DataType data;
543 memcpy(&data, ptr, sizeof(data));
544 // Signed types automatically sign-extend to int64_t.
545 return static_cast<uint64_t>(data);
546 }
547
548 template <typename DataType>
LoadFp(const void * ptr) const549 FpRegister LoadFp(const void* ptr) const {
550 static_assert(std::is_floating_point_v<DataType>);
551 FpRegister reg = ~0ULL;
552 memcpy(®, ptr, sizeof(DataType));
553 return reg;
554 }
555
556 template <typename DataType>
Store(void * ptr,uint64_t data) const557 void Store(void* ptr, uint64_t data) const {
558 static_assert(std::is_integral_v<DataType>);
559 memcpy(ptr, &data, sizeof(DataType));
560 }
561
562 template <typename DataType>
StoreFp(void * ptr,uint64_t data) const563 void StoreFp(void* ptr, uint64_t data) const {
564 static_assert(std::is_floating_point_v<DataType>);
565 memcpy(ptr, &data, sizeof(DataType));
566 }
567
CheckRegIsValid(uint8_t reg) const568 void CheckRegIsValid(uint8_t reg) const {
569 CHECK_GT(reg, 0u);
570 CHECK_LE(reg, arraysize(state_->cpu.x));
571 }
572
CheckFpRegIsValid(uint8_t reg) const573 void CheckFpRegIsValid(uint8_t reg) const { CHECK_LT(reg, arraysize(state_->cpu.f)); }
574
575 ThreadState* state_;
576 bool branch_taken_;
577 };
578
579 } // namespace
580
InterpretInsn(ThreadState * state)581 void InterpretInsn(ThreadState* state) {
582 GuestAddr pc = state->cpu.insn_addr;
583
584 Interpreter interpreter(state);
585 SemanticsPlayer sem_player(&interpreter);
586 Decoder decoder(&sem_player);
587 uint8_t insn_len = decoder.Decode(ToHostAddr<const uint16_t>(pc));
588 interpreter.FinalizeInsn(insn_len);
589 }
590
591 } // namespace berberis