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_DECODER_H_ 18 #define BERBERIS_DECODER_RISCV64_DECODER_H_ 19 20 #include <climits> 21 #include <cstdint> 22 #include <cstring> 23 #include <type_traits> 24 25 #include "berberis/base/bit_util.h" 26 #include "berberis/base/checks.h" 27 28 namespace berberis { 29 30 // Decode() method takes a sequence of bytes and decodes it into the instruction opcode and fields. 31 // The InsnConsumer's method corresponding to the decoded opcode is called with the decoded fields 32 // as an argument. Returned is the instruction size. 33 template <class InsnConsumer> 34 class Decoder { 35 public: Decoder(InsnConsumer * insn_consumer)36 explicit Decoder(InsnConsumer* insn_consumer) : insn_consumer_(insn_consumer) {} 37 38 // https://eel.is/c++draft/enum#dcl.enum-8 39 // For an enumeration whose underlying type is fixed, the values of the enumeration are the values 40 // of the underlying type. 41 42 // To ensure that there are no surprises we specify that type in all enums below. 43 44 enum class AmoOpcode : uint8_t { 45 kLr = 0b00010, 46 kSc = 0b00011, 47 kAmoswap = 0b00001, 48 kAmoadd = 0b00000, 49 kAmoxor = 0b00100, 50 kAmoand = 0b01100, 51 kAmoor = 0b01000, 52 kAmomin = 0b10000, 53 kAmomax = 0b10100, 54 kAmominu = 0b11000, 55 kAmomaxu = 0b11100, 56 }; 57 58 enum class BranchOpcode : uint8_t { 59 kBeq = 0b000, 60 kBne = 0b001, 61 kBlt = 0b100, 62 kBge = 0b101, 63 kBltu = 0b110, 64 kBgeu = 0b111, 65 }; 66 67 enum class CsrOpcode : uint8_t { 68 kCsrrw = 0b01, 69 kCsrrs = 0b10, 70 kCsrrc = 0b11, 71 }; 72 73 enum class CsrImmOpcode : uint8_t { 74 kCsrrwi = 0b01, 75 kCsrrsi = 0b10, 76 kCsrrci = 0b11, 77 }; 78 79 enum class FmaOpcode : uint8_t { 80 kFmadd = 0b00, 81 kFmsub = 0b01, 82 kFnmsub = 0b10, 83 kFnmadd = 0b11, 84 }; 85 86 enum class FenceOpcode : uint8_t { 87 kFence = 0b0000, 88 kFenceTso = 0b1000, 89 }; 90 91 enum class OpOpcode : uint16_t { 92 kAdd = 0b0000'000'000, 93 kSub = 0b0100'000'000, 94 kSll = 0b0000'000'001, 95 kSlt = 0b0000'000'010, 96 kSltu = 0b0000'000'011, 97 kXor = 0b0000'000'100, 98 kSrl = 0b0000'000'101, 99 kSra = 0b0100'000'101, 100 kOr = 0b0000'000'110, 101 kAnd = 0b0000'000'111, 102 kMul = 0b0000'001'000, 103 kMulh = 0b0000'001'001, 104 kMulhsu = 0b0000'001'010, 105 kMulhu = 0b0000'001'011, 106 kDiv = 0b0000'001'100, 107 kDivu = 0b0000'001'101, 108 kRem = 0b0000'001'110, 109 kRemu = 0b0000'001'111, 110 kAndn = 0b0100'000'111, 111 kOrn = 0b0100'000'110, 112 kXnor = 0b0100'000'100, 113 kMax = 0b0000'101'110, 114 kMaxu = 0b0000'101'111, 115 kMin = 0b0000'101'100, 116 kMinu = 0b0000'101'101, 117 kRol = 0b0110'000'001, 118 kRor = 0b0110'000'101, 119 kSh1add = 0b0010'000'010, 120 kSh2add = 0b0010'000'100, 121 kSh3add = 0b0010'000'110, 122 kBclr = 0b0100'100'001, 123 kBext = 0b0100'100'101, 124 kBinv = 0b0110'100'001, 125 kBset = 0b0010'100'001, 126 }; 127 128 enum class Op32Opcode : uint16_t { 129 kAddw = 0b0000'000'000, 130 kAdduw = 0b0000'100'000, 131 kSubw = 0b0100'000'000, 132 kSllw = 0b0000'000'001, 133 kSrlw = 0b0000'000'101, 134 kSraw = 0b0100'000'101, 135 kMulw = 0b0000'001'000, 136 kDivw = 0b0000'001'100, 137 kDivuw = 0b0000'001'101, 138 kRemw = 0b0000'001'110, 139 kRemuw = 0b0000'001'111, 140 kRolw = 0b0110'000'001, 141 kRorw = 0b0110'000'101, 142 kSh1adduw = 0b0010'000'010, 143 kSh2adduw = 0b0010'000'100, 144 kSh3adduw = 0b0010'000'110, 145 }; 146 147 enum class OpSingleInputOpcode : uint16_t { 148 kZexth = 0b0000'100'100, 149 kZextb, 150 kZextw, 151 kSextb, 152 kSexth, 153 }; 154 155 enum class OpFpGpRegisterTargetNoRoundingOpcode : uint8_t { 156 kFle = 0b00'000, 157 kFlt = 0b00'001, 158 kFeq = 0b00'010, 159 }; 160 161 enum class OpFpGpRegisterTargetSingleInputNoRoundingOpcode : uint16_t { 162 kFclass = 0b00'00000'001, 163 }; 164 165 enum class OpFpNoRoundingOpcode : uint8_t { 166 kFSgnj = 0b00'000, 167 kFSgnjn = 0b00'001, 168 kFSgnjx = 0b00'010, 169 kFMin = 0b01'000, 170 kFMax = 0b01'001, 171 }; 172 173 enum class OpFpOpcode : uint8_t { 174 kFAdd = 0b00, 175 kFSub = 0b01, 176 kFMul = 0b10, 177 kFDiv = 0b11, 178 }; 179 180 enum class OpFpSingleInputOpcode : uint8_t { 181 kFSqrt = 0b11'00000, 182 }; 183 184 enum class OpFpSingleInputNoRoundingOpcode : uint8_t { 185 kFmv, 186 }; 187 188 enum class OpImmOpcode : uint8_t { 189 kAddi = 0b000, 190 kSlti = 0b010, 191 kSltiu = 0b011, 192 kXori = 0b100, 193 kOri = 0b110, 194 kAndi = 0b111, 195 }; 196 197 enum class OpImm32Opcode : uint8_t { 198 kAddiw = 0b000, 199 }; 200 201 enum class ShiftImmOpcode : uint8_t { 202 kSlli = 0b000000'001, 203 kSrli = 0b000000'101, 204 kSrai = 0b010000'101, 205 }; 206 207 enum class ShiftImm32Opcode : uint16_t { 208 kSlliw = 0b0000000'001, 209 kSrliw = 0b0000000'101, 210 kSraiw = 0b0100000'101, 211 }; 212 213 enum class BitmanipImmOpcode : uint16_t { 214 kClz = 0b0110000'00000'001, 215 kCpop = 0b0110000'00010'001, 216 kCtz = 0b0110000'00001'001, 217 kSextb = 0b0110000'00100'001, 218 kSexth = 0b0110000'00101'001, 219 kOrcb = 0b0010100'00111'101, 220 kRev8 = 0b0110101'11000'101, 221 kRori = 0b011000'101, 222 kBclri = 0b010010'001, 223 kBexti = 0b010010'101, 224 kBinvi = 0b011010'001, 225 kBseti = 0b001010'001, 226 }; 227 228 enum class BitmanipImm32Opcode : uint16_t { 229 kClzw = 0b0110000'00000'001, 230 kCpopw = 0b0110000'00010'001, 231 kCtzw = 0b0110000'00001'001, 232 kRoriw = 0b0110000'101, 233 kSlliuw = 0b0000100'001, 234 }; 235 236 enum class SystemOpcode : uint32_t { 237 kEcall = 0b000000000000'00000'000'00000, 238 kEbreak = 0b000000000001'00000'000'00000, 239 }; 240 241 enum class VLUmOpOpcode : uint8_t { 242 kVleXX = 0b00000, 243 kVlXreXX = 0b01000, 244 kVleXXff = 0b10000, 245 kVlm = 0b01011, 246 }; 247 248 enum class VOpFVfOpcode : uint8_t { 249 kVfaddvf = 0b000000, 250 kVfsubvf = 0b000010, 251 kVfminvf = 0b000100, 252 kVfmaxvf = 0b000110, 253 kVfsgnjvf = 0b001000, 254 kVfsgnjnvf = 0b001001, 255 kVfsgnjxvf = 0b001010, 256 kVfslide1upvf = 0b001110, 257 kVfslide1downvf = 0b001111, 258 kVfmvsf = 0b010000, 259 kVfmergevf = 0b010111, // Also kVfmv.vf 260 kVmfeqvf = 0b011000, 261 kVmflevf = 0b011001, 262 kVmfltvf = 0b011011, 263 kVmfnevf = 0b011100, 264 kVmfgtvf = 0b011101, 265 kVmfgevf = 0b011111, 266 kVfdivvf = 0b100000, 267 kVfrdivvf = 0b100001, 268 kVfmulvf = 0b100100, 269 kVfrsubvf = 0b100111, 270 kVfmaddvf = 0b101000, 271 kVfnmaddvf = 0b101001, 272 kVfmsubvf = 0b101010, 273 kVfnmsubvf = 0b101011, 274 kVfmaccvf = 0b101100, 275 kVfnmaccvf = 0b101101, 276 kVfmsacvf = 0b101110, 277 kVfnmsacvf = 0b101111, 278 kVfwaddvf = 0b110000, 279 kVfwsubvf = 0b110010, 280 kVfwaddwf = 0b110100, 281 kVfwsubwf = 0b110110, 282 kVfwmulvf = 0b111000, 283 kVfwmaccvf = 0b111100, 284 kVfwnmaccvf = 0b111101, 285 kVfwmsacvf = 0b111110, 286 kVfwnmsacvf = 0b111111, 287 }; 288 289 enum class VOpFVvOpcode : uint8_t { 290 kVfaddvv = 0b000000, 291 kVfredusumvs = 0b000001, 292 kVfsubvv = 0b000010, 293 kVfredosumvs = 0b000011, 294 kVfminvv = 0b000100, 295 kVfredminvs = 0b000101, 296 kVfmaxvv = 0b000110, 297 kVfredmaxvs = 0b000111, 298 kVfsgnjvv = 0b001000, 299 kVfsgnjnvv = 0b001001, 300 kVfsgnjxvv = 0b001010, 301 kVfmvfs = 0b010000, 302 kVFUnary0 = 0b010010, 303 kVFUnary1 = 0b010011, 304 kVmfeqvv = 0b011000, 305 kVmflevv = 0b011001, 306 kVmfltvv = 0b011011, 307 kVmfnevv = 0b011100, 308 kVfdivvv = 0b100000, 309 kVfmulvv = 0b100100, 310 kVfmaddvv = 0b101000, 311 kVfnmaddvv = 0b101001, 312 kVfmsubvv = 0b101010, 313 kVfnmsubvv = 0b101011, 314 kVfmaccvv = 0b101100, 315 kVfnmaccvv = 0b101101, 316 kVfmsacvv = 0b101110, 317 kVfnmsacvv = 0b101111, 318 kVfwaddvv = 0b110000, 319 kVfwredusumvs = 0b110001, 320 kVfwsubvv = 0b110010, 321 kVfwredosumvs = 0b110011, 322 kVfwaddwv = 0b110100, 323 kVfwsubwv = 0b110110, 324 kVfwmulvv = 0b111000, 325 kVfwmaccvv = 0b111100, 326 kVfwnmaccvv = 0b111101, 327 kVfwmsacvv = 0b111110, 328 kVfwnmsacvv = 0b111111, 329 }; 330 331 enum class VOpIViOpcode : uint8_t { 332 kVaddvi = 0b000000, 333 kVrsubvi = 0b000011, 334 kVandvi = 0b001001, 335 kVorvi = 0b001010, 336 kVxorvi = 0b001011, 337 kVrgathervi = 0b001100, 338 kVslideupvi = 0b001110, 339 kVslidedownvi = 0b001111, 340 kVadcvi = 0b010000, 341 kVmadcvi = 0b010001, 342 kVmergevi = 0b010111, // Also kVmv.vi 343 kVmseqvi = 0b011000, 344 kVmsnevi = 0b011001, 345 kVmsleuvi = 0b011100, 346 kVmslevi = 0b011101, 347 kVmsgtuvi = 0b011110, 348 kVmsgtvi = 0b011111, 349 kVsadduvi = 0b100000, 350 kVsaddvi = 0b100001, 351 kVsllvi = 0b100101, 352 kVmvXrv = 0b100111, 353 kVsrlvi = 0b101000, 354 kVsravi = 0b101001, 355 kVssrlvi = 0b101010, 356 kVssravi = 0b101011, 357 kVnsrlwi = 0b101100, 358 kVnsrawi = 0b101101, 359 kVnclipuwi = 0b101110, 360 kVnclipwi = 0b101111, 361 }; 362 363 enum class VOpIVvOpcode : uint8_t { 364 kVaddvv = 0b000000, 365 kVsubvv = 0b000010, 366 kVminuvv = 0b000100, 367 kVminvv = 0b000101, 368 kVmaxuvv = 0b000110, 369 kVmaxvv = 0b000111, 370 kVandvv = 0b001001, 371 kVorvv = 0b001010, 372 kVxorvv = 0b001011, 373 kVrgathervv = 0b001100, 374 kVrgatherei16vv = 0b001110, 375 kVadcvv = 0b010000, 376 kVmadcvv = 0b010001, 377 kVsbcvv = 0b010010, 378 kVmsbcvv = 0b010011, 379 kVmergevv = 0b010111, // Also kVmv.vv 380 kVmseqvv = 0b011000, 381 kVmsnevv = 0b011001, 382 kVmsltuvv = 0b011010, 383 kVmsltvv = 0b011011, 384 kVmsleuvv = 0b011100, 385 kVmslevv = 0b011101, 386 kVsadduvv = 0b100000, 387 kVsaddvv = 0b100001, 388 kVssubuvv = 0b100010, 389 kVssubvv = 0b100011, 390 kVsllvv = 0b100101, 391 kVsmulvv = 0b100111, 392 kVsrlvv = 0b101000, 393 kVsravv = 0b101001, 394 kVssrlvv = 0b101010, 395 kVssravv = 0b101011, 396 kVnsrlwv = 0b101100, 397 kVnsrawv = 0b101101, 398 kVnclipuwv = 0b101110, 399 kVnclipwv = 0b101111, 400 kVwredsumuvs = 0b110000, 401 kVwredsumvs = 0b110001, 402 }; 403 404 enum class VOpIVxOpcode : uint8_t { 405 kVaddvx = 0b000000, 406 kVsubvx = 0b000010, 407 kVrsubvx = 0b000011, 408 kVminuvx = 0b000100, 409 kVminvx = 0b000101, 410 kVmaxuvx = 0b000110, 411 kVmaxvx = 0b000111, 412 kVandvx = 0b001001, 413 kVorvx = 0b001010, 414 kVxorvx = 0b001011, 415 kVrgathervx = 0b001100, 416 kVslideupvx = 0b001110, 417 kVslidedownvx = 0b001111, 418 kVadcvx = 0b010000, 419 kVmadcvx = 0b010001, 420 kVsbcvx = 0b010010, 421 kVmsbcvx = 0b010011, 422 kVmergevx = 0b010111, // Also Vmv.vx 423 kVmseqvx = 0b011000, 424 kVmsnevx = 0b011001, 425 kVmsltuvx = 0b011010, 426 kVmsltvx = 0b011011, 427 kVmsleuvx = 0b011100, 428 kVmslevx = 0b011101, 429 kVmsgtuvx = 0b011110, 430 kVmsgtvx = 0b011111, 431 kVsadduvx = 0b100000, 432 kVsaddvx = 0b100001, 433 kVssubuvx = 0b100010, 434 kVssubvx = 0b100011, 435 kVsllvx = 0b100101, 436 kVsmulvx = 0b100111, 437 kVsrlvx = 0b101000, 438 kVsravx = 0b101001, 439 kVssrlvx = 0b101010, 440 kVssravx = 0b101011, 441 kVnsrlwx = 0b101100, 442 kVnsrawx = 0b101101, 443 kVnclipuwx = 0b101110, 444 kVnclipwx = 0b101111, 445 }; 446 447 enum class VOpMVvOpcode : uint8_t { 448 kVredsumvs = 0b000000, 449 kVredandvs = 0b000001, 450 kVredorvs = 0b000010, 451 kVredxorvs = 0b000011, 452 kVredminuvs = 0b000100, 453 kVredminvs = 0b000101, 454 kVredmaxuvs = 0b000110, 455 kVredmaxvs = 0b000111, 456 kVaadduvv = 0b001000, 457 kVaaddvv = 0b001001, 458 kVasubuvv = 0b001010, 459 kVasubvv = 0b001011, 460 kVWXUnary0 = 0b010000, 461 kVFUnary0 = 0b010010, 462 kVMUnary0 = 0b010100, 463 kVmandnmm = 0b011000, 464 kVmandmm = 0b011001, 465 kVmormm = 0b011010, 466 kVmxormm = 0b011011, 467 kVmornmm = 0b011100, 468 kVmnandmm = 0b011101, 469 kVmnormm = 0b011110, 470 kVmxnormm = 0b011111, 471 kVdivuvv = 0b100000, 472 kVdivvv = 0b100001, 473 kVremuvv = 0b100010, 474 kVremvv = 0b100011, 475 kVmulhuvv = 0b100100, 476 kVmulvv = 0b100101, 477 kVmulhsuvv = 0b100110, 478 kVmulhvv = 0b100111, 479 kVmaddvv = 0b101001, 480 kVnmsubvv = 0b101011, 481 kVmaccvv = 0b101101, 482 kVnmsacvv = 0b101111, 483 kVwadduvv = 0b110000, 484 kVwaddvv = 0b110001, 485 kVwsubuvv = 0b110010, 486 kVwsubvv = 0b110011, 487 kVwadduwv = 0b110100, 488 kVwaddwv = 0b110101, 489 kVwsubuwv = 0b110110, 490 kVwsubwv = 0b110111, 491 kVwmuluvv = 0b111000, 492 kVwmulsuvv = 0b111010, 493 kVwmulvv = 0b111011, 494 kVwmaccuvv = 0b111100, 495 kVwmaccvv = 0b111101, 496 kVwmaccsuvv = 0b111111, 497 }; 498 499 enum class VOpMVxOpcode : uint8_t { 500 kVaadduvx = 0b001000, 501 kVaaddvx = 0b001001, 502 kVasubuvx = 0b001010, 503 kVasubvx = 0b001011, 504 kVslide1upvx = 0b001110, 505 kVslide1downvx = 0b001111, 506 kVRXUnary0 = 0b010000, 507 kVdivuvx = 0b100000, 508 kVdivvx = 0b100001, 509 kVremuvx = 0b100010, 510 kVremvx = 0b100011, 511 kVmulhuvx = 0b100100, 512 kVmulvx = 0b100101, 513 kVmulhsuvx = 0b100110, 514 kVmulhvx = 0b100111, 515 kVmaddvx = 0b101001, 516 kVnmsubvx = 0b101011, 517 kVmaccvx = 0b101101, 518 kVnmsacvx = 0b101111, 519 kVwadduvx = 0b110000, 520 kVwaddvx = 0b110001, 521 kVwsubuvx = 0b110010, 522 kVwsubvx = 0b110011, 523 kVwadduwx = 0b110100, 524 kVwaddwx = 0b110101, 525 kVwsubuwx = 0b110110, 526 kVwsubwx = 0b110111, 527 kVwmuluvx = 0b111000, 528 kVwmulsuvx = 0b111010, 529 kVwmulvx = 0b111011, 530 kVwmaccuvx = 0b111100, 531 kVwmaccvx = 0b111101, 532 kVwmaccusvx = 0b111110, 533 kVwmaccsuvx = 0b111111, 534 }; 535 536 enum class VSUmOpOpcode : uint8_t { 537 kVseXX = 0b00000, 538 kVsX = 0b01000, 539 kVsm = 0b01011, 540 }; 541 542 enum class VFUnary0Opcode : uint8_t { 543 kVfcvtxufv = 0b00000, 544 kVfcvtxfv = 0b00001, 545 kVfcvtfxuv = 0b00010, 546 kVfcvtfxv = 0b00011, 547 kVfcvtrtzxufv = 0b00110, 548 kVfcvtrtzxfv = 0b00111, 549 kVfwcvtxufv = 0b01000, 550 kVfwcvtxfv = 0b01001, 551 kVfwcvtfxuv = 0b01010, 552 kVfwcvtfxv = 0b01011, 553 kVfwcvtffv = 0b01100, 554 kVfwcvtrtzxufv = 0b01110, 555 kVfwcvtrtzxfv = 0b01111, 556 kVfncvtxufw = 0b10000, 557 kVfncvtxfw = 0b10001, 558 kVfncvtfxuw = 0b10010, 559 kVfncvtfxw = 0b10011, 560 kVfncvtffw = 0b10100, 561 kVfncvtrodffw = 0b10101, 562 kVfncvtrtzxufw = 0b10110, 563 kVfncvtrtzxfw = 0b10111, 564 }; 565 566 enum class VFUnary1Opcode : uint8_t { 567 kVfsqrtv = 0b00000, 568 kVfrsqrt7v = 0b00100, 569 kVfclassv = 0b10000, 570 }; 571 572 enum class VRXUnary0Opcode : uint8_t { 573 kVmvsx = 0b00000, 574 }; 575 576 enum class VWXUnary0Opcode : uint8_t { 577 kVmvxs = 0b00000, 578 kVcpopm = 0b10000, 579 kVfirstm = 0b10001, 580 }; 581 582 enum class VMUnary0Opcode : uint8_t { 583 kVmsbfm = 0b00001, 584 kVmsofm = 0b00010, 585 kVmsifm = 0b00011, 586 kViotam = 0b10000, 587 kVidv = 0b10001, 588 }; 589 590 enum class VXUnary0Opcode : uint8_t { 591 kVzextvf8m = 0b00010, 592 kVsextvf8m = 0b00011, 593 kVzextvf4m = 0b00100, 594 kVsextvf4m = 0b00101, 595 kVzextvf2m = 0b00110, 596 kVsextvf2m = 0b00111, 597 kVbrev8v = 0b01000, 598 }; 599 600 // Load/Store instruction include 3bit “width” field while all other floating-point instructions 601 // include 2bit “fmt” field. 602 // 603 // Decoder unifies these differences and uses FloatOperandType for types of all floating-point 604 // operands. 605 // 606 // Load/Store for regular instruction coulnd't be simiarly unified: Load instructions include 607 // seven types, while Store instructions have only four. 608 // 609 // Fcvt instructions have their own operand type encoding because they are only supporting 32bit 610 // and 64bit operands, there is no support for 8bit and 16bit operands. 611 // 612 // This is because Load can perform either sign-extension or zero-extension for all sizes except 613 // 64bit (which doesn't need neither sign-extension nor zero-extension since operand size is the 614 // same as register size in that case). 615 616 enum class FcvtOperandType : uint8_t { 617 k32bitSigned = 0b00000, 618 k32bitUnsigned = 0b00001, 619 k64bitSigned = 0b00010, 620 k64bitUnsigned = 0b00011, 621 }; 622 623 enum class FloatOperandType : uint8_t { 624 kFloat = 0b00, 625 kDouble = 0b01, 626 kHalf = 0b10, 627 kQuad = 0b11, 628 }; 629 630 // Used in vector loads and stores, and also in scalar stores. 631 // Scalar loads use different type because loads needs to either sign-extend value or zero-extend 632 // it which makes difference between signed and unsigned types meaningful. 633 enum class MemoryDataOperandType : uint8_t { 634 k8bit = 0b000, 635 k16bit = 0b001, 636 k32bit = 0b010, 637 k64bit = 0b011, 638 }; 639 640 enum class LoadOperandType : uint8_t { 641 k8bitSigned = 0b000, 642 k16bitSigned = 0b001, 643 k32bitSigned = 0b010, 644 k64bit = 0b011, 645 k8bitUnsigned = 0b100, 646 k16bitUnsigned = 0b101, 647 k32bitUnsigned = 0b110, 648 }; 649 650 struct AmoArgs { 651 AmoOpcode opcode; 652 MemoryDataOperandType operand_type; 653 uint8_t dst; 654 uint8_t src1; 655 uint8_t src2; 656 bool rl : 1; 657 bool aq : 1; 658 }; 659 660 struct BranchArgs { 661 BranchOpcode opcode; 662 uint8_t src1; 663 uint8_t src2; 664 int16_t offset; 665 }; 666 667 struct CsrArgs { 668 CsrOpcode opcode; 669 uint8_t dst; 670 uint8_t src; 671 uint16_t csr; 672 }; 673 674 struct CsrImmArgs { 675 CsrImmOpcode opcode; 676 uint8_t dst; 677 uint8_t imm; 678 uint16_t csr; 679 }; 680 681 struct FcvtFloatToFloatArgs { 682 FloatOperandType dst_type; 683 FloatOperandType src_type; 684 uint8_t dst; 685 uint8_t src; 686 uint8_t rm; 687 }; 688 689 struct FcvtFloatToIntegerArgs { 690 FcvtOperandType dst_type; 691 FloatOperandType src_type; 692 uint8_t dst; 693 uint8_t src; 694 uint8_t rm; 695 }; 696 697 struct FcvtIntegerToFloatArgs { 698 FloatOperandType dst_type; 699 FcvtOperandType src_type; 700 uint8_t dst; 701 uint8_t src; 702 uint8_t rm; 703 }; 704 705 struct FenceArgs { 706 FenceOpcode opcode; 707 uint8_t dst; 708 uint8_t src; 709 bool sw : 1; 710 bool sr : 1; 711 bool so : 1; 712 bool si : 1; 713 bool pw : 1; 714 bool pr : 1; 715 bool po : 1; 716 bool pi : 1; 717 }; 718 719 struct FenceIArgs { 720 uint8_t dst; 721 uint8_t src; 722 int16_t imm; 723 }; 724 725 struct FmaArgs { 726 FmaOpcode opcode; 727 FloatOperandType operand_type; 728 uint8_t dst; 729 uint8_t src1; 730 uint8_t src2; 731 uint8_t src3; 732 uint8_t rm; 733 }; 734 735 struct JumpAndLinkArgs { 736 uint8_t dst; 737 int32_t offset; 738 uint8_t insn_len; 739 }; 740 741 struct JumpAndLinkRegisterArgs { 742 uint8_t dst; 743 uint8_t base; 744 int16_t offset; 745 uint8_t insn_len; 746 }; 747 748 template <typename OpcodeType> 749 struct OpArgsTemplate { 750 OpcodeType opcode; 751 uint8_t dst; 752 uint8_t src1; 753 uint8_t src2; 754 }; 755 756 struct OpSingleInputArgs { 757 OpSingleInputOpcode opcode; 758 uint8_t dst; 759 uint8_t src; 760 }; 761 762 using OpArgs = OpArgsTemplate<OpOpcode>; 763 using Op32Args = OpArgsTemplate<Op32Opcode>; 764 765 struct OpFpArgs { 766 OpFpOpcode opcode; 767 FloatOperandType operand_type; 768 uint8_t dst; 769 uint8_t src1; 770 uint8_t src2; 771 uint8_t rm; 772 }; 773 774 struct OpFpGpRegisterTargetNoRoundingArgs { 775 OpFpGpRegisterTargetNoRoundingOpcode opcode; 776 FloatOperandType operand_type; 777 uint8_t dst; 778 uint8_t src1; 779 uint8_t src2; 780 }; 781 782 struct OpFpGpRegisterTargetSingleInputNoRoundingArgs { 783 OpFpGpRegisterTargetSingleInputNoRoundingOpcode opcode; 784 FloatOperandType operand_type; 785 uint8_t dst; 786 uint8_t src; 787 }; 788 789 struct FmvFloatToIntegerArgs { 790 FloatOperandType operand_type; 791 uint8_t dst; 792 uint8_t src; 793 }; 794 795 struct FmvIntegerToFloatArgs { 796 FloatOperandType operand_type; 797 uint8_t dst; 798 uint8_t src; 799 }; 800 801 struct OpFpNoRoundingArgs { 802 OpFpNoRoundingOpcode opcode; 803 FloatOperandType operand_type; 804 uint8_t dst; 805 uint8_t src1; 806 uint8_t src2; 807 }; 808 809 struct OpFpSingleInputArgs { 810 OpFpSingleInputOpcode opcode; 811 FloatOperandType operand_type; 812 uint8_t dst; 813 uint8_t src; 814 uint8_t rm; 815 }; 816 817 struct OpFpSingleInputNoRoundingArgs { 818 OpFpSingleInputNoRoundingOpcode opcode; 819 FloatOperandType operand_type; 820 uint8_t dst; 821 uint8_t src; 822 }; 823 824 template <typename OpcodeType> 825 struct OpImmArgsTemplate { 826 OpcodeType opcode; 827 uint8_t dst; 828 uint8_t src; 829 int16_t imm; 830 }; 831 832 using OpImmArgs = OpImmArgsTemplate<OpImmOpcode>; 833 using OpImm32Args = OpImmArgsTemplate<OpImm32Opcode>; 834 835 struct VLoadIndexedArgs { 836 MemoryDataOperandType width; 837 bool vm; 838 bool ordered; 839 uint8_t nf; 840 uint8_t dst; 841 uint8_t src; 842 uint8_t idx; 843 }; 844 845 struct VLoadStrideArgs { 846 MemoryDataOperandType width; 847 bool vm; 848 bool ordered; 849 uint8_t nf; 850 uint8_t dst; 851 uint8_t src; 852 uint8_t std; 853 }; 854 855 struct VLoadUnitStrideArgs { 856 VLUmOpOpcode opcode; 857 MemoryDataOperandType width; 858 bool vm; 859 uint8_t nf; 860 uint8_t dst; 861 uint8_t src; 862 }; 863 864 struct VOpFVfArgs { 865 VOpFVfOpcode opcode; 866 bool vm; 867 uint8_t dst; 868 uint8_t src1; 869 uint8_t src2; 870 }; 871 872 struct VOpFVvArgs { 873 VOpFVvOpcode opcode; 874 bool vm; 875 uint8_t dst; 876 uint8_t src1; 877 union { 878 VFUnary0Opcode vfunary0_opcode; 879 VFUnary1Opcode vfunary1_opcode; 880 uint8_t src2; 881 }; 882 }; 883 884 struct VOpIViArgs { 885 VOpIViOpcode opcode; 886 bool vm; 887 uint8_t dst; 888 uint8_t src; 889 union { 890 int8_t imm : 5; 891 uint8_t uimm : 5; 892 }; 893 }; 894 895 struct VOpIVvArgs { 896 VOpIVvOpcode opcode; 897 bool vm; 898 uint8_t dst; 899 uint8_t src1; 900 uint8_t src2; 901 }; 902 903 struct VOpIVxArgs { 904 VOpIVxOpcode opcode; 905 bool vm; 906 uint8_t dst; 907 uint8_t src1; 908 uint8_t src2; 909 }; 910 911 struct VOpMVvArgs { 912 VOpMVvOpcode opcode; 913 bool vm; 914 uint8_t dst; 915 uint8_t src1; 916 union { 917 VWXUnary0Opcode vwxunary0_opcode; 918 VMUnary0Opcode vmunary0_opcode; 919 VXUnary0Opcode vxunary0_opcode; 920 uint8_t src2; 921 }; 922 }; 923 924 struct VOpMVxArgs { 925 VOpMVxOpcode opcode; 926 bool vm; 927 uint8_t dst; 928 union { 929 VRXUnary0Opcode vrxunary0_opcode; 930 uint8_t src1; 931 }; 932 uint8_t src2; 933 }; 934 935 struct VsetivliArgs { 936 uint8_t dst; 937 uint8_t avl; 938 uint16_t vtype; 939 }; 940 941 struct VsetvliArgs { 942 uint8_t dst; 943 uint8_t src; 944 uint16_t vtype; 945 }; 946 947 struct VsetvlArgs { 948 uint8_t dst; 949 uint8_t src1; 950 uint8_t src2; 951 }; 952 953 struct VStoreIndexedArgs { 954 MemoryDataOperandType width; 955 bool vm; 956 bool ordered; 957 uint8_t nf; 958 uint8_t src; 959 uint8_t idx; 960 uint8_t data; 961 }; 962 963 struct VStoreStrideArgs { 964 MemoryDataOperandType width; 965 bool vm; 966 bool ordered; 967 uint8_t nf; 968 uint8_t src; 969 uint8_t std; 970 uint8_t data; 971 }; 972 973 struct VStoreUnitStrideArgs { 974 VSUmOpOpcode opcode; 975 MemoryDataOperandType width; 976 bool vm; 977 uint8_t nf; 978 uint8_t src; 979 uint8_t data; 980 }; 981 982 template <typename OperandTypeEnum> 983 struct LoadArgsTemplate { 984 OperandTypeEnum operand_type; 985 uint8_t dst; 986 uint8_t src; 987 int16_t offset; 988 }; 989 990 using LoadArgs = LoadArgsTemplate<LoadOperandType>; 991 using LoadFpArgs = LoadArgsTemplate<FloatOperandType>; 992 993 template <typename OpcodeType> 994 struct ShiftImmArgsTemplate { 995 OpcodeType opcode; 996 uint8_t dst; 997 uint8_t src; 998 uint8_t imm; 999 }; 1000 1001 using ShiftImmArgs = ShiftImmArgsTemplate<ShiftImmOpcode>; 1002 using ShiftImm32Args = ShiftImmArgsTemplate<ShiftImm32Opcode>; 1003 1004 template <typename OpcodeType> 1005 struct BitmanipImmArgsTemplate { 1006 OpcodeType opcode; 1007 uint8_t dst; 1008 uint8_t src; 1009 uint8_t shamt; 1010 }; 1011 1012 using BitmanipImmArgs = BitmanipImmArgsTemplate<BitmanipImmOpcode>; 1013 using BitmanipImm32Args = BitmanipImmArgsTemplate<BitmanipImm32Opcode>; 1014 1015 template <typename OperandTypeEnum> 1016 struct StoreArgsTemplate { 1017 OperandTypeEnum operand_type; 1018 uint8_t src; 1019 int16_t offset; 1020 uint8_t data; 1021 }; 1022 1023 using StoreArgs = StoreArgsTemplate<MemoryDataOperandType>; 1024 using StoreFpArgs = StoreArgsTemplate<FloatOperandType>; 1025 1026 struct SystemArgs { 1027 SystemOpcode opcode; 1028 }; 1029 1030 struct UpperImmArgs { 1031 uint8_t dst; 1032 int32_t imm; 1033 }; 1034 GetInsnSize(const uint16_t * code)1035 static uint8_t GetInsnSize(const uint16_t* code) { 1036 constexpr uint16_t kInsnLenMask = uint16_t{0b11}; 1037 return ((*code & kInsnLenMask) != kInsnLenMask) ? 2 : 4; 1038 } 1039 Decode(const uint16_t * code)1040 uint8_t Decode(const uint16_t* code) { 1041 uint8_t insn_size = GetInsnSize(code); 1042 if (insn_size == 2) { 1043 code_ = *code; 1044 return DecodeCompressedInstruction(); 1045 } 1046 CHECK_EQ(insn_size, 4); 1047 // Warning: do not cast and dereference the pointer 1048 // since the address may not be 4-bytes aligned. 1049 memcpy(&code_, code, sizeof(code_)); 1050 return DecodeBaseInstruction(); 1051 } 1052 DecodeCompressedInstruction()1053 uint8_t DecodeCompressedInstruction() { 1054 CompressedOpcode opcode_bits{(GetBits<13, 3>() << 2) | GetBits<0, 2>()}; 1055 1056 switch (opcode_bits) { 1057 case CompressedOpcode::kAddi4spn: 1058 DecodeCompressedAddi4spn(); 1059 break; 1060 case CompressedOpcode::kFld: 1061 DecodeCompressedLoadStore<LoadStore::kLoad, FloatOperandType::kDouble>(); 1062 break; 1063 case CompressedOpcode::kLw: 1064 DecodeCompressedLoadStore<LoadStore::kLoad, LoadOperandType::k32bitSigned>(); 1065 break; 1066 case CompressedOpcode::kLd: 1067 DecodeCompressedLoadStore<LoadStore::kLoad, LoadOperandType::k64bit>(); 1068 break; 1069 case CompressedOpcode::kFsd: 1070 DecodeCompressedLoadStore<LoadStore::kStore, FloatOperandType::kDouble>(); 1071 break; 1072 case CompressedOpcode::kSw: 1073 DecodeCompressedLoadStore<LoadStore::kStore, MemoryDataOperandType::k32bit>(); 1074 break; 1075 case CompressedOpcode::kSd: 1076 DecodeCompressedLoadStore<LoadStore::kStore, MemoryDataOperandType::k64bit>(); 1077 break; 1078 case CompressedOpcode::kAddi: 1079 DecodeCompressedAddi(); 1080 break; 1081 case CompressedOpcode::kAddiw: 1082 DecodeCompressedAddiw(); 1083 break; 1084 case CompressedOpcode::kLi: 1085 DecodeCompressedLi(); 1086 break; 1087 case CompressedOpcode::kLui_Addi16sp: 1088 DecodeCompressedLuiAddi16sp(); 1089 break; 1090 case CompressedOpcode::kMisc_Alu: 1091 DecodeCompressedMiscAlu(); 1092 break; 1093 case CompressedOpcode::kJ: 1094 DecodeCompressedJ(); 1095 break; 1096 case CompressedOpcode::kBeqz: 1097 case CompressedOpcode::kBnez: 1098 DecodeCompressedBeqzBnez(); 1099 break; 1100 case CompressedOpcode::kSlli: 1101 DecodeCompressedSlli(); 1102 break; 1103 case CompressedOpcode::kFldsp: 1104 DecodeCompressedLoadsp<FloatOperandType::kDouble>(); 1105 break; 1106 case CompressedOpcode::kLwsp: 1107 DecodeCompressedLoadsp<LoadOperandType::k32bitSigned>(); 1108 break; 1109 case CompressedOpcode::kLdsp: 1110 DecodeCompressedLoadsp<LoadOperandType::k64bit>(); 1111 break; 1112 case CompressedOpcode::kJr_Jalr_Mv_Add: 1113 DecodeCompressedJr_Jalr_Mv_Add(); 1114 break; 1115 case CompressedOpcode::kFsdsp: 1116 DecodeCompressedStoresp<FloatOperandType::kDouble>(); 1117 break; 1118 case CompressedOpcode::kSwsp: 1119 DecodeCompressedStoresp<MemoryDataOperandType::k32bit>(); 1120 break; 1121 case CompressedOpcode::kSdsp: 1122 DecodeCompressedStoresp<MemoryDataOperandType::k64bit>(); 1123 break; 1124 default: 1125 insn_consumer_->Undefined(); 1126 } 1127 return 2; 1128 } 1129 DecodeCompressedLi()1130 void DecodeCompressedLi() { 1131 uint8_t low_imm = GetBits<2, 5>(); 1132 uint8_t high_imm = GetBits<12, 1>(); 1133 uint8_t rd = GetBits<7, 5>(); 1134 int8_t imm = SignExtend<6>((high_imm << 5) + low_imm); 1135 const OpImmArgs args = { 1136 .opcode = OpImmOpcode::kAddi, 1137 .dst = rd, 1138 .src = 0, 1139 .imm = imm, 1140 }; 1141 insn_consumer_->OpImm(args); 1142 } 1143 DecodeCompressedMiscAlu()1144 void DecodeCompressedMiscAlu() { 1145 uint8_t r = GetBits<7, 3>() + 8; 1146 uint8_t low_imm = GetBits<2, 5>(); 1147 uint8_t high_imm = GetBits<12, 1>(); 1148 uint8_t imm = (high_imm << 5) + low_imm; 1149 uint8_t zc_high_opcode_bits = GetBits<10, 3>(); 1150 uint16_t zc_opcode{static_cast<uint16_t>(low_imm | (zc_high_opcode_bits << 5))}; 1151 1152 std::optional<OpSingleInputOpcode> si_opcode; 1153 switch (zc_opcode) { 1154 case 0b111'11'010: 1155 si_opcode = OpSingleInputOpcode::kZexth; 1156 break; 1157 case 0b111'11'000: 1158 si_opcode = OpSingleInputOpcode::kZextb; 1159 break; 1160 case 0b111'11'100: 1161 si_opcode = OpSingleInputOpcode::kZextw; 1162 break; 1163 case 0b111'11'001: 1164 si_opcode = OpSingleInputOpcode::kSextb; 1165 break; 1166 case 0b111'11'011: 1167 si_opcode = OpSingleInputOpcode::kSexth; 1168 break; 1169 default: 1170 break; 1171 } 1172 if (si_opcode.has_value()) { 1173 const OpSingleInputArgs args = {.opcode = si_opcode.value(), .dst = r, .src = r}; 1174 return insn_consumer_->OpSingleInput(args); 1175 } 1176 1177 switch (GetBits<10, 2>()) { 1178 case 0b00: { 1179 const ShiftImmArgs args = { 1180 .opcode = ShiftImmOpcode::kSrli, 1181 .dst = r, 1182 .src = r, 1183 .imm = imm, 1184 }; 1185 return insn_consumer_->OpImm(args); 1186 } 1187 case 0b01: { 1188 const ShiftImmArgs args = { 1189 .opcode = ShiftImmOpcode::kSrai, 1190 .dst = r, 1191 .src = r, 1192 .imm = imm, 1193 }; 1194 return insn_consumer_->OpImm(args); 1195 } 1196 case 0b10: { 1197 const OpImmArgs args = { 1198 .opcode = OpImmOpcode::kAndi, 1199 .dst = r, 1200 .src = r, 1201 .imm = SignExtend<6>(imm), 1202 }; 1203 return insn_consumer_->OpImm(args); 1204 } 1205 } 1206 uint8_t rs2 = GetBits<2, 3>() + 8; 1207 if (GetBits<12, 1>() == 0) { 1208 OpOpcode opcode; 1209 switch (GetBits<5, 2>()) { 1210 case 0b00: 1211 opcode = OpOpcode::kSub; 1212 break; 1213 case 0b01: 1214 opcode = OpOpcode::kXor; 1215 break; 1216 case 0b10: 1217 opcode = OpOpcode::kOr; 1218 break; 1219 case 0b11: 1220 opcode = OpOpcode::kAnd; 1221 break; 1222 } 1223 const OpArgs args = { 1224 .opcode = opcode, 1225 .dst = r, 1226 .src1 = r, 1227 .src2 = rs2, 1228 }; 1229 return insn_consumer_->Op(args); 1230 } else { 1231 Op32Opcode opcode; 1232 switch (GetBits<5, 2>()) { 1233 case 0b00: 1234 opcode = Op32Opcode::kSubw; 1235 break; 1236 case 0b01: 1237 opcode = Op32Opcode::kAddw; 1238 break; 1239 default: 1240 return Undefined(); 1241 } 1242 const Op32Args args = { 1243 .opcode = opcode, 1244 .dst = r, 1245 .src1 = r, 1246 .src2 = rs2, 1247 }; 1248 return insn_consumer_->Op(args); 1249 } 1250 } 1251 1252 template <auto kOperandType> DecodeCompressedStoresp()1253 void DecodeCompressedStoresp() { 1254 uint8_t raw_imm = GetBits<7, 6>(); 1255 uint8_t rs2 = GetBits<2, 5>(); 1256 constexpr uint8_t k32bit[64] = { 1257 0x00, 0x10, 0x20, 0x30, 0x01, 0x11, 0x21, 0x31, 0x02, 0x12, 0x22, 0x32, 0x03, 1258 0x13, 0x23, 0x33, 0x04, 0x14, 0x24, 0x34, 0x05, 0x15, 0x25, 0x35, 0x06, 0x16, 1259 0x26, 0x36, 0x07, 0x17, 0x27, 0x37, 0x08, 0x18, 0x28, 0x38, 0x09, 0x19, 0x29, 1260 0x39, 0x0a, 0x1a, 0x2a, 0x3a, 0x0b, 0x1b, 0x2b, 0x3b, 0x0c, 0x1c, 0x2c, 0x3c, 1261 0x0d, 0x1d, 0x2d, 0x3d, 0x0e, 0x1e, 0x2e, 0x3e, 0x0f, 0x1f, 0x2f, 0x3f}; 1262 constexpr uint8_t k64bit[64] = { 1263 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x02, 0x12, 0x22, 0x32, 0x42, 1264 0x52, 0x62, 0x72, 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, 0x06, 0x16, 1265 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 1266 0x78, 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a, 0x0c, 0x1c, 0x2c, 0x3c, 1267 0x4c, 0x5c, 0x6c, 0x7c, 0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e}; 1268 int16_t imm = (((uint8_t(kOperandType) & 1) == 0) ? k32bit : k64bit)[raw_imm] << 2; 1269 const StoreArgsTemplate<decltype(kOperandType)> args = { 1270 .operand_type = kOperandType, 1271 .src = 2, 1272 .offset = imm, 1273 .data = rs2, 1274 }; 1275 insn_consumer_->Store(args); 1276 } 1277 DecodeCompressedLuiAddi16sp()1278 void DecodeCompressedLuiAddi16sp() { 1279 uint8_t low_imm = GetBits<2, 5>(); 1280 uint8_t high_imm = GetBits<12, 1>(); 1281 uint8_t rd = GetBits<7, 5>(); 1282 if (rd != 2) { 1283 int32_t imm = SignExtend<18>((high_imm << 17) + (low_imm << 12)); 1284 const UpperImmArgs args = { 1285 .dst = rd, 1286 .imm = imm, 1287 }; 1288 return insn_consumer_->Lui(args); 1289 } 1290 constexpr uint8_t kAddi16spLow[32] = {0x00, 0x08, 0x20, 0x28, 0x40, 0x48, 0x60, 0x68, 1291 0x10, 0x18, 0x30, 0x38, 0x50, 0x58, 0x70, 0x78, 1292 0x04, 0x0c, 0x24, 0x2c, 0x44, 0x4c, 0x64, 0x6c, 1293 0x14, 0x1c, 0x34, 0x3c, 0x54, 0x5c, 0x74, 0x7c}; 1294 int16_t imm = SignExtend<10>((high_imm << 9) + (kAddi16spLow[low_imm] << 2)); 1295 const OpImmArgs args = { 1296 .opcode = OpImmOpcode::kAddi, 1297 .dst = 2, 1298 .src = 2, 1299 .imm = imm, 1300 }; 1301 insn_consumer_->OpImm(args); 1302 } 1303 1304 enum class LoadStore { kLoad, kStore }; 1305 1306 template <enum LoadStore kLoadStore, auto kOperandType> DecodeCompressedLoadStore()1307 void DecodeCompressedLoadStore() { 1308 uint8_t low_imm = GetBits<5, 2>(); 1309 uint8_t high_imm = GetBits<10, 3>(); 1310 uint8_t imm; 1311 if constexpr ((uint8_t(kOperandType) & 1) == 0) { 1312 constexpr uint8_t kLwLow[4] = {0x0, 0x40, 0x04, 0x44}; 1313 imm = (kLwLow[low_imm] | high_imm << 3); 1314 } else { 1315 imm = (low_imm << 6 | high_imm << 3); 1316 } 1317 uint8_t rd = GetBits<2, 3>(); 1318 uint8_t rs = GetBits<7, 3>(); 1319 if constexpr (kLoadStore == LoadStore::kStore) { 1320 const StoreArgsTemplate<decltype(kOperandType)> args = { 1321 .operand_type = kOperandType, 1322 .src = uint8_t(8 + rs), 1323 .offset = imm, 1324 .data = uint8_t(8 + rd), 1325 }; 1326 insn_consumer_->Store(args); 1327 } else { 1328 const LoadArgsTemplate<decltype(kOperandType)> args = { 1329 .operand_type = kOperandType, 1330 .dst = uint8_t(8 + rd), 1331 .src = uint8_t(8 + rs), 1332 .offset = imm, 1333 }; 1334 insn_consumer_->Load(args); 1335 } 1336 } 1337 1338 template <auto kOperandType> DecodeCompressedLoadsp()1339 void DecodeCompressedLoadsp() { 1340 uint8_t low_imm = GetBits<2, 5>(); 1341 uint8_t high_imm = GetBits<12, 1>(); 1342 uint8_t rd = GetBits<7, 5>(); 1343 constexpr uint8_t k32bitLow[32] = {0x00, 0x10, 0x20, 0x30, 0x01, 0x11, 0x21, 0x31, 1344 0x02, 0x12, 0x22, 0x32, 0x03, 0x13, 0x23, 0x33, 1345 0x04, 0x14, 0x24, 0x34, 0x05, 0x15, 0x25, 0x35, 1346 0x06, 0x16, 0x26, 0x36, 0x07, 0x17, 0x27, 0x37}; 1347 constexpr uint8_t k64bitLow[32] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 1348 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 1349 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, 1350 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76}; 1351 int16_t imm = (high_imm << 5) + 1352 ((((uint8_t(kOperandType) & 1) == 0) ? k32bitLow : k64bitLow)[low_imm] << 2); 1353 const LoadArgsTemplate<decltype(kOperandType)> args = { 1354 .operand_type = kOperandType, 1355 .dst = rd, 1356 .src = 2, 1357 .offset = imm, 1358 }; 1359 insn_consumer_->Load(args); 1360 } 1361 DecodeCompressedAddi()1362 void DecodeCompressedAddi() { 1363 uint8_t low_imm = GetBits<2, 5>(); 1364 uint8_t high_imm = GetBits<12, 1>(); 1365 int8_t imm = SignExtend<6>(high_imm << 5 | low_imm); 1366 uint8_t r = GetBits<7, 5>(); 1367 if (r == 0 || imm == 0) { 1368 insn_consumer_->Nop(); 1369 } 1370 const OpImmArgs args = { 1371 .opcode = OpImmOpcode::kAddi, 1372 .dst = r, 1373 .src = r, 1374 .imm = imm, 1375 }; 1376 insn_consumer_->OpImm(args); 1377 } 1378 DecodeCompressedAddiw()1379 void DecodeCompressedAddiw() { 1380 uint8_t low_imm = GetBits<2, 5>(); 1381 uint8_t high_imm = GetBits<12, 1>(); 1382 int8_t imm = SignExtend<6>(high_imm << 5 | low_imm); 1383 uint8_t r = GetBits<7, 5>(); 1384 const OpImm32Args args = { 1385 .opcode = OpImm32Opcode::kAddiw, 1386 .dst = r, 1387 .src = r, 1388 .imm = imm, 1389 }; 1390 insn_consumer_->OpImm(args); 1391 } 1392 DecodeCompressedBeqzBnez()1393 void DecodeCompressedBeqzBnez() { 1394 constexpr uint16_t kBHigh[8] = {0x0, 0x8, 0x10, 0x18, 0x100, 0x108, 0x110, 0x118}; 1395 constexpr uint8_t kBLow[32] = {0x00, 0x20, 0x02, 0x22, 0x04, 0x24, 0x06, 0x26, 0x40, 0x60, 0x42, 1396 0x62, 0x44, 0x64, 0x46, 0x66, 0x80, 0xa0, 0x82, 0xa2, 0x84, 0xa4, 1397 0x86, 0xa6, 0xc0, 0xe0, 0xc2, 0xe2, 0xc4, 0xe4, 0xc6, 0xe6}; 1398 uint8_t low_imm = GetBits<2, 5>(); 1399 uint8_t high_imm = GetBits<10, 3>(); 1400 uint8_t rs = GetBits<7, 3>(); 1401 1402 const BranchArgs args = { 1403 .opcode = BranchOpcode{GetBits<13, 1>()}, 1404 .src1 = uint8_t(8 + rs), 1405 .src2 = 0, 1406 .offset = static_cast<int16_t>(SignExtend<9>(kBHigh[high_imm] + kBLow[low_imm])), 1407 }; 1408 insn_consumer_->CompareAndBranch(args); 1409 } 1410 DecodeCompressedJ()1411 void DecodeCompressedJ() { 1412 constexpr uint16_t kJHigh[32] = { 1413 0x0, 0x400, 0x100, 0x500, 0x200, 0x600, 0x300, 0x700, 0x10, 0x410, 0x110, 1414 0x510, 0x210, 0x610, 0x310, 0x710, 0xf800, 0xfc00, 0xf900, 0xfd00, 0xfa00, 0xfe00, 1415 0xfb00, 0xff00, 0xf810, 0xfc10, 0xf910, 0xfd10, 0xfa10, 0xfe10, 0xfb10, 0xff10, 1416 }; 1417 constexpr uint8_t kJLow[64] = { 1418 0x0, 0x20, 0x2, 0x22, 0x4, 0x24, 0x6, 0x26, 0x8, 0x28, 0xa, 0x2a, 0xc, 1419 0x2c, 0xe, 0x2e, 0x80, 0xa0, 0x82, 0xa2, 0x84, 0xa4, 0x86, 0xa6, 0x88, 0xa8, 1420 0x8a, 0xaa, 0x8c, 0xac, 0x8e, 0xae, 0x40, 0x60, 0x42, 0x62, 0x44, 0x64, 0x46, 1421 0x66, 0x48, 0x68, 0x4a, 0x6a, 0x4c, 0x6c, 0x4e, 0x6e, 0xc0, 0xe0, 0xc2, 0xe2, 1422 0xc4, 0xe4, 0xc6, 0xe6, 0xc8, 0xe8, 0xca, 0xea, 0xcc, 0xec, 0xce, 0xee, 1423 }; 1424 const JumpAndLinkArgs args = { 1425 .dst = 0, 1426 .offset = bit_cast<int16_t>(kJHigh[GetBits<8, 5>()]) | kJLow[GetBits<2, 6>()], 1427 .insn_len = 2, 1428 }; 1429 insn_consumer_->JumpAndLink(args); 1430 } 1431 DecodeCompressedAddi4spn()1432 void DecodeCompressedAddi4spn() { 1433 constexpr uint8_t kAddi4spnHigh[16] = { 1434 0x0, 0x40, 0x80, 0xc0, 0x4, 0x44, 0x84, 0xc4, 0x8, 0x48, 0x88, 0xc8, 0xc, 0x4c, 0x8c, 0xcc}; 1435 constexpr uint8_t kAddi4spnLow[16] = { 1436 0x0, 0x2, 0x1, 0x3, 0x10, 0x12, 0x11, 0x13, 0x20, 0x22, 0x21, 0x23, 0x30, 0x32, 0x31, 0x33}; 1437 int16_t imm = (kAddi4spnHigh[GetBits<9, 4>()] | kAddi4spnLow[GetBits<5, 4>()]) << 2; 1438 // If immediate is zero then this instruction is treated as undefined. 1439 // This includes RISC-V dedicated 16bit “undefined instruction” 0x0000. 1440 if (imm == 0) { 1441 return Undefined(); 1442 } 1443 const OpImmArgs args = { 1444 .opcode = OpImmOpcode::kAddi, 1445 .dst = uint8_t(8 + GetBits<2, 3>()), 1446 .src = 2, 1447 .imm = imm, 1448 }; 1449 insn_consumer_->OpImm(args); 1450 } 1451 DecodeCompressedJr_Jalr_Mv_Add()1452 void DecodeCompressedJr_Jalr_Mv_Add() { 1453 uint8_t r = GetBits<7, 5>(); 1454 uint8_t rs2 = GetBits<2, 5>(); 1455 if (GetBits<12, 1>()) { 1456 if (r == 0 && rs2 == 0) { 1457 const SystemArgs args = { 1458 .opcode = SystemOpcode::kEbreak, 1459 }; 1460 return insn_consumer_->System(args); 1461 } else if (rs2 == 0) { 1462 const JumpAndLinkRegisterArgs args = { 1463 .dst = 1, 1464 .base = r, 1465 .offset = 0, 1466 .insn_len = 2, 1467 }; 1468 insn_consumer_->JumpAndLinkRegister(args); 1469 } else { 1470 const OpArgs args = { 1471 .opcode = OpOpcode::kAdd, 1472 .dst = r, 1473 .src1 = r, 1474 .src2 = rs2, 1475 }; 1476 insn_consumer_->Op(args); 1477 } 1478 } else { 1479 if (rs2 == 0) { 1480 const JumpAndLinkRegisterArgs args = { 1481 .dst = 0, 1482 .base = r, 1483 .offset = 0, 1484 .insn_len = 2, 1485 }; 1486 insn_consumer_->JumpAndLinkRegister(args); 1487 } else { 1488 const OpArgs args = { 1489 .opcode = OpOpcode::kAdd, 1490 .dst = r, 1491 .src1 = 0, 1492 .src2 = rs2, 1493 }; 1494 insn_consumer_->Op(args); 1495 } 1496 } 1497 } 1498 DecodeCompressedSlli()1499 void DecodeCompressedSlli() { 1500 uint8_t r = GetBits<7, 5>(); 1501 uint8_t low_imm = GetBits<2, 5>(); 1502 uint8_t high_imm = GetBits<12, 1>(); 1503 uint8_t imm = (high_imm << 5) + low_imm; 1504 const ShiftImmArgs args = { 1505 .opcode = ShiftImmOpcode::kSlli, 1506 .dst = r, 1507 .src = r, 1508 .imm = imm, 1509 }; 1510 return insn_consumer_->OpImm(args); 1511 } 1512 DecodeBaseInstruction()1513 uint8_t DecodeBaseInstruction() { 1514 BaseOpcode opcode_bits{GetBits<2, 5>()}; 1515 1516 switch (opcode_bits) { 1517 case BaseOpcode::kLoad: 1518 DecodeLoad<LoadOperandType>(); 1519 break; 1520 case BaseOpcode::kLoadFp: 1521 DecodeLoad<FloatOperandType>(); 1522 break; 1523 case BaseOpcode::kMiscMem: 1524 DecodeMiscMem(); 1525 break; 1526 case BaseOpcode::kOpImm: 1527 DecodeOp<OpImmOpcode, ShiftImmOpcode, BitmanipImmOpcode, 6>(); 1528 break; 1529 case BaseOpcode::kAuipc: 1530 DecodeAuipc(); 1531 break; 1532 case BaseOpcode::kOpImm32: 1533 DecodeOp<OpImm32Opcode, ShiftImm32Opcode, BitmanipImm32Opcode, 5>(); 1534 break; 1535 case BaseOpcode::kStore: 1536 DecodeStore<MemoryDataOperandType>(); 1537 break; 1538 case BaseOpcode::kStoreFp: 1539 DecodeStore<FloatOperandType>(); 1540 break; 1541 case BaseOpcode::kAmo: 1542 DecodeAmo(); 1543 break; 1544 case BaseOpcode::kOp: 1545 DecodeOp<OpOpcode>(); 1546 break; 1547 case BaseOpcode::kLui: 1548 DecodeLui(); 1549 break; 1550 case BaseOpcode::kOp32: 1551 DecodeOp<Op32Opcode>(); 1552 break; 1553 case BaseOpcode::kMAdd: 1554 case BaseOpcode::kMSub: 1555 case BaseOpcode::kNmSub: 1556 case BaseOpcode::kNmAdd: 1557 DecodeFma(); 1558 break; 1559 case BaseOpcode::kOpFp: 1560 DecodeOpFp(); 1561 break; 1562 case BaseOpcode::vOpV: 1563 DecodeOpV(); 1564 break; 1565 case BaseOpcode::kBranch: 1566 DecodeBranch(); 1567 break; 1568 case BaseOpcode::kJalr: 1569 DecodeJumpAndLinkRegister(); 1570 break; 1571 case BaseOpcode::kJal: 1572 DecodeJumpAndLink(); 1573 break; 1574 case BaseOpcode::kSystem: 1575 DecodeSystem(); 1576 break; 1577 default: 1578 insn_consumer_->Undefined(); 1579 } 1580 return 4; 1581 } 1582 1583 // Signextend bits from size to the corresponding signed type of sizeof(Type) size. 1584 // If the result of this function is assigned to a wider signed type it'll automatically 1585 // sign-extend. 1586 template <unsigned size, typename Type> SignExtend(const Type val)1587 static auto SignExtend(const Type val) { 1588 static_assert(std::is_integral_v<Type>, "Only integral types are supported"); 1589 static_assert(size > 0 && size < (sizeof(Type) * CHAR_BIT), "Invalid size value"); 1590 using SignedType = std::make_signed_t<Type>; 1591 struct { 1592 SignedType val : size; 1593 } holder = {.val = static_cast<SignedType>(val)}; 1594 // Compiler takes care of sign-extension of the field with the specified bit-length. 1595 return static_cast<SignedType>(holder.val); 1596 } 1597 1598 private: 1599 template <uint32_t start, uint32_t size> GetBits()1600 auto GetBits() { 1601 static_assert((start + size) <= 32 && size > 0, "Invalid start or size value"); 1602 using ResultType = std::conditional_t< 1603 size == 1, 1604 bool, 1605 std::conditional_t<size <= 8, uint8_t, std::conditional_t<size <= 16, uint16_t, uint32_t>>>; 1606 uint32_t shifted_val = code_ << (32 - start - size); 1607 return static_cast<ResultType>(shifted_val >> (32 - size)); 1608 } 1609 Undefined()1610 void Undefined() { insn_consumer_->Undefined(); } 1611 DecodeMiscMem()1612 void DecodeMiscMem() { 1613 uint8_t low_opcode = GetBits<12, 3>(); 1614 switch (low_opcode) { 1615 case 0b000: { 1616 uint8_t high_opcode = GetBits<28, 4>(); 1617 FenceOpcode opcode = FenceOpcode{high_opcode}; 1618 const FenceArgs args = { 1619 .opcode = opcode, 1620 .dst = GetBits<7, 5>(), 1621 .src = GetBits<15, 5>(), 1622 .sw = GetBits<20, 1>(), 1623 .sr = GetBits<21, 1>(), 1624 .so = GetBits<22, 1>(), 1625 .si = GetBits<23, 1>(), 1626 .pw = GetBits<24, 1>(), 1627 .pr = GetBits<25, 1>(), 1628 .po = GetBits<26, 1>(), 1629 .pi = GetBits<27, 1>(), 1630 }; 1631 insn_consumer_->Fence(args); 1632 break; 1633 } 1634 case 0b001: { 1635 uint16_t imm = GetBits<20, 12>(); 1636 const FenceIArgs args = { 1637 .dst = GetBits<7, 5>(), 1638 .src = GetBits<15, 5>(), 1639 .imm = SignExtend<12>(imm), 1640 }; 1641 insn_consumer_->FenceI(args); 1642 break; 1643 } 1644 default: 1645 return Undefined(); 1646 } 1647 } 1648 1649 template <typename OpcodeType> DecodeOp()1650 void DecodeOp() { 1651 uint8_t low_opcode = GetBits<12, 3>(); 1652 uint8_t high_opcode = GetBits<25, 7>(); 1653 uint16_t opcode_bits = static_cast<int16_t>(low_opcode | (high_opcode << 3)); 1654 OpcodeType opcode{opcode_bits}; 1655 OpSingleInputOpcode single_input_opcode{opcode_bits}; 1656 1657 switch (single_input_opcode) { 1658 case OpSingleInputOpcode::kZexth: { 1659 DecodeSingleInputOp(single_input_opcode); 1660 return; 1661 } 1662 default: 1663 break; 1664 } 1665 const OpArgsTemplate<OpcodeType> args = { 1666 .opcode = opcode, 1667 .dst = GetBits<7, 5>(), 1668 .src1 = GetBits<15, 5>(), 1669 .src2 = GetBits<20, 5>(), 1670 }; 1671 insn_consumer_->Op(args); 1672 } 1673 DecodeSingleInputOp(OpSingleInputOpcode opcode)1674 void DecodeSingleInputOp(OpSingleInputOpcode opcode) { 1675 uint8_t src1 = GetBits<15, 5>(); 1676 uint8_t src2 = GetBits<20, 5>(); 1677 1678 if (src2 != 0) { 1679 return Undefined(); 1680 } 1681 const OpSingleInputArgs args = {.opcode = opcode, .dst = GetBits<7, 5>(), .src = src1}; 1682 insn_consumer_->OpSingleInput(args); 1683 } 1684 DecodeAmo()1685 void DecodeAmo() { 1686 uint8_t low_opcode = GetBits<12, 3>(); 1687 uint8_t high_opcode = GetBits<27, 5>(); 1688 // lr instruction must have rs2 == 0 1689 if (high_opcode == 0b00010 && GetBits<20, 5>() != 0) { 1690 return Undefined(); 1691 } 1692 AmoOpcode opcode = AmoOpcode{high_opcode}; 1693 MemoryDataOperandType operand_type = MemoryDataOperandType{low_opcode}; 1694 const AmoArgs args = { 1695 .opcode = opcode, 1696 .operand_type = operand_type, 1697 .dst = GetBits<7, 5>(), 1698 .src1 = GetBits<15, 5>(), 1699 .src2 = GetBits<20, 5>(), 1700 .rl = GetBits<25, 1>(), 1701 .aq = GetBits<26, 1>(), 1702 }; 1703 insn_consumer_->Amo(args); 1704 } 1705 DecodeFma()1706 void DecodeFma() { 1707 uint8_t operand_type = GetBits<25, 2>(); 1708 uint8_t opcode_bits = GetBits<2, 2>(); 1709 const FmaArgs args = { 1710 .opcode = FmaOpcode{opcode_bits}, 1711 .operand_type = FloatOperandType{operand_type}, 1712 .dst = GetBits<7, 5>(), 1713 .src1 = GetBits<15, 5>(), 1714 .src2 = GetBits<20, 5>(), 1715 .src3 = GetBits<27, 5>(), 1716 .rm = GetBits<12, 3>(), 1717 }; 1718 insn_consumer_->Fma(args); 1719 } 1720 DecodeLui()1721 void DecodeLui() { 1722 int32_t imm = GetBits<12, 20>(); 1723 const UpperImmArgs args = { 1724 .dst = GetBits<7, 5>(), 1725 .imm = imm << 12, 1726 }; 1727 insn_consumer_->Lui(args); 1728 } 1729 DecodeAuipc()1730 void DecodeAuipc() { 1731 int32_t imm = GetBits<12, 20>(); 1732 const UpperImmArgs args = { 1733 .dst = GetBits<7, 5>(), 1734 .imm = imm << 12, 1735 }; 1736 insn_consumer_->Auipc(args); 1737 } 1738 1739 template <typename OperandTypeEnum> DecodeLoad()1740 void DecodeLoad() { 1741 OperandTypeEnum operand_type; 1742 if constexpr (std::is_same_v<OperandTypeEnum, FloatOperandType>) { 1743 auto decoded_operand_type = kLoadStoreWidthToOperandType[GetBits<12, 3>()]; 1744 if (decoded_operand_type.is_vector_instruction) { 1745 if (GetBits<28, 1>() == 1) { 1746 return Undefined(); 1747 } 1748 switch (GetBits<26, 2>()) { 1749 case 0b00: { 1750 const VLoadUnitStrideArgs args = { 1751 .opcode = VLUmOpOpcode{GetBits<20, 5>()}, 1752 .width = decoded_operand_type.eew, 1753 .vm = GetBits<25, 1>(), 1754 .nf = GetBits<29, 3>(), 1755 .dst = GetBits<7, 5>(), 1756 .src = GetBits<15, 5>(), 1757 }; 1758 return insn_consumer_->OpVector(args); 1759 } 1760 case 0b01: 1761 case 0b11: { 1762 const VLoadIndexedArgs args = { 1763 .width = decoded_operand_type.eew, 1764 .vm = GetBits<25, 1>(), 1765 .ordered = GetBits<27, 1>(), 1766 .nf = GetBits<29, 3>(), 1767 .dst = GetBits<7, 5>(), 1768 .src = GetBits<15, 5>(), 1769 .idx = GetBits<20, 5>(), 1770 }; 1771 return insn_consumer_->OpVector(args); 1772 } 1773 case 0b10: { 1774 const VLoadStrideArgs args = { 1775 .width = decoded_operand_type.eew, 1776 .vm = GetBits<25, 1>(), 1777 .ordered = GetBits<27, 1>(), 1778 .nf = GetBits<29, 3>(), 1779 .dst = GetBits<7, 5>(), 1780 .src = GetBits<15, 5>(), 1781 .std = GetBits<20, 5>(), 1782 }; 1783 return insn_consumer_->OpVector(args); 1784 } 1785 default: 1786 return Undefined(); 1787 } 1788 return Undefined(); 1789 } 1790 operand_type = decoded_operand_type.size; 1791 } else { 1792 operand_type = OperandTypeEnum{GetBits<12, 3>()}; 1793 } 1794 const LoadArgsTemplate<OperandTypeEnum> args = { 1795 .operand_type = operand_type, 1796 .dst = GetBits<7, 5>(), 1797 .src = GetBits<15, 5>(), 1798 .offset = SignExtend<12>(GetBits<20, 12>()), 1799 }; 1800 insn_consumer_->Load(args); 1801 } 1802 1803 template <typename OperandTypeEnum> DecodeStore()1804 void DecodeStore() { 1805 OperandTypeEnum operand_type; 1806 if constexpr (std::is_same_v<OperandTypeEnum, FloatOperandType>) { 1807 auto decoded_operand_type = kLoadStoreWidthToOperandType[GetBits<12, 3>()]; 1808 if (decoded_operand_type.is_vector_instruction) { 1809 if (GetBits<28, 1>() == 1) { 1810 return Undefined(); 1811 } 1812 switch (GetBits<26, 2>()) { 1813 case 0b00: { 1814 const VStoreUnitStrideArgs args = { 1815 .opcode = VSUmOpOpcode{GetBits<20, 5>()}, 1816 .width = decoded_operand_type.eew, 1817 .vm = GetBits<25, 1>(), 1818 .nf = GetBits<29, 3>(), 1819 .src = GetBits<15, 5>(), 1820 .data = GetBits<7, 5>(), 1821 }; 1822 return insn_consumer_->OpVector(args); 1823 } 1824 case 0b01: 1825 case 0b11: { 1826 const VStoreIndexedArgs args = { 1827 .width = decoded_operand_type.eew, 1828 .vm = GetBits<25, 1>(), 1829 .ordered = GetBits<27, 1>(), 1830 .nf = GetBits<29, 3>(), 1831 .src = GetBits<15, 5>(), 1832 .idx = GetBits<20, 5>(), 1833 .data = GetBits<7, 5>(), 1834 }; 1835 return insn_consumer_->OpVector(args); 1836 } 1837 case 0b10: { 1838 const VStoreStrideArgs args = { 1839 .width = decoded_operand_type.eew, 1840 .vm = GetBits<25, 1>(), 1841 .ordered = GetBits<27, 1>(), 1842 .nf = GetBits<29, 3>(), 1843 .src = GetBits<15, 5>(), 1844 .std = GetBits<20, 5>(), 1845 .data = GetBits<7, 5>(), 1846 }; 1847 return insn_consumer_->OpVector(args); 1848 } 1849 default: 1850 return Undefined(); 1851 } 1852 return Undefined(); 1853 } 1854 1855 operand_type = decoded_operand_type.size; 1856 } else { 1857 operand_type = OperandTypeEnum{GetBits<12, 3>()}; 1858 } 1859 1860 uint16_t low_imm = GetBits<7, 5>(); 1861 uint16_t high_imm = GetBits<25, 7>(); 1862 1863 const StoreArgsTemplate<OperandTypeEnum> args = { 1864 .operand_type = operand_type, 1865 .src = GetBits<15, 5>(), 1866 .offset = SignExtend<12>(static_cast<int16_t>(low_imm | (high_imm << 5))), 1867 .data = GetBits<20, 5>(), 1868 }; 1869 insn_consumer_->Store(args); 1870 } 1871 1872 template <typename OpOpcodeType, 1873 typename ShiftOpcodeType, 1874 typename BitmanipOpcodeType, 1875 uint32_t kShiftFieldSize> DecodeOp()1876 void DecodeOp() { 1877 uint8_t low_opcode = GetBits<12, 3>(); 1878 if (low_opcode != 0b001 && low_opcode != 0b101) { 1879 OpOpcodeType opcode{low_opcode}; 1880 1881 uint16_t imm = GetBits<20, 12>(); 1882 1883 const OpImmArgsTemplate<OpOpcodeType> args = { 1884 .opcode = opcode, 1885 .dst = GetBits<7, 5>(), 1886 .src = GetBits<15, 5>(), 1887 .imm = SignExtend<12>(imm), 1888 }; 1889 insn_consumer_->OpImm(args); 1890 } else if ((GetBits<31, 1>() + GetBits<20 + kShiftFieldSize, 10 - kShiftFieldSize>()) == 1891 0) { // For Canonical Shift Instructions from RV64G the opcode contains all 1892 // zeros except for the 30th (second highest) bit. 1893 uint16_t high_opcode = GetBits<20 + kShiftFieldSize, 12 - kShiftFieldSize>(); 1894 ShiftOpcodeType opcode{ 1895 static_cast<std::underlying_type_t<ShiftOpcodeType>>(low_opcode | (high_opcode << 3))}; 1896 1897 const ShiftImmArgsTemplate<ShiftOpcodeType> args = { 1898 .opcode = opcode, 1899 .dst = GetBits<7, 5>(), 1900 .src = GetBits<15, 5>(), 1901 .imm = GetBits<20, kShiftFieldSize>(), 1902 }; 1903 insn_consumer_->OpImm(args); 1904 } else { 1905 uint8_t shamt = GetBits<20, kShiftFieldSize>(); 1906 uint16_t high_opcode = GetBits<20 + kShiftFieldSize, 12 - kShiftFieldSize>(); 1907 BitmanipOpcodeType opcode{static_cast<uint16_t>(low_opcode | (high_opcode << 3))}; 1908 bool has_shamt = false; 1909 1910 switch ((BitmanipImmOpcode)opcode) { 1911 case BitmanipImmOpcode::kRori: 1912 case BitmanipImmOpcode::kBclri: 1913 case BitmanipImmOpcode::kBexti: 1914 case BitmanipImmOpcode::kBinvi: 1915 case BitmanipImmOpcode::kBseti: 1916 has_shamt = true; 1917 break; 1918 default: 1919 break; 1920 } 1921 1922 switch ((BitmanipImm32Opcode)opcode) { 1923 case BitmanipImm32Opcode::kRoriw: 1924 case BitmanipImm32Opcode::kSlliuw: 1925 has_shamt = true; 1926 break; 1927 default: 1928 break; 1929 } 1930 // TODO(b/291851792): Refactor instructions with shamt into ShiftImmArgs 1931 if (!has_shamt) { 1932 high_opcode = GetBits<20, 12>(); 1933 opcode = BitmanipOpcodeType{static_cast<uint16_t>(low_opcode | (high_opcode << 3))}; 1934 shamt = 0; 1935 } 1936 const BitmanipImmArgsTemplate<BitmanipOpcodeType> args = { 1937 .opcode = opcode, 1938 .dst = GetBits<7, 5>(), 1939 .src = GetBits<15, 5>(), 1940 .shamt = shamt, 1941 }; 1942 insn_consumer_->OpImm(args); 1943 } 1944 } 1945 DecodeBranch()1946 void DecodeBranch() { 1947 BranchOpcode opcode{GetBits<12, 3>()}; 1948 1949 // Decode the offset. 1950 auto low_imm = GetBits<8, 4>(); 1951 auto mid_imm = GetBits<25, 6>(); 1952 auto bit11_imm = GetBits<7, 1>(); 1953 auto bit12_imm = GetBits<31, 1>(); 1954 auto offset = 1955 static_cast<int16_t>(low_imm | (mid_imm << 4) | (bit11_imm << 10) | (bit12_imm << 11)); 1956 1957 const BranchArgs args = { 1958 .opcode = opcode, 1959 .src1 = GetBits<15, 5>(), 1960 .src2 = GetBits<20, 5>(), 1961 // The offset is encoded as 2-byte units, we need to multiply by 2. 1962 .offset = SignExtend<13>(static_cast<int16_t>(offset * 2)), 1963 }; 1964 insn_consumer_->CompareAndBranch(args); 1965 } 1966 DecodeJumpAndLink()1967 void DecodeJumpAndLink() { 1968 // Decode the offset. 1969 auto low_imm = GetBits<21, 10>(); 1970 auto mid_imm = GetBits<12, 8>(); 1971 auto bit11_imm = GetBits<20, 1>(); 1972 auto bit20_imm = GetBits<31, 1>(); 1973 auto offset = 1974 static_cast<int32_t>(low_imm | (bit11_imm << 10) | (mid_imm << 11) | (bit20_imm << 19)); 1975 1976 const JumpAndLinkArgs args = { 1977 .dst = GetBits<7, 5>(), 1978 // The offset is encoded as 2-byte units, we need to multiply by 2. 1979 .offset = SignExtend<21>(offset * 2), 1980 .insn_len = 4, 1981 }; 1982 insn_consumer_->JumpAndLink(args); 1983 } 1984 DecodeOpFp()1985 void DecodeOpFp() { 1986 // Bit #29 = 1: means rm is an opcode extension and not operand. 1987 // Bit #30 = 1: means rs2 is an opcode extension and not operand. 1988 // Bit #31 = 1: selects general purpose register instead of floating point register as target. 1989 uint8_t operand_type = GetBits<25, 2>(); 1990 uint8_t opcode_bits = GetBits<27, 2>(); 1991 uint8_t rd = GetBits<7, 5>(); 1992 uint8_t rs1 = GetBits<15, 5>(); 1993 uint8_t rs2 = GetBits<20, 5>(); 1994 uint8_t rm = GetBits<12, 3>(); 1995 switch (GetBits<29, 3>()) { 1996 case 0b000: { 1997 const OpFpArgs args = { 1998 .opcode = OpFpOpcode{opcode_bits}, 1999 .operand_type = FloatOperandType{operand_type}, 2000 .dst = rd, 2001 .src1 = rs1, 2002 .src2 = rs2, 2003 .rm = rm, 2004 }; 2005 return insn_consumer_->OpFp(args); 2006 } 2007 case 0b001: { 2008 uint8_t no_rounding_opcode_bits = (opcode_bits << 3) + rm; 2009 OpFpNoRoundingOpcode no_rounding_opcode = OpFpNoRoundingOpcode{no_rounding_opcode_bits}; 2010 if (no_rounding_opcode == Decoder::OpFpNoRoundingOpcode::kFSgnj && rs1 == rs2) { 2011 const OpFpSingleInputNoRoundingArgs args = { 2012 .opcode = OpFpSingleInputNoRoundingOpcode::kFmv, 2013 .operand_type = FloatOperandType{operand_type}, 2014 .dst = rd, 2015 .src = rs1, 2016 }; 2017 return insn_consumer_->OpFpSingleInputNoRounding(args); 2018 } 2019 const OpFpNoRoundingArgs args = { 2020 .opcode = no_rounding_opcode, 2021 .operand_type = FloatOperandType{operand_type}, 2022 .dst = rd, 2023 .src1 = rs1, 2024 .src2 = rs2, 2025 }; 2026 return insn_consumer_->OpFpNoRounding(args); 2027 } 2028 case 0b010: { 2029 if (opcode_bits == 0) { 2030 // Conversion from one float to the same float type is not supported. 2031 if (operand_type == rs2) { 2032 return Undefined(); 2033 } 2034 // Values larger than 0b11 are reserved in Fcvt. 2035 if (rs2 > 0b11) { 2036 return Undefined(); 2037 } 2038 const FcvtFloatToFloatArgs args = { 2039 .dst_type = FloatOperandType{operand_type}, 2040 .src_type = FloatOperandType{rs2}, 2041 .dst = rd, 2042 .src = rs1, 2043 .rm = rm, 2044 }; 2045 return insn_consumer_->Fcvt(args); 2046 } 2047 uint8_t opcode = (opcode_bits << 5) + rs2; 2048 const OpFpSingleInputArgs args = { 2049 .opcode = OpFpSingleInputOpcode{opcode}, 2050 .operand_type = FloatOperandType{operand_type}, 2051 .dst = rd, 2052 .src = rs1, 2053 .rm = rm, 2054 }; 2055 return insn_consumer_->OpFpSingleInput(args); 2056 } 2057 case 0b101: { 2058 uint8_t opcode = (opcode_bits << 3) + rm; 2059 const OpFpGpRegisterTargetNoRoundingArgs args = { 2060 .opcode = OpFpGpRegisterTargetNoRoundingOpcode{opcode}, 2061 .operand_type = FloatOperandType{operand_type}, 2062 .dst = rd, 2063 .src1 = rs1, 2064 .src2 = rs2, 2065 }; 2066 return insn_consumer_->OpFpGpRegisterTargetNoRounding(args); 2067 } 2068 case 0b110: 2069 switch (opcode_bits) { 2070 case 0b00: { 2071 const FcvtFloatToIntegerArgs args = { 2072 .dst_type = FcvtOperandType{rs2}, 2073 .src_type = FloatOperandType{operand_type}, 2074 .dst = rd, 2075 .src = rs1, 2076 .rm = rm, 2077 }; 2078 return insn_consumer_->Fcvt(args); 2079 } 2080 case 0b10: { 2081 const FcvtIntegerToFloatArgs args = { 2082 .dst_type = FloatOperandType{operand_type}, 2083 .src_type = FcvtOperandType{rs2}, 2084 .dst = rd, 2085 .src = rs1, 2086 .rm = rm, 2087 }; 2088 return insn_consumer_->Fcvt(args); 2089 } 2090 default: 2091 return Undefined(); 2092 } 2093 case 0b111: { 2094 uint16_t opcode = (opcode_bits << 8) + (rs2 << 3) + rm; 2095 switch (rm) { 2096 case 0b001: { 2097 const OpFpGpRegisterTargetSingleInputNoRoundingArgs args = { 2098 .opcode = OpFpGpRegisterTargetSingleInputNoRoundingOpcode{opcode}, 2099 .operand_type = FloatOperandType{operand_type}, 2100 .dst = rd, 2101 .src = rs1, 2102 }; 2103 return insn_consumer_->OpFpGpRegisterTargetSingleInputNoRounding(args); 2104 } 2105 case 0b000: { 2106 if (opcode_bits == 0b00) { 2107 const FmvFloatToIntegerArgs args = { 2108 .operand_type = FloatOperandType{operand_type}, 2109 .dst = rd, 2110 .src = rs1, 2111 }; 2112 return insn_consumer_->FmvFloatToInteger(args); 2113 } else if (opcode_bits == 0b10) { 2114 const FmvIntegerToFloatArgs args = { 2115 .operand_type = FloatOperandType{operand_type}, 2116 .dst = rd, 2117 .src = rs1, 2118 }; 2119 return insn_consumer_->FmvIntegerToFloat(args); 2120 } else { 2121 return Undefined(); 2122 } 2123 } 2124 default: 2125 return Undefined(); 2126 } 2127 } 2128 default: 2129 return Undefined(); 2130 } 2131 } 2132 DecodeOpV()2133 void DecodeOpV() { 2134 uint8_t low_opcode = GetBits<12, 3>(); 2135 bool vm = GetBits<25, 1>(); 2136 uint8_t opcode = GetBits<26, 6>(); 2137 uint8_t dst = GetBits<7, 5>(); 2138 // Note: in vector instructions vs2 field is 2nd operand while vs1 field is 3rd operand. 2139 // FMA instructions are exception, but there are not that many of these. 2140 uint8_t src1 = GetBits<20, 5>(); 2141 uint8_t src2 = GetBits<15, 5>(); 2142 switch (low_opcode) { 2143 case 0b000: { 2144 const VOpIVvArgs args = { 2145 .opcode = VOpIVvOpcode{opcode}, 2146 .vm = vm, 2147 .dst = dst, 2148 .src1 = src1, 2149 .src2 = src2, 2150 }; 2151 return insn_consumer_->OpVector(args); 2152 } 2153 case 0b001: { 2154 const VOpFVvArgs args = { 2155 .opcode = VOpFVvOpcode{opcode}, 2156 .vm = vm, 2157 .dst = dst, 2158 .src1 = src1, 2159 .src2 = src2, 2160 }; 2161 return insn_consumer_->OpVector(args); 2162 } 2163 case 0b010: { 2164 const VOpMVvArgs args = { 2165 .opcode = VOpMVvOpcode{opcode}, 2166 .vm = vm, 2167 .dst = dst, 2168 .src1 = src1, 2169 .src2 = src2, 2170 }; 2171 return insn_consumer_->OpVector(args); 2172 } 2173 case 0b011: { 2174 const VOpIViArgs args = { 2175 .opcode = VOpIViOpcode{opcode}, 2176 .vm = vm, 2177 .dst = dst, 2178 .src = src1, 2179 .uimm = src2, 2180 }; 2181 return insn_consumer_->OpVector(args); 2182 } 2183 case 0b100: { 2184 const VOpIVxArgs args = { 2185 .opcode = VOpIVxOpcode{opcode}, 2186 .vm = vm, 2187 .dst = dst, 2188 .src1 = src1, 2189 .src2 = src2, 2190 }; 2191 return insn_consumer_->OpVector(args); 2192 } 2193 case 0b101: { 2194 const VOpFVfArgs args = { 2195 .opcode = VOpFVfOpcode{opcode}, 2196 .vm = vm, 2197 .dst = dst, 2198 .src1 = src1, 2199 .src2 = src2, 2200 }; 2201 return insn_consumer_->OpVector(args); 2202 } 2203 case 0b110: { 2204 const VOpMVxArgs args = { 2205 .opcode = VOpMVxOpcode{opcode}, 2206 .vm = vm, 2207 .dst = dst, 2208 .src1 = src1, 2209 .src2 = src2, 2210 }; 2211 return insn_consumer_->OpVector(args); 2212 } 2213 case 0b111: 2214 if (GetBits<31, 1>() == 0) { 2215 const VsetvliArgs args = { 2216 .dst = GetBits<7, 5>(), 2217 .src = GetBits<15, 5>(), 2218 .vtype = GetBits<20, 11>(), 2219 }; 2220 return insn_consumer_->Vsetvli(args); 2221 } else if (GetBits<30, 1>() == 1) { 2222 const VsetivliArgs args = { 2223 .dst = GetBits<7, 5>(), 2224 .avl = GetBits<15, 5>(), 2225 .vtype = GetBits<20, 10>(), 2226 }; 2227 return insn_consumer_->Vsetivli(args); 2228 } else if (GetBits<25, 6>() == 0) { 2229 const VsetvlArgs args = { 2230 .dst = GetBits<7, 5>(), 2231 .src1 = GetBits<15, 5>(), 2232 .src2 = GetBits<20, 5>(), 2233 }; 2234 return insn_consumer_->Vsetvl(args); 2235 } 2236 } 2237 } 2238 DecodeSystem()2239 void DecodeSystem() { 2240 uint8_t low_opcode = GetBits<12, 2>(); 2241 if (low_opcode == 0b00) { 2242 uint32_t opcode = GetBits<7, 25>(); 2243 const SystemArgs args = { 2244 .opcode = SystemOpcode{opcode}, 2245 }; 2246 return insn_consumer_->System(args); 2247 } 2248 if (GetBits<14, 1>()) { 2249 CsrImmOpcode opcode = CsrImmOpcode{low_opcode}; 2250 const CsrImmArgs args = { 2251 .opcode = opcode, 2252 .dst = GetBits<7, 5>(), 2253 .imm = GetBits<15, 5>(), 2254 .csr = GetBits<20, 12>(), 2255 }; 2256 return insn_consumer_->Csr(args); 2257 } 2258 CsrOpcode opcode = CsrOpcode{low_opcode}; 2259 const CsrArgs args = { 2260 .opcode = opcode, 2261 .dst = GetBits<7, 5>(), 2262 .src = GetBits<15, 5>(), 2263 .csr = GetBits<20, 12>(), 2264 }; 2265 return insn_consumer_->Csr(args); 2266 } 2267 DecodeJumpAndLinkRegister()2268 void DecodeJumpAndLinkRegister() { 2269 if (GetBits<12, 3>() != 0b000) { 2270 Undefined(); 2271 return; 2272 } 2273 // Decode sign-extend offset. 2274 int16_t offset = GetBits<20, 12>(); 2275 offset = static_cast<int16_t>(offset << 4) >> 4; 2276 2277 const JumpAndLinkRegisterArgs args = { 2278 .dst = GetBits<7, 5>(), 2279 .base = GetBits<15, 5>(), 2280 .offset = offset, 2281 .insn_len = 4, 2282 }; 2283 insn_consumer_->JumpAndLinkRegister(args); 2284 } 2285 2286 enum class BaseOpcode { 2287 kLoad = 0b00'000, 2288 kLoadFp = 0b00'001, 2289 kCustom0 = 0b00'010, 2290 kMiscMem = 0b00'011, 2291 kOpImm = 0b00'100, 2292 kAuipc = 0b00'101, 2293 kOpImm32 = 0b00'110, 2294 // Reserved 0b00'111, 2295 kStore = 0b01'000, 2296 kStoreFp = 0b01'001, 2297 kCustom1 = 0b01'010, 2298 kAmo = 0b01'011, 2299 kOp = 0b01'100, 2300 kLui = 0b01'101, 2301 kOp32 = 0b01'110, 2302 // Reserved 0b01'111, 2303 kMAdd = 0b10'000, 2304 kMSub = 0b10'001, 2305 kNmSub = 0b10'010, 2306 kNmAdd = 0b10'011, 2307 kOpFp = 0b10'100, 2308 vOpV = 0b10'101, 2309 kCustom2 = 0b10'110, 2310 // Reserved 0b10'111, 2311 kBranch = 0b11'000, 2312 kJalr = 0b11'001, 2313 // Reserved 0b11'010, 2314 kJal = 0b11'011, 2315 kSystem = 0b11'100, 2316 // Reserved 0b11'101, 2317 kCustom3 = 0b11'110, 2318 // Reserved 0b11'111, 2319 }; 2320 2321 enum class CompressedOpcode { 2322 kAddi4spn = 0b00'000, 2323 kFld = 0b001'00, 2324 kLw = 0b010'00, 2325 kLd = 0b011'00, 2326 // Reserved 0b00'100 2327 kFsd = 0b101'00, 2328 kSw = 0b110'00, 2329 kSd = 0b111'00, 2330 kAddi = 0b000'01, 2331 kAddiw = 0b001'01, 2332 kLi = 0b010'01, 2333 kLui_Addi16sp = 0b011'01, 2334 kMisc_Alu = 0b100'01, 2335 kJ = 0b101'01, 2336 kBeqz = 0b110'01, 2337 kBnez = 0b111'01, 2338 kSlli = 0b000'10, 2339 kFldsp = 0b001'10, 2340 kLwsp = 0b010'10, 2341 kLdsp = 0b011'10, 2342 kJr_Jalr_Mv_Add = 0b100'10, 2343 kFsdsp = 0b101'10, 2344 kSwsp = 0b110'10, 2345 kSdsp = 0b111'10, 2346 // instruction with 0bxxx'11 opcodes are not compressed instruction and can not be in this 2347 // table. 2348 }; 2349 2350 static constexpr struct { 2351 bool is_vector_instruction; 2352 union { 2353 FloatOperandType size; 2354 MemoryDataOperandType eew; 2355 }; 2356 } kLoadStoreWidthToOperandType[8] = { 2357 {.is_vector_instruction = true, .eew = MemoryDataOperandType::k8bit}, 2358 {.is_vector_instruction = false, .size = FloatOperandType::kHalf}, 2359 {.is_vector_instruction = false, .size = FloatOperandType::kFloat}, 2360 {.is_vector_instruction = false, .size = FloatOperandType::kDouble}, 2361 {.is_vector_instruction = false, .size = FloatOperandType::kQuad}, 2362 {.is_vector_instruction = true, .eew = MemoryDataOperandType::k16bit}, 2363 {.is_vector_instruction = true, .eew = MemoryDataOperandType::k32bit}, 2364 {.is_vector_instruction = true, .eew = MemoryDataOperandType::k64bit}}; 2365 2366 InsnConsumer* insn_consumer_; 2367 uint32_t code_; 2368 }; 2369 2370 } // namespace berberis 2371 2372 #endif // BERBERIS_DECODER_RISCV64_DECODER_H_ 2373