nkeynes@4 | 1 | /*
|
nkeynes@4 | 2 | * armdasm.c 21 Aug 2004 - ARM7tdmi (ARMv4) disassembler
|
nkeynes@4 | 3 | *
|
nkeynes@4 | 4 | * Copyright (c) 2004 Nathan Keynes. Distribution and modification permitted
|
nkeynes@4 | 5 | * under the terms of the GNU General Public License version 2 or later.
|
nkeynes@4 | 6 | */
|
nkeynes@4 | 7 |
|
nkeynes@7 | 8 | #include "aica/armcore.h"
|
nkeynes@11 | 9 | #include "aica/armdasm.h"
|
nkeynes@7 | 10 | #include <stdlib.h>
|
nkeynes@4 | 11 |
|
nkeynes@4 | 12 | #define COND(ir) (ir>>28)
|
nkeynes@4 | 13 | #define OPCODE(ir) ((ir>>20)&0x1F)
|
nkeynes@4 | 14 | #define GRP(ir) ((ir>>26)&0x03)
|
nkeynes@4 | 15 | #define IFLAG(ir) (ir&0x02000000)
|
nkeynes@4 | 16 | #define SFLAG(ir) (ir&0x00100000)
|
nkeynes@4 | 17 | #define PFLAG(ir) (ir&0x01000000)
|
nkeynes@4 | 18 | #define UFLAG(ir) (ir&0x00800000)
|
nkeynes@4 | 19 | #define BFLAG(ir) (ir&0x00400000)
|
nkeynes@7 | 20 | #define WFLAG(ir) (ir&0x00200000)
|
nkeynes@4 | 21 | #define LFLAG(ir) SFLAG(ir)
|
nkeynes@4 | 22 | #define RN(ir) ((ir>>16)&0x0F)
|
nkeynes@4 | 23 | #define RD(ir) ((ir>>12)&0x0F)
|
nkeynes@4 | 24 | #define RS(ir) ((ir>>8)&0x0F)
|
nkeynes@4 | 25 | #define RM(ir) (ir&0x0F)
|
nkeynes@4 | 26 |
|
nkeynes@4 | 27 | #define IMM8(ir) (ir&0xFF)
|
nkeynes@4 | 28 | #define IMM12(ir) (ir&0xFFF)
|
nkeynes@7 | 29 | #define SHIFTIMM(ir) ((ir>>7)&0x1F)
|
nkeynes@7 | 30 | #define IMMROT(ir) ((ir>>7)&0x1E)
|
nkeynes@4 | 31 | #define SHIFT(ir) ((ir>>4)&0x07)
|
nkeynes@4 | 32 | #define DISP24(ir) ((ir&0x00FFFFFF))
|
nkeynes@4 | 33 | #define FSXC(ir) msrFieldMask[RN(ir)]
|
nkeynes@4 | 34 | #define ROTIMM12(ir) ROTATE_RIGHT_LONG(IMM8(ir),IMMROT(ir))
|
nkeynes@4 | 35 |
|
nkeynes@11 | 36 |
|
nkeynes@11 | 37 | const struct reg_desc_struct arm_reg_map[] =
|
nkeynes@11 | 38 | { {"R0", REG_INT, &armr.r[0]}, {"R1", REG_INT, &armr.r[1]},
|
nkeynes@11 | 39 | {"R2", REG_INT, &armr.r[2]}, {"R3", REG_INT, &armr.r[3]},
|
nkeynes@11 | 40 | {"R4", REG_INT, &armr.r[4]}, {"R5", REG_INT, &armr.r[5]},
|
nkeynes@11 | 41 | {"R6", REG_INT, &armr.r[6]}, {"R7", REG_INT, &armr.r[7]},
|
nkeynes@11 | 42 | {"R8", REG_INT, &armr.r[8]}, {"R9", REG_INT, &armr.r[9]},
|
nkeynes@11 | 43 | {"R10",REG_INT, &armr.r[10]}, {"R11",REG_INT, &armr.r[11]},
|
nkeynes@11 | 44 | {"R12",REG_INT, &armr.r[12]}, {"R13",REG_INT, &armr.r[13]},
|
nkeynes@11 | 45 | {"R14",REG_INT, &armr.r[14]}, {"R15",REG_INT, &armr.r[15]},
|
nkeynes@11 | 46 | {"CPSR", REG_INT, &armr.cpsr}, {"SPSR", REG_INT, &armr.spsr},
|
nkeynes@11 | 47 | {NULL, 0, NULL} };
|
nkeynes@11 | 48 |
|
nkeynes@11 | 49 |
|
nkeynes@11 | 50 | const struct cpu_desc_struct arm_cpu_desc = { "ARM7", arm_disasm_instruction, 4,
|
nkeynes@11 | 51 | (char *)&armr, sizeof(armr), arm_reg_map,
|
nkeynes@11 | 52 | &armr.r[15], &armr.icount };
|
nkeynes@11 | 53 | const struct cpu_desc_struct armt_cpu_desc = { "ARM7T", armt_disasm_instruction, 2,
|
nkeynes@11 | 54 | (char*)&armr, sizeof(armr), arm_reg_map,
|
nkeynes@11 | 55 | &armr.r[15], &armr.icount };
|
nkeynes@11 | 56 |
|
nkeynes@11 | 57 |
|
nkeynes@11 | 58 |
|
nkeynes@11 | 59 |
|
nkeynes@4 | 60 | char *conditionNames[] = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC",
|
nkeynes@4 | 61 | "HI", "LS", "GE", "LT", "GT", "LE", " " /*AL*/, "NV" };
|
nkeynes@4 | 62 |
|
nkeynes@4 | 63 | /* fsxc */
|
nkeynes@4 | 64 | char *msrFieldMask[] = { "", "c", "x", "xc", "s", "sc", "sx", "sxc",
|
nkeynes@4 | 65 | "f", "fc", "fx", "fxc", "fs", "fsc", "fsx", "fsxc" };
|
nkeynes@7 | 66 | char *ldmModes[] = { "DA", "IA", "DB", "IB" };
|
nkeynes@4 | 67 |
|
nkeynes@4 | 68 | #define UNIMP(ir) snprintf( buf, len, "??? " )
|
nkeynes@4 | 69 |
|
nkeynes@7 | 70 | int arm_disasm_shift_operand( uint32_t ir, char *buf, int len )
|
nkeynes@4 | 71 | {
|
nkeynes@7 | 72 | uint32_t operand, tmp;
|
nkeynes@7 | 73 | if( IFLAG(ir) == 0 ) {
|
nkeynes@7 | 74 | switch(SHIFT(ir)) {
|
nkeynes@7 | 75 | case 0: /* (Rm << imm) */
|
nkeynes@7 | 76 | return snprintf(buf, len, "R%d << %d", RM(ir), SHIFTIMM(ir) );
|
nkeynes@7 | 77 | case 1: /* (Rm << Rs) */
|
nkeynes@7 | 78 | return snprintf(buf, len, "R%d << R%d", RM(ir), RS(ir) );
|
nkeynes@7 | 79 | case 2: /* (Rm >> imm) */
|
nkeynes@7 | 80 | return snprintf(buf, len, "R%d >> %d", RM(ir), SHIFTIMM(ir) );
|
nkeynes@7 | 81 | case 3: /* (Rm >> Rs) */
|
nkeynes@7 | 82 | return snprintf(buf, len, "R%d >> R%d", RM(ir), RS(ir) );
|
nkeynes@7 | 83 | case 4: /* (Rm >>> imm) */
|
nkeynes@7 | 84 | return snprintf(buf, len, "R%d >>> %d", RM(ir), SHIFTIMM(ir) );
|
nkeynes@7 | 85 | case 5: /* (Rm >>> Rs) */
|
nkeynes@7 | 86 | return snprintf(buf, len, "R%d >>> R%d", RM(ir), RS(ir) );
|
nkeynes@7 | 87 | case 6:
|
nkeynes@7 | 88 | tmp = SHIFTIMM(ir);
|
nkeynes@7 | 89 | if( tmp == 0 ) /* RRX aka rotate with carry */
|
nkeynes@7 | 90 | return snprintf(buf, len, "R%d roc 1", RM(ir) );
|
nkeynes@7 | 91 | else
|
nkeynes@7 | 92 | return snprintf(buf, len, "R%d rot %d", RM(ir), SHIFTIMM(ir) );
|
nkeynes@7 | 93 | case 7:
|
nkeynes@7 | 94 | return snprintf(buf, len, "R%d rot R%d", RM(ir), RS(ir) );
|
nkeynes@7 | 95 | }
|
nkeynes@7 | 96 | } else {
|
nkeynes@7 | 97 | operand = IMM8(ir);
|
nkeynes@7 | 98 | tmp = IMMROT(ir);
|
nkeynes@7 | 99 | operand = ROTATE_RIGHT_LONG(operand, tmp);
|
nkeynes@7 | 100 | return snprintf(buf, len, "%08X", operand );
|
nkeynes@7 | 101 | }
|
nkeynes@7 | 102 | }
|
nkeynes@7 | 103 |
|
nkeynes@7 | 104 | static int arm_disasm_address_index( uint32_t ir, char *buf, int len )
|
nkeynes@7 | 105 | {
|
nkeynes@7 | 106 | uint32_t tmp;
|
nkeynes@7 | 107 |
|
nkeynes@7 | 108 | switch(SHIFT(ir)) {
|
nkeynes@7 | 109 | case 0: /* (Rm << imm) */
|
nkeynes@7 | 110 | return snprintf( buf, len, "R%d << %d", RM(ir), SHIFTIMM(ir) );
|
nkeynes@7 | 111 | case 2: /* (Rm >> imm) */
|
nkeynes@7 | 112 | return snprintf( buf, len, "R%d >> %d", RM(ir), SHIFTIMM(ir) );
|
nkeynes@7 | 113 | case 4: /* (Rm >>> imm) */
|
nkeynes@7 | 114 | return snprintf( buf, len, "R%d >>> %d", RM(ir), SHIFTIMM(ir) );
|
nkeynes@7 | 115 | case 6:
|
nkeynes@7 | 116 | tmp = SHIFTIMM(ir);
|
nkeynes@7 | 117 | if( tmp == 0 ) /* RRX aka rotate with carry */
|
nkeynes@7 | 118 | return snprintf( buf, len, "R%d roc 1", RM(ir) );
|
nkeynes@7 | 119 | else
|
nkeynes@7 | 120 | return snprintf( buf, len, "R%d rot %d", RM(ir), tmp );
|
nkeynes@7 | 121 | default:
|
nkeynes@7 | 122 | return UNIMP(ir);
|
nkeynes@7 | 123 | }
|
nkeynes@7 | 124 | }
|
nkeynes@7 | 125 |
|
nkeynes@7 | 126 | static int arm_disasm_address_operand( uint32_t ir, char *buf, int len )
|
nkeynes@7 | 127 | {
|
nkeynes@7 | 128 | char shift[32];
|
nkeynes@7 | 129 |
|
nkeynes@7 | 130 | char sign = UFLAG(ir) ? '-' : '+';
|
nkeynes@7 | 131 | /* I P U . W */
|
nkeynes@7 | 132 | switch( (ir>>21)&0x19 ) {
|
nkeynes@7 | 133 | case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
|
nkeynes@7 | 134 | case 1:
|
nkeynes@7 | 135 | return snprintf( buf, len, "[R%d], R%d %c= %04X", RN(ir), RN(ir), sign, IMM12(ir) );
|
nkeynes@7 | 136 | case 8: /* Rn - imm offset [5.2.2 A5-20] */
|
nkeynes@7 | 137 | return snprintf( buf, len, "[R%d %c %04X]", RN(ir), sign, IMM12(ir) );
|
nkeynes@7 | 138 | case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
|
nkeynes@7 | 139 | return snprintf( buf, len, "[R%d %c= %04X]", RN(ir), sign, IMM12(ir) );
|
nkeynes@7 | 140 | case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
|
nkeynes@7 | 141 | case 17:
|
nkeynes@7 | 142 | arm_disasm_address_index( ir, shift, sizeof(shift) );
|
nkeynes@7 | 143 | return snprintf( buf, len, "[R%d], R%d %c= %s", RN(ir), RN(ir), sign, shift );
|
nkeynes@7 | 144 | case 24: /* Rn - Rm [5.2.4 A5-23] */
|
nkeynes@7 | 145 | arm_disasm_address_index( ir, shift, sizeof(shift) );
|
nkeynes@7 | 146 | return snprintf( buf, len, "[R%d %c %s]", RN(ir), sign, shift );
|
nkeynes@7 | 147 | case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
|
nkeynes@7 | 148 | arm_disasm_address_index( ir, shift, sizeof(shift) );
|
nkeynes@7 | 149 | return snprintf( buf, len, "[R%d %c= %s]", RN(ir), sign, shift );
|
nkeynes@7 | 150 | default:
|
nkeynes@7 | 151 | return UNIMP(ir); /* Unreachable */
|
nkeynes@7 | 152 | }
|
nkeynes@7 | 153 | }
|
nkeynes@7 | 154 |
|
nkeynes@11 | 155 | uint32_t arm_disasm_instruction( uint32_t pc, char *buf, int len, char *opcode )
|
nkeynes@7 | 156 | {
|
nkeynes@11 | 157 | char operand[32];
|
nkeynes@11 | 158 | uint32_t ir = arm_read_long(pc);
|
nkeynes@11 | 159 | int i,j;
|
nkeynes@7 | 160 |
|
nkeynes@11 | 161 | sprintf( opcode, "%02X %02X %02X %02X", ir&0xFF, (ir>>8) & 0xFF,
|
nkeynes@11 | 162 | (ir>>16)&0xFF, (ir>>24) );
|
nkeynes@11 | 163 |
|
nkeynes@4 | 164 | if( COND(ir) == 0x0F ) {
|
nkeynes@4 | 165 | UNIMP(ir);
|
nkeynes@4 | 166 | return pc+4;
|
nkeynes@4 | 167 | }
|
nkeynes@4 | 168 | char *cond = conditionNames[COND(ir)];
|
nkeynes@4 | 169 |
|
nkeynes@4 | 170 | switch( GRP(ir) ) {
|
nkeynes@4 | 171 | case 0:
|
nkeynes@4 | 172 | if( (ir & 0x0D900000) == 0x01000000 ) {
|
nkeynes@4 | 173 | /* Instructions that aren't actual data processing */
|
nkeynes@4 | 174 | switch( ir & 0x0FF000F0 ) {
|
nkeynes@4 | 175 | case 0x01200010: /* BXcc */
|
nkeynes@4 | 176 | snprintf(buf, len, "BX%s R%d", cond, RM(ir));
|
nkeynes@4 | 177 | break;
|
nkeynes@4 | 178 | case 0x01000000: /* MRS Rd, CPSR */
|
nkeynes@4 | 179 | snprintf(buf, len, "MRS%s R%d, CPSR", cond, RD(ir));
|
nkeynes@4 | 180 | break;
|
nkeynes@4 | 181 | case 0x01400000: /* MRS Rd, SPSR */
|
nkeynes@4 | 182 | snprintf(buf, len, "MRS%s R%d, SPSR", cond, RD(ir));
|
nkeynes@4 | 183 | break;
|
nkeynes@4 | 184 | case 0x01200000: /* MSR CPSR, Rm */
|
nkeynes@4 | 185 | snprintf(buf, len, "MSR%s CPSR_%s, R%d", cond, FSXC(ir), RM(ir));
|
nkeynes@4 | 186 | break;
|
nkeynes@4 | 187 | case 0x01600000: /* MSR SPSR, Rm */
|
nkeynes@4 | 188 | snprintf(buf, len, "MSR%s SPSR_%s, R%d", cond, FSXC(ir), RM(ir));
|
nkeynes@4 | 189 | break;
|
nkeynes@4 | 190 | case 0x03200000: /* MSR CPSR, imm */
|
nkeynes@4 | 191 | snprintf(buf, len, "MSR%s CPSR_%s, #%08X", cond, FSXC(ir), ROTIMM12(ir));
|
nkeynes@4 | 192 | break;
|
nkeynes@4 | 193 | case 0x03600000: /* MSR SPSR, imm */
|
nkeynes@4 | 194 | snprintf(buf, len, "MSR%s SPSR_%s, #%08X", cond, FSXC(ir), ROTIMM12(ir));
|
nkeynes@4 | 195 | break;
|
nkeynes@4 | 196 | default:
|
nkeynes@4 | 197 | UNIMP();
|
nkeynes@4 | 198 | }
|
nkeynes@4 | 199 | } else if( (ir & 0x0E000090) == 0x00000090 ) {
|
nkeynes@4 | 200 | /* Neither are these */
|
nkeynes@4 | 201 | switch( (ir>>5)&0x03 ) {
|
nkeynes@4 | 202 | case 0:
|
nkeynes@4 | 203 | /* Arithmetic extension area */
|
nkeynes@4 | 204 | switch(OPCODE(ir)) {
|
nkeynes@4 | 205 | case 0: /* MUL */
|
nkeynes@4 | 206 | snprintf(buf,len, "MUL%s R%d, R%d, R%d", cond, RN(ir), RM(ir), RS(ir) );
|
nkeynes@4 | 207 | break;
|
nkeynes@4 | 208 | case 1: /* MULS */
|
nkeynes@4 | 209 | break;
|
nkeynes@4 | 210 | case 2: /* MLA */
|
nkeynes@4 | 211 | snprintf(buf,len, "MLA%s R%d, R%d, R%d, R%d", cond, RN(ir), RM(ir), RS(ir), RD(ir) );
|
nkeynes@4 | 212 | break;
|
nkeynes@4 | 213 | case 3: /* MLAS */
|
nkeynes@4 | 214 | break;
|
nkeynes@4 | 215 | case 8: /* UMULL */
|
nkeynes@4 | 216 | snprintf(buf,len, "UMULL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
|
nkeynes@4 | 217 | break;
|
nkeynes@4 | 218 | case 9: /* UMULLS */
|
nkeynes@4 | 219 | break;
|
nkeynes@4 | 220 | case 10: /* UMLAL */
|
nkeynes@4 | 221 | snprintf(buf,len, "UMLAL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
|
nkeynes@4 | 222 | break;
|
nkeynes@4 | 223 | case 11: /* UMLALS */
|
nkeynes@4 | 224 | break;
|
nkeynes@4 | 225 | case 12: /* SMULL */
|
nkeynes@4 | 226 | snprintf(buf,len, "SMULL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
|
nkeynes@4 | 227 | break;
|
nkeynes@4 | 228 | case 13: /* SMULLS */
|
nkeynes@4 | 229 | break;
|
nkeynes@4 | 230 | case 14: /* SMLAL */
|
nkeynes@4 | 231 | snprintf(buf,len, "SMLAL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
|
nkeynes@4 | 232 | break;
|
nkeynes@4 | 233 | case 15: /* SMLALS */
|
nkeynes@4 | 234 |
|
nkeynes@4 | 235 | break;
|
nkeynes@4 | 236 | case 16: /* SWP */
|
nkeynes@4 | 237 | snprintf(buf,len, "SWP%s R%d, R%d, [R%d]", cond, RD(ir), RN(ir), RM(ir) );
|
nkeynes@4 | 238 | break;
|
nkeynes@4 | 239 | case 20: /* SWPB */
|
nkeynes@4 | 240 | snprintf(buf,len, "SWPB%s R%d, R%d, [R%d]", cond, RD(ir), RN(ir), RM(ir) );
|
nkeynes@4 | 241 | break;
|
nkeynes@4 | 242 | default:
|
nkeynes@4 | 243 | UNIMP(ir);
|
nkeynes@4 | 244 | }
|
nkeynes@4 | 245 | break;
|
nkeynes@4 | 246 | case 1:
|
nkeynes@4 | 247 | if( LFLAG(ir) ) {
|
nkeynes@4 | 248 | /* LDRH */
|
nkeynes@4 | 249 | } else {
|
nkeynes@4 | 250 | /* STRH */
|
nkeynes@4 | 251 | }
|
nkeynes@4 | 252 | break;
|
nkeynes@4 | 253 | case 2:
|
nkeynes@4 | 254 | if( LFLAG(ir) ) {
|
nkeynes@4 | 255 | /* LDRSB */
|
nkeynes@4 | 256 | } else {
|
nkeynes@4 | 257 | UNIMP(ir);
|
nkeynes@4 | 258 | }
|
nkeynes@4 | 259 | break;
|
nkeynes@4 | 260 | case 3:
|
nkeynes@4 | 261 | if( LFLAG(ir) ) {
|
nkeynes@4 | 262 | /* LDRSH */
|
nkeynes@4 | 263 | } else {
|
nkeynes@4 | 264 | UNIMP(ir);
|
nkeynes@4 | 265 | }
|
nkeynes@4 | 266 | break;
|
nkeynes@4 | 267 | }
|
nkeynes@4 | 268 | } else {
|
nkeynes@4 | 269 | /* Data processing */
|
nkeynes@4 | 270 |
|
nkeynes@4 | 271 | switch(OPCODE(ir)) {
|
nkeynes@4 | 272 | case 0: /* AND Rd, Rn, operand */
|
nkeynes@7 | 273 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 274 | snprintf(buf, len, "AND%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 275 | break;
|
nkeynes@4 | 276 | case 1: /* ANDS Rd, Rn, operand */
|
nkeynes@7 | 277 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 278 | snprintf(buf, len, "ANDS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 279 | break;
|
nkeynes@4 | 280 | case 2: /* EOR Rd, Rn, operand */
|
nkeynes@7 | 281 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 282 | snprintf(buf, len, "EOR%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 283 | break;
|
nkeynes@4 | 284 | case 3: /* EORS Rd, Rn, operand */
|
nkeynes@7 | 285 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 286 | snprintf(buf, len, "EORS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 287 | break;
|
nkeynes@4 | 288 | case 4: /* SUB Rd, Rn, operand */
|
nkeynes@7 | 289 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 290 | snprintf(buf, len, "SUB%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 291 | break;
|
nkeynes@4 | 292 | case 5: /* SUBS Rd, Rn, operand */
|
nkeynes@7 | 293 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 294 | snprintf(buf, len, "SUBS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 295 | break;
|
nkeynes@7 | 296 | case 6: /* RSB Rd, Rn, operand */
|
nkeynes@7 | 297 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 298 | snprintf(buf, len, "RSB%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 299 | break;
|
nkeynes@7 | 300 | case 7: /* RSBS Rd, Rn, operand */
|
nkeynes@7 | 301 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 302 | snprintf(buf, len, "RSBS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 303 | break;
|
nkeynes@4 | 304 | case 8: /* ADD Rd, Rn, operand */
|
nkeynes@7 | 305 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 306 | snprintf(buf, len, "ADD%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 307 | break;
|
nkeynes@4 | 308 | case 9: /* ADDS Rd, Rn, operand */
|
nkeynes@7 | 309 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 310 | snprintf(buf, len, "ADDS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 311 | break;
|
nkeynes@7 | 312 | case 10: /* ADC Rd, Rn, operand */
|
nkeynes@7 | 313 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 314 | snprintf(buf, len, "ADC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 315 | break;
|
nkeynes@7 | 316 | case 11: /* ADCS Rd, Rn, operand */
|
nkeynes@7 | 317 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 318 | snprintf(buf, len, "ADCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 319 | break;
|
nkeynes@7 | 320 | case 12: /* SBC Rd, Rn, operand */
|
nkeynes@7 | 321 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 322 | snprintf(buf, len, "SBC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@7 | 323 | break;
|
nkeynes@7 | 324 | case 13: /* SBCS Rd, Rn, operand */
|
nkeynes@7 | 325 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 326 | snprintf(buf, len, "SBCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@7 | 327 | break;
|
nkeynes@7 | 328 | case 14: /* RSC Rd, Rn, operand */
|
nkeynes@7 | 329 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 330 | snprintf(buf, len, "RSC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@7 | 331 | break;
|
nkeynes@7 | 332 | case 15: /* RSCS Rd, Rn, operand */
|
nkeynes@7 | 333 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 334 | snprintf(buf, len, "RSCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@7 | 335 | break;
|
nkeynes@7 | 336 | case 16: /* TST Rd, Rn, operand */
|
nkeynes@7 | 337 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 338 | snprintf(buf, len, "TST%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@7 | 339 | break;
|
nkeynes@7 | 340 | case 18: /* TEQ Rd, Rn, operand */
|
nkeynes@7 | 341 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 342 | snprintf(buf, len, "TEQ%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@7 | 343 | break;
|
nkeynes@7 | 344 | case 20: /* CMP Rd, Rn, operand */
|
nkeynes@7 | 345 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 346 | snprintf(buf, len, "CMP%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@7 | 347 | break;
|
nkeynes@7 | 348 | case 22: /* CMN Rd, Rn, operand */
|
nkeynes@7 | 349 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 350 | snprintf(buf, len, "CMN%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 351 | break;
|
nkeynes@4 | 352 | case 24: /* ORR Rd, Rn, operand */
|
nkeynes@7 | 353 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 354 | snprintf(buf, len, "ORR%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 355 | break;
|
nkeynes@4 | 356 | case 25: /* ORRS Rd, Rn, operand */
|
nkeynes@7 | 357 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 358 | snprintf(buf, len, "ORRS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 359 | break;
|
nkeynes@7 | 360 | case 26: /* MOV Rd, Rn, operand */
|
nkeynes@7 | 361 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 362 | snprintf(buf, len, "MOV%s R%d, %s", cond, RD(ir), operand);
|
nkeynes@4 | 363 | break;
|
nkeynes@7 | 364 | case 27: /* MOVS Rd, Rn, operand */
|
nkeynes@7 | 365 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 366 | snprintf(buf, len, "MOVS%s R%d, %s", cond, RD(ir), operand);
|
nkeynes@4 | 367 | break;
|
nkeynes@4 | 368 | case 28: /* BIC Rd, Rn, operand */
|
nkeynes@7 | 369 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 370 | snprintf(buf, len, "BIC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 371 | break;
|
nkeynes@4 | 372 | case 29: /* BICS Rd, Rn, operand */
|
nkeynes@7 | 373 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 374 | snprintf(buf, len, "BICS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
|
nkeynes@4 | 375 | break;
|
nkeynes@7 | 376 | case 30: /* MVN Rd, Rn, operand */
|
nkeynes@7 | 377 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 378 | snprintf(buf, len, "MVN%s R%d, %s", cond, RD(ir), operand);
|
nkeynes@4 | 379 | break;
|
nkeynes@7 | 380 | case 31: /* MVNS Rd, Rn, operand */
|
nkeynes@7 | 381 | arm_disasm_shift_operand(ir, operand, sizeof(operand));
|
nkeynes@7 | 382 | snprintf(buf, len, "MVNS%s R%d, %s", cond, RD(ir), operand);
|
nkeynes@4 | 383 | break;
|
nkeynes@4 | 384 | default:
|
nkeynes@4 | 385 | UNIMP(ir);
|
nkeynes@4 | 386 | }
|
nkeynes@4 | 387 | }
|
nkeynes@4 | 388 | break;
|
nkeynes@4 | 389 | case 1: /* Load/store */
|
nkeynes@7 | 390 | arm_disasm_address_operand( ir, operand, sizeof(operand) );
|
nkeynes@7 | 391 | switch( (ir>>20)&0x17 ) {
|
nkeynes@7 | 392 | case 0:
|
nkeynes@7 | 393 | case 16:
|
nkeynes@7 | 394 | case 18:
|
nkeynes@7 | 395 | snprintf(buf, len, "STR%s R%d, %s", cond, RD(ir), operand );
|
nkeynes@7 | 396 | break;
|
nkeynes@7 | 397 | case 1:
|
nkeynes@7 | 398 | case 17:
|
nkeynes@7 | 399 | case 19:
|
nkeynes@7 | 400 | snprintf(buf, len, "LDR%s R%d, %s", cond, RD(ir), operand );
|
nkeynes@7 | 401 | break;
|
nkeynes@7 | 402 | case 2:
|
nkeynes@7 | 403 | snprintf(buf, len, "STRT%s R%d, %s", cond, RD(ir), operand );
|
nkeynes@7 | 404 | break;
|
nkeynes@7 | 405 | case 3:
|
nkeynes@7 | 406 | snprintf(buf, len, "LDRT%s R%d, %s", cond, RD(ir), operand );
|
nkeynes@7 | 407 | break;
|
nkeynes@7 | 408 | case 4:
|
nkeynes@7 | 409 | case 20:
|
nkeynes@7 | 410 | case 22:
|
nkeynes@7 | 411 | snprintf(buf, len, "STRB%s R%d, %s", cond, RD(ir), operand );
|
nkeynes@7 | 412 | break;
|
nkeynes@7 | 413 | case 5:
|
nkeynes@7 | 414 | case 21:
|
nkeynes@7 | 415 | case 23:
|
nkeynes@7 | 416 | snprintf(buf, len, "LDRB%s R%d, %s", cond, RD(ir), operand );
|
nkeynes@7 | 417 | break;
|
nkeynes@7 | 418 | case 6:
|
nkeynes@7 | 419 | snprintf(buf, len, "STRBT%s R%d, %s", cond, RD(ir), operand );
|
nkeynes@7 | 420 | break;
|
nkeynes@7 | 421 | case 7:
|
nkeynes@7 | 422 | snprintf(buf, len, "LDRBT%s R%d, %s", cond, RD(ir), operand );
|
nkeynes@7 | 423 | break;
|
nkeynes@7 | 424 | }
|
nkeynes@4 | 425 | break;
|
nkeynes@4 | 426 | case 2: /* Load/store multiple, branch*/
|
nkeynes@7 | 427 | j = snprintf( buf, len, LFLAG(ir) ? "LDM%s%s R%d%c,":"STM%s%s R%d%c,",
|
nkeynes@7 | 428 | ldmModes[(ir>>23)&0x03], cond, RN(ir), WFLAG(ir)?'!':' ' );
|
nkeynes@7 | 429 | buf += j;
|
nkeynes@7 | 430 | len -= j;
|
nkeynes@7 | 431 | for( i = 0; i<16 && len > 2; i++ ) {
|
nkeynes@7 | 432 | if( (ir >> i)&1 ) {
|
nkeynes@7 | 433 | j = snprintf( buf, len, "R%d", i );
|
nkeynes@7 | 434 | buf+=j;
|
nkeynes@7 | 435 | len-=j;
|
nkeynes@7 | 436 | }
|
nkeynes@7 | 437 | }
|
nkeynes@7 | 438 | if( SFLAG(ir) && len > 0 ) {
|
nkeynes@7 | 439 | buf[0] = '^';
|
nkeynes@7 | 440 | buf[1] = '\0';
|
nkeynes@7 | 441 | }
|
nkeynes@4 | 442 | break;
|
nkeynes@4 | 443 | case 3: /* Copro */
|
nkeynes@7 | 444 | UNIMP(ir);
|
nkeynes@4 | 445 | break;
|
nkeynes@4 | 446 | }
|
nkeynes@4 | 447 |
|
nkeynes@4 | 448 |
|
nkeynes@4 | 449 |
|
nkeynes@4 | 450 | return pc+4;
|
nkeynes@4 | 451 | }
|
nkeynes@11 | 452 |
|
nkeynes@11 | 453 |
|
nkeynes@11 | 454 | uint32_t armt_disasm_instruction( uint32_t pc, char *buf, int len, char *opcode )
|
nkeynes@11 | 455 | {
|
nkeynes@11 | 456 | uint32_t ir = arm_read_word(pc);
|
nkeynes@11 | 457 | sprintf( opcode, "%02X %02X", ir&0xFF, (ir>>8) );
|
nkeynes@11 | 458 | UNIMP(ir);
|
nkeynes@11 | 459 | return pc+2;
|
nkeynes@11 | 460 | }
|