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