From 74fade0042a65e913900b98e7e97175bf09c4284 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Tue, 14 Nov 2023 02:56:06 +0100 Subject: [PATCH] fxos: generate defs from insn table + some renaming --- CMakeLists.txt | 23 ++++++- include/fxos/lang.h | 2 +- lib/analysis.cpp | 2 +- lib/disassembly.cpp | 12 ++-- lib/lang.cpp | 2 +- lib/load-asm.l | 2 +- base-library/asmtables/sh3.txt => lib/sh3.def | 0 base-library/asmtables/sh4.txt => lib/sh4.def | 0 lib/view/assembly.cpp | 4 +- tools/mkdefs_insn.cc | 67 +++++++++++++++++++ 10 files changed, 100 insertions(+), 14 deletions(-) rename base-library/asmtables/sh3.txt => lib/sh3.def (100%) rename base-library/asmtables/sh4.txt => lib/sh4.def (100%) create mode 100644 tools/mkdefs_insn.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a253a8..3a4f176 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,22 @@ if(FXOS_CLEAN_LOGS) "${PROJECT_BINARY_DIR}/compiler_filter.sh") endif() +#--- +# tooling for generating code at compile-time +#--- + +add_executable(mkdefs_insn tools/mkdefs_insn.cc) +target_link_libraries(mkdefs_insn PRIVATE -lfmt) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/gendefs/insn.h" + COMMAND mkdir -p "${CMAKE_CURRENT_BINARY_DIR}/gendefs/" + COMMAND "$" + "${CMAKE_CURRENT_SOURCE_DIR}/lib/sh3.def" + "${CMAKE_CURRENT_SOURCE_DIR}/lib/sh4.def" > + "${CMAKE_CURRENT_BINARY_DIR}/gendefs/insn.h" + DEPENDS mkdefs_insn lib/sh3.def lib/sh4.def) + #--- # fxos core #--- @@ -69,10 +85,13 @@ set(fxos_core_SOURCES lib/util/bson.cpp lib/util/Buffer.cpp lib/util/log.cpp - lib/util/Timer.cpp) + lib/util/Timer.cpp + + "${CMAKE_CURRENT_BINARY_DIR}/gendefs/insn.h") add_library(fxos-core ${fxos_core_SOURCES} ${FLEX_LoadAsm_OUTPUTS}) -target_include_directories(fxos-core PUBLIC include) +target_include_directories(fxos-core + PUBLIC include "${CMAKE_CURRENT_BINARY_DIR}") #--- # fxos shell diff --git a/include/fxos/lang.h b/include/fxos/lang.h index e9ebe86..c1e5964 100644 --- a/include/fxos/lang.h +++ b/include/fxos/lang.h @@ -168,7 +168,7 @@ struct AsmInstruction /* Original opcode. Initialized to 0 when unset, which is an invalid instruction by design. */ - u32 opcode; + u32 encoding; /* Operation size (0, 1, 2 or 4) */ i8 opsize; /* Number of arguments */ diff --git a/lib/analysis.cpp b/lib/analysis.cpp index 6cd8a98..ea219a0 100644 --- a/lib/analysis.cpp +++ b/lib/analysis.cpp @@ -109,7 +109,7 @@ static ProgramStateDiff interpretInstruction( diff.setUnknown(); // TODO: Do this properly - u16 opc = ins.opcode().opcode; + u16 opc = ins.opcode().encoding; if((opc & 0xf000) == 0xe000) { int reg = (opc >> 8) & 0xf; int val = (int8_t)opc; diff --git a/lib/disassembly.cpp b/lib/disassembly.cpp index 6b56cee..f6912ee 100644 --- a/lib/disassembly.cpp +++ b/lib/disassembly.cpp @@ -19,13 +19,13 @@ std::array, 65536> insmap; void register_instruction(AsmInstruction const &ins) { - uint16_t opcode = ins.opcode; + uint16_t encoding = ins.encoding; - if(insmap[opcode]) - FxOS_log(ERR, "opcode collision between a %s and a %s at %04x", - insmap[opcode]->mnemonic, ins.mnemonic, opcode); + if(insmap[encoding]) + FxOS_log(ERR, "encoding collision between a %s and a %s at %04x", + insmap[encoding]->mnemonic, ins.mnemonic, encoding); else - insmap[opcode] = ins; + insmap[encoding] = ins; } //--- @@ -40,7 +40,7 @@ Argument::Argument() } OldInstruction::OldInstruction(AsmInstruction const *inst): - inst {inst}, args {}, opcode {inst->opcode}, leader {false}, + inst {inst}, args {}, opcode {inst->encoding}, leader {false}, delayslot {false}, terminal {false}, jump {false}, condjump {false}, jmptarget {0xffffffff} { diff --git a/lib/lang.cpp b/lib/lang.cpp index 8cc83df..33a6ebc 100644 --- a/lib/lang.cpp +++ b/lib/lang.cpp @@ -196,7 +196,7 @@ u32 AsmArgument::getPCRelativeTarget(u32 pc, int size) const //--- AsmInstruction::AsmInstruction(char const *mn): - opcode {0}, opsize {0}, arg_count {0} + encoding {0}, opsize {0}, arg_count {0} { int len = strlen(mn); int pos = std::max(0, len - 2); diff --git a/lib/load-asm.l b/lib/load-asm.l index 6ef843e..b480ca2 100644 --- a/lib/load-asm.l +++ b/lib/load-asm.l @@ -268,7 +268,7 @@ static int instantiate(struct Pattern p, char const *mnemonic, int argtoken1, opcode |= (i << p.i_sh); AsmInstruction ins(mnemonic); - ins.opcode = opcode; + ins.encoding = opcode; ins.tags = insntags; if(argtoken1) { diff --git a/base-library/asmtables/sh3.txt b/lib/sh3.def similarity index 100% rename from base-library/asmtables/sh3.txt rename to lib/sh3.def diff --git a/base-library/asmtables/sh4.txt b/lib/sh4.def similarity index 100% rename from base-library/asmtables/sh4.txt rename to lib/sh4.def diff --git a/lib/view/assembly.cpp b/lib/view/assembly.cpp index 14d1542..d8935c5 100644 --- a/lib/view/assembly.cpp +++ b/lib/view/assembly.cpp @@ -141,7 +141,7 @@ static void doOldInst(u32 pc, OldInstruction &i, } /* Raw data if instruction cannot be decoded */ - printf(" %08x: %04x", pc, (i.inst ? i.inst->opcode : i.opcode)); + printf(" %08x: %04x", pc, (i.inst ? i.inst->encoding : i.opcode)); if(!i.inst) { printf("\n"); m_lastAddress = pc; @@ -239,7 +239,7 @@ void viewAssemblyInstruction(Instruction const &ins, ViewAssemblyOptions *opts) ArgumentOutput argout; u32 pc = ins.address(); - printf(" %08x: %04x", pc, opcode.opcode); + printf(" %08x: %04x", pc, opcode.encoding); /* Mnemonic */ static char const *suffixes[5] = {"", ".b", ".w", "", ".l"}; diff --git a/tools/mkdefs_insn.cc b/tools/mkdefs_insn.cc new file mode 100644 index 0000000..0f650d8 --- /dev/null +++ b/tools/mkdefs_insn.cc @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void usage(int rc) +{ + fprintf(stderr, "usage: ./mkdefs_insn \n"); + exit(rc); +} + +std::string encodeMnemonic(std::string mnemonic) +{ + for(size_t i = 0; i < mnemonic.size(); i++) { + if(!isalnum(mnemonic[i])) + mnemonic[i] = '_'; + } + + return mnemonic; +} + +static void parseTable( + char const *file, std::map &allMnemonics) +{ + std::ifstream fin {file}; + std::string line, pattern, mnemonic; + + while(std::getline(fin, line)) { + if(line.size() == 0 || !strchr("01nmdi", line[0])) + continue; + + std::istringstream stream {line}; + stream >> pattern >> mnemonic; + + if(mnemonic.ends_with(".b") || mnemonic.ends_with(".w") || + mnemonic.ends_with(".l")) + mnemonic = mnemonic.substr(0, mnemonic.size() - 2); + + std::string enc = encodeMnemonic(mnemonic); + assert(!allMnemonics.count(enc) || allMnemonics.at(enc) == mnemonic); + allMnemonics.insert({ enc, mnemonic }); + } +} + +int main(int argc, char **argv) +{ + for(int i = 1; i < argc; i++) { + if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) + usage(0); + } + if(argc <= 1) + usage(1); + + std::map allMnemonics; + for(int i = 1; i < argc; i++) + parseTable(argv[i], allMnemonics); + + for(auto const &[e,m]: allMnemonics) + fmt::print("GENDEFS_INSN({}, \"{}\")\n", e, m); + + return 0; +}