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