diff --git a/CHANGES b/CHANGES index c201351bc..fe37bd382 100644 --- a/CHANGES +++ b/CHANGES @@ -45,6 +45,7 @@ Bugfixes: - GB Video: Hblank IRQs should mask LYC=LY IRQs - GB Audio: Reset envelope timer when reseting sound channel - SDL: Prevent crash on cores with no audio + - ARM7: Decode MCR/MRC Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers diff --git a/src/arm/decoder-arm.c b/src/arm/decoder-arm.c index 3b082a0d2..8ec0b9eb7 100644 --- a/src/arm/decoder-arm.c +++ b/src/arm/decoder-arm.c @@ -355,11 +355,24 @@ DEFINE_DECODER_ARM(BX, BX, // Begin coprocessor definitions -DEFINE_DECODER_ARM(CDP, ILL, info->operandFormat = ARM_OPERAND_NONE;) -DEFINE_DECODER_ARM(LDC, ILL, info->operandFormat = ARM_OPERAND_NONE;) -DEFINE_DECODER_ARM(STC, ILL, info->operandFormat = ARM_OPERAND_NONE;) -DEFINE_DECODER_ARM(MCR, ILL, info->operandFormat = ARM_OPERAND_NONE;) -DEFINE_DECODER_ARM(MRC, ILL, info->operandFormat = ARM_OPERAND_NONE;) +#define DEFINE_DECODER_COPROCESSOR(NAME, FORMAT) \ + DEFINE_DECODER_ARM(NAME, NAME, \ + info->cp.op1 = (opcode >> 21) & 7; \ + info->cp.op2 = (opcode >> 5) & 7; \ + info->op1.reg = (opcode >> 12) & 0xF; \ + info->cp.cp = (opcode >> 8) & 0xF; \ + info->op2.reg = (opcode >> 16) & 0xF; \ + info->op3.reg = opcode & 0xF; \ + info->operandFormat = ARM_OPERAND_REGISTER_1 |\ + ARM_OPERAND_COPROCESSOR_REG_2 | \ + ARM_OPERAND_COPROCESSOR_REG_3 | \ + (FORMAT);) + +DEFINE_DECODER_ARM(CDP, CDP, info->operandFormat = ARM_OPERAND_NONE;) +DEFINE_DECODER_ARM(LDC, LDC, info->operandFormat = ARM_OPERAND_NONE;) +DEFINE_DECODER_ARM(STC, STC, info->operandFormat = ARM_OPERAND_NONE;) +DEFINE_DECODER_COPROCESSOR(MCR, ARM_OPERAND_AFFECTED_2 | ARM_OPERAND_AFFECTED_3) +DEFINE_DECODER_COPROCESSOR(MRC, ARM_OPERAND_AFFECTED_1) // Begin miscellaneous definitions diff --git a/src/arm/decoder.c b/src/arm/decoder.c index 8e5ef3f8d..d31951fcf 100644 --- a/src/arm/decoder.c +++ b/src/arm/decoder.c @@ -251,15 +251,19 @@ static const char* _armMnemonicStrings[] = { "bkpt", "bl", "bx", + "cdp", "cmn", "cmp", "eor", + "ldc", "ldm", "ldr", "lsl", "lsr", + "mcr", "mla", "mov", + "mrc", "mrs", "msr", "mul", @@ -272,6 +276,7 @@ static const char* _armMnemonicStrings[] = { "sbc", "smlal", "smull", + "stc", "stm", "str", "sub", @@ -388,6 +393,10 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i } break; default: + if (info->operandFormat & ARM_OPERAND_COPROCESSOR) { + written = snprintf(buffer, blen - 1, "p%i, %i, ", info->cp.cp, info->cp.op1); + ADVANCE(written); + } if (info->operandFormat & ARM_OPERAND_IMMEDIATE_1) { written = snprintf(buffer, blen - 1, "#%i", info->op1.immediate); ADVANCE(written); @@ -401,6 +410,8 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = _decodePSR(info->op1.psrBits, buffer, blen); ADVANCE(written); } + } else if (info->operandFormat & ARM_OPERAND_COPROCESSOR_REG_1) { + written = snprintf(buffer, blen - 1, "c%i", info->op1.reg); } if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_1) { written = _decodeShift(info->op1, true, buffer, blen); @@ -422,6 +433,9 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i } else if (info->operandFormat & ARM_OPERAND_REGISTER_2) { written = _decodeRegister(info->op2.reg, buffer, blen); ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_COPROCESSOR_REG_2) { + written = snprintf(buffer, blen - 1, "c%i", info->op2.reg); + ADVANCE(written); } if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_2) { written = _decodeShift(info->op2, true, buffer, blen); @@ -443,6 +457,9 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i } else if (info->operandFormat & ARM_OPERAND_REGISTER_3) { written = _decodeRegister(info->op3.reg, buffer, blen); ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_COPROCESSOR_REG_3) { + written = snprintf(buffer, blen - 1, "c%i", info->op3.reg); + ADVANCE(written); } if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_3) { written = _decodeShift(info->op3, true, buffer, blen); @@ -464,6 +481,9 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i } else if (info->operandFormat & ARM_OPERAND_REGISTER_4) { written = _decodeRegister(info->op4.reg, buffer, blen); ADVANCE(written); + } else if (info->operandFormat & ARM_OPERAND_COPROCESSOR_REG_4) { + written = snprintf(buffer, blen - 1, "c%i", info->op4.reg); + ADVANCE(written); } if (info->operandFormat & ARM_OPERAND_SHIFT_REGISTER_4) { written = _decodeShift(info->op4, true, buffer, blen); @@ -472,6 +492,10 @@ int ARMDisassemble(struct ARMInstructionInfo* info, uint32_t pc, char* buffer, i written = _decodeShift(info->op4, false, buffer, blen); ADVANCE(written); } + if (info->cp.op2) { + written = snprintf(buffer, blen - 1, ", %i", info->cp.op2); + ADVANCE(written); + } break; } buffer[blen - 1] = '\0'; diff --git a/src/arm/decoder.h b/src/arm/decoder.h index 6ca478046..a466de048 100644 --- a/src/arm/decoder.h +++ b/src/arm/decoder.h @@ -14,6 +14,7 @@ // Bit 3: the destination of this operand is affected by this opcode // Bit 4: this operand is shifted by a register // Bit 5: this operand is shifted by an immediate +// Bit 6: a coprocessor register is involved with this command #define ARM_OPERAND_NONE 0x00000000 #define ARM_OPERAND_REGISTER_1 0x00000001 #define ARM_OPERAND_IMMEDIATE_1 0x00000002 @@ -21,6 +22,7 @@ #define ARM_OPERAND_AFFECTED_1 0x00000008 #define ARM_OPERAND_SHIFT_REGISTER_1 0x00000010 #define ARM_OPERAND_SHIFT_IMMEDIATE_1 0x00000020 +#define ARM_OPERAND_COPROCESSOR_REG_1 0x00000040 #define ARM_OPERAND_1 0x000000FF #define ARM_OPERAND_REGISTER_2 0x00000100 @@ -29,6 +31,7 @@ #define ARM_OPERAND_AFFECTED_2 0x00000800 #define ARM_OPERAND_SHIFT_REGISTER_2 0x00001000 #define ARM_OPERAND_SHIFT_IMMEDIATE_2 0x00002000 +#define ARM_OPERAND_COPROCESSOR_REG_2 0x00004000 #define ARM_OPERAND_2 0x0000FF00 #define ARM_OPERAND_REGISTER_3 0x00010000 @@ -37,6 +40,7 @@ #define ARM_OPERAND_AFFECTED_3 0x00080000 #define ARM_OPERAND_SHIFT_REGISTER_3 0x00100000 #define ARM_OPERAND_SHIFT_IMMEDIATE_3 0x00200000 +#define ARM_OPERAND_COPROCESSOR_REG_3 0x00400000 #define ARM_OPERAND_3 0x00FF0000 #define ARM_OPERAND_REGISTER_4 0x01000000 @@ -45,9 +49,11 @@ #define ARM_OPERAND_AFFECTED_4 0x08000000 #define ARM_OPERAND_SHIFT_REGISTER_4 0x10000000 #define ARM_OPERAND_SHIFT_IMMEDIATE_4 0x20000000 +#define ARM_OPERAND_COPROCESSOR_REG_4 0x40000000 #define ARM_OPERAND_4 0xFF000000 #define ARM_OPERAND_MEMORY (ARM_OPERAND_MEMORY_1 | ARM_OPERAND_MEMORY_2 | ARM_OPERAND_MEMORY_3 | ARM_OPERAND_MEMORY_4) +#define ARM_OPERAND_COPROCESSOR (ARM_OPERAND_COPROCESSOR_REG_1 | ARM_OPERAND_COPROCESSOR_REG_2 | ARM_OPERAND_COPROCESSOR_REG_3 | ARM_OPERAND_COPROCESSOR_REG_4) #define ARM_MEMORY_REGISTER_BASE 0x0001 #define ARM_MEMORY_IMMEDIATE_OFFSET 0x0002 @@ -112,6 +118,12 @@ union ARMOperand { int32_t immediate; }; +struct ARMCoprocessor { + uint8_t cp : 4; + uint8_t op1 : 4; + uint8_t op2 : 3; +}; + enum ARMMemoryAccessType { ARM_ACCESS_WORD = 4, ARM_ACCESS_HALFWORD = 2, @@ -147,15 +159,19 @@ enum ARMMnemonic { ARM_MN_BKPT, ARM_MN_BL, ARM_MN_BX, + ARM_MN_CDP, ARM_MN_CMN, ARM_MN_CMP, ARM_MN_EOR, + ARM_MN_LDC, ARM_MN_LDM, ARM_MN_LDR, ARM_MN_LSL, ARM_MN_LSR, + ARM_MN_MCR, ARM_MN_MLA, ARM_MN_MOV, + ARM_MN_MRC, ARM_MN_MRS, ARM_MN_MSR, ARM_MN_MUL, @@ -168,6 +184,7 @@ enum ARMMnemonic { ARM_MN_SBC, ARM_MN_SMLAL, ARM_MN_SMULL, + ARM_MN_STC, ARM_MN_STM, ARM_MN_STR, ARM_MN_SUB, @@ -206,6 +223,7 @@ struct ARMInstructionInfo { unsigned nInstructionCycles : 4; unsigned sDataCycles : 10; unsigned nDataCycles : 10; + struct ARMCoprocessor cp; }; void ARMDecodeARM(uint32_t opcode, struct ARMInstructionInfo* info); diff --git a/src/arm/emitter-arm.h b/src/arm/emitter-arm.h index e99a1b7ee..06a57dd43 100644 --- a/src/arm/emitter-arm.h +++ b/src/arm/emitter-arm.h @@ -67,8 +67,10 @@ DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)), \ DO_8(DECLARE_INSTRUCTION_ARM(EMITTER, NAME)) -#define DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, NAME1, NAME2) \ - DO_8(DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), DECLARE_INSTRUCTION_ARM(EMITTER, NAME2)))) +#define DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, NAME1, NAME2, NAME3) \ + DO_8(DO_INTERLACE( \ + DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), DECLARE_INSTRUCTION_ARM(EMITTER, NAME2))), \ + DO_8(DO_INTERLACE(DECLARE_INSTRUCTION_ARM(EMITTER, NAME1), DECLARE_INSTRUCTION_ARM(EMITTER, NAME3))))) #define DECLARE_ARM_SWI_BLOCK(EMITTER) \ DO_256(DECLARE_INSTRUCTION_ARM(EMITTER, SWI)) @@ -328,8 +330,7 @@ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, ), \ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, STC, P, U, N, W), \ DECLARE_ARM_LOAD_STORE_COPROCESSOR_BLOCK(EMITTER, LDC, P, U, N, W), \ - DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MCR), \ - DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MRC), \ + DECLARE_ARM_COPROCESSOR_BLOCK(EMITTER, CDP, MCR, MRC), \ DECLARE_ARM_SWI_BLOCK(EMITTER) #endif