nkeynes@30: /** nkeynes@302: * $Id: armdasm.c,v 1.12 2007-01-17 21:27:20 nkeynes Exp $ nkeynes@30: * nkeynes@4: * armdasm.c 21 Aug 2004 - ARM7tdmi (ARMv4) disassembler nkeynes@4: * nkeynes@30: * Copyright (c) 2005 Nathan Keynes. nkeynes@30: * nkeynes@30: * This program is free software; you can redistribute it and/or modify nkeynes@30: * it under the terms of the GNU General Public License as published by nkeynes@30: * the Free Software Foundation; either version 2 of the License, or nkeynes@30: * (at your option) any later version. nkeynes@30: * nkeynes@30: * This program is distributed in the hope that it will be useful, nkeynes@30: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@30: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@30: * GNU General Public License for more details. nkeynes@4: */ nkeynes@4: nkeynes@7: #include "aica/armcore.h" nkeynes@11: #include "aica/armdasm.h" nkeynes@7: #include nkeynes@4: nkeynes@4: #define COND(ir) (ir>>28) nkeynes@4: #define OPCODE(ir) ((ir>>20)&0x1F) nkeynes@4: #define GRP(ir) ((ir>>26)&0x03) nkeynes@4: #define IFLAG(ir) (ir&0x02000000) nkeynes@4: #define SFLAG(ir) (ir&0x00100000) nkeynes@4: #define PFLAG(ir) (ir&0x01000000) nkeynes@4: #define UFLAG(ir) (ir&0x00800000) nkeynes@4: #define BFLAG(ir) (ir&0x00400000) nkeynes@7: #define WFLAG(ir) (ir&0x00200000) nkeynes@4: #define LFLAG(ir) SFLAG(ir) nkeynes@4: #define RN(ir) ((ir>>16)&0x0F) nkeynes@4: #define RD(ir) ((ir>>12)&0x0F) nkeynes@4: #define RS(ir) ((ir>>8)&0x0F) nkeynes@4: #define RM(ir) (ir&0x0F) nkeynes@4: nkeynes@4: #define IMM8(ir) (ir&0xFF) nkeynes@4: #define IMM12(ir) (ir&0xFFF) nkeynes@7: #define SHIFTIMM(ir) ((ir>>7)&0x1F) nkeynes@7: #define IMMROT(ir) ((ir>>7)&0x1E) nkeynes@4: #define SHIFT(ir) ((ir>>4)&0x07) nkeynes@4: #define DISP24(ir) ((ir&0x00FFFFFF)) nkeynes@4: #define FSXC(ir) msrFieldMask[RN(ir)] nkeynes@4: #define ROTIMM12(ir) ROTATE_RIGHT_LONG(IMM8(ir),IMMROT(ir)) nkeynes@13: #define SIGNEXT24(n) ((n&0x00800000) ? (n|0xFF000000) : (n&0x00FFFFFF)) nkeynes@13: nkeynes@4: nkeynes@11: nkeynes@11: const struct reg_desc_struct arm_reg_map[] = nkeynes@13: { {"R0", REG_INT, &armr.r[0]}, {"R1", REG_INT, &armr.r[1]}, nkeynes@11: {"R2", REG_INT, &armr.r[2]}, {"R3", REG_INT, &armr.r[3]}, nkeynes@11: {"R4", REG_INT, &armr.r[4]}, {"R5", REG_INT, &armr.r[5]}, nkeynes@11: {"R6", REG_INT, &armr.r[6]}, {"R7", REG_INT, &armr.r[7]}, nkeynes@11: {"R8", REG_INT, &armr.r[8]}, {"R9", REG_INT, &armr.r[9]}, nkeynes@11: {"R10",REG_INT, &armr.r[10]}, {"R11",REG_INT, &armr.r[11]}, nkeynes@11: {"R12",REG_INT, &armr.r[12]}, {"R13",REG_INT, &armr.r[13]}, nkeynes@11: {"R14",REG_INT, &armr.r[14]}, {"R15",REG_INT, &armr.r[15]}, nkeynes@11: {"CPSR", REG_INT, &armr.cpsr}, {"SPSR", REG_INT, &armr.spsr}, nkeynes@11: {NULL, 0, NULL} }; nkeynes@11: nkeynes@11: nkeynes@14: const struct cpu_desc_struct arm_cpu_desc = nkeynes@43: { "ARM7", arm_disasm_instruction, arm_execute_instruction, arm_has_page, nkeynes@43: arm_set_breakpoint, arm_clear_breakpoint, arm_get_breakpoint, 4, nkeynes@14: (char *)&armr, sizeof(armr), arm_reg_map, nkeynes@302: &armr.r[15] }; nkeynes@14: const struct cpu_desc_struct armt_cpu_desc = nkeynes@48: { "ARM7T", armt_disasm_instruction, arm_execute_instruction, arm_has_page, nkeynes@48: arm_set_breakpoint, arm_clear_breakpoint, arm_get_breakpoint, 2, nkeynes@14: (char*)&armr, sizeof(armr), arm_reg_map, nkeynes@302: &armr.r[15] }; nkeynes@11: nkeynes@11: nkeynes@11: nkeynes@11: nkeynes@4: char *conditionNames[] = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", nkeynes@4: "HI", "LS", "GE", "LT", "GT", "LE", " " /*AL*/, "NV" }; nkeynes@4: nkeynes@4: /* fsxc */ nkeynes@4: char *msrFieldMask[] = { "", "c", "x", "xc", "s", "sc", "sx", "sxc", nkeynes@4: "f", "fc", "fx", "fxc", "fs", "fsc", "fsx", "fsxc" }; nkeynes@7: char *ldmModes[] = { "DA", "IA", "DB", "IB" }; nkeynes@4: nkeynes@4: #define UNIMP(ir) snprintf( buf, len, "??? " ) nkeynes@4: nkeynes@7: int arm_disasm_shift_operand( uint32_t ir, char *buf, int len ) nkeynes@4: { nkeynes@7: uint32_t operand, tmp; nkeynes@7: if( IFLAG(ir) == 0 ) { nkeynes@7: switch(SHIFT(ir)) { nkeynes@7: case 0: /* (Rm << imm) */ nkeynes@13: tmp = SHIFTIMM(ir); nkeynes@13: if( tmp != 0 ) { nkeynes@13: return snprintf(buf, len, "R%d << %d", RM(ir), tmp ); nkeynes@13: } else { nkeynes@13: return snprintf(buf, len, "R%d", RM(ir)); nkeynes@13: } nkeynes@7: case 1: /* (Rm << Rs) */ nkeynes@7: return snprintf(buf, len, "R%d << R%d", RM(ir), RS(ir) ); nkeynes@7: case 2: /* (Rm >> imm) */ nkeynes@7: return snprintf(buf, len, "R%d >> %d", RM(ir), SHIFTIMM(ir) ); nkeynes@7: case 3: /* (Rm >> Rs) */ nkeynes@7: return snprintf(buf, len, "R%d >> R%d", RM(ir), RS(ir) ); nkeynes@7: case 4: /* (Rm >>> imm) */ nkeynes@7: return snprintf(buf, len, "R%d >>> %d", RM(ir), SHIFTIMM(ir) ); nkeynes@7: case 5: /* (Rm >>> Rs) */ nkeynes@7: return snprintf(buf, len, "R%d >>> R%d", RM(ir), RS(ir) ); nkeynes@7: case 6: nkeynes@7: tmp = SHIFTIMM(ir); nkeynes@7: if( tmp == 0 ) /* RRX aka rotate with carry */ nkeynes@7: return snprintf(buf, len, "R%d roc 1", RM(ir) ); nkeynes@7: else nkeynes@7: return snprintf(buf, len, "R%d rot %d", RM(ir), SHIFTIMM(ir) ); nkeynes@7: case 7: nkeynes@7: return snprintf(buf, len, "R%d rot R%d", RM(ir), RS(ir) ); nkeynes@7: } nkeynes@7: } else { nkeynes@7: operand = IMM8(ir); nkeynes@7: tmp = IMMROT(ir); nkeynes@7: operand = ROTATE_RIGHT_LONG(operand, tmp); nkeynes@51: return snprintf(buf, len, "#%08Xh", operand ); nkeynes@7: } nkeynes@7: } nkeynes@7: nkeynes@7: static int arm_disasm_address_index( uint32_t ir, char *buf, int len ) nkeynes@7: { nkeynes@7: uint32_t tmp; nkeynes@7: nkeynes@7: switch(SHIFT(ir)) { nkeynes@7: case 0: /* (Rm << imm) */ nkeynes@13: tmp = SHIFTIMM(ir); nkeynes@13: if( tmp != 0 ) { nkeynes@13: return snprintf( buf, len, "R%d << %d", RM(ir), tmp ); nkeynes@13: } else { nkeynes@13: return snprintf( buf, len, "R%d", RM(ir) ); nkeynes@13: } nkeynes@7: case 2: /* (Rm >> imm) */ nkeynes@7: return snprintf( buf, len, "R%d >> %d", RM(ir), SHIFTIMM(ir) ); nkeynes@7: case 4: /* (Rm >>> imm) */ nkeynes@7: return snprintf( buf, len, "R%d >>> %d", RM(ir), SHIFTIMM(ir) ); nkeynes@7: case 6: nkeynes@7: tmp = SHIFTIMM(ir); nkeynes@7: if( tmp == 0 ) /* RRX aka rotate with carry */ nkeynes@7: return snprintf( buf, len, "R%d roc 1", RM(ir) ); nkeynes@7: else nkeynes@7: return snprintf( buf, len, "R%d rot %d", RM(ir), tmp ); nkeynes@7: default: nkeynes@7: return UNIMP(ir); nkeynes@7: } nkeynes@7: } nkeynes@7: nkeynes@13: static int arm_disasm_address_operand( uint32_t ir, char *buf, int len, int pc ) nkeynes@7: { nkeynes@7: char shift[32]; nkeynes@7: nkeynes@13: char sign = UFLAG(ir) ? '+' : '-'; nkeynes@7: /* I P U . W */ nkeynes@7: switch( (ir>>21)&0x19 ) { nkeynes@7: case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */ nkeynes@7: case 1: nkeynes@51: return snprintf( buf, len, "[R%d], R%d %c= #%04Xh", RN(ir), RN(ir), sign, IMM12(ir) ); nkeynes@7: case 8: /* Rn - imm offset [5.2.2 A5-20] */ nkeynes@13: if( RN(ir) == 15 ) { /* PC relative - decode here */ nkeynes@48: uint32_t addr = pc + 8 + (UFLAG(ir) ? IMM12(ir) : -IMM12(ir)); nkeynes@48: return snprintf( buf, len, "[$%08Xh] <- #%08Xh", addr, nkeynes@48: arm_read_long( addr ) ); nkeynes@13: } else { nkeynes@51: return snprintf( buf, len, "[R%d %c #%04Xh]", RN(ir), sign, IMM12(ir) ); nkeynes@13: } nkeynes@7: case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */ nkeynes@51: return snprintf( buf, len, "[R%d %c= #%04Xh]", RN(ir), sign, IMM12(ir) ); nkeynes@7: case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */ nkeynes@7: case 17: nkeynes@7: arm_disasm_address_index( ir, shift, sizeof(shift) ); nkeynes@7: return snprintf( buf, len, "[R%d], R%d %c= %s", RN(ir), RN(ir), sign, shift ); nkeynes@7: case 24: /* Rn - Rm [5.2.4 A5-23] */ nkeynes@7: arm_disasm_address_index( ir, shift, sizeof(shift) ); nkeynes@7: return snprintf( buf, len, "[R%d %c %s]", RN(ir), sign, shift ); nkeynes@7: case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */ nkeynes@7: arm_disasm_address_index( ir, shift, sizeof(shift) ); nkeynes@7: return snprintf( buf, len, "[R%d %c= %s]", RN(ir), sign, shift ); nkeynes@7: default: nkeynes@7: return UNIMP(ir); /* Unreachable */ nkeynes@7: } nkeynes@7: } nkeynes@7: nkeynes@11: uint32_t arm_disasm_instruction( uint32_t pc, char *buf, int len, char *opcode ) nkeynes@7: { nkeynes@48: char operand[64]; nkeynes@11: uint32_t ir = arm_read_long(pc); nkeynes@11: int i,j; nkeynes@7: nkeynes@11: sprintf( opcode, "%02X %02X %02X %02X", ir&0xFF, (ir>>8) & 0xFF, nkeynes@11: (ir>>16)&0xFF, (ir>>24) ); nkeynes@11: nkeynes@4: if( COND(ir) == 0x0F ) { nkeynes@4: UNIMP(ir); nkeynes@4: return pc+4; nkeynes@4: } nkeynes@4: char *cond = conditionNames[COND(ir)]; nkeynes@4: nkeynes@4: switch( GRP(ir) ) { nkeynes@4: case 0: nkeynes@4: if( (ir & 0x0D900000) == 0x01000000 ) { nkeynes@4: /* Instructions that aren't actual data processing */ nkeynes@4: switch( ir & 0x0FF000F0 ) { nkeynes@4: case 0x01200010: /* BXcc */ nkeynes@4: snprintf(buf, len, "BX%s R%d", cond, RM(ir)); nkeynes@4: break; nkeynes@4: case 0x01000000: /* MRS Rd, CPSR */ nkeynes@4: snprintf(buf, len, "MRS%s R%d, CPSR", cond, RD(ir)); nkeynes@4: break; nkeynes@4: case 0x01400000: /* MRS Rd, SPSR */ nkeynes@4: snprintf(buf, len, "MRS%s R%d, SPSR", cond, RD(ir)); nkeynes@4: break; nkeynes@4: case 0x01200000: /* MSR CPSR, Rm */ nkeynes@4: snprintf(buf, len, "MSR%s CPSR_%s, R%d", cond, FSXC(ir), RM(ir)); nkeynes@4: break; nkeynes@4: case 0x01600000: /* MSR SPSR, Rm */ nkeynes@4: snprintf(buf, len, "MSR%s SPSR_%s, R%d", cond, FSXC(ir), RM(ir)); nkeynes@4: break; nkeynes@4: case 0x03200000: /* MSR CPSR, imm */ nkeynes@4: snprintf(buf, len, "MSR%s CPSR_%s, #%08X", cond, FSXC(ir), ROTIMM12(ir)); nkeynes@4: break; nkeynes@4: case 0x03600000: /* MSR SPSR, imm */ nkeynes@4: snprintf(buf, len, "MSR%s SPSR_%s, #%08X", cond, FSXC(ir), ROTIMM12(ir)); nkeynes@4: break; nkeynes@4: default: nkeynes@4: UNIMP(); nkeynes@4: } nkeynes@4: } else if( (ir & 0x0E000090) == 0x00000090 ) { nkeynes@4: /* Neither are these */ nkeynes@4: switch( (ir>>5)&0x03 ) { nkeynes@4: case 0: nkeynes@4: /* Arithmetic extension area */ nkeynes@4: switch(OPCODE(ir)) { nkeynes@4: case 0: /* MUL */ nkeynes@4: snprintf(buf,len, "MUL%s R%d, R%d, R%d", cond, RN(ir), RM(ir), RS(ir) ); nkeynes@4: break; nkeynes@4: case 1: /* MULS */ nkeynes@4: break; nkeynes@4: case 2: /* MLA */ nkeynes@4: snprintf(buf,len, "MLA%s R%d, R%d, R%d, R%d", cond, RN(ir), RM(ir), RS(ir), RD(ir) ); nkeynes@4: break; nkeynes@4: case 3: /* MLAS */ nkeynes@4: break; nkeynes@4: case 8: /* UMULL */ nkeynes@4: snprintf(buf,len, "UMULL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) ); nkeynes@4: break; nkeynes@4: case 9: /* UMULLS */ nkeynes@4: break; nkeynes@4: case 10: /* UMLAL */ nkeynes@4: snprintf(buf,len, "UMLAL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) ); nkeynes@4: break; nkeynes@4: case 11: /* UMLALS */ nkeynes@4: break; nkeynes@4: case 12: /* SMULL */ nkeynes@4: snprintf(buf,len, "SMULL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) ); nkeynes@4: break; nkeynes@4: case 13: /* SMULLS */ nkeynes@4: break; nkeynes@4: case 14: /* SMLAL */ nkeynes@4: snprintf(buf,len, "SMLAL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) ); nkeynes@4: break; nkeynes@4: case 15: /* SMLALS */ nkeynes@4: nkeynes@4: break; nkeynes@4: case 16: /* SWP */ nkeynes@4: snprintf(buf,len, "SWP%s R%d, R%d, [R%d]", cond, RD(ir), RN(ir), RM(ir) ); nkeynes@4: break; nkeynes@4: case 20: /* SWPB */ nkeynes@4: snprintf(buf,len, "SWPB%s R%d, R%d, [R%d]", cond, RD(ir), RN(ir), RM(ir) ); nkeynes@4: break; nkeynes@4: default: nkeynes@4: UNIMP(ir); nkeynes@4: } nkeynes@4: break; nkeynes@4: case 1: nkeynes@4: if( LFLAG(ir) ) { nkeynes@4: /* LDRH */ nkeynes@4: } else { nkeynes@4: /* STRH */ nkeynes@4: } nkeynes@48: UNIMP(ir); nkeynes@4: break; nkeynes@4: case 2: nkeynes@4: if( LFLAG(ir) ) { nkeynes@4: /* LDRSB */ nkeynes@4: } else { nkeynes@4: } nkeynes@48: UNIMP(ir); nkeynes@4: break; nkeynes@4: case 3: nkeynes@4: if( LFLAG(ir) ) { nkeynes@4: /* LDRSH */ nkeynes@4: } else { nkeynes@4: } nkeynes@48: UNIMP(ir); nkeynes@4: break; nkeynes@4: } nkeynes@4: } else { nkeynes@4: /* Data processing */ nkeynes@4: nkeynes@4: switch(OPCODE(ir)) { nkeynes@4: case 0: /* AND Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "AND%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 1: /* ANDS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "ANDS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 2: /* EOR Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "EOR%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 3: /* EORS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "EORS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 4: /* SUB Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "SUB%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 5: /* SUBS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "SUBS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@7: case 6: /* RSB Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "RSB%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@7: case 7: /* RSBS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "RSBS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 8: /* ADD Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "ADD%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 9: /* ADDS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "ADDS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@7: case 10: /* ADC Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "ADC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@7: case 11: /* ADCS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "ADCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@7: case 12: /* SBC Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "SBC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@7: break; nkeynes@7: case 13: /* SBCS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "SBCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@7: break; nkeynes@7: case 14: /* RSC Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "RSC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@7: break; nkeynes@7: case 15: /* RSCS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "RSCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@7: break; nkeynes@48: case 17: /* TST Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@64: snprintf(buf, len, "TST%s R%d, %s", cond, RN(ir), operand); nkeynes@7: break; nkeynes@48: case 19: /* TEQ Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@64: snprintf(buf, len, "TEQ%s R%d, %s", cond, RN(ir), operand); nkeynes@7: break; nkeynes@48: case 21: /* CMP Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@64: snprintf(buf, len, "CMP%s R%d, %s", cond, RN(ir), operand); nkeynes@7: break; nkeynes@48: case 23: /* CMN Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@64: snprintf(buf, len, "CMN%s R%d, %s", cond, RN(ir), operand); nkeynes@4: break; nkeynes@4: case 24: /* ORR Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "ORR%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 25: /* ORRS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "ORRS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@51: case 26: /* MOV Rd, operand */ nkeynes@51: if( ir == 0xE1A00000 ) { nkeynes@51: /* Not technically a different instruction, nkeynes@51: * but this one is commonly used as a NOP, nkeynes@51: * so... nkeynes@51: */ nkeynes@51: snprintf(buf, len, "NOP"); nkeynes@51: } else { nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "MOV%s R%d, %s", cond, RD(ir), operand); nkeynes@51: } nkeynes@51: break; nkeynes@51: case 27: /* MOVS Rd, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "MOVS%s R%d, %s", cond, RD(ir), operand); nkeynes@4: break; nkeynes@4: case 28: /* BIC Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "BIC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@4: case 29: /* BICS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "BICS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand); nkeynes@4: break; nkeynes@7: case 30: /* MVN Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "MVN%s R%d, %s", cond, RD(ir), operand); nkeynes@4: break; nkeynes@7: case 31: /* MVNS Rd, Rn, operand */ nkeynes@7: arm_disasm_shift_operand(ir, operand, sizeof(operand)); nkeynes@7: snprintf(buf, len, "MVNS%s R%d, %s", cond, RD(ir), operand); nkeynes@4: break; nkeynes@4: default: nkeynes@4: UNIMP(ir); nkeynes@4: } nkeynes@4: } nkeynes@4: break; nkeynes@4: case 1: /* Load/store */ nkeynes@13: arm_disasm_address_operand( ir, operand, sizeof(operand), pc ); nkeynes@7: switch( (ir>>20)&0x17 ) { nkeynes@7: case 0: nkeynes@7: case 16: nkeynes@7: case 18: nkeynes@7: snprintf(buf, len, "STR%s R%d, %s", cond, RD(ir), operand ); nkeynes@7: break; nkeynes@7: case 1: nkeynes@7: case 17: nkeynes@7: case 19: nkeynes@7: snprintf(buf, len, "LDR%s R%d, %s", cond, RD(ir), operand ); nkeynes@7: break; nkeynes@7: case 2: nkeynes@7: snprintf(buf, len, "STRT%s R%d, %s", cond, RD(ir), operand ); nkeynes@7: break; nkeynes@7: case 3: nkeynes@7: snprintf(buf, len, "LDRT%s R%d, %s", cond, RD(ir), operand ); nkeynes@7: break; nkeynes@7: case 4: nkeynes@7: case 20: nkeynes@7: case 22: nkeynes@7: snprintf(buf, len, "STRB%s R%d, %s", cond, RD(ir), operand ); nkeynes@7: break; nkeynes@7: case 5: nkeynes@7: case 21: nkeynes@7: case 23: nkeynes@7: snprintf(buf, len, "LDRB%s R%d, %s", cond, RD(ir), operand ); nkeynes@7: break; nkeynes@7: case 6: nkeynes@7: snprintf(buf, len, "STRBT%s R%d, %s", cond, RD(ir), operand ); nkeynes@7: break; nkeynes@7: case 7: nkeynes@7: snprintf(buf, len, "LDRBT%s R%d, %s", cond, RD(ir), operand ); nkeynes@7: break; nkeynes@7: } nkeynes@4: break; nkeynes@13: case 2: nkeynes@13: if( (ir & 0x02000000) == 0x02000000 ) { nkeynes@13: int32_t offset = SIGNEXT24(ir&0x00FFFFFF) << 2; nkeynes@13: if( (ir & 0x01000000) == 0x01000000 ) { nkeynes@51: snprintf( buf, len, "BL%s $%08Xh", cond, pc + offset + 8 ); nkeynes@13: } else { nkeynes@51: snprintf( buf, len, "B%s $%08Xh", cond, pc + offset + 8 ); nkeynes@13: } nkeynes@13: } else { nkeynes@13: /* Load/store multiple */ nkeynes@7: j = snprintf( buf, len, LFLAG(ir) ? "LDM%s%s R%d%c,":"STM%s%s R%d%c,", nkeynes@13: ldmModes[(ir>>23)&0x03], cond, RN(ir), WFLAG(ir)?'!':' ' ); nkeynes@7: buf += j; nkeynes@7: len -= j; nkeynes@7: for( i = 0; i<16 && len > 2; i++ ) { nkeynes@51: if( ir & (1< 0 ) { nkeynes@7: buf[0] = '^'; nkeynes@7: buf[1] = '\0'; nkeynes@7: } nkeynes@13: } nkeynes@13: break; nkeynes@4: case 3: /* Copro */ nkeynes@51: if( (ir & 0x0F000000) == 0x0F000000 ) { nkeynes@60: snprintf( buf, len, "SWI%s #%08Xh", cond, SIGNEXT24(ir) ); nkeynes@51: } else { nkeynes@51: UNIMP(ir); nkeynes@51: } nkeynes@13: break; nkeynes@4: } nkeynes@4: nkeynes@4: nkeynes@4: nkeynes@4: return pc+4; nkeynes@4: } nkeynes@11: nkeynes@11: nkeynes@11: uint32_t armt_disasm_instruction( uint32_t pc, char *buf, int len, char *opcode ) nkeynes@11: { nkeynes@11: uint32_t ir = arm_read_word(pc); nkeynes@11: sprintf( opcode, "%02X %02X", ir&0xFF, (ir>>8) ); nkeynes@11: UNIMP(ir); nkeynes@11: return pc+2; nkeynes@11: }