Search
lxdream.org :: lxdream/src/aica/armcore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/armcore.c
changeset 35:21a4be098304
prev30:89b30313d757
next37:1d84f4c18816
author nkeynes
date Mon Dec 26 03:54:55 2005 +0000 (15 years ago)
permissions -rw-r--r--
last change Remove modules.h - move definitions into dream.h
Add source string to output list (taken from module name)
ARM Work in progress
file annotate diff log raw
nkeynes@30
     1
/**
nkeynes@35
     2
 * $Id: armcore.c,v 1.6 2005-12-26 03:54:55 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@35
    23
void arm_set_mode( int mode );
nkeynes@35
    24
nkeynes@35
    25
uint32_t arm_exceptions[][2] = {{ MODE_SVC, 0x00000000 },
nkeynes@35
    26
				{ MODE_UND, 0x00000004 },
nkeynes@35
    27
				{ MODE_SVC, 0x00000008 },
nkeynes@35
    28
				{ MODE_ABT, 0x0000000C },
nkeynes@35
    29
				{ MODE_ABT, 0x00000010 },
nkeynes@35
    30
				{ MODE_IRQ, 0x00000018 },
nkeynes@35
    31
				{ MODE_FIQ, 0x0000001C } };
nkeynes@35
    32
nkeynes@35
    33
#define EXC_RESET 0
nkeynes@35
    34
#define EXC_UNDEFINED 1
nkeynes@35
    35
#define EXC_SOFTWARE 2
nkeynes@35
    36
#define EXC_PREFETCH_ABORT 3
nkeynes@35
    37
#define EXC_DATA_ABORT 4
nkeynes@35
    38
#define EXC_IRQ 5
nkeynes@35
    39
#define EXC_FAST_IRQ 6
nkeynes@35
    40
nkeynes@35
    41
uint32_t arm_cpu_freq = ARM_BASE_RATE;
nkeynes@35
    42
uint32_t arm_cpu_period = 1000 / ARM_BASE_RATE;
nkeynes@35
    43
nkeynes@35
    44
uint32_t arm_run_slice( uint32_t nanosecs )
nkeynes@35
    45
{
nkeynes@35
    46
    uint32_t target = armr.icount + nanosecs / arm_cpu_period;
nkeynes@35
    47
    uint32_t start = armr.icount;
nkeynes@35
    48
    while( armr.icount < target ) {
nkeynes@35
    49
	armr.icount++;
nkeynes@35
    50
	if( !arm_execute_instruction() )
nkeynes@35
    51
	    break;
nkeynes@35
    52
    }
nkeynes@35
    53
nkeynes@35
    54
    if( target != armr.icount ) {
nkeynes@35
    55
	/* Halted - compute time actually executed */
nkeynes@35
    56
	nanosecs = (armr.icount - start) * arm_cpu_period;
nkeynes@35
    57
    }
nkeynes@35
    58
    return nanosecs;
nkeynes@35
    59
}
nkeynes@35
    60
nkeynes@35
    61
void arm_save_state( FILE *f )
nkeynes@35
    62
{
nkeynes@35
    63
    fwrite( &armr, sizeof(armr), 1, f );
nkeynes@35
    64
}
nkeynes@35
    65
nkeynes@35
    66
int arm_load_state( FILE *f )
nkeynes@35
    67
{
nkeynes@35
    68
    fread( &armr, sizeof(armr), 1, f );
nkeynes@35
    69
    return 0;
nkeynes@35
    70
}
nkeynes@35
    71
nkeynes@35
    72
/* Exceptions */
nkeynes@35
    73
void arm_reset( void )
nkeynes@35
    74
{
nkeynes@35
    75
    /* Wipe all processor state */
nkeynes@35
    76
    memset( &armr, 0, sizeof(armr) );
nkeynes@35
    77
nkeynes@35
    78
    armr.cpsr = MODE_SVC | CPSR_I | CPSR_F;
nkeynes@35
    79
    armr.r[15] = 0x00000000;
nkeynes@35
    80
}
nkeynes@35
    81
nkeynes@35
    82
/**
nkeynes@35
    83
 * Raise an ARM exception (other than reset, which uses arm_reset().
nkeynes@35
    84
 * @param exception one of the EXC_* exception codes defined above.
nkeynes@35
    85
 */
nkeynes@35
    86
void arm_raise_exception( int exception )
nkeynes@35
    87
{
nkeynes@35
    88
    int mode = arm_exceptions[exception][0];
nkeynes@35
    89
    arm_set_mode( mode );
nkeynes@35
    90
    armr.spsr = armr.cpsr;
nkeynes@35
    91
    armr.r[14] = armr.r[15];
nkeynes@35
    92
    armr.cpsr = (armr.cpsr & (~CPSR_T)) | CPSR_I; 
nkeynes@35
    93
    if( mode == MODE_FIQ )
nkeynes@35
    94
	armr.cpsr |= CPSR_F;
nkeynes@35
    95
    armr.r[15] = arm_exceptions[exception][1];
nkeynes@35
    96
}
nkeynes@35
    97
nkeynes@35
    98
/**
nkeynes@35
    99
 * Restore CPSR from SPSR, effectively (under most circumstances) executing
nkeynes@35
   100
 * a return-from-exception.
nkeynes@35
   101
 */
nkeynes@35
   102
void arm_restore_cpsr()
nkeynes@35
   103
{
nkeynes@35
   104
    int spsr = armr.spsr;
nkeynes@35
   105
    int mode = spsr & CPSR_MODE;
nkeynes@35
   106
    
nkeynes@35
   107
    arm_set_mode( mode );
nkeynes@35
   108
    armr.cpsr = spsr;
nkeynes@35
   109
}
nkeynes@35
   110
nkeynes@35
   111
nkeynes@35
   112
nkeynes@35
   113
/**
nkeynes@35
   114
 * Change the current executing ARM mode to the requested mode.
nkeynes@35
   115
 * Saves any required registers to banks and restores those for the
nkeynes@35
   116
 * correct mode. (Note does not actually update CPSR at the moment).
nkeynes@35
   117
 */
nkeynes@35
   118
void arm_set_mode( int targetMode )
nkeynes@35
   119
{
nkeynes@35
   120
    int currentMode = armr.cpsr & CPSR_MODE;
nkeynes@35
   121
    if( currentMode == targetMode )
nkeynes@35
   122
	return;
nkeynes@35
   123
nkeynes@35
   124
    switch( currentMode ) {
nkeynes@35
   125
    case MODE_USER:
nkeynes@35
   126
    case MODE_SYS:
nkeynes@35
   127
	armr.user_r[5] = armr.r[13];
nkeynes@35
   128
	armr.user_r[6] = armr.r[14];
nkeynes@35
   129
	break;
nkeynes@35
   130
    case MODE_SVC:
nkeynes@35
   131
	armr.svc_r[0] = armr.r[13];
nkeynes@35
   132
	armr.svc_r[1] = armr.r[14];
nkeynes@35
   133
	armr.svc_r[2] = armr.spsr;
nkeynes@35
   134
	break;
nkeynes@35
   135
    case MODE_ABT:
nkeynes@35
   136
	armr.abt_r[0] = armr.r[13];
nkeynes@35
   137
	armr.abt_r[1] = armr.r[14];
nkeynes@35
   138
	armr.abt_r[2] = armr.spsr;
nkeynes@35
   139
	break;
nkeynes@35
   140
    case MODE_UND:
nkeynes@35
   141
	armr.und_r[0] = armr.r[13];
nkeynes@35
   142
	armr.und_r[1] = armr.r[14];
nkeynes@35
   143
	armr.und_r[2] = armr.spsr;
nkeynes@35
   144
	break;
nkeynes@35
   145
    case MODE_IRQ:
nkeynes@35
   146
	armr.irq_r[0] = armr.r[13];
nkeynes@35
   147
	armr.irq_r[1] = armr.r[14];
nkeynes@35
   148
	armr.irq_r[2] = armr.spsr;
nkeynes@35
   149
	break;
nkeynes@35
   150
    case MODE_FIQ:
nkeynes@35
   151
	armr.fiq_r[0] = armr.r[8];
nkeynes@35
   152
	armr.fiq_r[1] = armr.r[9];
nkeynes@35
   153
	armr.fiq_r[2] = armr.r[10];
nkeynes@35
   154
	armr.fiq_r[3] = armr.r[11];
nkeynes@35
   155
	armr.fiq_r[4] = armr.r[12];
nkeynes@35
   156
	armr.fiq_r[5] = armr.r[13];
nkeynes@35
   157
	armr.fiq_r[6] = armr.r[14];
nkeynes@35
   158
	armr.fiq_r[7] = armr.spsr;
nkeynes@35
   159
	armr.r[8] = armr.user_r[0];
nkeynes@35
   160
	armr.r[9] = armr.user_r[1];
nkeynes@35
   161
	armr.r[10] = armr.user_r[2];
nkeynes@35
   162
	armr.r[11] = armr.user_r[3];
nkeynes@35
   163
	armr.r[12] = armr.user_r[4];
nkeynes@35
   164
	break;
nkeynes@35
   165
    }
nkeynes@35
   166
    
nkeynes@35
   167
    switch( targetMode ) {
nkeynes@35
   168
    case MODE_USER:
nkeynes@35
   169
    case MODE_SYS:
nkeynes@35
   170
	armr.r[13] = armr.user_r[5];
nkeynes@35
   171
	armr.r[14] = armr.user_r[6];
nkeynes@35
   172
	break;
nkeynes@35
   173
    case MODE_SVC:
nkeynes@35
   174
	armr.r[13] = armr.svc_r[0];
nkeynes@35
   175
	armr.r[14] = armr.svc_r[1];
nkeynes@35
   176
	armr.spsr = armr.svc_r[2];
nkeynes@35
   177
	break;
nkeynes@35
   178
    case MODE_ABT:
nkeynes@35
   179
	armr.r[13] = armr.abt_r[0];
nkeynes@35
   180
	armr.r[14] = armr.abt_r[1];
nkeynes@35
   181
	armr.spsr = armr.abt_r[2];
nkeynes@35
   182
	break;
nkeynes@35
   183
    case MODE_UND:
nkeynes@35
   184
	armr.r[13] = armr.und_r[0];
nkeynes@35
   185
	armr.r[14] = armr.und_r[1];
nkeynes@35
   186
	armr.spsr = armr.und_r[2];
nkeynes@35
   187
	break;
nkeynes@35
   188
    case MODE_IRQ:
nkeynes@35
   189
	armr.r[13] = armr.irq_r[0];
nkeynes@35
   190
	armr.r[14] = armr.irq_r[1];
nkeynes@35
   191
	armr.spsr = armr.irq_r[2];
nkeynes@35
   192
	break;
nkeynes@35
   193
    case MODE_FIQ:
nkeynes@35
   194
	armr.user_r[0] = armr.r[8];
nkeynes@35
   195
	armr.user_r[1] = armr.r[9];
nkeynes@35
   196
	armr.user_r[2] = armr.r[10];
nkeynes@35
   197
	armr.user_r[3] = armr.r[11];
nkeynes@35
   198
	armr.user_r[4] = armr.r[12];
nkeynes@35
   199
	armr.r[8] = armr.fiq_r[0];
nkeynes@35
   200
	armr.r[9] = armr.fiq_r[1];
nkeynes@35
   201
	armr.r[10] = armr.fiq_r[2];
nkeynes@35
   202
	armr.r[11] = armr.fiq_r[3];
nkeynes@35
   203
	armr.r[12] = armr.fiq_r[4];
nkeynes@35
   204
	armr.r[13] = armr.fiq_r[5];
nkeynes@35
   205
	armr.r[14] = armr.fiq_r[6];
nkeynes@35
   206
	armr.spsr = armr.fiq_r[7];
nkeynes@35
   207
	break;
nkeynes@35
   208
    }
nkeynes@35
   209
}
nkeynes@35
   210
nkeynes@5
   211
/* Page references are as per ARM DDI 0100E (June 2000) */
nkeynes@2
   212
nkeynes@11
   213
#define MEM_READ_BYTE( addr ) arm_read_byte(addr)
nkeynes@11
   214
#define MEM_READ_WORD( addr ) arm_read_word(addr)
nkeynes@11
   215
#define MEM_READ_LONG( addr ) arm_read_long(addr)
nkeynes@11
   216
#define MEM_WRITE_BYTE( addr, val ) arm_write_byte(addr, val)
nkeynes@11
   217
#define MEM_WRITE_WORD( addr, val ) arm_write_word(addr, val)
nkeynes@11
   218
#define MEM_WRITE_LONG( addr, val ) arm_write_long(addr, val)
nkeynes@2
   219
nkeynes@5
   220
nkeynes@5
   221
#define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
nkeynes@5
   222
#define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
nkeynes@5
   223
#define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
nkeynes@5
   224
#define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
nkeynes@5
   225
nkeynes@7
   226
#define PC armr.r[15]
nkeynes@2
   227
nkeynes@5
   228
/* Instruction fields */
nkeynes@5
   229
#define COND(ir) (ir>>28)
nkeynes@5
   230
#define GRP(ir) ((ir>>26)&0x03)
nkeynes@5
   231
#define OPCODE(ir) ((ir>>20)&0x1F)
nkeynes@5
   232
#define IFLAG(ir) (ir&0x02000000)
nkeynes@5
   233
#define SFLAG(ir) (ir&0x00100000)
nkeynes@5
   234
#define PFLAG(ir) (ir&0x01000000)
nkeynes@5
   235
#define UFLAG(ir) (ir&0x00800000)
nkeynes@5
   236
#define BFLAG(ir) (ir&0x00400000)
nkeynes@5
   237
#define WFLAG(ir) (IR&0x00200000)
nkeynes@5
   238
#define LFLAG(ir) SFLAG(ir)
nkeynes@5
   239
#define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
   240
#define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
   241
#define RDn(ir) ((ir>>12)&0x0F)
nkeynes@5
   242
#define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
   243
#define RM(ir) (armr.r[(ir&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
   244
#define LRN(ir) armr.r[((ir>>16)&0x0F)]
nkeynes@5
   245
#define LRD(ir) armr.r[((ir>>12)&0x0F)]
nkeynes@5
   246
#define LRS(ir) armr.r[((ir>>8)&0x0F)]
nkeynes@5
   247
#define LRM(ir) armr.r[(ir&0x0F)]
nkeynes@5
   248
nkeynes@5
   249
#define IMM8(ir) (ir&0xFF)
nkeynes@5
   250
#define IMM12(ir) (ir&0xFFF)
nkeynes@7
   251
#define SHIFTIMM(ir) ((ir>>7)&0x1F)
nkeynes@7
   252
#define IMMROT(ir) ((ir>>7)&0x1E)
nkeynes@5
   253
#define SHIFT(ir) ((ir>>4)&0x07)
nkeynes@5
   254
#define DISP24(ir) ((ir&0x00FFFFFF))
nkeynes@30
   255
#define UNDEF(ir) do{ ERROR( "Raising exception on undefined instruction at %08x, opcode = %04x", PC, ir ); return TRUE; } while(0)
nkeynes@30
   256
#define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); return FALSE; }while(0)
nkeynes@7
   257
nkeynes@5
   258
static uint32_t arm_get_shift_operand( uint32_t ir )
nkeynes@5
   259
{
nkeynes@5
   260
	uint32_t operand, tmp;
nkeynes@5
   261
	if( IFLAG(ir) == 0 ) {
nkeynes@5
   262
		operand = RM(ir);
nkeynes@5
   263
		switch(SHIFT(ir)) {
nkeynes@5
   264
		case 0: /* (Rm << imm) */
nkeynes@5
   265
			operand = operand << SHIFTIMM(ir);
nkeynes@5
   266
			break;
nkeynes@5
   267
		case 1: /* (Rm << Rs) */
nkeynes@5
   268
			tmp = RS(ir)&0xFF;
nkeynes@5
   269
			if( tmp > 31 ) operand = 0;
nkeynes@5
   270
			else operand = operand << tmp;
nkeynes@5
   271
			break;
nkeynes@5
   272
		case 2: /* (Rm >> imm) */
nkeynes@5
   273
			operand = operand >> SHIFTIMM(ir);
nkeynes@5
   274
			break;
nkeynes@5
   275
		case 3: /* (Rm >> Rs) */
nkeynes@5
   276
			tmp = RS(ir) & 0xFF;
nkeynes@5
   277
			if( tmp > 31 ) operand = 0;
nkeynes@5
   278
			else operand = operand >> ir;
nkeynes@5
   279
			break;
nkeynes@5
   280
		case 4: /* (Rm >>> imm) */
nkeynes@5
   281
			tmp = SHIFTIMM(ir);
nkeynes@5
   282
			if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
nkeynes@5
   283
			else operand = ((int32_t)operand) >> tmp;
nkeynes@5
   284
			break;
nkeynes@5
   285
		case 5: /* (Rm >>> Rs) */
nkeynes@5
   286
			tmp = RS(ir) & 0xFF;
nkeynes@5
   287
			if( tmp > 31 ) operand = ((int32_t)operand) >> 31;
nkeynes@5
   288
			else operand = ((int32_t)operand) >> tmp;
nkeynes@5
   289
			break;
nkeynes@5
   290
		case 6:
nkeynes@5
   291
			tmp = SHIFTIMM(ir);
nkeynes@5
   292
			if( tmp == 0 ) /* RRX aka rotate with carry */
nkeynes@7
   293
				operand = (operand >> 1) | (armr.c<<31);
nkeynes@5
   294
			else
nkeynes@5
   295
				operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   296
			break;
nkeynes@5
   297
		case 7:
nkeynes@5
   298
			tmp = RS(ir)&0x1F;
nkeynes@5
   299
			operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   300
			break;
nkeynes@5
   301
		}
nkeynes@5
   302
	} else {
nkeynes@5
   303
		operand = IMM8(ir);
nkeynes@5
   304
		tmp = IMMROT(ir);
nkeynes@5
   305
		operand = ROTATE_RIGHT_LONG(operand, tmp);
nkeynes@5
   306
	}
nkeynes@5
   307
	return operand;
nkeynes@5
   308
}
nkeynes@5
   309
nkeynes@5
   310
/**
nkeynes@5
   311
 * Compute the "shift operand" of the instruction for the data processing
nkeynes@5
   312
 * instructions. This variant also sets armr.shift_c (carry result for shifter)
nkeynes@5
   313
 * Reason for the variants is that most cases don't actually need the shift_c.
nkeynes@5
   314
 */
nkeynes@5
   315
static uint32_t arm_get_shift_operand_s( uint32_t ir )
nkeynes@5
   316
{
nkeynes@5
   317
	uint32_t operand, tmp;
nkeynes@5
   318
	if( IFLAG(ir) == 0 ) {
nkeynes@5
   319
		operand = RM(ir);
nkeynes@5
   320
		switch(SHIFT(ir)) {
nkeynes@5
   321
		case 0: /* (Rm << imm) */
nkeynes@5
   322
			tmp = SHIFTIMM(ir);
nkeynes@5
   323
			if( tmp == 0 ) { /* Rm */
nkeynes@5
   324
				armr.shift_c = armr.c;
nkeynes@5
   325
			} else { /* Rm << imm */
nkeynes@5
   326
				armr.shift_c = (operand >> (32-tmp)) & 0x01;
nkeynes@5
   327
				operand = operand << tmp;
nkeynes@5
   328
			}
nkeynes@5
   329
			break;
nkeynes@5
   330
		case 1: /* (Rm << Rs) */
nkeynes@5
   331
			tmp = RS(ir)&0xFF;
nkeynes@5
   332
			if( tmp == 0 ) {
nkeynes@5
   333
				armr.shift_c = armr.c;
nkeynes@5
   334
			} else {
nkeynes@5
   335
				if( tmp <= 32 )
nkeynes@5
   336
					armr.shift_c = (operand >> (32-tmp)) & 0x01;
nkeynes@5
   337
				else armr.shift_c = 0;
nkeynes@5
   338
				if( tmp < 32 )
nkeynes@5
   339
					operand = operand << tmp;
nkeynes@5
   340
				else operand = 0;
nkeynes@5
   341
			}
nkeynes@5
   342
			break;
nkeynes@5
   343
		case 2: /* (Rm >> imm) */
nkeynes@5
   344
			tmp = SHIFTIMM(ir);
nkeynes@5
   345
			if( tmp == 0 ) {
nkeynes@5
   346
				armr.shift_c = operand >> 31;
nkeynes@5
   347
				operand = 0;
nkeynes@5
   348
			} else {
nkeynes@5
   349
				armr.shift_c = (operand >> (tmp-1)) & 0x01;
nkeynes@5
   350
				operand = RM(ir) >> tmp;
nkeynes@5
   351
			}
nkeynes@5
   352
			break;
nkeynes@5
   353
		case 3: /* (Rm >> Rs) */
nkeynes@5
   354
			tmp = RS(ir) & 0xFF;
nkeynes@5
   355
			if( tmp == 0 ) {
nkeynes@5
   356
				armr.shift_c = armr.c;
nkeynes@5
   357
			} else {
nkeynes@5
   358
				if( tmp <= 32 )
nkeynes@5
   359
					armr.shift_c = (operand >> (tmp-1))&0x01;
nkeynes@5
   360
				else armr.shift_c = 0;
nkeynes@5
   361
				if( tmp < 32 )
nkeynes@5
   362
					operand = operand >> tmp;
nkeynes@5
   363
				else operand = 0;
nkeynes@5
   364
			}
nkeynes@5
   365
			break;
nkeynes@5
   366
		case 4: /* (Rm >>> imm) */
nkeynes@5
   367
			tmp = SHIFTIMM(ir);
nkeynes@5
   368
			if( tmp == 0 ) {
nkeynes@5
   369
				armr.shift_c = operand >> 31;
nkeynes@5
   370
				operand = -armr.shift_c;
nkeynes@5
   371
			} else {
nkeynes@5
   372
				armr.shift_c = (operand >> (tmp-1)) & 0x01;
nkeynes@5
   373
				operand = ((int32_t)operand) >> tmp;
nkeynes@5
   374
			}
nkeynes@5
   375
			break;
nkeynes@5
   376
		case 5: /* (Rm >>> Rs) */
nkeynes@5
   377
			tmp = RS(ir) & 0xFF;
nkeynes@5
   378
			if( tmp == 0 ) {
nkeynes@5
   379
				armr.shift_c = armr.c;
nkeynes@5
   380
			} else {
nkeynes@5
   381
				if( tmp < 32 ) {
nkeynes@5
   382
					armr.shift_c = (operand >> (tmp-1))&0x01;
nkeynes@5
   383
					operand = ((int32_t)operand) >> tmp;
nkeynes@5
   384
				} else {
nkeynes@5
   385
					armr.shift_c = operand >> 31;
nkeynes@5
   386
					operand = ((int32_t)operand) >> 31;
nkeynes@5
   387
				}
nkeynes@5
   388
			}
nkeynes@5
   389
			break;
nkeynes@5
   390
		case 6:
nkeynes@5
   391
			tmp = SHIFTIMM(ir);
nkeynes@5
   392
			if( tmp == 0 ) { /* RRX aka rotate with carry */
nkeynes@5
   393
				armr.shift_c = operand&0x01;
nkeynes@7
   394
				operand = (operand >> 1) | (armr.c<<31);
nkeynes@5
   395
			} else {
nkeynes@5
   396
				armr.shift_c = operand>>(tmp-1);
nkeynes@5
   397
				operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   398
			}
nkeynes@5
   399
			break;
nkeynes@5
   400
		case 7:
nkeynes@5
   401
			tmp = RS(ir)&0xFF;
nkeynes@5
   402
			if( tmp == 0 ) {
nkeynes@5
   403
				armr.shift_c = armr.c;
nkeynes@5
   404
			} else {
nkeynes@5
   405
				tmp &= 0x1F;
nkeynes@5
   406
				if( tmp == 0 ) {
nkeynes@5
   407
					armr.shift_c = operand>>31;
nkeynes@5
   408
				} else {
nkeynes@5
   409
					armr.shift_c = (operand>>(tmp-1))&0x1;
nkeynes@5
   410
					operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   411
				}
nkeynes@5
   412
			}
nkeynes@5
   413
			break;
nkeynes@5
   414
		}
nkeynes@5
   415
	} else {
nkeynes@5
   416
		operand = IMM8(ir);
nkeynes@5
   417
		tmp = IMMROT(ir);
nkeynes@5
   418
		if( tmp == 0 ) {
nkeynes@5
   419
			armr.shift_c = armr.c;
nkeynes@5
   420
		} else {
nkeynes@5
   421
			operand = ROTATE_RIGHT_LONG(operand, tmp);
nkeynes@5
   422
			armr.shift_c = operand>>31;
nkeynes@5
   423
		}
nkeynes@5
   424
	}
nkeynes@5
   425
	return operand;
nkeynes@5
   426
}
nkeynes@5
   427
nkeynes@5
   428
/**
nkeynes@5
   429
 * Another variant of the shifter code for index-based memory addressing.
nkeynes@5
   430
 * Distinguished by the fact that it doesn't support register shifts, and
nkeynes@5
   431
 * ignores the I flag (WTF do the load/store instructions use the I flag to
nkeynes@5
   432
 * mean the _exact opposite_ of what it means for the data processing 
nkeynes@5
   433
 * instructions ???)
nkeynes@5
   434
 */
nkeynes@5
   435
static uint32_t arm_get_address_index( uint32_t ir )
nkeynes@5
   436
{
nkeynes@5
   437
	uint32_t operand = RM(ir);
nkeynes@7
   438
	uint32_t tmp;
nkeynes@7
   439
	
nkeynes@5
   440
	switch(SHIFT(ir)) {
nkeynes@5
   441
	case 0: /* (Rm << imm) */
nkeynes@5
   442
		operand = operand << SHIFTIMM(ir);
nkeynes@5
   443
		break;
nkeynes@5
   444
	case 2: /* (Rm >> imm) */
nkeynes@5
   445
		operand = operand >> SHIFTIMM(ir);
nkeynes@5
   446
		break;
nkeynes@5
   447
	case 4: /* (Rm >>> imm) */
nkeynes@5
   448
		tmp = SHIFTIMM(ir);
nkeynes@5
   449
		if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
nkeynes@5
   450
		else operand = ((int32_t)operand) >> tmp;
nkeynes@5
   451
		break;
nkeynes@5
   452
	case 6:
nkeynes@5
   453
		tmp = SHIFTIMM(ir);
nkeynes@5
   454
		if( tmp == 0 ) /* RRX aka rotate with carry */
nkeynes@7
   455
			operand = (operand >> 1) | (armr.c<<31);
nkeynes@5
   456
		else
nkeynes@5
   457
			operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   458
		break;
nkeynes@5
   459
	default: UNIMP(ir);
nkeynes@5
   460
	}
nkeynes@5
   461
	return operand;	
nkeynes@5
   462
}
nkeynes@5
   463
nkeynes@5
   464
static uint32_t arm_get_address_operand( uint32_t ir )
nkeynes@5
   465
{
nkeynes@5
   466
	uint32_t addr;
nkeynes@5
   467
	
nkeynes@5
   468
	/* I P U . W */
nkeynes@5
   469
	switch( (ir>>21)&0x1D ) {
nkeynes@5
   470
	case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
nkeynes@5
   471
	case 1:
nkeynes@5
   472
		addr = RN(ir);
nkeynes@7
   473
		LRN(ir) = addr - IMM12(ir);
nkeynes@5
   474
		break;
nkeynes@5
   475
	case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
nkeynes@5
   476
	case 5:
nkeynes@5
   477
		addr = RN(ir);
nkeynes@7
   478
		LRN(ir) = addr + IMM12(ir);
nkeynes@5
   479
		break;
nkeynes@5
   480
	case 8: /* Rn - imm offset  [5.2.2 A5-20] */
nkeynes@5
   481
		addr = RN(ir) - IMM12(ir);
nkeynes@5
   482
		break;
nkeynes@5
   483
	case 9: /* Rn -= imm offset (pre-indexed)  [5.2.5 A5-24] */
nkeynes@5
   484
		addr = RN(ir) - IMM12(ir);
nkeynes@7
   485
		LRN(ir) = addr;
nkeynes@5
   486
		break;
nkeynes@5
   487
	case 12: /* Rn + imm offset  [5.2.2 A5-20] */
nkeynes@5
   488
		addr = RN(ir) + IMM12(ir);
nkeynes@5
   489
		break;
nkeynes@5
   490
	case 13: /* Rn += imm offset  [5.2.5 A5-24 ] */
nkeynes@5
   491
		addr = RN(ir) + IMM12(ir);
nkeynes@7
   492
		LRN(ir) = addr;
nkeynes@5
   493
		break;
nkeynes@5
   494
	case 16: /* Rn -= Rm (post-indexed)  [5.2.10 A5-32 ] */
nkeynes@5
   495
	case 17:
nkeynes@5
   496
		addr = RN(ir);
nkeynes@7
   497
		LRN(ir) = addr - arm_get_address_index(ir);
nkeynes@5
   498
		break;
nkeynes@5
   499
	case 20: /* Rn += Rm (post-indexed)  [5.2.10 A5-32 ] */
nkeynes@5
   500
	case 21:
nkeynes@5
   501
		addr = RN(ir);
nkeynes@7
   502
		LRN(ir) = addr - arm_get_address_index(ir);
nkeynes@5
   503
		break;
nkeynes@5
   504
	case 24: /* Rn - Rm  [5.2.4 A5-23] */
nkeynes@5
   505
		addr = RN(ir) - arm_get_address_index(ir);
nkeynes@5
   506
		break;
nkeynes@5
   507
	case 25: /* RN -= Rm (pre-indexed)  [5.2.7 A5-26] */
nkeynes@5
   508
		addr = RN(ir) - arm_get_address_index(ir);
nkeynes@7
   509
		LRN(ir) = addr;
nkeynes@5
   510
		break;
nkeynes@5
   511
	case 28: /* Rn + Rm  [5.2.4 A5-23] */
nkeynes@5
   512
		addr = RN(ir) + arm_get_address_index(ir);
nkeynes@5
   513
		break;
nkeynes@5
   514
	case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
nkeynes@5
   515
		addr = RN(ir) + arm_get_address_index(ir);
nkeynes@7
   516
		LRN(ir) = addr;
nkeynes@5
   517
		break;
nkeynes@5
   518
	default:
nkeynes@5
   519
		UNIMP(ir); /* Unreachable */
nkeynes@5
   520
	}
nkeynes@5
   521
	return addr;
nkeynes@5
   522
}
nkeynes@5
   523
nkeynes@30
   524
gboolean arm_execute_instruction( void ) 
nkeynes@2
   525
{
nkeynes@5
   526
	uint32_t pc = PC;
nkeynes@7
   527
	uint32_t ir = MEM_READ_LONG(pc);
nkeynes@7
   528
	uint32_t operand, operand2, tmp, cond;
nkeynes@2
   529
nkeynes@5
   530
	pc += 4;
nkeynes@5
   531
	PC = pc;
nkeynes@2
   532
nkeynes@5
   533
	switch( COND(ir) ) {
nkeynes@5
   534
		case 0: /* EQ */ 
nkeynes@5
   535
			cond = armr.z;
nkeynes@5
   536
			break;
nkeynes@5
   537
		case 1: /* NE */
nkeynes@5
   538
			cond = !armr.z;
nkeynes@5
   539
			break;
nkeynes@5
   540
		case 2: /* CS/HS */
nkeynes@5
   541
			cond = armr.c;
nkeynes@5
   542
			break;
nkeynes@5
   543
		case 3: /* CC/LO */
nkeynes@5
   544
			cond = !armr.c;
nkeynes@5
   545
			break;
nkeynes@5
   546
		case 4: /* MI */
nkeynes@5
   547
			cond = armr.n;
nkeynes@5
   548
			break;
nkeynes@5
   549
		case 5: /* PL */
nkeynes@5
   550
			cond = !armr.n;
nkeynes@5
   551
			break;
nkeynes@5
   552
		case 6: /* VS */
nkeynes@5
   553
			cond = armr.v;
nkeynes@5
   554
			break;
nkeynes@5
   555
		case 7: /* VC */
nkeynes@5
   556
			cond = !armr.v;
nkeynes@5
   557
			break;
nkeynes@5
   558
		case 8: /* HI */
nkeynes@5
   559
			cond = armr.c && !armr.z;
nkeynes@5
   560
			break;
nkeynes@5
   561
		case 9: /* LS */
nkeynes@5
   562
			cond = (!armr.c) || armr.z;
nkeynes@5
   563
			break;
nkeynes@5
   564
		case 10: /* GE */
nkeynes@5
   565
			cond = (armr.n == armr.v);
nkeynes@5
   566
			break;
nkeynes@5
   567
		case 11: /* LT */
nkeynes@5
   568
			cond = (armr.n != armr.v);
nkeynes@5
   569
			break;
nkeynes@5
   570
		case 12: /* GT */
nkeynes@5
   571
			cond = (!armr.z) && (armr.n == armr.v);
nkeynes@5
   572
			break;
nkeynes@5
   573
		case 13: /* LE */
nkeynes@5
   574
			cond = armr.z || (armr.n != armr.v);
nkeynes@5
   575
			break;
nkeynes@5
   576
		case 14: /* AL */
nkeynes@5
   577
			cond = 1;
nkeynes@5
   578
			break;
nkeynes@5
   579
		case 15: /* (NV) */
nkeynes@5
   580
			cond = 0;
nkeynes@5
   581
			UNDEF(ir);
nkeynes@5
   582
	}
nkeynes@5
   583
nkeynes@5
   584
	switch( GRP(ir) ) {
nkeynes@5
   585
	case 0:
nkeynes@5
   586
		if( (ir & 0x0D900000) == 0x01000000 ) {
nkeynes@5
   587
			/* Instructions that aren't actual data processing */
nkeynes@5
   588
			switch( ir & 0x0FF000F0 ) {
nkeynes@5
   589
			case 0x01200010: /* BX */
nkeynes@5
   590
				break;
nkeynes@5
   591
			case 0x01000000: /* MRS Rd, CPSR */
nkeynes@5
   592
				break;
nkeynes@5
   593
			case 0x01400000: /* MRS Rd, SPSR */
nkeynes@5
   594
				break;
nkeynes@5
   595
			case 0x01200000: /* MSR CPSR, Rd */
nkeynes@5
   596
				break;
nkeynes@5
   597
			case 0x01600000: /* MSR SPSR, Rd */
nkeynes@5
   598
				break;
nkeynes@5
   599
			case 0x03200000: /* MSR CPSR, imm */
nkeynes@5
   600
				break;
nkeynes@5
   601
			case 0x03600000: /* MSR SPSR, imm */
nkeynes@5
   602
				break;
nkeynes@5
   603
			default:
nkeynes@7
   604
				UNIMP(ir);
nkeynes@5
   605
			}
nkeynes@5
   606
		} else if( (ir & 0x0E000090) == 0x00000090 ) {
nkeynes@5
   607
			/* Neither are these */
nkeynes@5
   608
			switch( (ir>>5)&0x03 ) {
nkeynes@5
   609
			case 0:
nkeynes@5
   610
				/* Arithmetic extension area */
nkeynes@5
   611
				switch(OPCODE(ir)) {
nkeynes@5
   612
				case 0: /* MUL */
nkeynes@5
   613
					break;
nkeynes@5
   614
				case 1: /* MULS */
nkeynes@5
   615
					break;
nkeynes@5
   616
				case 2: /* MLA */
nkeynes@5
   617
					break;
nkeynes@5
   618
				case 3: /* MLAS */
nkeynes@5
   619
					break;
nkeynes@5
   620
				case 8: /* UMULL */
nkeynes@5
   621
					break;
nkeynes@5
   622
				case 9: /* UMULLS */
nkeynes@5
   623
					break;
nkeynes@5
   624
				case 10: /* UMLAL */
nkeynes@5
   625
					break;
nkeynes@5
   626
				case 11: /* UMLALS */
nkeynes@5
   627
					break;
nkeynes@5
   628
				case 12: /* SMULL */
nkeynes@5
   629
					break;
nkeynes@5
   630
				case 13: /* SMULLS */
nkeynes@5
   631
					break;
nkeynes@5
   632
				case 14: /* SMLAL */
nkeynes@5
   633
					break;
nkeynes@5
   634
				case 15: /* SMLALS */
nkeynes@5
   635
					break;
nkeynes@5
   636
				case 16: /* SWP */
nkeynes@5
   637
					break;
nkeynes@5
   638
				case 20: /* SWPB */
nkeynes@5
   639
					break;
nkeynes@5
   640
				default:
nkeynes@5
   641
					UNIMP(ir);
nkeynes@5
   642
				}
nkeynes@5
   643
				break;
nkeynes@5
   644
			case 1:
nkeynes@5
   645
				if( LFLAG(ir) ) {
nkeynes@5
   646
					/* LDRH */
nkeynes@5
   647
				} else {
nkeynes@5
   648
					/* STRH */
nkeynes@5
   649
				}
nkeynes@5
   650
				break;
nkeynes@5
   651
			case 2:
nkeynes@5
   652
				if( LFLAG(ir) ) {
nkeynes@5
   653
					/* LDRSB */
nkeynes@5
   654
				} else {
nkeynes@5
   655
					UNIMP(ir);
nkeynes@5
   656
				}
nkeynes@5
   657
				break;
nkeynes@5
   658
			case 3:
nkeynes@5
   659
				if( LFLAG(ir) ) {
nkeynes@5
   660
					/* LDRSH */
nkeynes@5
   661
				} else {
nkeynes@5
   662
					UNIMP(ir);
nkeynes@5
   663
				}
nkeynes@5
   664
				break;
nkeynes@5
   665
			}
nkeynes@5
   666
		} else {
nkeynes@5
   667
			/* Data processing */
nkeynes@5
   668
nkeynes@5
   669
			switch(OPCODE(ir)) {
nkeynes@5
   670
			case 0: /* AND Rd, Rn, operand */
nkeynes@7
   671
				LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
nkeynes@5
   672
				break;
nkeynes@5
   673
			case 1: /* ANDS Rd, Rn, operand */
nkeynes@5
   674
				operand = arm_get_shift_operand_s(ir) & RN(ir);
nkeynes@7
   675
				LRD(ir) = operand;
nkeynes@5
   676
				if( RDn(ir) == 15 ) {
nkeynes@5
   677
					arm_restore_cpsr();
nkeynes@5
   678
				} else {
nkeynes@5
   679
					armr.n = operand>>31;
nkeynes@5
   680
					armr.z = (operand == 0);
nkeynes@5
   681
					armr.c = armr.shift_c;
nkeynes@5
   682
				}
nkeynes@5
   683
				break;
nkeynes@5
   684
			case 2: /* EOR Rd, Rn, operand */
nkeynes@7
   685
				LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
nkeynes@5
   686
				break;
nkeynes@5
   687
			case 3: /* EORS Rd, Rn, operand */
nkeynes@5
   688
				operand = arm_get_shift_operand_s(ir) ^ RN(ir);
nkeynes@7
   689
				LRD(ir) = operand;
nkeynes@5
   690
				if( RDn(ir) == 15 ) {
nkeynes@5
   691
					arm_restore_cpsr();
nkeynes@5
   692
				} else {
nkeynes@5
   693
					armr.n = operand>>31;
nkeynes@5
   694
					armr.z = (operand == 0);
nkeynes@5
   695
					armr.c = armr.shift_c;
nkeynes@5
   696
				}
nkeynes@5
   697
				break;
nkeynes@5
   698
			case 4: /* SUB Rd, Rn, operand */
nkeynes@7
   699
				LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
nkeynes@5
   700
				break;
nkeynes@5
   701
			case 5: /* SUBS Rd, Rn, operand */
nkeynes@5
   702
			    operand = RN(ir);
nkeynes@7
   703
				operand2 = arm_get_shift_operand(ir);
nkeynes@5
   704
				tmp = operand - operand2;
nkeynes@7
   705
				LRD(ir) = tmp;
nkeynes@5
   706
				if( RDn(ir) == 15 ) {
nkeynes@5
   707
					arm_restore_cpsr();
nkeynes@5
   708
				} else {
nkeynes@5
   709
					armr.n = tmp>>31;
nkeynes@5
   710
					armr.z = (tmp == 0);
nkeynes@5
   711
					armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@5
   712
					armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@5
   713
				}
nkeynes@5
   714
				break;
nkeynes@5
   715
			case 6: /* RSB Rd, operand, Rn */
nkeynes@7
   716
				LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
nkeynes@5
   717
				break;
nkeynes@5
   718
			case 7: /* RSBS Rd, operand, Rn */
nkeynes@5
   719
				operand = arm_get_shift_operand(ir);
nkeynes@5
   720
			    operand2 = RN(ir);
nkeynes@5
   721
				tmp = operand - operand2;
nkeynes@7
   722
				LRD(ir) = tmp;
nkeynes@5
   723
				if( RDn(ir) == 15 ) {
nkeynes@5
   724
					arm_restore_cpsr();
nkeynes@5
   725
				} else {
nkeynes@5
   726
					armr.n = tmp>>31;
nkeynes@5
   727
					armr.z = (tmp == 0);
nkeynes@5
   728
					armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@5
   729
					armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@5
   730
				}
nkeynes@5
   731
				break;
nkeynes@5
   732
			case 8: /* ADD Rd, Rn, operand */
nkeynes@7
   733
				LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
nkeynes@5
   734
				break;
nkeynes@5
   735
			case 9: /* ADDS Rd, Rn, operand */
nkeynes@5
   736
				operand = arm_get_shift_operand(ir);
nkeynes@5
   737
			    operand2 = RN(ir);
nkeynes@7
   738
				tmp = operand + operand2;
nkeynes@7
   739
				LRD(ir) = tmp;
nkeynes@5
   740
				if( RDn(ir) == 15 ) {
nkeynes@5
   741
					arm_restore_cpsr();
nkeynes@5
   742
				} else {
nkeynes@5
   743
					armr.n = tmp>>31;
nkeynes@5
   744
					armr.z = (tmp == 0);
nkeynes@5
   745
					armr.c = IS_CARRY(tmp,operand,operand2);
nkeynes@5
   746
					armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
nkeynes@5
   747
				}
nkeynes@5
   748
				break;			
nkeynes@5
   749
			case 10: /* ADC */
nkeynes@5
   750
			case 11: /* ADCS */
nkeynes@5
   751
			case 12: /* SBC */
nkeynes@5
   752
			case 13: /* SBCS */
nkeynes@5
   753
			case 14: /* RSC */
nkeynes@5
   754
			case 15: /* RSCS */
nkeynes@5
   755
				break;
nkeynes@5
   756
			case 17: /* TST Rn, operand */
nkeynes@5
   757
				operand = arm_get_shift_operand_s(ir) & RN(ir);
nkeynes@5
   758
				armr.n = operand>>31;
nkeynes@5
   759
				armr.z = (operand == 0);
nkeynes@5
   760
				armr.c = armr.shift_c;
nkeynes@5
   761
				break;
nkeynes@5
   762
			case 19: /* TEQ Rn, operand */
nkeynes@5
   763
				operand = arm_get_shift_operand_s(ir) ^ RN(ir);
nkeynes@5
   764
				armr.n = operand>>31;
nkeynes@5
   765
				armr.z = (operand == 0);
nkeynes@5
   766
				armr.c = armr.shift_c;
nkeynes@5
   767
				break;				
nkeynes@5
   768
			case 21: /* CMP Rn, operand */
nkeynes@5
   769
			    operand = RN(ir);
nkeynes@7
   770
				operand2 = arm_get_shift_operand(ir);
nkeynes@5
   771
				tmp = operand - operand2;
nkeynes@5
   772
				armr.n = tmp>>31;
nkeynes@5
   773
				armr.z = (tmp == 0);
nkeynes@5
   774
				armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@5
   775
				armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@5
   776
				break;
nkeynes@5
   777
			case 23: /* CMN Rn, operand */
nkeynes@5
   778
			    operand = RN(ir);
nkeynes@7
   779
				operand2 = arm_get_shift_operand(ir);
nkeynes@5
   780
				tmp = operand + operand2;
nkeynes@5
   781
				armr.n = tmp>>31;
nkeynes@5
   782
				armr.z = (tmp == 0);
nkeynes@5
   783
				armr.c = IS_CARRY(tmp,operand,operand2);
nkeynes@5
   784
				armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
nkeynes@5
   785
				break;
nkeynes@5
   786
			case 24: /* ORR Rd, Rn, operand */
nkeynes@7
   787
				LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
nkeynes@5
   788
				break;
nkeynes@5
   789
			case 25: /* ORRS Rd, Rn, operand */
nkeynes@5
   790
				operand = arm_get_shift_operand_s(ir) | RN(ir);
nkeynes@7
   791
				LRD(ir) = operand;
nkeynes@5
   792
				if( RDn(ir) == 15 ) {
nkeynes@5
   793
					arm_restore_cpsr();
nkeynes@5
   794
				} else {
nkeynes@5
   795
					armr.n = operand>>31;
nkeynes@5
   796
					armr.z = (operand == 0);
nkeynes@5
   797
					armr.c = armr.shift_c;
nkeynes@5
   798
				}
nkeynes@5
   799
				break;
nkeynes@5
   800
			case 26: /* MOV Rd, operand */
nkeynes@7
   801
				LRD(ir) = arm_get_shift_operand(ir);
nkeynes@5
   802
				break;
nkeynes@5
   803
			case 27: /* MOVS Rd, operand */
nkeynes@5
   804
				operand = arm_get_shift_operand_s(ir);
nkeynes@7
   805
				LRD(ir) = operand;
nkeynes@5
   806
				if( RDn(ir) == 15 ) {
nkeynes@5
   807
					arm_restore_cpsr();
nkeynes@5
   808
				} else {
nkeynes@5
   809
					armr.n = operand>>31;
nkeynes@5
   810
					armr.z = (operand == 0);
nkeynes@5
   811
					armr.c = armr.shift_c;
nkeynes@5
   812
				}
nkeynes@5
   813
				break;
nkeynes@5
   814
			case 28: /* BIC Rd, Rn, operand */
nkeynes@7
   815
				LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
nkeynes@5
   816
				break;
nkeynes@5
   817
			case 29: /* BICS Rd, Rn, operand */
nkeynes@5
   818
				operand = RN(ir) & (~arm_get_shift_operand_s(ir));
nkeynes@7
   819
				LRD(ir) = operand;
nkeynes@5
   820
				if( RDn(ir) == 15 ) {
nkeynes@5
   821
					arm_restore_cpsr();
nkeynes@5
   822
				} else {
nkeynes@5
   823
					armr.n = operand>>31;
nkeynes@5
   824
					armr.z = (operand == 0);
nkeynes@5
   825
					armr.c = armr.shift_c;
nkeynes@5
   826
				}
nkeynes@5
   827
				break;
nkeynes@5
   828
			case 30: /* MVN Rd, operand */
nkeynes@7
   829
				LRD(ir) = ~arm_get_shift_operand(ir);
nkeynes@5
   830
				break;
nkeynes@5
   831
			case 31: /* MVNS Rd, operand */
nkeynes@5
   832
				operand = ~arm_get_shift_operand_s(ir);
nkeynes@7
   833
				LRD(ir) = operand;
nkeynes@5
   834
				if( RDn(ir) == 15 ) {
nkeynes@5
   835
					arm_restore_cpsr();
nkeynes@5
   836
				} else {
nkeynes@5
   837
					armr.n = operand>>31;
nkeynes@5
   838
					armr.z = (operand == 0);
nkeynes@5
   839
					armr.c = armr.shift_c;
nkeynes@5
   840
				}
nkeynes@5
   841
				break;
nkeynes@5
   842
			default:
nkeynes@5
   843
				UNIMP(ir);
nkeynes@5
   844
			}
nkeynes@5
   845
		}
nkeynes@5
   846
		break;
nkeynes@5
   847
	case 1: /* Load/store */
nkeynes@5
   848
		break;
nkeynes@5
   849
	case 2: /* Load/store multiple, branch*/
nkeynes@5
   850
		break;
nkeynes@5
   851
	case 3: /* Copro */
nkeynes@5
   852
		break;
nkeynes@5
   853
	}
nkeynes@30
   854
	return TRUE;
nkeynes@2
   855
}
.