summaryrefslogtreecommitdiff
path: root/disassembler/disassembler_riscv64.cc
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2023-08-11 13:11:26 +0000
committer VladimĂ­r Marko <vmarko@google.com> 2023-08-16 09:06:26 +0000
commit6e5e068a66f62439fac31243b2b4ef2268e5a99f (patch)
tree9ebb7d1d639b8f30b5e97dfc6d0af5d836f8509d /disassembler/disassembler_riscv64.cc
parent4a05ac01506780dfe4435c40016501041c38b6b9 (diff)
riscv64: Disassemble "Zicsr" extension...
... as well as ECALL, EBREAK, UNIMP and fences. This brings the disassembler support for the remaining instructions and macros currently supported by the ART riscv64 assembler. Test: m dump-oat Bug: 283082089 Change-Id: Ibb5d8e95bbc8e6fe1069252b6854b8a71c396420
Diffstat (limited to 'disassembler/disassembler_riscv64.cc')
-rw-r--r--disassembler/disassembler_riscv64.cc92
1 files changed, 90 insertions, 2 deletions
diff --git a/disassembler/disassembler_riscv64.cc b/disassembler/disassembler_riscv64.cc
index 58a23ef96d..18ca5bece3 100644
--- a/disassembler/disassembler_riscv64.cc
+++ b/disassembler/disassembler_riscv64.cc
@@ -88,6 +88,8 @@ class DisassemblerRiscv64::Printer {
void Print32Atomic(uint32_t insn32);
void Print32FpOp(uint32_t insn32);
void Print32FpFma(uint32_t insn32);
+ void Print32Zicsr(uint32_t insn32);
+ void Print32Fence(uint32_t insn32);
DisassemblerRiscv64* const disassembler_;
std::ostream& os_;
@@ -507,7 +509,7 @@ void DisassemblerRiscv64::Printer::Print32FpOp(uint32_t insn32) {
uint32_t funct7 = insn32 >> 25;
const char* type = ((funct7 & 1u) != 0u) ? ".d" : ".s";
if ((funct7 & 2u) != 0u) {
- os_ << "<unknown32>"; // Note: This includes the "Q" extension (`(funct7 & 3) == 3`).
+ os_ << "<unknown32>"; // Note: This includes the "H" and "Q" extensions.
return;
}
switch (funct7 >> 2) {
@@ -612,7 +614,7 @@ void DisassemblerRiscv64::Printer::Print32FpFma(uint32_t insn32) {
DCHECK_EQ(insn32 & 0x73u, 0x43u); // Note: Bits 0xc select the FMA opcode.
uint32_t funct2 = (insn32 >> 25) & 3u;
if (funct2 >= 2u) {
- os_ << "<unknown32>"; // Note: This includes the "Q" extension (`funct2 == 3`).
+ os_ << "<unknown32>"; // Note: This includes the "H" and "Q" extensions.
return;
}
static const char* const kOpcodes[] = { "fmadd", "fmsub", "fnmsub", "fnmadd" };
@@ -622,6 +624,82 @@ void DisassemblerRiscv64::Printer::Print32FpFma(uint32_t insn32) {
<< FRegName(GetRs2(insn32)) << ", " << FRegName(GetRs3(insn32));
}
+void DisassemblerRiscv64::Printer::Print32Zicsr(uint32_t insn32) {
+ DCHECK_EQ(insn32 & 0x7fu, 0x73u);
+ uint32_t funct3 = (insn32 >> 12) & 7u;
+ static const char* const kOpcodes[] = {
+ nullptr, "csrrw", "csrrs", "csrrc", nullptr, "csrrwi", "csrrsi", "csrrci"
+ };
+ const char* opcode = kOpcodes[funct3];
+ if (opcode == nullptr) {
+ os_ << "<unknown32>";
+ return;
+ }
+ uint32_t rd = GetRd(insn32);
+ uint32_t rs1_or_uimm = GetRs1(insn32);
+ uint32_t csr = insn32 >> 20;
+ // Print shorter macro instruction notation if available.
+ if (funct3 == /*CSRRW*/ 1u && rd == 0u && rs1_or_uimm == 0u && csr == 0xc00u) {
+ os_ << "unimp";
+ return;
+ } else if (funct3 == /*CSRRS*/ 2u && rs1_or_uimm == 0u) {
+ if (csr == 0xc00u) {
+ os_ << "rdcycle " << XRegName(rd);
+ } else if (csr == 0xc01u) {
+ os_ << "rdtime " << XRegName(rd);
+ } else if (csr == 0xc02u) {
+ os_ << "rdinstret " << XRegName(rd);
+ } else {
+ os_ << "csrr " << XRegName(rd) << ", " << csr;
+ }
+ return;
+ }
+
+ if (rd == 0u) {
+ static const char* const kAltOpcodes[] = {
+ nullptr, "csrw", "csrs", "csrc", nullptr, "csrwi", "csrsi", "csrci"
+ };
+ DCHECK(kAltOpcodes[funct3] != nullptr);
+ os_ << kAltOpcodes[funct3] << " " << csr << ", ";
+ } else {
+ os_ << opcode << " " << XRegName(rd) << ", " << csr << ", ";
+ }
+ if (funct3 >= /*CSRRWI/CSRRSI/CSRRCI*/ 4u) {
+ os_ << rs1_or_uimm;
+ } else {
+ os_ << XRegName(rs1_or_uimm);
+ }
+}
+
+void DisassemblerRiscv64::Printer::Print32Fence(uint32_t insn32) {
+ DCHECK_EQ(insn32 & 0x7fu, 0x0fu);
+ if ((insn32 & 0xf00fffffu) == 0x0000000fu) {
+ auto print_flags = [&](uint32_t flags) {
+ if (flags == 0u) {
+ os_ << "0";
+ } else {
+ DCHECK_LT(flags, 0x10u);
+ static const char kFlagNames[] = "wroi";
+ for (size_t bit : { 3u, 2u, 1u, 0u }) { // Print in the "iorw" order.
+ if ((flags & (1u << bit)) != 0u) {
+ os_ << kFlagNames[bit];
+ }
+ }
+ }
+ };
+ os_ << "fence.";
+ print_flags((insn32 >> 24) & 0xfu);
+ os_ << ".";
+ print_flags((insn32 >> 20) & 0xfu);
+ } else if (insn32 == 0x8330000fu) {
+ os_ << "fence.tso";
+ } else if (insn32 == 0x0000100fu) {
+ os_ << "fence.i";
+ } else {
+ os_ << "<unknown32>";
+ }
+}
+
void DisassemblerRiscv64::Printer::Dump32(const uint8_t* insn) {
uint32_t insn32 = static_cast<uint32_t>(insn[0]) +
(static_cast<uint32_t>(insn[1]) << 8) +
@@ -684,6 +762,16 @@ void DisassemblerRiscv64::Printer::Dump32(const uint8_t* insn) {
case 0x4fu:
Print32FpFma(insn32);
break;
+ case 0x73u:
+ if ((insn32 & 0xffefffffu) == 0x00000073u) {
+ os_ << ((insn32 == 0x00000073u) ? "ecall" : "ebreak");
+ } else {
+ Print32Zicsr(insn32);
+ }
+ break;
+ case 0x0fu:
+ Print32Fence(insn32);
+ break;
default:
// TODO(riscv64): Disassemble more instructions.
os_ << "<unknown32>";