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