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