2 * armdasm.c 21 Aug 2004 - ARM7tdmi (ARMv4) disassembler
4 * Copyright (c) 2004 Nathan Keynes. Distribution and modification permitted
5 * under the terms of the GNU General Public License version 2 or later.
8 #include "aica/armcore.h"
9 #include "aica/armdasm.h"
12 #define COND(ir) (ir>>28)
13 #define OPCODE(ir) ((ir>>20)&0x1F)
14 #define GRP(ir) ((ir>>26)&0x03)
15 #define IFLAG(ir) (ir&0x02000000)
16 #define SFLAG(ir) (ir&0x00100000)
17 #define PFLAG(ir) (ir&0x01000000)
18 #define UFLAG(ir) (ir&0x00800000)
19 #define BFLAG(ir) (ir&0x00400000)
20 #define WFLAG(ir) (ir&0x00200000)
21 #define LFLAG(ir) SFLAG(ir)
22 #define RN(ir) ((ir>>16)&0x0F)
23 #define RD(ir) ((ir>>12)&0x0F)
24 #define RS(ir) ((ir>>8)&0x0F)
25 #define RM(ir) (ir&0x0F)
27 #define IMM8(ir) (ir&0xFF)
28 #define IMM12(ir) (ir&0xFFF)
29 #define SHIFTIMM(ir) ((ir>>7)&0x1F)
30 #define IMMROT(ir) ((ir>>7)&0x1E)
31 #define SHIFT(ir) ((ir>>4)&0x07)
32 #define DISP24(ir) ((ir&0x00FFFFFF))
33 #define FSXC(ir) msrFieldMask[RN(ir)]
34 #define ROTIMM12(ir) ROTATE_RIGHT_LONG(IMM8(ir),IMMROT(ir))
35 #define SIGNEXT24(n) ((n&0x00800000) ? (n|0xFF000000) : (n&0x00FFFFFF))
39 const struct reg_desc_struct arm_reg_map[] =
40 { {"R0", REG_INT, &armr.r[0]}, {"R1", REG_INT, &armr.r[1]},
41 {"R2", REG_INT, &armr.r[2]}, {"R3", REG_INT, &armr.r[3]},
42 {"R4", REG_INT, &armr.r[4]}, {"R5", REG_INT, &armr.r[5]},
43 {"R6", REG_INT, &armr.r[6]}, {"R7", REG_INT, &armr.r[7]},
44 {"R8", REG_INT, &armr.r[8]}, {"R9", REG_INT, &armr.r[9]},
45 {"R10",REG_INT, &armr.r[10]}, {"R11",REG_INT, &armr.r[11]},
46 {"R12",REG_INT, &armr.r[12]}, {"R13",REG_INT, &armr.r[13]},
47 {"R14",REG_INT, &armr.r[14]}, {"R15",REG_INT, &armr.r[15]},
48 {"CPSR", REG_INT, &armr.cpsr}, {"SPSR", REG_INT, &armr.spsr},
52 const struct cpu_desc_struct arm_cpu_desc =
53 { "ARM7", arm_disasm_instruction, 4,
54 (char *)&armr, sizeof(armr), arm_reg_map,
55 &armr.r[15], &armr.icount,
57 const struct cpu_desc_struct armt_cpu_desc =
58 { "ARM7T", armt_disasm_instruction, 2,
59 (char*)&armr, sizeof(armr), arm_reg_map,
60 &armr.r[15], &armr.icount,
66 char *conditionNames[] = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC",
67 "HI", "LS", "GE", "LT", "GT", "LE", " " /*AL*/, "NV" };
70 char *msrFieldMask[] = { "", "c", "x", "xc", "s", "sc", "sx", "sxc",
71 "f", "fc", "fx", "fxc", "fs", "fsc", "fsx", "fsxc" };
72 char *ldmModes[] = { "DA", "IA", "DB", "IB" };
74 #define UNIMP(ir) snprintf( buf, len, "??? " )
76 int arm_disasm_shift_operand( uint32_t ir, char *buf, int len )
78 uint32_t operand, tmp;
79 if( IFLAG(ir) == 0 ) {
81 case 0: /* (Rm << imm) */
84 return snprintf(buf, len, "R%d << %d", RM(ir), tmp );
86 return snprintf(buf, len, "R%d", RM(ir));
88 case 1: /* (Rm << Rs) */
89 return snprintf(buf, len, "R%d << R%d", RM(ir), RS(ir) );
90 case 2: /* (Rm >> imm) */
91 return snprintf(buf, len, "R%d >> %d", RM(ir), SHIFTIMM(ir) );
92 case 3: /* (Rm >> Rs) */
93 return snprintf(buf, len, "R%d >> R%d", RM(ir), RS(ir) );
94 case 4: /* (Rm >>> imm) */
95 return snprintf(buf, len, "R%d >>> %d", RM(ir), SHIFTIMM(ir) );
96 case 5: /* (Rm >>> Rs) */
97 return snprintf(buf, len, "R%d >>> R%d", RM(ir), RS(ir) );
100 if( tmp == 0 ) /* RRX aka rotate with carry */
101 return snprintf(buf, len, "R%d roc 1", RM(ir) );
103 return snprintf(buf, len, "R%d rot %d", RM(ir), SHIFTIMM(ir) );
105 return snprintf(buf, len, "R%d rot R%d", RM(ir), RS(ir) );
110 operand = ROTATE_RIGHT_LONG(operand, tmp);
111 return snprintf(buf, len, "%08X", operand );
115 static int arm_disasm_address_index( uint32_t ir, char *buf, int len )
120 case 0: /* (Rm << imm) */
123 return snprintf( buf, len, "R%d << %d", RM(ir), tmp );
125 return snprintf( buf, len, "R%d", RM(ir) );
127 case 2: /* (Rm >> imm) */
128 return snprintf( buf, len, "R%d >> %d", RM(ir), SHIFTIMM(ir) );
129 case 4: /* (Rm >>> imm) */
130 return snprintf( buf, len, "R%d >>> %d", RM(ir), SHIFTIMM(ir) );
133 if( tmp == 0 ) /* RRX aka rotate with carry */
134 return snprintf( buf, len, "R%d roc 1", RM(ir) );
136 return snprintf( buf, len, "R%d rot %d", RM(ir), tmp );
142 static int arm_disasm_address_operand( uint32_t ir, char *buf, int len, int pc )
146 char sign = UFLAG(ir) ? '+' : '-';
148 switch( (ir>>21)&0x19 ) {
149 case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
151 return snprintf( buf, len, "[R%d], R%d %c= %04X", RN(ir), RN(ir), sign, IMM12(ir) );
152 case 8: /* Rn - imm offset [5.2.2 A5-20] */
153 if( RN(ir) == 15 ) { /* PC relative - decode here */
154 return snprintf( buf, len, "[$%08Xh]", pc + 8 +
155 (UFLAG(ir) ? IMM12(ir) : -IMM12(ir)) );
157 return snprintf( buf, len, "[R%d %c %04X]", RN(ir), sign, IMM12(ir) );
159 case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
160 return snprintf( buf, len, "[R%d %c= %04X]", RN(ir), sign, IMM12(ir) );
161 case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
163 arm_disasm_address_index( ir, shift, sizeof(shift) );
164 return snprintf( buf, len, "[R%d], R%d %c= %s", RN(ir), RN(ir), sign, shift );
165 case 24: /* Rn - Rm [5.2.4 A5-23] */
166 arm_disasm_address_index( ir, shift, sizeof(shift) );
167 return snprintf( buf, len, "[R%d %c %s]", RN(ir), sign, shift );
168 case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
169 arm_disasm_address_index( ir, shift, sizeof(shift) );
170 return snprintf( buf, len, "[R%d %c= %s]", RN(ir), sign, shift );
172 return UNIMP(ir); /* Unreachable */
176 uint32_t arm_disasm_instruction( uint32_t pc, char *buf, int len, char *opcode )
179 uint32_t ir = arm_read_long(pc);
182 sprintf( opcode, "%02X %02X %02X %02X", ir&0xFF, (ir>>8) & 0xFF,
183 (ir>>16)&0xFF, (ir>>24) );
185 if( COND(ir) == 0x0F ) {
189 char *cond = conditionNames[COND(ir)];
193 if( (ir & 0x0D900000) == 0x01000000 ) {
194 /* Instructions that aren't actual data processing */
195 switch( ir & 0x0FF000F0 ) {
196 case 0x01200010: /* BXcc */
197 snprintf(buf, len, "BX%s R%d", cond, RM(ir));
199 case 0x01000000: /* MRS Rd, CPSR */
200 snprintf(buf, len, "MRS%s R%d, CPSR", cond, RD(ir));
202 case 0x01400000: /* MRS Rd, SPSR */
203 snprintf(buf, len, "MRS%s R%d, SPSR", cond, RD(ir));
205 case 0x01200000: /* MSR CPSR, Rm */
206 snprintf(buf, len, "MSR%s CPSR_%s, R%d", cond, FSXC(ir), RM(ir));
208 case 0x01600000: /* MSR SPSR, Rm */
209 snprintf(buf, len, "MSR%s SPSR_%s, R%d", cond, FSXC(ir), RM(ir));
211 case 0x03200000: /* MSR CPSR, imm */
212 snprintf(buf, len, "MSR%s CPSR_%s, #%08X", cond, FSXC(ir), ROTIMM12(ir));
214 case 0x03600000: /* MSR SPSR, imm */
215 snprintf(buf, len, "MSR%s SPSR_%s, #%08X", cond, FSXC(ir), ROTIMM12(ir));
220 } else if( (ir & 0x0E000090) == 0x00000090 ) {
221 /* Neither are these */
222 switch( (ir>>5)&0x03 ) {
224 /* Arithmetic extension area */
227 snprintf(buf,len, "MUL%s R%d, R%d, R%d", cond, RN(ir), RM(ir), RS(ir) );
232 snprintf(buf,len, "MLA%s R%d, R%d, R%d, R%d", cond, RN(ir), RM(ir), RS(ir), RD(ir) );
237 snprintf(buf,len, "UMULL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
242 snprintf(buf,len, "UMLAL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
244 case 11: /* UMLALS */
247 snprintf(buf,len, "SMULL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
249 case 13: /* SMULLS */
252 snprintf(buf,len, "SMLAL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
254 case 15: /* SMLALS */
258 snprintf(buf,len, "SWP%s R%d, R%d, [R%d]", cond, RD(ir), RN(ir), RM(ir) );
261 snprintf(buf,len, "SWPB%s R%d, R%d, [R%d]", cond, RD(ir), RN(ir), RM(ir) );
290 /* Data processing */
293 case 0: /* AND Rd, Rn, operand */
294 arm_disasm_shift_operand(ir, operand, sizeof(operand));
295 snprintf(buf, len, "AND%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
297 case 1: /* ANDS Rd, Rn, operand */
298 arm_disasm_shift_operand(ir, operand, sizeof(operand));
299 snprintf(buf, len, "ANDS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
301 case 2: /* EOR Rd, Rn, operand */
302 arm_disasm_shift_operand(ir, operand, sizeof(operand));
303 snprintf(buf, len, "EOR%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
305 case 3: /* EORS Rd, Rn, operand */
306 arm_disasm_shift_operand(ir, operand, sizeof(operand));
307 snprintf(buf, len, "EORS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
309 case 4: /* SUB Rd, Rn, operand */
310 arm_disasm_shift_operand(ir, operand, sizeof(operand));
311 snprintf(buf, len, "SUB%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
313 case 5: /* SUBS Rd, Rn, operand */
314 arm_disasm_shift_operand(ir, operand, sizeof(operand));
315 snprintf(buf, len, "SUBS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
317 case 6: /* RSB Rd, Rn, operand */
318 arm_disasm_shift_operand(ir, operand, sizeof(operand));
319 snprintf(buf, len, "RSB%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
321 case 7: /* RSBS Rd, Rn, operand */
322 arm_disasm_shift_operand(ir, operand, sizeof(operand));
323 snprintf(buf, len, "RSBS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
325 case 8: /* ADD Rd, Rn, operand */
326 arm_disasm_shift_operand(ir, operand, sizeof(operand));
327 snprintf(buf, len, "ADD%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
329 case 9: /* ADDS Rd, Rn, operand */
330 arm_disasm_shift_operand(ir, operand, sizeof(operand));
331 snprintf(buf, len, "ADDS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
333 case 10: /* ADC Rd, Rn, operand */
334 arm_disasm_shift_operand(ir, operand, sizeof(operand));
335 snprintf(buf, len, "ADC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
337 case 11: /* ADCS Rd, Rn, operand */
338 arm_disasm_shift_operand(ir, operand, sizeof(operand));
339 snprintf(buf, len, "ADCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
341 case 12: /* SBC Rd, Rn, operand */
342 arm_disasm_shift_operand(ir, operand, sizeof(operand));
343 snprintf(buf, len, "SBC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
345 case 13: /* SBCS Rd, Rn, operand */
346 arm_disasm_shift_operand(ir, operand, sizeof(operand));
347 snprintf(buf, len, "SBCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
349 case 14: /* RSC Rd, Rn, operand */
350 arm_disasm_shift_operand(ir, operand, sizeof(operand));
351 snprintf(buf, len, "RSC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
353 case 15: /* RSCS Rd, Rn, operand */
354 arm_disasm_shift_operand(ir, operand, sizeof(operand));
355 snprintf(buf, len, "RSCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
357 case 16: /* TST Rd, Rn, operand */
358 arm_disasm_shift_operand(ir, operand, sizeof(operand));
359 snprintf(buf, len, "TST%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
361 case 18: /* TEQ Rd, Rn, operand */
362 arm_disasm_shift_operand(ir, operand, sizeof(operand));
363 snprintf(buf, len, "TEQ%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
365 case 20: /* CMP Rd, Rn, operand */
366 arm_disasm_shift_operand(ir, operand, sizeof(operand));
367 snprintf(buf, len, "CMP%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
369 case 22: /* CMN Rd, Rn, operand */
370 arm_disasm_shift_operand(ir, operand, sizeof(operand));
371 snprintf(buf, len, "CMN%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
373 case 24: /* ORR Rd, Rn, operand */
374 arm_disasm_shift_operand(ir, operand, sizeof(operand));
375 snprintf(buf, len, "ORR%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
377 case 25: /* ORRS Rd, Rn, operand */
378 arm_disasm_shift_operand(ir, operand, sizeof(operand));
379 snprintf(buf, len, "ORRS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
381 case 26: /* MOV Rd, Rn, operand */
382 arm_disasm_shift_operand(ir, operand, sizeof(operand));
383 snprintf(buf, len, "MOV%s R%d, %s", cond, RD(ir), operand);
385 case 27: /* MOVS Rd, Rn, operand */
386 arm_disasm_shift_operand(ir, operand, sizeof(operand));
387 snprintf(buf, len, "MOVS%s R%d, %s", cond, RD(ir), operand);
389 case 28: /* BIC Rd, Rn, operand */
390 arm_disasm_shift_operand(ir, operand, sizeof(operand));
391 snprintf(buf, len, "BIC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
393 case 29: /* BICS Rd, Rn, operand */
394 arm_disasm_shift_operand(ir, operand, sizeof(operand));
395 snprintf(buf, len, "BICS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
397 case 30: /* MVN Rd, Rn, operand */
398 arm_disasm_shift_operand(ir, operand, sizeof(operand));
399 snprintf(buf, len, "MVN%s R%d, %s", cond, RD(ir), operand);
401 case 31: /* MVNS Rd, Rn, operand */
402 arm_disasm_shift_operand(ir, operand, sizeof(operand));
403 snprintf(buf, len, "MVNS%s R%d, %s", cond, RD(ir), operand);
410 case 1: /* Load/store */
411 arm_disasm_address_operand( ir, operand, sizeof(operand), pc );
412 switch( (ir>>20)&0x17 ) {
416 snprintf(buf, len, "STR%s R%d, %s", cond, RD(ir), operand );
421 snprintf(buf, len, "LDR%s R%d, %s", cond, RD(ir), operand );
424 snprintf(buf, len, "STRT%s R%d, %s", cond, RD(ir), operand );
427 snprintf(buf, len, "LDRT%s R%d, %s", cond, RD(ir), operand );
432 snprintf(buf, len, "STRB%s R%d, %s", cond, RD(ir), operand );
437 snprintf(buf, len, "LDRB%s R%d, %s", cond, RD(ir), operand );
440 snprintf(buf, len, "STRBT%s R%d, %s", cond, RD(ir), operand );
443 snprintf(buf, len, "LDRBT%s R%d, %s", cond, RD(ir), operand );
448 if( (ir & 0x02000000) == 0x02000000 ) {
449 int32_t offset = SIGNEXT24(ir&0x00FFFFFF) << 2;
450 if( (ir & 0x01000000) == 0x01000000 ) {
451 snprintf( buf, len, "BL%s $%08Xh", cond, pc + offset + 8 );
453 snprintf( buf, len, "B%s $%08Xh", cond, pc + offset + 8 );
456 /* Load/store multiple */
457 j = snprintf( buf, len, LFLAG(ir) ? "LDM%s%s R%d%c,":"STM%s%s R%d%c,",
458 ldmModes[(ir>>23)&0x03], cond, RN(ir), WFLAG(ir)?'!':' ' );
461 for( i = 0; i<16 && len > 2; i++ ) {
463 j = snprintf( buf, len, "R%d", i );
468 if( SFLAG(ir) && len > 0 ) {
485 uint32_t armt_disasm_instruction( uint32_t pc, char *buf, int len, char *opcode )
487 uint32_t ir = arm_read_word(pc);
488 sprintf( opcode, "%02X %02X", ir&0xFF, (ir>>8) );
.