diff --git a/src/crash_screen/pages/page_stack.c b/src/crash_screen/pages/page_stack.c index 2459a7eb1..f4d36bb19 100644 --- a/src/crash_screen/pages/page_stack.c +++ b/src/crash_screen/pages/page_stack.c @@ -96,7 +96,7 @@ _Bool stacktrace_step(Address** sp, Address** ra, Address addr) { const size_t numInsnsInFunc = MIN(STACK_TRACE_MAX_INSN_SCAN, (symbol->size / sizeof(InsnData))); for (size_t i = 0; i < numInsnsInFunc; i++) { InsnData insn = *insnPtr; - u16 insnHi = (insn.raw >> 16); + u16 insnHi = insn.hi; s16 imm = insn.immediate; //! TODO: Use defines/enums for insn check magic values: diff --git a/src/crash_screen/util/insn_db.inc.c b/src/crash_screen/util/insn_db.inc.c index a761b7733..4527cbf67 100644 --- a/src/crash_screen/util/insn_db.inc.c +++ b/src/crash_screen/util/insn_db.inc.c @@ -36,217 +36,217 @@ ALIGNED32 static const InsnTemplate insn_db_standard[] = { // INSN_TYPE_OPCODE // OPC_SPECIAL (insn_db_spec) // 0: OPC_SPECIAL, INSN_TYPE_FUNC // OPC_REGIMM (insn_db_regi) // 1: OPC_REGIMM, INSN_TYPE_REGIMM - INSN_DB(OPC_J, "J ", FALSE, IFMT_J, 0, PSI_J ), // 2: Jump. - INSN_DB(OPC_JAL, "JAL ", FALSE, IFMT_J, 0, PSI_JAL ), // 3: Jump and Link. - INSN_DB(OPC_BEQ, "BEQ ", FALSE, IFMT_stB, 0, PSI_BEQ ), // 4: Branch on Equal. - INSN_DB(OPC_BNE, "BNE ", FALSE, IFMT_stB, 0, PSI_BNE ), // 5: Branch on Not Equal. - INSN_DB(OPC_BLEZ, "BLEZ ", FALSE, IFMT_sB, 0, PSI_BLEZ ), // 6: Branch on Less Than or Equal to Zero. - INSN_DB(OPC_BGTZ, "BGTZ ", FALSE, IFMT_sB, 0, PSI_BGTZ ), // 7: Branch on Greater Than Zero. - INSN_DB(OPC_ADDI, "ADDI ", FALSE, IFMT_tsI, 1, PSI_ADDI ), // 8: Add Immediate Word. - INSN_DB(OPC_ADDIU, "ADDIU ", FALSE, IFMT_tsI, 1, PSI_ADDI ), // 9: Add Immediate Unsigned Word. - INSN_DB(OPC_SLTI, "SLTI ", FALSE, IFMT_tsI, 1, PSI_SLTI ), // 10: Set on Less Than Immediate. - INSN_DB(OPC_SLTIU, "SLTIU ", FALSE, IFMT_tsI, 1, PSI_SLTI ), // 11: Set on Less Than Immediate Unsigned. - INSN_DB(OPC_ANDI, "ANDI ", FALSE, IFMT_tsI, 1, PSI_ANDI ), // 12: And Immediate. - INSN_DB(OPC_ORI, "ORI ", FALSE, IFMT_tsI, 1, PSI_ORI ), // 13: Or Immediate. - INSN_DB(OPC_XORI, "XORI ", FALSE, IFMT_tsI, 1, PSI_XORI ), // 14: Exclusive Or Immediate. - INSN_DB(OPC_LUI, "LUI ", FALSE, IFMT_tI, 1, PSI_LUI ), // 15: Load Upper Immediate. + INSN_DB(OPC_J, "j ", FALSE, IFMT_J, 0, PSI_J ), // 2: Jump. + INSN_DB(OPC_JAL, "jal ", FALSE, IFMT_J, 0, PSI_JAL ), // 3: Jump and Link. + INSN_DB(OPC_BEQ, "beq ", FALSE, IFMT_stB, 0, PSI_BEQ ), // 4: Branch on Equal. + INSN_DB(OPC_BNE, "bne ", FALSE, IFMT_stB, 0, PSI_BNE ), // 5: Branch on Not Equal. + INSN_DB(OPC_BLEZ, "blez ", FALSE, IFMT_sB, 0, PSI_BLEZ ), // 6: Branch on Less Than or Equal to Zero. + INSN_DB(OPC_BGTZ, "bgtz ", FALSE, IFMT_sB, 0, PSI_BGTZ ), // 7: Branch on Greater Than Zero. + INSN_DB(OPC_ADDI, "addi ", FALSE, IFMT_tsI, 1, PSI_ADDI ), // 8: Add Immediate Word. + INSN_DB(OPC_ADDIU, "addiu ", FALSE, IFMT_tsI, 1, PSI_ADDI ), // 9: Add Immediate Unsigned Word. + INSN_DB(OPC_SLTI, "slti ", FALSE, IFMT_tsI, 1, PSI_SLTI ), // 10: Set on Less Than Immediate. + INSN_DB(OPC_SLTIU, "sltiu ", FALSE, IFMT_tsI, 1, PSI_SLTI ), // 11: Set on Less Than Immediate Unsigned. + INSN_DB(OPC_ANDI, "andi ", FALSE, IFMT_tsI, 1, PSI_ANDI ), // 12: And Immediate. + INSN_DB(OPC_ORI, "ori ", FALSE, IFMT_tsI, 1, PSI_ORI ), // 13: Or Immediate. + INSN_DB(OPC_XORI, "xori ", FALSE, IFMT_tsI, 1, PSI_XORI ), // 14: Exclusive Or Immediate. + INSN_DB(OPC_LUI, "lui ", FALSE, IFMT_tI, 1, PSI_LUI ), // 15: Load Upper Immediate. // OPC_COP0 (insn_db_cop0) // 16: Coprocessor-0 (System Control Coprocessor). // OPC_COP1 (insn_db_cop1) // 17: Coprocessor-1 (Floating-Point Unit). // OPC_COP2 (insn_db_cop2) // 18: Coprocessor-2 (Reality Co-Processor Vector Unit). // OPC_COP3 (insn_db_cop3) // 19: Coprocessor-3 (CP3). - INSN_DB(OPC_BEQL, "BEQL ", FALSE, IFMT_stB, 0, PSI_BEQ ), // 20: Branch on Equal Likely. - INSN_DB(OPC_BNEL, "BNEL ", FALSE, IFMT_stB, 0, PSI_BNE ), // 21: Branch on Not Equal Likely. - INSN_DB(OPC_BLEZL, "BLEZL ", FALSE, IFMT_sB, 0, PSI_BLEZ ), // 22: Branch on Less Than or Equal to Zero Likely. - INSN_DB(OPC_BGTZL, "BGTZL ", FALSE, IFMT_sB, 0, PSI_BGTZ ), // 23: Branch on Greater Than Zero Likely. - INSN_DB(OPC_DADDI, "DADDI ", FALSE, IFMT_tsI, 1, PSI_ADDI ), // 24: Doubleword Add Immediate. - INSN_DB(OPC_DADDIU, "DADDIU ", FALSE, IFMT_tsI, 1, PSI_ADDI ), // 25: Doubleword Add Immediate Unsigned. - INSN_DB(OPC_LDL, "LDL ", FALSE, IFMT_to, 1, PSI_L_L ), // 26: Load Doubleword Left. - INSN_DB(OPC_LDR, "LDR ", FALSE, IFMT_to, 1, PSI_L_R ), // 27: Load Doubleword Right. - INSN_DB(OPC_LB, "LB ", FALSE, IFMT_to, 1, PSI_L ), // 32: Load Byte. - INSN_DB(OPC_LH, "LH ", FALSE, IFMT_to, 1, PSI_L ), // 33: Load Halfword. - INSN_DB(OPC_LWL, "LWL ", FALSE, IFMT_to, 1, PSI_L_L ), // 34: Load Word Left. - INSN_DB(OPC_LW, "LW ", FALSE, IFMT_to, 1, PSI_L ), // 35: Load Word. - INSN_DB(OPC_LBU, "LBU ", FALSE, IFMT_to, 1, PSI_L ), // 36: Load Byte Unsigned. - INSN_DB(OPC_LHU, "LHU ", FALSE, IFMT_to, 1, PSI_L ), // 37: Load Halfword Unsigned. - INSN_DB(OPC_LWR, "LWR ", FALSE, IFMT_to, 1, PSI_L_R ), // 38: Load Word Right. - INSN_DB(OPC_LWU, "LWU ", FALSE, IFMT_to, 1, PSI_L ), // 39: Load Word Unsigned. - INSN_DB(OPC_SB, "SB ", FALSE, IFMT_to, 0, PSI_S ), // 40: Store Byte. - INSN_DB(OPC_SH, "SH ", FALSE, IFMT_to, 0, PSI_S ), // 41: Store Halfword. - INSN_DB(OPC_SWL, "SWL ", FALSE, IFMT_to, 0, PSI_S_L ), // 42: Store Word Left. - INSN_DB(OPC_SW, "SW ", FALSE, IFMT_to, 0, PSI_S ), // 43: Store Word. - INSN_DB(OPC_SDL, "SDL ", FALSE, IFMT_to, 0, PSI_S_L ), // 44: Store Doubleword Left. - INSN_DB(OPC_SDR, "SDR ", FALSE, IFMT_to, 0, PSI_S_R ), // 45: Store Doubleword Right. - INSN_DB(OPC_SWR, "SWR ", FALSE, IFMT_to, 0, PSI_S_R ), // 46: Store Word Right. - INSN_DB(OPC_CACHE, "CACHE ", FALSE, IFMT_to, 0, PSI_CACHE), // 47: https://techpubs.jurassic.nl/manuals/hdwr/developer/R10K_UM/sgi_html/t5.Ver.2.0.book_301.html. - INSN_EX(OPC_LL, "LL ", FALSE, IFMT_to, 1, PSI_LL, EXR_LL, EXR_00, 0b10), // 48: Load Linked Word. - INSN_DB(OPC_LWC1, "LWC1 ", FALSE, IFMT_To, 1, PSI_LC1 ), // 49: Load Word to Coprocessor-1 (Floating-Point Unit). - INSN_DB(OPC_LWC2, "LWC2 ", FALSE, IFMT_to, 1, PSI_L ), // 50: Load Word to Coprocessor-2 (Reality Co-Processor Vector Unit). - INSN_DB(OPC_LWC3, "LWC3 ", FALSE, IFMT_to, 1, PSI_L ), // 51: Load Word to Coprocessor-3 (COP3). - INSN_EX(OPC_LLD , "LLD ", FALSE, IFMT_to, 1, PSI_LL, EXR_LL, EXR_00, 0b10), // 52: Load Linked Doubleword. - INSN_DB(OPC_LDC1, "LDC1 ", FALSE, IFMT_To, 1, PSI_LC1 ), // 53: Load Doubleword to Coprocessor-1 (Floating-Point Unit). - INSN_DB(OPC_LDC2, "LDC2 ", FALSE, IFMT_to, 1, PSI_L ), // 54: Load Doubleword to Coprocessor-2 (Reality Co-Processor Vector Unit). - INSN_DB(OPC_LD, "LD ", FALSE, IFMT_to, 1, PSI_L ), // 55: Load Doubleword. - INSN_DB(OPC_SC, "SC ", FALSE, IFMT_to, 0, PSI_SC ), // 56: Store Conditional Word. - INSN_DB(OPC_SWC1, "SWC1 ", FALSE, IFMT_To, 0, PSI_SC1 ), // 57: Store Word to Coprocessor-1 (Floating-Point Unit). - INSN_DB(OPC_SWC2, "SWC2 ", FALSE, IFMT_to, 0, PSI_S ), // 58: Store Word to Coprocessor-2 (Reality Co-Processor Vector Unit). - INSN_DB(OPC_SWC3, "SWC3 ", FALSE, IFMT_to, 0, PSI_S ), // 59: Store Word to Coprocessor-3 (COP3). - INSN_EX(OPC_SCD, "SCD ", FALSE, IFMT_to, 0, PSI_SC, EXR_LL, EXR_00, 0b00), // 60: Store Conditional Doubleword. - INSN_DB(OPC_SDC1, "SDC1 ", FALSE, IFMT_To, 0, PSI_SC1 ), // 61: Store Doubleword to Coprocessor-1 (Floating-Point Unit). - INSN_DB(OPC_SDC2, "SDC2 ", FALSE, IFMT_to, 0, PSI_S ), // 62: Store Doubleword to Coprocessor-2 (Reality Co-Processor Vector Unit). - INSN_EX(OPC_SD, "SD ", FALSE, IFMT_to, 0, PSI_S, EXR_LL, EXR_00, 0b00), // 63: Store Doubleword. + INSN_DB(OPC_BEQL, "beql ", FALSE, IFMT_stB, 0, PSI_BEQ ), // 20: Branch on Equal Likely. + INSN_DB(OPC_BNEL, "bnel ", FALSE, IFMT_stB, 0, PSI_BNE ), // 21: Branch on Not Equal Likely. + INSN_DB(OPC_BLEZL, "blezl ", FALSE, IFMT_sB, 0, PSI_BLEZ ), // 22: Branch on Less Than or Equal to Zero Likely. + INSN_DB(OPC_BGTZL, "bgtzl ", FALSE, IFMT_sB, 0, PSI_BGTZ ), // 23: Branch on Greater Than Zero Likely. + INSN_DB(OPC_DADDI, "daddi ", FALSE, IFMT_tsI, 1, PSI_ADDI ), // 24: Doubleword Add Immediate. + INSN_DB(OPC_DADDIU, "daddiu ", FALSE, IFMT_tsI, 1, PSI_ADDI ), // 25: Doubleword Add Immediate Unsigned. + INSN_DB(OPC_LDL, "ldl ", FALSE, IFMT_to, 1, PSI_L_L ), // 26: Load Doubleword Left. + INSN_DB(OPC_LDR, "ldr ", FALSE, IFMT_to, 1, PSI_L_R ), // 27: Load Doubleword Right. + INSN_DB(OPC_LB, "lb ", FALSE, IFMT_to, 1, PSI_L ), // 32: Load Byte. + INSN_DB(OPC_LH, "lh ", FALSE, IFMT_to, 1, PSI_L ), // 33: Load Halfword. + INSN_DB(OPC_LWL, "lwL ", FALSE, IFMT_to, 1, PSI_L_L ), // 34: Load Word Left. + INSN_DB(OPC_LW, "lw ", FALSE, IFMT_to, 1, PSI_L ), // 35: Load Word. + INSN_DB(OPC_LBU, "lbu ", FALSE, IFMT_to, 1, PSI_L ), // 36: Load Byte Unsigned. + INSN_DB(OPC_LHU, "lhu ", FALSE, IFMT_to, 1, PSI_L ), // 37: Load Halfword Unsigned. + INSN_DB(OPC_LWR, "lwr ", FALSE, IFMT_to, 1, PSI_L_R ), // 38: Load Word Right. + INSN_DB(OPC_LWU, "lwu ", FALSE, IFMT_to, 1, PSI_L ), // 39: Load Word Unsigned. + INSN_DB(OPC_SB, "sb ", FALSE, IFMT_to, 0, PSI_S ), // 40: Store Byte. + INSN_DB(OPC_SH, "sh ", FALSE, IFMT_to, 0, PSI_S ), // 41: Store Halfword. + INSN_DB(OPC_SWL, "swl ", FALSE, IFMT_to, 0, PSI_S_L ), // 42: Store Word Left. + INSN_DB(OPC_SW, "sw ", FALSE, IFMT_to, 0, PSI_S ), // 43: Store Word. + INSN_DB(OPC_SDL, "sdl ", FALSE, IFMT_to, 0, PSI_S_L ), // 44: Store Doubleword Left. + INSN_DB(OPC_SDR, "sdr ", FALSE, IFMT_to, 0, PSI_S_R ), // 45: Store Doubleword Right. + INSN_DB(OPC_SWR, "swr ", FALSE, IFMT_to, 0, PSI_S_R ), // 46: Store Word Right. + INSN_DB(OPC_CACHE, "cache ", FALSE, IFMT_to, 0, PSI_CACHE), // 47: https://techpubs.jurassic.nl/manuals/hdwr/developer/R10K_UM/sgi_html/t5.Ver.2.0.book_301.html. + INSN_EX(OPC_LL, "ll ", FALSE, IFMT_to, 1, PSI_LL, EXR_LL, EXR_00, 0b10), // 48: Load Linked Word. + INSN_DB(OPC_LWC1, "lwc1 ", FALSE, IFMT_To, 1, PSI_LC1 ), // 49: Load Word to Coprocessor-1 (Floating-Point Unit). + INSN_DB(OPC_LWC2, "lwc2 ", FALSE, IFMT_to, 1, PSI_L ), // 50: Load Word to Coprocessor-2 (Reality Co-Processor Vector Unit). + INSN_DB(OPC_LWC3, "lwc3 ", FALSE, IFMT_to, 1, PSI_L ), // 51: Load Word to Coprocessor-3 (COP3). + INSN_EX(OPC_LLD , "lld ", FALSE, IFMT_to, 1, PSI_LL, EXR_LL, EXR_00, 0b10), // 52: Load Linked Doubleword. + INSN_DB(OPC_LDC1, "ldc1 ", FALSE, IFMT_To, 1, PSI_LC1 ), // 53: Load Doubleword to Coprocessor-1 (Floating-Point Unit). + INSN_DB(OPC_LDC2, "ldc2 ", FALSE, IFMT_to, 1, PSI_L ), // 54: Load Doubleword to Coprocessor-2 (Reality Co-Processor Vector Unit). + INSN_DB(OPC_LD, "ld ", FALSE, IFMT_to, 1, PSI_L ), // 55: Load Doubleword. + INSN_DB(OPC_SC, "sc ", FALSE, IFMT_to, 0, PSI_SC ), // 56: Store Conditional Word. + INSN_DB(OPC_SWC1, "swc1 ", FALSE, IFMT_To, 0, PSI_SC1 ), // 57: Store Word to Coprocessor-1 (Floating-Point Unit). + INSN_DB(OPC_SWC2, "swc2 ", FALSE, IFMT_to, 0, PSI_S ), // 58: Store Word to Coprocessor-2 (Reality Co-Processor Vector Unit). + INSN_DB(OPC_SWC3, "swc3 ", FALSE, IFMT_to, 0, PSI_S ), // 59: Store Word to Coprocessor-3 (COP3). + INSN_EX(OPC_SCD, "scd ", FALSE, IFMT_to, 0, PSI_SC, EXR_LL, EXR_00, 0b00), // 60: Store Conditional Doubleword. + INSN_DB(OPC_SDC1, "sdc1 ", FALSE, IFMT_To, 0, PSI_SC1 ), // 61: Store Doubleword to Coprocessor-1 (Floating-Point Unit). + INSN_DB(OPC_SDC2, "sdc2 ", FALSE, IFMT_to, 0, PSI_S ), // 62: Store Doubleword to Coprocessor-2 (Reality Co-Processor Vector Unit). + INSN_EX(OPC_SD, "sd ", FALSE, IFMT_to, 0, PSI_S, EXR_LL, EXR_00, 0b00), // 63: Store Doubleword. INSN_END(), // NULL terminator. }; // Special opcode instructions: ALIGNED32 static const InsnTemplate insn_db_spec[] = { // OPC_SPECIAL, INSN_TYPE_FUNC - INSN_DB(OPS_SLL, "SLL ", FALSE, IFMT_dta, 1, PSI_SLI ), // 0: Shift Word Left Logical. - INSN_DB(OPS_SRL, "SRL ", FALSE, IFMT_dta, 1, PSI_SRI ), // 2: Shift Word Right Logical. - INSN_DB(OPS_SRA, "SRA ", FALSE, IFMT_dta, 1, PSI_SRI ), // 3: Shift Word Right Arithmetic. - INSN_DB(OPS_SLLV, "SLLV ", FALSE, IFMT_dts, 1, PSI_SLV ), // 4: Shift Word Left Logical Variable. - INSN_DB(OPS_SRLV, "SRLV ", FALSE, IFMT_dts, 1, PSI_SRV ), // 6: Shift Word Right Logical Variable. - INSN_DB(OPS_SRAV, "SRAV ", FALSE, IFMT_dts, 1, PSI_SRV ), // 7: Shift Word Right Arithmetic Variable. - INSN_DB(OPS_JR, "JR ", FALSE, IFMT_s, 0, PSI_JR ), // 8: Jump Register. - INSN_DB(OPS_JALR, "JALR ", FALSE, IFMT_ds, 1, PSI_JALR ), // 9: Jump and Link Register. - INSN_DB(OPS_SYSCALL, "SYSCALL", FALSE, IFMT_E, 0, PSI_BREAK ), // 12: System Call (assert). - INSN_DB(OPS_BREAK, "BREAK ", FALSE, IFMT_E, 0, PSI_BREAK ), // 13: Breakpoint. - INSN_DB(OPS_SYNC, "SYNC ", FALSE, IFMT_NOP, 0, PSI_FUNC ), // 15: Synchronize Shared Memory. - INSN_EX(OPS_MFHI, "MFHI ", FALSE, IFMT_d, 0, PSI_MFHI, EXR_HI, EXR_00, 0b00), // 16: Move From HI. - INSN_EX(OPS_MTHI, "MTHI ", FALSE, IFMT_s, 0, PSI_MTHI, EXR_HI, EXR_00, 0b11), // 17: Move To HI. - INSN_EX(OPS_MFLO, "MFLO ", FALSE, IFMT_d, 0, PSI_MFLO, EXR_LO, EXR_00, 0b00), // 18: Move From LO. - INSN_EX(OPS_MTLO, "MTLO ", FALSE, IFMT_s, 0, PSI_MTLO, EXR_LO, EXR_00, 0b11), // 19: Move To LO. - INSN_DB(OPS_DSLLV, "DSLLV ", FALSE, IFMT_dts, 1, PSI_SLV ), // 20: Doubleword Shift Left Logical Variable. - INSN_DB(OPS_DSRLV, "DSRLV ", FALSE, IFMT_dts, 1, PSI_SRV ), // 22: Doubleword Shift Right Logical Variable. - INSN_DB(OPS_DSRAV, "DSRAV ", FALSE, IFMT_dts, 1, PSI_SRV ), // 23: Doubleword Shift Right Arithmetic Variable. - INSN_EX(OPS_MULT, "MULT ", FALSE, IFMT_st, 0, PSI_MULT, EXR_HI, EXR_LO, 0b11), // 24: Multiply Word (5cyc). - INSN_EX(OPS_MULTU, "MULTU ", FALSE, IFMT_st, 0, PSI_MULT, EXR_HI, EXR_LO, 0b11), // 25: Multiply Unsigned Word (5cyc). - INSN_EX(OPS_DIV, "DIV ", FALSE, IFMT_st, 0, PSI_DIV, EXR_HI, EXR_LO, 0b11), // 26: Divide Word (37cyc). - INSN_EX(OPS_DIVU, "DIVU ", FALSE, IFMT_st, 0, PSI_DIV, EXR_HI, EXR_LO, 0b11), // 27: Divide Unsigned Word (37cyc). - INSN_EX(OPS_DMULT, "DMULT ", FALSE, IFMT_st, 0, PSI_MULT, EXR_HI, EXR_LO, 0b11), // 28: Doubleword Multiply (8cyc). - INSN_EX(OPS_DMULTU, "DMULTU ", FALSE, IFMT_st, 0, PSI_MULT, EXR_HI, EXR_LO, 0b11), // 29: Doubleword Multiply Unsigned (8cyc). - INSN_EX(OPS_DDIV, "DDIV ", FALSE, IFMT_st, 0, PSI_DIV, EXR_HI, EXR_LO, 0b11), // 30: Doubleword Divide (69cyc). - INSN_EX(OPS_DDIVU, "DDIVU ", FALSE, IFMT_st, 0, PSI_DIV, EXR_HI, EXR_LO, 0b11), // 31: Doubleword Divide Unsigned (69cyc). - INSN_DB(OPS_ADD, "ADD ", FALSE, IFMT_dst, 1, PSI_ADD ), // 32: Add Word. - INSN_DB(OPS_ADDU, "ADDU ", FALSE, IFMT_dst, 1, PSI_ADD ), // 33: Add Unsigned Word. - INSN_DB(OPS_SUB, "SUB ", FALSE, IFMT_dst, 1, PSI_SUB ), // 34: Subtract Word. - INSN_DB(OPS_SUBU, "SUBU ", FALSE, IFMT_dst, 1, PSI_SUB ), // 35: Subtract Unsigned Word. - INSN_DB(OPS_AND, "AND ", FALSE, IFMT_dst, 1, PSI_AND ), // 36: And. - INSN_DB(OPS_OR, "OR ", FALSE, IFMT_dst, 1, PSI_OR ), // 37: Or. - INSN_DB(OPS_XOR, "XOR ", FALSE, IFMT_dst, 1, PSI_XOR ), // 38: Exclusive Or. - INSN_DB(OPS_NOR, "NOR ", FALSE, IFMT_dst, 1, PSI_NOR ), // 39: Nor. - INSN_DB(OPS_SLT, "SLT ", FALSE, IFMT_dst, 1, PSI_SLT ), // 42: Set on Less Than. - INSN_DB(OPS_SLTU, "SLTU ", FALSE, IFMT_dst, 1, PSI_SLT ), // 43: Set on Less Than Unsigned. - INSN_DB(OPS_DADD, "DADD ", FALSE, IFMT_dst, 1, PSI_ADD ), // 44: Doubleword Add. - INSN_DB(OPS_DADDU, "DADDU ", FALSE, IFMT_dst, 1, PSI_ADD ), // 45: Doubleword Add Unsigned. - INSN_DB(OPS_DSUB, "DSUB ", FALSE, IFMT_dst, 1, PSI_SUB ), // 46: Doubleword Subtract. - INSN_DB(OPS_DSUBU, "DSUBU ", FALSE, IFMT_dst, 1, PSI_SUB ), // 47: Doubleword Subtract Unsigned. - INSN_DB(OPS_TGE, "TGE ", FALSE, IFMT_ste, 0, PSI_TGE ), // 48: Trap if Greater Than or Equal. - INSN_DB(OPS_TGEU, "TGEU ", FALSE, IFMT_ste, 0, PSI_TGE ), // 49: Trap if Greater Than or Equal Unsigned. - INSN_DB(OPS_TLT, "TLT ", FALSE, IFMT_ste, 0, PSI_TLT ), // 50: Trap if Less Than. - INSN_DB(OPS_TLTU, "TLTU ", FALSE, IFMT_ste, 0, PSI_TLT ), // 51: Trap if Less Than Unsigned. - INSN_DB(OPS_TEQ, "TEQ ", FALSE, IFMT_ste, 0, PSI_TEQ ), // 52: Trap if Equal. - INSN_DB(OPS_TNE, "TNE ", FALSE, IFMT_ste, 0, PSI_TEQ ), // 54: Trap if Not Equal. - INSN_DB(OPS_DSLL, "DSLL ", FALSE, IFMT_dta, 1, PSI_SLI ), // 56: Doubleword Shift Left Logical. - INSN_DB(OPS_DSRL, "DSRL ", FALSE, IFMT_dta, 1, PSI_SRI ), // 58: Doubleword Shift Right Logical. - INSN_DB(OPS_DSRA, "DSRA ", FALSE, IFMT_dta, 1, PSI_SRI ), // 59: Doubleword Shift Right Arithmetic. - INSN_DB(OPS_DSLL32, "DSLL32 ", FALSE, IFMT_dta, 1, PSI_DSLI32 ), // 60: Doubleword Shift Left Logical + 32. - INSN_DB(OPS_DSRL32, "DSRL32 ", FALSE, IFMT_dta, 1, PSI_DSRI32 ), // 62: Doubleword Shift Right Logical + 32. - INSN_DB(OPS_DSRA32, "DSRA32 ", FALSE, IFMT_dta, 1, PSI_DSRI32 ), // 63: Doubleword Shift Right Arithmetic + 32. + INSN_DB(OPS_SLL, "sll ", FALSE, IFMT_dta, 1, PSI_SLI ), // 0: Shift Word Left Logical. + INSN_DB(OPS_SRL, "srl ", FALSE, IFMT_dta, 1, PSI_SRI ), // 2: Shift Word Right Logical. + INSN_DB(OPS_SRA, "sra ", FALSE, IFMT_dta, 1, PSI_SRI ), // 3: Shift Word Right Arithmetic. + INSN_DB(OPS_SLLV, "sllV ", FALSE, IFMT_dts, 1, PSI_SLV ), // 4: Shift Word Left Logical Variable. + INSN_DB(OPS_SRLV, "srlV ", FALSE, IFMT_dts, 1, PSI_SRV ), // 6: Shift Word Right Logical Variable. + INSN_DB(OPS_SRAV, "sraV ", FALSE, IFMT_dts, 1, PSI_SRV ), // 7: Shift Word Right Arithmetic Variable. + INSN_DB(OPS_JR, "jr ", FALSE, IFMT_s, 0, PSI_JR ), // 8: Jump Register. + INSN_DB(OPS_JALR, "jalr ", FALSE, IFMT_ds, 1, PSI_JALR ), // 9: Jump and Link Register. + INSN_DB(OPS_SYSCALL, "syscall", FALSE, IFMT_E, 0, PSI_BREAK ), // 12: System Call (assert). + INSN_DB(OPS_BREAK, "break ", FALSE, IFMT_E, 0, PSI_BREAK ), // 13: Breakpoint. + INSN_DB(OPS_SYNC, "sync ", FALSE, IFMT_NOP, 0, PSI_FUNC ), // 15: Synchronize Shared Memory. + INSN_EX(OPS_MFHI, "mfhi ", FALSE, IFMT_d, 0, PSI_MFHI, EXR_HI, EXR_00, 0b00), // 16: Move From HI. + INSN_EX(OPS_MTHI, "mthi ", FALSE, IFMT_s, 0, PSI_MTHI, EXR_HI, EXR_00, 0b11), // 17: Move To HI. + INSN_EX(OPS_MFLO, "mflo ", FALSE, IFMT_d, 0, PSI_MFLO, EXR_LO, EXR_00, 0b00), // 18: Move From LO. + INSN_EX(OPS_MTLO, "mtlo ", FALSE, IFMT_s, 0, PSI_MTLO, EXR_LO, EXR_00, 0b11), // 19: Move To LO. + INSN_DB(OPS_DSLLV, "dsllv ", FALSE, IFMT_dts, 1, PSI_SLV ), // 20: Doubleword Shift Left Logical Variable. + INSN_DB(OPS_DSRLV, "dsrlv ", FALSE, IFMT_dts, 1, PSI_SRV ), // 22: Doubleword Shift Right Logical Variable. + INSN_DB(OPS_DSRAV, "dsrav ", FALSE, IFMT_dts, 1, PSI_SRV ), // 23: Doubleword Shift Right Arithmetic Variable. + INSN_EX(OPS_MULT, "mult ", FALSE, IFMT_st, 0, PSI_MULT, EXR_HI, EXR_LO, 0b11), // 24: Multiply Word (5cyc). + INSN_EX(OPS_MULTU, "multu ", FALSE, IFMT_st, 0, PSI_MULT, EXR_HI, EXR_LO, 0b11), // 25: Multiply Unsigned Word (5cyc). + INSN_EX(OPS_DIV, "div ", FALSE, IFMT_st, 0, PSI_DIV, EXR_HI, EXR_LO, 0b11), // 26: Divide Word (37cyc). + INSN_EX(OPS_DIVU, "divu ", FALSE, IFMT_st, 0, PSI_DIV, EXR_HI, EXR_LO, 0b11), // 27: Divide Unsigned Word (37cyc). + INSN_EX(OPS_DMULT, "dmult ", FALSE, IFMT_st, 0, PSI_MULT, EXR_HI, EXR_LO, 0b11), // 28: Doubleword Multiply (8cyc). + INSN_EX(OPS_DMULTU, "dmultu ", FALSE, IFMT_st, 0, PSI_MULT, EXR_HI, EXR_LO, 0b11), // 29: Doubleword Multiply Unsigned (8cyc). + INSN_EX(OPS_DDIV, "ddiv ", FALSE, IFMT_st, 0, PSI_DIV, EXR_HI, EXR_LO, 0b11), // 30: Doubleword Divide (69cyc). + INSN_EX(OPS_DDIVU, "ddivu ", FALSE, IFMT_st, 0, PSI_DIV, EXR_HI, EXR_LO, 0b11), // 31: Doubleword Divide Unsigned (69cyc). + INSN_DB(OPS_ADD, "add ", FALSE, IFMT_dst, 1, PSI_ADD ), // 32: Add Word. + INSN_DB(OPS_ADDU, "addu ", FALSE, IFMT_dst, 1, PSI_ADD ), // 33: Add Unsigned Word. + INSN_DB(OPS_SUB, "sub ", FALSE, IFMT_dst, 1, PSI_SUB ), // 34: Subtract Word. + INSN_DB(OPS_SUBU, "subu ", FALSE, IFMT_dst, 1, PSI_SUB ), // 35: Subtract Unsigned Word. + INSN_DB(OPS_AND, "and ", FALSE, IFMT_dst, 1, PSI_AND ), // 36: And. + INSN_DB(OPS_OR, "or ", FALSE, IFMT_dst, 1, PSI_OR ), // 37: Or. + INSN_DB(OPS_XOR, "xor ", FALSE, IFMT_dst, 1, PSI_XOR ), // 38: Exclusive Or. + INSN_DB(OPS_NOR, "nor ", FALSE, IFMT_dst, 1, PSI_NOR ), // 39: Nor. + INSN_DB(OPS_SLT, "slt ", FALSE, IFMT_dst, 1, PSI_SLT ), // 42: Set on Less Than. + INSN_DB(OPS_SLTU, "sltu ", FALSE, IFMT_dst, 1, PSI_SLT ), // 43: Set on Less Than Unsigned. + INSN_DB(OPS_DADD, "dadd ", FALSE, IFMT_dst, 1, PSI_ADD ), // 44: Doubleword Add. + INSN_DB(OPS_DADDU, "daddu ", FALSE, IFMT_dst, 1, PSI_ADD ), // 45: Doubleword Add Unsigned. + INSN_DB(OPS_DSUB, "dsub ", FALSE, IFMT_dst, 1, PSI_SUB ), // 46: Doubleword Subtract. + INSN_DB(OPS_DSUBU, "dsubu ", FALSE, IFMT_dst, 1, PSI_SUB ), // 47: Doubleword Subtract Unsigned. + INSN_DB(OPS_TGE, "tge ", FALSE, IFMT_ste, 0, PSI_TGE ), // 48: Trap if Greater Than or Equal. + INSN_DB(OPS_TGEU, "tgeu ", FALSE, IFMT_ste, 0, PSI_TGE ), // 49: Trap if Greater Than or Equal Unsigned. + INSN_DB(OPS_TLT, "tlt ", FALSE, IFMT_ste, 0, PSI_TLT ), // 50: Trap if Less Than. + INSN_DB(OPS_TLTU, "tltu ", FALSE, IFMT_ste, 0, PSI_TLT ), // 51: Trap if Less Than Unsigned. + INSN_DB(OPS_TEQ, "teq ", FALSE, IFMT_ste, 0, PSI_TEQ ), // 52: Trap if Equal. + INSN_DB(OPS_TNE, "tne ", FALSE, IFMT_ste, 0, PSI_TEQ ), // 54: Trap if Not Equal. + INSN_DB(OPS_DSLL, "dsll ", FALSE, IFMT_dta, 1, PSI_SLI ), // 56: Doubleword Shift Left Logical. + INSN_DB(OPS_DSRL, "dsrl ", FALSE, IFMT_dta, 1, PSI_SRI ), // 58: Doubleword Shift Right Logical. + INSN_DB(OPS_DSRA, "dsra ", FALSE, IFMT_dta, 1, PSI_SRI ), // 59: Doubleword Shift Right Arithmetic. + INSN_DB(OPS_DSLL32, "dsll32 ", FALSE, IFMT_dta, 1, PSI_DSLI32 ), // 60: Doubleword Shift Left Logical + 32. + INSN_DB(OPS_DSRL32, "dsrl32 ", FALSE, IFMT_dta, 1, PSI_DSRI32 ), // 62: Doubleword Shift Right Logical + 32. + INSN_DB(OPS_DSRA32, "dsra32 ", FALSE, IFMT_dta, 1, PSI_DSRI32 ), // 63: Doubleword Shift Right Arithmetic + 32. INSN_END(), // NULL terminator. }; // Register opcode instructions: ALIGNED32 static const InsnTemplate insn_db_regi[] = { // OPC_REGIMM, INSN_TYPE_REGIMM - INSN_DB(OPR_BLTZ, "BLTZ ", FALSE, IFMT_sB, 0, PSI_BLTZ ), // 0: Branch on Less Than Zero. - INSN_DB(OPR_BGEZ, "BGEZ ", FALSE, IFMT_sB, 0, PSI_BGEZ ), // 1: Branch on Greater Than or Equal to Zero. - INSN_DB(OPR_BLTZL, "BLTZL ", FALSE, IFMT_sB, 0, PSI_BLTZ ), // 2: Branch on Less Than Zero Likely. - INSN_DB(OPR_BGEZL, "BGEZL ", FALSE, IFMT_sB, 0, PSI_BGEZ ), // 3: Branch on Greater Than or Equal to Zero Likely. - INSN_EX(OPR_BLTZAL, "BLTZAL ", FALSE, IFMT_sB, 0, PSI_BLTZAL, EXR_LL, EXR_00, 0b00), // 16: Branch on Less Than Zero and Link. - INSN_EX(OPR_BGEZAL, "BGEZAL ", FALSE, IFMT_sB, 0, PSI_BGEZAL, EXR_LL, EXR_00, 0b00), // 17: Branch on Greater Than or Equal to Zero and Link. - INSN_EX(OPR_BLTZALL, "BLTZALL", FALSE, IFMT_sB, 0, PSI_BLTZAL, EXR_LL, EXR_00, 0b00), // 18: Branch on Less Than Zero and Link Likely. - INSN_EX(OPR_BGEZALL, "BGEZALL", FALSE, IFMT_sB, 0, PSI_BGEZAL, EXR_LL, EXR_00, 0b00), // 19: Branch on Greater Than or Equal to Zero and Link Likely. + INSN_DB(OPR_BLTZ, "bltz ", FALSE, IFMT_sB, 0, PSI_BLTZ ), // 0: Branch on Less Than Zero. + INSN_DB(OPR_BGEZ, "bgez ", FALSE, IFMT_sB, 0, PSI_BGEZ ), // 1: Branch on Greater Than or Equal to Zero. + INSN_DB(OPR_BLTZL, "bltzl ", FALSE, IFMT_sB, 0, PSI_BLTZ ), // 2: Branch on Less Than Zero Likely. + INSN_DB(OPR_BGEZL, "bgezl ", FALSE, IFMT_sB, 0, PSI_BGEZ ), // 3: Branch on Greater Than or Equal to Zero Likely. + INSN_EX(OPR_BLTZAL, "bltzal ", FALSE, IFMT_sB, 0, PSI_BLTZAL, EXR_LL, EXR_00, 0b00), // 16: Branch on Less Than Zero and Link. + INSN_EX(OPR_BGEZAL, "bgezal ", FALSE, IFMT_sB, 0, PSI_BGEZAL, EXR_LL, EXR_00, 0b00), // 17: Branch on Greater Than or Equal to Zero and Link. + INSN_EX(OPR_BLTZALL, "bltzall", FALSE, IFMT_sB, 0, PSI_BLTZAL, EXR_LL, EXR_00, 0b00), // 18: Branch on Less Than Zero and Link Likely. + INSN_EX(OPR_BGEZALL, "bgezall", FALSE, IFMT_sB, 0, PSI_BGEZAL, EXR_LL, EXR_00, 0b00), // 19: Branch on Greater Than or Equal to Zero and Link Likely. - INSN_DB(OPR_TGEI, "TGEI ", FALSE, IFMT_sI, 0, PSI_TGEI), // 8: Trap if Greater Than or Equal Immediate. - INSN_DB(OPR_TGEIU, "TGEIU ", FALSE, IFMT_sI, 0, PSI_TGEI), // 9: Trap if Greater Than or Equal Unsigned Immediate. - INSN_DB(OPR_TLTI, "TLTI ", FALSE, IFMT_sI, 0, PSI_TLTI), // 10: Trap if Less Than Immediate. - INSN_DB(OPR_TLTIU, "TLTIU ", FALSE, IFMT_sI, 0, PSI_TLTI), // 11: Trap if Less Than Unsigned Immediate. - INSN_DB(OPR_TEQI, "TEQI ", FALSE, IFMT_sI, 0, PSI_TEQI), // 12: Trap if Equal Immediate. - INSN_DB(OPR_TNEI, "TNEI ", FALSE, IFMT_sI, 0, PSI_TNEI), // 14: Trap if Not Equal Immediate. + INSN_DB(OPR_TGEI, "tgei ", FALSE, IFMT_sI, 0, PSI_TGEI), // 8: Trap if Greater Than or Equal Immediate. + INSN_DB(OPR_TGEIU, "tgeiu ", FALSE, IFMT_sI, 0, PSI_TGEI), // 9: Trap if Greater Than or Equal Unsigned Immediate. + INSN_DB(OPR_TLTI, "tlti ", FALSE, IFMT_sI, 0, PSI_TLTI), // 10: Trap if Less Than Immediate. + INSN_DB(OPR_TLTIU, "tltiu ", FALSE, IFMT_sI, 0, PSI_TLTI), // 11: Trap if Less Than Unsigned Immediate. + INSN_DB(OPR_TEQI, "teqi ", FALSE, IFMT_sI, 0, PSI_TEQI), // 12: Trap if Equal Immediate. + INSN_DB(OPR_TNEI, "tnei ", FALSE, IFMT_sI, 0, PSI_TNEI), // 14: Trap if Not Equal Immediate. INSN_END(), // NULL terminator. }; // Coprocessor-0 (System Control Coprocessor): ALIGNED32 static const InsnTemplate insn_db_cop0_sub00[] = { // OPC_COP0, INSN_TYPE_COP_FMT - INSN_DB(COP0_MF, "MFC0 ", FALSE, IFMT_tdCP0, 1, PSI_MFC0), // 0: Move from System Control Coprocessor. - INSN_DB(COP0_DMF, "DMFC0 ", FALSE, IFMT_tdCP0, 1, PSI_MFC0), // 1: Doubleword Move from System Control Coprocessor. - INSN_DB(COP0_MT, "MTC0 ", FALSE, IFMT_tdCP0, 2, PSI_MTC0), // 4: Move to System Control Coprocessor. - INSN_DB(COP0_DMT, "DMTC0 ", FALSE, IFMT_tdCP0, 2, PSI_MTC0), // 5: Doubleword Move to System Control Coprocessor. + INSN_DB(COP0_MF, "mfc0 ", FALSE, IFMT_tdCP0, 1, PSI_MFC0), // 0: Move from System Control Coprocessor. + INSN_DB(COP0_DMF, "dmfc0 ", FALSE, IFMT_tdCP0, 1, PSI_MFC0), // 1: Doubleword Move from System Control Coprocessor. + INSN_DB(COP0_MT, "mtc0 ", FALSE, IFMT_tdCP0, 2, PSI_MTC0), // 4: Move to System Control Coprocessor. + INSN_DB(COP0_DMT, "dmtc0 ", FALSE, IFMT_tdCP0, 2, PSI_MTC0), // 5: Doubleword Move to System Control Coprocessor. INSN_END(), // NULL terminator. }; ALIGNED32 static const InsnTemplate insn_db_cop0_sub10[] = { // OPC_COP0, INSN_TYPE_FUNC - INSN_EX(OPC_COP0_TLBP, "TLBP ", FALSE, IFMT_NOP, 0, PSI_FUNC, EXR_EN, EXR_00, 0b00), // 8: Searches for a TLB entry that matches the EntryHi register. - INSN_EX(OPC_COP0_TLBR, "TLBR ", FALSE, IFMT_NOP, 0, PSI_FUNC, EXR_EN, EXR_IX, 0b10), // 1: Loads EntryHi and EntryLo registers with the TLB entry pointed at by the Index register. - INSN_EX(OPC_COP0_TLBWI, "TLBWI ", FALSE, IFMT_NOP, 0, PSI_FUNC, EXR_EN, EXR_IX, 0b00), // 2: Stores the contents of EntryHi and EntryLo registers into the TLB entry pointed at by the Index register. - INSN_EX(OPC_COP0_TLBWR, "TLBWR ", FALSE, IFMT_NOP, 0, PSI_FUNC, EXR_EN, EXR_RD, 0b00), // 6: Stores the contents of EntryHi and EntryLo registers into the TLB entry pointed at by the Random register. - INSN_DB(OPC_COP0_ERET, "ERET ", FALSE, IFMT_NOP, 0, PSI_FUNC), // 24: Return from interrupt, exception, or error exception. + INSN_EX(OPC_COP0_TLBP, "tlbp ", FALSE, IFMT_NOP, 0, PSI_FUNC, EXR_EN, EXR_00, 0b00), // 8: Searches for a TLB entry that matches the EntryHi register. + INSN_EX(OPC_COP0_TLBR, "tlbr ", FALSE, IFMT_NOP, 0, PSI_FUNC, EXR_EN, EXR_IX, 0b10), // 1: Loads EntryHi and EntryLo registers with the TLB entry pointed at by the Index register. + INSN_EX(OPC_COP0_TLBWI, "tlbwi ", FALSE, IFMT_NOP, 0, PSI_FUNC, EXR_EN, EXR_IX, 0b00), // 2: Stores the contents of EntryHi and EntryLo registers into the TLB entry pointed at by the Index register. + INSN_EX(OPC_COP0_TLBWR, "tlbwr ", FALSE, IFMT_NOP, 0, PSI_FUNC, EXR_EN, EXR_RD, 0b00), // 6: Stores the contents of EntryHi and EntryLo registers into the TLB entry pointed at by the Random register. + INSN_DB(OPC_COP0_ERET, "eret ", FALSE, IFMT_NOP, 0, PSI_FUNC), // 24: Return from interrupt, exception, or error exception. INSN_END(), // NULL terminator. }; // Coprocessor-1 (Floating-Point Unit): ALIGNED32 static const InsnTemplate insn_db_cop1_sub00[] = { // OPC_COP1, INSN_TYPE_COP_FMT - INSN_DB(COP1_FMT_SINGLE, "MFC1 ", FALSE, IFMT_tSCP1, 1, PSI_MFC1), // 0: Move Word From Floating-Point. - INSN_DB(COP1_FMT_DOUBLE, "DMFC1 ", FALSE, IFMT_tSCP1, 1, PSI_MFC1), // 1: Doubleword Move From Floating-Point. - INSN_DB(COP1_FMT_WORD, "MTC1 ", FALSE, IFMT_tSCP1, 2, PSI_MTC1), // 4: Move Word To Floating-Point. - INSN_DB(COP1_FMT_LONG, "DMTC1 ", FALSE, IFMT_tSCP1, 2, PSI_MTC1), // 5: Doubleword Move To Floating-Point. - INSN_DB(COP1_FMT_CTL_F, "CFC1 ", FALSE, IFMT_tSFCR, 1, PSI_CFC1), // 2: Move Control Word From Floating-Point. - INSN_DB(COP1_FMT_CTL_T, "CTC1 ", FALSE, IFMT_tSFCR, 2, PSI_CTC1), // 6: Move Control Word To Floating-Point. + INSN_DB(COP1_FMT_SINGLE, "mfc1 ", FALSE, IFMT_tSCP1, 1, PSI_MFC1), // 0: Move Word From Floating-Point. + INSN_DB(COP1_FMT_DOUBLE, "dmfc1 ", FALSE, IFMT_tSCP1, 1, PSI_MFC1), // 1: Doubleword Move From Floating-Point. + INSN_DB(COP1_FMT_WORD, "mtc1 ", FALSE, IFMT_tSCP1, 2, PSI_MTC1), // 4: Move Word To Floating-Point. + INSN_DB(COP1_FMT_LONG, "dmtc1 ", FALSE, IFMT_tSCP1, 2, PSI_MTC1), // 5: Doubleword Move To Floating-Point. + INSN_DB(COP1_FMT_CTL_F, "cfc1 ", FALSE, IFMT_tSFCR, 1, PSI_CFC1), // 2: Move Control Word From Floating-Point. + INSN_DB(COP1_FMT_CTL_T, "ctc1 ", FALSE, IFMT_tSFCR, 2, PSI_CTC1), // 6: Move Control Word To Floating-Point. INSN_END(), // NULL terminator. }; ALIGNED32 static const InsnTemplate insn_db_cop1_sub01[] = { // OPC_COP1, INSN_TYPE_REGIMM - INSN_EX(OPT_COP1_BC1F, "BC1F ", FALSE, IFMT_B, 0, PSI_BC1F, EXR_FP, EXR_00, 0b00), // 0: Branch on FP False (1cyc*). - INSN_EX(OPT_COP1_BC1T, "BC1T ", FALSE, IFMT_B, 0, PSI_BC1T, EXR_FP, EXR_00, 0b00), // 1: Branch on FP True (1cyc*). - INSN_EX(OPT_COP1_BC1FL, "BC1FL ", FALSE, IFMT_B, 0, PSI_BC1F, EXR_FP, EXR_00, 0b00), // 2: Branch on FP False Likely (1cyc*). - INSN_EX(OPT_COP1_BC1TL, "BC1TL ", FALSE, IFMT_B, 0, PSI_BC1T, EXR_FP, EXR_00, 0b00), // 3: Branch on FP True Likely (1cyc*). + INSN_EX(OPT_COP1_BC1F, "bc1f ", FALSE, IFMT_B, 0, PSI_BC1F, EXR_FP, EXR_00, 0b00), // 0: Branch on FP False (1cyc*). + INSN_EX(OPT_COP1_BC1T, "bc1t ", FALSE, IFMT_B, 0, PSI_BC1T, EXR_FP, EXR_00, 0b00), // 1: Branch on FP True (1cyc*). + INSN_EX(OPT_COP1_BC1FL, "bc1fl ", FALSE, IFMT_B, 0, PSI_BC1F, EXR_FP, EXR_00, 0b00), // 2: Branch on FP False Likely (1cyc*). + INSN_EX(OPT_COP1_BC1TL, "bc1tl ", FALSE, IFMT_B, 0, PSI_BC1T, EXR_FP, EXR_00, 0b00), // 3: Branch on FP True Likely (1cyc*). INSN_END(), // NULL terminator. }; ALIGNED32 static const InsnTemplate insn_db_cop1_sub10[] = { // OPC_COP1, INSN_TYPE_FUNC - INSN_DB(OPS_ADD_F, "ADD ", TRUE, IFMT_DST, 1, PSI_ADDF), // 0: ADD.[fmt] Floating-Point Add (3cyc). - INSN_DB(OPS_SUB_F, "SUB ", TRUE, IFMT_DST, 1, PSI_SUBF), // 1: SUB.[fmt] Floating-Point Subtract (3cyc). - INSN_DB(OPS_MUL_F, "MUL ", TRUE, IFMT_DST, 1, PSI_MULF), // 2: MUL.[fmt] Floating-Point Multiply (S:5cyc; D:8cyc). - INSN_DB(OPS_DIV_F, "DIV ", TRUE, IFMT_DST, 1, PSI_DIVF), // 3: DIV.[fmt] Floating-Point Divide (S:29cyc; D:58cyc). - INSN_DB(OPS_SQRT_F, "SQRT ", TRUE, IFMT_DS_XX, 1, PSI_CVTF), // 4: SQRT.[fmt] Floating-Point Square Root (S:29cyc; D:58cyc). - INSN_DB(OPS_ABS_F, "ABS ", TRUE, IFMT_DS_XX, 1, PSI_CVTF), // 5: ABS.[fmt] Floating-Point Absolute Value (1cyc). - INSN_DB(OPS_MOV_F, "MOV ", TRUE, IFMT_DS_XX, 1, PSI_MOVF), // 6: MOV.[fmt] Floating-Point Move (1cyc). - INSN_DB(OPS_NEG_F, "NEG ", TRUE, IFMT_DS_XX, 1, PSI_NEGF), // 7: NEG.[fmt] Floating-Point Negate (1cyc). - INSN_DB(OPS_ROUND_L_F, "ROUND.L", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 8: ROUND.L.[fmt] Floating-Point Round to Long Fixed-Point (5cyc). - INSN_DB(OPS_TRUNC_L_F, "TRUNC.L", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 9: TRUNC.L.[fmt] Floating-Point Truncate to Long Fixed-Point (5cyc). - INSN_DB(OPS_CEIL_L_F, "CEIL.L ", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 10: CEIL.L.[fmt] Floating-Point Ceiling to Long Fixed-Point (5cyc). - INSN_DB(OPS_FLOOR_L_F, "FLOOR.L", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 11: FLOOR.L.[fmt] Floating-Point Floor to Long Fixed-Point (5cyc). - INSN_DB(OPS_ROUND_W_F, "ROUND.W", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 12: ROUND.W.[fmt] Floating-Point Round to Word Fixed-Point (5cyc). - INSN_DB(OPS_TRUNC_W_F, "TRUNC.W", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 13: TRUNC.W.[fmt] Floating-Point Truncate to Word Fixed-Point (5cyc). - INSN_DB(OPS_CEIL_W_F, "CEIL.W ", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 14: CEIL.W.[fmt] Floating-Point Ceiling to Word Fixed-Point (5cyc). - INSN_DB(OPS_FLOOR_W_F, "FLOOR.W", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 15: FLOOR.W.[fmt] Floating-Point Floor to Word Fixed-Point (5cyc). + INSN_DB(OPS_ADD_F, "add ", TRUE, IFMT_DST, 1, PSI_ADDF), // 0: ADD.[fmt] Floating-Point Add (3cyc). + INSN_DB(OPS_SUB_F, "sub ", TRUE, IFMT_DST, 1, PSI_SUBF), // 1: SUB.[fmt] Floating-Point Subtract (3cyc). + INSN_DB(OPS_MUL_F, "mul ", TRUE, IFMT_DST, 1, PSI_MULF), // 2: MUL.[fmt] Floating-Point Multiply (S:5cyc; D:8cyc). + INSN_DB(OPS_DIV_F, "div ", TRUE, IFMT_DST, 1, PSI_DIVF), // 3: DIV.[fmt] Floating-Point Divide (S:29cyc; D:58cyc). + INSN_DB(OPS_SQRT_F, "sqrt ", TRUE, IFMT_DS_XX, 1, PSI_CVTF), // 4: SQRT.[fmt] Floating-Point Square Root (S:29cyc; D:58cyc). + INSN_DB(OPS_ABS_F, "abs ", TRUE, IFMT_DS_XX, 1, PSI_CVTF), // 5: ABS.[fmt] Floating-Point Absolute Value (1cyc). + INSN_DB(OPS_MOV_F, "mov ", TRUE, IFMT_DS_XX, 1, PSI_MOVF), // 6: MOV.[fmt] Floating-Point Move (1cyc). + INSN_DB(OPS_NEG_F, "neg ", TRUE, IFMT_DS_XX, 1, PSI_NEGF), // 7: NEG.[fmt] Floating-Point Negate (1cyc). + INSN_DB(OPS_ROUND_L_F, "round.l", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 8: ROUND.L.[fmt] Floating-Point Round to Long Fixed-Point (5cyc). + INSN_DB(OPS_TRUNC_L_F, "trunc.l", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 9: TRUNC.L.[fmt] Floating-Point Truncate to Long Fixed-Point (5cyc). + INSN_DB(OPS_CEIL_L_F, "ceil.l ", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 10: CEIL.L.[fmt] Floating-Point Ceiling to Long Fixed-Point (5cyc). + INSN_DB(OPS_FLOOR_L_F, "floor.l", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 11: FLOOR.L.[fmt] Floating-Point Floor to Long Fixed-Point (5cyc). + INSN_DB(OPS_ROUND_W_F, "round.w", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 12: ROUND.W.[fmt] Floating-Point Round to Word Fixed-Point (5cyc). + INSN_DB(OPS_TRUNC_W_F, "trunc.w", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 13: TRUNC.W.[fmt] Floating-Point Truncate to Word Fixed-Point (5cyc). + INSN_DB(OPS_CEIL_W_F, "ceil.w ", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 14: CEIL.W.[fmt] Floating-Point Ceiling to Word Fixed-Point (5cyc). + INSN_DB(OPS_FLOOR_W_F, "floor.w", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 15: FLOOR.W.[fmt] Floating-Point Floor to Word Fixed-Point (5cyc). - INSN_DB(OPS_CVT_S_F, "CVT.S ", TRUE, IFMT_DS_FX, 1, PSI_CVTF), // 32: CVT.S.[fmt] Floating-Point Convert to Single Floating-Point (D:2cyc; W:5cyc; L:5cyc). - INSN_DB(OPS_CVT_D_F, "CVT.D ", TRUE, IFMT_DS_FX, 1, PSI_CVTF), // 33: CVT.D.[fmt] Floating-Point Convert to Double Floating-Point (S:1cyc; W:5cyc; L:5cyc). - INSN_DB(OPS_CVT_W_F, "CVT.W ", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 36: CVT.W.[fmt] Floating-Point Convert to Word Fixed-Point (5cyc). - INSN_DB(OPS_CVT_L_F, "CVT.L ", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 37: CVT.L.[fmt] Floating-Point Convert to Long Fixed-Point (5cyc). + INSN_DB(OPS_CVT_S_F, "cvt.s ", TRUE, IFMT_DS_FX, 1, PSI_CVTF), // 32: CVT.S.[fmt] Floating-Point Convert to Single Floating-Point (D:2cyc; W:5cyc; L:5cyc). + INSN_DB(OPS_CVT_D_F, "cvt.d ", TRUE, IFMT_DS_FX, 1, PSI_CVTF), // 33: CVT.D.[fmt] Floating-Point Convert to Double Floating-Point (S:1cyc; W:5cyc; L:5cyc). + INSN_DB(OPS_CVT_W_F, "cvt.w ", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 36: CVT.W.[fmt] Floating-Point Convert to Word Fixed-Point (5cyc). + INSN_DB(OPS_CVT_L_F, "cvt.l ", TRUE, IFMT_DS_IX, 1, PSI_CVTF), // 37: CVT.L.[fmt] Floating-Point Convert to Long Fixed-Point (5cyc). - INSN_EX(OPS_C_F, "C.F ", TRUE, IFMT_ST, 0, PSI_C_F, EXR_FP, EXR_00, 0b10), // 48: C.F.[fmt] Floating-Point Compare (False) (1cyc). - INSN_EX(OPS_C_UN, "C.UN ", TRUE, IFMT_ST, 0, PSI_C_UN, EXR_FP, EXR_00, 0b10), // 49: C.UN.[fmt] Floating-Point Compare (Unordered) (1cyc). - INSN_EX(OPS_C_EQ, "C.EQ ", TRUE, IFMT_ST, 0, PSI_C_EQ, EXR_FP, EXR_00, 0b10), // 50: C.EQ.[fmt] Floating-point Compare (Equal) (1cyc). - INSN_EX(OPS_C_UEQ, "C.UEQ ", TRUE, IFMT_ST, 0, PSI_C_UEQ, EXR_FP, EXR_00, 0b10), // 51: C.UEQ.[fmt] Floating-point Compare (Unordered or Equal) (1cyc). - INSN_EX(OPS_C_OLT, "C.OLT ", TRUE, IFMT_ST, 0, PSI_C_OLT, EXR_FP, EXR_00, 0b10), // 52: C.OLT.[fmt] Floating-point Compare (Ordered Less Than) (1cyc). - INSN_EX(OPS_C_ULT, "C.ULT ", TRUE, IFMT_ST, 0, PSI_C_ULT, EXR_FP, EXR_00, 0b10), // 53: C.ULT.[fmt] Floating-point Compare (Unordered or Less Than) (1cyc). - INSN_EX(OPS_C_OLE, "C.OLE ", TRUE, IFMT_ST, 0, PSI_C_OLE, EXR_FP, EXR_00, 0b10), // 54: C.OLE.[fmt] Floating-point Compare (Ordered or Less Than or Equal) (1cyc). - INSN_EX(OPS_C_ULE, "C.ULE ", TRUE, IFMT_ST, 0, PSI_C_ULE, EXR_FP, EXR_00, 0b10), // 55: C.ULE.[fmt] Floating-point Compare (Unordered or Less Than or Equal) (1cyc). - INSN_EX(OPS_C_SF, "C.SF ", TRUE, IFMT_ST, 0, PSI_C_SF, EXR_FP, EXR_00, 0b10), // 56: C.SF.[fmt] Floating-point Compare (Signaling False) (1cyc). - INSN_EX(OPS_C_NGLE, "C.NGLE ", TRUE, IFMT_ST, 0, PSI_C_NGLE, EXR_FP, EXR_00, 0b10), // 57: C.NGLE.[fmt] Floating-point Compare (Not Greater or Less Than or Equal) (1cyc). - INSN_EX(OPS_C_SEQ, "C.SEQ ", TRUE, IFMT_ST, 0, PSI_C_SEQ, EXR_FP, EXR_00, 0b10), // 58: C.SEQ.[fmt] Floating-point Compare (Signalling Equal) (1cyc). - INSN_EX(OPS_C_NGL, "C.NGL ", TRUE, IFMT_ST, 0, PSI_C_NGL, EXR_FP, EXR_00, 0b10), // 59: C.NGL.[fmt] Floating-point Compare (Not Greater or Less Than) (1cyc). - INSN_EX(OPS_C_LT, "C.LT ", TRUE, IFMT_ST, 0, PSI_C_LT, EXR_FP, EXR_00, 0b10), // 60: C.LT.[fmt] Floating-point Compare (Less Than) (1cyc). - INSN_EX(OPS_C_NGE, "C.NGE ", TRUE, IFMT_ST, 0, PSI_C_NGE, EXR_FP, EXR_00, 0b10), // 61: C.NGE.[fmt] Floating-point Compare (Not Greater Than or Equal) (1cyc). - INSN_EX(OPS_C_LE, "C.LE ", TRUE, IFMT_ST, 0, PSI_C_LE, EXR_FP, EXR_00, 0b10), // 62: C.LE.[fmt] Floating-point Compare (Less Than or Equal) (1cyc). - INSN_EX(OPS_C_NGT, "C.NGT ", TRUE, IFMT_ST, 0, PSI_C_NGT, EXR_FP, EXR_00, 0b10), // 63: C.NGT.[fmt] Floating-point Compare (Not Greater Than) (1cyc). + INSN_EX(OPS_C_F, "c.f ", TRUE, IFMT_ST, 0, PSI_C_F, EXR_FP, EXR_00, 0b10), // 48: c.f.[fmt] Floating-Point Compare (False) (1cyc). + INSN_EX(OPS_C_UN, "c.un ", TRUE, IFMT_ST, 0, PSI_C_UN, EXR_FP, EXR_00, 0b10), // 49: c.un.[fmt] Floating-Point Compare (Unordered) (1cyc). + INSN_EX(OPS_C_EQ, "c.eq ", TRUE, IFMT_ST, 0, PSI_C_EQ, EXR_FP, EXR_00, 0b10), // 50: c.eq.[fmt] Floating-point Compare (Equal) (1cyc). + INSN_EX(OPS_C_UEQ, "c.ueq ", TRUE, IFMT_ST, 0, PSI_C_UEQ, EXR_FP, EXR_00, 0b10), // 51: c.ueq.[fmt] Floating-point Compare (Unordered or Equal) (1cyc). + INSN_EX(OPS_C_OLT, "c.olt ", TRUE, IFMT_ST, 0, PSI_C_OLT, EXR_FP, EXR_00, 0b10), // 52: c.olt.[fmt] Floating-point Compare (Ordered Less Than) (1cyc). + INSN_EX(OPS_C_ULT, "c.ult ", TRUE, IFMT_ST, 0, PSI_C_ULT, EXR_FP, EXR_00, 0b10), // 53: c.ult.[fmt] Floating-point Compare (Unordered or Less Than) (1cyc). + INSN_EX(OPS_C_OLE, "c.ole ", TRUE, IFMT_ST, 0, PSI_C_OLE, EXR_FP, EXR_00, 0b10), // 54: c.ole.[fmt] Floating-point Compare (Ordered or Less Than or Equal) (1cyc). + INSN_EX(OPS_C_ULE, "c.ule ", TRUE, IFMT_ST, 0, PSI_C_ULE, EXR_FP, EXR_00, 0b10), // 55: c.ule.[fmt] Floating-point Compare (Unordered or Less Than or Equal) (1cyc). + INSN_EX(OPS_C_SF, "c.sf ", TRUE, IFMT_ST, 0, PSI_C_SF, EXR_FP, EXR_00, 0b10), // 56: c.sf.[fmt] Floating-point Compare (Signaling False) (1cyc). + INSN_EX(OPS_C_NGLE, "c.ngle ", TRUE, IFMT_ST, 0, PSI_C_NGLE, EXR_FP, EXR_00, 0b10), // 57: c.ngle.[fmt] Floating-point Compare (Not Greater or Less Than or Equal) (1cyc). + INSN_EX(OPS_C_SEQ, "c.seq ", TRUE, IFMT_ST, 0, PSI_C_SEQ, EXR_FP, EXR_00, 0b10), // 58: c.seq.[fmt] Floating-point Compare (Signalling Equal) (1cyc). + INSN_EX(OPS_C_NGL, "c.ngl ", TRUE, IFMT_ST, 0, PSI_C_NGL, EXR_FP, EXR_00, 0b10), // 59: c.ngl.[fmt] Floating-point Compare (Not Greater or Less Than) (1cyc). + INSN_EX(OPS_C_LT, "c.lt ", TRUE, IFMT_ST, 0, PSI_C_LT, EXR_FP, EXR_00, 0b10), // 60: c.lt.[fmt] Floating-point Compare (Less Than) (1cyc). + INSN_EX(OPS_C_NGE, "c.nge ", TRUE, IFMT_ST, 0, PSI_C_NGE, EXR_FP, EXR_00, 0b10), // 61: c.nge.[fmt] Floating-point Compare (Not Greater Than or Equal) (1cyc). + INSN_EX(OPS_C_LE, "c.le ", TRUE, IFMT_ST, 0, PSI_C_LE, EXR_FP, EXR_00, 0b10), // 62: c.le.[fmt] Floating-point Compare (Less Than or Equal) (1cyc). + INSN_EX(OPS_C_NGT, "c.ngt ", TRUE, IFMT_ST, 0, PSI_C_NGT, EXR_FP, EXR_00, 0b10), // 63: c.ngt.[fmt] Floating-point Compare (Not Greater Than) (1cyc). INSN_END(), // NULL terminator. }; @@ -260,22 +260,25 @@ static const InsnTemplate* insn_db_cop_lists[][0b11 + 1] = { // Single-line pseudo-instructions. ALIGNED32 static const InsnTemplate insn_db_pseudo[] = { - [PSEUDO_NOP ] = INSN_DB(OPS_SLL, "NOP ", FALSE, IFMT_NOP, 0, PSI_NOP ), // NOP (pseudo of SLL). - [PSEUDO_MOVET ] = INSN_DB(OPS_ADD, "MOVE ", FALSE, IFMT_dt, 1, PSI_MOVET), // Move (pseudo of ADD and OR). - [PSEUDO_MOVES ] = INSN_DB(OPS_ADD, "MOVE ", FALSE, IFMT_ds, 1, PSI_MOVES), // Move (pseudo of ADD). - [PSEUDO_B ] = INSN_DB(OPC_BEQ, "B ", FALSE, IFMT_B, 0, PSI_B ), // Branch (pseudo of BEQ). - [PSEUDO_BEQZ ] = INSN_DB(OPC_BEQ, "BEQZ ", FALSE, IFMT_sB, 0, PSI_BEQ ), // Branch on Equal to Zero (pseudo of BEQ). - [PSEUDO_BNEZ ] = INSN_DB(OPC_BNE, "BNEZ ", FALSE, IFMT_sB, 0, PSI_BNE ), // Branch on Not Equal to Zero (pseudo of BNE). - [PSEUDO_LI ] = INSN_DB(OPC_ADDI, "LI ", FALSE, IFMT_tI, 1, PSI_LI ), // Load Immediate (pseudo of ADDI and ADDIU). - [PSEUDO_SUBI ] = INSN_DB(OPC_ADDI, "SUBI ", FALSE, IFMT_tsI, 1, PSI_SUBI ), // Word Subtract Immediate (pseudo of ADDI). - [PSEUDO_SUBIU ] = INSN_DB(OPC_ADDIU, "SUBIU ", FALSE, IFMT_tsI, 1, PSI_SUBI ), // Word Subtract Immediate Unsigned (pseudo of ADDIU). - [PSEUDO_BEQZL ] = INSN_DB(OPC_BEQL, "BEQZL ", FALSE, IFMT_sB, 0, PSI_BEQ ), // Branch on Equal to Zero Likely (pseudo of BEQL). - [PSEUDO_BNEZL ] = INSN_DB(OPC_BNEL, "BNEZL ", FALSE, IFMT_sB, 0, PSI_BNE ), // Branch on Not Equal to Zero Likely (pseudo of BNEL). - [PSEUDO_DSUBI ] = INSN_DB(OPC_DADDI, "DSUBI ", FALSE, IFMT_tsI, 1, PSI_SUBI ), // Doubleword Subtract Immediate (pseudo of DADDI). - [PSEUDO_DSUBIU] = INSN_DB(OPC_DADDIU, "DSUBIU ", FALSE, IFMT_tsI, 1, PSI_SUBI ), // Doubleword Subtract Immediate Unsigned (pseudo of DADDIU). + [PSEUDO_NOP ] = INSN_DB(OPS_SLL, "nop ", FALSE, IFMT_NOP, 0, PSI_NOP ), // NOP (pseudo of SLL). + [PSEUDO_MOVET ] = INSN_DB(OPS_ADD, "move ", FALSE, IFMT_dt, 1, PSI_MOVET), // Move (pseudo of ADD and OR). + [PSEUDO_MOVES ] = INSN_DB(OPS_ADD, "move ", FALSE, IFMT_ds, 1, PSI_MOVES), // Move (pseudo of ADD). + [PSEUDO_B ] = INSN_DB(OPC_BEQ, "b ", FALSE, IFMT_B, 0, PSI_B ), // Branch (pseudo of BEQ). + [PSEUDO_BEQZ ] = INSN_DB(OPC_BEQ, "beqz ", FALSE, IFMT_sB, 0, PSI_BEQ ), // Branch on Equal to Zero (pseudo of BEQ). + [PSEUDO_BNEZ ] = INSN_DB(OPC_BNE, "bnez ", FALSE, IFMT_sB, 0, PSI_BNE ), // Branch on Not Equal to Zero (pseudo of BNE). + [PSEUDO_LI ] = INSN_DB(OPC_ADDI, "li ", FALSE, IFMT_tI, 1, PSI_LI ), // Load Immediate (pseudo of ADDI and ADDIU). + [PSEUDO_SUBI ] = INSN_DB(OPC_ADDI, "subi ", FALSE, IFMT_tsI, 1, PSI_SUBI ), // Word Subtract Immediate (pseudo of ADDI). + [PSEUDO_SUBIU ] = INSN_DB(OPC_ADDIU, "subiu ", FALSE, IFMT_tsI, 1, PSI_SUBI ), // Word Subtract Immediate Unsigned (pseudo of ADDIU). + [PSEUDO_BEQZL ] = INSN_DB(OPC_BEQL, "beqzl ", FALSE, IFMT_sB, 0, PSI_BEQ ), // Branch on Equal to Zero Likely (pseudo of BEQL). + [PSEUDO_BNEZL ] = INSN_DB(OPC_BNEL, "bnezl ", FALSE, IFMT_sB, 0, PSI_BNE ), // Branch on Not Equal to Zero Likely (pseudo of BNEL). + [PSEUDO_DSUBI ] = INSN_DB(OPC_DADDI, "dsubi ", FALSE, IFMT_tsI, 1, PSI_SUBI ), // Doubleword Subtract Immediate (pseudo of DADDI). + [PSEUDO_DSUBIU] = INSN_DB(OPC_DADDIU, "dsubiu ", FALSE, IFMT_tsI, 1, PSI_SUBI ), // Doubleword Subtract Immediate Unsigned (pseudo of DADDIU). }; +//! TODO: Everything below here is debug. Remove it later. + + #define asm_v(...) asm volatile(__VA_ARGS__) #define asm_v_b(_insnStr, _label) asm volatile goto(_insnStr" %l0"::::_label) // Inline an instruction that does nothing but prints a hex value from 0x0-0x3FF (0-1023). @@ -587,3 +590,58 @@ void mips_III_insn_test(f32 a, f32 b, f32 c) { }; volatile Address gMipsIIITest = (volatile Address)mips_III_insn_test; + + +#define alloca ALLOCA + + +#define NOINLINE static __attribute__((noinline,used)) +#define STACK_FRAME(n) volatile char __stackframe[n] = {0}; (void)__stackframe; + +void* bt_buf[32]; +int bt_buf_len; +int (*bt_null_func_ptr)(void); +int (*bt_invalid_func_ptr)(void) = (int(*)(void))0xECECECEC; +int (*bt_misaligned_func_ptr)(void) = (int(*)(void))0x80010002; + +// Test functions defined in backtrace_test.S +int btt_end(void) +{ + // memset(bt_buf, 0, sizeof(bt_buf)); + // bt_buf_len = backtrace(bt_buf, 32); + // return 0; + FORCE_CRASH(); +} + +NOINLINE int btt_fp(void) { STACK_FRAME(128); volatile char *buf = alloca(bt_buf_len+1); buf[0] = 2; return btt_end()+1+buf[0]; } +NOINLINE int btt_dummy(void) { return 1; } + +#define BT_SYSCALL() asm volatile ("syscall 0x0F001") // Syscall for the backtrace test +#define BT_SYSCALL_FP() asm volatile ("syscall 0x0F002") // Syscall for the backtrace test, clobbering the frame pointer + +NOINLINE int btt_b3(void) { STACK_FRAME( 128); return btt_end()+1; } +NOINLINE int btt_b2(void) { STACK_FRAME( 12); return btt_b3()+1; } +NOINLINE int btt_b1(void) { STACK_FRAME(1024); return btt_b2()+1; } + +NOINLINE int btt_c3(void) { STACK_FRAME( 128); volatile char *buf = alloca(bt_buf_len+1); return btt_end()+1+buf[0]; } +NOINLINE int btt_c2(void) { STACK_FRAME( 12); return btt_c3()+1; } +NOINLINE int btt_c1(void) { STACK_FRAME(1024); volatile char *buf = alloca(bt_buf_len+1); return btt_c2()+1+buf[0]; } + +NOINLINE int btt_d2(void) { STACK_FRAME( 12); return 0; } +NOINLINE int btt_d1(void) { STACK_FRAME( 16); BT_SYSCALL(); return btt_d2()+1; } + +NOINLINE int btt_e2(void) { BT_SYSCALL(); return 1; } // this is a leaf function (no stack frame) +NOINLINE int btt_e1(void) { STACK_FRAME(1024); return btt_e2()+1; } + +NOINLINE int btt_f3(void) { BT_SYSCALL_FP(); return 1; } +NOINLINE int btt_f2(void) { STACK_FRAME( 128); volatile char *buf = alloca(bt_buf_len+1); return btt_f3()+1+buf[0]; } +NOINLINE int btt_f1(void) { STACK_FRAME(1024); return btt_f2()+1; } + +NOINLINE int btt_g2(void) { STACK_FRAME(1024); return bt_null_func_ptr() + 1; } +NOINLINE int btt_g1(void) { STACK_FRAME(1024); return btt_g2()+1; } + +NOINLINE int btt_h2(void) { STACK_FRAME(1024); return bt_invalid_func_ptr() + 1; } +NOINLINE int btt_h1(void) { STACK_FRAME(1024); return btt_h2()+1; } + +NOINLINE int btt_i2(void) { STACK_FRAME(1024); return bt_misaligned_func_ptr() + 1; } +NOINLINE int btt_i1(void) { STACK_FRAME(1024); return btt_i2()+1; } diff --git a/src/crash_screen/util/insn_disasm.c b/src/crash_screen/util/insn_disasm.c index f4c71aac9..887ec4543 100644 --- a/src/crash_screen/util/insn_disasm.c +++ b/src/crash_screen/util/insn_disasm.c @@ -181,11 +181,12 @@ const InsnTemplate* get_insn(InsnData* insnSrc) { case OPC_COP1: case OPC_COP2: case OPC_COP3: - checkInsn = insn_db_cop_lists[insn.cop_num][insn.cop_subtype]; // Use COPz lists. + enum InsnType subtype = insn.cop_subtype; + checkInsn = insn_db_cop_lists[insn.cop_num][subtype]; // Use COPz lists. if (checkInsn == NULL) { return NULL; } - switch (insn.cop_subtype) { + switch (subtype) { case INSN_TYPE_COP_FMT: opcode = insn.fmt; break; // The 3 bits after the first 8. case INSN_TYPE_REGIMM: opcode = insn.regimm; break; // The 5 bits after the first 11. case INSN_TYPE_FUNC: opcode = insn.func; break; // Last 6 bits. @@ -194,15 +195,15 @@ const InsnTemplate* get_insn(InsnData* insnSrc) { break; case OPC_SPECIAL: checkInsn = insn_db_spec; - opcode = insn.func; + opcode = insn.func; // The last 6 bits. break; case OPC_REGIMM: checkInsn = insn_db_regi; - opcode = insn.regimm; + opcode = insn.regimm; // The 5 bits after the first 11. break; default: checkInsn = insn_db_standard; - opcode = insn.opcode; + opcode = insn.opcode; // The first 6 bits. break; } @@ -229,7 +230,7 @@ s16 insn_check_for_branch_offset(InsnData insn) { if (info != NULL) { MIPSParamFmts fmt = info->params; - const InsnParam* list = &insn_param_formats[fmt][0]; + const InsnParam* list = insn_param_formats[fmt]; for (size_t i = 0; i < MIPS_NUM_PARAMS; i++) { if (list[i].id == MP_B) { @@ -349,8 +350,10 @@ void append_reg_to_buffer(RegisterSources src, int idx, RegisterValueTypes type, */ void append_extra_regs(u8 ex1, u8 ex2, u8 exo) { u8 ex[2] = { ex1, ex2, }; + for (int i = 0; i < ARRAY_COUNT(ex); i++) { _Bool isOutput = (exo & (BIT((ARRAY_COUNT(ex) - 1) - i))); + switch (ex[i]) { case EXR_HI: append_reg_to_buffer(REGS_SPC, REG_SPC_HI, REG_VAL_TYPE_INT, isOutput); @@ -419,7 +422,8 @@ static Address instr_index_to_addr(InsnData insn) { return PHYSICAL_TO_VIRTUAL(insn.instr_index * sizeof(InsnData)); } -// "break" instruction codes generated by gcc: +// break/trap instruction codes generated by gcc: +// -mdivide-breaks or -mdivide-traps //! TODO: Are these names accurate, and are there more of these? static const IdNamePair insn_break_codes[] = { { .id = 6, .name = "overflow", }, @@ -465,6 +469,36 @@ static char insn_as_string[CHAR_BUFFER_SIZE] = ""; append_reg_to_buffer((_src), (_idx), REG_VAL_TYPE_ADDR, FALSE); \ } +const char* comment_from_insn(InsnData insn, const InsnTemplate* info) { + const u16 insnHi = insn.hi; + const char* comment = NULL; + + if ((insnHi == 0x27BD) || (insnHi == 0x67BD)) { // [addiu/daddiu] $sp, $sp, 0xXXXX + comment = "deallocate stack"; + if ((info != NULL) && (info->pseudoC == PSI_SUBI)) { + comment += STRLEN("de"); // "allocate stack" + } + } else if ((insnHi == 0xFFBF) || (insnHi == 0xAFBF)) { // [sw/sd] $ra, 0xXXXX($sp) + comment = "RA to stack"; + } else if ((insnHi == 0x8FBF) || (insnHi == 0xD7BF)) { // [lw/ld] $ra, 0xXXXX($sp) + comment = "RA from stack"; + } else if ((insnHi == 0xAFBE) || (insnHi == 0xFFBE)) { // [sw/sd] $fp, 0xXXXX($sp) + comment = "&frame to stack"; //! TODO: assume $s8 if $s7 is used + } else if ((insnHi == 0x8FBE) || (insnHi == 0xD7BE)) { // [lw/ld] $fp, 0xXXXX($sp) + comment = "&frame from stack"; //! TODO: assume $s8 if $s7 is used + } else if (insn.raw == 0x03A0F025) { // or $fp, $sp, $r0 + comment = "&frame = &stack"; + } else if (insn.raw == 0x03C0E825) { // or $sp, $fp, $r0 + comment = "&stack = &frame"; + } else if (((insnHi & 0xFFFE0) == 0x27C0)) { //! TODO: addiu/daddiu xx, $fp + comment = "deallocate frame"; //! TODO: Is this correct? + } else if (((insn.raw & 0xFFE0FFFF) == 0x03A0E823) || ((insn.raw & 0xFFE0FFFF) == 0x03A0E82F)) { + comment = ("deallocate stack" + STRLEN("de")); + } + + return comment; +} + /** * @brief Converts MIPS instruction data into a formatted string. * TODO: This is by far the largest crash screen function. Can it be reduced? @@ -498,7 +532,7 @@ char* cs_insn_to_string(Address addr, InsnData insn, const char** fname, _Bool f ADD_COLOR((insn.raw == OPS_NOP) ? COLOR_RGBA32_CRASH_DISASM_NOP : COLOR_RGBA32_CRASH_DISASM_INSN); char name[INSN_NAME_DISPLAY_WIDTH] = UNPACK_STR7(insn_alphabet_uppercase, info->name); - if (info->hasFmt) { + if (info->suffix) { char fmtChar = cp1_fmt_to_char(insn); sprintf(name, STR_INSN_NAME_FORMAT, name, fmtChar); overwriteFmt = ((fmtChar == 'S' || fmtChar == 'D') ? REG_VAL_TYPE_FLOAT : REG_VAL_TYPE_INT); // Overwrite secondary format. @@ -584,7 +618,7 @@ char* cs_insn_to_string(Address addr, InsnData insn, const char** fname, _Bool f break; case MP_EXC20: // For SYSCALL and BREAK instructions. ADD_COLOR(COLOR_RGBA32_LIGHT_GRAY); - if (info->opcode == OPS_BREAK) { + if (info->opcode == OPS_BREAK) { //! TODO: version of this for teq also (mdivide-traps) u16 eA = insn.codeA; u16 eB = insn.codeB; ADD_STR(STR_CODE10", "STR_CODE10, eA, eB); @@ -630,6 +664,12 @@ char* cs_insn_to_string(Address addr, InsnData insn, const char** fname, _Bool f curCmd++; } + const char* comment = comment_from_insn(insn, info); + if (comment != NULL) { + ADD_COLOR(COLOR_RGBA32_VSC_COMMENT); + ADD_STR(" # %s", comment); + } + append_extra_regs(info->ex1, info->ex2, info->exo); } else { unimpl = TRUE; @@ -708,7 +748,7 @@ const PSC_Entry psc_entries[] = { // Non-InsnData registers: #define PSC_FP '#' - { .c = PSC_FP, .col = PSC_COL_VAR, .a = "FP", }, // FP condition + { .c = PSC_FP, .col = PSC_COL_VAR, .a = "FC", }, // FP condition #define PSC_RA '$' { .c = PSC_RA, .col = PSC_COL_VAR, .a = "RA", }, #define PSC_PC '.' @@ -871,6 +911,57 @@ void add_reg_str(char** c, RegisterSources src, int idx, _Bool isBase) { *c += sprintf(*c, STR_COLOR_PREFIX"%s"STR_COLOR_PREFIX, color, str, gCSDefaultPrintColor); } +static _Bool modify_pseudo_c_assignment_str(const char** formatStr, InsnData insn, MIPS_C_Pseudocodes pseudoC) { + const char* s = NULL; + + if (insn.rt == insn.rs) { + switch (pseudoC) { + case PSI_ADDI: s = "t += i"; break; + // 15 + case PSI_ANDI: s = "t &= i"; break; + case PSI_ORI: s = "t |= i"; break; + case PSI_XORI: s = "t ^= i"; break; + // 19 + case PSI_SUBI: s = "t -= i"; break; + default: break; + } + } else if (insn.rd == insn.rs) { + switch (pseudoC) { + case PSI_ADD: s = "d += t"; break; + case PSI_SUB: s = "d -= t"; break; + case PSI_AND: s = "d &= t"; break; + case PSI_OR: s = "d |= t"; break; + case PSI_XOR: s = "d ^= t"; break; + default: break; + } + } else if (insn.rd == insn.rt) { + switch (pseudoC) { + case PSI_SLI: s = "d <<= a"; break; + case PSI_SRI: s = "d >>= a"; break; + case PSI_DSLI32: s = "d <<= A"; break; + case PSI_DSRI32: s = "d >>= A"; break; + case PSI_SLV: s = "d <<= s"; break; + case PSI_SRV: s = "d >>= s"; break; + default: break; + } + } else if (insn.fd == insn.fs) { + switch (pseudoC) { + case PSI_ADDF: s = "D += T"; break; + case PSI_SUBF: s = "D -= T"; break; + case PSI_MULF: s = "D *= T"; break; + case PSI_DIVF: s = "D /= T"; break; + default: break; + } + } + + if (s != NULL) { + *formatStr = s; + return TRUE; + } + + return FALSE; +} + #define INSN_RAW_JR_RA INSNDATA_6_5_5_5_5_6(OPC_SPECIAL, REG_CPU_RA, 0, 0, 0, OPS_JR ).raw // 0x03E00008 #define INSN_RAW_TEQ_R0_R0 INSNDATA_6_5_5_5_5_6(OPC_SPECIAL, 0, 0, 0, 0, OPS_TEQ).raw // 0x00000034 @@ -885,7 +976,7 @@ char* cs_insn_to_pseudo_c(InsnData insn, const char** comment) { return ""; } - u8 pseudoC = info->pseudoC; + MIPS_C_Pseudocodes pseudoC = info->pseudoC; const char* formatStr = pseudo_c_code_formats[pseudoC]; if (cs_get_setting_val(CS_OPT_GROUP_PAGE_DISASM, CS_OPT_DISASM_PSEUDOINSNS)) { @@ -898,9 +989,15 @@ char* cs_insn_to_pseudo_c(InsnData insn, const char** comment) { } else if (formatStr[0] == PSC_RA) { // "and link" formatStr += STRLEN(C_LINK); *comment = "RA=PC+2;"; + } else { + modify_pseudo_c_assignment_str(&formatStr, insn, pseudoC); } } + if (*comment == NULL) { + *comment = comment_from_insn(insn, info); + } + const char* c = &formatStr[0]; const RGBA32 baseColor = gCSDefaultPrintColor; @@ -978,22 +1075,23 @@ char* cs_insn_to_pseudo_c(InsnData insn, const char** comment) { break; case PSC_CACHE: const CacheInfo* cacheInfo = &sCacheInfos[insn.cache_cache]; - const char** opList = cacheInfo->opList; - const char* opName = NULL; - if (opList != NULL) { - opName = opList[insn.cache_op]; - } - - if (opName != NULL) { - strp += sprintf(strp, opName); - } else { - strp += sprintf(strp, STR_HEX_PREFIX"%X", insn.rt); - } - const char* cacheName = cacheInfo->name; + if (cacheName != NULL) { - *comment = cacheName; + const char** opList = cacheInfo->opList; + const char* opName = NULL; + + if (opList != NULL) { + opName = opList[insn.cache_op]; + + if (opName != NULL) { + strp += sprintf(strp, "%s.%s", cacheName, opName); + break; + } + } } + + strp += sprintf(strp, STR_HEX_PREFIX"%X", insn.rt); break; } } diff --git a/src/crash_screen/util/insn_disasm.h b/src/crash_screen/util/insn_disasm.h index cf607ba13..2d3935cdb 100644 --- a/src/crash_screen/util/insn_disasm.h +++ b/src/crash_screen/util/insn_disasm.h @@ -571,9 +571,13 @@ STATIC_ASSERT_STRUCT_SIZE_EQ(InsnData, sizeof(u32)); ((_c) >= '0' && (_c) <= '3') \ ? (((_c) - '0') + STRLEN(INSN_ALPHABET_STR_0)) \ : ( \ - (IS_UPPERCASE(_c) || IS_LOWERCASE(_c)) \ + (IS_UPPERCASE(_c)) \ ? (((_c) - 'A') + STRLEN(INSN_ALPHABET_STR_0 INSN_ALPHABET_STR_N)) \ - : 0 \ + : ( \ + (IS_LOWERCASE(_c)) \ + ? (((_c) - 'a') + STRLEN(INSN_ALPHABET_STR_0 INSN_ALPHABET_STR_N)) \ + : 0 \ + ) \ ) \ ) \ ) @@ -636,7 +640,7 @@ typedef union InsnTemplate { /*02*/ u8 opcode : 6; // Opcode to compare to. }; /*0x01*/ /*0x07*/ struct PACKED { - /*00*/ u8 hasFmt : 1; // Whether the name has a format suffix. + /*00*/ u8 suffix : 1; // Whether the name has a format suffix. /*01*/ u8 pseudoC : 7; // enum MIPS_C_Pseudocodes //! TODO: }; }; @@ -648,10 +652,10 @@ typedef union InsnTemplate { } InsnTemplate; /*0x08*/ STATIC_ASSERT_STRUCT_SIZE_LE(InsnTemplate, 0x8); -#define INSN_DB_IMPL(_opcode, _name, _hasFmt, _params, _output, _pseudoC, _ex1, _ex2, _exo) { \ +#define INSN_DB_IMPL(_opcode, _name, _suffix, _params, _output, _pseudoC, _ex1, _ex2, _exo) { \ .opcode = _opcode, \ .name = PACK_STR7(_name), \ - .hasFmt = _hasFmt, \ + .suffix = _suffix, \ .params = _params, \ .output = _output, \ .pseudoC = _pseudoC, \ @@ -660,10 +664,10 @@ STATIC_ASSERT_STRUCT_SIZE_LE(InsnTemplate, 0x8); .exo = _exo, \ } -#define INSN_DB(_opcode, _name, _hasFmt, _params, _output, _pseudoC) \ - INSN_DB_IMPL(_opcode, _name, _hasFmt, _params, _output, _pseudoC, EXR_00, EXR_00, 0b00) -#define INSN_EX(_opcode, _name, _hasFmt, _params, _output, _pseudoC, _ex1, _ex2, _exo) \ - INSN_DB_IMPL(_opcode, _name, _hasFmt, _params, _output, _pseudoC, _ex1, _ex2, _exo) +#define INSN_DB(_opcode, _name, _suffix, _params, _output, _pseudoC) \ + INSN_DB_IMPL(_opcode, _name, _suffix, _params, _output, _pseudoC, EXR_00, EXR_00, 0b00) +#define INSN_EX(_opcode, _name, _suffix, _params, _output, _pseudoC, _ex1, _ex2, _exo) \ + INSN_DB_IMPL(_opcode, _name, _suffix, _params, _output, _pseudoC, _ex1, _ex2, _exo) #define INSN_END() {}