filename | src/aica/armdasm.c |
changeset | 1091:186558374345 |
prev | 998:1754a8c6a9cf |
author | nkeynes |
date | Fri Jun 04 09:13:40 2010 +1000 (13 years ago) |
permissions | -rw-r--r-- |
last change | Add ability to wrap a binary program up in a virtual cd image (so that we can boot it normally) |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * armdasm.c 21 Aug 2004 - ARM7tdmi (ARMv4) disassembler
5 *
6 * Copyright (c) 2005 Nathan Keynes.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
19 #include "aica/armcore.h"
20 #include "aica/armdasm.h"
21 #include <stdlib.h>
23 #define COND(ir) (ir>>28)
24 #define OPCODE(ir) ((ir>>20)&0x1F)
25 #define GRP(ir) ((ir>>26)&0x03)
26 #define IFLAG(ir) (ir&0x02000000)
27 #define SFLAG(ir) (ir&0x00100000)
28 #define PFLAG(ir) (ir&0x01000000)
29 #define UFLAG(ir) (ir&0x00800000)
30 #define BFLAG(ir) (ir&0x00400000)
31 #define WFLAG(ir) (ir&0x00200000)
32 #define LFLAG(ir) SFLAG(ir)
33 #define RN(ir) ((ir>>16)&0x0F)
34 #define RD(ir) ((ir>>12)&0x0F)
35 #define RS(ir) ((ir>>8)&0x0F)
36 #define RM(ir) (ir&0x0F)
38 #define IMM8(ir) (ir&0xFF)
39 #define IMM12(ir) (ir&0xFFF)
40 #define IMMSPLIT8(ir) (((ir&0xF00)>>4)|(ir&0x0F))
41 #define SHIFTIMM(ir) ((ir>>7)&0x1F)
42 #define IMMROT(ir) ((ir>>7)&0x1E)
43 #define SHIFT(ir) ((ir>>4)&0x07)
44 #define DISP24(ir) ((ir&0x00FFFFFF))
45 #define FSXC(ir) msrFieldMask[RN(ir)]
46 #define ROTIMM12(ir) ROTATE_RIGHT_LONG(IMM8(ir),IMMROT(ir))
47 #define SIGNEXT24(n) (((n)&0x00800000) ? ((n)|0xFF000000) : ((n)&0x00FFFFFF))
51 const struct reg_desc_struct arm_reg_map[] =
52 { {"R0", REG_TYPE_INT, &armr.r[0]}, {"R1", REG_TYPE_INT, &armr.r[1]},
53 {"R2", REG_TYPE_INT, &armr.r[2]}, {"R3", REG_TYPE_INT, &armr.r[3]},
54 {"R4", REG_TYPE_INT, &armr.r[4]}, {"R5", REG_TYPE_INT, &armr.r[5]},
55 {"R6", REG_TYPE_INT, &armr.r[6]}, {"R7", REG_TYPE_INT, &armr.r[7]},
56 {"R8", REG_TYPE_INT, &armr.r[8]}, {"R9", REG_TYPE_INT, &armr.r[9]},
57 {"R10",REG_TYPE_INT, &armr.r[10]}, {"R11",REG_TYPE_INT, &armr.r[11]},
58 {"R12",REG_TYPE_INT, &armr.r[12]}, {"R13",REG_TYPE_INT, &armr.r[13]},
59 {"R14",REG_TYPE_INT, &armr.r[14]}, {"R15",REG_TYPE_INT, &armr.r[15]},
61 /* Block of FPA registers (arm-elf-gdb seems to expect these).
62 * Oddly enough the ARM7TDMI doesn't have them */
63 {"F0",REG_TYPE_NONE, NULL}, {"F1",REG_TYPE_NONE, NULL},
64 {"F2",REG_TYPE_NONE, NULL}, {"F3",REG_TYPE_NONE, NULL},
65 {"F4",REG_TYPE_NONE, NULL}, {"F5",REG_TYPE_NONE, NULL},
66 {"F6",REG_TYPE_NONE, NULL}, {"F7",REG_TYPE_NONE, NULL},
67 {"FPS",REG_TYPE_NONE, NULL},
69 /* System registers */
70 {"CPSR", REG_TYPE_INT, &armr.cpsr}, {"SPSR", REG_TYPE_INT, &armr.spsr},
71 {NULL, 0, NULL} };
73 /* Implementation of get_register - ARM has no pseudo registers so this
74 * is pretty simple
75 */
76 void *arm_get_register( int reg )
77 {
78 if( reg < 0 || reg >= 27 )
79 return NULL;
80 return arm_reg_map[reg].value;
81 }
83 const struct cpu_desc_struct arm_cpu_desc =
84 { "ARM7", arm_disasm_instruction, arm_get_register, arm_has_page,
85 arm_read_phys, arm_write_phys, arm_read_phys, arm_write_phys,
86 arm_execute_instruction, arm_set_breakpoint, arm_clear_breakpoint,
87 arm_get_breakpoint, 4, (char *)&armr, sizeof(armr), arm_reg_map, 26, 26,
88 &armr.r[15] };
89 const struct cpu_desc_struct armt_cpu_desc =
90 { "ARM7T", armt_disasm_instruction, arm_get_register, arm_has_page,
91 arm_read_phys, arm_write_phys, arm_read_phys, arm_write_phys,
92 arm_execute_instruction, arm_set_breakpoint, arm_clear_breakpoint,
93 arm_get_breakpoint, 2, (char*)&armr, sizeof(armr), arm_reg_map, 26, 26,
94 &armr.r[15] };
99 char *conditionNames[] = { "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC",
100 "HI", "LS", "GE", "LT", "GT", "LE", " " /*AL*/, "NV" };
102 /* fsxc */
103 char *msrFieldMask[] = { "", "c", "x", "xc", "s", "sc", "sx", "sxc",
104 "f", "fc", "fx", "fxc", "fs", "fsc", "fsx", "fsxc" };
105 char *ldmModes[] = { "DA", "IA", "DB", "IB" };
107 #define UNIMP(ir) snprintf( buf, len, "??? " )
109 int arm_disasm_shift_operand( uint32_t ir, char *buf, int len )
110 {
111 uint32_t operand, tmp;
112 if( IFLAG(ir) == 0 ) {
113 switch(SHIFT(ir)) {
114 case 0: /* (Rm << imm) */
115 tmp = SHIFTIMM(ir);
116 if( tmp != 0 ) {
117 return snprintf(buf, len, "R%d << %d", RM(ir), tmp );
118 } else {
119 return snprintf(buf, len, "R%d", RM(ir));
120 }
121 case 1: /* (Rm << Rs) */
122 return snprintf(buf, len, "R%d << R%d", RM(ir), RS(ir) );
123 case 2: /* (Rm >> imm) */
124 return snprintf(buf, len, "R%d >> %d", RM(ir), SHIFTIMM(ir) );
125 case 3: /* (Rm >> Rs) */
126 return snprintf(buf, len, "R%d >> R%d", RM(ir), RS(ir) );
127 case 4: /* (Rm >>> imm) */
128 return snprintf(buf, len, "R%d >>> %d", RM(ir), SHIFTIMM(ir) );
129 case 5: /* (Rm >>> Rs) */
130 return snprintf(buf, len, "R%d >>> R%d", RM(ir), RS(ir) );
131 case 6:
132 tmp = SHIFTIMM(ir);
133 if( tmp == 0 ) /* RRX aka rotate with carry */
134 return snprintf(buf, len, "R%d roc 1", RM(ir) );
135 else
136 return snprintf(buf, len, "R%d rot %d", RM(ir), SHIFTIMM(ir) );
137 case 7:
138 return snprintf(buf, len, "R%d rot R%d", RM(ir), RS(ir) );
139 }
140 } else {
141 operand = IMM8(ir);
142 tmp = IMMROT(ir);
143 operand = ROTATE_RIGHT_LONG(operand, tmp);
144 return snprintf(buf, len, "#%08Xh", operand );
145 }
146 return 0;
147 }
149 static int arm_disasm_address_index( uint32_t ir, char *buf, int len )
150 {
151 uint32_t tmp;
153 switch(SHIFT(ir)) {
154 case 0: /* (Rm << imm) */
155 tmp = SHIFTIMM(ir);
156 if( tmp != 0 ) {
157 return snprintf( buf, len, "R%d << %d", RM(ir), tmp );
158 } else {
159 return snprintf( buf, len, "R%d", RM(ir) );
160 }
161 case 2: /* (Rm >> imm) */
162 return snprintf( buf, len, "R%d >> %d", RM(ir), SHIFTIMM(ir) );
163 case 4: /* (Rm >>> imm) */
164 return snprintf( buf, len, "R%d >>> %d", RM(ir), SHIFTIMM(ir) );
165 case 6:
166 tmp = SHIFTIMM(ir);
167 if( tmp == 0 ) /* RRX aka rotate with carry */
168 return snprintf( buf, len, "R%d roc 1", RM(ir) );
169 else
170 return snprintf( buf, len, "R%d rot %d", RM(ir), tmp );
171 default:
172 return UNIMP(ir);
173 }
174 }
176 static int arm_disasm_address_operand( uint32_t ir, char *buf, int len, int pc )
177 {
178 char shift[32];
180 char sign = UFLAG(ir) ? '+' : '-';
181 /* I P U . W */
182 switch( (ir>>21)&0x19 ) {
183 case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
184 case 1:
185 return snprintf( buf, len, "[R%d], R%d %c= #%04Xh", RN(ir), RN(ir), sign, IMM12(ir) );
186 case 8: /* Rn - imm offset [5.2.2 A5-20] */
187 if( RN(ir) == 15 ) { /* PC relative - decode here */
188 uint32_t addr = pc + 8 + (UFLAG(ir) ? IMM12(ir) : -IMM12(ir));
189 return snprintf( buf, len, "[$%08Xh] <- #%08Xh", addr,
190 arm_read_long( addr ) );
191 } else {
192 return snprintf( buf, len, "[R%d %c #%04Xh]", RN(ir), sign, IMM12(ir) );
193 }
194 case 9: /* Rn -= imm offset (pre-indexed) [5.2.5 A5-24] */
195 return snprintf( buf, len, "[R%d %c= #%04Xh]", RN(ir), sign, IMM12(ir) );
196 case 16: /* Rn -= Rm (post-indexed) [5.2.10 A5-32 ] */
197 case 17:
198 arm_disasm_address_index( ir, shift, sizeof(shift) );
199 return snprintf( buf, len, "[R%d], R%d %c= %s", RN(ir), RN(ir), sign, shift );
200 case 24: /* Rn - Rm [5.2.4 A5-23] */
201 arm_disasm_address_index( ir, shift, sizeof(shift) );
202 return snprintf( buf, len, "[R%d %c %s]", RN(ir), sign, shift );
203 case 25: /* RN -= Rm (pre-indexed) [5.2.7 A5-26] */
204 arm_disasm_address_index( ir, shift, sizeof(shift) );
205 return snprintf( buf, len, "[R%d %c= %s]", RN(ir), sign, shift );
206 default:
207 return UNIMP(ir); /* Unreachable */
208 }
209 }
211 static int arm_disasm_address3_operand( uint32_t ir, char *buf, int len, int pc )
212 {
213 char sign = UFLAG(ir) ? '+' : '-';
215 switch( (ir>>21) & 0x0B) {
216 case 0: /* Rn -= Rm (post-indexed) [5.3.7 A5-48] */
217 case 1: /* UNPREDICTABLE */
218 return snprintf( buf, len, "[R%d], R%d %c= R%d", RN(ir), RN(ir), sign, RM(ir) ) ;
219 case 2: /* Rn -= imm (post-indexed) [5.3.6 A5-46] */
220 case 3: /* UNPREDICTABLE */
221 return snprintf( buf, len, "[R%d], R%d %c= #%04Xh", RN(ir), RN(ir), sign, IMMSPLIT8(ir) );
222 case 8: /* Rn - Rm [5.3.3 A5-38] */
223 return snprintf( buf, len, "[R%d %c R%d]", RN(ir), sign, RM(ir) );
224 case 9: /* Rn -= Rm (pre-indexed) [5.3.5 A5-42] */
225 return snprintf( buf, len, "[R%d %c= R%d]", RN(ir), sign, RM(ir) );
226 case 10: /* Rn - imm offset [5.3.2 A5-36] */
227 return snprintf( buf, len, "[R%d %c #%04Xh]", RN(ir), sign, IMMSPLIT8(ir) );
228 case 11: /* Rn -= imm offset (pre-indexed) [5.3.4 A5-40] */
229 return snprintf( buf, len, "[R%d %c= #%04Xh]", RN(ir), sign, IMMSPLIT8(ir) );
230 default:
231 return UNIMP(ir); /* Unreachable */
232 }
233 }
235 uint32_t arm_disasm_instruction( uint32_t pc, char *buf, int len, char *opcode )
236 {
237 char operand[64];
238 uint32_t ir = arm_read_long(pc);
239 int i,j;
241 sprintf( opcode, "%08X", ir );
243 if( COND(ir) == 0x0F ) {
244 UNIMP(ir);
245 return pc+4;
246 }
247 char *cond = conditionNames[COND(ir)];
249 switch( GRP(ir) ) {
250 case 0:
251 if( (ir & 0x0D900000) == 0x01000000 ) {
252 /* Instructions that aren't actual data processing */
253 switch( ir & 0x0FF000F0 ) {
254 case 0x01200010: /* BXcc */
255 snprintf(buf, len, "BX%s R%d", cond, RM(ir));
256 break;
257 case 0x01000000: /* MRS Rd, CPSR */
258 snprintf(buf, len, "MRS%s R%d, CPSR", cond, RD(ir));
259 break;
260 case 0x01400000: /* MRS Rd, SPSR */
261 snprintf(buf, len, "MRS%s R%d, SPSR", cond, RD(ir));
262 break;
263 case 0x01200000: /* MSR CPSR, Rm */
264 snprintf(buf, len, "MSR%s CPSR_%s, R%d", cond, FSXC(ir), RM(ir));
265 break;
266 case 0x01600000: /* MSR SPSR, Rm */
267 snprintf(buf, len, "MSR%s SPSR_%s, R%d", cond, FSXC(ir), RM(ir));
268 break;
269 case 0x03200000: /* MSR CPSR, imm */
270 snprintf(buf, len, "MSR%s CPSR_%s, #%08X", cond, FSXC(ir), ROTIMM12(ir));
271 break;
272 case 0x03600000: /* MSR SPSR, imm */
273 snprintf(buf, len, "MSR%s SPSR_%s, #%08X", cond, FSXC(ir), ROTIMM12(ir));
274 break;
275 default:
276 UNIMP();
277 }
278 } else if( (ir & 0x0E000090) == 0x00000090 ) {
279 /* Neither are these */
280 switch( (ir>>5)&0x03 ) {
281 case 0:
282 /* Arithmetic extension area */
283 switch(OPCODE(ir)) {
284 case 0: /* MUL */
285 snprintf(buf,len, "MUL%s R%d, R%d, R%d", cond, RN(ir), RM(ir), RS(ir) );
286 break;
287 case 1: /* MULS */
288 break;
289 case 2: /* MLA */
290 snprintf(buf,len, "MLA%s R%d, R%d, R%d, R%d", cond, RN(ir), RM(ir), RS(ir), RD(ir) );
291 break;
292 case 3: /* MLAS */
293 break;
294 case 8: /* UMULL */
295 snprintf(buf,len, "UMULL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
296 break;
297 case 9: /* UMULLS */
298 break;
299 case 10: /* UMLAL */
300 snprintf(buf,len, "UMLAL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
301 break;
302 case 11: /* UMLALS */
303 break;
304 case 12: /* SMULL */
305 snprintf(buf,len, "SMULL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
306 break;
307 case 13: /* SMULLS */
308 break;
309 case 14: /* SMLAL */
310 snprintf(buf,len, "SMLAL%s R%d, R%d, R%d, R%d", cond, RD(ir), RN(ir), RM(ir), RS(ir) );
311 break;
312 case 15: /* SMLALS */
314 break;
315 case 16: /* SWP */
316 snprintf(buf,len, "SWP%s R%d, R%d, [R%d]", cond, RD(ir), RN(ir), RM(ir) );
317 break;
318 case 20: /* SWPB */
319 snprintf(buf,len, "SWPB%s R%d, R%d, [R%d]", cond, RD(ir), RN(ir), RM(ir) );
320 break;
321 default:
322 UNIMP(ir);
323 }
324 break;
325 case 1:
326 arm_disasm_address3_operand( ir, operand, sizeof(operand), pc );
327 if( LFLAG(ir) ) { /* LDRH */
328 snprintf(buf, len, "LDR%sH R%d, %s", cond, RD(ir), operand );
329 } else { /* STRH */
330 snprintf(buf, len, "STR%sH R%d, %s", cond, RD(ir), operand );
331 }
332 break;
333 case 2:
334 if( LFLAG(ir) ) { /* LDRSB */
335 arm_disasm_address3_operand( ir, operand, sizeof(operand), pc );
336 snprintf(buf, len, "LDR%sSB R%d, %s", cond, RD(ir), operand );
337 } else {
338 UNIMP(ir);
339 }
340 break;
341 case 3:
342 if( LFLAG(ir) ) { /* LDRSH */
343 arm_disasm_address3_operand( ir, operand, sizeof(operand), pc );
344 snprintf(buf, len, "LDR%sSH R%d, %s", cond, RD(ir), operand );
345 } else {
346 UNIMP(ir);
347 }
348 break;
349 }
350 } else {
351 /* Data processing */
353 switch(OPCODE(ir)) {
354 case 0: /* AND Rd, Rn, operand */
355 arm_disasm_shift_operand(ir, operand, sizeof(operand));
356 snprintf(buf, len, "AND%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
357 break;
358 case 1: /* ANDS Rd, Rn, operand */
359 arm_disasm_shift_operand(ir, operand, sizeof(operand));
360 snprintf(buf, len, "ANDS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
361 break;
362 case 2: /* EOR Rd, Rn, operand */
363 arm_disasm_shift_operand(ir, operand, sizeof(operand));
364 snprintf(buf, len, "EOR%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
365 break;
366 case 3: /* EORS Rd, Rn, operand */
367 arm_disasm_shift_operand(ir, operand, sizeof(operand));
368 snprintf(buf, len, "EORS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
369 break;
370 case 4: /* SUB Rd, Rn, operand */
371 arm_disasm_shift_operand(ir, operand, sizeof(operand));
372 snprintf(buf, len, "SUB%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
373 break;
374 case 5: /* SUBS Rd, Rn, operand */
375 arm_disasm_shift_operand(ir, operand, sizeof(operand));
376 snprintf(buf, len, "SUBS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
377 break;
378 case 6: /* RSB Rd, Rn, operand */
379 arm_disasm_shift_operand(ir, operand, sizeof(operand));
380 snprintf(buf, len, "RSB%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
381 break;
382 case 7: /* RSBS Rd, Rn, operand */
383 arm_disasm_shift_operand(ir, operand, sizeof(operand));
384 snprintf(buf, len, "RSBS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
385 break;
386 case 8: /* ADD Rd, Rn, operand */
387 arm_disasm_shift_operand(ir, operand, sizeof(operand));
388 snprintf(buf, len, "ADD%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
389 break;
390 case 9: /* ADDS Rd, Rn, operand */
391 arm_disasm_shift_operand(ir, operand, sizeof(operand));
392 snprintf(buf, len, "ADDS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
393 break;
394 case 10: /* ADC Rd, Rn, operand */
395 arm_disasm_shift_operand(ir, operand, sizeof(operand));
396 snprintf(buf, len, "ADC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
397 break;
398 case 11: /* ADCS Rd, Rn, operand */
399 arm_disasm_shift_operand(ir, operand, sizeof(operand));
400 snprintf(buf, len, "ADCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
401 break;
402 case 12: /* SBC Rd, Rn, operand */
403 arm_disasm_shift_operand(ir, operand, sizeof(operand));
404 snprintf(buf, len, "SBC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
405 break;
406 case 13: /* SBCS Rd, Rn, operand */
407 arm_disasm_shift_operand(ir, operand, sizeof(operand));
408 snprintf(buf, len, "SBCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
409 break;
410 case 14: /* RSC Rd, Rn, operand */
411 arm_disasm_shift_operand(ir, operand, sizeof(operand));
412 snprintf(buf, len, "RSC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
413 break;
414 case 15: /* RSCS Rd, Rn, operand */
415 arm_disasm_shift_operand(ir, operand, sizeof(operand));
416 snprintf(buf, len, "RSCS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
417 break;
418 case 17: /* TST Rd, Rn, operand */
419 arm_disasm_shift_operand(ir, operand, sizeof(operand));
420 snprintf(buf, len, "TST%s R%d, %s", cond, RN(ir), operand);
421 break;
422 case 19: /* TEQ Rd, Rn, operand */
423 arm_disasm_shift_operand(ir, operand, sizeof(operand));
424 snprintf(buf, len, "TEQ%s R%d, %s", cond, RN(ir), operand);
425 break;
426 case 21: /* CMP Rd, Rn, operand */
427 arm_disasm_shift_operand(ir, operand, sizeof(operand));
428 snprintf(buf, len, "CMP%s R%d, %s", cond, RN(ir), operand);
429 break;
430 case 23: /* CMN Rd, Rn, operand */
431 arm_disasm_shift_operand(ir, operand, sizeof(operand));
432 snprintf(buf, len, "CMN%s R%d, %s", cond, RN(ir), operand);
433 break;
434 case 24: /* ORR Rd, Rn, operand */
435 arm_disasm_shift_operand(ir, operand, sizeof(operand));
436 snprintf(buf, len, "ORR%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
437 break;
438 case 25: /* ORRS Rd, Rn, operand */
439 arm_disasm_shift_operand(ir, operand, sizeof(operand));
440 snprintf(buf, len, "ORRS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
441 break;
442 case 26: /* MOV Rd, operand */
443 if( ir == 0xE1A00000 ) {
444 /* Not technically a different instruction,
445 * but this one is commonly used as a NOP,
446 * so...
447 */
448 snprintf(buf, len, "NOP");
449 } else {
450 arm_disasm_shift_operand(ir, operand, sizeof(operand));
451 snprintf(buf, len, "MOV%s R%d, %s", cond, RD(ir), operand);
452 }
453 break;
454 case 27: /* MOVS Rd, operand */
455 arm_disasm_shift_operand(ir, operand, sizeof(operand));
456 snprintf(buf, len, "MOVS%s R%d, %s", cond, RD(ir), operand);
457 break;
458 case 28: /* BIC Rd, Rn, operand */
459 arm_disasm_shift_operand(ir, operand, sizeof(operand));
460 snprintf(buf, len, "BIC%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
461 break;
462 case 29: /* BICS Rd, Rn, operand */
463 arm_disasm_shift_operand(ir, operand, sizeof(operand));
464 snprintf(buf, len, "BICS%s R%d, R%d, %s", cond, RD(ir), RN(ir), operand);
465 break;
466 case 30: /* MVN Rd, Rn, operand */
467 arm_disasm_shift_operand(ir, operand, sizeof(operand));
468 snprintf(buf, len, "MVN%s R%d, %s", cond, RD(ir), operand);
469 break;
470 case 31: /* MVNS Rd, Rn, operand */
471 arm_disasm_shift_operand(ir, operand, sizeof(operand));
472 snprintf(buf, len, "MVNS%s R%d, %s", cond, RD(ir), operand);
473 break;
474 default:
475 UNIMP(ir);
476 }
477 }
478 break;
479 case 1: /* Load/store */
480 arm_disasm_address_operand( ir, operand, sizeof(operand), pc );
481 switch( (ir>>20)&0x17 ) {
482 case 0:
483 case 16:
484 case 18:
485 snprintf(buf, len, "STR%s R%d, %s", cond, RD(ir), operand );
486 break;
487 case 1:
488 case 17:
489 case 19:
490 snprintf(buf, len, "LDR%s R%d, %s", cond, RD(ir), operand );
491 break;
492 case 2:
493 snprintf(buf, len, "STRT%s R%d, %s", cond, RD(ir), operand );
494 break;
495 case 3:
496 snprintf(buf, len, "LDRT%s R%d, %s", cond, RD(ir), operand );
497 break;
498 case 4:
499 case 20:
500 case 22:
501 snprintf(buf, len, "STRB%s R%d, %s", cond, RD(ir), operand );
502 break;
503 case 5:
504 case 21:
505 case 23:
506 snprintf(buf, len, "LDRB%s R%d, %s", cond, RD(ir), operand );
507 break;
508 case 6:
509 snprintf(buf, len, "STRBT%s R%d, %s", cond, RD(ir), operand );
510 break;
511 case 7:
512 snprintf(buf, len, "LDRBT%s R%d, %s", cond, RD(ir), operand );
513 break;
514 }
515 break;
516 case 2:
517 if( (ir & 0x02000000) == 0x02000000 ) {
518 int32_t offset = SIGNEXT24(ir&0x00FFFFFF) << 2;
519 if( (ir & 0x01000000) == 0x01000000 ) {
520 snprintf( buf, len, "BL%s $%08Xh", cond, pc + offset + 8 );
521 } else {
522 snprintf( buf, len, "B%s $%08Xh", cond, pc + offset + 8 );
523 }
524 } else {
525 /* Load/store multiple */
526 j = snprintf( buf, len, LFLAG(ir) ? "LDM%s%s R%d%c,":"STM%s%s R%d%c,",
527 ldmModes[(ir>>23)&0x03], cond, RN(ir), WFLAG(ir)?'!':' ' );
528 buf += j;
529 len -= j;
530 for( i = 0; i<16 && len > 2; i++ ) {
531 if( ir & (1<<i) ) {
532 j = snprintf( buf, len, "R%d", i );
533 buf+=j;
534 len-=j;
535 }
536 }
537 if( BFLAG(ir) && len > 0 ) {
538 buf[0] = '^';
539 buf[1] = '\0';
540 }
541 }
542 break;
543 case 3: /* Copro */
544 if( (ir & 0x0F000000) == 0x0F000000 ) {
545 snprintf( buf, len, "SWI%s #%08Xh", cond, SIGNEXT24(ir) );
546 } else {
547 UNIMP(ir);
548 }
549 break;
550 }
554 return pc+4;
555 }
558 uint32_t armt_disasm_instruction( uint32_t pc, char *buf, int len, char *opcode )
559 {
560 uint32_t ir = arm_read_word(pc);
561 sprintf( opcode, "%02X %02X", ir&0xFF, (ir>>8) );
562 UNIMP(ir);
563 return pc+2;
564 }
.