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