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 #ifndef BERBERIS_DECODER_RISCV64_SEMANTICS_PLAYER_H_ 18 #define BERBERIS_DECODER_RISCV64_SEMANTICS_PLAYER_H_ 19 20 #include "berberis/base/overloaded.h" 21 #include "berberis/decoder/riscv64/decoder.h" 22 23 namespace berberis { 24 25 // This class expresses the semantics of instructions by calling a sequence of SemanticsListener 26 // callbacks. 27 template <class SemanticsListener> 28 class SemanticsPlayer { 29 public: 30 using CsrName = typename SemanticsListener::CsrName; 31 using Decoder = Decoder<SemanticsPlayer>; 32 using Register = typename SemanticsListener::Register; 33 static constexpr Register no_register = SemanticsListener::no_register; 34 using Float32 = typename SemanticsListener::Float32; 35 using Float64 = typename SemanticsListener::Float64; 36 using FpRegister = typename SemanticsListener::FpRegister; 37 static constexpr FpRegister no_fp_register = SemanticsListener::no_fp_register; 38 SemanticsPlayer(SemanticsListener * listener)39 explicit SemanticsPlayer(SemanticsListener* listener) : listener_(listener) {} 40 41 // Decoder's InsnConsumer implementation. 42 Amo(const typename Decoder::AmoArgs & args)43 void Amo(const typename Decoder::AmoArgs& args) { 44 Register arg1 = GetRegOrZero(args.src1); 45 Register arg2 = GetRegOrZero(args.src2); 46 Register result = no_register; 47 switch (args.operand_type) { 48 case Decoder::MemoryDataOperandType::k32bit: 49 result = Amo<int32_t>(args.opcode, arg1, arg2, args.aq, args.rl); 50 break; 51 case Decoder::MemoryDataOperandType::k64bit: 52 result = Amo<int64_t>(args.opcode, arg1, arg2, args.aq, args.rl); 53 break; 54 default: 55 Undefined(); 56 return; 57 } 58 SetRegOrIgnore(args.dst, result); 59 } 60 61 template <typename IntType> Amo(typename Decoder::AmoOpcode opcode,Register arg1,Register arg2,bool aq,bool rl)62 Register Amo(typename Decoder::AmoOpcode opcode, Register arg1, Register arg2, bool aq, bool rl) { 63 if (aq) { 64 if (rl) { 65 return Amo<IntType, true, true>(opcode, arg1, arg2); 66 } else { 67 return Amo<IntType, true, false>(opcode, arg1, arg2); 68 } 69 } else { 70 if (rl) { 71 return Amo<IntType, false, true>(opcode, arg1, arg2); 72 } else { 73 return Amo<IntType, false, false>(opcode, arg1, arg2); 74 } 75 } 76 } 77 78 template <typename IntType, bool aq, bool rl> Amo(typename Decoder::AmoOpcode opcode,Register arg1,Register arg2)79 Register Amo(typename Decoder::AmoOpcode opcode, Register arg1, Register arg2) { 80 switch (opcode) { 81 case Decoder::AmoOpcode::kLr: 82 return listener_->template Lr<IntType, aq, rl>(arg1); 83 case Decoder::AmoOpcode::kSc: 84 return listener_->template Sc<IntType, aq, rl>(arg1, arg2); 85 case Decoder::AmoOpcode::kAmoswap: 86 return listener_->template AmoSwap<IntType, aq, rl>(arg1, arg2); 87 case Decoder::AmoOpcode::kAmoadd: 88 return listener_->template AmoAdd<IntType, aq, rl>(arg1, arg2); 89 case Decoder::AmoOpcode::kAmoxor: 90 return listener_->template AmoXor<IntType, aq, rl>(arg1, arg2); 91 case Decoder::AmoOpcode::kAmoand: 92 return listener_->template AmoAnd<IntType, aq, rl>(arg1, arg2); 93 case Decoder::AmoOpcode::kAmoor: 94 return listener_->template AmoOr<IntType, aq, rl>(arg1, arg2); 95 case Decoder::AmoOpcode::kAmomin: 96 return listener_->template AmoMin<std::make_signed_t<IntType>, aq, rl>(arg1, arg2); 97 case Decoder::AmoOpcode::kAmomax: 98 return listener_->template AmoMax<std::make_signed_t<IntType>, aq, rl>(arg1, arg2); 99 case Decoder::AmoOpcode::kAmominu: 100 return listener_->template AmoMin<std::make_unsigned_t<IntType>, aq, rl>(arg1, arg2); 101 case Decoder::AmoOpcode::kAmomaxu: 102 return listener_->template AmoMax<std::make_unsigned_t<IntType>, aq, rl>(arg1, arg2); 103 default: 104 Undefined(); 105 return no_register; 106 } 107 } 108 Auipc(const typename Decoder::UpperImmArgs & args)109 void Auipc(const typename Decoder::UpperImmArgs& args) { 110 Register result = listener_->Auipc(args.imm); 111 SetRegOrIgnore(args.dst, result); 112 } 113 CompareAndBranch(const typename Decoder::BranchArgs & args)114 void CompareAndBranch(const typename Decoder::BranchArgs& args) { 115 Register arg1 = GetRegOrZero(args.src1); 116 Register arg2 = GetRegOrZero(args.src2); 117 listener_->CompareAndBranch(args.opcode, arg1, arg2, args.offset); 118 } 119 Csr(const typename Decoder::CsrArgs & args)120 void Csr(const typename Decoder::CsrArgs& args) { 121 if (args.opcode == Decoder::CsrOpcode::kCsrrw) { 122 if (args.dst != 0) { 123 auto [csr_supported, csr] = GetCsr(static_cast<CsrName>(args.csr)); 124 if (!csr_supported) { 125 return Undefined(); 126 } 127 Register arg = listener_->GetReg(args.src); 128 SetCsr(static_cast<CsrName>(args.csr), arg); 129 listener_->SetReg(args.dst, csr); 130 return; 131 } 132 Register arg = listener_->GetReg(args.src); 133 if (!SetCsr(static_cast<CsrName>(args.csr), arg)) { 134 return Undefined(); 135 } 136 return; 137 } 138 auto [csr_supported, csr] = GetCsr(static_cast<CsrName>(args.csr)); 139 if (!csr_supported) { 140 return Undefined(); 141 } 142 if (args.src != 0) { 143 Register arg = listener_->GetReg(args.src); 144 if (!SetCsr(static_cast<CsrName>(args.csr), listener_->UpdateCsr(args.opcode, arg, csr))) { 145 return Undefined(); 146 } 147 } 148 SetRegOrIgnore(args.dst, csr); 149 } 150 Csr(const typename Decoder::CsrImmArgs & args)151 void Csr(const typename Decoder::CsrImmArgs& args) { 152 if (args.opcode == Decoder::CsrImmOpcode::kCsrrwi) { 153 if (args.dst != 0) { 154 auto [csr_supported, csr] = GetCsr(static_cast<CsrName>(args.csr)); 155 if (!csr_supported) { 156 return Undefined(); 157 } 158 if (!SetCsr(static_cast<CsrName>(args.csr), csr)) { 159 return Undefined(); 160 } 161 listener_->SetReg(args.dst, csr); 162 } 163 SetCsr(static_cast<CsrName>(args.csr), args.imm); 164 return; 165 } 166 auto [csr_supported, csr] = GetCsr(static_cast<CsrName>(args.csr)); 167 if (!csr_supported) { 168 return Undefined(); 169 } 170 if (args.imm != 0) { 171 if (!SetCsr(static_cast<CsrName>(args.csr), 172 listener_->UpdateCsr(args.opcode, args.imm, csr))) { 173 return Undefined(); 174 } 175 } 176 SetRegOrIgnore(args.dst, csr); 177 } 178 Fcvt(const typename Decoder::FcvtFloatToFloatArgs & args)179 void Fcvt(const typename Decoder::FcvtFloatToFloatArgs& args) { 180 if (args.dst_type == Decoder::FloatOperandType::kFloat && 181 args.src_type == Decoder::FloatOperandType::kDouble) { 182 FpRegister arg = GetFRegAndUnboxNan<Float64>(args.src); 183 Register frm = listener_->template GetCsr<CsrName::kFrm>(); 184 FpRegister result = listener_->template FCvtFloatToFloat<Float32, Float64>(args.rm, frm, arg); 185 NanBoxAndSetFpReg<Float32>(args.dst, result); 186 } else if (args.dst_type == Decoder::FloatOperandType::kDouble && 187 args.src_type == Decoder::FloatOperandType::kFloat) { 188 FpRegister arg = GetFRegAndUnboxNan<Float32>(args.src); 189 Register frm = listener_->template GetCsr<CsrName::kFrm>(); 190 FpRegister result = listener_->template FCvtFloatToFloat<Float64, Float32>(args.rm, frm, arg); 191 NanBoxAndSetFpReg<Float64>(args.dst, result); 192 } else { 193 Undefined(); 194 return; 195 } 196 } 197 Fcvt(const typename Decoder::FcvtFloatToIntegerArgs & args)198 void Fcvt(const typename Decoder::FcvtFloatToIntegerArgs& args) { 199 switch (args.src_type) { 200 case Decoder::FloatOperandType::kFloat: 201 return FcvtloatToInteger<Float32>(args.dst_type, args.rm, args.dst, args.src); 202 case Decoder::FloatOperandType::kDouble: 203 return FcvtloatToInteger<Float64>(args.dst_type, args.rm, args.dst, args.src); 204 default: 205 return Undefined(); 206 } 207 } 208 209 template <typename FLoatType> FcvtloatToInteger(typename Decoder::FcvtOperandType dst_type,int8_t rm,int8_t dst,int8_t src)210 void FcvtloatToInteger(typename Decoder::FcvtOperandType dst_type, 211 int8_t rm, 212 int8_t dst, 213 int8_t src) { 214 FpRegister arg = GetFRegAndUnboxNan<FLoatType>(src); 215 Register frm = listener_->template GetCsr<CsrName::kFrm>(); 216 Register result = no_register; 217 switch (dst_type) { 218 case Decoder::FcvtOperandType::k32bitSigned: 219 result = listener_->template FCvtFloatToInteger<int32_t, FLoatType>(rm, frm, arg); 220 break; 221 case Decoder::FcvtOperandType::k32bitUnsigned: 222 result = listener_->template FCvtFloatToInteger<uint32_t, FLoatType>(rm, frm, arg); 223 break; 224 case Decoder::FcvtOperandType::k64bitSigned: 225 result = listener_->template FCvtFloatToInteger<int64_t, FLoatType>(rm, frm, arg); 226 break; 227 case Decoder::FcvtOperandType::k64bitUnsigned: 228 result = listener_->template FCvtFloatToInteger<uint64_t, FLoatType>(rm, frm, arg); 229 break; 230 default: 231 return Undefined(); 232 } 233 SetRegOrIgnore(dst, result); 234 } 235 Fcvt(const typename Decoder::FcvtIntegerToFloatArgs & args)236 void Fcvt(const typename Decoder::FcvtIntegerToFloatArgs& args) { 237 switch (args.dst_type) { 238 case Decoder::FloatOperandType::kFloat: 239 return FcvtIntegerToFloat<Float32>(args.src_type, args.rm, args.dst, args.src); 240 case Decoder::FloatOperandType::kDouble: 241 return FcvtIntegerToFloat<Float64>(args.src_type, args.rm, args.dst, args.src); 242 default: 243 return Undefined(); 244 } 245 } 246 247 template <typename FloatType> FcvtIntegerToFloat(typename Decoder::FcvtOperandType src_type,int8_t rm,int8_t dst,int8_t src)248 void FcvtIntegerToFloat(typename Decoder::FcvtOperandType src_type, 249 int8_t rm, 250 int8_t dst, 251 int8_t src) { 252 Register arg = GetRegOrZero(src); 253 Register frm = listener_->template GetCsr<CsrName::kFrm>(); 254 FpRegister result = no_fp_register; 255 switch (src_type) { 256 case Decoder::FcvtOperandType::k32bitSigned: 257 result = listener_->template FCvtIntegerToFloat<FloatType, int32_t>(rm, frm, arg); 258 break; 259 case Decoder::FcvtOperandType::k32bitUnsigned: 260 result = listener_->template FCvtIntegerToFloat<FloatType, uint32_t>(rm, frm, arg); 261 break; 262 case Decoder::FcvtOperandType::k64bitSigned: 263 result = listener_->template FCvtIntegerToFloat<FloatType, int64_t>(rm, frm, arg); 264 break; 265 case Decoder::FcvtOperandType::k64bitUnsigned: 266 result = listener_->template FCvtIntegerToFloat<FloatType, uint64_t>(rm, frm, arg); 267 break; 268 default: 269 Undefined(); 270 return; 271 } 272 NanBoxAndSetFpReg<FloatType>(dst, result); 273 } 274 Fma(const typename Decoder::FmaArgs & args)275 void Fma(const typename Decoder::FmaArgs& args) { 276 switch (args.operand_type) { 277 case Decoder::FloatOperandType::kFloat: 278 return Fma<Float32>(args.opcode, args.rm, args.dst, args.src1, args.src2, args.src3); 279 break; 280 case Decoder::FloatOperandType::kDouble: 281 return Fma<Float64>(args.opcode, args.rm, args.dst, args.src1, args.src2, args.src3); 282 break; 283 default: 284 return Undefined(); 285 } 286 } 287 288 template <typename FloatType> Fma(typename Decoder::FmaOpcode opcode,int8_t rm,int8_t dst,int8_t src1,int8_t src2,int8_t src3)289 void Fma(typename Decoder::FmaOpcode opcode, 290 int8_t rm, 291 int8_t dst, 292 int8_t src1, 293 int8_t src2, 294 int8_t src3) { 295 FpRegister arg1 = GetFRegAndUnboxNan<FloatType>(src1); 296 FpRegister arg2 = GetFRegAndUnboxNan<FloatType>(src2); 297 FpRegister arg3 = GetFRegAndUnboxNan<FloatType>(src3); 298 Register frm = listener_->template GetCsr<CsrName::kFrm>(); 299 FpRegister result = no_fp_register; 300 switch (opcode) { 301 case Decoder::FmaOpcode::kFmadd: 302 result = listener_->template FMAdd<FloatType>(rm, frm, arg1, arg2, arg3); 303 break; 304 case Decoder::FmaOpcode::kFmsub: 305 result = listener_->template FMSub<FloatType>(rm, frm, arg1, arg2, arg3); 306 break; 307 // Note (from RISC-V manual): The FNMSUB and FNMADD instructions are counterintuitively named, 308 // owing to the naming of the corresponding instructions in MIPS-IV. The MIPS instructions 309 // were defined to negate the sum, rather than negating the product as the RISC-V instructions 310 // do, so the naming scheme was more rational at the time. The two definitions differ with 311 // respect to signed-zero results. The RISC-V definition matches the behavior of the x86 and 312 // ARM fused multiply-add instructions, but unfortunately the RISC-V FNMSUB and FNMADD 313 // instruction names are swapped compared to x86 and ARM. 314 // 315 // Since even official documentation calls the names “counterintuitive” it's better to use x86 316 // ones for intrinsics. 317 case Decoder::FmaOpcode::kFnmsub: 318 result = listener_->template FNMAdd<FloatType>(rm, frm, arg1, arg2, arg3); 319 break; 320 case Decoder::FmaOpcode::kFnmadd: 321 result = listener_->template FNMSub<FloatType>(rm, frm, arg1, arg2, arg3); 322 break; 323 default: 324 return Undefined(); 325 } 326 result = CanonicalizeNan<FloatType>(result); 327 NanBoxAndSetFpReg<FloatType>(dst, result); 328 } 329 Fence(const typename Decoder::FenceArgs & args)330 void Fence(const typename Decoder::FenceArgs& args) { 331 listener_->Fence(args.opcode, 332 // args.src is currently unused - read below. 333 no_register, 334 args.sw, 335 args.sr, 336 args.so, 337 args.si, 338 args.pw, 339 args.pr, 340 args.po, 341 args.pi); 342 // The unused fields in the FENCE instructions — args.src and args.dst — are reserved for 343 // finer-grain fences in future extensions. For forward compatibility, base implementations 344 // shall ignore these fields, and standard software shall zero these fields. Likewise, many 345 // args.opcode and predecessor/successor set settings are also reserved for future use. Base 346 // implementations shall treat all such reserved configurations as normal fences with 347 // args.opcode=0000, and standard software shall use only non-reserved configurations. 348 } 349 FenceI(const typename Decoder::FenceIArgs &)350 void FenceI(const typename Decoder::FenceIArgs& /* args */) { 351 // This instruction is not supported on linux. The recommendation is to use the 352 // riscv_flush_icache syscall instead. 353 Undefined(); 354 // The unused fields in the FENCE.I instruction, imm[11:0], rs1, and rd, are reserved for 355 // finer-grain fences in future extensions. For forward compatibility, base implementations 356 // shall ignore these fields, and standard software shall zero these fields. 357 } 358 JumpAndLink(const typename Decoder::JumpAndLinkArgs & args)359 void JumpAndLink(const typename Decoder::JumpAndLinkArgs& args) { 360 Register result = listener_->GetImm(listener_->GetInsnAddr() + args.insn_len); 361 SetRegOrIgnore(args.dst, result); 362 listener_->Branch(args.offset); 363 } 364 JumpAndLinkRegister(const typename Decoder::JumpAndLinkRegisterArgs & args)365 void JumpAndLinkRegister(const typename Decoder::JumpAndLinkRegisterArgs& args) { 366 Register base = GetRegOrZero(args.base); 367 if (args.base == args.dst) { 368 // If base and dst are the same register and the listener implements register mapping 369 // SetRegOrIgnore below will overwrite the original base register and make it invalid for 370 // BranchRegister call. Note that this issue only exists for JumpAndLinkRegister since we 371 // need to write the result before consuming all the arguments. 372 base = listener_->Copy(base); 373 } 374 Register next_insn_addr = listener_->GetImm(listener_->GetInsnAddr() + args.insn_len); 375 SetRegOrIgnore(args.dst, next_insn_addr); 376 listener_->BranchRegister(base, args.offset); 377 } 378 Load(const typename Decoder::LoadArgs & args)379 void Load(const typename Decoder::LoadArgs& args) { 380 Register arg = GetRegOrZero(args.src); 381 Register result = listener_->Load(args.operand_type, arg, args.offset); 382 SetRegOrIgnore(args.dst, result); 383 } 384 Load(const typename Decoder::LoadFpArgs & args)385 void Load(const typename Decoder::LoadFpArgs& args) { 386 switch (args.operand_type) { 387 case Decoder::FloatOperandType::kFloat: 388 return Load<Float32>(args.dst, args.src, args.offset); 389 case Decoder::FloatOperandType::kDouble: 390 return Load<Float64>(args.dst, args.src, args.offset); 391 default: 392 return Undefined(); 393 } 394 } 395 396 template <typename FloatType> Load(int8_t dst,int8_t src,int16_t offset)397 void Load(int8_t dst, int8_t src, int16_t offset) { 398 Register arg = GetRegOrZero(src); 399 FpRegister result = listener_->template LoadFp<FloatType>(arg, offset); 400 NanBoxAndSetFpReg<FloatType>(dst, result); 401 } 402 Lui(const typename Decoder::UpperImmArgs & args)403 void Lui(const typename Decoder::UpperImmArgs& args) { 404 Register result = listener_->Lui(args.imm); 405 SetRegOrIgnore(args.dst, result); 406 } 407 Nop()408 void Nop() { listener_->Nop(); } 409 410 template <typename OpArgs> Op(OpArgs && args)411 void Op(OpArgs&& args) { 412 Register arg1 = GetRegOrZero(args.src1); 413 Register arg2 = GetRegOrZero(args.src2); 414 Register result = Overloaded{[&](const typename Decoder::OpArgs& args) { 415 switch (args.opcode) { 416 case Decoder::OpOpcode::kDiv: 417 return listener_->template Div<int64_t>(arg1, arg2); 418 case Decoder::OpOpcode::kDivu: 419 return listener_->template Div<uint64_t>(arg1, arg2); 420 case Decoder::OpOpcode::kRem: 421 return listener_->template Rem<int64_t>(arg1, arg2); 422 case Decoder::OpOpcode::kRemu: 423 return listener_->template Rem<uint64_t>(arg1, arg2); 424 case Decoder::OpOpcode::kMax: 425 return listener_->template Max<int64_t>(arg1, arg2); 426 case Decoder::OpOpcode::kMaxu: 427 return listener_->template Max<uint64_t>(arg1, arg2); 428 case Decoder::OpOpcode::kMin: 429 return listener_->template Min<int64_t>(arg1, arg2); 430 case Decoder::OpOpcode::kMinu: 431 return listener_->template Min<uint64_t>(arg1, arg2); 432 case Decoder::OpOpcode::kRol: 433 return listener_->template Rol<int64_t>(arg1, arg2); 434 case Decoder::OpOpcode::kRor: 435 return listener_->template Ror<int64_t>(arg1, arg2); 436 case Decoder::OpOpcode::kSh1add: 437 return listener_->Sh1add(arg1, arg2); 438 case Decoder::OpOpcode::kSh2add: 439 return listener_->Sh2add(arg1, arg2); 440 case Decoder::OpOpcode::kSh3add: 441 return listener_->Sh3add(arg1, arg2); 442 case Decoder::OpOpcode::kBclr: 443 return listener_->Bclr(arg1, arg2); 444 case Decoder::OpOpcode::kBext: 445 return listener_->Bext(arg1, arg2); 446 case Decoder::OpOpcode::kBinv: 447 return listener_->Binv(arg1, arg2); 448 case Decoder::OpOpcode::kBset: 449 return listener_->Bset(arg1, arg2); 450 default: 451 return listener_->Op(args.opcode, arg1, arg2); 452 } 453 }, 454 [&](const typename Decoder::Op32Args& args) { 455 switch (args.opcode) { 456 case Decoder::Op32Opcode::kAdduw: 457 return listener_->Adduw(arg1, arg2); 458 case Decoder::Op32Opcode::kDivw: 459 return listener_->template Div<int32_t>(arg1, arg2); 460 case Decoder::Op32Opcode::kDivuw: 461 return listener_->template Div<uint32_t>(arg1, arg2); 462 case Decoder::Op32Opcode::kRemw: 463 return listener_->template Rem<int32_t>(arg1, arg2); 464 case Decoder::Op32Opcode::kRemuw: 465 return listener_->template Rem<uint32_t>(arg1, arg2); 466 case Decoder::Op32Opcode::kRolw: 467 return listener_->template Rol<int32_t>(arg1, arg2); 468 case Decoder::Op32Opcode::kRorw: 469 return listener_->template Ror<int32_t>(arg1, arg2); 470 case Decoder::Op32Opcode::kSh1adduw: 471 return listener_->Sh1adduw(arg1, arg2); 472 case Decoder::Op32Opcode::kSh2adduw: 473 return listener_->Sh2adduw(arg1, arg2); 474 case Decoder::Op32Opcode::kSh3adduw: 475 return listener_->Sh3adduw(arg1, arg2); 476 default: 477 return listener_->Op32(args.opcode, arg1, arg2); 478 } 479 }}(args); 480 SetRegOrIgnore(args.dst, result); 481 } 482 OpSingleInput(const typename Decoder::OpSingleInputArgs & args)483 void OpSingleInput(const typename Decoder::OpSingleInputArgs& args) { 484 Register arg = GetRegOrZero(args.src); 485 Register result = no_register; 486 switch (args.opcode) { 487 case Decoder::OpSingleInputOpcode::kZextb: 488 result = listener_->template Zext<uint8_t>(arg); 489 break; 490 case Decoder::OpSingleInputOpcode::kZexth: 491 result = listener_->template Zext<uint16_t>(arg); 492 break; 493 case Decoder::OpSingleInputOpcode::kZextw: 494 result = listener_->template Zext<uint32_t>(arg); 495 break; 496 case Decoder::OpSingleInputOpcode::kSextb: 497 result = listener_->template Sext<int8_t>(arg); 498 break; 499 case Decoder::OpSingleInputOpcode::kSexth: 500 result = listener_->template Sext<int16_t>(arg); 501 break; 502 default: 503 Undefined(); 504 return; 505 } 506 SetRegOrIgnore(args.dst, result); 507 } 508 OpFp(const typename Decoder::OpFpArgs & args)509 void OpFp(const typename Decoder::OpFpArgs& args) { 510 switch (args.operand_type) { 511 case Decoder::FloatOperandType::kFloat: 512 return OpFp<Float32>(args.opcode, args.rm, args.dst, args.src1, args.src2); 513 case Decoder::FloatOperandType::kDouble: 514 return OpFp<Float64>(args.opcode, args.rm, args.dst, args.src1, args.src2); 515 default: 516 return Undefined(); 517 } 518 } 519 520 template <typename FloatType> OpFp(typename Decoder::OpFpOpcode opcode,int8_t rm,int8_t dst,int8_t src1,int8_t src2)521 void OpFp(typename Decoder::OpFpOpcode opcode, int8_t rm, int8_t dst, int8_t src1, int8_t src2) { 522 FpRegister arg1 = GetFRegAndUnboxNan<FloatType>(src1); 523 FpRegister arg2 = GetFRegAndUnboxNan<FloatType>(src2); 524 Register frm = listener_->template GetCsr<CsrName::kFrm>(); 525 FpRegister result = no_fp_register; 526 switch (opcode) { 527 case Decoder::OpFpOpcode::kFAdd: 528 result = listener_->template FAdd<FloatType>(rm, frm, arg1, arg2); 529 break; 530 case Decoder::OpFpOpcode::kFSub: 531 result = listener_->template FSub<FloatType>(rm, frm, arg1, arg2); 532 break; 533 case Decoder::OpFpOpcode::kFMul: 534 result = listener_->template FMul<FloatType>(rm, frm, arg1, arg2); 535 break; 536 case Decoder::OpFpOpcode::kFDiv: 537 result = listener_->template FDiv<FloatType>(rm, frm, arg1, arg2); 538 break; 539 default: 540 return Undefined(); 541 } 542 result = CanonicalizeNan<FloatType>(result); 543 NanBoxAndSetFpReg<FloatType>(dst, result); 544 } 545 OpFpGpRegisterTargetNoRounding(const typename Decoder::OpFpGpRegisterTargetNoRoundingArgs & args)546 void OpFpGpRegisterTargetNoRounding( 547 const typename Decoder::OpFpGpRegisterTargetNoRoundingArgs& args) { 548 switch (args.operand_type) { 549 case Decoder::FloatOperandType::kFloat: 550 return OpFpGpRegisterTargetNoRounding<Float32>(args.opcode, args.dst, args.src1, args.src2); 551 case Decoder::FloatOperandType::kDouble: 552 return OpFpGpRegisterTargetNoRounding<Float64>(args.opcode, args.dst, args.src1, args.src2); 553 default: 554 return Undefined(); 555 } 556 } 557 558 template <typename FloatType> OpFpGpRegisterTargetNoRounding(typename Decoder::OpFpGpRegisterTargetNoRoundingOpcode opcode,int8_t dst,int8_t src1,int8_t src2)559 void OpFpGpRegisterTargetNoRounding(typename Decoder::OpFpGpRegisterTargetNoRoundingOpcode opcode, 560 int8_t dst, 561 int8_t src1, 562 int8_t src2) { 563 FpRegister arg1 = GetFRegAndUnboxNan<FloatType>(src1); 564 FpRegister arg2 = GetFRegAndUnboxNan<FloatType>(src2); 565 Register result = no_register; 566 switch (opcode) { 567 case Decoder::OpFpGpRegisterTargetNoRoundingOpcode::kFle: 568 result = listener_->template Fle<FloatType>(arg1, arg2); 569 break; 570 case Decoder::OpFpGpRegisterTargetNoRoundingOpcode::kFlt: 571 result = listener_->template Flt<FloatType>(arg1, arg2); 572 break; 573 case Decoder::OpFpGpRegisterTargetNoRoundingOpcode::kFeq: 574 result = listener_->template Feq<FloatType>(arg1, arg2); 575 break; 576 default: 577 return Undefined(); 578 } 579 SetRegOrIgnore(dst, result); 580 } 581 OpFpGpRegisterTargetSingleInputNoRounding(const typename Decoder::OpFpGpRegisterTargetSingleInputNoRoundingArgs & args)582 void OpFpGpRegisterTargetSingleInputNoRounding( 583 const typename Decoder::OpFpGpRegisterTargetSingleInputNoRoundingArgs& args) { 584 switch (args.operand_type) { 585 case Decoder::FloatOperandType::kFloat: 586 return OpFpGpRegisterTargetSingleInputNoRounding<Float32>(args.opcode, args.dst, args.src); 587 case Decoder::FloatOperandType::kDouble: 588 return OpFpGpRegisterTargetSingleInputNoRounding<Float64>(args.opcode, args.dst, args.src); 589 default: 590 return Undefined(); 591 } 592 } 593 594 template <typename FloatType> OpFpGpRegisterTargetSingleInputNoRounding(typename Decoder::OpFpGpRegisterTargetSingleInputNoRoundingOpcode opcode,int8_t dst,int8_t src)595 void OpFpGpRegisterTargetSingleInputNoRounding( 596 typename Decoder::OpFpGpRegisterTargetSingleInputNoRoundingOpcode opcode, 597 int8_t dst, 598 int8_t src) { 599 FpRegister arg = GetFRegAndUnboxNan<FloatType>(src); 600 Register result = no_register; 601 switch (opcode) { 602 case Decoder::OpFpGpRegisterTargetSingleInputNoRoundingOpcode::kFclass: 603 result = listener_->template FClass<FloatType>(arg); 604 break; 605 default: 606 return Undefined(); 607 } 608 SetRegOrIgnore(dst, result); 609 } 610 OpFpNoRounding(const typename Decoder::OpFpNoRoundingArgs & args)611 void OpFpNoRounding(const typename Decoder::OpFpNoRoundingArgs& args) { 612 switch (args.operand_type) { 613 case Decoder::FloatOperandType::kFloat: 614 return OpFpNoRounding<Float32>(args.opcode, args.dst, args.src1, args.src2); 615 case Decoder::FloatOperandType::kDouble: 616 return OpFpNoRounding<Float64>(args.opcode, args.dst, args.src1, args.src2); 617 default: 618 return Undefined(); 619 } 620 } 621 622 template <typename FloatType> OpFpNoRounding(const typename Decoder::OpFpNoRoundingOpcode opcode,int8_t dst,int8_t src1,int8_t src2)623 void OpFpNoRounding(const typename Decoder::OpFpNoRoundingOpcode opcode, 624 int8_t dst, 625 int8_t src1, 626 int8_t src2) { 627 FpRegister arg1 = no_fp_register; 628 FpRegister arg2 = no_fp_register; 629 FpRegister result = no_fp_register; 630 // The sign-injection instructions (FSGNJ, FSGNJN, FSGNJX) do not canonicalize NaNs; 631 // they manipulate the underlying bit patterns directly. 632 bool canonicalize_nan = true; 633 switch (opcode) { 634 case Decoder::OpFpNoRoundingOpcode::kFSgnj: 635 case Decoder::OpFpNoRoundingOpcode::kFSgnjn: 636 case Decoder::OpFpNoRoundingOpcode::kFSgnjx: 637 arg1 = GetFpReg(src1); 638 arg2 = GetFpReg(src2); 639 canonicalize_nan = false; 640 break; 641 default: 642 // Unboxing canonicalizes NaNs. 643 arg1 = GetFRegAndUnboxNan<FloatType>(src1); 644 arg2 = GetFRegAndUnboxNan<FloatType>(src2); 645 } 646 switch (opcode) { 647 case Decoder::OpFpNoRoundingOpcode::kFSgnj: 648 result = listener_->template FSgnj<FloatType>(arg1, arg2); 649 break; 650 case Decoder::OpFpNoRoundingOpcode::kFSgnjn: 651 result = listener_->template FSgnjn<FloatType>(arg1, arg2); 652 break; 653 case Decoder::OpFpNoRoundingOpcode::kFSgnjx: 654 result = listener_->template FSgnjx<FloatType>(arg1, arg2); 655 break; 656 case Decoder::OpFpNoRoundingOpcode::kFMin: 657 result = listener_->template FMin<FloatType>(arg1, arg2); 658 break; 659 case Decoder::OpFpNoRoundingOpcode::kFMax: 660 result = listener_->template FMax<FloatType>(arg1, arg2); 661 break; 662 default: 663 Undefined(); 664 return; 665 } 666 if (canonicalize_nan) { 667 result = CanonicalizeNan<FloatType>(result); 668 } 669 NanBoxAndSetFpReg<FloatType>(dst, result); 670 } 671 FmvFloatToInteger(const typename Decoder::FmvFloatToIntegerArgs & args)672 void FmvFloatToInteger(const typename Decoder::FmvFloatToIntegerArgs& args) { 673 FpRegister arg = GetFpReg(args.src); 674 Register result = no_register; 675 switch (args.operand_type) { 676 case Decoder::FloatOperandType::kFloat: 677 result = listener_->template FmvFloatToInteger<int32_t, Float32>(arg); 678 break; 679 case Decoder::FloatOperandType::kDouble: 680 result = listener_->template FmvFloatToInteger<int64_t, Float64>(arg); 681 break; 682 default: 683 Undefined(); 684 return; 685 } 686 SetRegOrIgnore(args.dst, result); 687 } 688 FmvIntegerToFloat(const typename Decoder::FmvIntegerToFloatArgs & args)689 void FmvIntegerToFloat(const typename Decoder::FmvIntegerToFloatArgs& args) { 690 Register arg = GetRegOrZero(args.src); 691 FpRegister result = no_fp_register; 692 switch (args.operand_type) { 693 case Decoder::FloatOperandType::kFloat: 694 result = listener_->template FmvIntegerToFloat<Float32, int32_t>(arg); 695 NanBoxAndSetFpReg<Float32>(args.dst, result); 696 break; 697 case Decoder::FloatOperandType::kDouble: 698 result = listener_->template FmvIntegerToFloat<Float64, int64_t>(arg); 699 NanBoxAndSetFpReg<Float64>(args.dst, result); 700 break; 701 default: 702 Undefined(); 703 return; 704 } 705 } 706 OpFpSingleInput(const typename Decoder::OpFpSingleInputArgs & args)707 void OpFpSingleInput(const typename Decoder::OpFpSingleInputArgs& args) { 708 switch (args.operand_type) { 709 case Decoder::FloatOperandType::kFloat: 710 return OpFpSingleInput<Float32>(args.opcode, args.rm, args.dst, args.src); 711 case Decoder::FloatOperandType::kDouble: 712 return OpFpSingleInput<Float64>(args.opcode, args.rm, args.dst, args.src); 713 default: 714 return Undefined(); 715 } 716 } 717 718 template <typename FloatType> OpFpSingleInput(typename Decoder::OpFpSingleInputOpcode opcode,int8_t rm,int8_t dst,int8_t src)719 void OpFpSingleInput(typename Decoder::OpFpSingleInputOpcode opcode, 720 int8_t rm, 721 int8_t dst, 722 int8_t src) { 723 FpRegister arg = GetFRegAndUnboxNan<FloatType>(src); 724 FpRegister result = no_fp_register; 725 Register frm = listener_->template GetCsr<CsrName::kFrm>(); 726 switch (opcode) { 727 case Decoder::OpFpSingleInputOpcode::kFSqrt: 728 result = listener_->template FSqrt<FloatType>(rm, frm, arg); 729 break; 730 default: 731 return Undefined(); 732 } 733 result = CanonicalizeNan<FloatType>(result); 734 NanBoxAndSetFpReg<FloatType>(dst, result); 735 } 736 OpFpSingleInputNoRounding(const typename Decoder::OpFpSingleInputNoRoundingArgs & args)737 void OpFpSingleInputNoRounding(const typename Decoder::OpFpSingleInputNoRoundingArgs& args) { 738 switch (args.operand_type) { 739 case Decoder::FloatOperandType::kFloat: 740 return OpFpSingleInputNoRounding<Float32>(args.opcode, args.dst, args.src); 741 case Decoder::FloatOperandType::kDouble: 742 return OpFpSingleInputNoRounding<Float64>(args.opcode, args.dst, args.src); 743 default: 744 return Undefined(); 745 } 746 } 747 748 template <typename FloatType> OpFpSingleInputNoRounding(typename Decoder::OpFpSingleInputNoRoundingOpcode opcode,int8_t dst,int8_t src)749 void OpFpSingleInputNoRounding(typename Decoder::OpFpSingleInputNoRoundingOpcode opcode, 750 int8_t dst, 751 int8_t src) { 752 FpRegister arg = GetFRegAndUnboxNan<FloatType>(src); 753 FpRegister result = no_fp_register; 754 switch (opcode) { 755 case Decoder::OpFpSingleInputNoRoundingOpcode::kFmv: 756 result = listener_->Fmv(arg); 757 break; 758 default: 759 Undefined(); 760 return; 761 } 762 result = CanonicalizeNan<FloatType>(result); 763 NanBoxAndSetFpReg<FloatType>(dst, result); 764 } 765 766 template <typename OpImmArgs> OpImm(OpImmArgs && args)767 void OpImm(OpImmArgs&& args) { 768 Register arg = GetRegOrZero(args.src); 769 Register result = Overloaded{[&](const typename Decoder::OpImmArgs& args) { 770 return listener_->OpImm(args.opcode, arg, args.imm); 771 }, 772 [&](const typename Decoder::OpImm32Args& args) { 773 return listener_->OpImm32(args.opcode, arg, args.imm); 774 }, 775 [&](const typename Decoder::ShiftImmArgs& args) { 776 switch (args.opcode) { 777 case Decoder::ShiftImmOpcode::kSlli: 778 return listener_->Slli(arg, args.imm); 779 case Decoder::ShiftImmOpcode::kSrli: 780 return listener_->Srli(arg, args.imm); 781 case Decoder::ShiftImmOpcode::kSrai: 782 return listener_->Srai(arg, args.imm); 783 default: 784 Undefined(); 785 return no_register; 786 } 787 }, 788 [&](const typename Decoder::ShiftImm32Args& args) { 789 return listener_->ShiftImm32(args.opcode, arg, args.imm); 790 }, 791 [&](const typename Decoder::BitmanipImmArgs& args) { 792 switch (args.opcode) { 793 case Decoder::BitmanipImmOpcode::kClz: 794 return listener_->template Clz<int64_t>(arg); 795 case Decoder::BitmanipImmOpcode::kCpop: 796 return listener_->template Cpop<int64_t>(arg); 797 case Decoder::BitmanipImmOpcode::kCtz: 798 return listener_->template Ctz<int64_t>(arg); 799 case Decoder::BitmanipImmOpcode::kSextb: 800 return listener_->template Sext<int8_t>(arg); 801 case Decoder::BitmanipImmOpcode::kSexth: 802 return listener_->template Sext<int16_t>(arg); 803 case Decoder::BitmanipImmOpcode::kOrcb: 804 return listener_->Orcb(arg); 805 case Decoder::BitmanipImmOpcode::kRev8: 806 return listener_->Rev8(arg); 807 case Decoder::BitmanipImmOpcode::kRori: 808 return listener_->Rori(arg, args.shamt); 809 case Decoder::BitmanipImmOpcode::kBclri: 810 return listener_->Bclri(arg, args.shamt); 811 case Decoder::BitmanipImmOpcode::kBexti: 812 return listener_->Bexti(arg, args.shamt); 813 case Decoder::BitmanipImmOpcode::kBinvi: 814 return listener_->Binvi(arg, args.shamt); 815 case Decoder::BitmanipImmOpcode::kBseti: 816 return listener_->Bseti(arg, args.shamt); 817 default: 818 Undefined(); 819 return no_register; 820 } 821 }, 822 [&](const typename Decoder::BitmanipImm32Args& args) { 823 switch (args.opcode) { 824 case Decoder::BitmanipImm32Opcode::kClzw: 825 return listener_->template Clz<int32_t>(arg); 826 case Decoder::BitmanipImm32Opcode::kCpopw: 827 return listener_->template Cpop<int32_t>(arg); 828 case Decoder::BitmanipImm32Opcode::kCtzw: 829 return listener_->template Ctz<int32_t>(arg); 830 case Decoder::BitmanipImm32Opcode::kRoriw: 831 return listener_->Roriw(arg, args.shamt); 832 case Decoder::BitmanipImm32Opcode::kSlliuw: 833 return listener_->Slliuw(arg, args.shamt); 834 default: 835 Undefined(); 836 return no_register; 837 } 838 }}(args); 839 SetRegOrIgnore(args.dst, result); 840 } 841 842 // TODO(b/300690740): develop and implement strategy which would allow us to support vector 843 // intrinsics not just in the interpreter. 844 OpVector(const typename Decoder::VLoadIndexedArgs & args)845 void OpVector(const typename Decoder::VLoadIndexedArgs& args) { 846 Register arg2 = GetRegOrZero(args.src); 847 listener_->OpVector(args, arg2); 848 } 849 OpVector(const typename Decoder::VLoadStrideArgs & args)850 void OpVector(const typename Decoder::VLoadStrideArgs& args) { 851 Register arg2 = GetRegOrZero(args.src); 852 Register arg3 = GetRegOrZero(args.std); 853 listener_->OpVector(args, arg2, arg3); 854 } 855 OpVector(const typename Decoder::VLoadUnitStrideArgs & args)856 void OpVector(const typename Decoder::VLoadUnitStrideArgs& args) { 857 Register arg2 = GetRegOrZero(args.src); 858 listener_->OpVector(args, arg2); 859 } 860 OpVector(const typename Decoder::VOpFVfArgs & args)861 void OpVector(const typename Decoder::VOpFVfArgs& args) { 862 // Note: we don't have information here to chosee between GetFRegAndUnboxNan<Float32> and 863 // GetFRegAndUnboxNan<Float64> because that depends on vtype. 864 FpRegister arg2 = GetFpReg(args.src2); 865 listener_->OpVector(args, arg2); 866 } 867 OpVector(const typename Decoder::VOpFVvArgs & args)868 void OpVector(const typename Decoder::VOpFVvArgs& args) { listener_->OpVector(args); } 869 OpVector(const typename Decoder::VOpIViArgs & args)870 void OpVector(const typename Decoder::VOpIViArgs& args) { listener_->OpVector(args); } 871 OpVector(const typename Decoder::VOpIVvArgs & args)872 void OpVector(const typename Decoder::VOpIVvArgs& args) { listener_->OpVector(args); } 873 OpVector(const typename Decoder::VOpMVvArgs & args)874 void OpVector(const typename Decoder::VOpMVvArgs& args) { listener_->OpVector(args); } 875 OpVector(const typename Decoder::VOpIVxArgs & args)876 void OpVector(const typename Decoder::VOpIVxArgs& args) { 877 Register arg2 = GetRegOrZero(args.src2); 878 listener_->OpVector(args, arg2); 879 } 880 OpVector(const typename Decoder::VOpMVxArgs & args)881 void OpVector(const typename Decoder::VOpMVxArgs& args) { 882 Register arg2 = GetRegOrZero(args.src2); 883 listener_->OpVector(args, arg2); 884 } 885 OpVector(const typename Decoder::VStoreIndexedArgs & args)886 void OpVector(const typename Decoder::VStoreIndexedArgs& args) { 887 Register arg2 = GetRegOrZero(args.src); 888 listener_->OpVector(args, arg2); 889 } 890 OpVector(const typename Decoder::VStoreStrideArgs & args)891 void OpVector(const typename Decoder::VStoreStrideArgs& args) { 892 Register arg2 = GetRegOrZero(args.src); 893 Register arg3 = GetRegOrZero(args.std); 894 listener_->OpVector(args, arg2, arg3); 895 } 896 OpVector(const typename Decoder::VStoreUnitStrideArgs & args)897 void OpVector(const typename Decoder::VStoreUnitStrideArgs& args) { 898 Register arg2 = GetRegOrZero(args.src); 899 listener_->OpVector(args, arg2); 900 } 901 Vsetivli(const typename Decoder::VsetivliArgs & args)902 void Vsetivli(const typename Decoder::VsetivliArgs& args) { 903 // Note: it's unclear whether args.avl should be treated similarly to x0 in Vsetvli or not. 904 // Keep implementation separate from Vsetvli to make it easier to adjust that code. 905 if (args.avl == 0) { 906 if (args.dst == 0) { 907 auto [vl_orig, vtype_orig] = GetVlAndVtypeCsr(); 908 auto [vl, vtype] = listener_->Vtestvli(vl_orig, vtype_orig, args.vtype); 909 SetVlAndVtypeCsr(vl, vtype); 910 } else { 911 auto [vl, vtype] = listener_->Vsetvlimax(args.vtype); 912 SetVlAndVtypeCsr(vl, vtype); 913 listener_->SetReg(args.dst, vl); 914 } 915 } else { 916 auto [vl, vtype] = listener_->Vsetivli(args.avl, args.vtype); 917 SetVlAndVtypeCsr(vl, vtype); 918 SetRegOrIgnore(args.dst, vl); 919 } 920 } 921 Vsetvl(const typename Decoder::VsetvlArgs & args)922 void Vsetvl(const typename Decoder::VsetvlArgs& args) { 923 Register vtype_new = listener_->GetReg(args.src2); 924 if (args.src1 == 0) { 925 if (args.dst == 0) { 926 auto [vl_orig, vtype_orig] = GetVlAndVtypeCsr(); 927 auto [vl, vtype] = listener_->Vtestvl(vl_orig, vtype_orig, vtype_new); 928 SetVlAndVtypeCsr(vl, vtype); 929 } else { 930 auto [vl, vtype] = listener_->Vsetvlmax(vtype_new); 931 SetVlAndVtypeCsr(vl, vtype); 932 listener_->SetReg(args.dst, vl); 933 } 934 } else { 935 Register avl = listener_->GetReg(args.src1); 936 auto [vl, vtype] = listener_->Vsetvl(avl, vtype_new); 937 SetVlAndVtypeCsr(vl, vtype); 938 SetRegOrIgnore(args.dst, vl); 939 } 940 } 941 Vsetvli(const typename Decoder::VsetvliArgs & args)942 void Vsetvli(const typename Decoder::VsetvliArgs& args) { 943 if (args.src == 0) { 944 if (args.dst == 0) { 945 auto [vl_orig, vtype_orig] = GetVlAndVtypeCsr(); 946 auto [vl, vtype] = listener_->Vtestvli(vl_orig, vtype_orig, args.vtype); 947 SetVlAndVtypeCsr(vl, vtype); 948 } else { 949 auto [vl, vtype] = listener_->Vsetvlimax(args.vtype); 950 SetVlAndVtypeCsr(vl, vtype); 951 listener_->SetReg(args.dst, vl); 952 } 953 } else { 954 Register avl = listener_->GetReg(args.src); 955 auto [vl, vtype] = listener_->Vsetvli(avl, args.vtype); 956 SetVlAndVtypeCsr(vl, vtype); 957 SetRegOrIgnore(args.dst, vl); 958 } 959 } 960 Store(const typename Decoder::StoreArgs & args)961 void Store(const typename Decoder::StoreArgs& args) { 962 Register arg = GetRegOrZero(args.src); 963 Register data = GetRegOrZero(args.data); 964 listener_->Store(args.operand_type, arg, args.offset, data); 965 } 966 Store(const typename Decoder::StoreFpArgs & args)967 void Store(const typename Decoder::StoreFpArgs& args) { 968 Register arg = GetRegOrZero(args.src); 969 FpRegister data = GetFpReg(args.data); 970 switch (args.operand_type) { 971 case Decoder::FloatOperandType::kFloat: 972 listener_->template StoreFp<Float32>(arg, args.offset, data); 973 break; 974 case Decoder::FloatOperandType::kDouble: 975 listener_->template StoreFp<Float64>(arg, args.offset, data); 976 break; 977 default: 978 Undefined(); 979 return; 980 } 981 } 982 983 // We may have executed a signal handler just after the syscall. If that handler changed x10, then 984 // overwriting x10 here would be incorrect. On the other hand asynchronous signals are unlikely to 985 // change CPU state, so we don't support this at the moment for simplicity." System(const typename Decoder::SystemArgs & args)986 void System(const typename Decoder::SystemArgs& args) { 987 if (args.opcode != Decoder::SystemOpcode::kEcall) { 988 return Undefined(); 989 } 990 Register syscall_nr = GetRegOrZero(17); 991 Register arg0 = GetRegOrZero(10); 992 Register arg1 = GetRegOrZero(11); 993 Register arg2 = GetRegOrZero(12); 994 Register arg3 = GetRegOrZero(13); 995 Register arg4 = GetRegOrZero(14); 996 Register arg5 = GetRegOrZero(15); 997 Register result = listener_->Ecall(syscall_nr, arg0, arg1, arg2, arg3, arg4, arg5); 998 SetRegOrIgnore(10, result); 999 } 1000 Undefined()1001 void Undefined() { listener_->Undefined(); }; 1002 1003 private: GetRegOrZero(uint8_t reg)1004 Register GetRegOrZero(uint8_t reg) { 1005 return reg == 0 ? listener_->GetImm(0) : listener_->GetReg(reg); 1006 } 1007 SetRegOrIgnore(uint8_t reg,Register value)1008 void SetRegOrIgnore(uint8_t reg, Register value) { 1009 if (reg != 0) { 1010 listener_->SetReg(reg, value); 1011 } 1012 } 1013 1014 // TODO(b/260725458): stop using GetCsrProcessor helper class and define lambda in GetCsr instead. 1015 // We need C++20 (https://wg21.link/P0428R2) for that. 1016 class GetCsrProcessor { 1017 public: GetCsrProcessor(Register & reg,SemanticsListener * listener)1018 GetCsrProcessor(Register& reg, SemanticsListener* listener) : reg_(reg), listener_(listener) {} 1019 template <CsrName kName> operator()1020 void operator()() { 1021 reg_ = listener_->template GetCsr<kName>(); 1022 } 1023 1024 private: 1025 Register& reg_; 1026 SemanticsListener* listener_; 1027 }; 1028 GetCsr(CsrName csr)1029 std::tuple<bool, Register> GetCsr(CsrName csr) { 1030 Register reg = no_register; 1031 GetCsrProcessor get_csr(reg, listener_); 1032 return {ProcessCsrNameAsTemplateParameter(csr, get_csr), reg}; 1033 } 1034 1035 // TODO(b/260725458): stop using SetCsrProcessor helper class and define lambda in SetCsr instead. 1036 // We need C++20 (https://wg21.link/P0428R2) for that. 1037 class SetCsrImmProcessor { 1038 public: SetCsrImmProcessor(uint8_t imm,SemanticsListener * listener)1039 SetCsrImmProcessor(uint8_t imm, SemanticsListener* listener) : imm_(imm), listener_(listener) {} 1040 template <CsrName kName> operator()1041 void operator()() { 1042 // Csr registers with two top bits set are read-only. 1043 // Attempts to write into such register raise illegal instruction exceptions. 1044 if constexpr (CsrWritable(kName)) { 1045 listener_->template SetCsr<kName>(imm_); 1046 } 1047 } 1048 1049 private: 1050 uint8_t imm_; 1051 SemanticsListener* listener_; 1052 }; 1053 SetCsr(CsrName csr,uint8_t imm)1054 bool SetCsr(CsrName csr, uint8_t imm) { 1055 // Csr registers with two top bits set are read-only. 1056 // Attempts to write into such register raise illegal instruction exceptions. 1057 if (!CsrWritable(csr)) { 1058 return false; 1059 } 1060 SetCsrImmProcessor set_csr(imm, listener_); 1061 return ProcessCsrNameAsTemplateParameter(csr, set_csr); 1062 } 1063 1064 // TODO(b/260725458): stop using SetCsrProcessor helper class and define lambda in SetCsr instead. 1065 // We need C++20 (https://wg21.link/P0428R2) for that. 1066 class SetCsrProcessor { 1067 public: SetCsrProcessor(Register reg,SemanticsListener * listener)1068 SetCsrProcessor(Register reg, SemanticsListener* listener) : reg_(reg), listener_(listener) {} 1069 template <CsrName kName> operator()1070 void operator()() { 1071 // Csr registers with two top bits set are read-only. 1072 // Attempts to write into such register raise illegal instruction exceptions. 1073 if constexpr (CsrWritable(kName)) { 1074 listener_->template SetCsr<kName>(reg_); 1075 } 1076 } 1077 1078 private: 1079 Register reg_; 1080 SemanticsListener* listener_; 1081 }; 1082 SetCsr(CsrName csr,Register reg)1083 bool SetCsr(CsrName csr, Register reg) { 1084 // Csr registers with two top bits set are read-only. 1085 // Attempts to write into such register raise illegal instruction exceptions. 1086 if (!CsrWritable(csr)) { 1087 return false; 1088 } 1089 SetCsrProcessor set_csr(reg, listener_); 1090 return ProcessCsrNameAsTemplateParameter(csr, set_csr); 1091 } 1092 1093 // Floating point instructions in RISC-V are encoded in a way where you may find out size of 1094 // operand (single-precision, double-precision, half-precision or quad-precesion; the latter 1095 // two optional) from the instruction encoding without determining the full form of instruction. 1096 // 1097 // Sources and targets are also specified via dedicated bits in opcodes. 1098 // 1099 // This allows us to split instruction handling in four steps: 1100 // 1. Load operands from register and convert it into a form suitable for host. 1101 // 2. Execute operations specified by opcode. 1102 // 3. Normalize NaNs if host and guest architctures handled them differently. 1103 // 4. Encode results as required by RISC-V (if host doesn't do that). 1104 // 1105 // Note that in case of execution of RISC-V on RISC-V all steps except #2 are not doing anything. 1106 1107 // Step #1: 1108 // • GetFpReg — for instructions like fsw or fmv.x.w use GetFpReg which doesn't change value. 1109 // • GetFRegAndBoxNan — for most instructions (improperly boxed narrow float is turned into NaN). GetFpReg(uint8_t reg)1110 FpRegister GetFpReg(uint8_t reg) { return listener_->GetFpReg(reg); } 1111 template <typename FloatType> GetFRegAndUnboxNan(uint8_t reg)1112 FpRegister GetFRegAndUnboxNan(uint8_t reg) { 1113 return listener_->template GetFRegAndUnboxNan<FloatType>(reg); 1114 } 1115 1116 // Step #3. 1117 template <typename FloatType> CanonicalizeNan(FpRegister value)1118 FpRegister CanonicalizeNan(FpRegister value) { 1119 return listener_->template CanonicalizeNan<FloatType>(value); 1120 } 1121 1122 // Step #4. Note the assymetry: step #1 may skip the NaN unboxing (would use GetFpReg if so), 1123 // but step #4 boxes uncoditionally (if actual instruction doesn't do that on host). 1124 template <typename FloatType> NanBoxAndSetFpReg(uint8_t reg,FpRegister value)1125 void NanBoxAndSetFpReg(uint8_t reg, FpRegister value) { 1126 listener_->template NanBoxAndSetFpReg<FloatType>(reg, value); 1127 } 1128 GetVlAndVtypeCsr()1129 std::tuple<Register, Register> GetVlAndVtypeCsr() { 1130 Register vl_orig = listener_->template GetCsr<CsrName::kVl>(); 1131 Register vtype_orig = listener_->template GetCsr<CsrName::kVtype>(); 1132 return {vl_orig, vtype_orig}; 1133 } 1134 SetVlAndVtypeCsr(Register vl,Register vtype)1135 void SetVlAndVtypeCsr(Register vl, Register vtype) { 1136 listener_->template SetCsr<CsrName::kVtype>(vtype); 1137 listener_->template SetCsr<CsrName::kVl>(vl); 1138 } 1139 1140 SemanticsListener* listener_; 1141 }; 1142 1143 } // namespace berberis 1144 1145 #endif // BERBERIS_DECODER_RISCV64_SEMANTICS_PLAYER_H_ 1146