| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "vm/globals.h" // Needed here to get TARGET_ARCH_RISCV. |
| #if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64) |
| |
| #include "vm/compiler/assembler/disassembler.h" |
| |
| #include "platform/assert.h" |
| #include "vm/instructions.h" |
| |
| namespace dart { |
| |
| #if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) |
| |
| // We deviate from objdump in two places: |
| // - branches display displacements instead of targets so our output is |
| // position independent for tests. |
| // - auipc/lui display the decoded value instead of the encoded value |
| class RISCVDisassembler { |
| public: |
| explicit RISCVDisassembler(char* buffer, |
| size_t buffer_size, |
| ExtensionSet extensions) |
| : extensions_(extensions), |
| buffer_(buffer), |
| buffer_size_(buffer_size), |
| buffer_pos_(0) {} |
| |
| bool Supports(Extension extension) const { |
| return extensions_.Includes(extension); |
| } |
| bool Supports(ExtensionSet extensions) const { |
| return extensions_.IncludesAll(extensions); |
| } |
| |
| intptr_t Disassemble(uword pc) { |
| uint16_t parcel = *reinterpret_cast<uint16_t*>(pc); |
| if (Supports(RV_C) && IsCInstruction(parcel)) { |
| CInstr instr(parcel); |
| DisassembleInstruction(instr); |
| return instr.length(); |
| } else { |
| uint32_t parcel = *reinterpret_cast<uint32_t*>(pc); |
| Instr instr(parcel); |
| DisassembleInstruction(instr); |
| return instr.length(); |
| } |
| } |
| |
| private: |
| void DisassembleInstruction(Instr instr); |
| void DisassembleInstruction(CInstr instr); |
| void DisassembleLUI(Instr instr); |
| void DisassembleAUIPC(Instr instr); |
| void DisassembleJAL(Instr instr); |
| void DisassembleJALR(Instr instr); |
| void DisassembleBRANCH(Instr instr); |
| void DisassembleLOAD(Instr instr); |
| void DisassembleSTORE(Instr instr); |
| void DisassembleOPIMM(Instr instr); |
| void DisassembleOPIMM32(Instr instr); |
| void DisassembleOP(Instr instr); |
| void DisassembleOP_0(Instr instr); |
| void DisassembleOP_SUB(Instr instr); |
| void DisassembleOP_MULDIV(Instr instr); |
| void DisassembleOP32(Instr instr); |
| void DisassembleOP32_0(Instr instr); |
| void DisassembleOP32_SUB(Instr instr); |
| void DisassembleOP32_MULDIV(Instr instr); |
| void DisassembleMISCMEM(Instr instr); |
| void DisassembleSYSTEM(Instr instr); |
| void DisassembleAMO(Instr instr); |
| void DisassembleAMO32(Instr instr); |
| void DisassembleAMO64(Instr instr); |
| void DisassembleLOADFP(Instr instr); |
| void DisassembleSTOREFP(Instr instr); |
| void DisassembleFMADD(Instr instr); |
| void DisassembleFMSUB(Instr instr); |
| void DisassembleFNMADD(Instr instr); |
| void DisassembleFNMSUB(Instr instr); |
| void DisassembleOPFP(Instr instr); |
| |
| void UnknownInstruction(Instr instr); |
| void UnknownInstruction(CInstr instr); |
| |
| void Print(const char* format, Instr instr, ExtensionSet extension); |
| void Print(const char* format, CInstr instr, ExtensionSet extension); |
| const char* PrintOption(const char* format, Instr instr); |
| const char* PrintOption(const char* format, CInstr instr); |
| |
| void Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3) { |
| va_list args; |
| va_start(args, format); |
| intptr_t len = Utils::VSNPrint(buffer_ + buffer_pos_, |
| buffer_size_ - buffer_pos_, format, args); |
| va_end(args); |
| buffer_pos_ += len; |
| buffer_[buffer_pos_] = '\0'; |
| } |
| |
| const ExtensionSet extensions_; |
| char* buffer_; // Decode instructions into this buffer. |
| size_t buffer_size_; // The size of the character buffer. |
| size_t buffer_pos_; // Current character position in buffer. |
| }; |
| |
| void RISCVDisassembler::DisassembleInstruction(Instr instr) { |
| switch (instr.opcode()) { |
| case LUI: |
| DisassembleLUI(instr); |
| break; |
| case AUIPC: |
| DisassembleAUIPC(instr); |
| break; |
| case JAL: |
| DisassembleJAL(instr); |
| break; |
| case JALR: |
| DisassembleJALR(instr); |
| break; |
| case BRANCH: |
| DisassembleBRANCH(instr); |
| break; |
| case LOAD: |
| DisassembleLOAD(instr); |
| break; |
| case STORE: |
| DisassembleSTORE(instr); |
| break; |
| case OPIMM: |
| DisassembleOPIMM(instr); |
| break; |
| case OPIMM32: |
| DisassembleOPIMM32(instr); |
| break; |
| case OP: |
| DisassembleOP(instr); |
| break; |
| case OP32: |
| DisassembleOP32(instr); |
| break; |
| case MISCMEM: |
| DisassembleMISCMEM(instr); |
| break; |
| case SYSTEM: |
| DisassembleSYSTEM(instr); |
| break; |
| case AMO: |
| DisassembleAMO(instr); |
| break; |
| case LOADFP: |
| DisassembleLOADFP(instr); |
| break; |
| case STOREFP: |
| DisassembleSTOREFP(instr); |
| break; |
| case FMADD: |
| DisassembleFMADD(instr); |
| break; |
| case FMSUB: |
| DisassembleFMSUB(instr); |
| break; |
| case FNMADD: |
| DisassembleFNMADD(instr); |
| break; |
| case FNMSUB: |
| DisassembleFNMSUB(instr); |
| break; |
| case OPFP: |
| DisassembleOPFP(instr); |
| break; |
| default: |
| if ((instr.encoding() == 0) || |
| (instr.encoding() == static_cast<uint32_t>(-1))) { |
| Print("trap", instr, RV_I); |
| break; |
| } |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleInstruction(CInstr instr) { |
| switch (instr.opcode()) { |
| case C_LWSP: |
| Print("lw 'rd, 'spload4imm(sp)", instr, RV_C); |
| break; |
| #if XLEN == 32 |
| case C_FLWSP: |
| Print("flw 'frd, 'spload4imm(sp)", instr, RV_C | RV_F); |
| break; |
| #else |
| case C_LDSP: |
| Print("ld 'rd, 'spload8imm(sp)", instr, RV_C); |
| break; |
| #endif |
| case C_FLDSP: |
| Print("fld 'frd, 'spload8imm(sp)", instr, RV_C | RV_D); |
| break; |
| case C_SWSP: |
| Print("sw 'rs2, 'spstore4imm(sp)", instr, RV_C); |
| break; |
| #if XLEN == 32 |
| case C_FSWSP: |
| Print("fsw 'frs2, 'spstore4imm(sp)", instr, RV_C | RV_F); |
| break; |
| #else |
| case C_SDSP: |
| Print("sd 'rs2, 'spstore8imm(sp)", instr, RV_C); |
| break; |
| #endif |
| case C_FSDSP: |
| Print("fsd 'frs2, 'spstore8imm(sp)", instr, RV_C | RV_D); |
| break; |
| case C_LW: |
| Print("lw 'rdp, 'mem4imm('rs1p)", instr, RV_C); |
| break; |
| #if XLEN == 32 |
| case C_FLW: |
| Print("flw 'frdp, 'mem4imm('rs1p)", instr, RV_C | RV_F); |
| break; |
| #else |
| case C_LD: |
| Print("ld 'rdp, 'mem8imm('rs1p)", instr, RV_C); |
| break; |
| #endif |
| case C_FLD: |
| Print("fld 'frdp, 'mem8imm('rs1p)", instr, RV_C | RV_D); |
| break; |
| case C_SW: |
| Print("sw 'rs2p, 'mem4imm('rs1p)", instr, RV_C); |
| break; |
| #if XLEN == 32 |
| case C_FSW: |
| Print("fsw 'frs2p, 'mem4imm('rs1p)", instr, RV_C | RV_F); |
| break; |
| #else |
| case C_SD: |
| Print("sd 'rs2p, 'mem8imm('rs1p)", instr, RV_C); |
| break; |
| #endif |
| case C_FSD: |
| Print("fsd 'frs2p, 'mem8imm('rs1p)", instr, RV_C | RV_F); |
| break; |
| case C_J: |
| Print("j 'jimm", instr, RV_C); |
| break; |
| #if XLEN == 32 |
| case C_JAL: |
| Print("jal 'jimm", instr, RV_C); |
| break; |
| #endif |
| case C_JR: |
| if (instr.encoding() & (C_JALR ^ C_JR)) { |
| if ((instr.rs1() == ZR) && (instr.rs2() == ZR)) { |
| Print("ebreak", instr, RV_C); |
| } else if (instr.rs2() == ZR) { |
| Print("jalr 'rs1", instr, RV_C); |
| } else { |
| Print("add 'rd, 'rs1, 'rs2", instr, RV_C); |
| } |
| } else { |
| if (instr.rd() != ZR && instr.rs2() != ZR) { |
| Print("mv 'rd, 'rs2", instr, RV_C); |
| } else if (instr.rs2() != ZR) { |
| UnknownInstruction(instr); |
| } else if (instr.rs1() == RA) { |
| Print("ret", instr, RV_C); |
| } else { |
| Print("jr 'rs1", instr, RV_C); |
| } |
| } |
| break; |
| case C_BEQZ: |
| Print("beqz 'rs1p, 'bimm", instr, RV_C); |
| break; |
| case C_BNEZ: |
| Print("bnez 'rs1p, 'bimm", instr, RV_C); |
| break; |
| case C_LI: |
| Print("li 'rd, 'iimm", instr, RV_C); |
| break; |
| case C_LUI: |
| if (instr.rd() == SP) { |
| Print("addi 'rd, 'rs1, 'i16imm", instr, RV_C); |
| } else { |
| Print("lui 'rd, 'uimm", instr, RV_C); |
| } |
| break; |
| case C_ADDI: |
| if ((instr.rd() == ZR) && (instr.rs1() == ZR) && (instr.i_imm() == 0)) { |
| Print("nop", instr, RV_C); |
| } else { |
| Print("addi 'rd, 'rs1, 'iimm", instr, RV_C); |
| } |
| break; |
| #if XLEN >= 64 |
| case C_ADDIW: |
| if (instr.i_imm() == 0) { |
| Print("sext.w 'rd, 'rs1", instr, RV_C); |
| } else { |
| Print("addiw 'rd, 'rs1, 'iimm", instr, RV_C); |
| } |
| break; |
| #endif |
| case C_ADDI4SPN: |
| if (instr.i4spn_imm() == 0) { |
| UnknownInstruction(instr); |
| } else { |
| Print("addi 'rdp, sp, 'i4spnimm", instr, RV_C); |
| } |
| break; |
| case C_SLLI: |
| if (instr.i_imm() == 0) { |
| UnknownInstruction(instr); |
| } else { |
| Print("slli 'rd, 'rs1, 'iimm", instr, RV_C); |
| } |
| break; |
| case C_MISCALU: |
| switch (instr.encoding() & C_MISCALU_MASK) { |
| case C_SRLI: |
| if (instr.i_imm() == 0) { |
| UnknownInstruction(instr); |
| } else { |
| Print("srli 'rs1p, 'rs1p, 'iimm", instr, RV_C); |
| } |
| break; |
| case C_SRAI: |
| if (instr.i_imm() == 0) { |
| UnknownInstruction(instr); |
| } else { |
| Print("srai 'rs1p, 'rs1p, 'iimm", instr, RV_C); |
| } |
| break; |
| case C_ANDI: |
| Print("andi 'rs1p, 'rs1p, 'iimm", instr, RV_C); |
| break; |
| case C_RR: |
| switch (instr.encoding() & C_RR_MASK) { |
| case C_AND: |
| Print("and 'rs1p, 'rs1p, 'rs2p", instr, RV_C); |
| break; |
| case C_OR: |
| Print("or 'rs1p, 'rs1p, 'rs2p", instr, RV_C); |
| break; |
| case C_XOR: |
| Print("xor 'rs1p, 'rs1p, 'rs2p", instr, RV_C); |
| break; |
| case C_SUB: |
| Print("sub 'rs1p, 'rs1p, 'rs2p", instr, RV_C); |
| break; |
| #if XLEN >= 64 |
| case C_ADDW: |
| Print("addw 'rs1p, 'rs1p, 'rs2p", instr, RV_C); |
| break; |
| case C_SUBW: |
| Print("subw 'rs1p, 'rs1p, 'rs2p", instr, RV_C); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| default: |
| if ((instr.encoding() == 0) || |
| (instr.encoding() == static_cast<uint16_t>(-1))) { |
| Print("trap", instr, RV_C); |
| break; |
| } |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleLUI(Instr instr) { |
| Print("lui 'rd, 'uimm", instr, RV_I); |
| } |
| |
| void RISCVDisassembler::DisassembleAUIPC(Instr instr) { |
| Print("auipc 'rd, 'uimm", instr, RV_I); |
| } |
| |
| void RISCVDisassembler::DisassembleJAL(Instr instr) { |
| if (instr.rd() == ZR) { |
| Print("j 'jimm", instr, RV_I); |
| } else if (instr.rd() == RA) { |
| Print("jal 'jimm", instr, RV_I); |
| } else { |
| Print("jal 'rd, 'jimm", instr, RV_I); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleJALR(Instr instr) { |
| if (instr.rd() == ZR) { |
| if ((instr.rs1() == RA) && (instr.itype_imm() == 0)) { |
| Print("ret", instr, RV_I); |
| } else if (instr.itype_imm() == 0) { |
| Print("jr 'rs1", instr, RV_I); |
| } else { |
| Print("jr 'iimm('rs1)", instr, RV_I); |
| } |
| } else if (instr.rd() == RA) { |
| if (instr.itype_imm() == 0) { |
| Print("jalr 'rs1", instr, RV_I); |
| } else { |
| Print("jalr 'iimm('rs1)", instr, RV_I); |
| } |
| } else { |
| if (instr.itype_imm() == 0) { |
| Print("jalr 'rd, 'rs1", instr, RV_I); |
| } else { |
| Print("jalr 'rd, 'iimm('rs1)", instr, RV_I); |
| } |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleBRANCH(Instr instr) { |
| switch (instr.funct3()) { |
| case BEQ: |
| if (instr.rs2() == ZR) { |
| Print("beqz 'rs1, 'bimm", instr, RV_I); |
| } else { |
| Print("beq 'rs1, 'rs2, 'bimm", instr, RV_I); |
| } |
| break; |
| case BNE: |
| if (instr.rs2() == ZR) { |
| Print("bnez 'rs1, 'bimm", instr, RV_I); |
| } else { |
| Print("bne 'rs1, 'rs2, 'bimm", instr, RV_I); |
| } |
| break; |
| case BLT: |
| if (instr.rs2() == ZR) { |
| Print("bltz 'rs1, 'bimm", instr, RV_I); |
| } else if (instr.rs1() == ZR) { |
| Print("bgtz 'rs2, 'bimm", instr, RV_I); |
| } else { |
| Print("blt 'rs1, 'rs2, 'bimm", instr, RV_I); |
| } |
| break; |
| case BGE: |
| if (instr.rs2() == ZR) { |
| Print("bgez 'rs1, 'bimm", instr, RV_I); |
| } else if (instr.rs1() == ZR) { |
| Print("blez 'rs2, 'bimm", instr, RV_I); |
| } else { |
| Print("ble 'rs2, 'rs1, 'bimm", instr, RV_I); |
| } |
| break; |
| case BLTU: |
| Print("bltu 'rs1, 'rs2, 'bimm", instr, RV_I); |
| break; |
| case BGEU: |
| Print("bleu 'rs2, 'rs1, 'bimm", instr, RV_I); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleLOAD(Instr instr) { |
| switch (instr.funct3()) { |
| case LB: |
| Print("lb 'rd, 'iimm('rs1)", instr, RV_I); |
| break; |
| case LH: |
| Print("lh 'rd, 'iimm('rs1)", instr, RV_I); |
| break; |
| case LW: |
| Print("lw 'rd, 'iimm('rs1)", instr, RV_I); |
| break; |
| case LBU: |
| Print("lbu 'rd, 'iimm('rs1)", instr, RV_I); |
| break; |
| case LHU: |
| Print("lhu 'rd, 'iimm('rs1)", instr, RV_I); |
| break; |
| #if XLEN >= 64 |
| case LWU: |
| Print("lwu 'rd, 'iimm('rs1)", instr, RV_I); |
| break; |
| case LD: |
| Print("ld 'rd, 'iimm('rs1)", instr, RV_I); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleLOADFP(Instr instr) { |
| switch (instr.funct3()) { |
| case S: |
| Print("flw 'frd, 'iimm('rs1)", instr, RV_F); |
| break; |
| case D: |
| Print("fld 'frd, 'iimm('rs1)", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleSTORE(Instr instr) { |
| switch (instr.funct3()) { |
| case SB: |
| Print("sb 'rs2, 'simm('rs1)", instr, RV_I); |
| break; |
| case SH: |
| Print("sh 'rs2, 'simm('rs1)", instr, RV_I); |
| break; |
| case SW: |
| Print("sw 'rs2, 'simm('rs1)", instr, RV_I); |
| break; |
| #if XLEN >= 64 |
| case SD: |
| Print("sd 'rs2, 'simm('rs1)", instr, RV_I); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleSTOREFP(Instr instr) { |
| switch (instr.funct3()) { |
| case S: |
| Print("fsw 'frs2, 'simm('rs1)", instr, RV_F); |
| break; |
| case D: |
| Print("fsd 'frs2, 'simm('rs1)", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOPIMM(Instr instr) { |
| switch (instr.funct3()) { |
| case ADDI: |
| if ((instr.rd() == ZR) && (instr.rs1() == ZR) && |
| (instr.itype_imm() == 0)) { |
| Print("nop", instr, RV_I); // The canonical nop. |
| } else if (instr.itype_imm() == 0) { |
| Print("mv 'rd, 'rs1", instr, RV_I); |
| } else if (instr.rs1() == ZR) { |
| Print("li 'rd, 'iimm", instr, RV_I); |
| } else { |
| Print("addi 'rd, 'rs1, 'iimm", instr, RV_I); |
| } |
| break; |
| case SLTI: |
| Print("slti 'rd, 'rs1, 'iimm", instr, RV_I); |
| break; |
| case SLTIU: |
| if (instr.itype_imm() == 1) { |
| Print("seqz 'rd, 'rs1", instr, RV_I); |
| } else { |
| Print("sltiu 'rd, 'rs1, 'iimm", instr, RV_I); |
| } |
| break; |
| case XORI: |
| if (instr.itype_imm() == -1) { |
| Print("not 'rd, 'rs1", instr, RV_I); |
| } else { |
| Print("xori 'rd, 'rs1, 'iimm", instr, RV_I); |
| } |
| break; |
| case ORI: |
| Print("ori 'rd, 'rs1, 'iimm", instr, RV_I); |
| break; |
| case ANDI: |
| Print("andi 'rd, 'rs1, 'iimm", instr, RV_I); |
| break; |
| case SLLI: |
| Print("slli 'rd, 'rs1, 'shamt", instr, RV_I); |
| break; |
| case SRI: |
| if ((instr.funct7() & 0b1111110) == SRA) { |
| Print("srai 'rd, 'rs1, 'shamt", instr, RV_I); |
| } else { |
| Print("srli 'rd, 'rs1, 'shamt", instr, RV_I); |
| } |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOPIMM32(Instr instr) { |
| switch (instr.funct3()) { |
| #if XLEN >= 64 |
| case ADDI: |
| if (instr.itype_imm() == 0) { |
| Print("sext.w 'rd, 'rs1", instr, RV_I); |
| } else { |
| Print("addiw 'rd, 'rs1, 'iimm", instr, RV_I); |
| } |
| break; |
| case SLLI: |
| Print("slliw 'rd, 'rs1, 'shamt", instr, RV_I); |
| break; |
| case SRI: |
| if (instr.funct7() == SRA) { |
| Print("sraiw 'rd, 'rs1, 'shamt", instr, RV_I); |
| } else { |
| Print("srliw 'rd, 'rs1, 'shamt", instr, RV_I); |
| } |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOP(Instr instr) { |
| switch (instr.funct7()) { |
| case 0: |
| DisassembleOP_0(instr); |
| break; |
| case SUB: |
| DisassembleOP_SUB(instr); |
| break; |
| case MULDIV: |
| DisassembleOP_MULDIV(instr); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOP_0(Instr instr) { |
| switch (instr.funct3()) { |
| case ADD: |
| Print("add 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| case SLL: |
| Print("sll 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| case SLT: |
| if (instr.rs2() == ZR) { |
| Print("sltz 'rd, 'rs1", instr, RV_I); |
| } else if (instr.rs1() == ZR) { |
| Print("sgtz 'rd, 'rs2", instr, RV_I); |
| } else { |
| Print("slt 'rd, 'rs1, 'rs2", instr, RV_I); |
| } |
| break; |
| case SLTU: |
| if (instr.rs1() == ZR) { |
| Print("snez 'rd, 'rs2", instr, RV_I); |
| } else { |
| Print("sltu 'rd, 'rs1, 'rs2", instr, RV_I); |
| } |
| break; |
| case XOR: |
| Print("xor 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| case SR: |
| Print("srl 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| case OR: |
| Print("or 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| case AND: |
| Print("and 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOP_SUB(Instr instr) { |
| switch (instr.funct3()) { |
| case ADD: |
| if (instr.rs1() == ZR) { |
| Print("neg 'rd, 'rs2", instr, RV_I); |
| } else { |
| Print("sub 'rd, 'rs1, 'rs2", instr, RV_I); |
| } |
| break; |
| case SR: |
| Print("sra 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOP_MULDIV(Instr instr) { |
| switch (instr.funct3()) { |
| case MUL: |
| Print("mul 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case MULH: |
| Print("mulh 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case MULHSU: |
| Print("mulhsu 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case MULHU: |
| Print("mulhu 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case DIV: |
| Print("div 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case DIVU: |
| Print("divu 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case REM: |
| Print("rem 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case REMU: |
| Print("remu 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOP32(Instr instr) { |
| switch (instr.funct7()) { |
| case 0: |
| DisassembleOP32_0(instr); |
| break; |
| case SUB: |
| DisassembleOP32_SUB(instr); |
| break; |
| case MULDIV: |
| DisassembleOP32_MULDIV(instr); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOP32_0(Instr instr) { |
| switch (instr.funct3()) { |
| #if XLEN >= 64 |
| case ADD: |
| Print("addw 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| case SLL: |
| Print("sllw 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| case SR: { |
| Print("srlw 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| } |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOP32_SUB(Instr instr) { |
| switch (instr.funct3()) { |
| #if XLEN >= 64 |
| case ADD: |
| if (instr.rs1() == ZR) { |
| Print("negw 'rd, 'rs2", instr, RV_I); |
| } else { |
| Print("subw 'rd, 'rs1, 'rs2", instr, RV_I); |
| } |
| break; |
| case SR: |
| Print("sraw 'rd, 'rs1, 'rs2", instr, RV_I); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOP32_MULDIV(Instr instr) { |
| switch (instr.funct3()) { |
| #if XLEN >= 64 |
| case MULW: |
| Print("mulw 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case DIVW: |
| Print("divw 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case DIVUW: |
| Print("divuw 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case REMW: |
| Print("remw 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| case REMUW: |
| Print("remuw 'rd, 'rs1, 'rs2", instr, RV_M); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleMISCMEM(Instr instr) { |
| switch (instr.funct3()) { |
| case FENCE: |
| Print("fence'predsucc", instr, RV_I); |
| break; |
| case FENCEI: |
| Print("fence.i", instr, RV_I); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleSYSTEM(Instr instr) { |
| switch (instr.funct3()) { |
| case 0: |
| switch (instr.funct12()) { |
| case ECALL: |
| if (instr.rs1() == ZR) { |
| Print("ecall", instr, RV_I); |
| } else { |
| Print("SimulatorPrintObject 'rs1", instr, RV_I); |
| } |
| break; |
| case EBREAK: |
| Print("ebreak", instr, RV_I); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| case CSRRW: |
| if (instr.rd() == ZR) { |
| Print("csrw 'csr, 'rs1", instr, RV_I); |
| } else { |
| Print("csrrw 'rd, 'csr, 'rs1", instr, RV_I); |
| } |
| break; |
| case CSRRS: |
| if (instr.rs1() == ZR) { |
| Print("csrr 'rd, 'csr", instr, RV_I); |
| } else if (instr.rd() == ZR) { |
| Print("csrs 'csr, 'rs1", instr, RV_I); |
| } else { |
| Print("csrrs 'rd, 'csr, 'rs1", instr, RV_I); |
| } |
| break; |
| case CSRRC: |
| if (instr.rd() == ZR) { |
| Print("csrc 'csr, 'rs1", instr, RV_I); |
| } else { |
| Print("csrrc 'rd, 'csr, 'rs1", instr, RV_I); |
| } |
| break; |
| case CSRRWI: |
| if (instr.rd() == ZR) { |
| Print("csrwi 'csr, 'zimm", instr, RV_I); |
| } else { |
| Print("csrrwi 'rd, 'csr, 'zimm", instr, RV_I); |
| } |
| break; |
| case CSRRSI: |
| if (instr.rd() == ZR) { |
| Print("csrsi 'csr, 'zimm", instr, RV_I); |
| } else { |
| Print("csrrsi 'rd, 'csr, 'zimm", instr, RV_I); |
| } |
| break; |
| case CSRRCI: |
| if (instr.rd() == ZR) { |
| Print("csrci 'csr, 'zimm", instr, RV_I); |
| } else { |
| Print("csrrci 'rd, 'csr, 'zimm", instr, RV_I); |
| } |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleAMO(Instr instr) { |
| switch (instr.funct3()) { |
| case WIDTH32: |
| DisassembleAMO32(instr); |
| break; |
| case WIDTH64: |
| DisassembleAMO64(instr); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleAMO32(Instr instr) { |
| switch (instr.funct5()) { |
| case LR: |
| Print("lr.w'order 'rd, ('rs1)", instr, RV_A); |
| break; |
| case SC: |
| Print("sc.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOSWAP: |
| Print("amoswap.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOADD: |
| Print("amoadd.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOXOR: |
| Print("amoxor.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOAND: |
| Print("amoand.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOOR: |
| Print("amoor.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOMIN: |
| Print("amomin.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOMAX: |
| Print("amomax.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOMINU: |
| Print("amominu.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOMAXU: |
| Print("amomaxu.w'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleAMO64(Instr instr) { |
| switch (instr.funct5()) { |
| #if XLEN >= 64 |
| case LR: |
| Print("lr.d'order 'rd, ('rs1)", instr, RV_A); |
| break; |
| case SC: |
| Print("sc.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOSWAP: |
| Print("amoswap.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOADD: |
| Print("amoadd.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOXOR: |
| Print("amoxor.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOAND: |
| Print("amoand.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOOR: |
| Print("amoor.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOMIN: |
| Print("amomin.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOMAX: |
| Print("amomax.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOMINU: |
| Print("amominu.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| case AMOMAXU: |
| Print("amomaxu.d'order 'rd, 'rs2, ('rs1)", instr, RV_A); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleFMADD(Instr instr) { |
| switch (instr.funct2()) { |
| case F2_S: |
| Print("fmadd.s 'frd, 'frs1, 'frs2, 'frs3'round", instr, RV_F); |
| break; |
| case F2_D: |
| Print("fmadd.d 'frd, 'frs1, 'frs2, 'frs3'round", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleFMSUB(Instr instr) { |
| switch (instr.funct2()) { |
| case F2_S: |
| Print("fmsub.s 'frd, 'frs1, 'frs2, 'frs3'round", instr, RV_F); |
| break; |
| case F2_D: |
| Print("fmsub.d 'frd, 'frs1, 'frs2, 'frs3'round", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleFNMADD(Instr instr) { |
| switch (instr.funct2()) { |
| case F2_S: |
| Print("fnmadd.s 'frd, 'frs1, 'frs2, 'frs3'round", instr, RV_F); |
| break; |
| case F2_D: |
| Print("fnmadd.d 'frd, 'frs1, 'frs2, 'frs3'round", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleFNMSUB(Instr instr) { |
| switch (instr.funct2()) { |
| case F2_S: |
| Print("fnmsub.s 'frd, 'frs1, 'frs2, 'frs3'round", instr, RV_F); |
| break; |
| case F2_D: |
| Print("fnmsub.d 'frd, 'frs1, 'frs2, 'frs3'round", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::DisassembleOPFP(Instr instr) { |
| switch (instr.funct7()) { |
| case FADDS: |
| Print("fadd.s 'frd, 'frs1, 'frs2'round", instr, RV_F); |
| break; |
| case FSUBS: |
| Print("fsub.s 'frd, 'frs1, 'frs2'round", instr, RV_F); |
| break; |
| case FMULS: |
| Print("fmul.s 'frd, 'frs1, 'frs2'round", instr, RV_F); |
| break; |
| case FDIVS: |
| Print("fdiv.s 'frd, 'frs1, 'frs2'round", instr, RV_F); |
| break; |
| case FSQRTS: |
| Print("fsqrt.s 'frd, 'frs1'round", instr, RV_F); |
| break; |
| case FSGNJS: { |
| switch (instr.funct3()) { |
| case J: |
| if (instr.frs1() == instr.frs2()) { |
| Print("fmv.s 'frd, 'frs1", instr, RV_F); |
| } else { |
| Print("fsgnj.s 'frd, 'frs1, 'frs2", instr, RV_F); |
| } |
| break; |
| case JN: |
| if (instr.frs1() == instr.frs2()) { |
| Print("fneg.s 'frd, 'frs1", instr, RV_F); |
| } else { |
| Print("fsgnjn.s 'frd, 'frs1, 'frs2", instr, RV_F); |
| } |
| break; |
| case JX: |
| if (instr.frs1() == instr.frs2()) { |
| Print("fabs.s 'frd, 'frs1", instr, RV_F); |
| } else { |
| Print("fsgnjx.s 'frd, 'frs1, 'frs2", instr, RV_F); |
| } |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| } |
| case FMINMAXS: { |
| switch (instr.funct3()) { |
| case MIN: |
| Print("fmin.s 'frd, 'frs1, 'frs2", instr, RV_F); |
| break; |
| case MAX: |
| Print("fmax.s 'frd, 'frs1, 'frs2", instr, RV_F); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| } |
| case FCMPS: { |
| switch (instr.funct3()) { |
| case FEQ: |
| Print("feq.s 'rd, 'frs1, 'frs2", instr, RV_F); |
| break; |
| case FLT: |
| Print("flt.s 'rd, 'frs1, 'frs2", instr, RV_F); |
| break; |
| case FLE: |
| Print("fle.s 'rd, 'frs1, 'frs2", instr, RV_F); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| } |
| case FCLASSS: // = FMVXW |
| switch (instr.funct3()) { |
| case 1: |
| Print("fclass.s 'rd, 'frs1", instr, RV_F); |
| break; |
| case 0: |
| Print("fmv.x.w 'rd, 'frs1", instr, RV_F); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| case FCVTintS: |
| switch (static_cast<FcvtRs2>(instr.rs2())) { |
| case W: |
| Print("fcvt.w.s 'rd, 'frs1'round", instr, RV_F); |
| break; |
| case WU: |
| Print("fcvt.wu.s 'rd, 'frs1'round", instr, RV_F); |
| break; |
| #if XLEN >= 64 |
| case L: |
| Print("fcvt.l.s 'rd, 'frs1'round", instr, RV_F); |
| break; |
| case LU: |
| Print("fcvt.lu.s 'rd, 'frs1'round", instr, RV_F); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| case FCVTSint: |
| switch (static_cast<FcvtRs2>(instr.rs2())) { |
| case W: |
| Print("fcvt.s.w 'frd, 'rs1", instr, RV_F); |
| break; |
| case WU: |
| Print("fcvt.s.wu 'frd, 'rs1", instr, RV_F); |
| break; |
| #if XLEN >= 64 |
| case L: |
| Print("fcvt.s.l 'frd, 'rs1", instr, RV_F); |
| break; |
| case LU: |
| Print("fcvt.s.lu 'frd, 'rs1", instr, RV_F); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| case FMVWX: |
| Print("fmv.w.x 'frd, 'rs1", instr, RV_F); |
| break; |
| case FADDD: |
| Print("fadd.d 'frd, 'frs1, 'frs2'round", instr, RV_D); |
| break; |
| case FSUBD: |
| Print("fsub.d 'frd, 'frs1, 'frs2'round", instr, RV_D); |
| break; |
| case FMULD: |
| Print("fmul.d 'frd, 'frs1, 'frs2'round", instr, RV_D); |
| break; |
| case FDIVD: |
| Print("fdiv.d 'frd, 'frs1, 'frs2'round", instr, RV_D); |
| break; |
| case FSQRTD: |
| Print("fsqrt.d 'frd, 'frs1'round", instr, RV_D); |
| break; |
| case FSGNJD: { |
| switch (instr.funct3()) { |
| case J: |
| if (instr.frs1() == instr.frs2()) { |
| Print("fmv.d 'frd, 'frs1", instr, RV_D); |
| } else { |
| Print("fsgnj.d 'frd, 'frs1, 'frs2", instr, RV_D); |
| } |
| break; |
| case JN: |
| if (instr.frs1() == instr.frs2()) { |
| Print("fneg.d 'frd, 'frs1", instr, RV_D); |
| } else { |
| Print("fsgnjn.d 'frd, 'frs1, 'frs2", instr, RV_D); |
| } |
| break; |
| case JX: |
| if (instr.frs1() == instr.frs2()) { |
| Print("fabs.d 'frd, 'frs1", instr, RV_D); |
| } else { |
| Print("fsgnjx.d 'frd, 'frs1, 'frs2", instr, RV_D); |
| } |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| } |
| case FMINMAXD: { |
| switch (instr.funct3()) { |
| case MIN: |
| Print("fmin.d 'frd, 'frs1, 'frs2", instr, RV_D); |
| break; |
| case MAX: |
| Print("fmax.d 'frd, 'frs1, 'frs2", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| } |
| case FCVTS: { |
| switch (instr.rs2()) { |
| case 1: |
| Print("fcvt.s.d 'frd, 'frs1'round", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| } |
| case FCVTD: { |
| switch (instr.rs2()) { |
| case 0: |
| Print("fcvt.d.s 'frd, 'frs1", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| } |
| case FCMPD: { |
| switch (instr.funct3()) { |
| case FEQ: |
| Print("feq.d 'rd, 'frs1, 'frs2", instr, RV_D); |
| break; |
| case FLT: |
| Print("flt.d 'rd, 'frs1, 'frs2", instr, RV_D); |
| break; |
| case FLE: |
| Print("fle.d 'rd, 'frs1, 'frs2", instr, RV_D); |
| break; |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| } |
| case FCLASSD: // = FMVXD |
| switch (instr.funct3()) { |
| case 1: |
| Print("fclass.d 'rd, 'frs1", instr, RV_D); |
| break; |
| #if XLEN >= 64 |
| case 0: |
| Print("fmv.x.d 'rd, 'frs1", instr, RV_D); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| case FCVTintD: |
| switch (static_cast<FcvtRs2>(instr.rs2())) { |
| case W: |
| Print("fcvt.w.d 'rd, 'frs1'round", instr, RV_D); |
| break; |
| case WU: |
| Print("fcvt.wu.d 'rd, 'frs1'round", instr, RV_D); |
| break; |
| #if XLEN >= 64 |
| case L: |
| Print("fcvt.l.d 'rd, 'frs1'round", instr, RV_D); |
| break; |
| case LU: |
| Print("fcvt.lu.d 'rd, 'frs1'round", instr, RV_D); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| case FCVTDint: |
| switch (static_cast<FcvtRs2>(instr.rs2())) { |
| case W: |
| Print("fcvt.d.w 'frd, 'rs1", instr, RV_D); |
| break; |
| case WU: |
| Print("fcvt.d.wu 'frd, 'rs1", instr, RV_D); |
| break; |
| #if XLEN >= 64 |
| case L: |
| Print("fcvt.d.l 'frd, 'rs1", instr, RV_D); |
| break; |
| case LU: |
| Print("fcvt.d.lu 'frd, 'rs1", instr, RV_D); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| break; |
| #if XLEN >= 64 |
| case FMVDX: |
| Print("fmv.d.x 'frd, 'rs1", instr, RV_D); |
| break; |
| #endif |
| default: |
| UnknownInstruction(instr); |
| } |
| } |
| |
| void RISCVDisassembler::UnknownInstruction(Instr instr) { |
| if (instr.encoding() == 0) { |
| Print("trap", instr, RV_I); |
| } else { |
| Print("unknown", instr, ExtensionSet::Empty()); |
| } |
| } |
| |
| void RISCVDisassembler::UnknownInstruction(CInstr instr) { |
| if (instr.encoding() == 0) { |
| Print("trap", instr, RV_I); |
| } else { |
| Print("unknown", instr, ExtensionSet::Empty()); |
| } |
| } |
| |
| void RISCVDisassembler::Print(const char* format, |
| Instr instr, |
| ExtensionSet ex) { |
| // Printf(" %08x ", instr.encoding()); |
| |
| while (format[0] != '\0') { |
| if (format[0] == '\'') { |
| format = PrintOption(format + 1, instr); |
| } else { |
| Printf("%c", format[0]); |
| format++; |
| } |
| } |
| |
| // Printf("\n"); |
| } |
| |
| void RISCVDisassembler::Print(const char* format, |
| CInstr instr, |
| ExtensionSet ex) { |
| // Printf(" %04x ", instr.encoding()); |
| |
| while (format[0] != '\0') { |
| if (format[0] == '\'') { |
| format = PrintOption(format + 1, instr); |
| } else { |
| Printf("%c", format[0]); |
| format++; |
| } |
| } |
| |
| // Printf("\n"); |
| } |
| |
| #define STRING_STARTS_WITH(string, compare_string) \ |
| (strncmp(string, compare_string, strlen(compare_string)) == 0) |
| |
| const char* RISCVDisassembler::PrintOption(const char* format, Instr instr) { |
| if (STRING_STARTS_WITH(format, "rd")) { |
| Printf("%s", cpu_reg_names[instr.rd()]); |
| return format + 2; |
| } else if (STRING_STARTS_WITH(format, "rs1")) { |
| Printf("%s", cpu_reg_names[instr.rs1()]); |
| return format + 3; |
| } else if (STRING_STARTS_WITH(format, "rs2")) { |
| Printf("%s", cpu_reg_names[instr.rs2()]); |
| return format + 3; |
| } else if (STRING_STARTS_WITH(format, "shamt")) { |
| Printf("0x%x", instr.shamt()); |
| return format + 5; |
| } else if (STRING_STARTS_WITH(format, "jimm")) { |
| Printf("%+" Pd, static_cast<intptr_t>(instr.jtype_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "uimm")) { |
| // objdump instead displays (imm >> 12) as hex. |
| Printf("%" Pd, static_cast<intptr_t>(instr.utype_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "iimm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.itype_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "simm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.stype_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "bimm")) { |
| Printf("%+" Pd, static_cast<intptr_t>(instr.btype_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "zimm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.zimm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "csr")) { |
| Printf("0x%" Px, static_cast<intptr_t>(instr.csr())); |
| return format + 3; |
| } else if (STRING_STARTS_WITH(format, "order")) { |
| switch (instr.memory_order()) { |
| case std::memory_order_relaxed: |
| break; |
| case std::memory_order_acquire: |
| Printf(".aq"); |
| break; |
| case std::memory_order_release: |
| Printf(".rl"); |
| break; |
| case std::memory_order_acq_rel: |
| Printf(".aqrl"); |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| return format + 5; |
| } else if (STRING_STARTS_WITH(format, "round")) { |
| switch (instr.rounding()) { |
| case RNE: |
| // Printf(", rne"); |
| break; |
| case RTZ: |
| Printf(", rtz"); |
| break; |
| case RDN: |
| Printf(", rdn"); |
| break; |
| case RUP: |
| Printf(", rup"); |
| break; |
| case RMM: |
| Printf(", rmm"); |
| break; |
| case DYN: |
| Printf(", dyn"); |
| break; |
| default: |
| Printf("<invalid rounding mode>"); |
| } |
| return format + 5; |
| } else if (STRING_STARTS_WITH(format, "predsucc")) { |
| HartEffects pred = static_cast<HartEffects>((instr.itype_imm() >> 4) & 0xF); |
| HartEffects succ = static_cast<HartEffects>((instr.itype_imm() >> 0) & 0xF); |
| if ((pred != HartEffects::kAll) || (succ != HartEffects::kAll)) { |
| Printf(" "); |
| if ((pred & HartEffects::kInput) != 0) Printf("i"); |
| if ((pred & HartEffects::kOutput) != 0) Printf("o"); |
| if ((pred & HartEffects::kRead) != 0) Printf("r"); |
| if ((pred & HartEffects::kWrite) != 0) Printf("w"); |
| Printf(","); |
| if ((succ & HartEffects::kInput) != 0) Printf("i"); |
| if ((succ & HartEffects::kOutput) != 0) Printf("o"); |
| if ((succ & HartEffects::kRead) != 0) Printf("r"); |
| if ((succ & HartEffects::kWrite) != 0) Printf("w"); |
| } |
| return format + 8; |
| } else if (STRING_STARTS_WITH(format, "frd")) { |
| Printf("%s", fpu_reg_names[instr.frd()]); |
| return format + 3; |
| } else if (STRING_STARTS_WITH(format, "frs1")) { |
| Printf("%s", fpu_reg_names[instr.frs1()]); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "frs2")) { |
| Printf("%s", fpu_reg_names[instr.frs2()]); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "frs3")) { |
| Printf("%s", fpu_reg_names[instr.frs3()]); |
| return format + 4; |
| } |
| |
| FATAL1("Bad format %s\n", format); |
| return nullptr; |
| } |
| |
| const char* RISCVDisassembler::PrintOption(const char* format, CInstr instr) { |
| if (STRING_STARTS_WITH(format, "rdp")) { |
| Printf("%s", cpu_reg_names[instr.rdp()]); |
| return format + 3; |
| } else if (STRING_STARTS_WITH(format, "rs1p")) { |
| Printf("%s", cpu_reg_names[instr.rs1p()]); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "rs2p")) { |
| Printf("%s", cpu_reg_names[instr.rs2p()]); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "rd")) { |
| Printf("%s", cpu_reg_names[instr.rd()]); |
| return format + 2; |
| } else if (STRING_STARTS_WITH(format, "rs1")) { |
| Printf("%s", cpu_reg_names[instr.rs1()]); |
| return format + 3; |
| } else if (STRING_STARTS_WITH(format, "rs2")) { |
| Printf("%s", cpu_reg_names[instr.rs2()]); |
| return format + 3; |
| } else if (STRING_STARTS_WITH(format, "frdp")) { |
| Printf("%s", fpu_reg_names[instr.frdp()]); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "frs1p")) { |
| Printf("%s", fpu_reg_names[instr.frs1p()]); |
| return format + 5; |
| } else if (STRING_STARTS_WITH(format, "frs2p")) { |
| Printf("%s", fpu_reg_names[instr.frs2p()]); |
| return format + 5; |
| } else if (STRING_STARTS_WITH(format, "frd")) { |
| Printf("%s", fpu_reg_names[instr.frd()]); |
| return format + 3; |
| } else if (STRING_STARTS_WITH(format, "frs1")) { |
| Printf("%s", fpu_reg_names[instr.frs1()]); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "frs2")) { |
| Printf("%s", fpu_reg_names[instr.frs2()]); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "spload4imm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.spload4_imm())); |
| return format + 10; |
| } else if (STRING_STARTS_WITH(format, "spload8imm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.spload8_imm())); |
| return format + 10; |
| } else if (STRING_STARTS_WITH(format, "spstore4imm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.spstore4_imm())); |
| return format + 11; |
| } else if (STRING_STARTS_WITH(format, "spstore8imm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.spstore8_imm())); |
| return format + 11; |
| } else if (STRING_STARTS_WITH(format, "mem4imm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.mem4_imm())); |
| return format + 7; |
| } else if (STRING_STARTS_WITH(format, "mem8imm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.mem8_imm())); |
| return format + 7; |
| } else if (STRING_STARTS_WITH(format, "jimm")) { |
| Printf("%+" Pd, static_cast<intptr_t>(instr.j_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "bimm")) { |
| Printf("%+" Pd, static_cast<intptr_t>(instr.b_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "iimm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.i_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "uimm")) { |
| // objdump instead displays (imm >> 12) as hex. |
| Printf("%" Pd, static_cast<intptr_t>(instr.u_imm())); |
| return format + 4; |
| } else if (STRING_STARTS_WITH(format, "i16imm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.i16_imm())); |
| return format + 6; |
| } else if (STRING_STARTS_WITH(format, "i4spnimm")) { |
| Printf("%" Pd, static_cast<intptr_t>(instr.i4spn_imm())); |
| return format + 8; |
| } |
| |
| FATAL1("Bad format %s\n", format); |
| return nullptr; |
| } |
| |
| void Disassembler::DecodeInstruction(char* hex_buffer, |
| intptr_t hex_size, |
| char* human_buffer, |
| intptr_t human_size, |
| int* out_instr_size, |
| const Code& code, |
| Object** object, |
| uword pc) { |
| RISCVDisassembler decoder(human_buffer, human_size, |
| FLAG_use_compressed_instructions ? RV_GC : RV_G); |
| int instr_size = decoder.Disassemble(pc); |
| if (instr_size == 2) { |
| Utils::SNPrint(hex_buffer, hex_size, " %04x", |
| *reinterpret_cast<uint16_t*>(pc)); |
| } else if (instr_size == 4) { |
| Utils::SNPrint(hex_buffer, hex_size, "%08x", |
| *reinterpret_cast<uint32_t*>(pc)); |
| } |
| if (out_instr_size) { |
| *out_instr_size = instr_size; |
| } |
| |
| *object = NULL; |
| if (!code.IsNull()) { |
| *object = &Object::Handle(); |
| if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { |
| *object = NULL; |
| } |
| } |
| } |
| |
| #endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) |
| |
| } // namespace dart |
| |
| #endif // defined(TARGET_ARCH_RISCV) |