Search
lxdream.org :: lxdream/src/aica/armcore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/armcore.c
changeset 30:89b30313d757
prev11:0a82ef380c45
next35:21a4be098304
author nkeynes
date Sun Dec 25 08:24:11 2005 +0000 (17 years ago)
permissions -rw-r--r--
last change Finish adding header blocks to all files
file annotate diff log raw
nkeynes@30
     1
/**
nkeynes@30
     2
 * $Id: armcore.c,v 1.5 2005-12-25 05:57:00 nkeynes Exp $
nkeynes@30
     3
 * 
nkeynes@30
     4
 * ARM7TDMI CPU emulation core.
nkeynes@30
     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@30
    17
 */
nkeynes@2
    18
nkeynes@7
    19
#include "aica/armcore.h"
nkeynes@2
    20
nkeynes@2
    21
struct arm_registers armr;
nkeynes@2
    22
nkeynes@5
    23
/* NB: The arm has a different memory map, but for the meantime... */
nkeynes@5
    24
/* Page references are as per ARM DDI 0100E (June 2000) */
nkeynes@2
    25
nkeynes@11
    26
#define MEM_READ_BYTE( addr ) arm_read_byte(addr)
nkeynes@11
    27
#define MEM_READ_WORD( addr ) arm_read_word(addr)
nkeynes@11
    28
#define MEM_READ_LONG( addr ) arm_read_long(addr)
nkeynes@11
    29
#define MEM_WRITE_BYTE( addr, val ) arm_write_byte(addr, val)
nkeynes@11
    30
#define MEM_WRITE_WORD( addr, val ) arm_write_word(addr, val)
nkeynes@11
    31
#define MEM_WRITE_LONG( addr, val ) arm_write_long(addr, val)
nkeynes@2
    32
nkeynes@5
    33
nkeynes@5
    34
#define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
nkeynes@5
    35
#define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
nkeynes@5
    36
#define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
nkeynes@5
    37
#define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
nkeynes@5
    38
nkeynes@7
    39
#define PC armr.r[15]
nkeynes@2
    40
nkeynes@5
    41
/* Instruction fields */
nkeynes@5
    42
#define COND(ir) (ir>>28)
nkeynes@5
    43
#define GRP(ir) ((ir>>26)&0x03)
nkeynes@5
    44
#define OPCODE(ir) ((ir>>20)&0x1F)
nkeynes@5
    45
#define IFLAG(ir) (ir&0x02000000)
nkeynes@5
    46
#define SFLAG(ir) (ir&0x00100000)
nkeynes@5
    47
#define PFLAG(ir) (ir&0x01000000)
nkeynes@5
    48
#define UFLAG(ir) (ir&0x00800000)
nkeynes@5
    49
#define BFLAG(ir) (ir&0x00400000)
nkeynes@5
    50
#define WFLAG(ir) (IR&0x00200000)
nkeynes@5
    51
#define LFLAG(ir) SFLAG(ir)
nkeynes@5
    52
#define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
    53
#define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
    54
#define RDn(ir) ((ir>>12)&0x0F)
nkeynes@5
    55
#define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
    56
#define RM(ir) (armr.r[(ir&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
    57
#define LRN(ir) armr.r[((ir>>16)&0x0F)]
nkeynes@5
    58
#define LRD(ir) armr.r[((ir>>12)&0x0F)]
nkeynes@5
    59
#define LRS(ir) armr.r[((ir>>8)&0x0F)]
nkeynes@5
    60
#define LRM(ir) armr.r[(ir&0x0F)]
nkeynes@5
    61
nkeynes@5
    62
#define IMM8(ir) (ir&0xFF)
nkeynes@5
    63
#define IMM12(ir) (ir&0xFFF)
nkeynes@7
    64
#define SHIFTIMM(ir) ((ir>>7)&0x1F)
nkeynes@7
    65
#define IMMROT(ir) ((ir>>7)&0x1E)
nkeynes@5
    66
#define SHIFT(ir) ((ir>>4)&0x07)
nkeynes@5
    67
#define DISP24(ir) ((ir&0x00FFFFFF))
nkeynes@30
    68
#define UNDEF(ir) do{ ERROR( "Raising exception on undefined instruction at %08x, opcode = %04x", PC, ir ); return TRUE; } while(0)
nkeynes@30
    69
#define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); return FALSE; }while(0)
nkeynes@7
    70
nkeynes@11
    71
void arm_restore_cpsr()
nkeynes@11
    72
{
nkeynes@11
    73
nkeynes@11
    74
}
nkeynes@5
    75
nkeynes@5
    76
static uint32_t arm_get_shift_operand( uint32_t ir )
nkeynes@5
    77
{
nkeynes@5
    78
	uint32_t operand, tmp;
nkeynes@5
    79
	if( IFLAG(ir) == 0 ) {
nkeynes@5
    80
		operand = RM(ir);
nkeynes@5
    81
		switch(SHIFT(ir)) {
nkeynes@5
    82
		case 0: /* (Rm << imm) */
nkeynes@5
    83
			operand = operand << SHIFTIMM(ir);
nkeynes@5
    84
			break;
nkeynes@5
    85
		case 1: /* (Rm << Rs) */
nkeynes@5
    86
			tmp = RS(ir)&0xFF;
nkeynes@5
    87
			if( tmp > 31 ) operand = 0;
nkeynes@5
    88
			else operand = operand << tmp;
nkeynes@5
    89
			break;
nkeynes@5
    90
		case 2: /* (Rm >> imm) */
nkeynes@5
    91
			operand = operand >> SHIFTIMM(ir);
nkeynes@5
    92
			break;
nkeynes@5
    93
		case 3: /* (Rm >> Rs) */
nkeynes@5
    94
			tmp = RS(ir) & 0xFF;
nkeynes@5
    95
			if( tmp > 31 ) operand = 0;
nkeynes@5
    96
			else operand = operand >> ir;
nkeynes@5
    97
			break;
nkeynes@5
    98
		case 4: /* (Rm >>> imm) */
nkeynes@5
    99
			tmp = SHIFTIMM(ir);
nkeynes@5
   100
			if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
nkeynes@5
   101
			else operand = ((int32_t)operand) >> tmp;
nkeynes@5
   102
			break;
nkeynes@5
   103
		case 5: /* (Rm >>> Rs) */
nkeynes@5
   104
			tmp = RS(ir) & 0xFF;
nkeynes@5
   105
			if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
nkeynes@5
   106
			else operand = ((int32_t)operand) >> tmp;
nkeynes@5
   107
			break;
nkeynes@5
   108
		case 6:
nkeynes@5
   109
			tmp = SHIFTIMM(ir);
nkeynes@5
   110
			if( tmp == 0 ) /* RRX aka rotate with carry */
nkeynes@7
   111
				operand = (operand >> 1) | (armr.c<<31);
nkeynes@5
   112
			else
nkeynes@5
   113
				operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   114
			break;
nkeynes@5
   115
		case 7:
nkeynes@5
   116
			tmp = RS(ir)&0x1F;
nkeynes@5
   117
			operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   118
			break;
nkeynes@5
   119
		}
nkeynes@5
   120
	} else {
nkeynes@5
   121
		operand = IMM8(ir);
nkeynes@5
   122
		tmp = IMMROT(ir);
nkeynes@5
   123
		operand = ROTATE_RIGHT_LONG(operand, tmp);
nkeynes@5
   124
	}
nkeynes@5
   125
	return operand;
nkeynes@5
   126
}
nkeynes@5
   127
nkeynes@5
   128
/**
nkeynes@5
   129
 * Compute the "shift operand" of the instruction for the data processing
nkeynes@5
   130
 * instructions. This variant also sets armr.shift_c (carry result for shifter)
nkeynes@5
   131
 * Reason for the variants is that most cases don't actually need the shift_c.
nkeynes@5
   132
 */
nkeynes@5
   133
static uint32_t arm_get_shift_operand_s( uint32_t ir )
nkeynes@5
   134
{
nkeynes@5
   135
	uint32_t operand, tmp;
nkeynes@5
   136
	if( IFLAG(ir) == 0 ) {
nkeynes@5
   137
		operand = RM(ir);
nkeynes@5
   138
		switch(SHIFT(ir)) {
nkeynes@5
   139
		case 0: /* (Rm << imm) */
nkeynes@5
   140
			tmp = SHIFTIMM(ir);
nkeynes@5
   141
			if( tmp == 0 ) { /* Rm */
nkeynes@5
   142
				armr.shift_c = armr.c;
nkeynes@5
   143
			} else { /* Rm << imm */
nkeynes@5
   144
				armr.shift_c = (operand >> (32-tmp)) & 0x01;
nkeynes@5
   145
				operand = operand << tmp;
nkeynes@5
   146
			}
nkeynes@5
   147
			break;
nkeynes@5
   148
		case 1: /* (Rm << Rs) */
nkeynes@5
   149
			tmp = RS(ir)&0xFF;
nkeynes@5
   150
			if( tmp == 0 ) {
nkeynes@5
   151
				armr.shift_c = armr.c;
nkeynes@5
   152
			} else {
nkeynes@5
   153
				if( tmp <= 32 )
nkeynes@5
   154
					armr.shift_c = (operand >> (32-tmp)) & 0x01;
nkeynes@5
   155
				else armr.shift_c = 0;
nkeynes@5
   156
				if( tmp < 32 )
nkeynes@5
   157
					operand = operand << tmp;
nkeynes@5
   158
				else operand = 0;
nkeynes@5
   159
			}
nkeynes@5
   160
			break;
nkeynes@5
   161
		case 2: /* (Rm >> imm) */
nkeynes@5
   162
			tmp = SHIFTIMM(ir);
nkeynes@5
   163
			if( tmp == 0 ) {
nkeynes@5
   164
				armr.shift_c = operand >> 31;
nkeynes@5
   165
				operand = 0;
nkeynes@5
   166
			} else {
nkeynes@5
   167
				armr.shift_c = (operand >> (tmp-1)) & 0x01;
nkeynes@5
   168
				operand = RM(ir) >> tmp;
nkeynes@5
   169
			}
nkeynes@5
   170
			break;
nkeynes@5
   171
		case 3: /* (Rm >> Rs) */
nkeynes@5
   172
			tmp = RS(ir) & 0xFF;
nkeynes@5
   173
			if( tmp == 0 ) {
nkeynes@5
   174
				armr.shift_c = armr.c;
nkeynes@5
   175
			} else {
nkeynes@5
   176
				if( tmp <= 32 )
nkeynes@5
   177
					armr.shift_c = (operand >> (tmp-1))&0x01;
nkeynes@5
   178
				else armr.shift_c = 0;
nkeynes@5
   179
				if( tmp < 32 )
nkeynes@5
   180
					operand = operand >> tmp;
nkeynes@5
   181
				else operand = 0;
nkeynes@5
   182
			}
nkeynes@5
   183
			break;
nkeynes@5
   184
		case 4: /* (Rm >>> imm) */
nkeynes@5
   185
			tmp = SHIFTIMM(ir);
nkeynes@5
   186
			if( tmp == 0 ) {
nkeynes@5
   187
				armr.shift_c = operand >> 31;
nkeynes@5
   188
				operand = -armr.shift_c;
nkeynes@5
   189
			} else {
nkeynes@5
   190
				armr.shift_c = (operand >> (tmp-1)) & 0x01;
nkeynes@5
   191
				operand = ((int32_t)operand) >> tmp;
nkeynes@5
   192
			}
nkeynes@5
   193
			break;
nkeynes@5
   194
		case 5: /* (Rm >>> Rs) */
nkeynes@5
   195
			tmp = RS(ir) & 0xFF;
nkeynes@5
   196
			if( tmp == 0 ) {
nkeynes@5
   197
				armr.shift_c = armr.c;
nkeynes@5
   198
			} else {
nkeynes@5
   199
				if( tmp < 32 ) {
nkeynes@5
   200
					armr.shift_c = (operand >> (tmp-1))&0x01;
nkeynes@5
   201
					operand = ((int32_t)operand) >> tmp;
nkeynes@5
   202
				} else {
nkeynes@5
   203
					armr.shift_c = operand >> 31;
nkeynes@5
   204
					operand = ((int32_t)operand) >> 31;
nkeynes@5
   205
				}
nkeynes@5
   206
			}
nkeynes@5
   207
			break;
nkeynes@5
   208
		case 6:
nkeynes@5
   209
			tmp = SHIFTIMM(ir);
nkeynes@5
   210
			if( tmp == 0 ) { /* RRX aka rotate with carry */
nkeynes@5
   211
				armr.shift_c = operand&0x01;
nkeynes@7
   212
				operand = (operand >> 1) | (armr.c<<31);
nkeynes@5
   213
			} else {
nkeynes@5
   214
				armr.shift_c = operand>>(tmp-1);
nkeynes@5
   215
				operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   216
			}
nkeynes@5
   217
			break;
nkeynes@5
   218
		case 7:
nkeynes@5
   219
			tmp = RS(ir)&0xFF;
nkeynes@5
   220
			if( tmp == 0 ) {
nkeynes@5
   221
				armr.shift_c = armr.c;
nkeynes@5
   222
			} else {
nkeynes@5
   223
				tmp &= 0x1F;
nkeynes@5
   224
				if( tmp == 0 ) {
nkeynes@5
   225
					armr.shift_c = operand>>31;
nkeynes@5
   226
				} else {
nkeynes@5
   227
					armr.shift_c = (operand>>(tmp-1))&0x1;
nkeynes@5
   228
					operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   229
				}
nkeynes@5
   230
			}
nkeynes@5
   231
			break;
nkeynes@5
   232
		}
nkeynes@5
   233
	} else {
nkeynes@5
   234
		operand = IMM8(ir);
nkeynes@5
   235
		tmp = IMMROT(ir);
nkeynes@5
   236
		if( tmp == 0 ) {
nkeynes@5
   237
			armr.shift_c = armr.c;
nkeynes@5
   238
		} else {
nkeynes@5
   239
			operand = ROTATE_RIGHT_LONG(operand, tmp);
nkeynes@5
   240
			armr.shift_c = operand>>31;
nkeynes@5
   241
		}
nkeynes@5
   242
	}
nkeynes@5
   243
	return operand;
nkeynes@5
   244
}
nkeynes@5
   245
nkeynes@5
   246
/**
nkeynes@5
   247
 * Another variant of the shifter code for index-based memory addressing.
nkeynes@5
   248
 * Distinguished by the fact that it doesn't support register shifts, and
nkeynes@5
   249
 * ignores the I flag (WTF do the load/store instructions use the I flag to
nkeynes@5
   250
 * mean the _exact opposite_ of what it means for the data processing 
nkeynes@5
   251
 * instructions ???)
nkeynes@5
   252
 */
nkeynes@5
   253
static uint32_t arm_get_address_index( uint32_t ir )
nkeynes@5
   254
{
nkeynes@5
   255
	uint32_t operand = RM(ir);
nkeynes@7
   256
	uint32_t tmp;
nkeynes@7
   257
	
nkeynes@5
   258
	switch(SHIFT(ir)) {
nkeynes@5
   259
	case 0: /* (Rm << imm) */
nkeynes@5
   260
		operand = operand << SHIFTIMM(ir);
nkeynes@5
   261
		break;
nkeynes@5
   262
	case 2: /* (Rm >> imm) */
nkeynes@5
   263
		operand = operand >> SHIFTIMM(ir);
nkeynes@5
   264
		break;
nkeynes@5
   265
	case 4: /* (Rm >>> imm) */
nkeynes@5
   266
		tmp = SHIFTIMM(ir);
nkeynes@5
   267
		if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
nkeynes@5
   268
		else operand = ((int32_t)operand) >> tmp;
nkeynes@5
   269
		break;
nkeynes@5
   270
	case 6:
nkeynes@5
   271
		tmp = SHIFTIMM(ir);
nkeynes@5
   272
		if( tmp == 0 ) /* RRX aka rotate with carry */
nkeynes@7
   273
			operand = (operand >> 1) | (armr.c<<31);
nkeynes@5
   274
		else
nkeynes@5
   275
			operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   276
		break;
nkeynes@5
   277
	default: UNIMP(ir);
nkeynes@5
   278
	}
nkeynes@5
   279
	return operand;	
nkeynes@5
   280
}
nkeynes@5
   281
nkeynes@5
   282
static uint32_t arm_get_address_operand( uint32_t ir )
nkeynes@5
   283
{
nkeynes@5
   284
	uint32_t addr;
nkeynes@5
   285
	
nkeynes@5
   286
	/* I P U . W */
nkeynes@5
   287
	switch( (ir>>21)&0x1D ) {
nkeynes@5
   288
	case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
nkeynes@5
   289
	case 1:
nkeynes@5
   290
		addr = RN(ir);
nkeynes@7
   291
		LRN(ir) = addr - IMM12(ir);
nkeynes@5
   292
		break;
nkeynes@5
   293
	case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
nkeynes@5
   294
	case 5:
nkeynes@5
   295
		addr = RN(ir);
nkeynes@7
   296
		LRN(ir) = addr + IMM12(ir);
nkeynes@5
   297
		break;
nkeynes@5
   298
	case 8: /* Rn - imm offset  [5.2.2 A5-20] */
nkeynes@5
   299
		addr = RN(ir) - IMM12(ir);
nkeynes@5
   300
		break;
nkeynes@5
   301
	case 9: /* Rn -= imm offset (pre-indexed)  [5.2.5 A5-24] */
nkeynes@5
   302
		addr = RN(ir) - IMM12(ir);
nkeynes@7
   303
		LRN(ir) = addr;
nkeynes@5
   304
		break;
nkeynes@5
   305
	case 12: /* Rn + imm offset  [5.2.2 A5-20] */
nkeynes@5
   306
		addr = RN(ir) + IMM12(ir);
nkeynes@5
   307
		break;
nkeynes@5
   308
	case 13: /* Rn += imm offset  [5.2.5 A5-24 ] */
nkeynes@5
   309
		addr = RN(ir) + IMM12(ir);
nkeynes@7
   310
		LRN(ir) = addr;
nkeynes@5
   311
		break;
nkeynes@5
   312
	case 16: /* Rn -= Rm (post-indexed)  [5.2.10 A5-32 ] */
nkeynes@5
   313
	case 17:
nkeynes@5
   314
		addr = RN(ir);
nkeynes@7
   315
		LRN(ir) = addr - arm_get_address_index(ir);
nkeynes@5
   316
		break;
nkeynes@5
   317
	case 20: /* Rn += Rm (post-indexed)  [5.2.10 A5-32 ] */
nkeynes@5
   318
	case 21:
nkeynes@5
   319
		addr = RN(ir);
nkeynes@7
   320
		LRN(ir) = addr - arm_get_address_index(ir);
nkeynes@5
   321
		break;
nkeynes@5
   322
	case 24: /* Rn - Rm  [5.2.4 A5-23] */
nkeynes@5
   323
		addr = RN(ir) - arm_get_address_index(ir);
nkeynes@5
   324
		break;
nkeynes@5
   325
	case 25: /* RN -= Rm (pre-indexed)  [5.2.7 A5-26] */
nkeynes@5
   326
		addr = RN(ir) - arm_get_address_index(ir);
nkeynes@7
   327
		LRN(ir) = addr;
nkeynes@5
   328
		break;
nkeynes@5
   329
	case 28: /* Rn + Rm  [5.2.4 A5-23] */
nkeynes@5
   330
		addr = RN(ir) + arm_get_address_index(ir);
nkeynes@5
   331
		break;
nkeynes@5
   332
	case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
nkeynes@5
   333
		addr = RN(ir) + arm_get_address_index(ir);
nkeynes@7
   334
		LRN(ir) = addr;
nkeynes@5
   335
		break;
nkeynes@5
   336
	default:
nkeynes@5
   337
		UNIMP(ir); /* Unreachable */
nkeynes@5
   338
	}
nkeynes@5
   339
	return addr;
nkeynes@5
   340
}
nkeynes@5
   341
nkeynes@30
   342
gboolean arm_execute_instruction( void ) 
nkeynes@2
   343
{
nkeynes@5
   344
	uint32_t pc = PC;
nkeynes@7
   345
	uint32_t ir = MEM_READ_LONG(pc);
nkeynes@7
   346
	uint32_t operand, operand2, tmp, cond;
nkeynes@2
   347
nkeynes@5
   348
	pc += 4;
nkeynes@5
   349
	PC = pc;
nkeynes@2
   350
nkeynes@5
   351
	switch( COND(ir) ) {
nkeynes@5
   352
		case 0: /* EQ */ 
nkeynes@5
   353
			cond = armr.z;
nkeynes@5
   354
			break;
nkeynes@5
   355
		case 1: /* NE */
nkeynes@5
   356
			cond = !armr.z;
nkeynes@5
   357
			break;
nkeynes@5
   358
		case 2: /* CS/HS */
nkeynes@5
   359
			cond = armr.c;
nkeynes@5
   360
			break;
nkeynes@5
   361
		case 3: /* CC/LO */
nkeynes@5
   362
			cond = !armr.c;
nkeynes@5
   363
			break;
nkeynes@5
   364
		case 4: /* MI */
nkeynes@5
   365
			cond = armr.n;
nkeynes@5
   366
			break;
nkeynes@5
   367
		case 5: /* PL */
nkeynes@5
   368
			cond = !armr.n;
nkeynes@5
   369
			break;
nkeynes@5
   370
		case 6: /* VS */
nkeynes@5
   371
			cond = armr.v;
nkeynes@5
   372
			break;
nkeynes@5
   373
		case 7: /* VC */
nkeynes@5
   374
			cond = !armr.v;
nkeynes@5
   375
			break;
nkeynes@5
   376
		case 8: /* HI */
nkeynes@5
   377
			cond = armr.c && !armr.z;
nkeynes@5
   378
			break;
nkeynes@5
   379
		case 9: /* LS */
nkeynes@5
   380
			cond = (!armr.c) || armr.z;
nkeynes@5
   381
			break;
nkeynes@5
   382
		case 10: /* GE */
nkeynes@5
   383
			cond = (armr.n == armr.v);
nkeynes@5
   384
			break;
nkeynes@5
   385
		case 11: /* LT */
nkeynes@5
   386
			cond = (armr.n != armr.v);
nkeynes@5
   387
			break;
nkeynes@5
   388
		case 12: /* GT */
nkeynes@5
   389
			cond = (!armr.z) && (armr.n == armr.v);
nkeynes@5
   390
			break;
nkeynes@5
   391
		case 13: /* LE */
nkeynes@5
   392
			cond = armr.z || (armr.n != armr.v);
nkeynes@5
   393
			break;
nkeynes@5
   394
		case 14: /* AL */
nkeynes@5
   395
			cond = 1;
nkeynes@5
   396
			break;
nkeynes@5
   397
		case 15: /* (NV) */
nkeynes@5
   398
			cond = 0;
nkeynes@5
   399
			UNDEF(ir);
nkeynes@5
   400
	}
nkeynes@5
   401
nkeynes@5
   402
	switch( GRP(ir) ) {
nkeynes@5
   403
	case 0:
nkeynes@5
   404
		if( (ir & 0x0D900000) == 0x01000000 ) {
nkeynes@5
   405
			/* Instructions that aren't actual data processing */
nkeynes@5
   406
			switch( ir & 0x0FF000F0 ) {
nkeynes@5
   407
			case 0x01200010: /* BX */
nkeynes@5
   408
				break;
nkeynes@5
   409
			case 0x01000000: /* MRS Rd, CPSR */
nkeynes@5
   410
				break;
nkeynes@5
   411
			case 0x01400000: /* MRS Rd, SPSR */
nkeynes@5
   412
				break;
nkeynes@5
   413
			case 0x01200000: /* MSR CPSR, Rd */
nkeynes@5
   414
				break;
nkeynes@5
   415
			case 0x01600000: /* MSR SPSR, Rd */
nkeynes@5
   416
				break;
nkeynes@5
   417
			case 0x03200000: /* MSR CPSR, imm */
nkeynes@5
   418
				break;
nkeynes@5
   419
			case 0x03600000: /* MSR SPSR, imm */
nkeynes@5
   420
				break;
nkeynes@5
   421
			default:
nkeynes@7
   422
				UNIMP(ir);
nkeynes@5
   423
			}
nkeynes@5
   424
		} else if( (ir & 0x0E000090) == 0x00000090 ) {
nkeynes@5
   425
			/* Neither are these */
nkeynes@5
   426
			switch( (ir>>5)&0x03 ) {
nkeynes@5
   427
			case 0:
nkeynes@5
   428
				/* Arithmetic extension area */
nkeynes@5
   429
				switch(OPCODE(ir)) {
nkeynes@5
   430
				case 0: /* MUL */
nkeynes@5
   431
					break;
nkeynes@5
   432
				case 1: /* MULS */
nkeynes@5
   433
					break;
nkeynes@5
   434
				case 2: /* MLA */
nkeynes@5
   435
					break;
nkeynes@5
   436
				case 3: /* MLAS */
nkeynes@5
   437
					break;
nkeynes@5
   438
				case 8: /* UMULL */
nkeynes@5
   439
					break;
nkeynes@5
   440
				case 9: /* UMULLS */
nkeynes@5
   441
					break;
nkeynes@5
   442
				case 10: /* UMLAL */
nkeynes@5
   443
					break;
nkeynes@5
   444
				case 11: /* UMLALS */
nkeynes@5
   445
					break;
nkeynes@5
   446
				case 12: /* SMULL */
nkeynes@5
   447
					break;
nkeynes@5
   448
				case 13: /* SMULLS */
nkeynes@5
   449
					break;
nkeynes@5
   450
				case 14: /* SMLAL */
nkeynes@5
   451
					break;
nkeynes@5
   452
				case 15: /* SMLALS */
nkeynes@5
   453
					break;
nkeynes@5
   454
				case 16: /* SWP */
nkeynes@5
   455
					break;
nkeynes@5
   456
				case 20: /* SWPB */
nkeynes@5
   457
					break;
nkeynes@5
   458
				default:
nkeynes@5
   459
					UNIMP(ir);
nkeynes@5
   460
				}
nkeynes@5
   461
				break;
nkeynes@5
   462
			case 1:
nkeynes@5
   463
				if( LFLAG(ir) ) {
nkeynes@5
   464
					/* LDRH */
nkeynes@5
   465
				} else {
nkeynes@5
   466
					/* STRH */
nkeynes@5
   467
				}
nkeynes@5
   468
				break;
nkeynes@5
   469
			case 2:
nkeynes@5
   470
				if( LFLAG(ir) ) {
nkeynes@5
   471
					/* LDRSB */
nkeynes@5
   472
				} else {
nkeynes@5
   473
					UNIMP(ir);
nkeynes@5
   474
				}
nkeynes@5
   475
				break;
nkeynes@5
   476
			case 3:
nkeynes@5
   477
				if( LFLAG(ir) ) {
nkeynes@5
   478
					/* LDRSH */
nkeynes@5
   479
				} else {
nkeynes@5
   480
					UNIMP(ir);
nkeynes@5
   481
				}
nkeynes@5
   482
				break;
nkeynes@5
   483
			}
nkeynes@5
   484
		} else {
nkeynes@5
   485
			/* Data processing */
nkeynes@5
   486
nkeynes@5
   487
			switch(OPCODE(ir)) {
nkeynes@5
   488
			case 0: /* AND Rd, Rn, operand */
nkeynes@7
   489
				LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
nkeynes@5
   490
				break;
nkeynes@5
   491
			case 1: /* ANDS Rd, Rn, operand */
nkeynes@5
   492
				operand = arm_get_shift_operand_s(ir) & RN(ir);
nkeynes@7
   493
				LRD(ir) = operand;
nkeynes@5
   494
				if( RDn(ir) == 15 ) {
nkeynes@5
   495
					arm_restore_cpsr();
nkeynes@5
   496
				} else {
nkeynes@5
   497
					armr.n = operand>>31;
nkeynes@5
   498
					armr.z = (operand == 0);
nkeynes@5
   499
					armr.c = armr.shift_c;
nkeynes@5
   500
				}
nkeynes@5
   501
				break;
nkeynes@5
   502
			case 2: /* EOR Rd, Rn, operand */
nkeynes@7
   503
				LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
nkeynes@5
   504
				break;
nkeynes@5
   505
			case 3: /* EORS Rd, Rn, operand */
nkeynes@5
   506
				operand = arm_get_shift_operand_s(ir) ^ RN(ir);
nkeynes@7
   507
				LRD(ir) = operand;
nkeynes@5
   508
				if( RDn(ir) == 15 ) {
nkeynes@5
   509
					arm_restore_cpsr();
nkeynes@5
   510
				} else {
nkeynes@5
   511
					armr.n = operand>>31;
nkeynes@5
   512
					armr.z = (operand == 0);
nkeynes@5
   513
					armr.c = armr.shift_c;
nkeynes@5
   514
				}
nkeynes@5
   515
				break;
nkeynes@5
   516
			case 4: /* SUB Rd, Rn, operand */
nkeynes@7
   517
				LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
nkeynes@5
   518
				break;
nkeynes@5
   519
			case 5: /* SUBS Rd, Rn, operand */
nkeynes@5
   520
			    operand = RN(ir);
nkeynes@7
   521
				operand2 = arm_get_shift_operand(ir);
nkeynes@5
   522
				tmp = operand - operand2;
nkeynes@7
   523
				LRD(ir) = tmp;
nkeynes@5
   524
				if( RDn(ir) == 15 ) {
nkeynes@5
   525
					arm_restore_cpsr();
nkeynes@5
   526
				} else {
nkeynes@5
   527
					armr.n = tmp>>31;
nkeynes@5
   528
					armr.z = (tmp == 0);
nkeynes@5
   529
					armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@5
   530
					armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@5
   531
				}
nkeynes@5
   532
				break;
nkeynes@5
   533
			case 6: /* RSB Rd, operand, Rn */
nkeynes@7
   534
				LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
nkeynes@5
   535
				break;
nkeynes@5
   536
			case 7: /* RSBS Rd, operand, Rn */
nkeynes@5
   537
				operand = arm_get_shift_operand(ir);
nkeynes@5
   538
			    operand2 = RN(ir);
nkeynes@5
   539
				tmp = operand - operand2;
nkeynes@7
   540
				LRD(ir) = tmp;
nkeynes@5
   541
				if( RDn(ir) == 15 ) {
nkeynes@5
   542
					arm_restore_cpsr();
nkeynes@5
   543
				} else {
nkeynes@5
   544
					armr.n = tmp>>31;
nkeynes@5
   545
					armr.z = (tmp == 0);
nkeynes@5
   546
					armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@5
   547
					armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@5
   548
				}
nkeynes@5
   549
				break;
nkeynes@5
   550
			case 8: /* ADD Rd, Rn, operand */
nkeynes@7
   551
				LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
nkeynes@5
   552
				break;
nkeynes@5
   553
			case 9: /* ADDS Rd, Rn, operand */
nkeynes@5
   554
				operand = arm_get_shift_operand(ir);
nkeynes@5
   555
			    operand2 = RN(ir);
nkeynes@7
   556
				tmp = operand + operand2;
nkeynes@7
   557
				LRD(ir) = tmp;
nkeynes@5
   558
				if( RDn(ir) == 15 ) {
nkeynes@5
   559
					arm_restore_cpsr();
nkeynes@5
   560
				} else {
nkeynes@5
   561
					armr.n = tmp>>31;
nkeynes@5
   562
					armr.z = (tmp == 0);
nkeynes@5
   563
					armr.c = IS_CARRY(tmp,operand,operand2);
nkeynes@5
   564
					armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
nkeynes@5
   565
				}
nkeynes@5
   566
				break;			
nkeynes@5
   567
			case 10: /* ADC */
nkeynes@5
   568
			case 11: /* ADCS */
nkeynes@5
   569
			case 12: /* SBC */
nkeynes@5
   570
			case 13: /* SBCS */
nkeynes@5
   571
			case 14: /* RSC */
nkeynes@5
   572
			case 15: /* RSCS */
nkeynes@5
   573
				break;
nkeynes@5
   574
			case 17: /* TST Rn, operand */
nkeynes@5
   575
				operand = arm_get_shift_operand_s(ir) & RN(ir);
nkeynes@5
   576
				armr.n = operand>>31;
nkeynes@5
   577
				armr.z = (operand == 0);
nkeynes@5
   578
				armr.c = armr.shift_c;
nkeynes@5
   579
				break;
nkeynes@5
   580
			case 19: /* TEQ Rn, operand */
nkeynes@5
   581
				operand = arm_get_shift_operand_s(ir) ^ RN(ir);
nkeynes@5
   582
				armr.n = operand>>31;
nkeynes@5
   583
				armr.z = (operand == 0);
nkeynes@5
   584
				armr.c = armr.shift_c;
nkeynes@5
   585
				break;				
nkeynes@5
   586
			case 21: /* CMP Rn, operand */
nkeynes@5
   587
			    operand = RN(ir);
nkeynes@7
   588
				operand2 = arm_get_shift_operand(ir);
nkeynes@5
   589
				tmp = operand - operand2;
nkeynes@5
   590
				armr.n = tmp>>31;
nkeynes@5
   591
				armr.z = (tmp == 0);
nkeynes@5
   592
				armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@5
   593
				armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@5
   594
				break;
nkeynes@5
   595
			case 23: /* CMN Rn, operand */
nkeynes@5
   596
			    operand = RN(ir);
nkeynes@7
   597
				operand2 = arm_get_shift_operand(ir);
nkeynes@5
   598
				tmp = operand + operand2;
nkeynes@5
   599
				armr.n = tmp>>31;
nkeynes@5
   600
				armr.z = (tmp == 0);
nkeynes@5
   601
				armr.c = IS_CARRY(tmp,operand,operand2);
nkeynes@5
   602
				armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
nkeynes@5
   603
				break;
nkeynes@5
   604
			case 24: /* ORR Rd, Rn, operand */
nkeynes@7
   605
				LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
nkeynes@5
   606
				break;
nkeynes@5
   607
			case 25: /* ORRS Rd, Rn, operand */
nkeynes@5
   608
				operand = arm_get_shift_operand_s(ir) | RN(ir);
nkeynes@7
   609
				LRD(ir) = operand;
nkeynes@5
   610
				if( RDn(ir) == 15 ) {
nkeynes@5
   611
					arm_restore_cpsr();
nkeynes@5
   612
				} else {
nkeynes@5
   613
					armr.n = operand>>31;
nkeynes@5
   614
					armr.z = (operand == 0);
nkeynes@5
   615
					armr.c = armr.shift_c;
nkeynes@5
   616
				}
nkeynes@5
   617
				break;
nkeynes@5
   618
			case 26: /* MOV Rd, operand */
nkeynes@7
   619
				LRD(ir) = arm_get_shift_operand(ir);
nkeynes@5
   620
				break;
nkeynes@5
   621
			case 27: /* MOVS Rd, operand */
nkeynes@5
   622
				operand = arm_get_shift_operand_s(ir);
nkeynes@7
   623
				LRD(ir) = operand;
nkeynes@5
   624
				if( RDn(ir) == 15 ) {
nkeynes@5
   625
					arm_restore_cpsr();
nkeynes@5
   626
				} else {
nkeynes@5
   627
					armr.n = operand>>31;
nkeynes@5
   628
					armr.z = (operand == 0);
nkeynes@5
   629
					armr.c = armr.shift_c;
nkeynes@5
   630
				}
nkeynes@5
   631
				break;
nkeynes@5
   632
			case 28: /* BIC Rd, Rn, operand */
nkeynes@7
   633
				LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
nkeynes@5
   634
				break;
nkeynes@5
   635
			case 29: /* BICS Rd, Rn, operand */
nkeynes@5
   636
				operand = RN(ir) & (~arm_get_shift_operand_s(ir));
nkeynes@7
   637
				LRD(ir) = operand;
nkeynes@5
   638
				if( RDn(ir) == 15 ) {
nkeynes@5
   639
					arm_restore_cpsr();
nkeynes@5
   640
				} else {
nkeynes@5
   641
					armr.n = operand>>31;
nkeynes@5
   642
					armr.z = (operand == 0);
nkeynes@5
   643
					armr.c = armr.shift_c;
nkeynes@5
   644
				}
nkeynes@5
   645
				break;
nkeynes@5
   646
			case 30: /* MVN Rd, operand */
nkeynes@7
   647
				LRD(ir) = ~arm_get_shift_operand(ir);
nkeynes@5
   648
				break;
nkeynes@5
   649
			case 31: /* MVNS Rd, operand */
nkeynes@5
   650
				operand = ~arm_get_shift_operand_s(ir);
nkeynes@7
   651
				LRD(ir) = operand;
nkeynes@5
   652
				if( RDn(ir) == 15 ) {
nkeynes@5
   653
					arm_restore_cpsr();
nkeynes@5
   654
				} else {
nkeynes@5
   655
					armr.n = operand>>31;
nkeynes@5
   656
					armr.z = (operand == 0);
nkeynes@5
   657
					armr.c = armr.shift_c;
nkeynes@5
   658
				}
nkeynes@5
   659
				break;
nkeynes@5
   660
			default:
nkeynes@5
   661
				UNIMP(ir);
nkeynes@5
   662
			}
nkeynes@5
   663
		}
nkeynes@5
   664
		break;
nkeynes@5
   665
	case 1: /* Load/store */
nkeynes@5
   666
		break;
nkeynes@5
   667
	case 2: /* Load/store multiple, branch*/
nkeynes@5
   668
		break;
nkeynes@5
   669
	case 3: /* Copro */
nkeynes@5
   670
		break;
nkeynes@5
   671
	}
nkeynes@30
   672
	return TRUE;
nkeynes@2
   673
}
.