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