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