├── .gitignore ├── README.md ├── arm7-dasm.c ├── arm7core.h ├── arm7dasm.c └── emu.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | 4 | # Libraries 5 | *.lib 6 | *.a 7 | 8 | # Shared objects (inc. Windows DLLs) 9 | *.dll 10 | *.so 11 | *.so.* 12 | *.dylib 13 | 14 | # Executables 15 | *.exe 16 | *.out 17 | *.app 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | arm7-dasm 2 | ========= 3 | 4 | android kernel disassembler based on MAME emulator code 5 | 6 | Compile: 7 | 8 | $ gcc -o arm7-dasm arm7-dasm.c 9 | 10 | Disassemble: 11 | 12 | $ ./arm7-dasm [kernel image filename] [image base address] [start address] 13 | 14 | Disassemble with symbol table: 15 | 16 | $ ./arm7-dasm [kernel image filename] [image base address] [start address or symbol name] [symbol table file] 17 | 18 | Example: 19 | 20 | $ kallsymsprint kernel.Image > kallsyms.txt 21 | [+]mmap 22 | mem=f6a0b000 length=00bcff4c offset=c95fd000 23 | [+]kallsyms_addresses=c076dc90 24 | count=0000d90e 25 | [+]kallsyms_num_syms=0000d90e 26 | [+]kallsyms_names=c07a40e0 27 | [+]kallsyms_markers=c08415b0 28 | [+]kallsyms_token_table=c0841920 29 | [+]kallsyms_token_index=c0841cd0 30 | [+]kallsyms_lookup_name 31 | 32 | $ ./arm7-dasm kernel.Image c0008000 vmalloc_exec kallsyms.txt > vmalloc_exec.dasm 33 | 55417 symbols are loaded. 34 | 35 | $ cat vmalloc_exec.dasm 36 | Disassemble 0xc0143354 - 0xc0143374 37 | c0143354: e5 9f 30 1c LDR R3, =$c0bd8318 [$c0143378] 38 | c0143358: e9 2d 40 07 STMPW [SP], { R0-R2, LR } 39 | c014335c: e3 e0 20 00 MVN R2, #$0 40 | c0143360: e5 93 30 00 LDR R3, [R3] 41 | c0143364: e3 a0 10 01 MOV R1, #$1 42 | c0143368: e8 8d 40 04 STMU [SP], { R2, LR } 43 | c014336c: e3 a0 20 d2 MOV R2, #$d2 44 | c0143370: eb ff ff 85 BL $c014318c <__vmalloc_node> 45 | c0143374: e8 bd 80 0e LDMUW [SP], { R1-R3, PC } 46 | 47 | Example 2: 48 | How to find ptms_fops address 49 | 50 | Generate kallsyms table 51 | 52 | $ kallsymsprint kernel.Image > kallsyms.txt 53 | [+]mmap 54 | mem=f6a0b000 length=00bcff4c offset=c95fd000 55 | [+]kallsyms_addresses=c076dc90 56 | count=0000d90e 57 | [+]kallsyms_num_syms=0000d90e 58 | [+]kallsyms_names=c07a40e0 59 | [+]kallsyms_markers=c08415b0 60 | [+]kallsyms_token_table=c0841920 61 | [+]kallsyms_token_index=c0841cd0 62 | [+]kallsyms_lookup_name 63 | 64 | Disassemble pty_init with kallsyms table 65 | 66 | $ arm7-dasm kernel.Image c0008000 pty_init kallsyms.txt > pty_init.dasm 67 | 55417 symbols are loaded. 68 | 69 | Search where tty_default_fops is called 70 | 71 | $ grep tty_default_fops pty_init.dasm 72 | c0a1d188: eb e3 e6 c7 BL $c0316cac 73 | 74 | Check more a few lines 75 | 76 | $ grep ^c0a1d1[8-9] pty_init.dasm 77 | c0a1d180: 1a ff ff 5f BNE $c0a1cf04 78 | c0a1d184: e2 85 00 08 ADD R0, R5, #$8 79 | c0a1d188: eb e3 e6 c7 BL $c0316cac 80 | c0a1d18c: e5 9f 30 c0 LDR R3, =$c031ea48 [$c0a1d254] 81 | c0a1d190: e2 85 00 70 ADD R0, R5, #$70 82 | c0a1d194: e2 85 10 08 ADD R1, R5, #$8 83 | c0a1d198: e5 85 30 34 STR R3, [R5, #$34] 84 | c0a1d19c: eb dc e0 f0 BL $c0155564 85 | 86 | Now we know "ptms_fops = R5 + $8", check R5 value 87 | 88 | $ grep -n ^c0a1d184 pty_init.dasm 89 | 188:c0a1d184: e2 85 00 08 ADD R0, R5, #$8 90 | 91 | $ head -n 188 pty_init.dasm | grep 'R5.*=' | tail -1 92 | c0a1d02c: e5 9f 51 fc LDR R5, =$c0cc37e0 [$c0a1d230] 93 | 94 | Finally we found "ptms_fops = $c0cc37e0 + $8 = $c0cc37e8" 95 | -------------------------------------------------------------------------------- /arm7-dasm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define INT8 signed char 7 | #define INT16 signed short 8 | #define INT32 signed int 9 | #define UINT8 unsigned char 10 | #define UINT16 unsigned short 11 | #define UINT32 unsigned int 12 | 13 | #define endianness_t int 14 | #define device_irq_callback void * 15 | #define legacy_cpu_device void * 16 | #define address_space void * 17 | #define direct_read_data void * 18 | 19 | #define write32_device_func void * 20 | #define read32_device_func void * 21 | 22 | #define DASMFLAG_STEP_OVER 1 23 | #define DASMFLAG_STEP_OUT 2 24 | #define DASMFLAG_SUPPORTED 4 25 | 26 | #define CPU_DISASSEMBLE(x) int x(char *buffer, UINT32 pc, const UINT8 *oprom) 27 | 28 | #define KSYM_NAME_LEN 128 29 | 30 | UINT8 *image_data; 31 | UINT32 image_base; 32 | UINT32 image_size; 33 | 34 | int dasm_process_pass; 35 | 36 | struct _coderef_t; 37 | typedef struct _coderef_t coderef_t; 38 | 39 | struct _coderef_t 40 | { 41 | UINT32 from; 42 | struct _coderef_t *next; 43 | }; 44 | 45 | coderef_t **coderef; 46 | 47 | void register_coderef(UINT32 from, UINT32 to) 48 | { 49 | coderef_t *p, **q; 50 | 51 | if (dasm_process_pass) 52 | return; 53 | 54 | if (to < image_base) 55 | return; 56 | 57 | to -= image_base; 58 | if (to >= image_size) 59 | return; 60 | 61 | to /= 4; 62 | 63 | p = malloc(sizeof *p); 64 | if (!p) 65 | { 66 | fprintf(stderr, "Out fo memory\n"); 67 | exit(1); 68 | } 69 | 70 | p->from = from; 71 | p->next = NULL; 72 | 73 | for (q = &coderef[to]; *q; q = &(*q)->next); 74 | *q = p; 75 | } 76 | 77 | typedef struct 78 | { 79 | char name[KSYM_NAME_LEN]; 80 | UINT32 addr; 81 | } symbol_t; 82 | 83 | symbol_t *symbols; 84 | size_t symbol_len; 85 | size_t symbol_size; 86 | 87 | static int search_symbol(UINT32 addr) 88 | { 89 | int s = 0; 90 | int e = symbol_len - 1; 91 | 92 | while (e >= s) 93 | { 94 | int i = (s + e) / 2; 95 | if (symbols[i].addr == addr) 96 | return i; 97 | 98 | if (symbols[i].addr > addr) 99 | e = i - 1; 100 | else 101 | s = i + 1; 102 | } 103 | 104 | return s; 105 | } 106 | 107 | int have_symbol(UINT32 addr) 108 | { 109 | int i; 110 | 111 | if (symbols == NULL) 112 | return 0; 113 | 114 | i = search_symbol(addr); 115 | return symbols[i].addr == addr; 116 | } 117 | 118 | const char *get_symbol_name(UINT32 addr) 119 | { 120 | static char buf[KSYM_NAME_LEN + 16]; 121 | 122 | if (symbols) 123 | { 124 | int i; 125 | 126 | i = search_symbol(addr); 127 | if (symbols[i].addr == addr) 128 | { 129 | snprintf(buf, sizeof (buf) - 1, "$%x <%s>", addr, symbols[i].name); 130 | buf[sizeof (buf) - 1] = '\0'; 131 | return buf; 132 | } 133 | } 134 | 135 | sprintf(buf, "$%x", addr); 136 | return buf; 137 | } 138 | 139 | const UINT32 get_symbol_address(const char *name) 140 | { 141 | int i; 142 | 143 | if (symbols == NULL) 144 | return 0; 145 | 146 | for (i = 0; i < symbol_len; i++) 147 | if (strcmp(symbols[i].name, name) == 0) 148 | return symbols[i].addr; 149 | 150 | return 0; 151 | } 152 | 153 | UINT32 rnv_requested; 154 | 155 | void check_rnv(UINT32 addr) 156 | { 157 | if (rnv_requested != 0 && rnv_requested < addr) 158 | return; 159 | 160 | if (addr & 3) 161 | { 162 | #ifdef DEBUG 163 | fprintf(stderr, "skip: check_rnv(0x%08x)\n", addr); 164 | #endif /* DEBUG */ 165 | return; 166 | } 167 | 168 | #ifdef DEBUG 169 | if (!dasm_process_pass) 170 | fprintf(stderr, "check_rnv(0x%08x)\n", addr); 171 | #endif /* DEBUG */ 172 | 173 | rnv_requested = addr; 174 | } 175 | 176 | #include "arm7dasm.c" 177 | 178 | static void insert_symbol(int pos, const char *name, UINT32 addr) 179 | { 180 | int i; 181 | 182 | for (i = symbol_len - 1; i >= pos; i--) 183 | symbols[i + 1] = symbols[i]; 184 | 185 | symbols[pos].addr = addr; 186 | 187 | strncpy(symbols[pos].name, name, sizeof (symbols[0].name) - 1); 188 | symbols[pos].name[sizeof (symbols[0].name) - 1] = '\0'; 189 | 190 | symbol_len++; 191 | } 192 | 193 | static void register_symbol(const char *name, UINT32 addr) 194 | { 195 | int i; 196 | 197 | if (symbols == NULL) 198 | { 199 | symbol_size = 1024; 200 | symbols = malloc(sizeof (*symbols) * symbol_size); 201 | if (symbols == NULL) 202 | return; 203 | 204 | symbol_len = 0; 205 | } 206 | 207 | i = search_symbol(addr); 208 | if (symbols[i].addr == addr) 209 | return; 210 | 211 | if (symbol_len == symbol_size) 212 | { 213 | symbol_size += 1024; 214 | symbols = realloc(symbols, sizeof (*symbols) * symbol_size); 215 | if (symbols == NULL) 216 | return; 217 | } 218 | 219 | insert_symbol(i, name, addr); 220 | } 221 | 222 | static void read_kallsyms(const char *filename) 223 | { 224 | FILE *fp = fopen(filename, "rt"); 225 | 226 | if (!fp) 227 | { 228 | fprintf(stderr, "cannot open file: %s\n", filename); 229 | return; 230 | } 231 | 232 | while (!feof(fp)) 233 | { 234 | char buf[1024]; 235 | UINT32 addr; 236 | char name[KSYM_NAME_LEN]; 237 | char *s; 238 | char *p; 239 | 240 | if (fgets(buf, sizeof buf, fp) == NULL) 241 | break; 242 | 243 | s = strtok_r(buf, " \r\n", &p); 244 | if (s == NULL) 245 | break; 246 | 247 | if (sscanf(s, "%x", &addr) != 1) 248 | break; 249 | 250 | s = strtok_r(NULL, " \r\n", &p); 251 | if (s == NULL) 252 | continue; 253 | 254 | strncpy(name, s, KSYM_NAME_LEN - 1); 255 | name[KSYM_NAME_LEN - 1] = '\0'; 256 | 257 | if ((s = strtok_r(NULL, " \r\n", &p)) != NULL) 258 | { 259 | strncpy(name, s, KSYM_NAME_LEN - 1); 260 | name[KSYM_NAME_LEN - 1] = '\0'; 261 | } 262 | 263 | register_symbol(name, addr); 264 | } 265 | 266 | fclose(fp); 267 | 268 | fprintf(stderr, "%d symbols are loaded.\n", symbol_len); 269 | } 270 | 271 | enum 272 | { 273 | STAT_START = 0, 274 | STAT_HAS_STACKFRAME, 275 | STAT_END_STACKFRAME, 276 | STAT_END_FUNCTION, 277 | STAT_PROCESS_WHOLE, 278 | STAT_UNKNOWN 279 | }; 280 | 281 | int load_image(const char *name) 282 | { 283 | FILE *fp; 284 | 285 | fp = fopen(name, "rb"); 286 | if (!fp) 287 | return 1; 288 | 289 | fseek(fp, 0, SEEK_END); 290 | 291 | image_size = ftell(fp); 292 | if (image_size < 4) 293 | { 294 | fprintf(stderr, "image file is too small\n"); 295 | goto error_exit; 296 | } 297 | 298 | fseek(fp, 0, SEEK_SET); 299 | 300 | image_data = malloc(image_size); 301 | if (!image_data) 302 | { 303 | fprintf(stderr, "out of memory for rom image\n"); 304 | goto error_exit; 305 | } 306 | 307 | memset(image_data, 0, image_size); 308 | 309 | if (fread(image_data, image_size, 1, fp) != 1) 310 | { 311 | fprintf(stderr, "file read error\n"); 312 | goto error_exit; 313 | } 314 | 315 | fclose(fp); 316 | 317 | return 0; 318 | 319 | error_exit: 320 | fclose(fp); 321 | return 1; 322 | } 323 | 324 | static UINT32 start; 325 | static UINT32 end; 326 | static int status; 327 | 328 | static void check_stackframe(UINT32 pc, UINT32 op, UINT32 *frameregs) 329 | { 330 | switch (status) 331 | { 332 | case STAT_START: 333 | // BX LR 334 | // MOV PC, LR 335 | if (op == 0xe12fff1e 336 | || op == 0xe1a0f00e) 337 | { 338 | status = STAT_END_FUNCTION; 339 | return; 340 | } 341 | 342 | // e92d4xxx: STMPW [SP], { ..., LR } 343 | // e92ddxxx: STMPW [SP], { , LR, PC } 344 | if (((op & 0xfffff000) == 0xe92d4000) 345 | || ((op & 0xfffff000) == 0xe92dd000)) 346 | { 347 | status = STAT_HAS_STACKFRAME; 348 | // R4-R12 349 | *frameregs = op & 0x00000ff0; 350 | 351 | #ifdef DEBUG 352 | fprintf(stderr, "found: STMPW: pc = 0x%08x, frameregs = 0x%08x\n", pc, *frameregs); 353 | #endif /* DEBUG */ 354 | return; 355 | } 356 | 357 | if (pc - start >= 32) 358 | { 359 | status = STAT_PROCESS_WHOLE; 360 | fprintf(stderr, "Disassemble whole image.\n"); 361 | } 362 | 363 | return; 364 | 365 | case STAT_HAS_STACKFRAME: 366 | // e8bd8xxx: LDMUW [SP], { ..., PC } 367 | // e89daxxx: LDMU [SP], { ..., SP, PC } 368 | if (((op & 0xfffffff0) == (0xe8bd8000 | *frameregs)) 369 | || ((op & 0xfffffff0) == (0xe89da000 | *frameregs))) 370 | { 371 | if (end <= pc) 372 | status = STAT_END_FUNCTION; 373 | else 374 | status = STAT_END_STACKFRAME; 375 | 376 | #ifdef DEBUG 377 | fprintf(stderr, "found: LDMUW (PC): pc = 0x%08x, frameregs = 0x%08x\n", pc, *frameregs); 378 | #endif /* DEBUG */ 379 | 380 | } 381 | 382 | return; 383 | } 384 | } 385 | 386 | static int check_branch(UINT32 pc, UINT32 op) 387 | { 388 | // Bxx $xxxxxxxx 389 | if ((op & 0x0f000000) == 0x0a000000) 390 | { 391 | int b = pc + (op & 0x00ffffff) * 4 + 8; 392 | 393 | if (op & 0x00800000) 394 | b += 0xff000000 * 4; /* sign-extend */ 395 | 396 | // B $xxxxxxxx 397 | if ((op & 0xff000000) == 0xea000000) 398 | if (b < pc && pc > end) 399 | return 1; 400 | 401 | if (b > image_base + image_size) 402 | return 0; 403 | 404 | if (status == STAT_END_STACKFRAME) 405 | { 406 | if (b > end) 407 | return 1; 408 | } 409 | else if (!have_symbol(b)) 410 | { 411 | if (end < b) 412 | end = b; 413 | } 414 | #if 0 415 | else if (status != STAT_HAS_STACKFRAME) 416 | { 417 | fprintf(stderr, "end due to branch to symbol\n"); 418 | return 1; 419 | } 420 | #endif 421 | } 422 | 423 | return 0; 424 | } 425 | 426 | static void write_result(UINT32 pc, const char *asm7) 427 | { 428 | coderef_t *ref; 429 | UINT32 off; 430 | int i; 431 | 432 | off = pc - image_base; 433 | ref = coderef[off / 4]; 434 | 435 | if (ref) 436 | { 437 | printf("%08x: %*s; from %08x\n", pc, 44, "", ref->from); 438 | 439 | for (ref = ref->next; ref; ref = ref->next) 440 | printf("%08x: %*s; %08x\n", pc, 44, "", ref->from); 441 | } 442 | 443 | if (have_symbol(pc)) 444 | { 445 | i = search_symbol(pc); 446 | printf("%08x: %12s<%s>\n", pc, "", symbols[i].name); 447 | } 448 | 449 | printf("%08x: ", pc); 450 | 451 | for (i = 0; i < 4; i++) 452 | printf("%02x ", image_data[off + 3 - i]); 453 | 454 | printf(" %s\n", asm7); 455 | } 456 | 457 | static int do_disassemble(void) 458 | { 459 | UINT32 pc; 460 | 461 | rnv_requested = 0; 462 | end = 0; 463 | 464 | status = STAT_START; 465 | 466 | for (dasm_process_pass = 0; dasm_process_pass < 2; dasm_process_pass++) 467 | { 468 | UINT32 frameregs = 0; 469 | 470 | if (dasm_process_pass == 1) 471 | printf("Disassemble 0x%08x - 0x%08x\n", start, end); 472 | 473 | for (pc = start; pc < image_base + image_size; pc += 4) 474 | { 475 | UINT32 off; 476 | UINT32 op; 477 | char buf[1024]; 478 | int i; 479 | int n; 480 | 481 | off = pc - image_base; 482 | 483 | for (i = 0; i < 4; i++) 484 | { 485 | op <<= 8; 486 | op += image_data[off + 3 - i]; 487 | } 488 | 489 | if (!dasm_process_pass) 490 | { 491 | if (end < pc) 492 | end = pc; 493 | 494 | check_stackframe(pc, op, &frameregs); 495 | } 496 | 497 | n = arm7arm(buf, pc, &image_data[off]); 498 | 499 | if (dasm_process_pass) 500 | { 501 | write_result(pc, buf); 502 | 503 | if (pc >= end) 504 | break; 505 | 506 | continue; 507 | } 508 | 509 | if (status == STAT_PROCESS_WHOLE) 510 | continue; 511 | 512 | if (status == STAT_END_FUNCTION) 513 | if (pc >= end) 514 | break; 515 | 516 | if (check_branch(pc, op)) 517 | { 518 | #ifdef DEBUG 519 | fprintf(stderr, "end by branch\n"); 520 | break; 521 | #endif /* DEBUG */ 522 | } 523 | 524 | if (status != STAT_HAS_STACKFRAME && status != STAT_UNKNOWN) 525 | if (rnv_requested != 0 && pc >= rnv_requested) 526 | { 527 | fprintf(stderr, "end at 0x%08x by rnv requested\n", pc); 528 | 529 | end = pc - 4; 530 | break; 531 | } 532 | } 533 | } 534 | 535 | #ifdef DEBUG 536 | fprintf(stderr, "done at 0x%08x (end = 0x%08x, rnv requested: 0x%08x)\n", pc, end, rnv_requested); 537 | #endif /* DEBUG */ 538 | } 539 | 540 | int main(int argc, const char *argv[]) 541 | { 542 | if (argc != 4 && argc != 5) 543 | return 1; 544 | 545 | if (sscanf(argv[2], "%x", &image_base) != 1) 546 | return 1; 547 | 548 | if (load_image(argv[1])) 549 | return 1; 550 | 551 | coderef = malloc(image_size / 4 * sizeof *coderef); 552 | if (!coderef) 553 | { 554 | fprintf(stderr, "out of memory for coderef\n"); 555 | return 1; 556 | } 557 | 558 | memset(coderef, 0, image_size / 4 * sizeof *coderef); 559 | 560 | if (argv[4]) 561 | read_kallsyms(argv[4]); 562 | 563 | start = get_symbol_address(argv[3]); 564 | if (start == 0) 565 | if (sscanf(argv[3], "%x", &start) != 1) 566 | return 1; 567 | 568 | if (start < image_base || start >= image_base + image_size) 569 | return 1; 570 | 571 | do_disassemble(); 572 | 573 | return 0; 574 | } 575 | 576 | /* 577 | vi:ts=2:nowrap:ai:noexpandtab:sw=2 578 | */ 579 | -------------------------------------------------------------------------------- /arm7core.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * arm7core.h 4 | * Portable ARM7TDMI Core Emulator 5 | * 6 | * Copyright Steve Ellenoff, all rights reserved. 7 | * 8 | * - This source code is released as freeware for non-commercial purposes. 9 | * - You are free to use and redistribute this code in modified or 10 | * unmodified form, provided you list me in the credits. 11 | * - If you modify this source code, you must add a notice to each modified 12 | * source file that it has been changed. If you're a nice person, you 13 | * will clearly mark each change too. :) 14 | * - If you wish to use this for commercial purposes, please contact me at 15 | * sellenoff@hotmail.com 16 | * - The author of this copywritten work reserves the right to change the 17 | * terms of its usage and license at any time, including retroactively 18 | * - This entire notice must remain in the source code. 19 | * 20 | * This work is based on: 21 | * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' 22 | * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) 23 | * 24 | ***************************************************************************** 25 | 26 | This file contains everything related to the arm7 core itself, and is presumed 27 | to be cpu implementation non-specific, ie, applies to only the core. 28 | 29 | ******************************************************************************/ 30 | 31 | #pragma once 32 | 33 | #ifndef __ARM7CORE_H__ 34 | #define __ARM7CORE_H__ 35 | 36 | 37 | /**************************************************************************************************** 38 | * INTERRUPT LINES/EXCEPTIONS 39 | ***************************************************************************************************/ 40 | enum 41 | { 42 | ARM7_IRQ_LINE=0, ARM7_FIRQ_LINE, 43 | ARM7_ABORT_EXCEPTION, ARM7_ABORT_PREFETCH_EXCEPTION, ARM7_UNDEFINE_EXCEPTION, 44 | ARM7_NUM_LINES 45 | }; 46 | // Really there's only 1 ABORT Line.. and cpu decides whether it's during data fetch or prefetch, but we let the user specify 47 | 48 | /**************************************************************************************************** 49 | * ARM7 CORE REGISTERS 50 | ***************************************************************************************************/ 51 | enum 52 | { 53 | ARM7_PC = 0, 54 | ARM7_R0, ARM7_R1, ARM7_R2, ARM7_R3, ARM7_R4, ARM7_R5, ARM7_R6, ARM7_R7, 55 | ARM7_R8, ARM7_R9, ARM7_R10, ARM7_R11, ARM7_R12, ARM7_R13, ARM7_R14, ARM7_R15, 56 | ARM7_FR8, ARM7_FR9, ARM7_FR10, ARM7_FR11, ARM7_FR12, ARM7_FR13, ARM7_FR14, 57 | ARM7_IR13, ARM7_IR14, ARM7_SR13, ARM7_SR14, ARM7_FSPSR, ARM7_ISPSR, ARM7_SSPSR, 58 | ARM7_CPSR, ARM7_AR13, ARM7_AR14, ARM7_ASPSR, ARM7_UR13, ARM7_UR14, ARM7_USPSR 59 | }; 60 | 61 | /* There are 36 Unique - 32 bit processor registers */ 62 | /* Each mode has 17 registers (except user & system, which have 16) */ 63 | /* This is a list of each *unique* register */ 64 | enum 65 | { 66 | /* All modes have the following */ 67 | eR0 = 0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, 68 | eR8, eR9, eR10, eR11, eR12, 69 | eR13, /* Stack Pointer */ 70 | eR14, /* Link Register (holds return address) */ 71 | eR15, /* Program Counter */ 72 | eCPSR, /* Current Status Program Register */ 73 | 74 | /* Fast Interrupt - Bank switched registers */ 75 | eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ, eR13_FIQ, eR14_FIQ, eSPSR_FIQ, 76 | 77 | /* IRQ - Bank switched registers */ 78 | eR13_IRQ, eR14_IRQ, eSPSR_IRQ, 79 | 80 | /* Supervisor/Service Mode - Bank switched registers */ 81 | eR13_SVC, eR14_SVC, eSPSR_SVC, 82 | 83 | /* Abort Mode - Bank switched registers */ 84 | eR13_ABT, eR14_ABT, eSPSR_ABT, 85 | 86 | /* Undefined Mode - Bank switched registers */ 87 | eR13_UND, eR14_UND, eSPSR_UND, 88 | 89 | kNumRegisters 90 | }; 91 | 92 | /* Coprocessor-related macros */ 93 | #define COPRO_TLB_BASE cpustate->tlbBase 94 | #define COPRO_TLB_BASE_MASK 0xffffc000 95 | #define COPRO_TLB_VADDR_FLTI_MASK 0xfff00000 96 | #define COPRO_TLB_VADDR_FLTI_MASK_SHIFT 18 97 | #define COPRO_TLB_VADDR_CSLTI_MASK 0x000ff000 98 | #define COPRO_TLB_VADDR_CSLTI_MASK_SHIFT 10 99 | #define COPRO_TLB_VADDR_FSLTI_MASK 0x000ffc00 100 | #define COPRO_TLB_VADDR_FSLTI_MASK_SHIFT 8 101 | #define COPRO_TLB_CFLD_ADDR_MASK 0xfffffc00 102 | #define COPRO_TLB_CFLD_ADDR_MASK_SHIFT 10 103 | #define COPRO_TLB_SECTION_PAGE_MASK 0xfff00000 104 | #define COPRO_TLB_LARGE_PAGE_MASK 0xffff0000 105 | #define COPRO_TLB_SMALL_PAGE_MASK 0xfffff000 106 | #define COPRO_TLB_TINY_PAGE_MASK 0xfffffc00 107 | #define COPRO_TLB_UNMAPPED 0 108 | #define COPRO_TLB_LARGE_PAGE 1 109 | #define COPRO_TLB_SMALL_PAGE 2 110 | #define COPRO_TLB_TINY_PAGE 3 111 | #define COPRO_TLB_COARSE_TABLE 1 112 | #define COPRO_TLB_SECTION_TABLE 2 113 | #define COPRO_TLB_FINE_TABLE 3 114 | 115 | #define COPRO_CTRL cpustate->control 116 | #define COPRO_CTRL_MMU_EN 0x00000001 117 | #define COPRO_CTRL_ADDRFAULT_EN 0x00000002 118 | #define COPRO_CTRL_DCACHE_EN 0x00000004 119 | #define COPRO_CTRL_WRITEBUF_EN 0x00000008 120 | #define COPRO_CTRL_ENDIAN 0x00000080 121 | #define COPRO_CTRL_SYSTEM 0x00000100 122 | #define COPRO_CTRL_ROM 0x00000200 123 | #define COPRO_CTRL_ICACHE_EN 0x00001000 124 | #define COPRO_CTRL_INTVEC_ADJUST 0x00002000 125 | #define COPRO_CTRL_ADDRFAULT_EN_SHIFT 1 126 | #define COPRO_CTRL_DCACHE_EN_SHIFT 2 127 | #define COPRO_CTRL_WRITEBUF_EN_SHIFT 3 128 | #define COPRO_CTRL_ENDIAN_SHIFT 7 129 | #define COPRO_CTRL_SYSTEM_SHIFT 8 130 | #define COPRO_CTRL_ROM_SHIFT 9 131 | #define COPRO_CTRL_ICACHE_EN_SHIFT 12 132 | #define COPRO_CTRL_INTVEC_ADJUST_SHIFT 13 133 | #define COPRO_CTRL_LITTLE_ENDIAN 0 134 | #define COPRO_CTRL_BIG_ENDIAN 1 135 | #define COPRO_CTRL_INTVEC_0 0 136 | #define COPRO_CTRL_INTVEC_F 1 137 | #define COPRO_CTRL_MASK 0x0000338f 138 | 139 | /* Coprocessor Registers */ 140 | #define ARM7COPRO_REGS \ 141 | UINT32 control; \ 142 | UINT32 tlbBase; 143 | 144 | enum 145 | { 146 | eARM_ARCHFLAGS_T = 1, // Thumb present 147 | eARM_ARCHFLAGS_E = 2, // extended DSP operations present (only for v5+) 148 | eARM_ARCHFLAGS_J = 4, // "Jazelle" (direct execution of Java bytecode) 149 | eARM_ARCHFLAGS_MMU = 8, // has on-board MMU (traditional ARM style like the SA1110) 150 | eARM_ARCHFLAGS_SA = 16, // StrongARM extensions (enhanced TLB) 151 | eARM_ARCHFLAGS_XSCALE = 32, // XScale extensions (CP14, enhanced TLB) 152 | }; 153 | 154 | #define ARM7CORE_REGS \ 155 | UINT32 sArmRegister[kNumRegisters]; \ 156 | UINT8 pendingIrq; \ 157 | UINT8 pendingFiq; \ 158 | UINT8 pendingAbtD; \ 159 | UINT8 pendingAbtP; \ 160 | UINT8 pendingUnd; \ 161 | UINT8 pendingSwi; \ 162 | INT32 iCount; \ 163 | endianness_t endian; \ 164 | device_irq_callback irq_callback; \ 165 | legacy_cpu_device *device; \ 166 | address_space *program; \ 167 | direct_read_data *direct; 168 | 169 | 170 | /* CPU state struct */ 171 | typedef struct 172 | { 173 | ARM7CORE_REGS // these must be included in your cpu specific register implementation 174 | ARM7COPRO_REGS 175 | 176 | UINT8 archRev; // ARM architecture revision (3, 4, and 5 are valid) 177 | UINT8 archFlags; // architecture flags 178 | 179 | } arm_state; 180 | 181 | /**************************************************************************************************** 182 | * VARIOUS INTERNAL STRUCS/DEFINES/ETC.. 183 | ***************************************************************************************************/ 184 | // Mode values come from bit 4-0 of CPSR, but we are ignoring bit 4 here, since bit 4 always = 1 for valid modes 185 | enum 186 | { 187 | eARM7_MODE_USER = 0x0, // Bit: 4-0 = 10000 188 | eARM7_MODE_FIQ = 0x1, // Bit: 4-0 = 10001 189 | eARM7_MODE_IRQ = 0x2, // Bit: 4-0 = 10010 190 | eARM7_MODE_SVC = 0x3, // Bit: 4-0 = 10011 191 | eARM7_MODE_ABT = 0x7, // Bit: 4-0 = 10111 192 | eARM7_MODE_UND = 0xb, // Bit: 4-0 = 11011 193 | eARM7_MODE_SYS = 0xf // Bit: 4-0 = 11111 194 | }; 195 | 196 | #define ARM7_NUM_MODES 0x10 197 | 198 | static const int thumbCycles[256] = 199 | { 200 | // 0 1 2 3 4 5 6 7 8 9 a b c d e f 201 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 202 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 203 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 204 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 205 | 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 4 206 | 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 5 207 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 6 208 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 7 209 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 8 210 | 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 9 211 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // a 212 | 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 4, 1, 1, // b 213 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c 214 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, // d 215 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // e 216 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // f 217 | }; 218 | 219 | /* 17 processor registers are visible at any given time, 220 | * banked depending on processor mode. 221 | */ 222 | 223 | static const int sRegisterTable[ARM7_NUM_MODES][18] = 224 | { 225 | { /* USR */ 226 | eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, 227 | eR8, eR9, eR10, eR11, eR12, 228 | eR13, eR14, 229 | eR15, eCPSR // No SPSR in this mode 230 | }, 231 | { /* FIQ */ 232 | eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, 233 | eR8_FIQ, eR9_FIQ, eR10_FIQ, eR11_FIQ, eR12_FIQ, 234 | eR13_FIQ, eR14_FIQ, 235 | eR15, eCPSR, eSPSR_FIQ 236 | }, 237 | { /* IRQ */ 238 | eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, 239 | eR8, eR9, eR10, eR11, eR12, 240 | eR13_IRQ, eR14_IRQ, 241 | eR15, eCPSR, eSPSR_IRQ 242 | }, 243 | { /* SVC */ 244 | eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, 245 | eR8, eR9, eR10, eR11, eR12, 246 | eR13_SVC, eR14_SVC, 247 | eR15, eCPSR, eSPSR_SVC 248 | }, 249 | {0}, {0}, {0}, // values for modes 4,5,6 are not valid 250 | { /* ABT */ 251 | eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, 252 | eR8, eR9, eR10, eR11, eR12, 253 | eR13_ABT, eR14_ABT, 254 | eR15, eCPSR, eSPSR_ABT 255 | }, 256 | {0}, {0}, {0}, // values for modes 8,9,a are not valid! 257 | { /* UND */ 258 | eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, 259 | eR8, eR9, eR10, eR11, eR12, 260 | eR13_UND, eR14_UND, 261 | eR15, eCPSR, eSPSR_UND 262 | }, 263 | {0}, {0}, {0}, // values for modes c,d, e are not valid! 264 | { /* SYS */ 265 | eR0, eR1, eR2, eR3, eR4, eR5, eR6, eR7, 266 | eR8, eR9, eR10, eR11, eR12, 267 | eR13, eR14, 268 | eR15, eCPSR // No SPSR in this mode 269 | } 270 | }; 271 | 272 | #define N_BIT 31 273 | #define Z_BIT 30 274 | #define C_BIT 29 275 | #define V_BIT 28 276 | #define Q_BIT 27 277 | #define I_BIT 7 278 | #define F_BIT 6 279 | #define T_BIT 5 // Thumb mode 280 | 281 | #define N_MASK ((UINT32)(1 << N_BIT)) /* Negative flag */ 282 | #define Z_MASK ((UINT32)(1 << Z_BIT)) /* Zero flag */ 283 | #define C_MASK ((UINT32)(1 << C_BIT)) /* Carry flag */ 284 | #define V_MASK ((UINT32)(1 << V_BIT)) /* oVerflow flag */ 285 | #define Q_MASK ((UINT32)(1 << Q_BIT)) /* signed overflow for QADD, MAC */ 286 | #define I_MASK ((UINT32)(1 << I_BIT)) /* Interrupt request disable */ 287 | #define F_MASK ((UINT32)(1 << F_BIT)) /* Fast interrupt request disable */ 288 | #define T_MASK ((UINT32)(1 << T_BIT)) /* Thumb Mode flag */ 289 | 290 | #define N_IS_SET(pc) ((pc) & N_MASK) 291 | #define Z_IS_SET(pc) ((pc) & Z_MASK) 292 | #define C_IS_SET(pc) ((pc) & C_MASK) 293 | #define V_IS_SET(pc) ((pc) & V_MASK) 294 | #define Q_IS_SET(pc) ((pc) & Q_MASK) 295 | #define I_IS_SET(pc) ((pc) & I_MASK) 296 | #define F_IS_SET(pc) ((pc) & F_MASK) 297 | #define T_IS_SET(pc) ((pc) & T_MASK) 298 | 299 | #define N_IS_CLEAR(pc) (!N_IS_SET(pc)) 300 | #define Z_IS_CLEAR(pc) (!Z_IS_SET(pc)) 301 | #define C_IS_CLEAR(pc) (!C_IS_SET(pc)) 302 | #define V_IS_CLEAR(pc) (!V_IS_SET(pc)) 303 | #define Q_IS_CLEAR(pc) (!Q_IS_SET(pc)) 304 | #define I_IS_CLEAR(pc) (!I_IS_SET(pc)) 305 | #define F_IS_CLEAR(pc) (!F_IS_SET(pc)) 306 | #define T_IS_CLEAR(pc) (!T_IS_SET(pc)) 307 | 308 | /* Deconstructing an instruction */ 309 | // todo: use these in all places (including dasm file) 310 | #define INSN_COND ((UINT32)0xf0000000u) 311 | #define INSN_SDT_L ((UINT32)0x00100000u) 312 | #define INSN_SDT_W ((UINT32)0x00200000u) 313 | #define INSN_SDT_B ((UINT32)0x00400000u) 314 | #define INSN_SDT_U ((UINT32)0x00800000u) 315 | #define INSN_SDT_P ((UINT32)0x01000000u) 316 | #define INSN_BDT_L ((UINT32)0x00100000u) 317 | #define INSN_BDT_W ((UINT32)0x00200000u) 318 | #define INSN_BDT_S ((UINT32)0x00400000u) 319 | #define INSN_BDT_U ((UINT32)0x00800000u) 320 | #define INSN_BDT_P ((UINT32)0x01000000u) 321 | #define INSN_BDT_REGS ((UINT32)0x0000ffffu) 322 | #define INSN_SDT_IMM ((UINT32)0x00000fffu) 323 | #define INSN_MUL_A ((UINT32)0x00200000u) 324 | #define INSN_MUL_RM ((UINT32)0x0000000fu) 325 | #define INSN_MUL_RS ((UINT32)0x00000f00u) 326 | #define INSN_MUL_RN ((UINT32)0x0000f000u) 327 | #define INSN_MUL_RD ((UINT32)0x000f0000u) 328 | #define INSN_I ((UINT32)0x02000000u) 329 | #define INSN_OPCODE ((UINT32)0x01e00000u) 330 | #define INSN_S ((UINT32)0x00100000u) 331 | #define INSN_BL ((UINT32)0x01000000u) 332 | #define INSN_BRANCH ((UINT32)0x00ffffffu) 333 | #define INSN_SWI ((UINT32)0x00ffffffu) 334 | #define INSN_RN ((UINT32)0x000f0000u) 335 | #define INSN_RD ((UINT32)0x0000f000u) 336 | #define INSN_OP2 ((UINT32)0x00000fffu) 337 | #define INSN_OP2_SHIFT ((UINT32)0x00000f80u) 338 | #define INSN_OP2_SHIFT_TYPE ((UINT32)0x00000070u) 339 | #define INSN_OP2_RM ((UINT32)0x0000000fu) 340 | #define INSN_OP2_ROTATE ((UINT32)0x00000f00u) 341 | #define INSN_OP2_IMM ((UINT32)0x000000ffu) 342 | #define INSN_OP2_SHIFT_TYPE_SHIFT 4 343 | #define INSN_OP2_SHIFT_SHIFT 7 344 | #define INSN_OP2_ROTATE_SHIFT 8 345 | #define INSN_MUL_RS_SHIFT 8 346 | #define INSN_MUL_RN_SHIFT 12 347 | #define INSN_MUL_RD_SHIFT 16 348 | #define INSN_OPCODE_SHIFT 21 349 | #define INSN_RN_SHIFT 16 350 | #define INSN_RD_SHIFT 12 351 | #define INSN_COND_SHIFT 28 352 | 353 | #define INSN_COPRO_N ((UINT32) 0x00100000u) 354 | #define INSN_COPRO_CREG ((UINT32) 0x000f0000u) 355 | #define INSN_COPRO_AREG ((UINT32) 0x0000f000u) 356 | #define INSN_COPRO_CPNUM ((UINT32) 0x00000f00u) 357 | #define INSN_COPRO_OP2 ((UINT32) 0x000000e0u) 358 | #define INSN_COPRO_OP3 ((UINT32) 0x0000000fu) 359 | #define INSN_COPRO_N_SHIFT 20 360 | #define INSN_COPRO_CREG_SHIFT 16 361 | #define INSN_COPRO_AREG_SHIFT 12 362 | #define INSN_COPRO_CPNUM_SHIFT 8 363 | #define INSN_COPRO_OP2_SHIFT 5 364 | 365 | #define THUMB_INSN_TYPE ((UINT16)0xf000) 366 | #define THUMB_COND_TYPE ((UINT16)0x0f00) 367 | #define THUMB_GROUP4_TYPE ((UINT16)0x0c00) 368 | #define THUMB_GROUP5_TYPE ((UINT16)0x0e00) 369 | #define THUMB_GROUP5_RM ((UINT16)0x01c0) 370 | #define THUMB_GROUP5_RN ((UINT16)0x0038) 371 | #define THUMB_GROUP5_RD ((UINT16)0x0007) 372 | #define THUMB_ADDSUB_RNIMM ((UINT16)0x01c0) 373 | #define THUMB_ADDSUB_RS ((UINT16)0x0038) 374 | #define THUMB_ADDSUB_RD ((UINT16)0x0007) 375 | #define THUMB_INSN_ADDSUB ((UINT16)0x0800) 376 | #define THUMB_INSN_CMP ((UINT16)0x0800) 377 | #define THUMB_INSN_SUB ((UINT16)0x0800) 378 | #define THUMB_INSN_IMM_RD ((UINT16)0x0700) 379 | #define THUMB_INSN_IMM_S ((UINT16)0x0080) 380 | #define THUMB_INSN_IMM ((UINT16)0x00ff) 381 | #define THUMB_ADDSUB_TYPE ((UINT16)0x0600) 382 | #define THUMB_HIREG_OP ((UINT16)0x0300) 383 | #define THUMB_HIREG_H ((UINT16)0x00c0) 384 | #define THUMB_HIREG_RS ((UINT16)0x0038) 385 | #define THUMB_HIREG_RD ((UINT16)0x0007) 386 | #define THUMB_STACKOP_TYPE ((UINT16)0x0f00) 387 | #define THUMB_STACKOP_L ((UINT16)0x0800) 388 | #define THUMB_STACKOP_RD ((UINT16)0x0700) 389 | #define THUMB_ALUOP_TYPE ((UINT16)0x03c0) 390 | #define THUMB_BLOP_LO ((UINT16)0x0800) 391 | #define THUMB_BLOP_OFFS ((UINT16)0x07ff) 392 | #define THUMB_SHIFT_R ((UINT16)0x0800) 393 | #define THUMB_SHIFT_AMT ((UINT16)0x07c0) 394 | #define THUMB_HALFOP_L ((UINT16)0x0800) 395 | #define THUMB_HALFOP_OFFS ((UINT16)0x07c0) 396 | #define THUMB_BRANCH_OFFS ((UINT16)0x07ff) 397 | #define THUMB_LSOP_L ((UINT16)0x0800) 398 | #define THUMB_LSOP_OFFS ((UINT16)0x07c0) 399 | #define THUMB_MULTLS ((UINT16)0x0800) 400 | #define THUMB_MULTLS_BASE ((UINT16)0x0700) 401 | #define THUMB_RELADDR_SP ((UINT16)0x0800) 402 | #define THUMB_RELADDR_RD ((UINT16)0x0700) 403 | #define THUMB_INSN_TYPE_SHIFT 12 404 | #define THUMB_COND_TYPE_SHIFT 8 405 | #define THUMB_GROUP4_TYPE_SHIFT 10 406 | #define THUMB_GROUP5_TYPE_SHIFT 9 407 | #define THUMB_ADDSUB_TYPE_SHIFT 9 408 | #define THUMB_INSN_IMM_RD_SHIFT 8 409 | #define THUMB_STACKOP_TYPE_SHIFT 8 410 | #define THUMB_HIREG_OP_SHIFT 8 411 | #define THUMB_STACKOP_RD_SHIFT 8 412 | #define THUMB_MULTLS_BASE_SHIFT 8 413 | #define THUMB_RELADDR_RD_SHIFT 8 414 | #define THUMB_HIREG_H_SHIFT 6 415 | #define THUMB_HIREG_RS_SHIFT 3 416 | #define THUMB_ALUOP_TYPE_SHIFT 6 417 | #define THUMB_SHIFT_AMT_SHIFT 6 418 | #define THUMB_HALFOP_OFFS_SHIFT 6 419 | #define THUMB_LSOP_OFFS_SHIFT 6 420 | #define THUMB_GROUP5_RM_SHIFT 6 421 | #define THUMB_GROUP5_RN_SHIFT 3 422 | #define THUMB_GROUP5_RD_SHIFT 0 423 | #define THUMB_ADDSUB_RNIMM_SHIFT 6 424 | #define THUMB_ADDSUB_RS_SHIFT 3 425 | #define THUMB_ADDSUB_RD_SHIFT 0 426 | 427 | enum 428 | { 429 | OPCODE_AND, /* 0000 */ 430 | OPCODE_EOR, /* 0001 */ 431 | OPCODE_SUB, /* 0010 */ 432 | OPCODE_RSB, /* 0011 */ 433 | OPCODE_ADD, /* 0100 */ 434 | OPCODE_ADC, /* 0101 */ 435 | OPCODE_SBC, /* 0110 */ 436 | OPCODE_RSC, /* 0111 */ 437 | OPCODE_TST, /* 1000 */ 438 | OPCODE_TEQ, /* 1001 */ 439 | OPCODE_CMP, /* 1010 */ 440 | OPCODE_CMN, /* 1011 */ 441 | OPCODE_ORR, /* 1100 */ 442 | OPCODE_MOV, /* 1101 */ 443 | OPCODE_BIC, /* 1110 */ 444 | OPCODE_MVN /* 1111 */ 445 | }; 446 | 447 | enum 448 | { 449 | COND_EQ = 0, /* Z equal */ 450 | COND_NE, /* ~Z not equal */ 451 | COND_CS, COND_HS = 2, /* C unsigned higher or same */ 452 | COND_CC, COND_LO = 3, /* ~C unsigned lower */ 453 | COND_MI, /* N negative */ 454 | COND_PL, /* ~N positive or zero */ 455 | COND_VS, /* V overflow */ 456 | COND_VC, /* ~V no overflow */ 457 | COND_HI, /* C && ~Z unsigned higher */ 458 | COND_LS, /* ~C || Z unsigned lower or same */ 459 | COND_GE, /* N == V greater or equal */ 460 | COND_LT, /* N != V less than */ 461 | COND_GT, /* ~Z && N == V greater than */ 462 | COND_LE, /* Z || N != V less than or equal */ 463 | COND_AL, /* 1 always */ 464 | COND_NV /* 0 never */ 465 | }; 466 | 467 | #define LSL(v, s) ((v) << (s)) 468 | #define LSR(v, s) ((v) >> (s)) 469 | #define ROL(v, s) (LSL((v), (s)) | (LSR((v), 32u - (s)))) 470 | #define ROR(v, s) (LSR((v), (s)) | (LSL((v), 32u - (s)))) 471 | 472 | /* Convenience Macros */ 473 | #define R15 ARM7REG(eR15) 474 | #define SPSR 17 // SPSR is always the 18th register in our 0 based array sRegisterTable[][18] 475 | #define GET_CPSR ARM7REG(eCPSR) 476 | #define SET_CPSR(v) (GET_CPSR = (v)) 477 | #define MODE_FLAG 0xF // Mode bits are 4:0 of CPSR, but we ignore bit 4. 478 | #define GET_MODE (GET_CPSR & MODE_FLAG) 479 | #define SIGN_BIT ((UINT32)(1 << 31)) 480 | #define SIGN_BITS_DIFFER(a, b) (((a) ^ (b)) >> 31) 481 | /* I really don't know why these were set to 16-bit, the thumb registers are still 32-bit ... */ 482 | #define THUMB_SIGN_BIT ((UINT32)(1 << 31)) 483 | #define THUMB_SIGN_BITS_DIFFER(a, b) (((a)^(b)) >> 31) 484 | 485 | /* At one point I thought these needed to be cpu implementation specific, but they don't.. */ 486 | #define GET_REGISTER(state, reg) GetRegister(state, reg) 487 | #define SET_REGISTER(state, reg, val) SetRegister(state, reg, val) 488 | #define ARM7_CHECKIRQ arm7_check_irq_state(cpustate) 489 | 490 | extern write32_device_func arm7_coproc_do_callback; 491 | extern read32_device_func arm7_coproc_rt_r_callback; 492 | extern write32_device_func arm7_coproc_rt_w_callback; 493 | extern void arm7_dt_r_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, UINT32 (*read32)(arm_state *cpustate, UINT32 addr)); 494 | extern void arm7_dt_w_callback(arm_state *cpustate, UINT32 insn, UINT32 *prn, void (*write32)(arm_state *cpustate, UINT32 addr, UINT32 data)); 495 | 496 | #ifdef UNUSED_DEFINITION 497 | extern char *(*arm7_dasm_cop_dt_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0); 498 | extern char *(*arm7_dasm_cop_rt_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0); 499 | extern char *(*arm7_dasm_cop_do_callback)(arm_state *cpustate, char *pBuf, UINT32 opcode, char *pConditionCode, char *pBuf0); 500 | #endif 501 | 502 | #endif /* __ARM7CORE_H__ */ 503 | -------------------------------------------------------------------------------- /arm7dasm.c: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | * 3 | * arm7dasm.c 4 | * Portable ARM7TDMI Core Emulator - Disassembler 5 | * 6 | * Copyright Steve Ellenoff, all rights reserved. 7 | * 8 | * - This source code is released as freeware for non-commercial purposes. 9 | * - You are free to use and redistribute this code in modified or 10 | * unmodified form, provided you list me in the credits. 11 | * - If you modify this source code, you must add a notice to each modified 12 | * source file that it has been changed. If you're a nice person, you 13 | * will clearly mark each change too. :) 14 | * - If you wish to use this for commercial purposes, please contact me at 15 | * sellenoff@hotmail.com 16 | * - The author of this copywritten work reserves the right to change the 17 | * terms of its usage and license at any time, including retroactively 18 | * - This entire notice must remain in the source code. 19 | * 20 | * This work is based on: 21 | * #1) 'Atmel Corporation ARM7TDMI (Thumb) Datasheet - January 1999' 22 | * #2) Arm 2/3/6 emulator By Bryan McPhail (bmcphail@tendril.co.uk) and Phil Stroffolino (MAME CORE 0.76) 23 | * 24 | *****************************************************************************/ 25 | /****************************************************************************** 26 | * Notes: 27 | * 28 | * Because Co-Processor functions are highly specialized to the actual co-proc 29 | * implementation being used, I've setup callback handlers to allow for custom 30 | * dasm display of the co-proc functions so that the implementation specific 31 | * commands/interpretation can be used. If not used, the default handlers which 32 | * implement the ARM7TDMI guideline format is used 33 | ******************************************************************************/ 34 | 35 | #include "emu.h" 36 | #include "arm7core.h" 37 | 38 | static char *get_reg_name(int n) 39 | { 40 | static char buf[16][4]; 41 | static int i; 42 | 43 | n &= 15; 44 | i &= 15; 45 | 46 | switch (n) 47 | { 48 | case 13: 49 | return "SP"; 50 | case 14: 51 | return "LR"; 52 | case 15: 53 | return "PC"; 54 | } 55 | 56 | sprintf(buf[i], "R%d", n); 57 | 58 | return buf[i++]; 59 | } 60 | 61 | static char *WritePadding( char *pBuf, const char *pBuf0 ) 62 | { 63 | pBuf0 += 8; 64 | while( pBuf>8)&0xf, (opcode>>21)&7, get_reg_name((opcode>>12)&0xf), (opcode>>16)&0xf, opcode&0xf ); 87 | if((opcode>>5)&7) pBuf += sprintf( pBuf, ", %d",(opcode>>5)&7); 88 | return pBuf; 89 | } 90 | 91 | static char *DasmCoProc_DT( char *pBuf, UINT32 opcode, const char *pConditionCode, const char *pBuf0 ) 92 | { 93 | /* co processor data transfer */ 94 | /* xxxx 111P UNWL nnnn dddd pppp oooooooo */ 95 | //todo: test this on valid instructions 96 | 97 | pBuf += sprintf(pBuf, "%s%s",(opcode&0x00100000)?"LDC":"STC",pConditionCode); //Bit 20 = 1 for Load, 0 for Store 98 | //Long Operation 99 | if(opcode & 0x400000) pBuf += sprintf(pBuf, "L"); 100 | pBuf = WritePadding( pBuf, pBuf0 ); 101 | 102 | //P# & CD # 103 | pBuf += sprintf(pBuf, "p%d, c%d, ",(opcode>>8)&0x0f,(opcode>>12)&0x0f); 104 | 105 | //Base Register (Rn) 106 | pBuf += sprintf(pBuf, "[%s%s",get_reg_name((opcode>>16)&0x0f),(opcode&0x1000000)?"":"]"); //If Bit 24 = 1, Pre-increment, otherwise, Post increment so close brace 107 | 108 | //immediate value ( 8 bit value is << 2 according to manual ) 109 | if(opcode & 0xff) pBuf += sprintf(pBuf, ",%s#$%x",(opcode&0x800000)?"":"-",(opcode & 0xff)<<2); 110 | 111 | //Pre-Inc brace & Write back 112 | pBuf += sprintf(pBuf, "%s%s",(opcode&0x1000000)?"]":"",(opcode&0x200000)?"{!}":""); 113 | return pBuf; 114 | } 115 | 116 | static char *DasmCoProc_DO( char *pBuf, UINT32 opcode, const char *pConditionCode, const char *pBuf0 ) 117 | { 118 | /* co processor data operation */ 119 | /* xxxx 1110 oooo nnnn dddd cccc ppp0 mmmm */ 120 | pBuf += sprintf( pBuf, "CDP" ); 121 | pBuf += sprintf( pBuf, "%s", pConditionCode ); 122 | pBuf = WritePadding( pBuf, pBuf0 ); 123 | //p#,CPOpc,cd,cn,cm 124 | pBuf += sprintf( pBuf, "p%d, %d, c%d, c%d, c%d", 125 | (opcode>>8)&0xf, (opcode>>20)&0xf, (opcode>>12)&0xf, (opcode>>16)&0xf, opcode&0xf ); 126 | if((opcode>>5)&7) pBuf += sprintf( pBuf, ", %d",(opcode>>5)&7); 127 | return pBuf; 128 | } 129 | 130 | static char *WriteImmediateOperand( char *pBuf, UINT32 opcode ) 131 | { 132 | /* rrrrbbbbbbbb */ 133 | UINT32 imm; 134 | int r; 135 | 136 | imm = opcode&0xff; 137 | r = ((opcode>>8)&0xf)*2; 138 | imm = (imm>>r)|(imm<<(32-r)); 139 | pBuf += sprintf( pBuf, ", #$%x", imm ); 140 | return pBuf; 141 | } 142 | 143 | static char *WriteDataProcessingOperand( char *pBuf, UINT32 opcode, int printOp0, int printOp1, int printOp2 ) 144 | { 145 | /* ccccctttmmmm */ 146 | static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; 147 | 148 | if (printOp0) 149 | pBuf += sprintf(pBuf,"%s, ", get_reg_name((opcode>>12)&0xf)); 150 | if (printOp1) 151 | pBuf += sprintf(pBuf,"%s, ", get_reg_name((opcode>>16)&0xf)); 152 | 153 | /* Immediate Op2 */ 154 | if( opcode&0x02000000 ) 155 | return WriteImmediateOperand(pBuf-2,opcode); 156 | 157 | /* Register Op2 */ 158 | if (printOp2) 159 | //SJE: pBuf += sprintf(pBuf,"%s, ", get_reg_name((opcode>>0)&0xf)); 160 | pBuf += sprintf(pBuf,"%s ", get_reg_name((opcode>>0)&0xf)); 161 | 162 | /* Immediate Op2 */ 163 | 164 | //SJE: ignore if LSL#0 for register shift 165 | if( ((opcode&0x2000000) == 0) && (((opcode>>4) & 0xff)==0) ) 166 | return pBuf; 167 | 168 | pBuf += sprintf(pBuf, ",%s ", pRegOp[(opcode>>5)&3] ); 169 | //SJE: pBuf += sprintf(pBuf, "%s ", pRegOp[(opcode>>5)&3] ); 170 | 171 | if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ 172 | { 173 | pBuf += sprintf( pBuf, "%s", get_reg_name((opcode>>8)&0xf)); 174 | } 175 | else /* Shift amount immediate 5 bit unsigned integer */ 176 | { 177 | int c=(opcode>>7)&0x1f; 178 | if( c==0 ) c = 32; 179 | pBuf += sprintf( pBuf, "#%d", c ); 180 | } 181 | return pBuf; 182 | } 183 | 184 | static char *WriteRegisterOperand1( char *pBuf, UINT32 opcode ) 185 | { 186 | /* ccccctttmmmm */ 187 | static const char *const pRegOp[4] = { "LSL","LSR","ASR","ROR" }; 188 | 189 | pBuf += sprintf( 190 | pBuf, 191 | ", %s", /* Operand 1 register, Operand 2 register, shift type */ 192 | get_reg_name((opcode>> 0)&0xf)); 193 | 194 | //check for LSL 0 195 | if( (((opcode>>5)&3)==0) && (((opcode>>7)&0xf)==0) ) 196 | return pBuf; 197 | else 198 | //Add rotation type 199 | pBuf += sprintf(pBuf," %s ",pRegOp[(opcode>>5)&3]); 200 | 201 | if( opcode&0x10 ) /* Shift amount specified in bottom bits of RS */ 202 | { 203 | pBuf += sprintf( pBuf, "%s", get_reg_name((opcode>>7)&0xf)); 204 | } 205 | else /* Shift amount immediate 5 bit unsigned integer */ 206 | { 207 | int c=(opcode>>7)&0x1f; 208 | if( c==0 ) c = 32; 209 | pBuf += sprintf( pBuf, "#%d", c ); 210 | } 211 | return pBuf; 212 | } /* WriteRegisterOperand */ 213 | 214 | 215 | static char *WriteBranchAddress( char *pBuf, UINT32 pc, UINT32 opcode ) 216 | { 217 | opcode &= 0x00ffffff; 218 | if( opcode&0x00800000 ) 219 | { 220 | opcode |= 0xff000000; /* sign-extend */ 221 | } 222 | register_coderef(pc, pc + 8 + 4 * opcode); 223 | pc += 8+4*opcode; 224 | strcpy(pBuf, get_symbol_name(pc)); 225 | return pBuf; 226 | } /* WriteBranchAddress */ 227 | 228 | static UINT32 arm7_disasm( char *pBuf, UINT32 pc, UINT32 opcode ) 229 | { 230 | const char *pBuf0; 231 | 232 | static const char *const pConditionCodeTable[16] = 233 | { 234 | "EQ","NE","CS","CC", 235 | "MI","PL","VS","VC", 236 | "HI","LS","GE","LT", 237 | "GT","LE","","NV" 238 | }; 239 | static const char *const pOperation[16] = 240 | { 241 | "AND","EOR","SUB","RSB", 242 | "ADD","ADC","SBC","RSC", 243 | "TST","TEQ","CMP","CMN", 244 | "ORR","MOV","BIC","MVN" 245 | }; 246 | const char *pConditionCode; 247 | UINT32 dasmflags = 0; 248 | 249 | pConditionCode= pConditionCodeTable[opcode>>28]; 250 | pBuf0 = pBuf; 251 | 252 | if( (opcode&0x0fffffd0)==0x012fff10 ) { //bits 27-4 == 0001001011111111111100x1 253 | /* Branch and Exchange (BX,BLX) */ 254 | if (opcode & 0x00000020) { 255 | pBuf += sprintf( pBuf, "BL"); 256 | dasmflags = DASMFLAG_STEP_OUT; 257 | } 258 | else { 259 | pBuf += sprintf( pBuf, "B"); 260 | } 261 | pBuf += sprintf( pBuf, "%sX", pConditionCode ); 262 | pBuf = WritePadding( pBuf, pBuf0 ); 263 | pBuf += sprintf( pBuf, "%s",get_reg_name((opcode&0xf))); 264 | if ((opcode & 0x0f) == 14) 265 | dasmflags = DASMFLAG_STEP_OUT; 266 | } 267 | else if ((opcode & 0x0ff000f0) == 0x01600010) // CLZ - v5 268 | { 269 | pBuf += sprintf(pBuf, "CLZ"); 270 | pBuf = WritePadding( pBuf, pBuf0 ); 271 | pBuf += sprintf(pBuf, "%s, %s", get_reg_name((opcode>>12)&0xf), get_reg_name(opcode&0xf)); 272 | } 273 | else if ((opcode & 0x0ff000f0) == 0x01000050) // QADD - v5 274 | { 275 | pBuf += sprintf(pBuf, "QADD"); 276 | pBuf = WritePadding( pBuf, pBuf0 ); 277 | pBuf += sprintf(pBuf, "%s, %s, %s", get_reg_name((opcode>>12)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>16)&0xf)); 278 | } 279 | else if ((opcode & 0x0ff000f0) == 0x01400050) // QDADD - v5 280 | { 281 | pBuf += sprintf(pBuf, "QDADD"); 282 | pBuf = WritePadding( pBuf, pBuf0 ); 283 | pBuf += sprintf(pBuf, "%s, %s, %s", get_reg_name((opcode>>12)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>16)&0xf)); 284 | } 285 | else if ((opcode & 0x0ff000f0) == 0x01200050) // QSUB - v5 286 | { 287 | pBuf += sprintf(pBuf, "QSUB"); 288 | pBuf = WritePadding( pBuf, pBuf0 ); 289 | pBuf += sprintf(pBuf, "%s, %s, %s", get_reg_name((opcode>>12)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>16)&0xf)); 290 | } 291 | else if ((opcode & 0x0ff000f0) == 0x01600050) // QDSUB - v5 292 | { 293 | pBuf += sprintf(pBuf, "QDSUB"); 294 | pBuf = WritePadding( pBuf, pBuf0 ); 295 | pBuf += sprintf(pBuf, "%s, %s, %s", get_reg_name((opcode>>12)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>16)&0xf)); 296 | } 297 | else if ((opcode & 0x0ff00090) == 0x01000080) // SMLAxy - v5 298 | { 299 | pBuf += sprintf(pBuf, "SMLA%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B'); 300 | pBuf = WritePadding( pBuf, pBuf0 ); 301 | pBuf += sprintf(pBuf, "%s, %s, %s, %s", get_reg_name((opcode>>16)&0xf), get_reg_name((opcode>>12)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>8)&0xf)); 302 | } 303 | else if ((opcode & 0x0ff00090) == 0x01400080) // SMLALxy - v5 304 | { 305 | pBuf += sprintf(pBuf, "SMLAL%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B'); 306 | pBuf = WritePadding( pBuf, pBuf0 ); 307 | pBuf += sprintf(pBuf, "%s, %s, %s, %s", get_reg_name((opcode>>16)&0xf), get_reg_name((opcode>>12)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>8)&0xf)); 308 | } 309 | else if ((opcode & 0x0ff00090) == 0x01600080) // SMULxy - v5 310 | { 311 | pBuf += sprintf(pBuf, "SMUL%c%c", (opcode&0x20) ? 'T' : 'B', (opcode&0x40) ? 'T' : 'B'); 312 | pBuf = WritePadding( pBuf, pBuf0 ); 313 | pBuf += sprintf(pBuf, "%s, %s, %s", get_reg_name((opcode>>16)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>12)&0xf)); 314 | } 315 | else if ((opcode & 0x0ff000b0) == 0x012000a0) // SMULWy - v5 316 | { 317 | pBuf += sprintf(pBuf, "SMULW%c", (opcode&0x40) ? 'T' : 'B'); 318 | pBuf = WritePadding( pBuf, pBuf0 ); 319 | pBuf += sprintf(pBuf, "%s, %s, %s", get_reg_name((opcode>>16)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>8)&0xf)); 320 | } 321 | else if ((opcode & 0x0ff000b0) == 0x01200080) // SMLAWy - v5 322 | { 323 | pBuf += sprintf(pBuf, "SMLAW%c", (opcode&0x40) ? 'T' : 'B'); 324 | pBuf = WritePadding( pBuf, pBuf0 ); 325 | pBuf += sprintf(pBuf, "%s, %s, %s, %s", get_reg_name((opcode>>16)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>8)&0xf), get_reg_name((opcode>>12)&0xf)); 326 | } 327 | else if( (opcode&0x0e000000)==0 && (opcode&0x80) && (opcode&0x10) ) //bits 27-25 == 000, bit 7=1, bit 4=1 328 | { 329 | /* multiply or swap or half word data transfer */ 330 | if(opcode&0x60) 331 | { //bits = 6-5 != 00 332 | /* half word data transfer */ 333 | if (((opcode & 0x60) == 0x40) && !(opcode & 0x100000)) // bit 20 = 0, bits 5&6 = 10 is ARMv5 LDRD 334 | { 335 | pBuf += sprintf(pBuf, "LDRD%s", pConditionCode); 336 | } 337 | else if (((opcode & 0x60) == 0x60) && !(opcode & 0x100000)) // bit 20 = 0, bits 5&6 = 11 is ARMv5 STRD 338 | { 339 | pBuf += sprintf(pBuf, "STRD%s", pConditionCode); 340 | } 341 | else 342 | { 343 | pBuf += sprintf(pBuf, "%s%s",(opcode&0x00100000)?"LDR":"STR",pConditionCode); //Bit 20 = 1 for Load, 0 for Store 344 | 345 | //Signed? (if not, always unsigned half word) 346 | if(opcode&0x40) 347 | { 348 | pBuf += sprintf(pBuf, "%s",(opcode&0x20)?"SH":"SB"); //Bit 5 = 1 for Half Word, 0 for Byte 349 | } 350 | else 351 | { 352 | pBuf += sprintf(pBuf, "H"); 353 | } 354 | } 355 | 356 | pBuf = WritePadding( pBuf, pBuf0 ); 357 | 358 | //Dest Register 359 | pBuf += sprintf(pBuf, "%s, ", get_reg_name((opcode>>12)&0x0f)); 360 | //Base Register 361 | pBuf += sprintf(pBuf, "[%s%s", get_reg_name((opcode>>16)&0x0f),(opcode&0x1000000)?"":"]"); //If Bit 24 = 1, Pre-increment, otherwise, Post increment so close brace 362 | 363 | //Immediate or Register Offset? 364 | if(opcode&0x400000) { //Bit 22 - 1 = immediate, 0 = register 365 | //immediate ( imm. value in high nibble (bits 8-11) and lo nibble (bit 0-3) ) 366 | pBuf += sprintf(pBuf, ",%s#$%x",(opcode&0x800000)?"":"-",( (((opcode>>8)&0x0f)<<4) | (opcode&0x0f))); 367 | } 368 | else { 369 | //register 370 | pBuf += sprintf(pBuf, ",%s%s",(opcode&0x800000)?"":"-", get_reg_name((opcode & 0x0f))); 371 | } 372 | 373 | //Pre-Inc brace & Write back 374 | pBuf += sprintf(pBuf, "%s%s",(opcode&0x1000000)?"]":"",(opcode&0x200000)?"{!}":""); 375 | } 376 | else { 377 | if(opcode&0x01000000) { //bit 24 = 1 378 | /* swap */ 379 | //todo: Test on valid instructions 380 | /* xxxx 0001 0B00 nnnn dddd 0000 1001 mmmm */ 381 | pBuf += sprintf( pBuf, "SWP" ); 382 | pBuf += sprintf( pBuf, "%s%s", pConditionCode, (opcode & 0x400000)?"B":"" ); //Bit 22 = Byte/Word selection 383 | //Rd, Rm, [Rn] 384 | pBuf += sprintf( pBuf, "%s, %s, [%s]", 385 | get_reg_name((opcode>>12)&0xf), get_reg_name(opcode&0xf), get_reg_name((opcode>>16)&0xf)); 386 | } 387 | else { 388 | /* multiply or multiply long */ 389 | 390 | if( opcode&0x800000 ) //Bit 23 = 1 for Multiply Long 391 | { 392 | /* Multiply Long */ 393 | /* xxxx0001 UAShhhhllllnnnn1001mmmm */ 394 | 395 | /* Signed? */ 396 | if( opcode&0x00400000 ) 397 | pBuf += sprintf( pBuf, "S" ); 398 | else 399 | pBuf += sprintf( pBuf, "U" ); 400 | 401 | /* Multiply & Accumulate? */ 402 | if( opcode&0x00200000 ) 403 | { 404 | pBuf += sprintf( pBuf, "MLAL" ); 405 | } 406 | else 407 | { 408 | pBuf += sprintf( pBuf, "MULL" ); 409 | } 410 | pBuf += sprintf( pBuf, "%s", pConditionCode ); 411 | 412 | /* Set Status Flags */ 413 | if( opcode&0x00100000 ) 414 | { 415 | *pBuf++ = 'S'; 416 | } 417 | pBuf = WritePadding( pBuf, pBuf0 ); 418 | 419 | //Format is RLo,RHi,Rm,Rs 420 | pBuf += sprintf( pBuf, 421 | "%s, %s, %s, %s", 422 | get_reg_name((opcode>>12)&0xf), 423 | get_reg_name((opcode>>16)&0xf), 424 | get_reg_name((opcode&0xf)), 425 | get_reg_name((opcode>>8)&0xf)); 426 | } 427 | else 428 | { 429 | /* Multiply */ 430 | /* xxxx0000 00ASdddd nnnnssss 1001mmmm */ 431 | 432 | /* Multiply & Accumulate? */ 433 | if( opcode&0x00200000 ) 434 | { 435 | pBuf += sprintf( pBuf, "MLA" ); 436 | } 437 | /* Multiply */ 438 | else 439 | { 440 | pBuf += sprintf( pBuf, "MUL" ); 441 | } 442 | pBuf += sprintf( pBuf, "%s", pConditionCode ); 443 | if( opcode&0x00100000 ) 444 | { 445 | *pBuf++ = 'S'; 446 | } 447 | pBuf = WritePadding( pBuf, pBuf0 ); 448 | 449 | pBuf += sprintf( pBuf, 450 | "%s, %s, %s", 451 | get_reg_name((opcode>>16)&0xf), 452 | get_reg_name((opcode&0xf)), 453 | get_reg_name((opcode>>8)&0xf)); 454 | 455 | if( opcode&0x00200000 ) 456 | { 457 | pBuf += sprintf( pBuf, ", %s", get_reg_name((opcode>>12)&0xf)); 458 | } 459 | } 460 | } 461 | } 462 | } 463 | else if( (opcode&0x0c000000)==0 ) //bits 27-26 == 00 - This check can only exist properly after Multiplication check above 464 | { 465 | 466 | /* Data Processing OR PSR Transfer */ 467 | 468 | //SJE: check for MRS & MSR ( S bit must be clear, and bit 24,23 = 10 ) 469 | if( ((opcode&0x00100000)==0) && ((opcode&0x01800000)==0x01000000) ) { 470 | char strpsr[6]; 471 | sprintf(strpsr, "%s",(opcode&0x400000)?"SPSR":"CPSR"); 472 | 473 | //MSR ( bit 21 set ) 474 | if( (opcode&0x00200000) ) { 475 | pBuf += sprintf(pBuf, "MSR%s",pConditionCode ); 476 | //Flag Bits Only? (Bit 16 Clear) 477 | if( (opcode&0x10000)==0) pBuf += sprintf(pBuf, "F"); 478 | pBuf = WritePadding( pBuf, pBuf0 ); 479 | pBuf += sprintf(pBuf, "%s,",strpsr); 480 | WriteDataProcessingOperand(pBuf, opcode, (opcode&0x02000000)?1:0, 0, 1); 481 | } 482 | //MRS ( bit 21 clear ) 483 | else { 484 | pBuf += sprintf(pBuf, "MRS%s",pConditionCode ); 485 | pBuf = WritePadding( pBuf, pBuf0 ); 486 | pBuf += sprintf(pBuf, "%s,", get_reg_name((opcode>>12)&0x0f)); 487 | pBuf += sprintf(pBuf, "%s",strpsr); 488 | } 489 | } 490 | else { 491 | /* Data Processing */ 492 | /* xxxx001a aaaSnnnn ddddrrrr bbbbbbbb */ 493 | /* xxxx000a aaaSnnnn ddddcccc ctttmmmm */ 494 | int op=(opcode>>21)&0xf; 495 | pBuf += sprintf( 496 | pBuf, "%s%s", 497 | pOperation[op], 498 | pConditionCode ); 499 | 500 | //SJE: corrected S-Bit bug here 501 | //if( (opcode&0x01000000) ) 502 | if( (opcode&0x0100000) ) 503 | { 504 | *pBuf++ = 'S'; 505 | } 506 | 507 | pBuf = WritePadding( pBuf, pBuf0 ); 508 | 509 | switch (op) { 510 | case 0x00: 511 | case 0x01: 512 | case 0x02: 513 | case 0x03: 514 | case 0x04: 515 | case 0x05: 516 | case 0x06: 517 | case 0x07: 518 | case 0x0c: 519 | case 0x0e: 520 | WriteDataProcessingOperand(pBuf, opcode, 1, 1, 1); 521 | break; 522 | case 0x08: 523 | case 0x09: 524 | case 0x0a: 525 | case 0x0b: 526 | WriteDataProcessingOperand(pBuf, opcode, 0, 1, 1); 527 | break; 528 | case 0x0d: 529 | /* look for mov pc,lr */ 530 | if (((opcode >> 12) & 0x0f) == 15 && ((opcode >> 0) & 0x0f) == 14 && (opcode & 0x02000000) == 0) 531 | dasmflags = DASMFLAG_STEP_OUT; 532 | case 0x0f: 533 | WriteDataProcessingOperand(pBuf, opcode, 1, 0, 1); 534 | break; 535 | } 536 | } 537 | } 538 | else if( (opcode&0x0c000000)==0x04000000 ) //bits 27-26 == 01 539 | { 540 | UINT32 rn = 0; 541 | UINT32 rnv = 0; 542 | 543 | /* Data Transfer */ 544 | 545 | /* xxxx010P UBWLnnnn ddddoooo oooooooo Immediate form */ 546 | /* xxxx011P UBWLnnnn ddddcccc ctt0mmmm Register form */ 547 | if( opcode&0x00100000 ) 548 | { 549 | pBuf += sprintf( pBuf, "LDR" ); 550 | } 551 | else 552 | { 553 | pBuf += sprintf( pBuf, "STR" ); 554 | } 555 | pBuf += sprintf( pBuf, "%s", pConditionCode ); 556 | 557 | if( opcode&0x00400000 ) 558 | { 559 | pBuf += sprintf( pBuf, "B" ); 560 | } 561 | 562 | if( opcode&0x00200000 ) 563 | { 564 | /* writeback addr */ 565 | if( opcode&0x01000000 ) 566 | { 567 | /* pre-indexed addressing */ 568 | pBuf += sprintf( pBuf, "!" ); 569 | } 570 | else 571 | { 572 | /* post-indexed addressing */ 573 | pBuf += sprintf( pBuf, "T" ); 574 | } 575 | } 576 | 577 | pBuf = WritePadding( pBuf, pBuf0 ); 578 | if (((opcode>>16) & 0xf) == 15 && (opcode & 0x02000000) == 0) 579 | { 580 | pBuf += sprintf( pBuf, "%s, ", get_reg_name((opcode>>12) & 0xf)); 581 | rnv = pc + 8; 582 | 583 | if (rnv) 584 | { 585 | if (opcode & 0xfff) 586 | { 587 | if( opcode & 0x00800000 ) 588 | rnv += opcode & 0xfff; 589 | else 590 | rnv -= opcode & 0xfff; 591 | } 592 | 593 | if (rnv >= image_base && rnv < image_base + image_size) 594 | { 595 | UINT32 data = rnv - image_base; 596 | data = (image_data[data + 3] << 24) | (image_data[data + 2] << 16) | (image_data[data + 1] << 8) | image_data[data]; 597 | pBuf += sprintf( pBuf, "=%s ", get_symbol_name(data)); 598 | check_rnv(rnv); 599 | } 600 | 601 | pBuf += sprintf( pBuf, "[$%08x]", rnv); 602 | } 603 | else 604 | pBuf += sprintf( pBuf, "[PC]"); 605 | } 606 | else 607 | { 608 | pBuf += sprintf( pBuf, "%s, [%s", 609 | get_reg_name((opcode>>12)&0xf), get_reg_name((opcode>>16)&0xf)); 610 | 611 | //grab value of pc if used as base register 612 | rn = (opcode>>16)&0xf; 613 | if(rn==15) rnv = pc+8; 614 | 615 | if( opcode&0x02000000 ) 616 | { 617 | /* register form */ 618 | pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"":"]" ); 619 | pBuf = WriteRegisterOperand1( pBuf, opcode ); 620 | pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"]":"" ); 621 | } 622 | else 623 | { 624 | /* immediate form */ 625 | pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"":"]" ); 626 | //hide zero offsets 627 | if(opcode&0xfff) { 628 | if( opcode&0x00800000 ) 629 | { 630 | pBuf += sprintf( pBuf, ", #$%x", opcode&0xfff ); 631 | rnv += (rnv)?opcode&0xfff:0; 632 | } 633 | else 634 | { 635 | pBuf += sprintf( pBuf, ", -#$%x", opcode&0xfff ); 636 | rnv -= (rnv)?opcode&0xfff:0; 637 | } 638 | } 639 | pBuf += sprintf( pBuf, "%s",(opcode&0x01000000)?"]":"" ); 640 | //show where the read will occur if we found a value 641 | if(rnv) pBuf += sprintf( pBuf, " (%x)",rnv); 642 | } 643 | } 644 | } 645 | else if( (opcode&0x0e000000) == 0x08000000 ) //bits 27-25 == 100 646 | { 647 | /* xxxx100P USWLnnnn llllllll llllllll */ 648 | /* Block Data Transfer */ 649 | 650 | if( opcode&0x00100000 ) 651 | { 652 | pBuf += sprintf( pBuf, "LDM" ); 653 | } 654 | else 655 | { 656 | pBuf += sprintf( pBuf, "STM" ); 657 | } 658 | pBuf += sprintf( pBuf, "%s", pConditionCode ); 659 | 660 | if( opcode&0x01000000 ) 661 | { 662 | pBuf += sprintf( pBuf, "P" ); 663 | } 664 | if( opcode&0x00800000 ) 665 | { 666 | pBuf += sprintf( pBuf, "U" ); 667 | } 668 | if( opcode&0x00400000 ) 669 | { 670 | pBuf += sprintf( pBuf, "^" ); 671 | } 672 | if( opcode&0x00200000 ) 673 | { 674 | pBuf += sprintf( pBuf, "W" ); 675 | } 676 | 677 | pBuf = WritePadding( pBuf, pBuf0 ); 678 | pBuf += sprintf( pBuf, "[%s], {", get_reg_name((opcode>>16)&0xf)); 679 | 680 | { 681 | int j=0,last=0,found=0; 682 | #if 0 683 | for (j=0; j<16; j++) { 684 | if (opcode&(1<> THUMB_INSN_TYPE_SHIFT ) 796 | { 797 | case 0x0: /* Logical shifting */ 798 | if( opcode & THUMB_SHIFT_R ) /* Shift right */ 799 | { 800 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 801 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 802 | offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT; 803 | pBuf += sprintf( pBuf, "LSR %s, %s, %d", get_reg_name(rd), get_reg_name(rs), offs); 804 | } 805 | else /* Shift left */ 806 | { 807 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 808 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 809 | offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT; 810 | pBuf += sprintf( pBuf, "LSL %s, %s, %d", get_reg_name(rd), get_reg_name(rs), offs); 811 | } 812 | break; 813 | case 0x1: /* Arithmetic */ 814 | if( opcode & THUMB_INSN_ADDSUB ) 815 | { 816 | switch( ( opcode & THUMB_ADDSUB_TYPE ) >> THUMB_ADDSUB_TYPE_SHIFT ) 817 | { 818 | case 0x0: /* ADD Rd, Rs, Rn */ 819 | rn = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT; 820 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 821 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 822 | pBuf += sprintf( pBuf, "ADD %s, %s, %s", get_reg_name(rd), get_reg_name(rs), get_reg_name(rn)); 823 | break; 824 | case 0x1: /* SUB Rd, Rs, Rn */ 825 | rn = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT; 826 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 827 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 828 | pBuf += sprintf( pBuf, "SUB %s, %s, %s", get_reg_name(rd), get_reg_name(rs), get_reg_name(rn)); 829 | break; 830 | case 0x2: /* ADD Rd, Rs, #imm */ 831 | imm = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT; 832 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 833 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 834 | pBuf += sprintf( pBuf, "ADD %s, %s, #%d", get_reg_name(rd), get_reg_name(rs), imm ); 835 | break; 836 | case 0x3: /* SUB Rd, Rs, #imm */ 837 | imm = ( opcode & THUMB_ADDSUB_RNIMM ) >> THUMB_ADDSUB_RNIMM_SHIFT; 838 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 839 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 840 | pBuf += sprintf( pBuf, "SUB %s, %s, #%d", get_reg_name(rd), get_reg_name(rs), imm ); 841 | break; 842 | default: 843 | sprintf( pBuf, "INVALID %04x", opcode); 844 | break; 845 | } 846 | } 847 | else 848 | { 849 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 850 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 851 | offs = ( opcode & THUMB_SHIFT_AMT ) >> THUMB_SHIFT_AMT_SHIFT; 852 | pBuf += sprintf( pBuf, "ASR %s, %s, %d", get_reg_name(rd), get_reg_name(rs), offs); 853 | } 854 | break; 855 | case 0x2: /* CMP / MOV */ 856 | if( opcode & THUMB_INSN_CMP ) 857 | { 858 | rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; 859 | op2 = ( opcode & THUMB_INSN_IMM ); 860 | pBuf += sprintf( pBuf, "CMP %s, %02x", get_reg_name(rn), op2 ); 861 | } 862 | else 863 | { 864 | rd = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; 865 | op2 = ( opcode & THUMB_INSN_IMM ); 866 | pBuf += sprintf( pBuf, "MOV %s, %02x", get_reg_name(rd), op2 ); 867 | } 868 | break; 869 | case 0x3: /* ADD/SUB immediate */ 870 | if( opcode & THUMB_INSN_SUB ) /* SUB Rd, #Offset8 */ 871 | { 872 | rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; 873 | op2 = ( opcode & THUMB_INSN_IMM ); 874 | pBuf += sprintf( pBuf, "SUB %s, %02x", get_reg_name(rn), op2 ); // fixed, rd -> rn 875 | } 876 | else /* ADD Rd, #Offset8 */ 877 | { 878 | rn = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; 879 | op2 = opcode & THUMB_INSN_IMM; 880 | pBuf += sprintf( pBuf, "ADD %s, %02x", get_reg_name(rn), op2 ); 881 | } 882 | break; 883 | case 0x4: /* Rd & Rm instructions */ 884 | switch( ( opcode & THUMB_GROUP4_TYPE ) >> THUMB_GROUP4_TYPE_SHIFT ) 885 | { 886 | case 0x0: 887 | switch( ( opcode & THUMB_ALUOP_TYPE ) >> THUMB_ALUOP_TYPE_SHIFT ) 888 | { 889 | case 0x0: /* AND Rd, Rs */ 890 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 891 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 892 | pBuf += sprintf( pBuf, "AND %s, %s", get_reg_name(rd), get_reg_name(rs)); 893 | 894 | break; 895 | case 0x1: /* EOR Rd, Rs */ 896 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 897 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 898 | pBuf += sprintf( pBuf, "EOR %s, %s", get_reg_name(rd), get_reg_name(rs)); 899 | break; 900 | case 0x2: /* LSL Rd, Rs */ 901 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 902 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 903 | pBuf += sprintf( pBuf, "LSL %s, %s", get_reg_name(rd), get_reg_name(rs)); 904 | break; 905 | case 0x3: /* LSR Rd, Rs */ 906 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 907 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 908 | pBuf += sprintf( pBuf, "LSR %s, %s", get_reg_name(rd), get_reg_name(rs)); 909 | break; 910 | case 0x4: /* ASR Rd, Rs */ 911 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 912 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 913 | pBuf += sprintf( pBuf, "ASR %s, %s", get_reg_name(rd), get_reg_name(rs)); 914 | break; 915 | case 0x5: /* ADC Rd, Rs */ 916 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 917 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 918 | pBuf += sprintf( pBuf, "ADC %s, %s", get_reg_name(rd), get_reg_name(rs)); 919 | break; 920 | case 0x6: /* SBC Rd, Rs */ 921 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 922 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 923 | pBuf += sprintf( pBuf, "SBC %s, %s", get_reg_name(rd), get_reg_name(rs)); 924 | break; 925 | case 0x7: /* ROR Rd, Rs */ 926 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 927 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 928 | pBuf += sprintf( pBuf, "ROR %s, %s", get_reg_name(rd), get_reg_name(rs)); 929 | break; 930 | case 0x8: /* TST Rd, Rs */ 931 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 932 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 933 | pBuf += sprintf( pBuf, "TST %s, %s", get_reg_name(rd), get_reg_name(rs)); 934 | break; 935 | case 0x9: /* NEG Rd, Rs */ 936 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 937 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 938 | pBuf += sprintf( pBuf, "NEG %s, %s", get_reg_name(rd), get_reg_name(rs)); 939 | break; 940 | case 0xa: /* CMP Rd, Rs */ 941 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 942 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 943 | pBuf += sprintf( pBuf, "CMP %s, %s", get_reg_name(rd), get_reg_name(rs)); 944 | break; 945 | case 0xb: /* CMN Rd, Rs - check flags, add dasm */ 946 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 947 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 948 | pBuf += sprintf( pBuf, "CMN %s, %s", get_reg_name(rd), get_reg_name(rs)); 949 | break; 950 | case 0xc: /* ORR Rd, Rs */ 951 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 952 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 953 | pBuf += sprintf( pBuf, "ORR %s, %s", get_reg_name(rd), get_reg_name(rs)); 954 | break; 955 | case 0xd: /* MUL Rd, Rs */ 956 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 957 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 958 | pBuf += sprintf( pBuf, "MUL %s, %s", get_reg_name(rd), get_reg_name(rs)); 959 | break; 960 | case 0xe: /* MUL Rd, Rs */ 961 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 962 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 963 | pBuf += sprintf( pBuf, "BIC %s, %s", get_reg_name(rd), get_reg_name(rs)); 964 | break; 965 | case 0xf: /* MVN Rd, Rs */ 966 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 967 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 968 | pBuf += sprintf( pBuf, "MVN %s, %s", get_reg_name(rd), get_reg_name(rs)); 969 | break; 970 | default: 971 | sprintf( pBuf, "INVALID %04x", opcode); 972 | break; 973 | } 974 | break; 975 | case 0x1: 976 | switch( ( opcode & THUMB_HIREG_OP ) >> THUMB_HIREG_OP_SHIFT ) 977 | { 978 | case 0x0: /* ADD Rd, Rs */ 979 | rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 980 | rd = opcode & THUMB_HIREG_RD; 981 | switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT ) 982 | { 983 | case 0x1: /* ADD Rd, HRs */ 984 | pBuf += sprintf( pBuf, "ADD %s, %s", get_reg_name(rd), get_reg_name(rs + 8)); 985 | break; 986 | case 0x2: /* ADD HRd, Rs */ 987 | pBuf += sprintf( pBuf, "ADD %s, %s", get_reg_name(rd + 8), get_reg_name(rs)); 988 | break; 989 | case 0x3: /* ADD HRd, HRs */ 990 | pBuf += sprintf( pBuf, "ADD %s, %s", get_reg_name(rd + 8), get_reg_name(rs + 8)); 991 | break; 992 | default: 993 | sprintf( pBuf, "INVALID %04x", opcode); 994 | break; 995 | } 996 | break; 997 | case 0x1: /* CMP */ 998 | switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT ) 999 | { 1000 | case 0x0: /* CMP Rd, Rs */ 1001 | rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 1002 | rd = opcode & THUMB_HIREG_RD; 1003 | pBuf += sprintf( pBuf, "CMP %s, %s", get_reg_name(rd), get_reg_name(rs)); 1004 | break; 1005 | case 0x1: /* CMP Rd, HRs */ 1006 | rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 1007 | rd = opcode & THUMB_HIREG_RD; 1008 | pBuf += sprintf( pBuf, "CMP %s, %s", get_reg_name(rd), get_reg_name(rs + 8)); 1009 | break; 1010 | case 0x2: /* CMP Hd, Rs */ 1011 | rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 1012 | rd = opcode & THUMB_HIREG_RD; 1013 | pBuf += sprintf( pBuf, "CMP %s, %s", get_reg_name(rd + 8), get_reg_name(rs)); 1014 | break; 1015 | case 0x3: /* CMP Hd, Hs */ 1016 | rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 1017 | rd = opcode & THUMB_HIREG_RD; 1018 | pBuf += sprintf( pBuf, "CMP %s, %s", get_reg_name(rd + 8), get_reg_name(rs + 8)); 1019 | break; 1020 | default: 1021 | sprintf( pBuf, "INVALID %04x", opcode); 1022 | break; 1023 | } 1024 | break; 1025 | case 0x2: /* MOV */ 1026 | switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT ) 1027 | { 1028 | case 0x1: 1029 | rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 1030 | rd = opcode & THUMB_HIREG_RD; 1031 | pBuf += sprintf( pBuf, "MOV %s, %s", get_reg_name(rd), get_reg_name(rs + 8)); 1032 | break; 1033 | case 0x2: 1034 | rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 1035 | rd = opcode & THUMB_HIREG_RD; 1036 | pBuf += sprintf( pBuf, "MOV %s, %s", get_reg_name(rd + 8), get_reg_name(rs)); 1037 | break; 1038 | case 0x3: 1039 | rs = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 1040 | rd = opcode & THUMB_HIREG_RD; 1041 | pBuf += sprintf( pBuf, "MOV %s, %s", get_reg_name(rd + 8), get_reg_name(rs + 8)); 1042 | break; 1043 | default: 1044 | sprintf( pBuf, "INVALID %04x", opcode); 1045 | break; 1046 | } 1047 | break; 1048 | case 0x3: 1049 | switch( ( opcode & THUMB_HIREG_H ) >> THUMB_HIREG_H_SHIFT ) 1050 | { 1051 | case 0x0: 1052 | rd = ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT; 1053 | pBuf += sprintf( pBuf, "BX %s", get_reg_name(rd)); 1054 | break; 1055 | case 0x1: 1056 | rd = ( ( opcode & THUMB_HIREG_RS ) >> THUMB_HIREG_RS_SHIFT ) + 8; 1057 | pBuf += sprintf( pBuf, "BX %s", get_reg_name(rd)); 1058 | if (rd == 14) 1059 | dasmflags = DASMFLAG_STEP_OUT; 1060 | break; 1061 | default: 1062 | sprintf( pBuf, "INVALID %04x", opcode); 1063 | break; 1064 | } 1065 | break; 1066 | default: 1067 | sprintf( pBuf, "INVALID %04x", opcode); 1068 | break; 1069 | } 1070 | break; 1071 | case 0x2: 1072 | case 0x3: 1073 | rd = ( opcode & THUMB_INSN_IMM_RD ) >> THUMB_INSN_IMM_RD_SHIFT; 1074 | addr = ( opcode & THUMB_INSN_IMM ) << 2; 1075 | pBuf += sprintf( pBuf, "LDR %s, [PC, #%03x]", get_reg_name(rd), addr ); 1076 | break; 1077 | default: 1078 | sprintf( pBuf, "INVALID %04x", opcode); 1079 | break; 1080 | } 1081 | break; 1082 | case 0x5: /* LDR* STR* */ 1083 | switch( ( opcode & THUMB_GROUP5_TYPE ) >> THUMB_GROUP5_TYPE_SHIFT ) 1084 | { 1085 | case 0x0: /* STR Rd, [Rn, Rm] */ 1086 | rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; 1087 | rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; 1088 | rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; 1089 | pBuf += sprintf( pBuf, "STR %s, [%s, %s]", get_reg_name(rd), get_reg_name(rn), get_reg_name(rm)); 1090 | break; 1091 | case 0x1: /* STRH Rd, [Rn, Rm] */ 1092 | rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; 1093 | rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; 1094 | rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; 1095 | pBuf += sprintf( pBuf, "STRH %s, [%s, %s]", get_reg_name(rd), get_reg_name(rn), get_reg_name(rm)); 1096 | break; 1097 | case 0x2: /* STRB Rd, [Rn, Rm] */ /* check */ 1098 | rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; 1099 | rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; 1100 | rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; 1101 | pBuf += sprintf( pBuf, "STRB %s, [%s, %s]", get_reg_name(rd), get_reg_name(rn), get_reg_name(rm)); 1102 | break; 1103 | case 0x3: /* LDRSB Rd, [Rn, Rm] */ 1104 | rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; 1105 | rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; 1106 | rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; 1107 | pBuf += sprintf( pBuf, "LDRSB %s, [%s, %s]", get_reg_name(rd), get_reg_name(rn), get_reg_name(rm)); 1108 | break; 1109 | case 0x4: /* LDR Rd, [Rn, Rm] */ /* check */ 1110 | rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; 1111 | rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; 1112 | rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; 1113 | pBuf += sprintf( pBuf, "LDR %s, [%s, %s]", get_reg_name(rd), get_reg_name(rn), get_reg_name(rm)); 1114 | break; 1115 | case 0x5: /* LDRH Rd, [Rn, Rm] */ 1116 | rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; 1117 | rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; 1118 | rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; 1119 | pBuf += sprintf( pBuf, "LDRH %s, [%s, %s]", get_reg_name(rd), get_reg_name(rn), get_reg_name(rm)); 1120 | break; 1121 | 1122 | case 0x6: /* LDRB Rd, [Rn, Rm] */ 1123 | rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; 1124 | rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; 1125 | rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; 1126 | pBuf += sprintf( pBuf, "LDRB %s, [%s, %s]", get_reg_name(rd), get_reg_name(rn), get_reg_name(rm)); 1127 | break; 1128 | case 0x7: /* LDSH Rd, [Rn, Rm] */ 1129 | rm = ( opcode & THUMB_GROUP5_RM ) >> THUMB_GROUP5_RM_SHIFT; 1130 | rn = ( opcode & THUMB_GROUP5_RN ) >> THUMB_GROUP5_RN_SHIFT; 1131 | rd = ( opcode & THUMB_GROUP5_RD ) >> THUMB_GROUP5_RD_SHIFT; 1132 | pBuf += sprintf( pBuf, "LDSH %s, [%s, %s]", get_reg_name(rd), get_reg_name(rn), get_reg_name(rm)); 1133 | break; 1134 | default: 1135 | sprintf( pBuf, "INVALID %04x", opcode); 1136 | break; 1137 | } 1138 | break; 1139 | case 0x6: /* Word Store w/ Immediate Offset */ 1140 | if( opcode & THUMB_LSOP_L ) /* Load */ 1141 | { 1142 | rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 1143 | rd = opcode & THUMB_ADDSUB_RD; 1144 | offs = ( ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2; 1145 | pBuf += sprintf( pBuf, "LDR %s [%s + #%02x]", get_reg_name(rd), get_reg_name(rn), offs ); 1146 | } 1147 | else /* Store */ 1148 | { 1149 | rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 1150 | rd = opcode & THUMB_ADDSUB_RD; 1151 | offs = ( ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT ) << 2; 1152 | pBuf += sprintf( pBuf, "STR %s [%s + #%02x]", get_reg_name(rd), get_reg_name(rn), offs ); 1153 | } 1154 | break; 1155 | case 0x7: /* Byte Store w/ Immeidate Offset */ 1156 | if( opcode & THUMB_LSOP_L ) /* Load */ 1157 | { 1158 | rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 1159 | rd = opcode & THUMB_ADDSUB_RD; 1160 | offs = ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT; 1161 | pBuf += sprintf( pBuf, "LDRB %s [%s + #%02x]", get_reg_name(rd), get_reg_name(rn), offs ); 1162 | } 1163 | else /* Store */ 1164 | { 1165 | rn = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 1166 | rd = opcode & THUMB_ADDSUB_RD; 1167 | offs = ( opcode & THUMB_LSOP_OFFS ) >> THUMB_LSOP_OFFS_SHIFT; 1168 | pBuf += sprintf( pBuf, "STRB %s [%s + #%02x]", get_reg_name(rd), get_reg_name(rn), offs ); 1169 | } 1170 | break; 1171 | case 0x8: /* Load/Store Halfword */ 1172 | if( opcode & THUMB_HALFOP_L ) /* Load */ 1173 | { 1174 | imm = ( opcode & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT; 1175 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 1176 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 1177 | pBuf += sprintf( pBuf, "LDRH %s, [%s, #%03x]", get_reg_name(rd), get_reg_name(rs), imm << 1 ); 1178 | } 1179 | else /* Store */ 1180 | { 1181 | imm = ( opcode & THUMB_HALFOP_OFFS ) >> THUMB_HALFOP_OFFS_SHIFT; 1182 | rs = ( opcode & THUMB_ADDSUB_RS ) >> THUMB_ADDSUB_RS_SHIFT; 1183 | rd = ( opcode & THUMB_ADDSUB_RD ) >> THUMB_ADDSUB_RD_SHIFT; 1184 | pBuf += sprintf( pBuf, "STRH %s, [%s, #%03x]", get_reg_name(rd), get_reg_name(rs), imm << 1 ); 1185 | } 1186 | break; 1187 | case 0x9: /* Stack-Relative Load/Store */ 1188 | if( opcode & THUMB_STACKOP_L ) 1189 | { 1190 | rd = ( opcode & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT; 1191 | offs = (UINT8)( opcode & THUMB_INSN_IMM ); 1192 | pBuf += sprintf( pBuf, "LDR %s, [SP, #%03x]", get_reg_name(rd), offs << 2 ); 1193 | } 1194 | else 1195 | { 1196 | rd = ( opcode & THUMB_STACKOP_RD ) >> THUMB_STACKOP_RD_SHIFT; 1197 | offs = (UINT8)( opcode & THUMB_INSN_IMM ); 1198 | pBuf += sprintf( pBuf, "STR %s, [SP, #%03x]", get_reg_name(rd), offs << 2 ); 1199 | } 1200 | break; 1201 | case 0xa: /* Get relative address */ 1202 | if( opcode & THUMB_RELADDR_SP ) /* ADD Rd, SP, #nn */ 1203 | { 1204 | rd = ( opcode & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT; 1205 | offs = (UINT8)( opcode & THUMB_INSN_IMM ) << 2; 1206 | pBuf += sprintf( pBuf, "ADD %s, SP, #%03x", get_reg_name(rd), offs ); 1207 | } 1208 | else /* ADD Rd, PC, #nn */ 1209 | { 1210 | rd = ( opcode & THUMB_RELADDR_RD ) >> THUMB_RELADDR_RD_SHIFT; 1211 | offs = (UINT8)( opcode & THUMB_INSN_IMM ) << 2; 1212 | pBuf += sprintf( pBuf, "ADD %s, PC, #%03x", get_reg_name(rd), offs ); 1213 | } 1214 | break; 1215 | case 0xb: /* Stack-Related Opcodes */ 1216 | switch( ( opcode & THUMB_STACKOP_TYPE ) >> THUMB_STACKOP_TYPE_SHIFT ) 1217 | { 1218 | case 0x0: /* ADD SP, #imm */ 1219 | addr = ( opcode & THUMB_INSN_IMM ); 1220 | addr &= ~THUMB_INSN_IMM_S; 1221 | pBuf += sprintf( pBuf, "ADD SP, #"); 1222 | if( opcode & THUMB_INSN_IMM_S ) 1223 | { 1224 | pBuf += sprintf( pBuf, "-"); 1225 | } 1226 | pBuf += sprintf( pBuf, "%03x", addr << 2); 1227 | break; 1228 | case 0x5: /* PUSH {Rlist}{LR} */ 1229 | pBuf += sprintf( pBuf, "PUSH {LR, "); 1230 | for( offs = 7; offs >= 0; offs-- ) 1231 | { 1232 | if( opcode & ( 1 << offs ) ) 1233 | { 1234 | pBuf += sprintf( pBuf, "%s, ", get_reg_name(offs)); 1235 | } 1236 | } 1237 | pBuf += sprintf( pBuf, "}"); 1238 | break; 1239 | case 0x4: /* PUSH {Rlist} */ 1240 | pBuf += sprintf( pBuf, "PUSH {"); 1241 | for( offs = 7; offs >= 0; offs-- ) 1242 | { 1243 | if( opcode & ( 1 << offs ) ) 1244 | { 1245 | pBuf += sprintf( pBuf, "%s, ", get_reg_name(offs)); 1246 | } 1247 | } 1248 | pBuf += sprintf( pBuf, "}"); 1249 | break; 1250 | case 0xc: /* POP {Rlist} */ 1251 | pBuf += sprintf( pBuf, "POP {"); 1252 | for( offs = 0; offs < 8; offs++ ) 1253 | { 1254 | if( opcode & ( 1 << offs ) ) 1255 | { 1256 | pBuf += sprintf( pBuf, "%s, ", get_reg_name(offs)); 1257 | } 1258 | } 1259 | pBuf += sprintf( pBuf, "}"); 1260 | break; 1261 | case 0xd: /* POP {Rlist}{PC} */ 1262 | pBuf += sprintf( pBuf, "POP {"); 1263 | for( offs = 0; offs < 8; offs++ ) 1264 | { 1265 | if( opcode & ( 1 << offs ) ) 1266 | { 1267 | pBuf += sprintf( pBuf, "%s, ", get_reg_name(offs)); 1268 | } 1269 | } 1270 | pBuf += sprintf( pBuf, "PC}"); 1271 | break; 1272 | default: 1273 | sprintf( pBuf, "INVALID %04x", opcode); 1274 | break; 1275 | } 1276 | break; 1277 | case 0xc: /* Multiple Load/Store */ 1278 | if( opcode & THUMB_MULTLS ) /* Load */ 1279 | { 1280 | rd = ( opcode & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT; 1281 | pBuf += sprintf( pBuf, "LDMIA %s!,{", get_reg_name(rd)); 1282 | for( offs = 0; offs < 8; offs++ ) 1283 | { 1284 | if( opcode & ( 1 << offs ) ) 1285 | { 1286 | pBuf += sprintf( pBuf, "%s, ", get_reg_name(offs)); 1287 | } 1288 | } 1289 | pBuf += sprintf( pBuf, "}"); 1290 | } 1291 | else /* Store */ 1292 | { 1293 | rd = ( opcode & THUMB_MULTLS_BASE ) >> THUMB_MULTLS_BASE_SHIFT; 1294 | pBuf += sprintf( pBuf, "STMIA %s!,{", get_reg_name(rd)); 1295 | for( offs = 7; offs >= 0; offs-- ) 1296 | { 1297 | if( opcode & ( 1 << offs ) ) 1298 | { 1299 | pBuf += sprintf( pBuf, "%s, ", get_reg_name(offs)); 1300 | } 1301 | } 1302 | pBuf += sprintf( pBuf, "}"); 1303 | } 1304 | break; 1305 | case 0xd: /* Conditional Branch */ 1306 | offs = (INT8)( opcode & THUMB_INSN_IMM ); 1307 | register_coderef(pc, pc + 4 + (offs << 1)); 1308 | 1309 | switch( ( opcode & THUMB_COND_TYPE ) >> THUMB_COND_TYPE_SHIFT ) 1310 | { 1311 | case COND_EQ: 1312 | pBuf += sprintf( pBuf, "BEQ %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1313 | break; 1314 | case COND_NE: 1315 | pBuf += sprintf( pBuf, "BNE %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1316 | break; 1317 | case COND_CS: 1318 | pBuf += sprintf( pBuf, "BCS %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1319 | break; 1320 | case COND_CC: 1321 | pBuf += sprintf( pBuf, "BCC %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1322 | break; 1323 | case COND_MI: 1324 | pBuf += sprintf( pBuf, "BMI %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1325 | break; 1326 | case COND_PL: 1327 | pBuf += sprintf( pBuf, "BPL %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1328 | break; 1329 | case COND_VS: 1330 | pBuf += sprintf( pBuf, "BVS %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1331 | break; 1332 | case COND_VC: 1333 | pBuf += sprintf( pBuf, "BVC %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1334 | break; 1335 | case COND_HI: 1336 | pBuf += sprintf( pBuf, "BHI %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1337 | break; 1338 | case COND_LS: 1339 | pBuf += sprintf( pBuf, "BLS %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1340 | break; 1341 | case COND_GE: 1342 | pBuf += sprintf( pBuf, "BGE %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1343 | break; 1344 | case COND_LT: 1345 | pBuf += sprintf( pBuf, "BLT %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1346 | break; 1347 | case COND_GT: 1348 | pBuf += sprintf( pBuf, "BGT %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1349 | break; 1350 | case COND_LE: 1351 | pBuf += sprintf( pBuf, "BLE %08x (%02x)", pc + 4 + (offs << 1), offs << 1); 1352 | break; 1353 | case COND_AL: 1354 | pBuf += sprintf( pBuf, "INVALID"); 1355 | break; 1356 | case COND_NV: 1357 | pBuf += sprintf( pBuf, "SWI %02x\n", opcode & 0xff); 1358 | break; 1359 | } 1360 | break; 1361 | case 0xe: /* B #offs */ 1362 | if( opcode & THUMB_BLOP_LO ) 1363 | { 1364 | addr = ( ( opcode & THUMB_BLOP_OFFS ) << 1 ) & 0xfffc; 1365 | pBuf += sprintf( pBuf, "BLX (LO) %08x", addr ); 1366 | dasmflags = DASMFLAG_STEP_OVER; 1367 | } 1368 | else 1369 | { 1370 | offs = ( opcode & THUMB_BRANCH_OFFS ) << 1; 1371 | if( offs & 0x00000800 ) 1372 | { 1373 | offs |= 0xfffff800; 1374 | } 1375 | pBuf += sprintf( pBuf, "B #%08x (%08x)", offs, pc + 4 + offs); 1376 | } 1377 | break; 1378 | case 0xf: /* BL */ 1379 | if( opcode & THUMB_BLOP_LO ) 1380 | { 1381 | pBuf += sprintf( pBuf, "BL (LO) %08x", ( opcode & THUMB_BLOP_OFFS ) << 1 ); 1382 | dasmflags = DASMFLAG_STEP_OVER; 1383 | } 1384 | else 1385 | { 1386 | addr = ( opcode & THUMB_BLOP_OFFS ) << 12; 1387 | if( addr & ( 1 << 22 ) ) 1388 | { 1389 | addr |= 0xff800000; 1390 | } 1391 | pBuf += sprintf( pBuf, "BL (HI) %08x", addr ); 1392 | dasmflags = DASMFLAG_STEP_OVER; 1393 | } 1394 | break; 1395 | default: 1396 | sprintf( pBuf, "INVALID %04x", opcode); 1397 | break; 1398 | } 1399 | 1400 | return dasmflags | DASMFLAG_SUPPORTED; 1401 | } 1402 | 1403 | CPU_DISASSEMBLE( arm7arm ) 1404 | { 1405 | return arm7_disasm(buffer, pc, oprom[0] | (oprom[1] << 8) | (oprom[2] << 16) | (oprom[3] << 24)) | 4; 1406 | } 1407 | 1408 | CPU_DISASSEMBLE( arm7arm_be ) 1409 | { 1410 | return arm7_disasm(buffer, pc, oprom[3] | (oprom[2] << 8) | (oprom[1] << 16) | (oprom[0] << 24)) | 4; 1411 | } 1412 | 1413 | CPU_DISASSEMBLE( arm7thumb ) 1414 | { 1415 | return thumb_disasm(buffer, pc, oprom[0] | (oprom[1] << 8)) | 2; 1416 | } 1417 | 1418 | CPU_DISASSEMBLE( arm7thumb_be ) 1419 | { 1420 | return thumb_disasm(buffer, pc, oprom[1] | (oprom[0] << 8)) | 2; 1421 | } 1422 | 1423 | -------------------------------------------------------------------------------- /emu.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fi01/arm7-dasm/40c193ab29ea9952755c98fad723aa1e7df9e4c1/emu.h --------------------------------------------------------------------------------