From 86d309afc8177b12767795d4fa5f31745a9f8fb0 Mon Sep 17 00:00:00 2001 From: shygoo Date: Sun, 21 Jan 2018 03:36:20 -0600 Subject: [PATCH 1/2] [Debugger] Support all commands in code editor --- .../UserInterface/Debugger/Assembler.cpp | 442 ++++++++---------- .../UserInterface/Debugger/Assembler.h | 331 ++++++++++++- 2 files changed, 512 insertions(+), 261 deletions(-) diff --git a/Source/Project64/UserInterface/Debugger/Assembler.cpp b/Source/Project64/UserInterface/Debugger/Assembler.cpp index be15899c9..283f4bae0 100644 --- a/Source/Project64/UserInterface/Debugger/Assembler.cpp +++ b/Source/Project64/UserInterface/Debugger/Assembler.cpp @@ -9,59 +9,153 @@ #include "Assembler.h" #include "Project64-core\N64System\Mips\OpCode.h" -REGISTER* lookup_register(char* name); +ASM_PARSE_ERROR CAssembler::m_ParseError = ERR_NONE; +uint32_t CAssembler::m_Address = 0; -static ParseError parse_error = ERR_NONE; -static uint32_t m_Address = 0x00000000; +char* CAssembler::m_TokContext = NULL; -void to_lower(char* str) +bool CAssembler::AssembleLine(char* line, uint32_t* opcode, uint32_t address) { - while (*str) - { - if (*str >= 'A' && *str <= 'Z') - { - *str |= 0x20; - } - str++; - } + m_ParseError = ERR_NONE; + m_Address = address; + + char line_c[128]; + strncpy(line_c, line, 128); + StrToLower(line_c); + + if (line_c[0] == '\0') + { + *opcode = 0; + return true; + } + + char* name = strtok_s(line_c, " \t", &m_TokContext); + + // attempt to assemble the line + // if a syntax error occurs, check if the command has alternative syntax forms and retry + + for(int nFallback = 0;; nFallback++) + { + const ASM_INSTRUCTION* instruction = LookupInstruction(name, nFallback); + + if (instruction == NULL) + { + m_ParseError = ERR_UNKNOWN_CMD; + return false; + } + + m_ParseError = ERR_NONE; + + if (nFallback > 0) + { + // prepare for re-tokenization + strncpy(line_c, line, 128); + StrToLower(line_c); + name = strtok_s(line_c, " \t", &m_TokContext); + } + + *opcode = instruction->base(instruction->val); + + if (instruction->syntax == NULL) + { + // No parameters + return true; + } + + for (int i = 0; instruction->syntax[i]; i++) + { + instruction->syntax[i](opcode); + + if (m_ParseError != ERR_NONE) + { + goto next_fallback; + } + } + + // assembled without errors + return true; + + next_fallback:; + } } -uint32_t pop_reg() +const ASM_INSTRUCTION* CAssembler::LookupInstruction(char* name, int nFallback) { - char* r = strtok(NULL, " \t,()"); + for (int i = 0; m_Instructions[i].name != NULL; i++) + { + if (strcmp(name, m_Instructions[i].name) == 0) + { + if (nFallback != 0) + { + nFallback--; + continue; + } + return &m_Instructions[i]; + } + } + return NULL; +} + +const ASM_REGISTER* CAssembler::LookupRegister(char* name) +{ + for (int i = 0; m_Registers[i].name != NULL; i++) + { + if (strcmp(name, m_Registers[i].name) == 0) + { + return &m_Registers[i]; + } + } + return NULL; +} + +void CAssembler::StrToLower(char* str) +{ + while (*str) + { + if (*str >= 'A' && *str <= 'Z') + { + *str |= 0x20; + } + str++; + } +} + +uint32_t CAssembler::pop_reg() +{ + char* r = strtok_s(NULL, " \t,()", &m_TokContext); if (r == NULL) { - parse_error = ERR_EXPECTED_REG; + m_ParseError = ERR_EXPECTED_REG; return 0; } - REGISTER* reg = lookup_register(r); + const ASM_REGISTER* reg = LookupRegister(r); if (reg == NULL) { - parse_error = ERR_INVALID_REG; + m_ParseError = ERR_INVALID_REG; return 0; } return reg->val; } -uint32_t pop_val() +uint32_t CAssembler::pop_val() { - char* v = strtok(NULL, " \t,()"); + char* v = strtok_s(NULL, " \t,()", &m_TokContext); if (v == NULL) { - parse_error = ERR_EXPECTED_VAL; + m_ParseError = ERR_EXPECTED_VAL; return 0; } - if (isalpha(*v)) - { - // todo lookup label value - return 0; - } + //if (isalpha(*v)) + //{ + // // todo lookup label value + // return 0; + //} int base = 0; // hex or dec @@ -77,280 +171,120 @@ uint32_t pop_val() if (*endptr != '\0') { - parse_error = ERR_EXPECTED_VAL; + m_ParseError = ERR_EXPECTED_VAL; return 0; } return val; } -uint32_t base_op(uint32_t val) +uint32_t CAssembler::base_op(uint32_t val) { return val << 26; } -uint32_t base_spec(uint32_t val) +uint32_t CAssembler::base_spec(uint32_t val) { return val; } -uint32_t base_regimm(uint32_t val) +uint32_t CAssembler::base_spec_jalr_ra(uint32_t val) +{ + return (31 << 11) | val; +} + +uint32_t CAssembler::base_regimm(uint32_t val) { return (R4300i_REGIMM << 26) | (val << 16); } -void arg_reg_s(uint32_t* opcode) +uint32_t CAssembler::base_cop0_co(uint32_t val) +{ + return (R4300i_CP0 << 26) | (1 << 25) | val; +} + +uint32_t CAssembler::base_cop0_mv(uint32_t val) +{ + return (R4300i_CP0 << 26) | (val << 21); +} + +uint32_t CAssembler::base_cop1_mv(uint32_t val) +{ + return (R4300i_CP1 << 26) | (val << 21); +} + +uint32_t CAssembler::base_cop1_s(uint32_t val) +{ + return (R4300i_CP1 << 26) | (R4300i_COP1_S << 21) | val; +} + +uint32_t CAssembler::base_cop1_d(uint32_t val) +{ + return (R4300i_CP1 << 26) | (R4300i_COP1_D << 21) | val; +} + +uint32_t CAssembler::base_cop1_bc(uint32_t val) +{ + return (R4300i_CP1 << 26) | (R4300i_COP1_BC << 21) | (val << 16); +} + +void CAssembler::arg_reg_t(uint32_t* opcode) +{ + *opcode |= pop_reg() << 16; +} + +void CAssembler::arg_reg_s(uint32_t* opcode) { *opcode |= pop_reg() << 21; } -void arg_reg_t(uint32_t* opcode) -{ - *opcode |= pop_reg() << 16; -} - -void arg_reg_d(uint32_t* opcode) +void CAssembler::arg_reg_d(uint32_t* opcode) { *opcode |= pop_reg() << 11; } -void arg_jump(uint32_t* opcode) +void CAssembler::arg_reg_ft(uint32_t* opcode) +{ + *opcode |= pop_reg() << 16; +} + +void CAssembler::arg_reg_fs(uint32_t* opcode) +{ + *opcode |= pop_reg() << 11; +} + +void CAssembler::arg_reg_fd(uint32_t* opcode) +{ + *opcode |= pop_reg() << 6; +} + +void CAssembler::arg_jump(uint32_t* opcode) { *opcode |= (pop_val() / 4) & 0x3FFFFFF; } -void arg_imm16(uint32_t* opcode) +void CAssembler::arg_imm16(uint32_t* opcode) { *opcode |= (pop_val() & 0xFFFF); } -void arg_bra_target(uint32_t* opcode) +void CAssembler::arg_bra_target(uint32_t* opcode) { uint16_t relTarget = (((pop_val() - m_Address) / 4) & 0xFFFF) - 1; *opcode |= relTarget; } -void arg_shamt(uint32_t* opcode) +void CAssembler::arg_shamt(uint32_t* opcode) { *opcode |= (pop_val() & 0x1F) << 6; } -SYNTAX syn_jump[] = { arg_jump, NULL }; -SYNTAX syn_loadstore[] = { arg_reg_t, arg_imm16, arg_reg_s, NULL }; -SYNTAX syn_arith[] = { arg_reg_d, arg_reg_s, arg_reg_t, NULL }; -SYNTAX syn_arith_i[] = { arg_reg_t, arg_reg_s, arg_imm16, NULL }; -SYNTAX syn_load_i[] = { arg_reg_t, arg_imm16, NULL }; - -SYNTAX syn_branch_z[] = { arg_reg_s, arg_bra_target, NULL }; -SYNTAX syn_branch[] = { arg_reg_s, arg_reg_t, arg_bra_target, NULL }; -SYNTAX syn_branch_unc[] = { arg_bra_target, NULL }; - -SYNTAX syn_trap_i[] = { arg_reg_s, arg_imm16, NULL }; - -SYNTAX syn_shift[] = { arg_reg_d, arg_reg_t, arg_shamt, NULL }; - -SYNTAX syn_mf[] = { arg_reg_d, NULL }; -SYNTAX syn_jr[] = { arg_reg_s, NULL }; - -INSTRUCTION instructions[] = +void CAssembler::arg_cache_op(uint32_t* opcode) { - { "j", R4300i_J, base_op, syn_jump }, - { "jal", R4300i_JAL, base_op, syn_jump }, - { "beq", R4300i_BEQ, base_op, syn_branch }, - { "beqz", R4300i_BEQ, base_op, syn_branch_z }, - { "b", R4300i_BEQ, base_op, syn_branch_unc }, - { "bne", R4300i_BNE, base_op, syn_branch }, - { "bnez", R4300i_BNE, base_op, syn_branch_z }, - { "blez", R4300i_BLEZ, base_op, syn_branch_z }, - { "bgtz", R4300i_BGTZ, base_op, syn_branch_z }, - { "addi", R4300i_ADDI, base_op, syn_arith_i }, - { "addiu", R4300i_ADDIU, base_op, syn_arith_i }, - { "slti", R4300i_SLTI, base_op, syn_arith_i }, - { "sltiu", R4300i_SLTIU, base_op, syn_arith_i }, - { "andi", R4300i_ANDI, base_op, syn_arith_i }, - { "ori", R4300i_ORI, base_op, syn_arith_i }, - { "xori", R4300i_XORI, base_op, syn_arith_i }, - { "lui", R4300i_LUI, base_op, syn_load_i }, - // cp0 cp1 - { "beql", R4300i_BEQL, base_op, syn_branch }, - { "beqzl", R4300i_BEQL, base_op, syn_branch_z }, - { "bnel", R4300i_BNEL, base_op, syn_branch }, - { "bnezl", R4300i_BNEL, base_op, syn_branch_z }, - { "blezl", R4300i_BLEZL, base_op, syn_branch_z }, - { "bgtzl", R4300i_BGTZL, base_op, syn_branch_z }, - { "daddi", R4300i_DADDI, base_op, syn_arith_i }, - { "daddiu", R4300i_DADDI, base_op, syn_arith_i }, - { "ldl", R4300i_LDL, base_op, syn_loadstore }, - { "ldr", R4300i_LDR, base_op, syn_loadstore }, - { "lb", R4300i_LB, base_op, syn_loadstore }, - { "lh", R4300i_LH, base_op, syn_loadstore }, - { "lwl", R4300i_LWL, base_op, syn_loadstore }, - { "lw", R4300i_LW, base_op, syn_loadstore }, - { "lbu", R4300i_LBU, base_op, syn_loadstore }, - { "lhu", R4300i_LHU, base_op, syn_loadstore }, - { "lwr", R4300i_LWR, base_op, syn_loadstore }, - { "lwu", R4300i_LWU, base_op, syn_loadstore }, - { "sb", R4300i_SB, base_op, syn_loadstore }, - { "sh", R4300i_SH, base_op, syn_loadstore }, - { "swl", R4300i_SWL, base_op, syn_loadstore }, - { "sw", R4300i_SW, base_op, syn_loadstore }, - { "sdl", R4300i_SDL, base_op, syn_loadstore }, - { "sdr", R4300i_SDR, base_op, syn_loadstore }, - { "swr", R4300i_SWR, base_op, syn_loadstore }, - //{ "cache", R4300i_CACHE, base_op, }, - { "ll", R4300i_LL, base_op, syn_loadstore }, - { "lwc1", R4300i_LWC1, base_op, syn_loadstore }, - { "ldc1", R4300i_LDC1, base_op, syn_loadstore }, - { "ld", R4300i_LD, base_op, syn_loadstore }, - { "sc", R4300i_SC, base_op, syn_loadstore }, - { "swc1", R4300i_SWC1, base_op, syn_loadstore }, - { "sdc1", R4300i_SDC1, base_op, syn_loadstore }, - { "sdc2", R4300i_SDC2, base_op, syn_loadstore }, - { "sd", R4300i_SD, base_op, syn_loadstore }, - - { "bltz", R4300i_REGIMM_BLTZ, base_regimm, syn_branch_z }, - { "bgez", R4300i_REGIMM_BGEZ, base_regimm, syn_branch_z }, - { "bltzl", R4300i_REGIMM_BLTZL, base_regimm, syn_branch_z }, - { "bgezl", R4300i_REGIMM_BGEZL, base_regimm, syn_branch_z }, - { "tgei", R4300i_REGIMM_TGEI, base_regimm, syn_trap_i }, - { "tgeiu", R4300i_REGIMM_TGEIU, base_regimm, syn_trap_i }, - { "tlti", R4300i_REGIMM_TLTIU, base_regimm, syn_trap_i }, - { "tltiu", R4300i_REGIMM_TLTIU, base_regimm, syn_trap_i }, - { "teqi", R4300i_REGIMM_TEQI, base_regimm, syn_trap_i }, - { "tnei", R4300i_REGIMM_TNEI, base_regimm, syn_trap_i }, - { "bltzal", R4300i_REGIMM_BLTZAL, base_regimm, syn_branch_z }, - { "bgezal", R4300i_REGIMM_BGEZAL, base_regimm, syn_branch_z }, - { "bal", R4300i_REGIMM_BGEZAL, base_regimm, syn_branch_unc }, - { "bltzall", R4300i_REGIMM_BLTZALL, base_regimm, syn_branch_z }, - { "bgezall", R4300i_REGIMM_BGEZALL, base_regimm, syn_branch_z }, - - { "sll", R4300i_SPECIAL_SLL, base_spec, syn_shift }, - { "nop", R4300i_SPECIAL_SLL, base_spec, NULL }, - { "srl", R4300i_SPECIAL_SRL, base_spec, syn_shift }, - { "sra", R4300i_SPECIAL_SRA, base_spec, syn_shift }, - - { "jr", R4300i_SPECIAL_JR, base_spec, syn_jr }, - { "syscall", R4300i_SPECIAL_SYSCALL, base_spec, NULL }, - { "break", R4300i_SPECIAL_BREAK, base_spec, NULL }, - { "sync", R4300i_SPECIAL_SYNC, base_spec, NULL }, - - { "mfhi", R4300i_SPECIAL_MFHI, base_spec, syn_mf }, - { "mthi", R4300i_SPECIAL_MTHI, base_spec, syn_mf }, - { "mflo", R4300i_SPECIAL_MFLO, base_spec, syn_mf }, - { "mtlo", R4300i_SPECIAL_MTLO, base_spec, syn_mf }, - - { "add", R4300i_SPECIAL_ADD, base_spec, syn_arith }, - { "addu", R4300i_SPECIAL_ADDU, base_spec, syn_arith }, - { "sub", R4300i_SPECIAL_SUB, base_spec, syn_arith }, - { "subu", R4300i_SPECIAL_SUBU, base_spec, syn_arith }, - { "and", R4300i_SPECIAL_AND, base_spec, syn_arith }, - { "or", R4300i_SPECIAL_OR, base_spec, syn_arith }, - { "xor", R4300i_SPECIAL_XOR, base_spec, syn_arith }, - { "nor", R4300i_SPECIAL_NOR, base_spec, syn_arith }, - { "slt", R4300i_SPECIAL_SLT, base_spec, syn_arith }, - { "sltu", R4300i_SPECIAL_SLTU, base_spec, syn_arith }, - { "dadd", R4300i_SPECIAL_DADD, base_spec, syn_arith }, - { "daddu", R4300i_SPECIAL_DADDU, base_spec, syn_arith }, - { "dsub", R4300i_SPECIAL_DSUB, base_spec, syn_arith }, - { "dsubu", R4300i_SPECIAL_DSUBU, base_spec, syn_arith }, - - { "dsll", R4300i_SPECIAL_DSLL, base_spec, syn_shift }, - { "dsrl", R4300i_SPECIAL_DSRL, base_spec, syn_shift }, - { "dsra", R4300i_SPECIAL_DSRA, base_spec, syn_shift }, - { "dsll32", R4300i_SPECIAL_DSLL32, base_spec, syn_shift }, - { "dsrl32", R4300i_SPECIAL_DSRL32, base_spec, syn_shift }, - { "dsra32", R4300i_SPECIAL_DSRA32, base_spec, syn_shift }, - - { 0 } -}; - -REGISTER registers[] = -{ - { "r0", 0 },{ "at", 1 },{ "v0", 2 },{ "v1", 3 },{ "a0", 4 },{ "a1", 5 },{ "a2", 6 },{ "a3", 7 }, - { "t0", 8 },{ "t1", 9 },{ "t2", 10 },{ "t3", 11 },{ "t4", 12 },{ "t5", 13 },{ "t6", 14 },{ "t7", 15 }, - { "s0", 16 },{ "s1", 17 },{ "s2", 18 },{ "s3", 19 },{ "s4", 20 },{ "s5", 21 },{ "s6", 22 },{ "s7", 23 }, - { "t8", 24 },{ "t9", 25 },{ "k0", 26 },{ "k1", 27 },{ "gp", 28 },{ "sp", 29 },{ "s8", 30 },{ "ra", 31 }, - - { "fp", 30 }, - - { "f0", 0 },{ "f1", 1 },{ "f2", 2 },{ "f3", 3 },{ "f4", 4 },{ "f5", 5 },{ "f6", 6 },{ "f7", 7 }, - { "f8", 8 },{ "f9", 9 },{ "f10", 10 },{ "f11", 11 },{ "f12", 12 },{ "f13", 13 },{ "f14", 14 },{ "f15", 15 }, - { "f16", 16 },{ "f17", 17 },{ "f18", 18 },{ "f19", 19 },{ "f20", 20 },{ "f21", 21 },{ "f22", 22 },{ "f23", 23 }, - { "f24", 24 },{ "f25", 25 },{ "f26", 26 },{ "f27", 27 },{ "f28", 28 },{ "f29", 29 },{ "f30", 30 },{ "f31", 31 }, - - { "r0", 0 },{ "r1", 1 },{ "r2", 2 },{ "r3", 3 },{ "r4", 4 },{ "r5", 5 },{ "r6", 6 },{ "r7", 7 }, - { "r8", 8 },{ "r9", 9 },{ "r10", 10 },{ "r11", 11 },{ "r12", 12 },{ "r13", 13 },{ "r14", 14 },{ "r15", 15 }, - { "r16", 16 },{ "r17", 17 },{ "r18", 18 },{ "r19", 19 },{ "r20", 20 },{ "r21", 21 },{ "r22", 22 },{ "r23", 23 }, - { "r24", 24 },{ "r25", 25 },{ "r26", 26 },{ "r27", 27 },{ "r28", 28 },{ "r29", 29 },{ "r30", 30 },{ "r31", 31 }, - - { 0 } -}; - -INSTRUCTION* lookup_instruction(char* name) -{ - for (int i = 0; instructions[i].name != NULL; i++) - { - if (strcmp(name, instructions[i].name) == 0) - { - return &instructions[i]; - } - } - return NULL; + *opcode |= (pop_val() & 0x1F) << 16; } -REGISTER* lookup_register(char* name) +void CAssembler::arg_syscall_code(uint32_t* opcode) { - for (int i = 0; registers[i].name != NULL; i++) - { - if (strcmp(name, registers[i].name) == 0) - { - return ®isters[i]; - } - } - return NULL; -} - -bool CAssembler::AssembleLine(char* line, uint32_t* opcode, uint32_t address) -{ - parse_error = ERR_NONE; - - m_Address = address; - char line_c[128]; - strncpy(line_c, line, 128); - - to_lower(line_c); - - if (line_c[0] == '\0') - { - *opcode = 0; - return true; - } - - char* name = strtok(line_c, " \t"); - - INSTRUCTION* instruction = lookup_instruction(name); - - if (instruction == NULL) - { - return false; - } - - *opcode = instruction->base(instruction->val); - - if (instruction->syntax == NULL) - { - // No parameters - return true; - } - - for (int i = 0; instruction->syntax[i]; i++) - { - instruction->syntax[i](opcode); - - if (parse_error != ERR_NONE) - { - return false; - } - } - return true; + *opcode |= (pop_val() & 0xFFFFF) << 6; } \ No newline at end of file diff --git a/Source/Project64/UserInterface/Debugger/Assembler.h b/Source/Project64/UserInterface/Debugger/Assembler.h index 262d8012b..11753dae2 100644 --- a/Source/Project64/UserInterface/Debugger/Assembler.h +++ b/Source/Project64/UserInterface/Debugger/Assembler.h @@ -2,29 +2,346 @@ #include -typedef void(*SYNTAX)(uint32_t* opcode); +typedef void(*ASM_SYNTAX_FN)(uint32_t* opcode); typedef struct { const char* name; uint32_t val; uint32_t(*base)(uint32_t val); // value shift - SYNTAX* syntax; // arguments -} INSTRUCTION; + const ASM_SYNTAX_FN* syntax; // arguments +} ASM_INSTRUCTION; typedef struct { const char* name; uint32_t val; -} REGISTER; +} ASM_REGISTER; -enum ParseError +enum ASM_PARSE_ERROR { ERR_NONE, ERR_EXPECTED_REG, ERR_INVALID_REG, - ERR_EXPECTED_VAL + ERR_EXPECTED_VAL, + ERR_UNKNOWN_CMD }; -class CAssembler { +class CAssembler +{ +private: + static uint32_t m_Address; + static ASM_PARSE_ERROR m_ParseError; + public: static bool AssembleLine(char* line, uint32_t* opcode, uint32_t address = 0x00000000); + +private: + + static char* m_TokContext; + + static const ASM_REGISTER* LookupRegister(char* name); + static const ASM_INSTRUCTION* LookupInstruction(char* name, int nFallback); + + static void StrToLower(char* str); + + static uint32_t pop_reg(); + static uint32_t pop_val(); + + static uint32_t base_op(uint32_t val); + static uint32_t base_spec(uint32_t val); + static uint32_t base_spec_jalr_ra(uint32_t val); + static uint32_t base_regimm(uint32_t val); + static uint32_t base_cop1_s(uint32_t val); + static uint32_t base_cop1_d(uint32_t val); + static uint32_t base_cop1_bc(uint32_t val); + static uint32_t base_cop0_co(uint32_t val); + static uint32_t base_cop0_mv(uint32_t val); + static uint32_t base_cop1_mv(uint32_t val); + + static void arg_reg_t(uint32_t* opcode); + static void arg_reg_s(uint32_t* opcode); + static void arg_reg_d(uint32_t* opcode); + static void arg_reg_ft(uint32_t* opcode); + static void arg_reg_fs(uint32_t* opcode); + static void arg_reg_fd(uint32_t* opcode); + static void arg_jump(uint32_t* opcode); + static void arg_imm16(uint32_t* opcode); + static void arg_bra_target(uint32_t* opcode); + static void arg_shamt(uint32_t* opcode); + static void arg_cache_op(uint32_t* opcode); + static void arg_syscall_code(uint32_t* opcode); + + static constexpr ASM_SYNTAX_FN syn_jump[] = { arg_jump, NULL }; + static constexpr ASM_SYNTAX_FN syn_loadstore[] = { arg_reg_t, arg_imm16, arg_reg_s, NULL }; + static constexpr ASM_SYNTAX_FN syn_arith[] = { arg_reg_d, arg_reg_s, arg_reg_t, NULL }; + static constexpr ASM_SYNTAX_FN syn_arith2[] = { arg_reg_s, arg_reg_t, NULL }; + static constexpr ASM_SYNTAX_FN syn_shiftv[] = { arg_reg_d, arg_reg_t, arg_reg_s, NULL }; + static constexpr ASM_SYNTAX_FN syn_arith_i[] = { arg_reg_t, arg_reg_s, arg_imm16, NULL }; + static constexpr ASM_SYNTAX_FN syn_load_i[] = { arg_reg_t, arg_imm16, NULL }; + static constexpr ASM_SYNTAX_FN syn_branch_z[] = { arg_reg_s, arg_bra_target, NULL }; + static constexpr ASM_SYNTAX_FN syn_branch[] = { arg_reg_s, arg_reg_t, arg_bra_target, NULL }; + static constexpr ASM_SYNTAX_FN syn_branch_unc[] = { arg_bra_target, NULL }; + static constexpr ASM_SYNTAX_FN syn_trap_i[] = { arg_reg_s, arg_imm16, NULL }; + static constexpr ASM_SYNTAX_FN syn_shift[] = { arg_reg_d, arg_reg_t, arg_shamt, NULL }; + static constexpr ASM_SYNTAX_FN syn_mf[] = { arg_reg_d, NULL }; + static constexpr ASM_SYNTAX_FN syn_jr[] = { arg_reg_s, NULL }; + static constexpr ASM_SYNTAX_FN syn_jalr[] = { arg_reg_d, arg_reg_s, NULL }; + static constexpr ASM_SYNTAX_FN syn_cop1_arith[] = { arg_reg_fd, arg_reg_fs, arg_reg_ft, NULL }; + static constexpr ASM_SYNTAX_FN syn_cop1[] = { arg_reg_fd, arg_reg_fs, NULL }; + static constexpr ASM_SYNTAX_FN syn_cop1_cmp[] = { arg_reg_fs, arg_reg_ft, NULL }; + static constexpr ASM_SYNTAX_FN syn_cop_mv[] = { arg_reg_t, arg_reg_d, NULL }; + static constexpr ASM_SYNTAX_FN syn_cache[] = { arg_cache_op, arg_imm16, arg_reg_s, NULL }; + static constexpr ASM_SYNTAX_FN syn_syscall[] = { arg_syscall_code, NULL }; + + static constexpr ASM_INSTRUCTION m_Instructions[] = + { + { "j", R4300i_J, base_op, syn_jump }, + { "jal", R4300i_JAL, base_op, syn_jump }, + { "beq", R4300i_BEQ, base_op, syn_branch }, + { "beqz", R4300i_BEQ, base_op, syn_branch_z }, + { "b", R4300i_BEQ, base_op, syn_branch_unc }, + { "bne", R4300i_BNE, base_op, syn_branch }, + { "bnez", R4300i_BNE, base_op, syn_branch_z }, + { "blez", R4300i_BLEZ, base_op, syn_branch_z }, + { "bgtz", R4300i_BGTZ, base_op, syn_branch_z }, + { "addi", R4300i_ADDI, base_op, syn_arith_i }, + { "addiu", R4300i_ADDIU, base_op, syn_arith_i }, + { "slti", R4300i_SLTI, base_op, syn_arith_i }, + { "sltiu", R4300i_SLTIU, base_op, syn_arith_i }, + { "andi", R4300i_ANDI, base_op, syn_arith_i }, + { "ori", R4300i_ORI, base_op, syn_arith_i }, + { "xori", R4300i_XORI, base_op, syn_arith_i }, + { "lui", R4300i_LUI, base_op, syn_load_i }, + { "beql", R4300i_BEQL, base_op, syn_branch }, + { "beqzl", R4300i_BEQL, base_op, syn_branch_z }, + { "bnel", R4300i_BNEL, base_op, syn_branch }, + { "bnezl", R4300i_BNEL, base_op, syn_branch_z }, + { "blezl", R4300i_BLEZL, base_op, syn_branch_z }, + { "bgtzl", R4300i_BGTZL, base_op, syn_branch_z }, + { "daddi", R4300i_DADDI, base_op, syn_arith_i }, + { "daddiu", R4300i_DADDIU, base_op, syn_arith_i }, + { "ldl", R4300i_LDL, base_op, syn_loadstore }, + { "ldr", R4300i_LDR, base_op, syn_loadstore }, + { "lb", R4300i_LB, base_op, syn_loadstore }, + { "lh", R4300i_LH, base_op, syn_loadstore }, + { "lwl", R4300i_LWL, base_op, syn_loadstore }, + { "lw", R4300i_LW, base_op, syn_loadstore }, + { "lbu", R4300i_LBU, base_op, syn_loadstore }, + { "lhu", R4300i_LHU, base_op, syn_loadstore }, + { "lwr", R4300i_LWR, base_op, syn_loadstore }, + { "lwu", R4300i_LWU, base_op, syn_loadstore }, + { "sb", R4300i_SB, base_op, syn_loadstore }, + { "sh", R4300i_SH, base_op, syn_loadstore }, + { "swl", R4300i_SWL, base_op, syn_loadstore }, + { "sw", R4300i_SW, base_op, syn_loadstore }, + { "sdl", R4300i_SDL, base_op, syn_loadstore }, + { "sdr", R4300i_SDR, base_op, syn_loadstore }, + { "swr", R4300i_SWR, base_op, syn_loadstore }, + { "cache", R4300i_CACHE, base_op, syn_cache }, + { "ll", R4300i_LL, base_op, syn_loadstore }, + { "lwc1", R4300i_LWC1, base_op, syn_loadstore }, + { "ldc1", R4300i_LDC1, base_op, syn_loadstore }, + { "ld", R4300i_LD, base_op, syn_loadstore }, + { "sc", R4300i_SC, base_op, syn_loadstore }, + { "swc1", R4300i_SWC1, base_op, syn_loadstore }, + { "sdc1", R4300i_SDC1, base_op, syn_loadstore }, + { "sdc2", R4300i_SDC2, base_op, syn_loadstore }, + { "sd", R4300i_SD, base_op, syn_loadstore }, + + { "sll", R4300i_SPECIAL_SLL, base_spec, syn_shift }, + { "nop", R4300i_SPECIAL_SLL, base_spec, NULL }, + { "srl", R4300i_SPECIAL_SRL, base_spec, syn_shift }, + { "sra", R4300i_SPECIAL_SRA, base_spec, syn_shift }, + { "sllv", R4300i_SPECIAL_SLLV, base_spec, syn_shiftv }, + { "srlv", R4300i_SPECIAL_SRLV, base_spec, syn_shiftv }, + { "srav", R4300i_SPECIAL_SRAV, base_spec, syn_shiftv }, + { "jr", R4300i_SPECIAL_JR, base_spec, syn_jr }, + { "jalr", R4300i_SPECIAL_JALR, base_spec, syn_jalr }, + { "jalr", R4300i_SPECIAL_JALR, base_spec_jalr_ra, syn_jr }, + { "syscall", R4300i_SPECIAL_SYSCALL, base_spec, syn_syscall }, + { "break", R4300i_SPECIAL_BREAK, base_spec, syn_syscall }, + { "sync", R4300i_SPECIAL_SYNC, base_spec, NULL }, + { "mfhi", R4300i_SPECIAL_MFHI, base_spec, syn_mf }, + { "mthi", R4300i_SPECIAL_MTHI, base_spec, syn_mf }, + { "mflo", R4300i_SPECIAL_MFLO, base_spec, syn_mf }, + { "mtlo", R4300i_SPECIAL_MTLO, base_spec, syn_mf }, + { "dsllv", R4300i_SPECIAL_DSLLV, base_spec, syn_shiftv }, + { "dsrlv", R4300i_SPECIAL_DSRLV, base_spec, syn_shiftv }, + { "dsrav", R4300i_SPECIAL_DSRAV, base_spec, syn_shiftv }, + { "mult", R4300i_SPECIAL_MULT, base_spec, syn_arith2 }, + { "multu", R4300i_SPECIAL_MULTU, base_spec, syn_arith2 }, + { "div", R4300i_SPECIAL_DIV, base_spec, syn_arith2 }, + { "divu", R4300i_SPECIAL_DIVU, base_spec, syn_arith2 }, + { "dmult", R4300i_SPECIAL_DMULT, base_spec, syn_arith2 }, + { "dmultu", R4300i_SPECIAL_DMULTU, base_spec, syn_arith2 }, + { "ddiv", R4300i_SPECIAL_DDIV, base_spec, syn_arith2 }, + { "ddivu", R4300i_SPECIAL_DDIVU, base_spec, syn_arith2 }, + { "add", R4300i_SPECIAL_ADD, base_spec, syn_arith }, + { "addu", R4300i_SPECIAL_ADDU, base_spec, syn_arith }, + { "sub", R4300i_SPECIAL_SUB, base_spec, syn_arith }, + { "subu", R4300i_SPECIAL_SUBU, base_spec, syn_arith }, + { "and", R4300i_SPECIAL_AND, base_spec, syn_arith }, + { "or", R4300i_SPECIAL_OR, base_spec, syn_arith }, + { "xor", R4300i_SPECIAL_XOR, base_spec, syn_arith }, + { "nor", R4300i_SPECIAL_NOR, base_spec, syn_arith }, + { "slt", R4300i_SPECIAL_SLT, base_spec, syn_arith }, + { "sltu", R4300i_SPECIAL_SLTU, base_spec, syn_arith }, + { "dadd", R4300i_SPECIAL_DADD, base_spec, syn_arith }, + { "daddu", R4300i_SPECIAL_DADDU, base_spec, syn_arith }, + { "dsub", R4300i_SPECIAL_DSUB, base_spec, syn_arith }, + { "dsubu", R4300i_SPECIAL_DSUBU, base_spec, syn_arith }, + { "tge", R4300i_SPECIAL_TGE, base_spec, syn_arith2 }, // note: no code field + { "tgeu", R4300i_SPECIAL_TGEU, base_spec, syn_arith2 }, // + { "tlt", R4300i_SPECIAL_TLT, base_spec, syn_arith2 }, // + { "tltu", R4300i_SPECIAL_TLTU, base_spec, syn_arith2 }, // + { "teq", R4300i_SPECIAL_TEQ, base_spec, syn_arith2 }, // + { "tne", R4300i_SPECIAL_TNE, base_spec, syn_arith2 }, // + { "dsll", R4300i_SPECIAL_DSLL, base_spec, syn_shift }, + { "dsrl", R4300i_SPECIAL_DSRL, base_spec, syn_shift }, + { "dsra", R4300i_SPECIAL_DSRA, base_spec, syn_shift }, + { "dsll32", R4300i_SPECIAL_DSLL32, base_spec, syn_shift }, + { "dsrl32", R4300i_SPECIAL_DSRL32, base_spec, syn_shift }, + { "dsra32", R4300i_SPECIAL_DSRA32, base_spec, syn_shift }, + + { "bltz", R4300i_REGIMM_BLTZ, base_regimm, syn_branch_z }, + { "bgez", R4300i_REGIMM_BGEZ, base_regimm, syn_branch_z }, + { "bltzl", R4300i_REGIMM_BLTZL, base_regimm, syn_branch_z }, + { "bgezl", R4300i_REGIMM_BGEZL, base_regimm, syn_branch_z }, + { "tgei", R4300i_REGIMM_TGEI, base_regimm, syn_trap_i }, + { "tgeiu", R4300i_REGIMM_TGEIU, base_regimm, syn_trap_i }, + { "tlti", R4300i_REGIMM_TLTI, base_regimm, syn_trap_i }, + { "tltiu", R4300i_REGIMM_TLTIU, base_regimm, syn_trap_i }, + { "teqi", R4300i_REGIMM_TEQI, base_regimm, syn_trap_i }, + { "tnei", R4300i_REGIMM_TNEI, base_regimm, syn_trap_i }, + { "bltzal", R4300i_REGIMM_BLTZAL, base_regimm, syn_branch_z }, + { "bgezal", R4300i_REGIMM_BGEZAL, base_regimm, syn_branch_z }, + { "bal", R4300i_REGIMM_BGEZAL, base_regimm, syn_branch_unc }, + { "bltzall", R4300i_REGIMM_BLTZALL, base_regimm, syn_branch_z }, + { "bgezall", R4300i_REGIMM_BGEZALL, base_regimm, syn_branch_z }, + + { "mfc0", R4300i_COP0_MF , base_cop0_mv, syn_cop_mv }, + { "mtc0", R4300i_COP0_MT , base_cop0_mv, syn_cop_mv }, + + { "tlbr", R4300i_COP0_CO_TLBR, base_cop0_co, NULL }, + { "tlbwi", R4300i_COP0_CO_TLBWI, base_cop0_co, NULL }, + { "tlbwr", R4300i_COP0_CO_TLBWR, base_cop0_co, NULL }, + { "tlbp", R4300i_COP0_CO_TLBP, base_cop0_co, NULL }, + { "eret", R4300i_COP0_CO_ERET, base_cop0_co, NULL }, + + { "mfc1", R4300i_COP1_MF, base_cop1_mv, syn_cop_mv }, + { "dmfc1", R4300i_COP1_DMF, base_cop1_mv, syn_cop_mv }, + { "cfc1", R4300i_COP1_CF, base_cop1_mv, syn_cop_mv }, + { "mtc1", R4300i_COP1_MT, base_cop1_mv, syn_cop_mv }, + { "dmtc1", R4300i_COP1_DMT, base_cop1_mv, syn_cop_mv }, + { "ctc1", R4300i_COP1_CT, base_cop1_mv, syn_cop_mv }, + + { "bc1f", R4300i_COP1_BC_BCF, base_cop1_bc, syn_branch_unc }, + { "bc1t", R4300i_COP1_BC_BCT, base_cop1_bc, syn_branch_unc }, + { "bc1fl", R4300i_COP1_BC_BCFL, base_cop1_bc, syn_branch_unc }, + { "bc1tl", R4300i_COP1_BC_BCTL, base_cop1_bc, syn_branch_unc }, + + { "add.s", R4300i_COP1_FUNCT_ADD, base_cop1_s, syn_cop1_arith }, + { "sub.s", R4300i_COP1_FUNCT_SUB, base_cop1_s, syn_cop1_arith }, + { "mul.s", R4300i_COP1_FUNCT_MUL, base_cop1_s, syn_cop1_arith }, + { "div.s", R4300i_COP1_FUNCT_DIV, base_cop1_s, syn_cop1_arith }, + { "sqrt.s", R4300i_COP1_FUNCT_SQRT, base_cop1_s, syn_cop1 }, + { "abs.s", R4300i_COP1_FUNCT_ABS, base_cop1_s, syn_cop1 }, + { "mov.s", R4300i_COP1_FUNCT_MOV, base_cop1_s, syn_cop1 }, + { "neg.s", R4300i_COP1_FUNCT_NEG, base_cop1_s, syn_cop1 }, + { "round.l.s", R4300i_COP1_FUNCT_ROUND_L, base_cop1_s, syn_cop1 }, + { "trunc.l.s", R4300i_COP1_FUNCT_TRUNC_L, base_cop1_s, syn_cop1 }, + { "ceil.l.s", R4300i_COP1_FUNCT_CEIL_L, base_cop1_s, syn_cop1 }, + { "floor.l.s", R4300i_COP1_FUNCT_FLOOR_L, base_cop1_s, syn_cop1 }, + { "round.w.s", R4300i_COP1_FUNCT_ROUND_W, base_cop1_s, syn_cop1 }, + { "trunc.w.s", R4300i_COP1_FUNCT_TRUNC_W, base_cop1_s, syn_cop1 }, + { "ceil.w.s", R4300i_COP1_FUNCT_CEIL_W, base_cop1_s, syn_cop1 }, + { "floor.w.s", R4300i_COP1_FUNCT_FLOOR_W, base_cop1_s, syn_cop1 }, + { "cvt.s.s", R4300i_COP1_FUNCT_CVT_S, base_cop1_s, syn_cop1 }, + { "cvt.d.s", R4300i_COP1_FUNCT_CVT_D, base_cop1_s, syn_cop1 }, + { "cvt.w.s", R4300i_COP1_FUNCT_CVT_W, base_cop1_s, syn_cop1 }, + { "cvt.l.s", R4300i_COP1_FUNCT_CVT_L, base_cop1_s, syn_cop1 }, + { "c.f.s", R4300i_COP1_FUNCT_C_F, base_cop1_s, syn_cop1_cmp }, + { "c.un.s", R4300i_COP1_FUNCT_C_UN, base_cop1_s, syn_cop1_cmp }, + { "c.eq.s", R4300i_COP1_FUNCT_C_EQ, base_cop1_s, syn_cop1_cmp }, + { "c.ueq.s", R4300i_COP1_FUNCT_C_UEQ, base_cop1_s, syn_cop1_cmp }, + { "c.olt.s", R4300i_COP1_FUNCT_C_OLT, base_cop1_s, syn_cop1_cmp }, + { "c.ult.s", R4300i_COP1_FUNCT_C_ULT, base_cop1_s, syn_cop1_cmp }, + { "c.ole.s", R4300i_COP1_FUNCT_C_OLE, base_cop1_s, syn_cop1_cmp }, + { "c.ule.s", R4300i_COP1_FUNCT_C_ULE, base_cop1_s, syn_cop1_cmp }, + { "c.sf.s", R4300i_COP1_FUNCT_C_SF, base_cop1_s, syn_cop1_cmp }, + { "c.ngle.s", R4300i_COP1_FUNCT_C_NGLE, base_cop1_s, syn_cop1_cmp }, + { "c.seq.s", R4300i_COP1_FUNCT_C_SEQ, base_cop1_s, syn_cop1_cmp }, + { "c.ngl.s", R4300i_COP1_FUNCT_C_NGL, base_cop1_s, syn_cop1_cmp }, + { "c.lt.s", R4300i_COP1_FUNCT_C_LT, base_cop1_s, syn_cop1_cmp }, + { "c.nge.s", R4300i_COP1_FUNCT_C_NGE, base_cop1_s, syn_cop1_cmp }, + { "c.le.s", R4300i_COP1_FUNCT_C_LE, base_cop1_s, syn_cop1_cmp }, + { "c.ngt.s", R4300i_COP1_FUNCT_C_NGT, base_cop1_s, syn_cop1_cmp }, + + { "add.d", R4300i_COP1_FUNCT_ADD, base_cop1_d, syn_cop1_arith }, + { "sub.d", R4300i_COP1_FUNCT_SUB, base_cop1_d, syn_cop1_arith }, + { "mul.d", R4300i_COP1_FUNCT_MUL, base_cop1_d, syn_cop1_arith }, + { "div.d", R4300i_COP1_FUNCT_DIV, base_cop1_d, syn_cop1_arith }, + { "sqrt.d", R4300i_COP1_FUNCT_SQRT, base_cop1_d, syn_cop1 }, + { "abs.d", R4300i_COP1_FUNCT_ABS, base_cop1_d, syn_cop1 }, + { "mov.d", R4300i_COP1_FUNCT_MOV, base_cop1_d, syn_cop1 }, + { "neg.d", R4300i_COP1_FUNCT_NEG, base_cop1_d, syn_cop1 }, + { "round.l.d", R4300i_COP1_FUNCT_ROUND_L, base_cop1_d, syn_cop1 }, + { "trunc.l.d", R4300i_COP1_FUNCT_TRUNC_L, base_cop1_d, syn_cop1 }, + { "ceil.l.d", R4300i_COP1_FUNCT_CEIL_L, base_cop1_d, syn_cop1 }, + { "floor.l.d", R4300i_COP1_FUNCT_FLOOR_L, base_cop1_d, syn_cop1 }, + { "round.w.d", R4300i_COP1_FUNCT_ROUND_W, base_cop1_d, syn_cop1 }, + { "trunc.w.d", R4300i_COP1_FUNCT_TRUNC_W, base_cop1_d, syn_cop1 }, + { "ceil.w.d", R4300i_COP1_FUNCT_CEIL_W, base_cop1_d, syn_cop1 }, + { "floor.w.d", R4300i_COP1_FUNCT_FLOOR_W, base_cop1_d, syn_cop1 }, + { "cvt.s.d", R4300i_COP1_FUNCT_CVT_S, base_cop1_d, syn_cop1 }, + { "cvt.d.d", R4300i_COP1_FUNCT_CVT_D, base_cop1_d, syn_cop1 }, + { "cvt.w.d", R4300i_COP1_FUNCT_CVT_W, base_cop1_d, syn_cop1 }, + { "cvt.l.d", R4300i_COP1_FUNCT_CVT_L, base_cop1_d, syn_cop1 }, + { "c.f.d", R4300i_COP1_FUNCT_C_F, base_cop1_d, syn_cop1_cmp }, + { "c.un.d", R4300i_COP1_FUNCT_C_UN, base_cop1_d, syn_cop1_cmp }, + { "c.eq.d", R4300i_COP1_FUNCT_C_EQ, base_cop1_d, syn_cop1_cmp }, + { "c.ueq.d", R4300i_COP1_FUNCT_C_UEQ, base_cop1_d, syn_cop1_cmp }, + { "c.olt.d", R4300i_COP1_FUNCT_C_OLT, base_cop1_d, syn_cop1_cmp }, + { "c.ult.d", R4300i_COP1_FUNCT_C_ULT, base_cop1_d, syn_cop1_cmp }, + { "c.ole.d", R4300i_COP1_FUNCT_C_OLE, base_cop1_d, syn_cop1_cmp }, + { "c.ule.d", R4300i_COP1_FUNCT_C_ULE, base_cop1_d, syn_cop1_cmp }, + { "c.sf.d", R4300i_COP1_FUNCT_C_SF, base_cop1_d, syn_cop1_cmp }, + { "c.ngle.d", R4300i_COP1_FUNCT_C_NGLE, base_cop1_d, syn_cop1_cmp }, + { "c.seq.d", R4300i_COP1_FUNCT_C_SEQ, base_cop1_d, syn_cop1_cmp }, + { "c.ngl.d", R4300i_COP1_FUNCT_C_NGL, base_cop1_d, syn_cop1_cmp }, + { "c.lt.d", R4300i_COP1_FUNCT_C_LT, base_cop1_d, syn_cop1_cmp }, + { "c.nge.d", R4300i_COP1_FUNCT_C_NGE, base_cop1_d, syn_cop1_cmp }, + { "c.le.d", R4300i_COP1_FUNCT_C_LE, base_cop1_d, syn_cop1_cmp }, + { "c.ngt.d", R4300i_COP1_FUNCT_C_NGT, base_cop1_d, syn_cop1_cmp }, + { NULL } + }; + + static constexpr ASM_REGISTER m_Registers[] = + { + { "r0", 0 }, { "at", 1 },{ "v0", 2 },{ "v1", 3 },{ "a0", 4 },{ "a1", 5 },{ "a2", 6 },{ "a3", 7 }, + { "t0", 8 }, { "t1", 9 },{ "t2", 10 },{ "t3", 11 },{ "t4", 12 },{ "t5", 13 },{ "t6", 14 },{ "t7", 15 }, + { "s0", 16 }, { "s1", 17 },{ "s2", 18 },{ "s3", 19 },{ "s4", 20 },{ "s5", 21 },{ "s6", 22 },{ "s7", 23 }, + { "t8", 24 }, { "t9", 25 },{ "k0", 26 },{ "k1", 27 },{ "gp", 28 },{ "sp", 29 },{ "s8", 30 },{ "ra", 31 }, + + { "fp", 30 }, + + { "r0", 0 },{ "r1", 1 },{ "r2", 2 },{ "r3", 3 },{ "r4", 4 },{ "r5", 5 },{ "r6", 6 },{ "r7", 7 }, + { "r8", 8 },{ "r9", 9 },{ "r10", 10 },{ "r11", 11 },{ "r12", 12 },{ "r13", 13 },{ "r14", 14 },{ "r15", 15 }, + { "r16", 16 },{ "r17", 17 },{ "r18", 18 },{ "r19", 19 },{ "r20", 20 },{ "r21", 21 },{ "r22", 22 },{ "r23", 23 }, + { "r24", 24 },{ "r25", 25 },{ "r26", 26 },{ "r27", 27 },{ "r28", 28 },{ "r29", 29 },{ "r30", 30 },{ "r31", 31 }, + + { "f0", 0 },{ "f1", 1 },{ "f2", 2 },{ "f3", 3 },{ "f4", 4 },{ "f5", 5 },{ "f6", 6 },{ "f7", 7 }, + { "f8", 8 },{ "f9", 9 },{ "f10", 10 },{ "f11", 11 },{ "f12", 12 },{ "f13", 13 },{ "f14", 14 },{ "f15", 15 }, + { "f16", 16 },{ "f17", 17 },{ "f18", 18 },{ "f19", 19 },{ "f20", 20 },{ "f21", 21 },{ "f22", 22 },{ "f23", 23 }, + { "f24", 24 },{ "f25", 25 },{ "f26", 26 },{ "f27", 27 },{ "f28", 28 },{ "f29", 29 },{ "f30", 30 },{ "f31", 31 }, + + { "revision", 0 }, { "fcsr", 31 }, { "fcs", 31 }, + + { "index", 0 }, { "random", 1 }, { "entrylo0", 2 }, { "entrylo1", 3 }, { "context", 4 }, { "pagemask", 5 }, + { "wired", 6 }, { "badvaddr", 8 }, { "count", 9 }, { "entryhi", 10 }, { "compare", 11 }, { "status", 12 }, + { "cause", 13 }, { "epc", 14 }, { "prid", 15 }, { "config", 16 }, { "lladdr", 17 }, { "watchlo", 18 }, + { "watchhi", 19 }, { "xcontext", 20 }, { "ecc", 26 }, { "cacheerr", 27 }, { "taglo", 28 }, { "taghi", 29 }, + { "errepc", 30 }, + + { NULL } + }; }; From 4bd9611986aa65d4f46825470b7f4ee85a97fa32 Mon Sep 17 00:00:00 2001 From: shygoo Date: Thu, 25 Jan 2018 00:07:51 -0600 Subject: [PATCH 2/2] [Debugger] Add step over button to commands window --- .../Debugger/Debugger-Commands.cpp | 44 +++++++++++++++++-- .../Debugger/Debugger-Commands.h | 5 +++ .../Project64/UserInterface/Debugger/OpInfo.h | 5 +++ Source/Project64/UserInterface/UIResources.rc | 11 +++-- Source/Project64/UserInterface/resource.h | 1 + 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/Source/Project64/UserInterface/Debugger/Debugger-Commands.cpp b/Source/Project64/UserInterface/Debugger/Debugger-Commands.cpp index 61dcff941..d282ac000 100644 --- a/Source/Project64/UserInterface/Debugger/Debugger-Commands.cpp +++ b/Source/Project64/UserInterface/Debugger/Debugger-Commands.cpp @@ -74,6 +74,7 @@ LRESULT CDebugCommandsView::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARA m_PCEdit.Attach(GetDlgItem(IDC_PC_EDIT)); m_ViewPCButton.Attach(GetDlgItem(IDC_VIEWPC_BTN)); m_StepButton.Attach(GetDlgItem(IDC_STEP_BTN)); + m_StepOverButton.Attach(GetDlgItem(IDC_STEPOVER_BTN)); m_SkipButton.Attach(GetDlgItem(IDC_SKIP_BTN)); m_GoButton.Attach(GetDlgItem(IDC_GO_BTN)); m_RegisterTabs.Attach(GetDlgItem(IDC_REG_TABS)); @@ -101,6 +102,7 @@ LRESULT CDebugCommandsView::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARA // Setup View PC button m_ViewPCButton.EnableWindow(FALSE); m_StepButton.EnableWindow(FALSE); + m_StepOverButton.EnableWindow(FALSE); m_SkipButton.EnableWindow(FALSE); m_GoButton.EnableWindow(FALSE); @@ -126,6 +128,7 @@ LRESULT CDebugCommandsView::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARA { m_ViewPCButton.EnableWindow(TRUE); m_StepButton.EnableWindow(TRUE); + m_StepOverButton.EnableWindow(TRUE); m_SkipButton.EnableWindow(TRUE); m_GoButton.EnableWindow(TRUE); } @@ -153,6 +156,7 @@ LRESULT CDebugCommandsView::OnDestroy(void) m_GoButton.Detach(); m_SkipButton.Detach(); m_StepButton.Detach(); + m_StepOverButton.Detach(); m_ViewPCButton.Detach(); m_PCEdit.Detach(); m_AddressEdit.Detach(); @@ -172,9 +176,7 @@ void CDebugCommandsView::InterceptKeyDown(WPARAM wParam, LPARAM /*lParam*/) m_StepEvent.Trigger(); } break; - case VK_F3: - // reserved step over - break; + case VK_F3: CPUStepOver(); break; case VK_F4: CPUResume(); break; } } @@ -487,6 +489,7 @@ void CDebugCommandsView::ShowAddress(uint32_t address, bool top) // Disable buttons m_ViewPCButton.EnableWindow(FALSE); m_StepButton.EnableWindow(FALSE); + m_StepOverButton.EnableWindow(FALSE); m_SkipButton.EnableWindow(FALSE); m_GoButton.EnableWindow(FALSE); @@ -516,6 +519,7 @@ void CDebugCommandsView::ShowAddress(uint32_t address, bool top) // Enable buttons m_ViewPCButton.EnableWindow(TRUE); m_StepButton.EnableWindow(TRUE); + m_StepOverButton.EnableWindow(TRUE); m_SkipButton.EnableWindow(TRUE); m_GoButton.EnableWindow(TRUE); @@ -1085,6 +1089,32 @@ void CDebugCommandsView::CPUResume() } } +void CDebugCommandsView::CPUStepOver() +{ + if (g_MMU == NULL) + { + return; + } + + COpInfo opInfo; + g_MMU->LW_VAddr(g_Reg->m_PROGRAM_COUNTER, opInfo.m_OpCode.Hex); + + if (opInfo.IsJAL()) + { + // put temp BP on return address and resume + m_Breakpoints->AddExecution(g_Reg->m_PROGRAM_COUNTER + 8, true); + CPUResume(); + } + else + { + // normal step + if (WaitingForStep()) + { + m_StepEvent.Trigger(); + } + } +} + LRESULT CDebugCommandsView::OnBackButton(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hwnd*/, BOOL& /*bHandled*/) { if (m_HistoryIndex > 0) @@ -1145,6 +1175,12 @@ LRESULT CDebugCommandsView::OnStepButton(WORD /*wNotifyCode*/, WORD /*wID*/, HWN return FALSE; } +LRESULT CDebugCommandsView::OnStepOverButton(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hwnd*/, BOOL& /*bHandled*/) +{ + CPUStepOver(); + return FALSE; +} + LRESULT CDebugCommandsView::OnSkipButton(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hwnd*/, BOOL& /*bHandled*/) { CPUSkip(); @@ -1497,12 +1533,14 @@ void CDebugCommandsView::WaitingForStepChanged(void) m_Debugger->Debug_RefreshStackWindow(); m_Debugger->Debug_RefreshStackTraceWindow(); m_StepButton.EnableWindow(true); + m_StepOverButton.EnableWindow(true); m_GoButton.EnableWindow(true); m_AddressEdit.SetFocus(); } else { m_StepButton.EnableWindow(false); + m_StepOverButton.EnableWindow(false); m_GoButton.EnableWindow(false); } } diff --git a/Source/Project64/UserInterface/Debugger/Debugger-Commands.h b/Source/Project64/UserInterface/Debugger/Debugger-Commands.h index 47157f8e5..fc4883c25 100644 --- a/Source/Project64/UserInterface/Debugger/Debugger-Commands.h +++ b/Source/Project64/UserInterface/Debugger/Debugger-Commands.h @@ -103,6 +103,7 @@ private: COMMAND_HANDLER(ID_POPUPMENU_RUNTO, BN_CLICKED, OnPopupmenuRunTo) COMMAND_HANDLER(IDC_GO_BTN, BN_CLICKED, OnGoButton) COMMAND_HANDLER(IDC_STEP_BTN, BN_CLICKED, OnStepButton) + COMMAND_HANDLER(IDC_STEPOVER_BTN, BN_CLICKED, OnStepOverButton) COMMAND_HANDLER(IDC_SKIP_BTN, BN_CLICKED, OnSkipButton) COMMAND_HANDLER(IDC_CLEARBP_BTN, BN_CLICKED, OnClearBPButton) COMMAND_HANDLER(IDC_ADDBP_BTN, BN_CLICKED, OnAddBPButton) @@ -150,6 +151,7 @@ private: BEGIN_TOOLTIP_MAP() TOOLTIP(IDC_SKIP_BTN, "Skip (F1)") TOOLTIP(IDC_STEP_BTN, "Step (F2)") + TOOLTIP(IDC_STEP_BTN, "Step Over (F3)") TOOLTIP(IDC_GO_BTN, "Go (F4)") TOOLTIP(IDC_ADDBP_BTN, "Add breakpoint...") TOOLTIP(IDC_RMBP_BTN, "Remove selected breakpoint") @@ -176,6 +178,7 @@ private: LRESULT OnPopupmenuRunTo(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& bHandled); LRESULT OnGoButton(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& bHandled); LRESULT OnStepButton(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& bHandled); + LRESULT OnStepOverButton(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& bHandled); LRESULT OnSkipButton(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& bHandled); LRESULT OnClearBPButton(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& bHandled); LRESULT OnAddBPButton(WORD wNotifyCode, WORD wID, HWND hwnd, BOOL& bHandled); @@ -229,6 +232,7 @@ private: void CPUSkip(); void CPUResume(); + void CPUStepOver(); void WaitingForStepChanged(void); void SteppingOpsChanged(void); @@ -265,6 +269,7 @@ private: CButton m_ViewPCButton; CButton m_StepButton; + CButton m_StepOverButton; CButton m_SkipButton; CButton m_GoButton; diff --git a/Source/Project64/UserInterface/Debugger/OpInfo.h b/Source/Project64/UserInterface/Debugger/OpInfo.h index 252ec5f84..bba22f505 100644 --- a/Source/Project64/UserInterface/Debugger/OpInfo.h +++ b/Source/Project64/UserInterface/Debugger/OpInfo.h @@ -80,6 +80,11 @@ public: return false; } + bool IsJAL() + { + return (m_OpCode.op == R4300i_JAL || (m_OpCode.op == R4300i_SPECIAL && m_OpCode.funct == R4300i_SPECIAL_JALR)); + } + bool IsBranch() { uint32_t op = m_OpCode.op; diff --git a/Source/Project64/UserInterface/UIResources.rc b/Source/Project64/UserInterface/UIResources.rc index 4fc7414e9..ce280bcbe 100644 --- a/Source/Project64/UserInterface/UIResources.rc +++ b/Source/Project64/UserInterface/UIResources.rc @@ -683,9 +683,10 @@ BEGIN PUSHBUTTON "‹",IDC_BACK_BTN,286,1,11,15,WS_DISABLED PUSHBUTTON "›",IDC_FORWARD_BTN,298,1,11,15,WS_DISABLED PUSHBUTTON "...",IDC_SYMBOLS_BTN,357,1,17,15 - PUSHBUTTON "Skip",IDC_SKIP_BTN,380,1,35,15,WS_DISABLED - PUSHBUTTON "Step",IDC_STEP_BTN,416,1,35,15,WS_DISABLED - PUSHBUTTON "Go",IDC_GO_BTN,452,1,35,15,WS_DISABLED + PUSHBUTTON "Skip",IDC_SKIP_BTN,376,1,27,15,WS_DISABLED + PUSHBUTTON "Step",IDC_STEP_BTN,404,1,27,15,WS_DISABLED + PUSHBUTTON "St.Ovr", IDC_STEPOVER_BTN, 432, 1, 27, 15, WS_DISABLED + PUSHBUTTON "Go",IDC_GO_BTN,460,1,27,15,WS_DISABLED LTEXT "PC",IDC_PC_STATIC,292,24,8,9 EDITTEXT IDC_PC_EDIT,303,22,44,12,ES_UPPERCASE | ES_AUTOHSCROLL,WS_EX_RIGHT PUSHBUTTON "View",IDC_VIEWPC_BTN,348,22,30,13,WS_DISABLED @@ -1840,9 +1841,11 @@ BEGIN 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 100 + 0, 0, 0, 100, + 0, 0, 0, 0 END + ///////////////////////////////////////////////////////////////////////////// // // Dialog Info diff --git a/Source/Project64/UserInterface/resource.h b/Source/Project64/UserInterface/resource.h index 46ab7ffc7..5c87a4f7a 100644 --- a/Source/Project64/UserInterface/resource.h +++ b/Source/Project64/UserInterface/resource.h @@ -292,6 +292,7 @@ #define IDC_STEP_BTN 1119 #define IDC_ADDSYMBOL_BTN 1119 #define IDC_NOTES 1120 +#define IDC_STEPOVER_BTN 1120 #define IDC_CHEAT_LIST 1121 #define IDC_CHEAT_NAME 1122 #define IDC_DELAY_SI 1123