Search
lxdream.org :: lxdream/src/aica/armcore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/aica/armcore.c
changeset 86:f151e63f9754
prev81:1c1d53584da4
next431:248dd77a9e44
author nkeynes
date Sun Feb 05 04:04:25 2006 +0000 (18 years ago)
permissions -rw-r--r--
last change Install the bios hooks if we're loading a demo
file annotate diff log raw
nkeynes@30
     1
/**
nkeynes@86
     2
 * $Id: armcore.c,v 1.20 2006-01-22 22:40:05 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@73
    21
#include "mem.h"
nkeynes@7
    22
#include "aica/armcore.h"
nkeynes@73
    23
#include "aica/aica.h"
nkeynes@2
    24
nkeynes@51
    25
#define STM_R15_OFFSET 12
nkeynes@51
    26
nkeynes@2
    27
struct arm_registers armr;
nkeynes@2
    28
nkeynes@35
    29
void arm_set_mode( int mode );
nkeynes@35
    30
nkeynes@35
    31
uint32_t arm_exceptions[][2] = {{ MODE_SVC, 0x00000000 },
nkeynes@35
    32
				{ MODE_UND, 0x00000004 },
nkeynes@35
    33
				{ MODE_SVC, 0x00000008 },
nkeynes@35
    34
				{ MODE_ABT, 0x0000000C },
nkeynes@35
    35
				{ MODE_ABT, 0x00000010 },
nkeynes@35
    36
				{ MODE_IRQ, 0x00000018 },
nkeynes@35
    37
				{ MODE_FIQ, 0x0000001C } };
nkeynes@35
    38
nkeynes@35
    39
#define EXC_RESET 0
nkeynes@35
    40
#define EXC_UNDEFINED 1
nkeynes@35
    41
#define EXC_SOFTWARE 2
nkeynes@35
    42
#define EXC_PREFETCH_ABORT 3
nkeynes@35
    43
#define EXC_DATA_ABORT 4
nkeynes@35
    44
#define EXC_IRQ 5
nkeynes@35
    45
#define EXC_FAST_IRQ 6
nkeynes@35
    46
nkeynes@35
    47
uint32_t arm_cpu_freq = ARM_BASE_RATE;
nkeynes@35
    48
uint32_t arm_cpu_period = 1000 / ARM_BASE_RATE;
nkeynes@35
    49
nkeynes@73
    50
#define CYCLES_PER_SAMPLE ((ARM_BASE_RATE * 1000000) / AICA_SAMPLE_RATE)
nkeynes@43
    51
nkeynes@43
    52
static struct breakpoint_struct arm_breakpoints[MAX_BREAKPOINTS];
nkeynes@43
    53
static int arm_breakpoint_count = 0;
nkeynes@43
    54
nkeynes@43
    55
void arm_set_breakpoint( uint32_t pc, int type )
nkeynes@43
    56
{
nkeynes@43
    57
    arm_breakpoints[arm_breakpoint_count].address = pc;
nkeynes@43
    58
    arm_breakpoints[arm_breakpoint_count].type = type;
nkeynes@43
    59
    arm_breakpoint_count++;
nkeynes@43
    60
}
nkeynes@43
    61
nkeynes@43
    62
gboolean arm_clear_breakpoint( uint32_t pc, int type )
nkeynes@43
    63
{
nkeynes@43
    64
    int i;
nkeynes@43
    65
nkeynes@43
    66
    for( i=0; i<arm_breakpoint_count; i++ ) {
nkeynes@43
    67
	if( arm_breakpoints[i].address == pc && 
nkeynes@43
    68
	    arm_breakpoints[i].type == type ) {
nkeynes@43
    69
	    while( ++i < arm_breakpoint_count ) {
nkeynes@43
    70
		arm_breakpoints[i-1].address = arm_breakpoints[i].address;
nkeynes@43
    71
		arm_breakpoints[i-1].type = arm_breakpoints[i].type;
nkeynes@43
    72
	    }
nkeynes@43
    73
	    arm_breakpoint_count--;
nkeynes@43
    74
	    return TRUE;
nkeynes@43
    75
	}
nkeynes@43
    76
    }
nkeynes@43
    77
    return FALSE;
nkeynes@43
    78
}
nkeynes@43
    79
nkeynes@43
    80
int arm_get_breakpoint( uint32_t pc )
nkeynes@43
    81
{
nkeynes@43
    82
    int i;
nkeynes@43
    83
    for( i=0; i<arm_breakpoint_count; i++ ) {
nkeynes@43
    84
	if( arm_breakpoints[i].address == pc )
nkeynes@43
    85
	    return arm_breakpoints[i].type;
nkeynes@43
    86
    }
nkeynes@43
    87
    return 0;
nkeynes@43
    88
}
nkeynes@43
    89
nkeynes@73
    90
uint32_t arm_run_slice( uint32_t num_samples )
nkeynes@35
    91
{
nkeynes@73
    92
    int i,j,k;
nkeynes@86
    93
nkeynes@86
    94
    if( !armr.running )
nkeynes@86
    95
	return num_samples;
nkeynes@86
    96
nkeynes@73
    97
    for( i=0; i<num_samples; i++ ) {
nkeynes@73
    98
	for( j=0; j < CYCLES_PER_SAMPLE; j++ ) {
nkeynes@73
    99
	    armr.icount++;
nkeynes@73
   100
	    if( !arm_execute_instruction() )
nkeynes@73
   101
		return i;
nkeynes@73
   102
#ifdef ENABLE_DEBUG_MODE
nkeynes@73
   103
	    for( k=0; k<arm_breakpoint_count; k++ ) {
nkeynes@73
   104
		if( arm_breakpoints[k].address == armr.r[15] ) {
nkeynes@73
   105
		    dreamcast_stop();
nkeynes@73
   106
		    if( arm_breakpoints[k].type == BREAK_ONESHOT )
nkeynes@73
   107
			arm_clear_breakpoint( armr.r[15], BREAK_ONESHOT );
nkeynes@73
   108
		    return i;
nkeynes@73
   109
		}
nkeynes@73
   110
	    }
nkeynes@73
   111
#endif	
nkeynes@73
   112
	}
nkeynes@80
   113
	
nkeynes@80
   114
	k = MMIO_READ( AICA2, AICA_TCR );
nkeynes@80
   115
	if( k & 0x40 ) {
nkeynes@73
   116
	    uint8_t val = MMIO_READ( AICA2, AICA_TIMER );
nkeynes@73
   117
	    val++;
nkeynes@80
   118
	    if( val == 0 ) {
nkeynes@73
   119
		aica_event( AICA_EVENT_TIMER );
nkeynes@80
   120
		MMIO_WRITE( AICA2, AICA_TCR, k & ~0x40 );
nkeynes@80
   121
	    }
nkeynes@73
   122
	    MMIO_WRITE( AICA2, AICA_TIMER, val );
nkeynes@73
   123
	}
nkeynes@73
   124
	if( !dreamcast_is_running() )
nkeynes@35
   125
	    break;
nkeynes@35
   126
    }
nkeynes@35
   127
nkeynes@73
   128
    return i;
nkeynes@35
   129
}
nkeynes@35
   130
nkeynes@35
   131
void arm_save_state( FILE *f )
nkeynes@35
   132
{
nkeynes@35
   133
    fwrite( &armr, sizeof(armr), 1, f );
nkeynes@35
   134
}
nkeynes@35
   135
nkeynes@35
   136
int arm_load_state( FILE *f )
nkeynes@35
   137
{
nkeynes@35
   138
    fread( &armr, sizeof(armr), 1, f );
nkeynes@35
   139
    return 0;
nkeynes@35
   140
}
nkeynes@35
   141
nkeynes@35
   142
/* Exceptions */
nkeynes@35
   143
void arm_reset( void )
nkeynes@35
   144
{
nkeynes@35
   145
    /* Wipe all processor state */
nkeynes@35
   146
    memset( &armr, 0, sizeof(armr) );
nkeynes@35
   147
nkeynes@35
   148
    armr.cpsr = MODE_SVC | CPSR_I | CPSR_F;
nkeynes@35
   149
    armr.r[15] = 0x00000000;
nkeynes@86
   150
    armr.running = TRUE;
nkeynes@35
   151
}
nkeynes@35
   152
nkeynes@37
   153
#define SET_CPSR_CONTROL   0x00010000
nkeynes@37
   154
#define SET_CPSR_EXTENSION 0x00020000
nkeynes@37
   155
#define SET_CPSR_STATUS    0x00040000
nkeynes@37
   156
#define SET_CPSR_FLAGS     0x00080000
nkeynes@37
   157
nkeynes@37
   158
uint32_t arm_get_cpsr( void )
nkeynes@37
   159
{
nkeynes@37
   160
    /* write back all flags to the cpsr */
nkeynes@37
   161
    armr.cpsr = armr.cpsr & CPSR_COMPACT_MASK;
nkeynes@37
   162
    if( armr.n ) armr.cpsr |= CPSR_N;
nkeynes@37
   163
    if( armr.z ) armr.cpsr |= CPSR_Z;
nkeynes@37
   164
    if( armr.c ) armr.cpsr |= CPSR_C;
nkeynes@37
   165
    if( armr.v ) armr.cpsr |= CPSR_V;
nkeynes@37
   166
    if( armr.t ) armr.cpsr |= CPSR_T;  
nkeynes@37
   167
    return armr.cpsr;
nkeynes@37
   168
}
nkeynes@37
   169
nkeynes@37
   170
/**
nkeynes@66
   171
 * Return a pointer to the specified register in the user bank,
nkeynes@66
   172
 * regardless of the active bank
nkeynes@66
   173
 */
nkeynes@66
   174
static uint32_t *arm_user_reg( int reg )
nkeynes@66
   175
{
nkeynes@66
   176
    if( IS_EXCEPTION_MODE() ) {
nkeynes@66
   177
	if( reg == 13 || reg == 14 )
nkeynes@66
   178
	    return &armr.user_r[reg-8];
nkeynes@66
   179
	if( IS_FIQ_MODE() ) {
nkeynes@66
   180
	    if( reg >= 8 || reg <= 12 )
nkeynes@66
   181
		return &armr.user_r[reg-8];
nkeynes@66
   182
	}
nkeynes@66
   183
    }
nkeynes@66
   184
    return &armr.r[reg];
nkeynes@66
   185
}
nkeynes@66
   186
nkeynes@66
   187
#define USER_R(n) *arm_user_reg(n)
nkeynes@66
   188
nkeynes@66
   189
/**
nkeynes@37
   190
 * Set the CPSR to the specified value.
nkeynes@37
   191
 *
nkeynes@37
   192
 * @param value values to set in CPSR
nkeynes@37
   193
 * @param fields set of mask values to define which sections of the 
nkeynes@37
   194
 *   CPSR to set (one of the SET_CPSR_* values above)
nkeynes@37
   195
 */
nkeynes@37
   196
void arm_set_cpsr( uint32_t value, uint32_t fields )
nkeynes@37
   197
{
nkeynes@37
   198
    if( IS_PRIVILEGED_MODE() ) {
nkeynes@37
   199
	if( fields & SET_CPSR_CONTROL ) {
nkeynes@37
   200
	    int mode = value & CPSR_MODE;
nkeynes@37
   201
	    arm_set_mode( mode );
nkeynes@37
   202
	    armr.t = ( value & CPSR_T ); /* Technically illegal to change */
nkeynes@37
   203
	    armr.cpsr = (armr.cpsr & 0xFFFFFF00) | (value & 0x000000FF);
nkeynes@37
   204
	}
nkeynes@37
   205
nkeynes@37
   206
	/* Middle 16 bits not currently defined */
nkeynes@37
   207
    }
nkeynes@37
   208
    if( fields & SET_CPSR_FLAGS ) {
nkeynes@37
   209
	/* Break flags directly out of given value - don't bother writing
nkeynes@37
   210
	 * back to CPSR 
nkeynes@37
   211
	 */
nkeynes@37
   212
	armr.n = ( value & CPSR_N );
nkeynes@37
   213
	armr.z = ( value & CPSR_Z );
nkeynes@37
   214
	armr.c = ( value & CPSR_C );
nkeynes@37
   215
	armr.v = ( value & CPSR_V );
nkeynes@37
   216
    }
nkeynes@37
   217
}
nkeynes@37
   218
nkeynes@37
   219
void arm_set_spsr( uint32_t value, uint32_t fields )
nkeynes@37
   220
{
nkeynes@37
   221
    /* Only defined if we actually have an SPSR register */
nkeynes@37
   222
    if( IS_EXCEPTION_MODE() ) {
nkeynes@37
   223
	if( fields & SET_CPSR_CONTROL ) {
nkeynes@37
   224
	    armr.spsr = (armr.spsr & 0xFFFFFF00) | (value & 0x000000FF);
nkeynes@37
   225
	}
nkeynes@37
   226
nkeynes@37
   227
	/* Middle 16 bits not currently defined */
nkeynes@37
   228
nkeynes@37
   229
	if( fields & SET_CPSR_FLAGS ) {
nkeynes@37
   230
	    armr.spsr = (armr.spsr & 0x00FFFFFF) | (value & 0xFF000000);
nkeynes@37
   231
	}
nkeynes@37
   232
    }
nkeynes@37
   233
}
nkeynes@37
   234
nkeynes@35
   235
/**
nkeynes@35
   236
 * Raise an ARM exception (other than reset, which uses arm_reset().
nkeynes@35
   237
 * @param exception one of the EXC_* exception codes defined above.
nkeynes@35
   238
 */
nkeynes@35
   239
void arm_raise_exception( int exception )
nkeynes@35
   240
{
nkeynes@35
   241
    int mode = arm_exceptions[exception][0];
nkeynes@37
   242
    uint32_t spsr = arm_get_cpsr();
nkeynes@35
   243
    arm_set_mode( mode );
nkeynes@37
   244
    armr.spsr = spsr;
nkeynes@63
   245
    armr.r[14] = armr.r[15] + 4;
nkeynes@59
   246
    armr.cpsr = (spsr & 0xFFFFFF00) | mode | CPSR_I; 
nkeynes@35
   247
    if( mode == MODE_FIQ )
nkeynes@35
   248
	armr.cpsr |= CPSR_F;
nkeynes@35
   249
    armr.r[15] = arm_exceptions[exception][1];
nkeynes@35
   250
}
nkeynes@35
   251
nkeynes@37
   252
void arm_restore_cpsr( void )
nkeynes@35
   253
{
nkeynes@35
   254
    int spsr = armr.spsr;
nkeynes@35
   255
    int mode = spsr & CPSR_MODE;
nkeynes@35
   256
    arm_set_mode( mode );
nkeynes@35
   257
    armr.cpsr = spsr;
nkeynes@37
   258
    armr.n = ( spsr & CPSR_N );
nkeynes@37
   259
    armr.z = ( spsr & CPSR_Z );
nkeynes@37
   260
    armr.c = ( spsr & CPSR_C );
nkeynes@37
   261
    armr.v = ( spsr & CPSR_V );
nkeynes@37
   262
    armr.t = ( spsr & CPSR_T );
nkeynes@35
   263
}
nkeynes@35
   264
nkeynes@35
   265
nkeynes@35
   266
nkeynes@35
   267
/**
nkeynes@35
   268
 * Change the current executing ARM mode to the requested mode.
nkeynes@35
   269
 * Saves any required registers to banks and restores those for the
nkeynes@35
   270
 * correct mode. (Note does not actually update CPSR at the moment).
nkeynes@35
   271
 */
nkeynes@35
   272
void arm_set_mode( int targetMode )
nkeynes@35
   273
{
nkeynes@35
   274
    int currentMode = armr.cpsr & CPSR_MODE;
nkeynes@35
   275
    if( currentMode == targetMode )
nkeynes@35
   276
	return;
nkeynes@35
   277
nkeynes@35
   278
    switch( currentMode ) {
nkeynes@35
   279
    case MODE_USER:
nkeynes@35
   280
    case MODE_SYS:
nkeynes@35
   281
	armr.user_r[5] = armr.r[13];
nkeynes@35
   282
	armr.user_r[6] = armr.r[14];
nkeynes@35
   283
	break;
nkeynes@35
   284
    case MODE_SVC:
nkeynes@35
   285
	armr.svc_r[0] = armr.r[13];
nkeynes@35
   286
	armr.svc_r[1] = armr.r[14];
nkeynes@35
   287
	armr.svc_r[2] = armr.spsr;
nkeynes@35
   288
	break;
nkeynes@35
   289
    case MODE_ABT:
nkeynes@35
   290
	armr.abt_r[0] = armr.r[13];
nkeynes@35
   291
	armr.abt_r[1] = armr.r[14];
nkeynes@35
   292
	armr.abt_r[2] = armr.spsr;
nkeynes@35
   293
	break;
nkeynes@35
   294
    case MODE_UND:
nkeynes@35
   295
	armr.und_r[0] = armr.r[13];
nkeynes@35
   296
	armr.und_r[1] = armr.r[14];
nkeynes@35
   297
	armr.und_r[2] = armr.spsr;
nkeynes@35
   298
	break;
nkeynes@35
   299
    case MODE_IRQ:
nkeynes@35
   300
	armr.irq_r[0] = armr.r[13];
nkeynes@35
   301
	armr.irq_r[1] = armr.r[14];
nkeynes@35
   302
	armr.irq_r[2] = armr.spsr;
nkeynes@35
   303
	break;
nkeynes@35
   304
    case MODE_FIQ:
nkeynes@35
   305
	armr.fiq_r[0] = armr.r[8];
nkeynes@35
   306
	armr.fiq_r[1] = armr.r[9];
nkeynes@35
   307
	armr.fiq_r[2] = armr.r[10];
nkeynes@35
   308
	armr.fiq_r[3] = armr.r[11];
nkeynes@35
   309
	armr.fiq_r[4] = armr.r[12];
nkeynes@35
   310
	armr.fiq_r[5] = armr.r[13];
nkeynes@35
   311
	armr.fiq_r[6] = armr.r[14];
nkeynes@35
   312
	armr.fiq_r[7] = armr.spsr;
nkeynes@35
   313
	armr.r[8] = armr.user_r[0];
nkeynes@35
   314
	armr.r[9] = armr.user_r[1];
nkeynes@35
   315
	armr.r[10] = armr.user_r[2];
nkeynes@35
   316
	armr.r[11] = armr.user_r[3];
nkeynes@35
   317
	armr.r[12] = armr.user_r[4];
nkeynes@35
   318
	break;
nkeynes@35
   319
    }
nkeynes@35
   320
    
nkeynes@35
   321
    switch( targetMode ) {
nkeynes@35
   322
    case MODE_USER:
nkeynes@35
   323
    case MODE_SYS:
nkeynes@35
   324
	armr.r[13] = armr.user_r[5];
nkeynes@35
   325
	armr.r[14] = armr.user_r[6];
nkeynes@35
   326
	break;
nkeynes@35
   327
    case MODE_SVC:
nkeynes@35
   328
	armr.r[13] = armr.svc_r[0];
nkeynes@35
   329
	armr.r[14] = armr.svc_r[1];
nkeynes@35
   330
	armr.spsr = armr.svc_r[2];
nkeynes@35
   331
	break;
nkeynes@35
   332
    case MODE_ABT:
nkeynes@35
   333
	armr.r[13] = armr.abt_r[0];
nkeynes@35
   334
	armr.r[14] = armr.abt_r[1];
nkeynes@35
   335
	armr.spsr = armr.abt_r[2];
nkeynes@35
   336
	break;
nkeynes@35
   337
    case MODE_UND:
nkeynes@35
   338
	armr.r[13] = armr.und_r[0];
nkeynes@35
   339
	armr.r[14] = armr.und_r[1];
nkeynes@35
   340
	armr.spsr = armr.und_r[2];
nkeynes@35
   341
	break;
nkeynes@35
   342
    case MODE_IRQ:
nkeynes@35
   343
	armr.r[13] = armr.irq_r[0];
nkeynes@35
   344
	armr.r[14] = armr.irq_r[1];
nkeynes@35
   345
	armr.spsr = armr.irq_r[2];
nkeynes@35
   346
	break;
nkeynes@35
   347
    case MODE_FIQ:
nkeynes@35
   348
	armr.user_r[0] = armr.r[8];
nkeynes@35
   349
	armr.user_r[1] = armr.r[9];
nkeynes@35
   350
	armr.user_r[2] = armr.r[10];
nkeynes@35
   351
	armr.user_r[3] = armr.r[11];
nkeynes@35
   352
	armr.user_r[4] = armr.r[12];
nkeynes@35
   353
	armr.r[8] = armr.fiq_r[0];
nkeynes@35
   354
	armr.r[9] = armr.fiq_r[1];
nkeynes@35
   355
	armr.r[10] = armr.fiq_r[2];
nkeynes@35
   356
	armr.r[11] = armr.fiq_r[3];
nkeynes@35
   357
	armr.r[12] = armr.fiq_r[4];
nkeynes@35
   358
	armr.r[13] = armr.fiq_r[5];
nkeynes@35
   359
	armr.r[14] = armr.fiq_r[6];
nkeynes@35
   360
	armr.spsr = armr.fiq_r[7];
nkeynes@35
   361
	break;
nkeynes@35
   362
    }
nkeynes@35
   363
}
nkeynes@35
   364
nkeynes@5
   365
/* Page references are as per ARM DDI 0100E (June 2000) */
nkeynes@2
   366
nkeynes@11
   367
#define MEM_READ_BYTE( addr ) arm_read_byte(addr)
nkeynes@11
   368
#define MEM_READ_WORD( addr ) arm_read_word(addr)
nkeynes@11
   369
#define MEM_READ_LONG( addr ) arm_read_long(addr)
nkeynes@11
   370
#define MEM_WRITE_BYTE( addr, val ) arm_write_byte(addr, val)
nkeynes@11
   371
#define MEM_WRITE_WORD( addr, val ) arm_write_word(addr, val)
nkeynes@11
   372
#define MEM_WRITE_LONG( addr, val ) arm_write_long(addr, val)
nkeynes@2
   373
nkeynes@5
   374
nkeynes@5
   375
#define IS_NOTBORROW( result, op1, op2 ) (op2 > op1 ? 0 : 1)
nkeynes@5
   376
#define IS_CARRY( result, op1, op2 ) (result < op1 ? 1 : 0)
nkeynes@5
   377
#define IS_SUBOVERFLOW( result, op1, op2 ) (((op1^op2) & (result^op1)) >> 31)
nkeynes@5
   378
#define IS_ADDOVERFLOW( result, op1, op2 ) (((op1&op2) & (result^op1)) >> 31)
nkeynes@5
   379
nkeynes@7
   380
#define PC armr.r[15]
nkeynes@2
   381
nkeynes@5
   382
/* Instruction fields */
nkeynes@5
   383
#define COND(ir) (ir>>28)
nkeynes@5
   384
#define GRP(ir) ((ir>>26)&0x03)
nkeynes@5
   385
#define OPCODE(ir) ((ir>>20)&0x1F)
nkeynes@5
   386
#define IFLAG(ir) (ir&0x02000000)
nkeynes@5
   387
#define SFLAG(ir) (ir&0x00100000)
nkeynes@5
   388
#define PFLAG(ir) (ir&0x01000000)
nkeynes@5
   389
#define UFLAG(ir) (ir&0x00800000)
nkeynes@5
   390
#define BFLAG(ir) (ir&0x00400000)
nkeynes@46
   391
#define WFLAG(ir) (ir&0x00200000)
nkeynes@5
   392
#define LFLAG(ir) SFLAG(ir)
nkeynes@5
   393
#define RN(ir) (armr.r[((ir>>16)&0x0F)] + (((ir>>16)&0x0F) == 0x0F ? 4 : 0))
nkeynes@37
   394
#define RD(ir) (armr.r[((ir>>12)&0x0F)] + (((ir>>12)&0x0F) == 0x0F ? 4 : 0))
nkeynes@5
   395
#define RDn(ir) ((ir>>12)&0x0F)
nkeynes@37
   396
#define RS(ir) (armr.r[((ir>>8)&0x0F)] + (((ir>>8)&0x0F) == 0x0F ? 4 : 0))
nkeynes@37
   397
#define RM(ir) (armr.r[(ir&0x0F)] + (((ir&0x0F) == 0x0F ? 4 : 0)) )
nkeynes@5
   398
#define LRN(ir) armr.r[((ir>>16)&0x0F)]
nkeynes@5
   399
#define LRD(ir) armr.r[((ir>>12)&0x0F)]
nkeynes@5
   400
#define LRS(ir) armr.r[((ir>>8)&0x0F)]
nkeynes@5
   401
#define LRM(ir) armr.r[(ir&0x0F)]
nkeynes@5
   402
nkeynes@5
   403
#define IMM8(ir) (ir&0xFF)
nkeynes@5
   404
#define IMM12(ir) (ir&0xFFF)
nkeynes@7
   405
#define SHIFTIMM(ir) ((ir>>7)&0x1F)
nkeynes@7
   406
#define IMMROT(ir) ((ir>>7)&0x1E)
nkeynes@37
   407
#define ROTIMM12(ir) ROTATE_RIGHT_LONG(IMM8(ir),IMMROT(ir))
nkeynes@37
   408
#define SIGNEXT24(n) ((n&0x00800000) ? (n|0xFF000000) : (n&0x00FFFFFF))
nkeynes@5
   409
#define SHIFT(ir) ((ir>>4)&0x07)
nkeynes@5
   410
#define DISP24(ir) ((ir&0x00FFFFFF))
nkeynes@37
   411
#define UNDEF(ir) do{ arm_raise_exception( EXC_UNDEFINED ); return TRUE; } while(0)
nkeynes@46
   412
#define UNIMP(ir) do{ PC-=4; ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", PC, ir ); dreamcast_stop(); return FALSE; }while(0)
nkeynes@7
   413
nkeynes@37
   414
/**
nkeynes@37
   415
 * Determine the value of the shift-operand for a data processing instruction,
nkeynes@37
   416
 * without determing a value for shift_C (optimized form for instructions that
nkeynes@37
   417
 * don't require shift_C ).
nkeynes@37
   418
 * @see s5.1 Addressing Mode 1 - Data-processing operands (p A5-2, 218)
nkeynes@37
   419
 */
nkeynes@5
   420
static uint32_t arm_get_shift_operand( uint32_t ir )
nkeynes@5
   421
{
nkeynes@5
   422
	uint32_t operand, tmp;
nkeynes@5
   423
	if( IFLAG(ir) == 0 ) {
nkeynes@5
   424
		operand = RM(ir);
nkeynes@5
   425
		switch(SHIFT(ir)) {
nkeynes@5
   426
		case 0: /* (Rm << imm) */
nkeynes@5
   427
			operand = operand << SHIFTIMM(ir);
nkeynes@5
   428
			break;
nkeynes@5
   429
		case 1: /* (Rm << Rs) */
nkeynes@5
   430
			tmp = RS(ir)&0xFF;
nkeynes@5
   431
			if( tmp > 31 ) operand = 0;
nkeynes@5
   432
			else operand = operand << tmp;
nkeynes@5
   433
			break;
nkeynes@5
   434
		case 2: /* (Rm >> imm) */
nkeynes@5
   435
			operand = operand >> SHIFTIMM(ir);
nkeynes@5
   436
			break;
nkeynes@5
   437
		case 3: /* (Rm >> Rs) */
nkeynes@5
   438
			tmp = RS(ir) & 0xFF;
nkeynes@5
   439
			if( tmp > 31 ) operand = 0;
nkeynes@5
   440
			else operand = operand >> ir;
nkeynes@5
   441
			break;
nkeynes@5
   442
		case 4: /* (Rm >>> imm) */
nkeynes@5
   443
			tmp = SHIFTIMM(ir);
nkeynes@5
   444
			if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
nkeynes@5
   445
			else operand = ((int32_t)operand) >> tmp;
nkeynes@5
   446
			break;
nkeynes@5
   447
		case 5: /* (Rm >>> Rs) */
nkeynes@5
   448
			tmp = RS(ir) & 0xFF;
nkeynes@5
   449
			if( tmp > 31 ) 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
		case 7:
nkeynes@5
   460
			tmp = RS(ir)&0x1F;
nkeynes@5
   461
			operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   462
			break;
nkeynes@5
   463
		}
nkeynes@5
   464
	} else {
nkeynes@5
   465
		operand = IMM8(ir);
nkeynes@5
   466
		tmp = IMMROT(ir);
nkeynes@5
   467
		operand = ROTATE_RIGHT_LONG(operand, tmp);
nkeynes@5
   468
	}
nkeynes@5
   469
	return operand;
nkeynes@5
   470
}
nkeynes@5
   471
nkeynes@5
   472
/**
nkeynes@37
   473
 * Determine the value of the shift-operand for a data processing instruction,
nkeynes@37
   474
 * and set armr.shift_c accordingly.
nkeynes@37
   475
 * @see s5.1 Addressing Mode 1 - Data-processing operands (p A5-2, 218)
nkeynes@5
   476
 */
nkeynes@5
   477
static uint32_t arm_get_shift_operand_s( uint32_t ir )
nkeynes@5
   478
{
nkeynes@5
   479
	uint32_t operand, tmp;
nkeynes@5
   480
	if( IFLAG(ir) == 0 ) {
nkeynes@5
   481
		operand = RM(ir);
nkeynes@5
   482
		switch(SHIFT(ir)) {
nkeynes@5
   483
		case 0: /* (Rm << imm) */
nkeynes@5
   484
			tmp = SHIFTIMM(ir);
nkeynes@5
   485
			if( tmp == 0 ) { /* Rm */
nkeynes@5
   486
				armr.shift_c = armr.c;
nkeynes@5
   487
			} else { /* Rm << imm */
nkeynes@5
   488
				armr.shift_c = (operand >> (32-tmp)) & 0x01;
nkeynes@5
   489
				operand = operand << tmp;
nkeynes@5
   490
			}
nkeynes@5
   491
			break;
nkeynes@5
   492
		case 1: /* (Rm << Rs) */
nkeynes@5
   493
			tmp = RS(ir)&0xFF;
nkeynes@5
   494
			if( tmp == 0 ) {
nkeynes@5
   495
				armr.shift_c = armr.c;
nkeynes@5
   496
			} else {
nkeynes@5
   497
				if( tmp <= 32 )
nkeynes@5
   498
					armr.shift_c = (operand >> (32-tmp)) & 0x01;
nkeynes@5
   499
				else armr.shift_c = 0;
nkeynes@5
   500
				if( tmp < 32 )
nkeynes@5
   501
					operand = operand << tmp;
nkeynes@5
   502
				else operand = 0;
nkeynes@5
   503
			}
nkeynes@5
   504
			break;
nkeynes@5
   505
		case 2: /* (Rm >> imm) */
nkeynes@5
   506
			tmp = SHIFTIMM(ir);
nkeynes@5
   507
			if( tmp == 0 ) {
nkeynes@5
   508
				armr.shift_c = operand >> 31;
nkeynes@5
   509
				operand = 0;
nkeynes@5
   510
			} else {
nkeynes@5
   511
				armr.shift_c = (operand >> (tmp-1)) & 0x01;
nkeynes@5
   512
				operand = RM(ir) >> tmp;
nkeynes@5
   513
			}
nkeynes@5
   514
			break;
nkeynes@5
   515
		case 3: /* (Rm >> Rs) */
nkeynes@5
   516
			tmp = RS(ir) & 0xFF;
nkeynes@5
   517
			if( tmp == 0 ) {
nkeynes@5
   518
				armr.shift_c = armr.c;
nkeynes@5
   519
			} else {
nkeynes@5
   520
				if( tmp <= 32 )
nkeynes@5
   521
					armr.shift_c = (operand >> (tmp-1))&0x01;
nkeynes@5
   522
				else armr.shift_c = 0;
nkeynes@5
   523
				if( tmp < 32 )
nkeynes@5
   524
					operand = operand >> tmp;
nkeynes@5
   525
				else operand = 0;
nkeynes@5
   526
			}
nkeynes@5
   527
			break;
nkeynes@5
   528
		case 4: /* (Rm >>> imm) */
nkeynes@5
   529
			tmp = SHIFTIMM(ir);
nkeynes@5
   530
			if( tmp == 0 ) {
nkeynes@5
   531
				armr.shift_c = operand >> 31;
nkeynes@5
   532
				operand = -armr.shift_c;
nkeynes@5
   533
			} else {
nkeynes@5
   534
				armr.shift_c = (operand >> (tmp-1)) & 0x01;
nkeynes@5
   535
				operand = ((int32_t)operand) >> tmp;
nkeynes@5
   536
			}
nkeynes@5
   537
			break;
nkeynes@5
   538
		case 5: /* (Rm >>> Rs) */
nkeynes@5
   539
			tmp = RS(ir) & 0xFF;
nkeynes@5
   540
			if( tmp == 0 ) {
nkeynes@5
   541
				armr.shift_c = armr.c;
nkeynes@5
   542
			} else {
nkeynes@5
   543
				if( tmp < 32 ) {
nkeynes@5
   544
					armr.shift_c = (operand >> (tmp-1))&0x01;
nkeynes@5
   545
					operand = ((int32_t)operand) >> tmp;
nkeynes@5
   546
				} else {
nkeynes@5
   547
					armr.shift_c = operand >> 31;
nkeynes@5
   548
					operand = ((int32_t)operand) >> 31;
nkeynes@5
   549
				}
nkeynes@5
   550
			}
nkeynes@5
   551
			break;
nkeynes@5
   552
		case 6:
nkeynes@5
   553
			tmp = SHIFTIMM(ir);
nkeynes@5
   554
			if( tmp == 0 ) { /* RRX aka rotate with carry */
nkeynes@5
   555
				armr.shift_c = operand&0x01;
nkeynes@7
   556
				operand = (operand >> 1) | (armr.c<<31);
nkeynes@5
   557
			} else {
nkeynes@5
   558
				armr.shift_c = operand>>(tmp-1);
nkeynes@5
   559
				operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   560
			}
nkeynes@5
   561
			break;
nkeynes@5
   562
		case 7:
nkeynes@5
   563
			tmp = RS(ir)&0xFF;
nkeynes@5
   564
			if( tmp == 0 ) {
nkeynes@5
   565
				armr.shift_c = armr.c;
nkeynes@5
   566
			} else {
nkeynes@5
   567
				tmp &= 0x1F;
nkeynes@5
   568
				if( tmp == 0 ) {
nkeynes@5
   569
					armr.shift_c = operand>>31;
nkeynes@5
   570
				} else {
nkeynes@5
   571
					armr.shift_c = (operand>>(tmp-1))&0x1;
nkeynes@5
   572
					operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   573
				}
nkeynes@5
   574
			}
nkeynes@5
   575
			break;
nkeynes@5
   576
		}
nkeynes@5
   577
	} else {
nkeynes@5
   578
		operand = IMM8(ir);
nkeynes@5
   579
		tmp = IMMROT(ir);
nkeynes@5
   580
		if( tmp == 0 ) {
nkeynes@5
   581
			armr.shift_c = armr.c;
nkeynes@5
   582
		} else {
nkeynes@5
   583
			operand = ROTATE_RIGHT_LONG(operand, tmp);
nkeynes@5
   584
			armr.shift_c = operand>>31;
nkeynes@5
   585
		}
nkeynes@5
   586
	}
nkeynes@5
   587
	return operand;
nkeynes@5
   588
}
nkeynes@5
   589
nkeynes@5
   590
/**
nkeynes@5
   591
 * Another variant of the shifter code for index-based memory addressing.
nkeynes@5
   592
 * Distinguished by the fact that it doesn't support register shifts, and
nkeynes@5
   593
 * ignores the I flag (WTF do the load/store instructions use the I flag to
nkeynes@5
   594
 * mean the _exact opposite_ of what it means for the data processing 
nkeynes@5
   595
 * instructions ???)
nkeynes@5
   596
 */
nkeynes@5
   597
static uint32_t arm_get_address_index( uint32_t ir )
nkeynes@5
   598
{
nkeynes@5
   599
	uint32_t operand = RM(ir);
nkeynes@7
   600
	uint32_t tmp;
nkeynes@7
   601
	
nkeynes@5
   602
	switch(SHIFT(ir)) {
nkeynes@5
   603
	case 0: /* (Rm << imm) */
nkeynes@5
   604
		operand = operand << SHIFTIMM(ir);
nkeynes@5
   605
		break;
nkeynes@5
   606
	case 2: /* (Rm >> imm) */
nkeynes@5
   607
		operand = operand >> SHIFTIMM(ir);
nkeynes@5
   608
		break;
nkeynes@5
   609
	case 4: /* (Rm >>> imm) */
nkeynes@5
   610
		tmp = SHIFTIMM(ir);
nkeynes@5
   611
		if( tmp == 0 ) operand = ((int32_t)operand) >> 31;
nkeynes@5
   612
		else operand = ((int32_t)operand) >> tmp;
nkeynes@5
   613
		break;
nkeynes@5
   614
	case 6:
nkeynes@5
   615
		tmp = SHIFTIMM(ir);
nkeynes@5
   616
		if( tmp == 0 ) /* RRX aka rotate with carry */
nkeynes@7
   617
			operand = (operand >> 1) | (armr.c<<31);
nkeynes@5
   618
		else
nkeynes@5
   619
			operand = ROTATE_RIGHT_LONG(operand,tmp);
nkeynes@5
   620
		break;
nkeynes@5
   621
	default: UNIMP(ir);
nkeynes@5
   622
	}
nkeynes@5
   623
	return operand;	
nkeynes@5
   624
}
nkeynes@5
   625
nkeynes@37
   626
/**
nkeynes@37
   627
 * Determine the address operand of a load/store instruction, including
nkeynes@37
   628
 * applying any pre/post adjustments to the address registers.
nkeynes@37
   629
 * @see s5.2 Addressing Mode 2 - Load and Store Word or Unsigned Byte
nkeynes@37
   630
 * @param The instruction word.
nkeynes@37
   631
 * @return The calculated address
nkeynes@37
   632
 */
nkeynes@5
   633
static uint32_t arm_get_address_operand( uint32_t ir )
nkeynes@5
   634
{
nkeynes@5
   635
	uint32_t addr;
nkeynes@5
   636
	
nkeynes@5
   637
	/* I P U . W */
nkeynes@5
   638
	switch( (ir>>21)&0x1D ) {
nkeynes@5
   639
	case 0: /* Rn -= imm offset (post-indexed) [5.2.8 A5-28] */
nkeynes@5
   640
	case 1:
nkeynes@5
   641
		addr = RN(ir);
nkeynes@7
   642
		LRN(ir) = addr - IMM12(ir);
nkeynes@5
   643
		break;
nkeynes@5
   644
	case 4: /* Rn += imm offsett (post-indexed) [5.2.8 A5-28] */
nkeynes@5
   645
	case 5:
nkeynes@5
   646
		addr = RN(ir);
nkeynes@7
   647
		LRN(ir) = addr + IMM12(ir);
nkeynes@5
   648
		break;
nkeynes@5
   649
	case 8: /* Rn - imm offset  [5.2.2 A5-20] */
nkeynes@5
   650
		addr = RN(ir) - IMM12(ir);
nkeynes@5
   651
		break;
nkeynes@5
   652
	case 9: /* Rn -= imm offset (pre-indexed)  [5.2.5 A5-24] */
nkeynes@5
   653
		addr = RN(ir) - IMM12(ir);
nkeynes@7
   654
		LRN(ir) = addr;
nkeynes@5
   655
		break;
nkeynes@5
   656
	case 12: /* Rn + imm offset  [5.2.2 A5-20] */
nkeynes@5
   657
		addr = RN(ir) + IMM12(ir);
nkeynes@5
   658
		break;
nkeynes@5
   659
	case 13: /* Rn += imm offset  [5.2.5 A5-24 ] */
nkeynes@5
   660
		addr = RN(ir) + IMM12(ir);
nkeynes@7
   661
		LRN(ir) = addr;
nkeynes@5
   662
		break;
nkeynes@5
   663
	case 16: /* Rn -= Rm (post-indexed)  [5.2.10 A5-32 ] */
nkeynes@5
   664
	case 17:
nkeynes@5
   665
		addr = RN(ir);
nkeynes@7
   666
		LRN(ir) = addr - arm_get_address_index(ir);
nkeynes@5
   667
		break;
nkeynes@5
   668
	case 20: /* Rn += Rm (post-indexed)  [5.2.10 A5-32 ] */
nkeynes@5
   669
	case 21:
nkeynes@5
   670
		addr = RN(ir);
nkeynes@7
   671
		LRN(ir) = addr - arm_get_address_index(ir);
nkeynes@5
   672
		break;
nkeynes@5
   673
	case 24: /* Rn - Rm  [5.2.4 A5-23] */
nkeynes@5
   674
		addr = RN(ir) - arm_get_address_index(ir);
nkeynes@5
   675
		break;
nkeynes@5
   676
	case 25: /* RN -= Rm (pre-indexed)  [5.2.7 A5-26] */
nkeynes@5
   677
		addr = RN(ir) - arm_get_address_index(ir);
nkeynes@7
   678
		LRN(ir) = addr;
nkeynes@5
   679
		break;
nkeynes@5
   680
	case 28: /* Rn + Rm  [5.2.4 A5-23] */
nkeynes@5
   681
		addr = RN(ir) + arm_get_address_index(ir);
nkeynes@5
   682
		break;
nkeynes@5
   683
	case 29: /* RN += Rm (pre-indexed) [5.2.7 A5-26] */
nkeynes@5
   684
		addr = RN(ir) + arm_get_address_index(ir);
nkeynes@7
   685
		LRN(ir) = addr;
nkeynes@5
   686
		break;
nkeynes@5
   687
	}
nkeynes@5
   688
	return addr;
nkeynes@5
   689
}
nkeynes@5
   690
nkeynes@30
   691
gboolean arm_execute_instruction( void ) 
nkeynes@2
   692
{
nkeynes@59
   693
    uint32_t pc;
nkeynes@59
   694
    uint32_t ir;
nkeynes@49
   695
    uint32_t operand, operand2, tmp, tmp2, cond;
nkeynes@66
   696
    int i;
nkeynes@2
   697
nkeynes@52
   698
    tmp = armr.int_pending & (~armr.cpsr);
nkeynes@51
   699
    if( tmp ) {
nkeynes@51
   700
	if( tmp & CPSR_F ) {
nkeynes@51
   701
	    arm_raise_exception( EXC_FAST_IRQ );
nkeynes@51
   702
	} else {
nkeynes@51
   703
	    arm_raise_exception( EXC_IRQ );
nkeynes@51
   704
	}
nkeynes@51
   705
    }
nkeynes@51
   706
nkeynes@59
   707
    ir = MEM_READ_LONG(PC);
nkeynes@59
   708
    pc = PC + 4;
nkeynes@37
   709
    PC = pc;
nkeynes@2
   710
nkeynes@37
   711
    /** 
nkeynes@37
   712
     * Check the condition bits first - if the condition fails return 
nkeynes@37
   713
     * immediately without actually looking at the rest of the instruction.
nkeynes@37
   714
     */
nkeynes@37
   715
    switch( COND(ir) ) {
nkeynes@37
   716
    case 0: /* EQ */ 
nkeynes@37
   717
	cond = armr.z;
nkeynes@37
   718
	break;
nkeynes@37
   719
    case 1: /* NE */
nkeynes@37
   720
	cond = !armr.z;
nkeynes@37
   721
	break;
nkeynes@37
   722
    case 2: /* CS/HS */
nkeynes@37
   723
	cond = armr.c;
nkeynes@37
   724
	break;
nkeynes@37
   725
    case 3: /* CC/LO */
nkeynes@37
   726
	cond = !armr.c;
nkeynes@37
   727
	break;
nkeynes@37
   728
    case 4: /* MI */
nkeynes@37
   729
	cond = armr.n;
nkeynes@37
   730
	break;
nkeynes@37
   731
    case 5: /* PL */
nkeynes@37
   732
	cond = !armr.n;
nkeynes@37
   733
	break;
nkeynes@37
   734
    case 6: /* VS */
nkeynes@37
   735
	cond = armr.v;
nkeynes@37
   736
	break;
nkeynes@37
   737
    case 7: /* VC */
nkeynes@37
   738
	cond = !armr.v;
nkeynes@37
   739
	break;
nkeynes@37
   740
    case 8: /* HI */
nkeynes@37
   741
	cond = armr.c && !armr.z;
nkeynes@37
   742
	break;
nkeynes@37
   743
    case 9: /* LS */
nkeynes@37
   744
	cond = (!armr.c) || armr.z;
nkeynes@37
   745
	break;
nkeynes@37
   746
    case 10: /* GE */
nkeynes@37
   747
	cond = (armr.n == armr.v);
nkeynes@37
   748
	break;
nkeynes@37
   749
    case 11: /* LT */
nkeynes@37
   750
	cond = (armr.n != armr.v);
nkeynes@37
   751
	break;
nkeynes@37
   752
    case 12: /* GT */
nkeynes@37
   753
	cond = (!armr.z) && (armr.n == armr.v);
nkeynes@37
   754
	break;
nkeynes@37
   755
    case 13: /* LE */
nkeynes@37
   756
	cond = armr.z || (armr.n != armr.v);
nkeynes@37
   757
	break;
nkeynes@37
   758
    case 14: /* AL */
nkeynes@37
   759
	cond = 1;
nkeynes@37
   760
	break;
nkeynes@37
   761
    case 15: /* (NV) */
nkeynes@37
   762
	cond = 0;
nkeynes@37
   763
	UNDEF(ir);
nkeynes@37
   764
    }
nkeynes@86
   765
    if( cond ) {
nkeynes@5
   766
nkeynes@37
   767
    /**
nkeynes@37
   768
     * Condition passed, now for the actual instructions...
nkeynes@37
   769
     */
nkeynes@37
   770
    switch( GRP(ir) ) {
nkeynes@37
   771
    case 0:
nkeynes@37
   772
	if( (ir & 0x0D900000) == 0x01000000 ) {
nkeynes@37
   773
	    /* Instructions that aren't actual data processing even though
nkeynes@37
   774
	     * they sit in the DP instruction block.
nkeynes@37
   775
	     */
nkeynes@37
   776
	    switch( ir & 0x0FF000F0 ) {
nkeynes@37
   777
	    case 0x01200010: /* BX Rd */
nkeynes@37
   778
		armr.t = ir & 0x01;
nkeynes@37
   779
		armr.r[15] = RM(ir) & 0xFFFFFFFE;
nkeynes@37
   780
		break;
nkeynes@37
   781
	    case 0x01000000: /* MRS Rd, CPSR */
nkeynes@37
   782
		LRD(ir) = arm_get_cpsr();
nkeynes@37
   783
		break;
nkeynes@37
   784
	    case 0x01400000: /* MRS Rd, SPSR */
nkeynes@37
   785
		LRD(ir) = armr.spsr;
nkeynes@37
   786
		break;
nkeynes@37
   787
	    case 0x01200000: /* MSR CPSR, Rd */
nkeynes@37
   788
		arm_set_cpsr( RM(ir), ir );
nkeynes@37
   789
		break;
nkeynes@37
   790
	    case 0x01600000: /* MSR SPSR, Rd */
nkeynes@37
   791
		arm_set_spsr( RM(ir), ir );
nkeynes@37
   792
		break;
nkeynes@37
   793
	    case 0x03200000: /* MSR CPSR, imm */
nkeynes@37
   794
		arm_set_cpsr( ROTIMM12(ir), ir );
nkeynes@37
   795
		break;
nkeynes@37
   796
	    case 0x03600000: /* MSR SPSR, imm */
nkeynes@37
   797
		arm_set_spsr( ROTIMM12(ir), ir );
nkeynes@37
   798
		break;
nkeynes@37
   799
	    default:
nkeynes@37
   800
		UNIMP(ir);
nkeynes@37
   801
	    }
nkeynes@37
   802
	} else if( (ir & 0x0E000090) == 0x00000090 ) {
nkeynes@37
   803
	    /* Neither are these */
nkeynes@37
   804
	    switch( (ir>>5)&0x03 ) {
nkeynes@37
   805
	    case 0:
nkeynes@37
   806
		/* Arithmetic extension area */
nkeynes@37
   807
		switch(OPCODE(ir)) {
nkeynes@37
   808
		case 0: /* MUL */
nkeynes@51
   809
		    LRN(ir) = RM(ir) * RS(ir);
nkeynes@37
   810
		    break;
nkeynes@37
   811
		case 1: /* MULS */
nkeynes@51
   812
		    tmp = RM(ir) * RS(ir);
nkeynes@51
   813
		    LRN(ir) = tmp;
nkeynes@51
   814
		    armr.n = tmp>>31;
nkeynes@51
   815
		    armr.z = (tmp == 0);
nkeynes@37
   816
		    break;
nkeynes@37
   817
		case 2: /* MLA */
nkeynes@51
   818
		    LRN(ir) = RM(ir) * RS(ir) + RD(ir);
nkeynes@37
   819
		    break;
nkeynes@37
   820
		case 3: /* MLAS */
nkeynes@51
   821
		    tmp = RM(ir) * RS(ir) + RD(ir);
nkeynes@51
   822
		    LRN(ir) = tmp;
nkeynes@51
   823
		    armr.n = tmp>>31;
nkeynes@51
   824
		    armr.z = (tmp == 0);
nkeynes@37
   825
		    break;
nkeynes@37
   826
		case 8: /* UMULL */
nkeynes@37
   827
		case 9: /* UMULLS */
nkeynes@37
   828
		case 10: /* UMLAL */
nkeynes@37
   829
		case 11: /* UMLALS */
nkeynes@37
   830
		case 12: /* SMULL */
nkeynes@37
   831
		case 13: /* SMULLS */
nkeynes@37
   832
		case 14: /* SMLAL */
nkeynes@37
   833
		case 15: /* SMLALS */
nkeynes@63
   834
		    UNIMP(ir);
nkeynes@37
   835
		    break;
nkeynes@37
   836
		case 16: /* SWP */
nkeynes@51
   837
		    tmp = arm_read_long( RN(ir) );
nkeynes@51
   838
		    switch( RN(ir) & 0x03 ) {
nkeynes@51
   839
		    case 1:
nkeynes@51
   840
			tmp = ROTATE_RIGHT_LONG(tmp, 8);
nkeynes@51
   841
			break;
nkeynes@51
   842
		    case 2:
nkeynes@51
   843
			tmp = ROTATE_RIGHT_LONG(tmp, 16);
nkeynes@51
   844
			break;
nkeynes@51
   845
		    case 3:
nkeynes@51
   846
			tmp = ROTATE_RIGHT_LONG(tmp, 24);
nkeynes@51
   847
			break;
nkeynes@51
   848
		    }
nkeynes@51
   849
		    arm_write_long( RN(ir), RM(ir) );
nkeynes@51
   850
		    LRD(ir) = tmp;
nkeynes@37
   851
		    break;
nkeynes@37
   852
		case 20: /* SWPB */
nkeynes@51
   853
		    tmp = arm_read_byte( RN(ir) );
nkeynes@51
   854
		    arm_write_byte( RN(ir), RM(ir) );
nkeynes@51
   855
		    LRD(ir) = tmp;
nkeynes@37
   856
		    break;
nkeynes@37
   857
		default:
nkeynes@37
   858
		    UNIMP(ir);
nkeynes@5
   859
		}
nkeynes@5
   860
		break;
nkeynes@37
   861
	    case 1:
nkeynes@37
   862
		if( LFLAG(ir) ) {
nkeynes@37
   863
		    /* LDRH */
nkeynes@37
   864
		} else {
nkeynes@37
   865
		    /* STRH */
nkeynes@37
   866
		}
nkeynes@49
   867
		UNIMP(ir);
nkeynes@5
   868
		break;
nkeynes@37
   869
	    case 2:
nkeynes@37
   870
		if( LFLAG(ir) ) {
nkeynes@37
   871
		    /* LDRSB */
nkeynes@37
   872
		} else {
nkeynes@37
   873
		}
nkeynes@49
   874
		UNIMP(ir);
nkeynes@5
   875
		break;
nkeynes@37
   876
	    case 3:
nkeynes@37
   877
		if( LFLAG(ir) ) {
nkeynes@37
   878
		    /* LDRSH */
nkeynes@37
   879
		} else {
nkeynes@37
   880
		}
nkeynes@49
   881
		UNIMP(ir);
nkeynes@5
   882
		break;
nkeynes@37
   883
	    }
nkeynes@37
   884
	} else {
nkeynes@37
   885
	    /* Data processing */
nkeynes@37
   886
nkeynes@37
   887
	    switch(OPCODE(ir)) {
nkeynes@37
   888
	    case 0: /* AND Rd, Rn, operand */
nkeynes@37
   889
		LRD(ir) = RN(ir) & arm_get_shift_operand(ir);
nkeynes@37
   890
		break;
nkeynes@37
   891
	    case 1: /* ANDS Rd, Rn, operand */
nkeynes@37
   892
		operand = arm_get_shift_operand_s(ir) & RN(ir);
nkeynes@37
   893
		LRD(ir) = operand;
nkeynes@37
   894
		if( RDn(ir) == 15 ) {
nkeynes@37
   895
		    arm_restore_cpsr();
nkeynes@37
   896
		} else {
nkeynes@37
   897
		    armr.n = operand>>31;
nkeynes@37
   898
		    armr.z = (operand == 0);
nkeynes@37
   899
		    armr.c = armr.shift_c;
nkeynes@37
   900
		}
nkeynes@37
   901
		break;
nkeynes@37
   902
	    case 2: /* EOR Rd, Rn, operand */
nkeynes@37
   903
		LRD(ir) = RN(ir) ^ arm_get_shift_operand(ir);
nkeynes@37
   904
		break;
nkeynes@37
   905
	    case 3: /* EORS Rd, Rn, operand */
nkeynes@37
   906
		operand = arm_get_shift_operand_s(ir) ^ RN(ir);
nkeynes@37
   907
		LRD(ir) = operand;
nkeynes@37
   908
		if( RDn(ir) == 15 ) {
nkeynes@37
   909
		    arm_restore_cpsr();
nkeynes@37
   910
		} else {
nkeynes@37
   911
		    armr.n = operand>>31;
nkeynes@37
   912
		    armr.z = (operand == 0);
nkeynes@37
   913
		    armr.c = armr.shift_c;
nkeynes@37
   914
		}
nkeynes@37
   915
		break;
nkeynes@37
   916
	    case 4: /* SUB Rd, Rn, operand */
nkeynes@37
   917
		LRD(ir) = RN(ir) - arm_get_shift_operand(ir);
nkeynes@37
   918
		break;
nkeynes@37
   919
	    case 5: /* SUBS Rd, Rn, operand */
nkeynes@37
   920
		operand = RN(ir);
nkeynes@37
   921
		operand2 = arm_get_shift_operand(ir);
nkeynes@37
   922
		tmp = operand - operand2;
nkeynes@37
   923
		LRD(ir) = tmp;
nkeynes@37
   924
		if( RDn(ir) == 15 ) {
nkeynes@37
   925
		    arm_restore_cpsr();
nkeynes@37
   926
		} else {
nkeynes@37
   927
		    armr.n = tmp>>31;
nkeynes@37
   928
		    armr.z = (tmp == 0);
nkeynes@37
   929
		    armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@37
   930
		    armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@37
   931
		}
nkeynes@37
   932
		break;
nkeynes@37
   933
	    case 6: /* RSB Rd, operand, Rn */
nkeynes@37
   934
		LRD(ir) = arm_get_shift_operand(ir) - RN(ir);
nkeynes@37
   935
		break;
nkeynes@37
   936
	    case 7: /* RSBS Rd, operand, Rn */
nkeynes@37
   937
		operand = arm_get_shift_operand(ir);
nkeynes@37
   938
		operand2 = RN(ir);
nkeynes@37
   939
		tmp = operand - operand2;
nkeynes@37
   940
		LRD(ir) = tmp;
nkeynes@37
   941
		if( RDn(ir) == 15 ) {
nkeynes@37
   942
		    arm_restore_cpsr();
nkeynes@37
   943
		} else {
nkeynes@37
   944
		    armr.n = tmp>>31;
nkeynes@37
   945
		    armr.z = (tmp == 0);
nkeynes@37
   946
		    armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@37
   947
		    armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@37
   948
		}
nkeynes@37
   949
		break;
nkeynes@37
   950
	    case 8: /* ADD Rd, Rn, operand */
nkeynes@37
   951
		LRD(ir) = RN(ir) + arm_get_shift_operand(ir);
nkeynes@37
   952
		break;
nkeynes@37
   953
	    case 9: /* ADDS Rd, Rn, operand */
nkeynes@37
   954
		operand = arm_get_shift_operand(ir);
nkeynes@37
   955
		operand2 = RN(ir);
nkeynes@37
   956
		tmp = operand + operand2;
nkeynes@37
   957
		LRD(ir) = tmp;
nkeynes@37
   958
		if( RDn(ir) == 15 ) {
nkeynes@37
   959
		    arm_restore_cpsr();
nkeynes@37
   960
		} else {
nkeynes@37
   961
		    armr.n = tmp>>31;
nkeynes@37
   962
		    armr.z = (tmp == 0);
nkeynes@37
   963
		    armr.c = IS_CARRY(tmp,operand,operand2);
nkeynes@37
   964
		    armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
nkeynes@37
   965
		}
nkeynes@37
   966
		break;			
nkeynes@37
   967
	    case 10: /* ADC */
nkeynes@49
   968
		LRD(ir) = RN(ir) + arm_get_shift_operand(ir) + 
nkeynes@49
   969
		    (armr.c ? 1 : 0);
nkeynes@49
   970
		break;
nkeynes@37
   971
	    case 11: /* ADCS */
nkeynes@49
   972
		operand = arm_get_shift_operand(ir);
nkeynes@49
   973
		operand2 = RN(ir);
nkeynes@49
   974
		tmp = operand + operand2;
nkeynes@49
   975
		tmp2 = tmp + armr.c ? 1 : 0;
nkeynes@49
   976
		LRD(ir) = tmp2;
nkeynes@49
   977
		if( RDn(ir) == 15 ) {
nkeynes@49
   978
		    arm_restore_cpsr();
nkeynes@49
   979
		} else {
nkeynes@49
   980
		    armr.n = tmp >> 31;
nkeynes@49
   981
		    armr.z = (tmp == 0 );
nkeynes@49
   982
		    armr.c = IS_CARRY(tmp,operand,operand2) ||
nkeynes@49
   983
			(tmp2 < tmp);
nkeynes@49
   984
		    armr.v = IS_ADDOVERFLOW(tmp,operand, operand2) ||
nkeynes@49
   985
			((tmp&0x80000000) != (tmp2&0x80000000));
nkeynes@49
   986
		}
nkeynes@49
   987
		break;
nkeynes@37
   988
	    case 12: /* SBC */
nkeynes@49
   989
		LRD(ir) = RN(ir) - arm_get_shift_operand(ir) - 
nkeynes@49
   990
		    (armr.c ? 0 : 1);
nkeynes@49
   991
		break;
nkeynes@37
   992
	    case 13: /* SBCS */
nkeynes@49
   993
		operand = RN(ir);
nkeynes@49
   994
		operand2 = arm_get_shift_operand(ir);
nkeynes@49
   995
		tmp = operand - operand2;
nkeynes@49
   996
		tmp2 = tmp - (armr.c ? 0 : 1);
nkeynes@49
   997
		if( RDn(ir) == 15 ) {
nkeynes@49
   998
		    arm_restore_cpsr();
nkeynes@49
   999
		} else {
nkeynes@49
  1000
		    armr.n = tmp >> 31;
nkeynes@49
  1001
		    armr.z = (tmp == 0 );
nkeynes@49
  1002
		    armr.c = IS_NOTBORROW(tmp,operand,operand2) &&
nkeynes@49
  1003
			(tmp2<tmp);
nkeynes@49
  1004
		    armr.v = IS_SUBOVERFLOW(tmp,operand,operand2) ||
nkeynes@49
  1005
			((tmp&0x80000000) != (tmp2&0x80000000));
nkeynes@49
  1006
		}
nkeynes@49
  1007
		break;
nkeynes@37
  1008
	    case 14: /* RSC */
nkeynes@49
  1009
		LRD(ir) = arm_get_shift_operand(ir) - RN(ir) -
nkeynes@49
  1010
		    (armr.c ? 0 : 1);
nkeynes@49
  1011
		break;
nkeynes@37
  1012
	    case 15: /* RSCS */
nkeynes@49
  1013
		operand = arm_get_shift_operand(ir);
nkeynes@49
  1014
		operand2 = RN(ir);
nkeynes@49
  1015
		tmp = operand - operand2;
nkeynes@49
  1016
		tmp2 = tmp - (armr.c ? 0 : 1);
nkeynes@49
  1017
		if( RDn(ir) == 15 ) {
nkeynes@49
  1018
		    arm_restore_cpsr();
nkeynes@49
  1019
		} else {
nkeynes@49
  1020
		    armr.n = tmp >> 31;
nkeynes@49
  1021
		    armr.z = (tmp == 0 );
nkeynes@49
  1022
		    armr.c = IS_NOTBORROW(tmp,operand,operand2) &&
nkeynes@49
  1023
			(tmp2<tmp);
nkeynes@49
  1024
		    armr.v = IS_SUBOVERFLOW(tmp,operand,operand2) ||
nkeynes@49
  1025
			((tmp&0x80000000) != (tmp2&0x80000000));
nkeynes@49
  1026
		}
nkeynes@37
  1027
		break;
nkeynes@37
  1028
	    case 17: /* TST Rn, operand */
nkeynes@37
  1029
		operand = arm_get_shift_operand_s(ir) & RN(ir);
nkeynes@37
  1030
		armr.n = operand>>31;
nkeynes@37
  1031
		armr.z = (operand == 0);
nkeynes@37
  1032
		armr.c = armr.shift_c;
nkeynes@37
  1033
		break;
nkeynes@37
  1034
	    case 19: /* TEQ Rn, operand */
nkeynes@37
  1035
		operand = arm_get_shift_operand_s(ir) ^ RN(ir);
nkeynes@37
  1036
		armr.n = operand>>31;
nkeynes@37
  1037
		armr.z = (operand == 0);
nkeynes@37
  1038
		armr.c = armr.shift_c;
nkeynes@37
  1039
		break;				
nkeynes@37
  1040
	    case 21: /* CMP Rn, operand */
nkeynes@37
  1041
		operand = RN(ir);
nkeynes@37
  1042
		operand2 = arm_get_shift_operand(ir);
nkeynes@37
  1043
		tmp = operand - operand2;
nkeynes@37
  1044
		armr.n = tmp>>31;
nkeynes@37
  1045
		armr.z = (tmp == 0);
nkeynes@37
  1046
		armr.c = IS_NOTBORROW(tmp,operand,operand2);
nkeynes@37
  1047
		armr.v = IS_SUBOVERFLOW(tmp,operand,operand2);
nkeynes@37
  1048
		break;
nkeynes@37
  1049
	    case 23: /* CMN Rn, operand */
nkeynes@37
  1050
		operand = RN(ir);
nkeynes@37
  1051
		operand2 = arm_get_shift_operand(ir);
nkeynes@37
  1052
		tmp = operand + operand2;
nkeynes@37
  1053
		armr.n = tmp>>31;
nkeynes@37
  1054
		armr.z = (tmp == 0);
nkeynes@37
  1055
		armr.c = IS_CARRY(tmp,operand,operand2);
nkeynes@37
  1056
		armr.v = IS_ADDOVERFLOW(tmp,operand,operand2);
nkeynes@37
  1057
		break;
nkeynes@37
  1058
	    case 24: /* ORR Rd, Rn, operand */
nkeynes@37
  1059
		LRD(ir) = RN(ir) | arm_get_shift_operand(ir);
nkeynes@37
  1060
		break;
nkeynes@37
  1061
	    case 25: /* ORRS Rd, Rn, operand */
nkeynes@37
  1062
		operand = arm_get_shift_operand_s(ir) | RN(ir);
nkeynes@37
  1063
		LRD(ir) = operand;
nkeynes@37
  1064
		if( RDn(ir) == 15 ) {
nkeynes@37
  1065
		    arm_restore_cpsr();
nkeynes@37
  1066
		} else {
nkeynes@37
  1067
		    armr.n = operand>>31;
nkeynes@37
  1068
		    armr.z = (operand == 0);
nkeynes@37
  1069
		    armr.c = armr.shift_c;
nkeynes@37
  1070
		}
nkeynes@37
  1071
		break;
nkeynes@37
  1072
	    case 26: /* MOV Rd, operand */
nkeynes@37
  1073
		LRD(ir) = arm_get_shift_operand(ir);
nkeynes@37
  1074
		break;
nkeynes@37
  1075
	    case 27: /* MOVS Rd, operand */
nkeynes@37
  1076
		operand = arm_get_shift_operand_s(ir);
nkeynes@37
  1077
		LRD(ir) = operand;
nkeynes@37
  1078
		if( RDn(ir) == 15 ) {
nkeynes@37
  1079
		    arm_restore_cpsr();
nkeynes@37
  1080
		} else {
nkeynes@37
  1081
		    armr.n = operand>>31;
nkeynes@37
  1082
		    armr.z = (operand == 0);
nkeynes@37
  1083
		    armr.c = armr.shift_c;
nkeynes@37
  1084
		}
nkeynes@37
  1085
		break;
nkeynes@37
  1086
	    case 28: /* BIC Rd, Rn, operand */
nkeynes@37
  1087
		LRD(ir) = RN(ir) & (~arm_get_shift_operand(ir));
nkeynes@37
  1088
		break;
nkeynes@37
  1089
	    case 29: /* BICS Rd, Rn, operand */
nkeynes@37
  1090
		operand = RN(ir) & (~arm_get_shift_operand_s(ir));
nkeynes@37
  1091
		LRD(ir) = operand;
nkeynes@37
  1092
		if( RDn(ir) == 15 ) {
nkeynes@37
  1093
		    arm_restore_cpsr();
nkeynes@37
  1094
		} else {
nkeynes@37
  1095
		    armr.n = operand>>31;
nkeynes@37
  1096
		    armr.z = (operand == 0);
nkeynes@37
  1097
		    armr.c = armr.shift_c;
nkeynes@37
  1098
		}
nkeynes@37
  1099
		break;
nkeynes@37
  1100
	    case 30: /* MVN Rd, operand */
nkeynes@37
  1101
		LRD(ir) = ~arm_get_shift_operand(ir);
nkeynes@37
  1102
		break;
nkeynes@37
  1103
	    case 31: /* MVNS Rd, operand */
nkeynes@37
  1104
		operand = ~arm_get_shift_operand_s(ir);
nkeynes@37
  1105
		LRD(ir) = operand;
nkeynes@37
  1106
		if( RDn(ir) == 15 ) {
nkeynes@37
  1107
		    arm_restore_cpsr();
nkeynes@37
  1108
		} else {
nkeynes@37
  1109
		    armr.n = operand>>31;
nkeynes@37
  1110
		    armr.z = (operand == 0);
nkeynes@37
  1111
		    armr.c = armr.shift_c;
nkeynes@37
  1112
		}
nkeynes@37
  1113
		break;
nkeynes@37
  1114
	    default:
nkeynes@37
  1115
		UNIMP(ir);
nkeynes@37
  1116
	    }
nkeynes@5
  1117
	}
nkeynes@37
  1118
	break;
nkeynes@37
  1119
    case 1: /* Load/store */
nkeynes@37
  1120
	operand = arm_get_address_operand(ir);
nkeynes@37
  1121
	switch( (ir>>20)&0x17 ) {
nkeynes@37
  1122
	case 0: case 16: case 18: /* STR Rd, address */
nkeynes@37
  1123
	    arm_write_long( operand, RD(ir) );
nkeynes@37
  1124
	    break;
nkeynes@37
  1125
	case 1: case 17: case 19: /* LDR Rd, address */
nkeynes@37
  1126
	    LRD(ir) = arm_read_long(operand);
nkeynes@37
  1127
	    break;
nkeynes@37
  1128
	case 2: /* STRT Rd, address */
nkeynes@37
  1129
	    arm_write_long_user( operand, RD(ir) );
nkeynes@37
  1130
	    break;
nkeynes@37
  1131
	case 3: /* LDRT Rd, address */
nkeynes@37
  1132
	    LRD(ir) = arm_read_long_user( operand );
nkeynes@37
  1133
	    break;
nkeynes@37
  1134
	case 4: case 20: case 22: /* STRB Rd, address */
nkeynes@37
  1135
	    arm_write_byte( operand, RD(ir) );
nkeynes@37
  1136
	    break;
nkeynes@37
  1137
	case 5: case 21: case 23: /* LDRB Rd, address */
nkeynes@37
  1138
	    LRD(ir) = arm_read_byte( operand );
nkeynes@37
  1139
	    break;
nkeynes@37
  1140
	case 6: /* STRBT Rd, address */
nkeynes@37
  1141
	    arm_write_byte_user( operand, RD(ir) );
nkeynes@37
  1142
	    break;
nkeynes@37
  1143
	case 7: /* LDRBT Rd, address */
nkeynes@37
  1144
	    LRD(ir) = arm_read_byte_user( operand );
nkeynes@37
  1145
	    break;
nkeynes@37
  1146
	}
nkeynes@37
  1147
	break;
nkeynes@37
  1148
    case 2: /* Load/store multiple, branch*/
nkeynes@37
  1149
	if( (ir & 0x02000000) == 0x02000000 ) { /* B[L] imm24 */
nkeynes@37
  1150
	    operand = (SIGNEXT24(ir&0x00FFFFFF) << 2);
nkeynes@37
  1151
	    if( (ir & 0x01000000) == 0x01000000 ) { 
nkeynes@37
  1152
		armr.r[14] = pc; /* BL */
nkeynes@37
  1153
	    }
nkeynes@37
  1154
	    armr.r[15] = pc + 4 + operand;
nkeynes@37
  1155
	} else { /* Load/store multiple */
nkeynes@81
  1156
	    gboolean needRestore = FALSE;
nkeynes@46
  1157
	    operand = RN(ir);
nkeynes@66
  1158
	    
nkeynes@66
  1159
	    switch( (ir & 0x01D00000) >> 20 ) {
nkeynes@66
  1160
	    case 0: /* STMDA */
nkeynes@81
  1161
		if( ir & 0x8000 ) {
nkeynes@81
  1162
		    arm_write_long( operand, armr.r[15]+4 );
nkeynes@81
  1163
		    operand -= 4;
nkeynes@81
  1164
		}
nkeynes@81
  1165
		for( i=14; i>= 0; i-- ) {
nkeynes@66
  1166
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1167
			arm_write_long( operand, armr.r[i] );
nkeynes@66
  1168
			operand -= 4;
nkeynes@66
  1169
		    }
nkeynes@66
  1170
		}
nkeynes@66
  1171
		break;
nkeynes@66
  1172
	    case 1: /* LDMDA */
nkeynes@66
  1173
		for( i=15; i>= 0; i-- ) {
nkeynes@66
  1174
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1175
			armr.r[i] = arm_read_long( operand );
nkeynes@66
  1176
			operand -= 4;
nkeynes@66
  1177
		    }
nkeynes@66
  1178
		}
nkeynes@66
  1179
		break;
nkeynes@66
  1180
	    case 4: /* STMDA (S) */
nkeynes@81
  1181
		if( ir & 0x8000 ) {
nkeynes@81
  1182
		    arm_write_long( operand, armr.r[15]+4 );
nkeynes@81
  1183
		    operand -= 4;
nkeynes@81
  1184
		}
nkeynes@81
  1185
		for( i=14; i>= 0; i-- ) {
nkeynes@66
  1186
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1187
			arm_write_long( operand, USER_R(i) );
nkeynes@66
  1188
			operand -= 4;
nkeynes@66
  1189
		    }
nkeynes@66
  1190
		}
nkeynes@66
  1191
		break;
nkeynes@66
  1192
	    case 5: /* LDMDA (S) */
nkeynes@66
  1193
		if( (ir&0x00008000) ) { /* Load PC */
nkeynes@66
  1194
		    for( i=15; i>= 0; i-- ) {
nkeynes@66
  1195
			if( (ir & (1<<i)) ) {
nkeynes@66
  1196
			    armr.r[i] = arm_read_long( operand );
nkeynes@66
  1197
			    operand -= 4;
nkeynes@46
  1198
			}
nkeynes@46
  1199
		    }
nkeynes@81
  1200
		    needRestore = TRUE;
nkeynes@46
  1201
		} else {
nkeynes@66
  1202
		    for( i=15; i>= 0; i-- ) {
nkeynes@66
  1203
			if( (ir & (1<<i)) ) {
nkeynes@66
  1204
			    USER_R(i) = arm_read_long( operand );
nkeynes@66
  1205
			    operand -= 4;
nkeynes@46
  1206
			}
nkeynes@46
  1207
		    }
nkeynes@66
  1208
		}
nkeynes@66
  1209
		break;
nkeynes@66
  1210
	    case 8: /* STMIA */
nkeynes@81
  1211
		for( i=0; i< 15; i++ ) {
nkeynes@66
  1212
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1213
			arm_write_long( operand, armr.r[i] );
nkeynes@66
  1214
			operand += 4;
nkeynes@66
  1215
		    }
nkeynes@66
  1216
		}
nkeynes@81
  1217
		if( ir & 0x8000 ) {
nkeynes@81
  1218
		    arm_write_long( operand, armr.r[15]+4 );
nkeynes@81
  1219
		    operand += 4;
nkeynes@81
  1220
		}
nkeynes@66
  1221
		break;
nkeynes@66
  1222
	    case 9: /* LDMIA */
nkeynes@66
  1223
		for( i=0; i< 16; i++ ) {
nkeynes@66
  1224
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1225
			armr.r[i] = arm_read_long( operand );
nkeynes@66
  1226
			operand += 4;
nkeynes@66
  1227
		    }
nkeynes@66
  1228
		}
nkeynes@66
  1229
		break;
nkeynes@66
  1230
	    case 12: /* STMIA (S) */
nkeynes@81
  1231
		for( i=0; i< 15; i++ ) {
nkeynes@66
  1232
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1233
			arm_write_long( operand, USER_R(i) );
nkeynes@66
  1234
			operand += 4;
nkeynes@66
  1235
		    }
nkeynes@66
  1236
		}
nkeynes@81
  1237
		if( ir & 0x8000 ) {
nkeynes@81
  1238
		    arm_write_long( operand, armr.r[15]+4 );
nkeynes@81
  1239
		    operand += 4;
nkeynes@81
  1240
		}
nkeynes@66
  1241
		break;
nkeynes@66
  1242
	    case 13: /* LDMIA (S) */
nkeynes@66
  1243
		if( (ir&0x00008000) ) { /* Load PC */
nkeynes@66
  1244
		    for( i=0; i < 16; i++ ) {
nkeynes@66
  1245
			if( (ir & (1<<i)) ) {
nkeynes@66
  1246
			    armr.r[i] = arm_read_long( operand );
nkeynes@66
  1247
			    operand += 4;
nkeynes@46
  1248
			}
nkeynes@46
  1249
		    }
nkeynes@81
  1250
		    needRestore = TRUE;
nkeynes@66
  1251
		} else {
nkeynes@66
  1252
		    for( i=0; i < 16; i++ ) {
nkeynes@66
  1253
			if( (ir & (1<<i)) ) {
nkeynes@66
  1254
			    USER_R(i) = arm_read_long( operand );
nkeynes@66
  1255
			    operand += 4;
nkeynes@46
  1256
			}
nkeynes@46
  1257
		    }
nkeynes@46
  1258
		}
nkeynes@66
  1259
		break;
nkeynes@66
  1260
	    case 16: /* STMDB */
nkeynes@81
  1261
		if( ir & 0x8000 ) {
nkeynes@81
  1262
		    operand -= 4;
nkeynes@81
  1263
		    arm_write_long( operand, armr.r[15]+4 );
nkeynes@81
  1264
		}
nkeynes@81
  1265
		for( i=14; i>= 0; i-- ) {
nkeynes@66
  1266
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1267
			operand -= 4;
nkeynes@66
  1268
			arm_write_long( operand, armr.r[i] );
nkeynes@46
  1269
		    }
nkeynes@46
  1270
		}
nkeynes@66
  1271
		break;
nkeynes@66
  1272
	    case 17: /* LDMDB */
nkeynes@66
  1273
		for( i=15; i>= 0; i-- ) {
nkeynes@66
  1274
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1275
			operand -= 4;
nkeynes@66
  1276
			armr.r[i] = arm_read_long( operand );
nkeynes@66
  1277
		    }
nkeynes@66
  1278
		}
nkeynes@66
  1279
		break;
nkeynes@66
  1280
	    case 20: /* STMDB (S) */
nkeynes@81
  1281
		if( ir & 0x8000 ) {
nkeynes@81
  1282
		    operand -= 4;
nkeynes@81
  1283
		    arm_write_long( operand, armr.r[15]+4 );
nkeynes@81
  1284
		}
nkeynes@81
  1285
		for( i=14; i>= 0; i-- ) {
nkeynes@66
  1286
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1287
			operand -= 4;
nkeynes@66
  1288
			arm_write_long( operand, USER_R(i) );
nkeynes@66
  1289
		    }
nkeynes@66
  1290
		}
nkeynes@66
  1291
		break;
nkeynes@66
  1292
	    case 21: /* LDMDB (S) */
nkeynes@66
  1293
		if( (ir&0x00008000) ) { /* Load PC */
nkeynes@66
  1294
		    for( i=15; i>= 0; i-- ) {
nkeynes@66
  1295
			if( (ir & (1<<i)) ) {
nkeynes@66
  1296
			    operand -= 4;
nkeynes@66
  1297
			    armr.r[i] = arm_read_long( operand );
nkeynes@66
  1298
			}
nkeynes@66
  1299
		    }
nkeynes@81
  1300
		    needRestore = TRUE;
nkeynes@66
  1301
		} else {
nkeynes@66
  1302
		    for( i=15; i>= 0; i-- ) {
nkeynes@66
  1303
			if( (ir & (1<<i)) ) {
nkeynes@66
  1304
			    operand -= 4;
nkeynes@66
  1305
			    USER_R(i) = arm_read_long( operand );
nkeynes@66
  1306
			}
nkeynes@66
  1307
		    }
nkeynes@66
  1308
		}
nkeynes@66
  1309
		break;
nkeynes@66
  1310
	    case 24: /* STMIB */
nkeynes@81
  1311
		for( i=0; i< 15; i++ ) {
nkeynes@66
  1312
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1313
			operand += 4;
nkeynes@66
  1314
			arm_write_long( operand, armr.r[i] );
nkeynes@66
  1315
		    }
nkeynes@66
  1316
		}
nkeynes@81
  1317
		if( ir & 0x8000 ) {
nkeynes@81
  1318
		    operand += 4;
nkeynes@81
  1319
		    arm_write_long( operand, armr.r[15]+4 );
nkeynes@81
  1320
		}
nkeynes@66
  1321
		break;
nkeynes@66
  1322
	    case 25: /* LDMIB */
nkeynes@66
  1323
		for( i=0; i< 16; i++ ) {
nkeynes@66
  1324
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1325
			operand += 4;
nkeynes@66
  1326
			armr.r[i] = arm_read_long( operand );
nkeynes@66
  1327
		    }
nkeynes@66
  1328
		}
nkeynes@66
  1329
		break;
nkeynes@66
  1330
	    case 28: /* STMIB (S) */
nkeynes@81
  1331
		for( i=0; i< 15; i++ ) {
nkeynes@66
  1332
		    if( (ir & (1<<i)) ) {
nkeynes@66
  1333
			operand += 4;
nkeynes@66
  1334
			arm_write_long( operand, USER_R(i) );
nkeynes@66
  1335
		    }
nkeynes@66
  1336
		}
nkeynes@81
  1337
		if( ir & 0x8000 ) {
nkeynes@81
  1338
		    operand += 4;
nkeynes@81
  1339
		    arm_write_long( operand, armr.r[15]+4 );
nkeynes@81
  1340
		}
nkeynes@66
  1341
		break;
nkeynes@66
  1342
	    case 29: /* LDMIB (S) */
nkeynes@66
  1343
		if( (ir&0x00008000) ) { /* Load PC */
nkeynes@66
  1344
		    for( i=0; i < 16; i++ ) {
nkeynes@66
  1345
			if( (ir & (1<<i)) ) {
nkeynes@66
  1346
			    operand += 4;
nkeynes@66
  1347
			    armr.r[i] = arm_read_long( operand );
nkeynes@66
  1348
			}
nkeynes@66
  1349
		    }
nkeynes@81
  1350
		    needRestore = TRUE;
nkeynes@66
  1351
		} else {
nkeynes@66
  1352
		    for( i=0; i < 16; i++ ) {
nkeynes@66
  1353
			if( (ir & (1<<i)) ) {
nkeynes@66
  1354
			    operand += 4;
nkeynes@66
  1355
			    USER_R(i) = arm_read_long( operand );
nkeynes@66
  1356
			}
nkeynes@66
  1357
		    }
nkeynes@66
  1358
		}
nkeynes@66
  1359
		break;
nkeynes@46
  1360
	    }
nkeynes@66
  1361
	    
nkeynes@66
  1362
	    if( WFLAG(ir) ) 
nkeynes@66
  1363
		LRN(ir) = operand;
nkeynes@81
  1364
	    if( needRestore ) 
nkeynes@81
  1365
		arm_restore_cpsr();
nkeynes@37
  1366
	}
nkeynes@37
  1367
	break;
nkeynes@37
  1368
    case 3: /* Copro */
nkeynes@51
  1369
	if( (ir & 0x0F000000) == 0x0F000000 ) { /* SWI */
nkeynes@51
  1370
	    arm_raise_exception( EXC_SOFTWARE );
nkeynes@51
  1371
	} else {
nkeynes@51
  1372
	    UNIMP(ir);
nkeynes@51
  1373
	}
nkeynes@37
  1374
	break;
nkeynes@37
  1375
    }
nkeynes@86
  1376
nkeynes@86
  1377
    }
nkeynes@86
  1378
nkeynes@86
  1379
    if( armr.r[15] >= 0x00200000 ) {
nkeynes@86
  1380
	armr.running = FALSE;
nkeynes@86
  1381
	ERROR( "ARM Halted: BRANCH to invalid address %08X at %08X", armr.r[15], pc );
nkeynes@81
  1382
	return FALSE;
nkeynes@81
  1383
    }
nkeynes@37
  1384
    return TRUE;
nkeynes@2
  1385
}
.