From 7e3bd09a14f452fcef805092bc744ca0d16ad813 Mon Sep 17 00:00:00 2001 From: trdthg Date: Thu, 25 Apr 2024 09:15:23 +0000 Subject: [PATCH 1/2] fix inst_base split --- src/machine/CMakeLists.txt | 9 +- src/machine/instruction.test.cpp | 37 +++++- src/machine/instruction.test.data.h | 162 +++++++++++++++++++++++ src/machine/instruction.test.gendata.cpp | 138 +++++++++++++++++++ src/machine/instruction.test.h | 4 +- 5 files changed, 341 insertions(+), 9 deletions(-) create mode 100644 src/machine/instruction.test.data.h create mode 100644 src/machine/instruction.test.gendata.cpp diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 3f226d32..38e2bc44 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -147,6 +147,13 @@ if(NOT ${WASM}) PRIVATE ${QtLib}::Core ${QtLib}::Test) add_test(NAME cache COMMAND cache_test) + add_executable(instruction_test_gendata + instruction.test.gendata.cpp + ) + target_link_libraries(instruction_test_gendata + PRIVATE machine ${QtLib}::Core + ) + add_executable(instruction_test csr/controlstate.cpp csr/controlstate.h @@ -216,5 +223,5 @@ if(NOT ${WASM}) add_test(NAME core COMMAND core_test) add_custom_target(machine_unit_tests - DEPENDS alu_test registers_test memory_test cache_test instruction_test program_loader_test core_test) + DEPENDS alu_test registers_test memory_test cache_test instruction_test_gendata instruction_test program_loader_test core_test) endif() diff --git a/src/machine/instruction.test.cpp b/src/machine/instruction.test.cpp index 11b2922e..0873798b 100644 --- a/src/machine/instruction.test.cpp +++ b/src/machine/instruction.test.cpp @@ -7,9 +7,6 @@ using namespace machine; // Test that we are correctly encoding instructions in constructor void TestInstruction::instruction() { QCOMPARE(Instruction(0x0), Instruction()); - // QCOMPARE(Instruction(0x4432146), Instruction(1, 2, 3, 4, 5, 6)); - // QCOMPARE(Instruction(0x4430004), Instruction(1, 2, 3, 4)); - // QCOMPARE(Instruction(0x4000002), Instruction(1, 2_addr)); } // Test that we are correctly decoding instruction fields @@ -17,16 +14,42 @@ void TestInstruction::instruction_access() { Instruction i(0xffffffff); QCOMPARE(i.data(), (uint32_t)0xffffffff); - QCOMPARE(i.opcode(), (uint8_t)0x3f); + QCOMPARE(i.opcode(), (uint8_t)0x7f); QCOMPARE(i.rs(), (uint8_t)0x1f); QCOMPARE(i.rt(), (uint8_t)0x1f); QCOMPARE(i.rd(), (uint8_t)0x1f); QCOMPARE(i.shamt(), (uint8_t)0x1f); - QCOMPARE(i.funct(), (uint16_t)0x3f); - QCOMPARE(i.immediate(), (int32_t)0xffff); + QCOMPARE(i.funct(), (uint16_t)0x3ff); + QCOMPARE(i.immediate(), (int32_t)0); QCOMPARE(i.address().get_raw(), (uint64_t)0x3ffffff); } -// TODO test to_str +static struct { uint32_t code; QString str; } code_to_string[] = { + {0xffffffff, "unknown"}, + {0x0, "unknown"}, + {0b00000000000000000000000000010011, "nop"}, + {0b00000000000000001000000010010011, "addi x1, x1, 0"}, + {0b01111111111111111000111110010011, "addi x31, x31, 2047"}, + {0b11111111111100001000000010010011, "addi x1, x1, -1"}, + {0b10000000000000001000000010010011, "addi x1, x1, -2048"}, + #include<./instruction.test.data.h> +}; + +void TestInstruction::instruction_to_str() { + size_t array_length = sizeof(code_to_string) / sizeof(code_to_string[0]); + for (size_t i = 0; i < array_length; ++i) { + QCOMPARE(Instruction(code_to_string[i].code).to_str(), code_to_string[i].str); + } +} + +void TestInstruction::instruction_code_from_str() { + size_t array_length = sizeof(code_to_string) / sizeof(code_to_string[0]); + for (size_t i = 0; i < array_length; ++i) { + if (code_to_string[i].str == "unknown") { continue; } + uint32_t code = 0; + Instruction::code_from_string(&code, code_to_string[i].str.length(), code_to_string[i].str, machine::Address(0x0)); + QCOMPARE(code, code_to_string[i].code); + } +} QTEST_APPLESS_MAIN(TestInstruction) diff --git a/src/machine/instruction.test.data.h b/src/machine/instruction.test.data.h new file mode 100644 index 00000000..25387a58 --- /dev/null +++ b/src/machine/instruction.test.data.h @@ -0,0 +1,162 @@ +{0x108083, "lb x1, 1(x1)"}, +{0x109083, "lh x1, 1(x1)"}, +{0x10a083, "lw x1, 1(x1)"}, +{0x10b083, "ld x1, 1(x1)"}, +{0x10c083, "lbu x1, 1(x1)"}, +{0x10d083, "lhu x1, 1(x1)"}, +{0x10e083, "lwu x1, 1(x1)"}, +{0xf, "fence"}, +{0x100f, "fence.i"}, +{0x108093, "addi x1, x1, 1"}, +{0x109093, "slli x1, x1, 0x1"}, +{0x10a093, "slti x1, x1, 1"}, +{0x10b093, "sltiu x1, x1, 1"}, +{0x10c093, "xori x1, x1, 1"}, +{0x10d093, "srli x1, x1, 0x1"}, +{0x4010d093, "srai x1, x1, 0x1"}, +{0x10e093, "ori x1, x1, 1"}, +{0x10f093, "andi x1, x1, 1"}, +{0x1097, "auipc x1, 0x1"}, +{0x10809b, "addiw x1, x1, 1"}, +{0x10909b, "slliw x1, x1, 0x1"}, +{0x10d09b, "srliw x1, x1, 0x1"}, +{0x4010d09b, "sraiw x1, x1, 0x1"}, +{0x1080a3, "sb x1, 1(x1)"}, +{0x1090a3, "sh x1, 1(x1)"}, +{0x10a0a3, "sw x1, 1(x1)"}, +{0x10b0a3, "sd x1, 1(x1)"}, +{0x10a0af, "amoadd.w x1, x1, (x1)"}, +{0x210a0af, "amoadd.w.rl x1, x1, (x1)"}, +{0x410a0af, "amoadd.w.aq x1, x1, (x1)"}, +{0x610a0af, "amoadd.w.aqrl x1, x1, (x1)"}, +{0x810a0af, "amoswap.w x1, x1, (x1)"}, +{0xa10a0af, "amoswap.w.rl x1, x1, (x1)"}, +{0xc10a0af, "amoswap.w.aq x1, x1, (x1)"}, +{0xe10a0af, "amoswap.w.aqrl x1, x1, (x1)"}, +{0x1000a0af, "lr.w x1, (x1)"}, +{0x1200a0af, "lr.w.rl x1, (x1)"}, +{0x1400a0af, "lr.w.aq x1, (x1)"}, +{0x1600a0af, "lr.w.aqrl x1, (x1)"}, +{0x1810a0af, "sc.w x1, x1, (x1)"}, +{0x1a10a0af, "sc.w.rl x1, x1, (x1)"}, +{0x1c10a0af, "sc.w.aq x1, x1, (x1)"}, +{0x1e10a0af, "sc.w.aqrl x1, x1, (x1)"}, +{0x2010a0af, "amoxor.w x1, x1, (x1)"}, +{0x2210a0af, "amoxor.w.rl x1, x1, (x1)"}, +{0x2410a0af, "amoxor.w.aq x1, x1, (x1)"}, +{0x2610a0af, "amoxor.w.aqrl x1, x1, (x1)"}, +{0x4010a0af, "amoor.w x1, x1, (x1)"}, +{0x4210a0af, "amoor.w.rl x1, x1, (x1)"}, +{0x4410a0af, "amoor.w.aq x1, x1, (x1)"}, +{0x4610a0af, "amoor.w.aqrl x1, x1, (x1)"}, +{0x6010a0af, "amoand.w x1, x1, (x1)"}, +{0x6210a0af, "amoand.w.rl x1, x1, (x1)"}, +{0x6410a0af, "amoand.w.aq x1, x1, (x1)"}, +{0x6610a0af, "amoand.w.aqrl x1, x1, (x1)"}, +{0x8010a0af, "amomin.w x1, x1, (x1)"}, +{0x8210a0af, "amomin.w.rl x1, x1, (x1)"}, +{0x8410a0af, "amomin.w.aq x1, x1, (x1)"}, +{0x8610a0af, "amomin.w.aqrl x1, x1, (x1)"}, +{0xa010a0af, "amomax.w x1, x1, (x1)"}, +{0xa210a0af, "amomax.w.rl x1, x1, (x1)"}, +{0xa410a0af, "amomax.w.aq x1, x1, (x1)"}, +{0xa610a0af, "amomax.w.aqrl x1, x1, (x1)"}, +{0xc010a0af, "amominu.w x1, x1, (x1)"}, +{0xc210a0af, "amominu.w.rl x1, x1, (x1)"}, +{0xc410a0af, "amominu.w.aq x1, x1, (x1)"}, +{0xc610a0af, "amominu.w.aqrl x1, x1, (x1)"}, +{0xe010a0af, "amomaxu.w x1, x1, (x1)"}, +{0xe210a0af, "amomaxu.w.rl x1, x1, (x1)"}, +{0xe410a0af, "amomaxu.w.aq x1, x1, (x1)"}, +{0xe610a0af, "amomaxu.w.aqrl x1, x1, (x1)"}, +{0x10b0af, "amoadd.d x1, x1, (x1)"}, +{0x210b0af, "amoadd.d.rl x1, x1, (x1)"}, +{0x410b0af, "amoadd.d.aq x1, x1, (x1)"}, +{0x610b0af, "amoadd.d.aqrl x1, x1, (x1)"}, +{0x810b0af, "amoswap.d x1, x1, (x1)"}, +{0xa10b0af, "amoswap.d.rl x1, x1, (x1)"}, +{0xc10b0af, "amoswap.d.aq x1, x1, (x1)"}, +{0xe10b0af, "amoswap.d.aqrl x1, x1, (x1)"}, +{0x1000b0af, "lr.d x1, (x1)"}, +{0x1200b0af, "lr.d.rl x1, (x1)"}, +{0x1400b0af, "lr.d.aq x1, (x1)"}, +{0x1600b0af, "lr.d.aqrl x1, (x1)"}, +{0x1810b0af, "sc.d x1, x1, (x1)"}, +{0x1a10b0af, "sc.d.rl x1, x1, (x1)"}, +{0x1c10b0af, "sc.d.aq x1, x1, (x1)"}, +{0x1e10b0af, "sc.d.aqrl x1, x1, (x1)"}, +{0x2010b0af, "amoxor.d x1, x1, (x1)"}, +{0x2210b0af, "amoxor.d.rl x1, x1, (x1)"}, +{0x2410b0af, "amoxor.d.aq x1, x1, (x1)"}, +{0x2610b0af, "amoxor.d.aqrl x1, x1, (x1)"}, +{0x4010b0af, "amoor.d x1, x1, (x1)"}, +{0x4210b0af, "amoor.d.rl x1, x1, (x1)"}, +{0x4410b0af, "amoor.d.aq x1, x1, (x1)"}, +{0x4610b0af, "amoor.d.aqrl x1, x1, (x1)"}, +{0x6010b0af, "amoand.d x1, x1, (x1)"}, +{0x6210b0af, "amoand.d.rl x1, x1, (x1)"}, +{0x6410b0af, "amoand.d.aq x1, x1, (x1)"}, +{0x6610b0af, "amoand.d.aqrl x1, x1, (x1)"}, +{0x8010b0af, "amomin.d x1, x1, (x1)"}, +{0x8210b0af, "amomin.d.rl x1, x1, (x1)"}, +{0x8410b0af, "amomin.d.aq x1, x1, (x1)"}, +{0x8610b0af, "amomin.d.aqrl x1, x1, (x1)"}, +{0xa010b0af, "amomax.d x1, x1, (x1)"}, +{0xa210b0af, "amomax.d.rl x1, x1, (x1)"}, +{0xa410b0af, "amomax.d.aq x1, x1, (x1)"}, +{0xa610b0af, "amomax.d.aqrl x1, x1, (x1)"}, +{0xc010b0af, "amominu.d x1, x1, (x1)"}, +{0xc210b0af, "amominu.d.rl x1, x1, (x1)"}, +{0xc410b0af, "amominu.d.aq x1, x1, (x1)"}, +{0xc610b0af, "amominu.d.aqrl x1, x1, (x1)"}, +{0xe010b0af, "amomaxu.d x1, x1, (x1)"}, +{0xe210b0af, "amomaxu.d.rl x1, x1, (x1)"}, +{0xe410b0af, "amomaxu.d.aq x1, x1, (x1)"}, +{0xe610b0af, "amomaxu.d.aqrl x1, x1, (x1)"}, +{0x1080b3, "add x1, x1, x1"}, +{0x401080b3, "sub x1, x1, x1"}, +{0x1090b3, "sll x1, x1, x1"}, +{0x10a0b3, "slt x1, x1, x1"}, +{0x10b0b3, "sltu x1, x1, x1"}, +{0x10c0b3, "xor x1, x1, x1"}, +{0x10d0b3, "srl x1, x1, x1"}, +{0x4010d0b3, "sra x1, x1, x1"}, +{0x10e0b3, "or x1, x1, x1"}, +{0x10f0b3, "and x1, x1, x1"}, +{0x21080b3, "mul x1, x1, x1"}, +{0x21090b3, "mulh x1, x1, x1"}, +{0x210a0b3, "mulhsu x1, x1, x1"}, +{0x210b0b3, "mulhu x1, x1, x1"}, +{0x210c0b3, "div x1, x1, x1"}, +{0x210d0b3, "divu x1, x1, x1"}, +{0x210e0b3, "rem x1, x1, x1"}, +{0x210f0b3, "remu x1, x1, x1"}, +{0x10b7, "lui x1, 0x1"}, +{0x1080bb, "addw x1, x1, x1"}, +{0x401080bb, "subw x1, x1, x1"}, +{0x1090bb, "sllw x1, x1, x1"}, +{0x10d0bb, "srlw x1, x1, x1"}, +{0x4010d0bb, "sraw x1, x1, x1"}, +{0x21080bb, "mulw x1, x1, x1"}, +{0x210c0bb, "divw x1, x1, x1"}, +{0x210d0bb, "divuw x1, x1, x1"}, +{0x210e0bb, "remw x1, x1, x1"}, +{0x210f0bb, "remuw x1, x1, x1"}, +{0x108163, "beq x1, x1, 0x2"}, +{0x109163, "bne x1, x1, 0x2"}, +{0x10c163, "blt x1, x1, 0x2"}, +{0x10d163, "bge x1, x1, 0x2"}, +{0x10e163, "bltu x1, x1, 0x2"}, +{0x10f163, "bgeu x1, x1, 0x2"}, +{0x1080e7, "jalr x1, 1(x1)"}, +{0x2000ef, "jal x1, 0x2"}, +{0x73, "ecall"}, +{0x100073, "ebreak"}, +{0x10200073, "sret"}, +{0x30200073, "mret"}, +{0x1090f3, "csrrw x1, 0x1, x1"}, +{0x10a0f3, "csrrs x1, 0x1, x1"}, +{0x10b0f3, "csrrc x1, 0x1, x1"}, +{0x10d0f3, "csrrwi x1, 0x1, 0x1"}, +{0x10e0f3, "csrrsi x1, 0x1, 0x1"}, +{0x10f0f3, "csrrci x1, 0x1, 0x1"}, diff --git a/src/machine/instruction.test.gendata.cpp b/src/machine/instruction.test.gendata.cpp new file mode 100644 index 00000000..46654cf2 --- /dev/null +++ b/src/machine/instruction.test.gendata.cpp @@ -0,0 +1,138 @@ +#include "common/logging.h" +#include "machine/instruction.h" +#include "machine/instruction.cpp" +#include +#include + +using namespace machine; + +static uint32_t MASK_AMO_RS2 = 0b1111100000000000000000000; + +#define AMO_MAP_4ITEMS(NAME_BASE, MASK) \ + { NAME_BASE, MASK}, \ + { NAME_BASE ".rl", MASK }, \ + { NAME_BASE ".aq", MASK }, \ + { NAME_BASE ".aqrl", MASK }, + +static std::unordered_map mask_map = { + AMO_MAP_4ITEMS("lr.w", MASK_AMO_RS2) + AMO_MAP_4ITEMS("lr.d", MASK_AMO_RS2) +}; + +void generate_code_and_string_data(QTextStream& out, const InstructionMap* im_iter, BitField subfield) { + for (int i = 0; i < (1 << subfield.count); i++) { + const InstructionMap* im = &im_iter[i]; + + if (im->name == "unknown") { + continue; + } + + if (im->subclass != nullptr) { + generate_code_and_string_data(out, im->subclass, im->subfield); + continue; + } + + uint32_t code = im->code; + QString string_data = im->name; + + if (im->args.size()) { + int val_mask; + switch (im->type) { + case Instruction::Type::R: + case Instruction::Type::AMO: { + val_mask = 0b00000000000100001000000010000000; + break; + } + case Instruction::Type::I: + val_mask = 0b00000000000100001000000010000000; + break; + case Instruction::Type::ZICSR: { + val_mask = 0b00000000000100001000000010000000; + break; + } + case Instruction::Type::S: { + val_mask = 0b00000000000100001000000010000000; + break; + } + case Instruction::Type::B: { + val_mask = 0b00000000000100001000000100000000; + break; + } + case Instruction::Type::U: { + val_mask = 0b00000000000000000001000010000000; + break; + } + case Instruction::Type::J: { + val_mask = 0b00000000001000000000000010000000; + break; + } + case Instruction::Type::UNKNOWN: { + return; + } + } + code |= val_mask & ~im->mask; + if (mask_map.count(im->name)) { + uint32_t old_code = code; + code &= ~mask_map[im->name]; + } + + QString next_delim = " "; + for (const QString &arg_string : im->args) { + string_data += next_delim; + next_delim = ", "; + for (int pos = 0; pos < arg_string.size(); pos += 1) { + char arg_letter = arg_string[pos].toLatin1(); + const ArgumentDesc *arg_desc = arg_desc_by_code[(unsigned char)arg_letter]; + if (arg_desc == nullptr) { + string_data += arg_letter; + continue; + } + switch (arg_desc->kind) { + case 'g': { + string_data += "x1"; + break; + } + case 'p': + case 'a': + string_data += QString::asprintf("0x%d", Instruction(code).immediate()); + break; + case 'o': + case 'n': { + if (arg_desc->min < 0) { + string_data += "1"; + } else { + string_data += "0x1"; + } + break; + } + case 'E': { + string_data += "0x1"; + break; + } + } + } + } + } + + QString enum_str = QString::asprintf("{0x%x, \"%s\"},", code, qPrintable(string_data)); + if (Instruction(code).to_str() != string_data) { + enum_str += " // failed"; + } + enum_str += "\n"; + out << enum_str; + } +} + +int main(int argc, char *argv[]) { + fill_argdesbycode(); + instruction_from_string_build_base(); + QFile outfile("instruction.test.data.h"); + if (outfile.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&outfile); + generate_code_and_string_data(out, C_inst_map, instruction_map_opcode_field); + outfile.close(); + } else { + printf("open output file failed\n"); + exit(1); + } +} \ No newline at end of file diff --git a/src/machine/instruction.test.h b/src/machine/instruction.test.h index c5030555..49184709 100644 --- a/src/machine/instruction.test.h +++ b/src/machine/instruction.test.h @@ -6,9 +6,11 @@ class TestInstruction : public QObject { Q_OBJECT -public slots: +private slots: void instruction(); void instruction_access(); + void instruction_to_str(); + void instruction_code_from_str(); }; #endif // INSTRUCTION_TEST_H From 2777e7630947ff326863c8d0cd261479952e2cd5 Mon Sep 17 00:00:00 2001 From: trdthg Date: Wed, 26 Jun 2024 02:13:20 +0000 Subject: [PATCH 2/2] refactor --- src/machine/csr/controlstate.h | 6 +- src/machine/instruction.cpp | 108 ++++++----- src/machine/instruction.h | 5 +- src/machine/instruction.test.cpp | 72 +++++-- src/machine/instruction.test.data.def | 192 ++++++++++++++++++ src/machine/instruction.test.data.h | 162 ---------------- src/machine/instruction.test.gendata.cpp | 237 ++++++++++++----------- src/machine/instruction.test.gendata.h | 92 +++++++++ 8 files changed, 524 insertions(+), 350 deletions(-) create mode 100644 src/machine/instruction.test.data.def delete mode 100644 src/machine/instruction.test.data.h create mode 100644 src/machine/instruction.test.gendata.h diff --git a/src/machine/csr/controlstate.h b/src/machine/csr/controlstate.h index 7f5cde29..90918fd9 100644 --- a/src/machine/csr/controlstate.h +++ b/src/machine/csr/controlstate.h @@ -255,16 +255,16 @@ namespace machine { namespace CSR { class RegisterMapByName { bool initialized = false; - std::unordered_map map; + std::unordered_map map; void init() { for (size_t i = 0; i < REGISTERS.size(); i++) { - map.emplace(REGISTERS[i].name, i); + map.emplace(std::string(REGISTERS[i].name), i); } initialized = true; } public: - size_t at(const char* name) { + size_t at(std::string name) { if (!initialized) init(); return map.at(name); } diff --git a/src/machine/instruction.cpp b/src/machine/instruction.cpp index c132096a..a83c7063 100644 --- a/src/machine/instruction.cpp +++ b/src/machine/instruction.cpp @@ -765,6 +765,55 @@ Instruction &Instruction::operator=(const Instruction &c) { return *this; } +QString field_to_string(int32_t field, const ArgumentDesc* arg_desc, Address inst_addr, bool symbolic_registers_enabled) { + QString res = ""; + if (arg_desc->min < 0) { + field = extend(field, [&]() { + int sum = (int)arg_desc->arg.shift; + for (auto chunk : arg_desc->arg) { + sum += chunk.count; + } + return sum; + }()); + } + switch (arg_desc->kind) { + case 'g': { + if (symbolic_registers_enabled) { + res += QString(Rv_regnames[field]); + } else { + res += "x" + QString::number(field); + } + break; + } + case 'p': + case 'a': { + field += (int32_t)inst_addr.get_raw(); + res.append(str::asHex(field)); + break; + } + case 'o': + case 'n': { + if (arg_desc->min < 0) { + res += QString::number((int32_t)field, 10); + } else { + res.append(str::asHex(uint32_t(field))); + } + break; + } + case 'E': { + if (symbolic_registers_enabled) { + try { + res += CSR::REGISTERS[CSR::REGISTER_MAP.at(CSR::Address(field))].name; + } catch (std::out_of_range &e) { res.append(str::asHex(field)); } + } else { + res.append(str::asHex(field)); + } + break; + } + } + return res; +} + QString Instruction::to_str(Address inst_addr) const { const InstructionMap &im = InstructionMapFind(dt); // TODO there are exception where some fields are zero and such so we should @@ -787,50 +836,7 @@ QString Instruction::to_str(Address inst_addr) const { continue; } auto field = (int32_t)arg_desc->arg.decode(this->dt); - if (arg_desc->min < 0) { - field = extend(field, [&]() { - int sum = (int)arg_desc->arg.shift; - for (auto chunk : arg_desc->arg) { - sum += chunk.count; - } - return sum; - }()); - } - switch (arg_desc->kind) { - case 'g': { - if (symbolic_registers_enabled) { - res += QString(Rv_regnames[field]); - } else { - res += "x" + QString::number(field); - } - break; - } - case 'p': - case 'a': { - field += (int32_t)inst_addr.get_raw(); - res.append(str::asHex(uint32_t(field))); - break; - } - case 'o': - case 'n': { - if (arg_desc->min < 0) { - res += QString::number((int32_t)field, 10); - } else { - res.append(str::asHex(uint32_t(field))); - } - break; - } - case 'E': { - if (symbolic_registers_enabled) { - try { - res += CSR::REGISTERS[CSR::REGISTER_MAP.at(CSR::Address(field))].name; - } catch (std::out_of_range &e) { res.append(str::asHex(field)); } - } else { - res.append(str::asHex(field)); - } - break; - } - } + res += field_to_string(field, arg_desc, inst_addr, symbolic_registers_enabled); } } return res; @@ -1375,14 +1381,15 @@ bool parse_immediate_value( uint16_t parse_csr_address(const QString &field_token, uint &chars_taken) { if (field_token.at(0).isLetter()) { - size_t index = CSR::REGISTER_MAP_BY_NAME.at(qPrintable(field_token)); - if (index < 0) { + try { + size_t index = CSR::REGISTER_MAP_BY_NAME.at(field_token.toStdString()); + auto ® = CSR::REGISTERS[index]; + chars_taken = strlen(reg.name); + return reg.address.data; + } catch (std::out_of_range &e) { chars_taken = 0; return 0; } - auto ® = CSR::REGISTERS[index]; - chars_taken = strlen(reg.name); - return reg.address.data; } else { char *r; uint64_t val; @@ -1449,9 +1456,6 @@ void Instruction::set_symbolic_registers(bool enable) { symbolic_registers_enabled = enable; } -inline int32_t Instruction::extend(uint32_t value, uint32_t used_bits) const { - return value | ~((value & (1 << (used_bits - 1))) - 1); -} void Instruction::append_recognized_registers(QStringList &list) { for (auto name : Rv_regnames) { diff --git a/src/machine/instruction.h b/src/machine/instruction.h index 3719d877..cc38d963 100644 --- a/src/machine/instruction.h +++ b/src/machine/instruction.h @@ -90,6 +90,10 @@ struct TokenizedInstruction { struct RelocExpression; typedef QVector RelocExpressionList; +inline int32_t extend(uint32_t value, uint32_t used_bits) { + return value | ~((value & (1 << (used_bits - 1))) - 1); +} + class Instruction { public: Instruction(); @@ -208,7 +212,6 @@ class Instruction { RelocExpressionList *reloc, Modifier pseudo_mod = Modifier::NONE, uint64_t initial_immediate_value = 0); - inline int32_t extend(uint32_t value, uint32_t used_bits) const; static uint32_t parse_field( QString &field_token, const QString &arg, diff --git a/src/machine/instruction.test.cpp b/src/machine/instruction.test.cpp index 0873798b..560a6fca 100644 --- a/src/machine/instruction.test.cpp +++ b/src/machine/instruction.test.cpp @@ -24,31 +24,73 @@ void TestInstruction::instruction_access() { QCOMPARE(i.address().get_raw(), (uint64_t)0x3ffffff); } -static struct { uint32_t code; QString str; } code_to_string[] = { - {0xffffffff, "unknown"}, - {0x0, "unknown"}, - {0b00000000000000000000000000010011, "nop"}, - {0b00000000000000001000000010010011, "addi x1, x1, 0"}, - {0b01111111111111111000111110010011, "addi x31, x31, 2047"}, - {0b11111111111100001000000010010011, "addi x1, x1, -1"}, - {0b10000000000000001000000010010011, "addi x1, x1, -2048"}, - #include<./instruction.test.data.h> +static const struct { + uint32_t code; + QString str; + QString alias_str = nullptr; +} code_to_string[] = { + { 0xffffffff, "unknown" }, + { 0x0, "unknown" }, + { 0b00000000000000000000000000010011, "nop" }, + { 0b00000000000000001000000010010011, "addi x1, x1, 0" }, + { 0b01111111111111111000111110010011, "addi x31, x31, 2047" }, + { 0b11111111111100001000000010010011, "addi x1, x1, -1" }, + { 0b10000000000000001000000010010011, "addi x1, x1, -2048" }, +#include <./instruction.test.data.def> +}; + +struct Pair { + uint32_t code; + QString str; +}; +static const struct { + QString string_data; + std::vector pairs; +} pesude_code_to_string[] = { + { "nop", { { 0b00000000000000000000000000010011, "nop" } } }, + { "la x1, 0xffffefff", + { { 0xfffff097, "auipc x1, 0xfffff" }, { 0xfff08093, "addi x1, x1, -1" } } }, + { "li x1, 0xffffefff", + { { 0xfffff0b7, "lui x1, 0xfffff" }, { 0xfff08093, "addi x1, x1, -1" } } }, + { "call 0xfffeffff", + { { 0xffff0317, "auipc x6, 0xffff0" }, { 0xfff300e7, "jalr x1, -1(x6)" } } }, + { "tail 0xfffeffff", + { { 0xffff0317, "auipc x6, 0xffff0" }, { 0xfff30067, "jalr x0, -1(x6)" } } }, + { "sext.b x1, x2", { { 0x11093, "slli x1, x2, 0x0" }, { 0x4000d093, "srai x1, x1, 0x0" } } }, + { "sext.h x1, x2", { { 0x11093, "slli x1, x2, 0x0" }, { 0x4000d093, "srai x1, x1, 0x0" } } }, + { "zext.h x1, x2", { { 0x11093, "slli x1, x2, 0x0" }, { 0xd093, "srli x1, x1, 0x0" } } }, + { "zext.w x1, x2", { { 0x11093, "slli x1, x2, 0x0" }, { 0xd093, "srli x1, x1, 0x0" } } }, }; void TestInstruction::instruction_to_str() { - size_t array_length = sizeof(code_to_string) / sizeof(code_to_string[0]); - for (size_t i = 0; i < array_length; ++i) { + for (size_t i = 0; i < sizeof(code_to_string) / sizeof(code_to_string[0]); i++) { QCOMPARE(Instruction(code_to_string[i].code).to_str(), code_to_string[i].str); } + + for (size_t i = 0; i < sizeof(pesude_code_to_string) / sizeof(pesude_code_to_string[0]); i++) { + for (size_t j = 0; j < pesude_code_to_string[i].pairs.size(); j++) { + Pair pair = pesude_code_to_string[i].pairs[j]; + QCOMPARE(Instruction(pair.code).to_str(), pair.str); + } + } } void TestInstruction::instruction_code_from_str() { - size_t array_length = sizeof(code_to_string) / sizeof(code_to_string[0]); - for (size_t i = 0; i < array_length; ++i) { + for (size_t i = 0; i < sizeof(code_to_string) / sizeof(code_to_string[0]); i++) { if (code_to_string[i].str == "unknown") { continue; } + QString test_string_data = code_to_string[i].alias_str == nullptr + ? code_to_string[i].str + : code_to_string[i].alias_str; uint32_t code = 0; - Instruction::code_from_string(&code, code_to_string[i].str.length(), code_to_string[i].str, machine::Address(0x0)); - QCOMPARE(code, code_to_string[i].code); + try { + Instruction::code_from_string( + &code, code_to_string[i].str.length(), test_string_data, Address(0x0)); + QCOMPARE(code, code_to_string[i].code); + } catch (const Instruction::ParseError &e) { + TokenizedInstruction inst + = TokenizedInstruction::from_line(test_string_data, Address(0x0), nullptr, 0); + QFAIL(qPrintable(e.message)); + } catch (...) { QFAIL("code_from_string throw unexpected exception"); } } } diff --git a/src/machine/instruction.test.data.def b/src/machine/instruction.test.data.def new file mode 100644 index 00000000..7800fa38 --- /dev/null +++ b/src/machine/instruction.test.data.def @@ -0,0 +1,192 @@ +{0x40978003, "lb x0, 1033(x15)"}, +{0x25011d83, "lh x27, 592(x2)"}, +{0xed702f83, "lw x31, -297(x0)"}, +{0x29883d03, "ld x26, 664(x16)"}, +{0xdf624703, "lbu x14, -522(x4)"}, +{0x28d6db83, "lhu x23, 653(x13)"}, +{0x6c306803, "lwu x16, 1731(x0)"}, +{0xf, "fence"}, +{0x100f, "fence.i"}, +{0x68393, "addi x7, x13, 0", "mv x7, x13"}, +{0x765a0313, "addi x6, x20, 1893"}, +{0xb01413, "slli x8, x0, 0xb"}, +{0xa2ad2e13, "slti x28, x26, -1494"}, +{0x133593, "sltiu x11, x6, 1", "seqz x11, x6"}, +{0x8a7e3e93, "sltiu x29, x28, -1881"}, +{0xfff44a13, "xori x20, x8, -1", "not x20, x8"}, +{0x4e8a4d93, "xori x27, x20, 1256"}, +{0x170d293, "srli x5, x1, 0x17"}, +{0x41ea5b93, "srai x23, x20, 0x1e"}, +{0xb25dee93, "ori x29, x27, -1243"}, +{0xff67513, "andi x10, x12, 255", "zext.b x10, x12"}, +{0xeecd7193, "andi x3, x26, -276"}, +{0x7c660497, "auipc x9, 0x7c660"}, +{0x3809b, "addiw x1, x7, 0", "sext.w x1, x7"}, +{0x58c5021b, "addiw x4, x10, 1420"}, +{0x421e9b, "slliw x29, x4, 0x4"}, +{0x9a509b, "srliw x1, x20, 0x9"}, +{0x41e0d79b, "sraiw x15, x1, 0x1e"}, +{0xb4218823, "sb x2, -1200(x3)"}, +{0x97639b23, "sh x22, -1674(x7)"}, +{0xce52aea3, "sw x5, -771(x5)"}, +{0x862f31a3, "sd x2, -1949(x30)"}, +{0x6c23af, "amoadd.w x7, x6, (x24)"}, +{0x313afaf, "amoadd.w.rl x31, x17, (x7)"}, +{0x4a22f2f, "amoadd.w.aq x30, x10, (x4)"}, +{0x66aac2f, "amoadd.w.aqrl x24, x6, (x21)"}, +{0x9f6222f, "amoswap.w x4, x31, (x12)"}, +{0xa5026af, "amoswap.w.rl x13, x5, (x0)"}, +{0xdbca5af, "amoswap.w.aq x11, x27, (x25)"}, +{0xf32a9af, "amoswap.w.aqrl x19, x19, (x5)"}, +{0x10032a2f, "lr.w x20, (x6)"}, +{0x12002a2f, "lr.w.rl x20, (x0)"}, +{0x1403a1af, "lr.w.aq x3, (x7)"}, +{0x160e24af, "lr.w.aqrl x9, (x28)"}, +{0x19d3a92f, "sc.w x18, x29, (x7)"}, +{0x1b7d26af, "sc.w.rl x13, x23, (x26)"}, +{0x1c0f23af, "sc.w.aq x7, x0, (x30)"}, +{0x1f242aaf, "sc.w.aqrl x21, x18, (x8)"}, +{0x218a20af, "amoxor.w x1, x24, (x20)"}, +{0x237f28af, "amoxor.w.rl x17, x23, (x30)"}, +{0x2592a92f, "amoxor.w.aq x18, x25, (x5)"}, +{0x276cab2f, "amoxor.w.aqrl x22, x22, (x25)"}, +{0x4138ab2f, "amoor.w x22, x19, (x17)"}, +{0x438120af, "amoor.w.rl x1, x24, (x2)"}, +{0x44adabaf, "amoor.w.aq x23, x10, (x27)"}, +{0x4694ac2f, "amoor.w.aqrl x24, x9, (x9)"}, +{0x60afa2af, "amoand.w x5, x10, (x31)"}, +{0x63f724af, "amoand.w.rl x9, x31, (x14)"}, +{0x64c3a42f, "amoand.w.aq x8, x12, (x7)"}, +{0x6629a52f, "amoand.w.aqrl x10, x2, (x19)"}, +{0x81962c2f, "amomin.w x24, x25, (x12)"}, +{0x83d1a1af, "amomin.w.rl x3, x29, (x3)"}, +{0x84d5ac2f, "amomin.w.aq x24, x13, (x11)"}, +{0x864526af, "amomin.w.aqrl x13, x4, (x10)"}, +{0xa0742baf, "amomax.w x23, x7, (x8)"}, +{0xa36329af, "amomax.w.rl x19, x22, (x6)"}, +{0xa4132b2f, "amomax.w.aq x22, x1, (x6)"}, +{0xa60a2e2f, "amomax.w.aqrl x28, x0, (x20)"}, +{0xc0f5242f, "amominu.w x8, x15, (x10)"}, +{0xc227abaf, "amominu.w.rl x23, x2, (x15)"}, +{0xc5d7a32f, "amominu.w.aq x6, x29, (x15)"}, +{0xc6752caf, "amominu.w.aqrl x25, x7, (x10)"}, +{0xe1892faf, "amomaxu.w x31, x24, (x18)"}, +{0xe27520af, "amomaxu.w.rl x1, x7, (x10)"}, +{0xe55c202f, "amomaxu.w.aq x0, x21, (x24)"}, +{0xe63b24af, "amomaxu.w.aqrl x9, x3, (x22)"}, +{0x117bbaf, "amoadd.d x23, x17, (x15)"}, +{0x29e3b2f, "amoadd.d.rl x22, x9, (x28)"}, +{0x492322f, "amoadd.d.aq x4, x9, (x4)"}, +{0x730372f, "amoadd.d.aqrl x14, x19, (x0)"}, +{0x83cb2af, "amoswap.d x5, x3, (x25)"}, +{0xb2a3d2f, "amoswap.d.rl x26, x18, (x20)"}, +{0xd10b82f, "amoswap.d.aq x16, x17, (x1)"}, +{0xf15b52f, "amoswap.d.aqrl x10, x17, (x11)"}, +{0x1009be2f, "lr.d x28, (x19)"}, +{0x120833af, "lr.d.rl x7, (x16)"}, +{0x140b3b2f, "lr.d.aq x22, (x22)"}, +{0x160b352f, "lr.d.aqrl x10, (x22)"}, +{0x19413faf, "sc.d x31, x20, (x2)"}, +{0x1b49b7af, "sc.d.rl x15, x20, (x19)"}, +{0x1d6ab1af, "sc.d.aq x3, x22, (x21)"}, +{0x1f7d30af, "sc.d.aqrl x1, x23, (x26)"}, +{0x2099b22f, "amoxor.d x4, x9, (x19)"}, +{0x2281b8af, "amoxor.d.rl x17, x8, (x3)"}, +{0x243e3e2f, "amoxor.d.aq x28, x3, (x28)"}, +{0x26fc322f, "amoxor.d.aqrl x4, x15, (x24)"}, +{0x411934af, "amoor.d x9, x17, (x18)"}, +{0x42d0b6af, "amoor.d.rl x13, x13, (x1)"}, +{0x45d4b12f, "amoor.d.aq x2, x29, (x9)"}, +{0x46c432af, "amoor.d.aqrl x5, x12, (x8)"}, +{0x6189ba2f, "amoand.d x20, x24, (x19)"}, +{0x62d9b22f, "amoand.d.rl x4, x13, (x19)"}, +{0x657c312f, "amoand.d.aq x2, x23, (x24)"}, +{0x6731372f, "amoand.d.aqrl x14, x19, (x2)"}, +{0x8042b7af, "amomin.d x15, x4, (x5)"}, +{0x82f6bcaf, "amomin.d.rl x25, x15, (x13)"}, +{0x84a8bc2f, "amomin.d.aq x24, x10, (x17)"}, +{0x87693a2f, "amomin.d.aqrl x20, x22, (x18)"}, +{0xa0e430af, "amomax.d x1, x14, (x8)"}, +{0xa38fb02f, "amomax.d.rl x0, x24, (x31)"}, +{0xa4eabaaf, "amomax.d.aq x21, x14, (x21)"}, +{0xa6abbdaf, "amomax.d.aqrl x27, x10, (x23)"}, +{0xc0643f2f, "amominu.d x30, x6, (x8)"}, +{0xc2463eaf, "amominu.d.rl x29, x4, (x12)"}, +{0xc4c7b72f, "amominu.d.aq x14, x12, (x15)"}, +{0xc6c6b72f, "amominu.d.aqrl x14, x12, (x13)"}, +{0xe1e1b72f, "amomaxu.d x14, x30, (x3)"}, +{0xe2ab3d2f, "amomaxu.d.rl x26, x10, (x22)"}, +{0xe5353d2f, "amomaxu.d.aq x26, x19, (x10)"}, +{0xe6fbb52f, "amomaxu.d.aqrl x10, x15, (x23)"}, +{0xe80533, "add x10, x16, x14"}, +{0x413004b3, "sub x9, x0, x19", "neg x9, x19"}, +{0x40180d33, "sub x26, x16, x1"}, +{0x9419b3, "sll x19, x8, x9"}, +{0xea133, "slt x2, x29, x0", "sltz x2, x29"}, +{0x1f026b3, "slt x13, x0, x31", "sgtz x13, x31"}, +{0x92133, "slt x2, x18, x0"}, +{0x6031b3, "sltu x3, x0, x6", "snez x3, x6"}, +{0xe53ab3, "sltu x21, x10, x14"}, +{0x1b34ab3, "xor x21, x6, x27"}, +{0x1a7dbb3, "srl x23, x15, x26"}, +{0x40285e33, "sra x28, x16, x2"}, +{0x9beb33, "or x22, x23, x9"}, +{0x57f033, "and x0, x15, x5"}, +{0x2830033, "mul x0, x6, x8"}, +{0x21c9133, "mulh x2, x25, x1"}, +{0x2d62833, "mulhsu x16, x12, x13"}, +{0x378b733, "mulhu x14, x17, x23"}, +{0x32ac333, "div x6, x21, x18"}, +{0x33ad733, "divu x14, x21, x19"}, +{0x342e0b3, "rem x1, x5, x20"}, +{0x3f4f733, "remu x14, x9, x31"}, +{0x4f615cb7, "lui x25, 0x4f615"}, +{0x530f3b, "addw x30, x6, x5"}, +{0x408003bb, "subw x7, x0, x8", "negw x7, x8"}, +{0x41cd83bb, "subw x7, x27, x28"}, +{0x3490bb, "sllw x1, x9, x3"}, +{0xed5f3b, "srlw x30, x26, x14"}, +{0x40c752bb, "sraw x5, x14, x12"}, +{0x31706bb, "mulw x13, x14, x17"}, +{0x33ec93b, "divw x18, x29, x19"}, +{0x2ce5e3b, "divuw x28, x28, x12"}, +{0x2b1e2bb, "remw x5, x3, x11"}, +{0x38af43b, "remuw x8, x21, x24"}, +{0x400d0863, "beq x26, x0, 0x410", "beqz x26, 0x410"}, +{0x5d2e0c63, "beq x28, x18, 0x5d8"}, +{0xfe0793e3, "bne x15, x0, -0x1a", "bnez x15, -0x1a"}, +{0x90a21763, "bne x4, x10, -0xef2"}, +{0x6204cd63, "blt x9, x0, 0x63a", "bltz x9, 0x63a"}, +{0x16604ae3, "blt x0, x6, 0x974", "bgtz x6, 0x974"}, +{0x4762c2e3, "blt x5, x22, 0xc64", "bgt x22, x5, 0xc64"}, +{0x4f3cc63, "blt x7, x15, 0x58"}, +{0x40c5e63, "bge x24, x0, 0x5c", "bgez x24, 0x5c"}, +{0xfab1df63, "bge x3, x11, -0x842", "ble x11, x3, -0x842"}, +{0xa4705663, "bge x0, x7, -0xdb4", "blez x7, -0xdb4"}, +{0xbe195ee3, "bge x18, x1, -0x404"}, +{0xb90866e3, "bltu x16, x16, -0x474", "bgtu x16, x16, -0x474"}, +{0x1ca1e8e3, "bltu x3, x10, 0x9d0"}, +{0x153070e3, "bgeu x0, x19, 0x940", "bleu x19, x0, 0x940"}, +{0xca7777e3, "bgeu x14, x7, -0x352"}, +{0x8067, "jalr x0, 0(x1)", "ret"}, +{0x98067, "jalr x0, 0(x19)", "jr x19"}, +{0xa88a0067, "jalr x0, -1400(x20)", "jr -1400(x20)"}, +{0xf80e7, "jalr x1, 0(x31)", "jalr x31"}, +{0x58cc00e7, "jalr x1, 1420(x24)", "jalr 1420(x24)"}, +{0x69698ae7, "jalr x21, 1686(x19)", "jalr x21, x19, 1686"}, +{0x1dc90967, "jalr x18, 476(x18)"}, +{0x5f11506f, "jal x0, 0x15df0", "j 0x15df0"}, +{0xb2210ef, "jal x1, 0x210b2", "jal 0x210b2"}, +{0x7ef56e6f, "jal x28, 0x56fee"}, +{0x73, "ecall"}, +{0x100073, "ebreak"}, +{0x10200073, "sret"}, +{0x30200073, "mret"}, +{0x305b1073, "csrrw x0, 0x305, x22", "csrw mtvec, x22"}, +{0xf13c1f73, "csrrw x30, 0xf13, x24", "csrrw x30, mimpid, x24"}, +{0x30102cf3, "csrrs x25, 0x301, x0", "csrr x25, misa"}, +{0xb02022f3, "csrrs x5, 0xb02, x0", "csrrs x5, minstret, x0"}, +{0xb0053673, "csrrc x12, 0xb00, x10", "csrrc x12, mcycle, x10"}, +{0x34365973, "csrrwi x18, 0x343, 0xc", "csrrwi x18, mtval, 0xc"}, +{0x34a061f3, "csrrsi x3, 0x34a, 0x0", "csrrsi x3, mtinst, 0x0"}, +{0xb025f473, "csrrci x8, 0xb02, 0xb", "csrrci x8, minstret, 0xb"}, diff --git a/src/machine/instruction.test.data.h b/src/machine/instruction.test.data.h deleted file mode 100644 index 25387a58..00000000 --- a/src/machine/instruction.test.data.h +++ /dev/null @@ -1,162 +0,0 @@ -{0x108083, "lb x1, 1(x1)"}, -{0x109083, "lh x1, 1(x1)"}, -{0x10a083, "lw x1, 1(x1)"}, -{0x10b083, "ld x1, 1(x1)"}, -{0x10c083, "lbu x1, 1(x1)"}, -{0x10d083, "lhu x1, 1(x1)"}, -{0x10e083, "lwu x1, 1(x1)"}, -{0xf, "fence"}, -{0x100f, "fence.i"}, -{0x108093, "addi x1, x1, 1"}, -{0x109093, "slli x1, x1, 0x1"}, -{0x10a093, "slti x1, x1, 1"}, -{0x10b093, "sltiu x1, x1, 1"}, -{0x10c093, "xori x1, x1, 1"}, -{0x10d093, "srli x1, x1, 0x1"}, -{0x4010d093, "srai x1, x1, 0x1"}, -{0x10e093, "ori x1, x1, 1"}, -{0x10f093, "andi x1, x1, 1"}, -{0x1097, "auipc x1, 0x1"}, -{0x10809b, "addiw x1, x1, 1"}, -{0x10909b, "slliw x1, x1, 0x1"}, -{0x10d09b, "srliw x1, x1, 0x1"}, -{0x4010d09b, "sraiw x1, x1, 0x1"}, -{0x1080a3, "sb x1, 1(x1)"}, -{0x1090a3, "sh x1, 1(x1)"}, -{0x10a0a3, "sw x1, 1(x1)"}, -{0x10b0a3, "sd x1, 1(x1)"}, -{0x10a0af, "amoadd.w x1, x1, (x1)"}, -{0x210a0af, "amoadd.w.rl x1, x1, (x1)"}, -{0x410a0af, "amoadd.w.aq x1, x1, (x1)"}, -{0x610a0af, "amoadd.w.aqrl x1, x1, (x1)"}, -{0x810a0af, "amoswap.w x1, x1, (x1)"}, -{0xa10a0af, "amoswap.w.rl x1, x1, (x1)"}, -{0xc10a0af, "amoswap.w.aq x1, x1, (x1)"}, -{0xe10a0af, "amoswap.w.aqrl x1, x1, (x1)"}, -{0x1000a0af, "lr.w x1, (x1)"}, -{0x1200a0af, "lr.w.rl x1, (x1)"}, -{0x1400a0af, "lr.w.aq x1, (x1)"}, -{0x1600a0af, "lr.w.aqrl x1, (x1)"}, -{0x1810a0af, "sc.w x1, x1, (x1)"}, -{0x1a10a0af, "sc.w.rl x1, x1, (x1)"}, -{0x1c10a0af, "sc.w.aq x1, x1, (x1)"}, -{0x1e10a0af, "sc.w.aqrl x1, x1, (x1)"}, -{0x2010a0af, "amoxor.w x1, x1, (x1)"}, -{0x2210a0af, "amoxor.w.rl x1, x1, (x1)"}, -{0x2410a0af, "amoxor.w.aq x1, x1, (x1)"}, -{0x2610a0af, "amoxor.w.aqrl x1, x1, (x1)"}, -{0x4010a0af, "amoor.w x1, x1, (x1)"}, -{0x4210a0af, "amoor.w.rl x1, x1, (x1)"}, -{0x4410a0af, "amoor.w.aq x1, x1, (x1)"}, -{0x4610a0af, "amoor.w.aqrl x1, x1, (x1)"}, -{0x6010a0af, "amoand.w x1, x1, (x1)"}, -{0x6210a0af, "amoand.w.rl x1, x1, (x1)"}, -{0x6410a0af, "amoand.w.aq x1, x1, (x1)"}, -{0x6610a0af, "amoand.w.aqrl x1, x1, (x1)"}, -{0x8010a0af, "amomin.w x1, x1, (x1)"}, -{0x8210a0af, "amomin.w.rl x1, x1, (x1)"}, -{0x8410a0af, "amomin.w.aq x1, x1, (x1)"}, -{0x8610a0af, "amomin.w.aqrl x1, x1, (x1)"}, -{0xa010a0af, "amomax.w x1, x1, (x1)"}, -{0xa210a0af, "amomax.w.rl x1, x1, (x1)"}, -{0xa410a0af, "amomax.w.aq x1, x1, (x1)"}, -{0xa610a0af, "amomax.w.aqrl x1, x1, (x1)"}, -{0xc010a0af, "amominu.w x1, x1, (x1)"}, -{0xc210a0af, "amominu.w.rl x1, x1, (x1)"}, -{0xc410a0af, "amominu.w.aq x1, x1, (x1)"}, -{0xc610a0af, "amominu.w.aqrl x1, x1, (x1)"}, -{0xe010a0af, "amomaxu.w x1, x1, (x1)"}, -{0xe210a0af, "amomaxu.w.rl x1, x1, (x1)"}, -{0xe410a0af, "amomaxu.w.aq x1, x1, (x1)"}, -{0xe610a0af, "amomaxu.w.aqrl x1, x1, (x1)"}, -{0x10b0af, "amoadd.d x1, x1, (x1)"}, -{0x210b0af, "amoadd.d.rl x1, x1, (x1)"}, -{0x410b0af, "amoadd.d.aq x1, x1, (x1)"}, -{0x610b0af, "amoadd.d.aqrl x1, x1, (x1)"}, -{0x810b0af, "amoswap.d x1, x1, (x1)"}, -{0xa10b0af, "amoswap.d.rl x1, x1, (x1)"}, -{0xc10b0af, "amoswap.d.aq x1, x1, (x1)"}, -{0xe10b0af, "amoswap.d.aqrl x1, x1, (x1)"}, -{0x1000b0af, "lr.d x1, (x1)"}, -{0x1200b0af, "lr.d.rl x1, (x1)"}, -{0x1400b0af, "lr.d.aq x1, (x1)"}, -{0x1600b0af, "lr.d.aqrl x1, (x1)"}, -{0x1810b0af, "sc.d x1, x1, (x1)"}, -{0x1a10b0af, "sc.d.rl x1, x1, (x1)"}, -{0x1c10b0af, "sc.d.aq x1, x1, (x1)"}, -{0x1e10b0af, "sc.d.aqrl x1, x1, (x1)"}, -{0x2010b0af, "amoxor.d x1, x1, (x1)"}, -{0x2210b0af, "amoxor.d.rl x1, x1, (x1)"}, -{0x2410b0af, "amoxor.d.aq x1, x1, (x1)"}, -{0x2610b0af, "amoxor.d.aqrl x1, x1, (x1)"}, -{0x4010b0af, "amoor.d x1, x1, (x1)"}, -{0x4210b0af, "amoor.d.rl x1, x1, (x1)"}, -{0x4410b0af, "amoor.d.aq x1, x1, (x1)"}, -{0x4610b0af, "amoor.d.aqrl x1, x1, (x1)"}, -{0x6010b0af, "amoand.d x1, x1, (x1)"}, -{0x6210b0af, "amoand.d.rl x1, x1, (x1)"}, -{0x6410b0af, "amoand.d.aq x1, x1, (x1)"}, -{0x6610b0af, "amoand.d.aqrl x1, x1, (x1)"}, -{0x8010b0af, "amomin.d x1, x1, (x1)"}, -{0x8210b0af, "amomin.d.rl x1, x1, (x1)"}, -{0x8410b0af, "amomin.d.aq x1, x1, (x1)"}, -{0x8610b0af, "amomin.d.aqrl x1, x1, (x1)"}, -{0xa010b0af, "amomax.d x1, x1, (x1)"}, -{0xa210b0af, "amomax.d.rl x1, x1, (x1)"}, -{0xa410b0af, "amomax.d.aq x1, x1, (x1)"}, -{0xa610b0af, "amomax.d.aqrl x1, x1, (x1)"}, -{0xc010b0af, "amominu.d x1, x1, (x1)"}, -{0xc210b0af, "amominu.d.rl x1, x1, (x1)"}, -{0xc410b0af, "amominu.d.aq x1, x1, (x1)"}, -{0xc610b0af, "amominu.d.aqrl x1, x1, (x1)"}, -{0xe010b0af, "amomaxu.d x1, x1, (x1)"}, -{0xe210b0af, "amomaxu.d.rl x1, x1, (x1)"}, -{0xe410b0af, "amomaxu.d.aq x1, x1, (x1)"}, -{0xe610b0af, "amomaxu.d.aqrl x1, x1, (x1)"}, -{0x1080b3, "add x1, x1, x1"}, -{0x401080b3, "sub x1, x1, x1"}, -{0x1090b3, "sll x1, x1, x1"}, -{0x10a0b3, "slt x1, x1, x1"}, -{0x10b0b3, "sltu x1, x1, x1"}, -{0x10c0b3, "xor x1, x1, x1"}, -{0x10d0b3, "srl x1, x1, x1"}, -{0x4010d0b3, "sra x1, x1, x1"}, -{0x10e0b3, "or x1, x1, x1"}, -{0x10f0b3, "and x1, x1, x1"}, -{0x21080b3, "mul x1, x1, x1"}, -{0x21090b3, "mulh x1, x1, x1"}, -{0x210a0b3, "mulhsu x1, x1, x1"}, -{0x210b0b3, "mulhu x1, x1, x1"}, -{0x210c0b3, "div x1, x1, x1"}, -{0x210d0b3, "divu x1, x1, x1"}, -{0x210e0b3, "rem x1, x1, x1"}, -{0x210f0b3, "remu x1, x1, x1"}, -{0x10b7, "lui x1, 0x1"}, -{0x1080bb, "addw x1, x1, x1"}, -{0x401080bb, "subw x1, x1, x1"}, -{0x1090bb, "sllw x1, x1, x1"}, -{0x10d0bb, "srlw x1, x1, x1"}, -{0x4010d0bb, "sraw x1, x1, x1"}, -{0x21080bb, "mulw x1, x1, x1"}, -{0x210c0bb, "divw x1, x1, x1"}, -{0x210d0bb, "divuw x1, x1, x1"}, -{0x210e0bb, "remw x1, x1, x1"}, -{0x210f0bb, "remuw x1, x1, x1"}, -{0x108163, "beq x1, x1, 0x2"}, -{0x109163, "bne x1, x1, 0x2"}, -{0x10c163, "blt x1, x1, 0x2"}, -{0x10d163, "bge x1, x1, 0x2"}, -{0x10e163, "bltu x1, x1, 0x2"}, -{0x10f163, "bgeu x1, x1, 0x2"}, -{0x1080e7, "jalr x1, 1(x1)"}, -{0x2000ef, "jal x1, 0x2"}, -{0x73, "ecall"}, -{0x100073, "ebreak"}, -{0x10200073, "sret"}, -{0x30200073, "mret"}, -{0x1090f3, "csrrw x1, 0x1, x1"}, -{0x10a0f3, "csrrs x1, 0x1, x1"}, -{0x10b0f3, "csrrc x1, 0x1, x1"}, -{0x10d0f3, "csrrwi x1, 0x1, 0x1"}, -{0x10e0f3, "csrrsi x1, 0x1, 0x1"}, -{0x10f0f3, "csrrci x1, 0x1, 0x1"}, diff --git a/src/machine/instruction.test.gendata.cpp b/src/machine/instruction.test.gendata.cpp index 46654cf2..10399f5c 100644 --- a/src/machine/instruction.test.gendata.cpp +++ b/src/machine/instruction.test.gendata.cpp @@ -1,138 +1,141 @@ -#include "common/logging.h" -#include "machine/instruction.h" -#include "machine/instruction.cpp" -#include -#include +#include -using namespace machine; +uint32_t +random_arg_code_mask(const ArgumentDesc *arg_desc, const InstructionMap *im, QString *string_data) { + int32_t field + // = QRandomGenerator::global()->generate(); + = QRandomGenerator::global()->bounded(int32_t(arg_desc->min), int32_t(arg_desc->max)); -static uint32_t MASK_AMO_RS2 = 0b1111100000000000000000000; + // set fields from value + uint32_t code_mask = arg_desc->arg.encode(field); -#define AMO_MAP_4ITEMS(NAME_BASE, MASK) \ - { NAME_BASE, MASK}, \ - { NAME_BASE ".rl", MASK }, \ - { NAME_BASE ".aq", MASK }, \ - { NAME_BASE ".aqrl", MASK }, + switch (arg_desc->kind) { + case 'E': { + field = field % CSR::Id::_COUNT; + CSR::RegisterDesc reg = CSR::REGISTERS[field]; + field = reg.address.data; + code_mask = arg_desc->arg.encode(reg.address.data); + } + } + // set to zero if needed + if (zero_mask_tb.count(im->name)) { code_mask &= zero_mask_tb[im->name].zero_mask; } + + uint32_t decoded_value = arg_desc->arg.decode(code_mask); + *string_data = field_to_string(decoded_value, arg_desc, Address(0), false); + return code_mask; +} -static std::unordered_map mask_map = { - AMO_MAP_4ITEMS("lr.w", MASK_AMO_RS2) - AMO_MAP_4ITEMS("lr.d", MASK_AMO_RS2) -}; +GeneratedInst random_inst_from_im(const InstructionMap *im, const InstructionMap *im_source) { + if (im->flags & InstructionFlags::IMF_CSR) {} -void generate_code_and_string_data(QTextStream& out, const InstructionMap* im_iter, BitField subfield) { - for (int i = 0; i < (1 << subfield.count); i++) { - const InstructionMap* im = &im_iter[i]; + uint32_t code = im->code; + QString string_data = im->name; - if (im->name == "unknown") { - continue; + code &= im->mask; + + QString next_delim = " "; + for (const QString &arg_string : im->args) { + string_data += next_delim; + next_delim = ", "; + for (int pos = 0; pos < arg_string.size(); pos += 1) { + char arg_letter = arg_string[pos].toLatin1(); + const ArgumentDesc *arg_desc = arg_desc_by_code[(unsigned char)arg_letter]; + if (arg_desc == nullptr) { + string_data += arg_letter; + continue; + } + + QString field = 0; + const uint32_t code_mask = random_arg_code_mask(arg_desc, im, &field); + string_data += field; + + code |= code_mask; } + } + return GeneratedInst { code, string_data, im, im_source }; +} + +void WalkInstructionMapHelper( + const InstructionMap *im_iter, + BitField subfield, + const InstructionMap *im_source, + std::function handler) { + for (int i = 0;; i++) { + if (im_source == nullptr) { + // end of subclass table + if (i >= (1 << subfield.count)) { break; } + } else { + // end of alias + if (im_iter[i].name == nullptr) { break; } + } + + const InstructionMap *im = &im_iter[i]; if (im->subclass != nullptr) { - generate_code_and_string_data(out, im->subclass, im->subfield); + // walk into subclass + WalkInstructionMapHelper(im->subclass, im->subfield, nullptr, handler); continue; } - uint32_t code = im->code; - QString string_data = im->name; + // handle alias + if (im->aliases != nullptr) { + WalkInstructionMapHelper(im->aliases, im->subfield, im, handler); + } - if (im->args.size()) { - int val_mask; - switch (im->type) { - case Instruction::Type::R: - case Instruction::Type::AMO: { - val_mask = 0b00000000000100001000000010000000; - break; - } - case Instruction::Type::I: - val_mask = 0b00000000000100001000000010000000; - break; - case Instruction::Type::ZICSR: { - val_mask = 0b00000000000100001000000010000000; - break; - } - case Instruction::Type::S: { - val_mask = 0b00000000000100001000000010000000; - break; - } - case Instruction::Type::B: { - val_mask = 0b00000000000100001000000100000000; - break; - } - case Instruction::Type::U: { - val_mask = 0b00000000000000000001000010000000; - break; - } - case Instruction::Type::J: { - val_mask = 0b00000000001000000000000010000000; - break; - } - case Instruction::Type::UNKNOWN: { - return; - } - } - code |= val_mask & ~im->mask; - if (mask_map.count(im->name)) { - uint32_t old_code = code; - code &= ~mask_map[im->name]; - } + Instruction::Type t = im->type; + if (im_source != nullptr) { t = im_source->type; } + if (t == IT_UNKNOWN) { continue; } - QString next_delim = " "; - for (const QString &arg_string : im->args) { - string_data += next_delim; - next_delim = ", "; - for (int pos = 0; pos < arg_string.size(); pos += 1) { - char arg_letter = arg_string[pos].toLatin1(); - const ArgumentDesc *arg_desc = arg_desc_by_code[(unsigned char)arg_letter]; - if (arg_desc == nullptr) { - string_data += arg_letter; - continue; - } - switch (arg_desc->kind) { - case 'g': { - string_data += "x1"; - break; + // handle self + handler(im, im_source); + } +} + +void WalkInstructionMap( + std::function handler) { + return WalkInstructionMapHelper(C_inst_map, instruction_map_opcode_field, nullptr, handler); +} + +int main() { + fill_argdesbycode(); + instruction_from_string_build_base(); + WalkInstructionMap([](const InstructionMap *im, const InstructionMap *im_source) { + printf("\ninst: [%s] \n\n", im->name); + for (int i = 0; i < 100; i++) { + printf(" - [%2d]", i); + auto generated = random_inst_from_im(im, im_source); + if (generated.im != nullptr) { + printf( + " code: [%10x] str: [%30s]\n", generated.code, + qPrintable(generated.string_data)); + + try { + uint32_t parsed_code; + // mv 0, 0 => nop, which buffer is shorter + Instruction::code_from_string( + &parsed_code, 20, generated.string_data, Address(0x0)); + + // check code_from_string + if (parsed_code != generated.code) { + throw Instruction::ParseError("code_from_string not match"); } - case 'p': - case 'a': - string_data += QString::asprintf("0x%d", Instruction(code).immediate()); - break; - case 'o': - case 'n': { - if (arg_desc->min < 0) { - string_data += "1"; - } else { - string_data += "0x1"; + + if (im->flags & IMF_CSR || im_source != nullptr) { + // alias inst || csr inst + } else { + // base inst + // check to_str() + QString parsed_string_data = Instruction(generated.code).to_str(); + if (parsed_string_data != generated.string_data) { + throw Instruction::ParseError("to_string not match"); } - break; - } - case 'E': { - string_data += "0x1"; - break; - } } + } catch (const Instruction::ParseError &e) { + // QFAIL + throw(e); } } } - - QString enum_str = QString::asprintf("{0x%x, \"%s\"},", code, qPrintable(string_data)); - if (Instruction(code).to_str() != string_data) { - enum_str += " // failed"; - } - enum_str += "\n"; - out << enum_str; - } -} - -int main(int argc, char *argv[]) { - fill_argdesbycode(); - instruction_from_string_build_base(); - QFile outfile("instruction.test.data.h"); - if (outfile.open(QIODevice::WriteOnly | QIODevice::Text)) { - QTextStream out(&outfile); - generate_code_and_string_data(out, C_inst_map, instruction_map_opcode_field); - outfile.close(); - } else { - printf("open output file failed\n"); - exit(1); - } + }); + return 0; } \ No newline at end of file diff --git a/src/machine/instruction.test.gendata.h b/src/machine/instruction.test.gendata.h new file mode 100644 index 00000000..f25e17be --- /dev/null +++ b/src/machine/instruction.test.gendata.h @@ -0,0 +1,92 @@ +#ifndef INSTRUCTION_TEST_GENDATA_H +#define INSTRUCTION_TEST_GENDATA_H + +#include "machine/instruction.h" +#include "machine/instruction.cpp" + +#include +#include +#include + +using namespace machine; + +struct GeneratedInst { + uint32_t code; + QString string_data; + + const InstructionMap *im; + const InstructionMap *im_source; +}; + +GeneratedInst random_inst_from_im(const InstructionMap *im, const InstructionMap *im_source); +uint32_t random_arg_code_mask(const ArgumentDesc *arg_desc, const InstructionMap *im, QString *string_data); +void WalkInstructionMap(std::function handler); +void WalkInstructionMapHelper( + const InstructionMap *im_iter, + BitField subfield, + const InstructionMap *parent, + std::function handler); + +bool fill_argdesbycode(); +void instruction_from_string_build_base(); +QString field_to_string(int32_t field, const ArgumentDesc* arg_desc, Address inst_addr, bool symbolic_registers_enabled); + +static const BitField MASK_R_RD = { 5, 7 }; +static const BitField MASK_R_RS1 = { 5, 15 }; +static const BitField MASK_R_RS2 = { 5, 20 }; + +static const BitField MASK_AMO_RD = { 5, 7 }; +static const BitField MASK_AMO_RS1 = { 5, 15 }; +static const BitField MASK_AMO_RS2 = { 5, 20 }; + +static const BitField MASK_I_RD = { 5, 7 }; +static const BitField MASK_I_RS1 = { 5, 15 }; +static const BitField MASK_I_IMM = { 12, 20 }; + +static const BitField MASK_ZICSR_RD = { 5, 7 }; +static const BitField MASK_ZICSR_RS1 = { 5, 15 }; +static const BitField MASK_ZICSR_CSR = { 12, 20 }; + +static const BitField MASK_S_IMM_0_4 = { 4, 7 }; +static const BitField MASK_S_IMM_5_11 = { 7, 25 }; +static const BitField MASK_S_IMM_12 = { 1, 31 }; +static const BitField MASK_S_RS1 = { 5, 15 }; +static const BitField MASK_S_RS2 = { 5, 20 }; + +static const BitField MASK_B_IMM_1_4 = { 4, 8 }; +static const BitField MASK_B_IMM_11 = { 1, 7 }; +static const BitField MASK_B_IMM_5_10 = { 6, 25 }; +static const BitField MASK_B_IMM_12 = { 1, 31 }; +static const BitField MASK_B_RS1 = { 5, 15 }; +static const BitField MASK_B_RS2 = { 5, 20 }; + +static const BitField MASK_U_RD = { 5, 7 }; +static const BitField MASK_U_IMM = { 20, 12 }; + +static const BitField MASK_J_RD = { 5, 7 }; +static const BitField MASK_J_IMM_12_19 = { 8, 12 }; +static const BitField MASK_J_IMM_11 = { 1, 20 }; +static const BitField MASK_J_IMM_1_10 = { 31, 21 }; +static const BitField MASK_J_IMM_20 = { 1, 31 }; + +#define AMO_MAP_4ITEMS(NAME, MASK) \ + { NAME, { MASK } }, { NAME ".aq", { MASK } }, { NAME ".rl", { MASK } }, { \ + NAME ".aqrl", { \ + MASK \ + } \ + } + +struct ADDITIONAL_TB { + uint64_t zero_mask; + uint64_t value = 0; + uint64_t alias = false; +}; +static const QMap zero_mask_tb = { + // lr.w/d rs2 = 0 + AMO_MAP_4ITEMS("lr.w", ~MASK_AMO_RS2.mask()), + AMO_MAP_4ITEMS("lr.d", ~MASK_AMO_RS2.mask()), + // csrw(alias of csrrs) rs1 = 0 + { "csrrs", { ~MASK_I_RS1.mask() } } +}; + +#endif \ No newline at end of file