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/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 11b2922e..560a6fca 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,84 @@ 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 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() { + 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() { + 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; + 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"); } + } +} QTEST_APPLESS_MAIN(TestInstruction) 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.gendata.cpp b/src/machine/instruction.test.gendata.cpp new file mode 100644 index 00000000..10399f5c --- /dev/null +++ b/src/machine/instruction.test.gendata.cpp @@ -0,0 +1,141 @@ +#include + +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)); + + // set fields from value + uint32_t code_mask = arg_desc->arg.encode(field); + + 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; +} + +GeneratedInst random_inst_from_im(const InstructionMap *im, const InstructionMap *im_source) { + if (im->flags & InstructionFlags::IMF_CSR) {} + + uint32_t code = im->code; + QString string_data = im->name; + + 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) { + // walk into subclass + WalkInstructionMapHelper(im->subclass, im->subfield, nullptr, handler); + continue; + } + + // handle alias + if (im->aliases != nullptr) { + WalkInstructionMapHelper(im->aliases, im->subfield, im, handler); + } + + Instruction::Type t = im->type; + if (im_source != nullptr) { t = im_source->type; } + if (t == IT_UNKNOWN) { continue; } + + // 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"); + } + + 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"); + } + } + } catch (const Instruction::ParseError &e) { + // QFAIL + throw(e); + } + } + } + }); + 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 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