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