Search
lxdream.org :: lxdream/src/sh4/sh4core.in
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4core.in
changeset 1083:34895c8bab20
prev1067:d3c00ffccfcd
next1103:de9ad2c0cf56
author nkeynes
date Wed Dec 02 10:36:49 2009 +1000 (14 years ago)
permissions -rw-r--r--
last change Add missing SUBV instruction to the emulation core (translation core is ok),
along with test cases. Thanks to D. Jeff Dionne for pointing this out.
file annotate diff log raw
nkeynes@359
     1
/**
nkeynes@586
     2
 * $Id$
nkeynes@359
     3
 * 
nkeynes@359
     4
 * SH4 emulation core, and parent module for all the SH4 peripheral
nkeynes@359
     5
 * modules.
nkeynes@359
     6
 *
nkeynes@359
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@359
     8
 *
nkeynes@359
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@359
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@359
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@359
    12
 * (at your option) any later version.
nkeynes@359
    13
 *
nkeynes@359
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@359
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@359
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@359
    17
 * GNU General Public License for more details.
nkeynes@359
    18
 */
nkeynes@359
    19
nkeynes@359
    20
#define MODULE sh4_module
nkeynes@586
    21
#include <assert.h>
nkeynes@359
    22
#include <math.h>
nkeynes@359
    23
#include "dream.h"
nkeynes@430
    24
#include "dreamcast.h"
nkeynes@430
    25
#include "eventq.h"
nkeynes@430
    26
#include "mem.h"
nkeynes@430
    27
#include "clock.h"
nkeynes@430
    28
#include "syscall.h"
nkeynes@359
    29
#include "sh4/sh4core.h"
nkeynes@359
    30
#include "sh4/sh4mmio.h"
nkeynes@671
    31
#include "sh4/sh4stat.h"
nkeynes@945
    32
#include "sh4/mmu.h"
nkeynes@359
    33
nkeynes@359
    34
#define SH4_CALLTRACE 1
nkeynes@359
    35
nkeynes@359
    36
#define MAX_INT 0x7FFFFFFF
nkeynes@359
    37
#define MIN_INT 0x80000000
nkeynes@359
    38
#define MAX_INTF 2147483647.0
nkeynes@359
    39
#define MIN_INTF -2147483648.0
nkeynes@359
    40
nkeynes@359
    41
/********************** SH4 Module Definition ****************************/
nkeynes@359
    42
nkeynes@740
    43
uint32_t sh4_emulate_run_slice( uint32_t nanosecs ) 
nkeynes@359
    44
{
nkeynes@359
    45
    int i;
nkeynes@359
    46
nkeynes@359
    47
    if( sh4_breakpoint_count == 0 ) {
nkeynes@359
    48
	for( ; sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) {
nkeynes@359
    49
	    if( SH4_EVENT_PENDING() ) {
nkeynes@359
    50
		if( sh4r.event_types & PENDING_EVENT ) {
nkeynes@359
    51
		    event_execute();
nkeynes@359
    52
		}
nkeynes@359
    53
		/* Eventq execute may (quite likely) deliver an immediate IRQ */
nkeynes@359
    54
		if( sh4r.event_types & PENDING_IRQ ) {
nkeynes@359
    55
		    sh4_accept_interrupt();
nkeynes@359
    56
		}
nkeynes@359
    57
	    }
nkeynes@359
    58
	    if( !sh4_execute_instruction() ) {
nkeynes@359
    59
		break;
nkeynes@359
    60
	    }
nkeynes@359
    61
	}
nkeynes@359
    62
    } else {
nkeynes@359
    63
	for( ;sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) {
nkeynes@359
    64
	    if( SH4_EVENT_PENDING() ) {
nkeynes@359
    65
		if( sh4r.event_types & PENDING_EVENT ) {
nkeynes@359
    66
		    event_execute();
nkeynes@359
    67
		}
nkeynes@359
    68
		/* Eventq execute may (quite likely) deliver an immediate IRQ */
nkeynes@359
    69
		if( sh4r.event_types & PENDING_IRQ ) {
nkeynes@359
    70
		    sh4_accept_interrupt();
nkeynes@359
    71
		}
nkeynes@359
    72
	    }
nkeynes@359
    73
                 
nkeynes@359
    74
	    if( !sh4_execute_instruction() )
nkeynes@359
    75
		break;
nkeynes@359
    76
#ifdef ENABLE_DEBUG_MODE
nkeynes@359
    77
	    for( i=0; i<sh4_breakpoint_count; i++ ) {
nkeynes@359
    78
		if( sh4_breakpoints[i].address == sh4r.pc ) {
nkeynes@359
    79
		    break;
nkeynes@359
    80
		}
nkeynes@359
    81
	    }
nkeynes@359
    82
	    if( i != sh4_breakpoint_count ) {
nkeynes@740
    83
	    	sh4_core_exit( CORE_EXIT_BREAKPOINT );
nkeynes@359
    84
	    }
nkeynes@359
    85
#endif	
nkeynes@359
    86
	}
nkeynes@359
    87
    }
nkeynes@359
    88
nkeynes@359
    89
    /* If we aborted early, but the cpu is still technically running,
nkeynes@359
    90
     * we're doing a hard abort - cut the timeslice back to what we
nkeynes@359
    91
     * actually executed
nkeynes@359
    92
     */
nkeynes@359
    93
    if( sh4r.slice_cycle != nanosecs && sh4r.sh4_state == SH4_STATE_RUNNING ) {
nkeynes@359
    94
	nanosecs = sh4r.slice_cycle;
nkeynes@359
    95
    }
nkeynes@359
    96
    if( sh4r.sh4_state != SH4_STATE_STANDBY ) {
nkeynes@359
    97
	TMU_run_slice( nanosecs );
nkeynes@359
    98
	SCIF_run_slice( nanosecs );
nkeynes@359
    99
    }
nkeynes@359
   100
    return nanosecs;
nkeynes@359
   101
}
nkeynes@359
   102
nkeynes@359
   103
/********************** SH4 emulation core  ****************************/
nkeynes@359
   104
nkeynes@359
   105
#if(SH4_CALLTRACE == 1)
nkeynes@359
   106
#define MAX_CALLSTACK 32
nkeynes@359
   107
static struct call_stack {
nkeynes@359
   108
    sh4addr_t call_addr;
nkeynes@359
   109
    sh4addr_t target_addr;
nkeynes@359
   110
    sh4addr_t stack_pointer;
nkeynes@359
   111
} call_stack[MAX_CALLSTACK];
nkeynes@359
   112
nkeynes@359
   113
static int call_stack_depth = 0;
nkeynes@359
   114
int sh4_call_trace_on = 0;
nkeynes@359
   115
nkeynes@430
   116
static inline void trace_call( sh4addr_t source, sh4addr_t dest ) 
nkeynes@359
   117
{
nkeynes@359
   118
    if( call_stack_depth < MAX_CALLSTACK ) {
nkeynes@359
   119
	call_stack[call_stack_depth].call_addr = source;
nkeynes@359
   120
	call_stack[call_stack_depth].target_addr = dest;
nkeynes@359
   121
	call_stack[call_stack_depth].stack_pointer = sh4r.r[15];
nkeynes@359
   122
    }
nkeynes@359
   123
    call_stack_depth++;
nkeynes@359
   124
}
nkeynes@359
   125
nkeynes@430
   126
static inline void trace_return( sh4addr_t source, sh4addr_t dest )
nkeynes@359
   127
{
nkeynes@359
   128
    if( call_stack_depth > 0 ) {
nkeynes@359
   129
	call_stack_depth--;
nkeynes@359
   130
    }
nkeynes@359
   131
}
nkeynes@359
   132
nkeynes@359
   133
void fprint_stack_trace( FILE *f )
nkeynes@359
   134
{
nkeynes@359
   135
    int i = call_stack_depth -1;
nkeynes@359
   136
    if( i >= MAX_CALLSTACK )
nkeynes@359
   137
	i = MAX_CALLSTACK - 1;
nkeynes@359
   138
    for( ; i >= 0; i-- ) {
nkeynes@359
   139
	fprintf( f, "%d. Call from %08X => %08X, SP=%08X\n", 
nkeynes@359
   140
		 (call_stack_depth - i), call_stack[i].call_addr,
nkeynes@359
   141
		 call_stack[i].target_addr, call_stack[i].stack_pointer );
nkeynes@359
   142
    }
nkeynes@359
   143
}
nkeynes@359
   144
nkeynes@359
   145
#define TRACE_CALL( source, dest ) trace_call(source, dest)
nkeynes@359
   146
#define TRACE_RETURN( source, dest ) trace_return(source, dest)
nkeynes@359
   147
#else
nkeynes@359
   148
#define TRACE_CALL( dest, rts ) 
nkeynes@359
   149
#define TRACE_RETURN( source, dest )
nkeynes@359
   150
#endif
nkeynes@359
   151
nkeynes@951
   152
static gboolean FASTCALL sh4_raise_slot_exception( int normal_code, int slot_code ) {
nkeynes@951
   153
    if( sh4r.in_delay_slot ) {
nkeynes@951
   154
        sh4_raise_exception(slot_code);
nkeynes@951
   155
    } else {
nkeynes@951
   156
        sh4_raise_exception(normal_code);
nkeynes@951
   157
    }
nkeynes@951
   158
    return TRUE;
nkeynes@951
   159
}
nkeynes@951
   160
nkeynes@951
   161
nkeynes@951
   162
#define CHECKPRIV() if( !IS_SH4_PRIVMODE() ) { return sh4_raise_slot_exception( EXC_ILLEGAL, EXC_SLOT_ILLEGAL ); }
nkeynes@951
   163
#define CHECKRALIGN16(addr) if( (addr)&0x01 ) { sh4_raise_exception( EXC_DATA_ADDR_READ ); return TRUE; }
nkeynes@951
   164
#define CHECKRALIGN32(addr) if( (addr)&0x03 ) { sh4_raise_exception( EXC_DATA_ADDR_READ ); return TRUE; }
nkeynes@951
   165
#define CHECKRALIGN64(addr) if( (addr)&0x07 ) { sh4_raise_exception( EXC_DATA_ADDR_READ ); return TRUE; }
nkeynes@951
   166
#define CHECKWALIGN16(addr) if( (addr)&0x01 ) { sh4_raise_exception( EXC_DATA_ADDR_WRITE ); return TRUE; }
nkeynes@951
   167
#define CHECKWALIGN32(addr) if( (addr)&0x03 ) { sh4_raise_exception( EXC_DATA_ADDR_WRITE ); return TRUE; }
nkeynes@951
   168
#define CHECKWALIGN64(addr) if( (addr)&0x07 ) { sh4_raise_exception( EXC_DATA_ADDR_WRITE ); return TRUE; }
nkeynes@732
   169
nkeynes@732
   170
#define CHECKFPUEN() if( !IS_FPU_ENABLED() ) { if( ir == 0xFFFD ) { UNDEF(ir); } else { return sh4_raise_slot_exception( EXC_FPU_DISABLED, EXC_SLOT_FPU_DISABLED ); } }
nkeynes@740
   171
#define CHECKDEST(p) if( (p) == 0 ) { ERROR( "%08X: Branch/jump to NULL, CPU halted", sh4r.pc ); sh4_core_exit(CORE_EXIT_HALT); return FALSE; }
nkeynes@951
   172
#define CHECKSLOTILLEGAL() if(sh4r.in_delay_slot) { sh4_raise_exception(EXC_SLOT_ILLEGAL); return TRUE; }
nkeynes@732
   173
nkeynes@939
   174
#define ADDRSPACE (IS_SH4_PRIVMODE() ? sh4_address_space : sh4_user_address_space)
nkeynes@939
   175
#define SQADDRSPACE (IS_SH4_PRIVMODE() ? storequeue_address_space : storequeue_user_address_space)
nkeynes@939
   176
nkeynes@927
   177
#ifdef HAVE_FRAME_ADDRESS
nkeynes@927
   178
static FASTCALL __attribute__((noinline)) void *__first_arg(void *a, void *b) { return a; }
nkeynes@927
   179
#define INIT_EXCEPTIONS(label) goto *__first_arg(&&fnstart,&&label); fnstart:
nkeynes@939
   180
#define MEM_READ_BYTE( addr, val ) val = ((mem_read_exc_fn_t)ADDRSPACE[(addr)>>12]->read_byte)((addr), &&except)
nkeynes@939
   181
#define MEM_READ_WORD( addr, val ) val = ((mem_read_exc_fn_t)ADDRSPACE[(addr)>>12]->read_word)((addr), &&except)
nkeynes@939
   182
#define MEM_READ_LONG( addr, val ) val = ((mem_read_exc_fn_t)ADDRSPACE[(addr)>>12]->read_long)((addr), &&except)
nkeynes@939
   183
#define MEM_WRITE_BYTE( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_byte)((addr), (val), &&except)
nkeynes@939
   184
#define MEM_WRITE_WORD( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_word)((addr), (val), &&except)
nkeynes@939
   185
#define MEM_WRITE_LONG( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_long)((addr), (val), &&except)
nkeynes@946
   186
#define MEM_PREFETCH( addr ) ((mem_prefetch_exc_fn_t)ADDRSPACE[(addr)>>12]->prefetch)((addr), &&except)
nkeynes@927
   187
#else
nkeynes@927
   188
#define INIT_EXCEPTIONS(label)
nkeynes@939
   189
#define MEM_READ_BYTE( addr, val ) val = ADDRSPACE[(addr)>>12]->read_byte(addr)
nkeynes@939
   190
#define MEM_READ_WORD( addr, val ) val = ADDRSPACE[(addr)>>12]->read_word(addr)
nkeynes@939
   191
#define MEM_READ_LONG( addr, val ) val = ADDRSPACE[(addr)>>12]->read_long(addr)
nkeynes@939
   192
#define MEM_WRITE_BYTE( addr, val ) ADDRSPACE[(addr)>>12]->write_byte(addr, val)
nkeynes@939
   193
#define MEM_WRITE_WORD( addr, val ) ADDRSPACE[(addr)>>12]->write_word(addr, val)
nkeynes@939
   194
#define MEM_WRITE_LONG( addr, val ) ADDRSPACE[(addr)>>12]->write_long(addr, val)
nkeynes@946
   195
#define MEM_PREFETCH( addr ) ADDRSPACE[(addr)>>12]->prefetch(addr)
nkeynes@927
   196
#endif
nkeynes@359
   197
nkeynes@359
   198
#define FP_WIDTH (IS_FPU_DOUBLESIZE() ? 8 : 4)
nkeynes@359
   199
nkeynes@732
   200
#define MEM_FP_READ( addr, reg ) \
nkeynes@732
   201
    if( IS_FPU_DOUBLESIZE() ) { \
nkeynes@732
   202
	CHECKRALIGN64(addr); \
nkeynes@927
   203
        if( reg & 1 ) { \
nkeynes@939
   204
            MEM_READ_LONG( addr, *((uint32_t *)&XF((reg) & 0x0E)) ); \
nkeynes@939
   205
            MEM_READ_LONG( addr+4, *((uint32_t *)&XF(reg)) ); \
nkeynes@927
   206
        } else { \
nkeynes@939
   207
            MEM_READ_LONG( addr, *((uint32_t *)&FR(reg)) ); \
nkeynes@939
   208
            MEM_READ_LONG( addr+4, *((uint32_t *)&FR((reg)|0x01)) ); \
nkeynes@732
   209
	} \
nkeynes@732
   210
    } else { \
nkeynes@732
   211
        CHECKRALIGN32(addr); \
nkeynes@939
   212
        MEM_READ_LONG( addr, *((uint32_t *)&FR(reg)) ); \
nkeynes@359
   213
    }
nkeynes@732
   214
#define MEM_FP_WRITE( addr, reg ) \
nkeynes@732
   215
    if( IS_FPU_DOUBLESIZE() ) { \
nkeynes@732
   216
        CHECKWALIGN64(addr); \
nkeynes@927
   217
        if( reg & 1 ) { \
nkeynes@939
   218
	    MEM_WRITE_LONG( addr, *((uint32_t *)&XF((reg)&0x0E)) ); \
nkeynes@939
   219
	    MEM_WRITE_LONG( addr+4, *((uint32_t *)&XF(reg)) ); \
nkeynes@927
   220
        } else { \
nkeynes@939
   221
	    MEM_WRITE_LONG( addr, *((uint32_t *)&FR(reg)) ); \
nkeynes@939
   222
	    MEM_WRITE_LONG( addr+4, *((uint32_t *)&FR((reg)|0x01)) ); \
nkeynes@732
   223
	} \
nkeynes@732
   224
    } else { \
nkeynes@732
   225
    	CHECKWALIGN32(addr); \
nkeynes@939
   226
        MEM_WRITE_LONG(addr, *((uint32_t *)&FR((reg))) ); \
nkeynes@359
   227
    }
nkeynes@359
   228
nkeynes@948
   229
#define UNDEF(ir)
nkeynes@948
   230
#define UNIMP(ir)
nkeynes@948
   231
nkeynes@948
   232
/**
nkeynes@948
   233
 * Perform instruction-completion following core exit of a partially completed
nkeynes@948
   234
 * instruction. NOTE: This is only allowed on memory writes, operation is not
nkeynes@948
   235
 * guaranteed in any other case.
nkeynes@948
   236
 */
nkeynes@948
   237
void sh4_finalize_instruction( void )
nkeynes@948
   238
{
nkeynes@948
   239
    unsigned short ir;
nkeynes@948
   240
    uint32_t tmp;
nkeynes@948
   241
nkeynes@1014
   242
    if( IS_SYSCALL(sh4r.pc) ) {
nkeynes@1014
   243
        return;
nkeynes@359
   244
    }
nkeynes@948
   245
    assert( IS_IN_ICACHE(sh4r.pc) );
nkeynes@948
   246
    ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc);
nkeynes@948
   247
    
nkeynes@948
   248
    /**
nkeynes@948
   249
     * Note - we can't take an exit on a control transfer instruction itself,
nkeynes@948
   250
     * which means the exit must have happened in the delay slot. So for these
nkeynes@948
   251
     * cases, finalize the delay slot instruction, and re-execute the control transfer.
nkeynes@948
   252
     *
nkeynes@948
   253
     * For delay slots which modify the argument used in the branch instruction,
nkeynes@948
   254
     * we pretty much just assume that that can't have already happened in an exit case.
nkeynes@948
   255
     */
nkeynes@948
   256
    
nkeynes@948
   257
%%
nkeynes@948
   258
BRA disp {: 
nkeynes@948
   259
    sh4r.pc += 2; 
nkeynes@948
   260
    sh4_finalize_instruction(); 
nkeynes@948
   261
    sh4r.pc += disp;
nkeynes@948
   262
:}
nkeynes@948
   263
BRAF Rn {: 
nkeynes@948
   264
    sh4r.pc += 2; 
nkeynes@948
   265
    tmp = sh4r.r[Rn];
nkeynes@948
   266
    sh4_finalize_instruction(); 
nkeynes@948
   267
    sh4r.pc += tmp;
nkeynes@948
   268
:}
nkeynes@948
   269
BSR disp {: 
nkeynes@948
   270
    /* Note: PR is already set */ 
nkeynes@948
   271
    sh4r.pc += 2;
nkeynes@948
   272
    sh4_finalize_instruction();
nkeynes@948
   273
    sh4r.pc += disp;
nkeynes@948
   274
:}
nkeynes@948
   275
BSRF Rn {:
nkeynes@948
   276
    /* Note: PR is already set */ 
nkeynes@948
   277
    sh4r.pc += 2;
nkeynes@948
   278
    tmp = sh4r.r[Rn];
nkeynes@948
   279
    sh4_finalize_instruction();
nkeynes@948
   280
    sh4r.pc += tmp;
nkeynes@948
   281
:}
nkeynes@948
   282
BF/S disp {: 
nkeynes@948
   283
    sh4r.pc += 2;
nkeynes@948
   284
    sh4_finalize_instruction();
nkeynes@948
   285
    if( !sh4r.t ) {
nkeynes@948
   286
        sh4r.pc += disp;
nkeynes@948
   287
    }
nkeynes@948
   288
:}
nkeynes@948
   289
BT/S disp {: 
nkeynes@948
   290
    sh4r.pc += 2;
nkeynes@948
   291
    sh4_finalize_instruction();
nkeynes@948
   292
    if( sh4r.t ) {
nkeynes@948
   293
        sh4r.pc += disp;
nkeynes@948
   294
    }
nkeynes@948
   295
:}
nkeynes@948
   296
JMP @Rn {:
nkeynes@948
   297
    sh4r.pc += 2;
nkeynes@948
   298
    tmp = sh4r.r[Rn];
nkeynes@948
   299
    sh4_finalize_instruction();
nkeynes@948
   300
    sh4r.pc = tmp;
nkeynes@948
   301
    sh4r.new_pc = tmp + 2;
nkeynes@974
   302
    sh4r.slice_cycle += sh4_cpu_period;
nkeynes@948
   303
    return;
nkeynes@948
   304
:}
nkeynes@948
   305
JSR @Rn {: 
nkeynes@948
   306
    /* Note: PR is already set */ 
nkeynes@948
   307
    sh4r.pc += 2;
nkeynes@948
   308
    tmp = sh4r.r[Rn];
nkeynes@948
   309
    sh4_finalize_instruction();
nkeynes@948
   310
    sh4r.pc = tmp;
nkeynes@948
   311
    sh4r.new_pc = tmp + 2;
nkeynes@974
   312
    sh4r.slice_cycle += sh4_cpu_period;
nkeynes@948
   313
    return;
nkeynes@948
   314
:}
nkeynes@948
   315
RTS {: 
nkeynes@948
   316
    sh4r.pc += 2;
nkeynes@948
   317
    sh4_finalize_instruction();
nkeynes@948
   318
    sh4r.pc = sh4r.pr;
nkeynes@948
   319
    sh4r.new_pc = sh4r.pr + 2;
nkeynes@974
   320
    sh4r.slice_cycle += sh4_cpu_period;
nkeynes@948
   321
    return;
nkeynes@948
   322
:}
nkeynes@948
   323
RTE {: 
nkeynes@948
   324
    /* SR is already set */
nkeynes@948
   325
    sh4r.pc += 2;
nkeynes@948
   326
    sh4_finalize_instruction();
nkeynes@948
   327
    sh4r.pc = sh4r.spc;
nkeynes@948
   328
    sh4r.new_pc = sh4r.pr + 2;
nkeynes@974
   329
    sh4r.slice_cycle += sh4_cpu_period;
nkeynes@948
   330
    return;
nkeynes@948
   331
:}
nkeynes@948
   332
MOV.B Rm, @-Rn {: sh4r.r[Rn]--; :}
nkeynes@948
   333
MOV.W Rm, @-Rn {: sh4r.r[Rn] -= 2; :}
nkeynes@948
   334
MOV.L Rm, @-Rn {: sh4r.r[Rn] -= 4; :}
nkeynes@970
   335
MOV.B @Rm+, Rn {: if( Rm != Rn ) { sh4r.r[Rm] ++;  } :}
nkeynes@970
   336
MOV.W @Rm+, Rn {: if( Rm != Rn ) { sh4r.r[Rm] += 2; } :}
nkeynes@970
   337
MOV.L @Rm+, Rn {: if( Rm != Rn ) { sh4r.r[Rm] += 4; } :}
nkeynes@948
   338
%%
nkeynes@974
   339
    sh4r.in_delay_slot = 0;
nkeynes@948
   340
    sh4r.pc += 2;
nkeynes@948
   341
    sh4r.new_pc = sh4r.pc+2;
nkeynes@948
   342
    sh4r.slice_cycle += sh4_cpu_period;
nkeynes@948
   343
}
nkeynes@948
   344
nkeynes@986
   345
#undef UNDEF
nkeynes@986
   346
#undef UNIMP
nkeynes@948
   347
nkeynes@948
   348
#define UNDEF(ir) return sh4_raise_slot_exception(EXC_ILLEGAL, EXC_SLOT_ILLEGAL)
nkeynes@948
   349
#define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", sh4r.pc, ir ); sh4_core_exit(CORE_EXIT_HALT); return FALSE; }while(0)
nkeynes@948
   350
nkeynes@948
   351
nkeynes@359
   352
gboolean sh4_execute_instruction( void )
nkeynes@359
   353
{
nkeynes@359
   354
    uint32_t pc;
nkeynes@359
   355
    unsigned short ir;
nkeynes@359
   356
    uint32_t tmp;
nkeynes@359
   357
    float ftmp;
nkeynes@359
   358
    double dtmp;
nkeynes@586
   359
    int64_t memtmp; // temporary holder for memory reads
nkeynes@927
   360
nkeynes@927
   361
    INIT_EXCEPTIONS(except)
nkeynes@359
   362
    
nkeynes@359
   363
#define R0 sh4r.r[0]
nkeynes@359
   364
    pc = sh4r.pc;
nkeynes@359
   365
    if( pc > 0xFFFFFF00 ) {
nkeynes@359
   366
	/* SYSCALL Magic */
nkeynes@359
   367
	syscall_invoke( pc );
nkeynes@359
   368
	sh4r.in_delay_slot = 0;
nkeynes@359
   369
	pc = sh4r.pc = sh4r.pr;
nkeynes@359
   370
	sh4r.new_pc = sh4r.pc + 2;
nkeynes@671
   371
        return TRUE;
nkeynes@359
   372
    }
nkeynes@359
   373
    CHECKRALIGN16(pc);
nkeynes@359
   374
nkeynes@671
   375
#ifdef ENABLE_SH4STATS
nkeynes@671
   376
    sh4_stats_add_by_pc(sh4r.pc);
nkeynes@671
   377
#endif
nkeynes@671
   378
nkeynes@359
   379
    /* Read instruction */
nkeynes@586
   380
    if( !IS_IN_ICACHE(pc) ) {
nkeynes@974
   381
        gboolean delay_slot = sh4r.in_delay_slot;
nkeynes@586
   382
	if( !mmu_update_icache(pc) ) {
nkeynes@974
   383
	    if( delay_slot ) {
nkeynes@974
   384
	        sh4r.spc -= 2;
nkeynes@974
   385
	    }
nkeynes@586
   386
	    // Fault - look for the fault handler
nkeynes@586
   387
	    if( !mmu_update_icache(sh4r.pc) ) {
nkeynes@586
   388
		// double fault - halt
nkeynes@586
   389
		ERROR( "Double fault - halting" );
nkeynes@740
   390
		sh4_core_exit(CORE_EXIT_HALT);
nkeynes@586
   391
		return FALSE;
nkeynes@586
   392
	    }
nkeynes@359
   393
	}
nkeynes@586
   394
	pc = sh4r.pc;
nkeynes@359
   395
    }
nkeynes@586
   396
    assert( IS_IN_ICACHE(pc) );
nkeynes@586
   397
    ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc);
nkeynes@948
   398
    
nkeynes@948
   399
    /* FIXME: This is a bit of a hack, but the PC of the delay slot should not
nkeynes@948
   400
     * be visible until after the instruction has executed (for exception 
nkeynes@948
   401
     * correctness)
nkeynes@948
   402
     */
nkeynes@948
   403
    if( sh4r.in_delay_slot ) {
nkeynes@948
   404
    	sh4r.pc -= 2;
nkeynes@948
   405
    }
nkeynes@359
   406
%%
nkeynes@359
   407
AND Rm, Rn {: sh4r.r[Rn] &= sh4r.r[Rm]; :}
nkeynes@359
   408
AND #imm, R0 {: R0 &= imm; :}
nkeynes@586
   409
 AND.B #imm, @(R0, GBR) {: MEM_READ_BYTE(R0+sh4r.gbr, tmp); MEM_WRITE_BYTE( R0 + sh4r.gbr, imm & tmp ); :}
nkeynes@359
   410
NOT Rm, Rn {: sh4r.r[Rn] = ~sh4r.r[Rm]; :}
nkeynes@359
   411
OR Rm, Rn {: sh4r.r[Rn] |= sh4r.r[Rm]; :}
nkeynes@359
   412
OR #imm, R0  {: R0 |= imm; :}
nkeynes@586
   413
 OR.B #imm, @(R0, GBR) {: MEM_READ_BYTE(R0+sh4r.gbr, tmp); MEM_WRITE_BYTE( R0 + sh4r.gbr, imm | tmp ); :}
nkeynes@359
   414
TAS.B @Rn {:
nkeynes@586
   415
    MEM_READ_BYTE( sh4r.r[Rn], tmp );
nkeynes@359
   416
    sh4r.t = ( tmp == 0 ? 1 : 0 );
nkeynes@359
   417
    MEM_WRITE_BYTE( sh4r.r[Rn], tmp | 0x80 );
nkeynes@359
   418
:}
nkeynes@359
   419
TST Rm, Rn {: sh4r.t = (sh4r.r[Rn]&sh4r.r[Rm] ? 0 : 1); :}
nkeynes@359
   420
TST #imm, R0 {: sh4r.t = (R0 & imm ? 0 : 1); :}
nkeynes@586
   421
 TST.B #imm, @(R0, GBR) {: MEM_READ_BYTE(R0+sh4r.gbr, tmp); sh4r.t = ( tmp & imm ? 0 : 1 ); :}
nkeynes@359
   422
XOR Rm, Rn {: sh4r.r[Rn] ^= sh4r.r[Rm]; :}
nkeynes@359
   423
XOR #imm, R0 {: R0 ^= imm; :}
nkeynes@586
   424
 XOR.B #imm, @(R0, GBR) {: MEM_READ_BYTE(R0+sh4r.gbr, tmp); MEM_WRITE_BYTE( R0 + sh4r.gbr, imm ^ tmp ); :}
nkeynes@359
   425
XTRCT Rm, Rn {: sh4r.r[Rn] = (sh4r.r[Rn]>>16) | (sh4r.r[Rm]<<16); :}
nkeynes@359
   426
nkeynes@359
   427
ROTL Rn {:
nkeynes@359
   428
    sh4r.t = sh4r.r[Rn] >> 31;
nkeynes@359
   429
    sh4r.r[Rn] <<= 1;
nkeynes@359
   430
    sh4r.r[Rn] |= sh4r.t;
nkeynes@359
   431
:}
nkeynes@359
   432
ROTR Rn {:
nkeynes@359
   433
    sh4r.t = sh4r.r[Rn] & 0x00000001;
nkeynes@359
   434
    sh4r.r[Rn] >>= 1;
nkeynes@359
   435
    sh4r.r[Rn] |= (sh4r.t << 31);
nkeynes@359
   436
:}
nkeynes@359
   437
ROTCL Rn {:
nkeynes@359
   438
    tmp = sh4r.r[Rn] >> 31;
nkeynes@359
   439
    sh4r.r[Rn] <<= 1;
nkeynes@359
   440
    sh4r.r[Rn] |= sh4r.t;
nkeynes@359
   441
    sh4r.t = tmp;
nkeynes@359
   442
:}
nkeynes@359
   443
ROTCR Rn {:
nkeynes@359
   444
    tmp = sh4r.r[Rn] & 0x00000001;
nkeynes@359
   445
    sh4r.r[Rn] >>= 1;
nkeynes@359
   446
    sh4r.r[Rn] |= (sh4r.t << 31 );
nkeynes@359
   447
    sh4r.t = tmp;
nkeynes@359
   448
:}
nkeynes@359
   449
SHAD Rm, Rn {:
nkeynes@359
   450
    tmp = sh4r.r[Rm];
nkeynes@359
   451
    if( (tmp & 0x80000000) == 0 ) sh4r.r[Rn] <<= (tmp&0x1f);
nkeynes@359
   452
    else if( (tmp & 0x1F) == 0 )  
nkeynes@359
   453
        sh4r.r[Rn] = ((int32_t)sh4r.r[Rn]) >> 31;
nkeynes@359
   454
    else 
nkeynes@359
   455
	sh4r.r[Rn] = ((int32_t)sh4r.r[Rn]) >> (((~sh4r.r[Rm]) & 0x1F)+1);
nkeynes@359
   456
:}
nkeynes@359
   457
SHLD Rm, Rn {:
nkeynes@359
   458
    tmp = sh4r.r[Rm];
nkeynes@359
   459
    if( (tmp & 0x80000000) == 0 ) sh4r.r[Rn] <<= (tmp&0x1f);
nkeynes@359
   460
    else if( (tmp & 0x1F) == 0 ) sh4r.r[Rn] = 0;
nkeynes@359
   461
    else sh4r.r[Rn] >>= (((~tmp) & 0x1F)+1);
nkeynes@359
   462
:}
nkeynes@359
   463
SHAL Rn {:
nkeynes@359
   464
    sh4r.t = sh4r.r[Rn] >> 31;
nkeynes@359
   465
    sh4r.r[Rn] <<= 1;
nkeynes@359
   466
:}
nkeynes@359
   467
SHAR Rn {:
nkeynes@359
   468
    sh4r.t = sh4r.r[Rn] & 0x00000001;
nkeynes@359
   469
    sh4r.r[Rn] = ((int32_t)sh4r.r[Rn]) >> 1;
nkeynes@359
   470
:}
nkeynes@359
   471
SHLL Rn {: sh4r.t = sh4r.r[Rn] >> 31; sh4r.r[Rn] <<= 1; :}
nkeynes@359
   472
SHLR Rn {: sh4r.t = sh4r.r[Rn] & 0x00000001; sh4r.r[Rn] >>= 1; :}
nkeynes@359
   473
SHLL2 Rn {: sh4r.r[Rn] <<= 2; :}
nkeynes@359
   474
SHLR2 Rn {: sh4r.r[Rn] >>= 2; :}
nkeynes@359
   475
SHLL8 Rn {: sh4r.r[Rn] <<= 8; :}
nkeynes@359
   476
SHLR8 Rn {: sh4r.r[Rn] >>= 8; :}
nkeynes@359
   477
SHLL16 Rn {: sh4r.r[Rn] <<= 16; :}
nkeynes@359
   478
SHLR16 Rn {: sh4r.r[Rn] >>= 16; :}
nkeynes@359
   479
nkeynes@359
   480
EXTU.B Rm, Rn {: sh4r.r[Rn] = sh4r.r[Rm]&0x000000FF; :}
nkeynes@359
   481
EXTU.W Rm, Rn {: sh4r.r[Rn] = sh4r.r[Rm]&0x0000FFFF; :}
nkeynes@359
   482
EXTS.B Rm, Rn {: sh4r.r[Rn] = SIGNEXT8( sh4r.r[Rm]&0x000000FF ); :}
nkeynes@359
   483
EXTS.W Rm, Rn {: sh4r.r[Rn] = SIGNEXT16( sh4r.r[Rm]&0x0000FFFF ); :}
nkeynes@359
   484
SWAP.B Rm, Rn {: sh4r.r[Rn] = (sh4r.r[Rm]&0xFFFF0000) | ((sh4r.r[Rm]&0x0000FF00)>>8) | ((sh4r.r[Rm]&0x000000FF)<<8); :}
nkeynes@359
   485
SWAP.W Rm, Rn {: sh4r.r[Rn] = (sh4r.r[Rm]>>16) | (sh4r.r[Rm]<<16); :}
nkeynes@359
   486
nkeynes@359
   487
CLRT {: sh4r.t = 0; :}
nkeynes@359
   488
SETT {: sh4r.t = 1; :}
nkeynes@359
   489
CLRMAC {: sh4r.mac = 0; :}
nkeynes@550
   490
LDTLB {: MMU_ldtlb(); :}
nkeynes@359
   491
CLRS {: sh4r.s = 0; :}
nkeynes@359
   492
SETS {: sh4r.s = 1; :}
nkeynes@359
   493
MOVT Rn {: sh4r.r[Rn] = sh4r.t; :}
nkeynes@359
   494
NOP {: /* NOP */ :}
nkeynes@359
   495
nkeynes@359
   496
PREF @Rn {:
nkeynes@946
   497
    MEM_PREFETCH(sh4r.r[Rn]);
nkeynes@359
   498
:}
nkeynes@359
   499
OCBI @Rn {: :}
nkeynes@359
   500
OCBP @Rn {: :}
nkeynes@359
   501
OCBWB @Rn {: :}
nkeynes@359
   502
MOVCA.L R0, @Rn {:
nkeynes@359
   503
    tmp = sh4r.r[Rn];
nkeynes@359
   504
    CHECKWALIGN32(tmp);
nkeynes@359
   505
    MEM_WRITE_LONG( tmp, R0 );
nkeynes@359
   506
:}
nkeynes@359
   507
MOV.B Rm, @(R0, Rn) {: MEM_WRITE_BYTE( R0 + sh4r.r[Rn], sh4r.r[Rm] ); :}
nkeynes@359
   508
MOV.W Rm, @(R0, Rn) {: 
nkeynes@359
   509
    CHECKWALIGN16( R0 + sh4r.r[Rn] );
nkeynes@359
   510
    MEM_WRITE_WORD( R0 + sh4r.r[Rn], sh4r.r[Rm] );
nkeynes@359
   511
:}
nkeynes@359
   512
MOV.L Rm, @(R0, Rn) {:
nkeynes@359
   513
    CHECKWALIGN32( R0 + sh4r.r[Rn] );
nkeynes@359
   514
    MEM_WRITE_LONG( R0 + sh4r.r[Rn], sh4r.r[Rm] );
nkeynes@359
   515
:}
nkeynes@586
   516
MOV.B @(R0, Rm), Rn {: MEM_READ_BYTE( R0 + sh4r.r[Rm], sh4r.r[Rn] ); :}
nkeynes@359
   517
MOV.W @(R0, Rm), Rn {: CHECKRALIGN16( R0 + sh4r.r[Rm] );
nkeynes@586
   518
    MEM_READ_WORD( R0 + sh4r.r[Rm], sh4r.r[Rn] );
nkeynes@359
   519
:}
nkeynes@359
   520
MOV.L @(R0, Rm), Rn {: CHECKRALIGN32( R0 + sh4r.r[Rm] );
nkeynes@586
   521
    MEM_READ_LONG( R0 + sh4r.r[Rm], sh4r.r[Rn] );
nkeynes@359
   522
:}
nkeynes@359
   523
MOV.L Rm, @(disp, Rn) {:
nkeynes@359
   524
    tmp = sh4r.r[Rn] + disp;
nkeynes@359
   525
    CHECKWALIGN32( tmp );
nkeynes@359
   526
    MEM_WRITE_LONG( tmp, sh4r.r[Rm] );
nkeynes@359
   527
:}
nkeynes@359
   528
MOV.B Rm, @Rn {: MEM_WRITE_BYTE( sh4r.r[Rn], sh4r.r[Rm] ); :}
nkeynes@359
   529
MOV.W Rm, @Rn {: CHECKWALIGN16( sh4r.r[Rn] ); MEM_WRITE_WORD( sh4r.r[Rn], sh4r.r[Rm] ); :}
nkeynes@359
   530
MOV.L Rm, @Rn {: CHECKWALIGN32( sh4r.r[Rn] ); MEM_WRITE_LONG( sh4r.r[Rn], sh4r.r[Rm] ); :}
nkeynes@587
   531
 MOV.B Rm, @-Rn {: MEM_WRITE_BYTE( sh4r.r[Rn]-1, sh4r.r[Rm] ); sh4r.r[Rn]--; :}
nkeynes@587
   532
 MOV.W Rm, @-Rn {: CHECKWALIGN16( sh4r.r[Rn] ); MEM_WRITE_WORD( sh4r.r[Rn]-2, sh4r.r[Rm] ); sh4r.r[Rn] -= 2; :}
nkeynes@587
   533
 MOV.L Rm, @-Rn {: CHECKWALIGN32( sh4r.r[Rn] ); MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.r[Rm] ); sh4r.r[Rn] -= 4; :}
nkeynes@359
   534
MOV.L @(disp, Rm), Rn {:
nkeynes@359
   535
    tmp = sh4r.r[Rm] + disp;
nkeynes@359
   536
    CHECKRALIGN32( tmp );
nkeynes@586
   537
    MEM_READ_LONG( tmp, sh4r.r[Rn] );
nkeynes@359
   538
:}
nkeynes@586
   539
MOV.B @Rm, Rn {: MEM_READ_BYTE( sh4r.r[Rm], sh4r.r[Rn] ); :}
nkeynes@586
   540
 MOV.W @Rm, Rn {: CHECKRALIGN16( sh4r.r[Rm] ); MEM_READ_WORD( sh4r.r[Rm], sh4r.r[Rn] ); :}
nkeynes@586
   541
 MOV.L @Rm, Rn {: CHECKRALIGN32( sh4r.r[Rm] ); MEM_READ_LONG( sh4r.r[Rm], sh4r.r[Rn] ); :}
nkeynes@359
   542
MOV Rm, Rn {: sh4r.r[Rn] = sh4r.r[Rm]; :}
nkeynes@970
   543
 MOV.B @Rm+, Rn {: MEM_READ_BYTE( sh4r.r[Rm], sh4r.r[Rn] ); if( Rm != Rn ) { sh4r.r[Rm] ++; } :}
nkeynes@970
   544
 MOV.W @Rm+, Rn {: CHECKRALIGN16( sh4r.r[Rm] ); MEM_READ_WORD( sh4r.r[Rm], sh4r.r[Rn] ); if( Rm != Rn ) { sh4r.r[Rm] += 2; } :}
nkeynes@970
   545
 MOV.L @Rm+, Rn {: CHECKRALIGN32( sh4r.r[Rm] ); MEM_READ_LONG( sh4r.r[Rm], sh4r.r[Rn] ); if( Rm != Rn ) { sh4r.r[Rm] += 4; } :}
nkeynes@359
   546
MOV.L @(disp, PC), Rn {:
nkeynes@359
   547
    CHECKSLOTILLEGAL();
nkeynes@359
   548
    tmp = (pc&0xFFFFFFFC) + disp + 4;
nkeynes@586
   549
    MEM_READ_LONG( tmp, sh4r.r[Rn] );
nkeynes@359
   550
:}
nkeynes@359
   551
MOV.B R0, @(disp, GBR) {: MEM_WRITE_BYTE( sh4r.gbr + disp, R0 ); :}
nkeynes@359
   552
MOV.W R0, @(disp, GBR) {:
nkeynes@359
   553
    tmp = sh4r.gbr + disp;
nkeynes@359
   554
    CHECKWALIGN16( tmp );
nkeynes@359
   555
    MEM_WRITE_WORD( tmp, R0 );
nkeynes@359
   556
:}
nkeynes@359
   557
MOV.L R0, @(disp, GBR) {:
nkeynes@359
   558
    tmp = sh4r.gbr + disp;
nkeynes@359
   559
    CHECKWALIGN32( tmp );
nkeynes@359
   560
    MEM_WRITE_LONG( tmp, R0 );
nkeynes@359
   561
:}
nkeynes@586
   562
 MOV.B @(disp, GBR), R0 {: MEM_READ_BYTE( sh4r.gbr + disp, R0 ); :}
nkeynes@359
   563
MOV.W @(disp, GBR), R0 {: 
nkeynes@359
   564
    tmp = sh4r.gbr + disp;
nkeynes@359
   565
    CHECKRALIGN16( tmp );
nkeynes@586
   566
    MEM_READ_WORD( tmp, R0 );
nkeynes@359
   567
:}
nkeynes@359
   568
MOV.L @(disp, GBR), R0 {:
nkeynes@359
   569
    tmp = sh4r.gbr + disp;
nkeynes@359
   570
    CHECKRALIGN32( tmp );
nkeynes@586
   571
    MEM_READ_LONG( tmp, R0 );
nkeynes@359
   572
:}
nkeynes@359
   573
MOV.B R0, @(disp, Rn) {: MEM_WRITE_BYTE( sh4r.r[Rn] + disp, R0 ); :}
nkeynes@359
   574
MOV.W R0, @(disp, Rn) {: 
nkeynes@359
   575
    tmp = sh4r.r[Rn] + disp;
nkeynes@359
   576
    CHECKWALIGN16( tmp );
nkeynes@359
   577
    MEM_WRITE_WORD( tmp, R0 );
nkeynes@359
   578
:}
nkeynes@586
   579
 MOV.B @(disp, Rm), R0 {: MEM_READ_BYTE( sh4r.r[Rm] + disp, R0 ); :}
nkeynes@359
   580
MOV.W @(disp, Rm), R0 {: 
nkeynes@359
   581
    tmp = sh4r.r[Rm] + disp;
nkeynes@359
   582
    CHECKRALIGN16( tmp );
nkeynes@586
   583
    MEM_READ_WORD( tmp, R0 );
nkeynes@359
   584
:}
nkeynes@359
   585
MOV.W @(disp, PC), Rn {:
nkeynes@359
   586
    CHECKSLOTILLEGAL();
nkeynes@359
   587
    tmp = pc + 4 + disp;
nkeynes@586
   588
    MEM_READ_WORD( tmp, sh4r.r[Rn] );
nkeynes@359
   589
:}
nkeynes@359
   590
MOVA @(disp, PC), R0 {:
nkeynes@359
   591
    CHECKSLOTILLEGAL();
nkeynes@359
   592
    R0 = (pc&0xFFFFFFFC) + disp + 4;
nkeynes@359
   593
:}
nkeynes@359
   594
MOV #imm, Rn {:  sh4r.r[Rn] = imm; :}
nkeynes@359
   595
nkeynes@732
   596
FMOV @(R0, Rm), FRn {: MEM_FP_READ( sh4r.r[Rm] + R0, FRn ); :}
nkeynes@732
   597
FMOV FRm, @(R0, Rn) {: MEM_FP_WRITE( sh4r.r[Rn] + R0, FRm ); :}
nkeynes@732
   598
FMOV @Rm, FRn {: MEM_FP_READ( sh4r.r[Rm], FRn ); :}
nkeynes@732
   599
FMOV @Rm+, FRn {: MEM_FP_READ( sh4r.r[Rm], FRn ); sh4r.r[Rm] += FP_WIDTH; :}
nkeynes@732
   600
FMOV FRm, @Rn {: MEM_FP_WRITE( sh4r.r[Rn], FRm ); :}
nkeynes@732
   601
 FMOV FRm, @-Rn {: MEM_FP_WRITE( sh4r.r[Rn] - FP_WIDTH, FRm ); sh4r.r[Rn] -= FP_WIDTH; :}
nkeynes@732
   602
FMOV FRm, FRn {: 
nkeynes@732
   603
    if( IS_FPU_DOUBLESIZE() )
nkeynes@732
   604
	DR(FRn) = DR(FRm);
nkeynes@732
   605
    else
nkeynes@732
   606
	FR(FRn) = FR(FRm);
nkeynes@732
   607
:}
nkeynes@732
   608
nkeynes@359
   609
CMP/EQ #imm, R0 {: sh4r.t = ( R0 == imm ? 1 : 0 ); :}
nkeynes@359
   610
CMP/EQ Rm, Rn {: sh4r.t = ( sh4r.r[Rm] == sh4r.r[Rn] ? 1 : 0 ); :}
nkeynes@359
   611
CMP/GE Rm, Rn {: sh4r.t = ( ((int32_t)sh4r.r[Rn]) >= ((int32_t)sh4r.r[Rm]) ? 1 : 0 ); :}
nkeynes@359
   612
CMP/GT Rm, Rn {: sh4r.t = ( ((int32_t)sh4r.r[Rn]) > ((int32_t)sh4r.r[Rm]) ? 1 : 0 ); :}
nkeynes@359
   613
CMP/HI Rm, Rn {: sh4r.t = ( sh4r.r[Rn] > sh4r.r[Rm] ? 1 : 0 ); :}
nkeynes@359
   614
CMP/HS Rm, Rn {: sh4r.t = ( sh4r.r[Rn] >= sh4r.r[Rm] ? 1 : 0 ); :}
nkeynes@359
   615
CMP/PL Rn {: sh4r.t = ( ((int32_t)sh4r.r[Rn]) > 0 ? 1 : 0 ); :}
nkeynes@359
   616
CMP/PZ Rn {: sh4r.t = ( ((int32_t)sh4r.r[Rn]) >= 0 ? 1 : 0 ); :}
nkeynes@359
   617
CMP/STR Rm, Rn {: 
nkeynes@359
   618
    /* set T = 1 if any byte in RM & RN is the same */
nkeynes@359
   619
    tmp = sh4r.r[Rm] ^ sh4r.r[Rn];
nkeynes@359
   620
    sh4r.t = ((tmp&0x000000FF)==0 || (tmp&0x0000FF00)==0 ||
nkeynes@359
   621
             (tmp&0x00FF0000)==0 || (tmp&0xFF000000)==0)?1:0;
nkeynes@359
   622
:}
nkeynes@359
   623
nkeynes@359
   624
ADD Rm, Rn {: sh4r.r[Rn] += sh4r.r[Rm]; :}
nkeynes@359
   625
ADD #imm, Rn {: sh4r.r[Rn] += imm; :}
nkeynes@359
   626
ADDC Rm, Rn {:
nkeynes@359
   627
    tmp = sh4r.r[Rn];
nkeynes@359
   628
    sh4r.r[Rn] += sh4r.r[Rm] + sh4r.t;
nkeynes@359
   629
    sh4r.t = ( sh4r.r[Rn] < tmp || (sh4r.r[Rn] == tmp && sh4r.t != 0) ? 1 : 0 );
nkeynes@359
   630
:}
nkeynes@359
   631
ADDV Rm, Rn {:
nkeynes@359
   632
    tmp = sh4r.r[Rn] + sh4r.r[Rm];
nkeynes@359
   633
    sh4r.t = ( (sh4r.r[Rn]>>31) == (sh4r.r[Rm]>>31) && ((sh4r.r[Rn]>>31) != (tmp>>31)) );
nkeynes@359
   634
    sh4r.r[Rn] = tmp;
nkeynes@359
   635
:}
nkeynes@359
   636
DIV0U {: sh4r.m = sh4r.q = sh4r.t = 0; :}
nkeynes@359
   637
DIV0S Rm, Rn {: 
nkeynes@359
   638
    sh4r.q = sh4r.r[Rn]>>31;
nkeynes@359
   639
    sh4r.m = sh4r.r[Rm]>>31;
nkeynes@359
   640
    sh4r.t = sh4r.q ^ sh4r.m;
nkeynes@359
   641
:}
nkeynes@359
   642
DIV1 Rm, Rn {:
nkeynes@384
   643
    /* This is derived from the sh4 manual with some simplifications */
nkeynes@359
   644
    uint32_t tmp0, tmp1, tmp2, dir;
nkeynes@359
   645
nkeynes@359
   646
    dir = sh4r.q ^ sh4r.m;
nkeynes@359
   647
    sh4r.q = (sh4r.r[Rn] >> 31);
nkeynes@359
   648
    tmp2 = sh4r.r[Rm];
nkeynes@359
   649
    sh4r.r[Rn] = (sh4r.r[Rn] << 1) | sh4r.t;
nkeynes@359
   650
    tmp0 = sh4r.r[Rn];
nkeynes@359
   651
    if( dir ) {
nkeynes@359
   652
         sh4r.r[Rn] += tmp2;
nkeynes@359
   653
         tmp1 = (sh4r.r[Rn]<tmp0 ? 1 : 0 );
nkeynes@359
   654
    } else {
nkeynes@359
   655
         sh4r.r[Rn] -= tmp2;
nkeynes@359
   656
         tmp1 = (sh4r.r[Rn]>tmp0 ? 1 : 0 );
nkeynes@359
   657
    }
nkeynes@359
   658
    sh4r.q ^= sh4r.m ^ tmp1;
nkeynes@359
   659
    sh4r.t = ( sh4r.q == sh4r.m ? 1 : 0 );
nkeynes@359
   660
:}
nkeynes@359
   661
DMULS.L Rm, Rn {: sh4r.mac = SIGNEXT32(sh4r.r[Rm]) * SIGNEXT32(sh4r.r[Rn]); :}
nkeynes@359
   662
DMULU.L Rm, Rn {: sh4r.mac = ((uint64_t)sh4r.r[Rm]) * ((uint64_t)sh4r.r[Rn]); :}
nkeynes@359
   663
DT Rn {:
nkeynes@359
   664
    sh4r.r[Rn] --;
nkeynes@359
   665
    sh4r.t = ( sh4r.r[Rn] == 0 ? 1 : 0 );
nkeynes@359
   666
:}
nkeynes@359
   667
MAC.W @Rm+, @Rn+ {:
nkeynes@587
   668
    int32_t stmp;
nkeynes@587
   669
    if( Rm == Rn ) {
nkeynes@587
   670
	CHECKRALIGN16(sh4r.r[Rn]);
nkeynes@587
   671
	MEM_READ_WORD( sh4r.r[Rn], tmp );
nkeynes@587
   672
	stmp = SIGNEXT16(tmp);
nkeynes@587
   673
	MEM_READ_WORD( sh4r.r[Rn]+2, tmp );
nkeynes@587
   674
	stmp *= SIGNEXT16(tmp);
nkeynes@587
   675
	sh4r.r[Rn] += 4;
nkeynes@587
   676
    } else {
nkeynes@587
   677
	CHECKRALIGN16( sh4r.r[Rn] );
nkeynes@587
   678
	CHECKRALIGN16( sh4r.r[Rm] );
nkeynes@587
   679
	MEM_READ_WORD(sh4r.r[Rn], tmp);
nkeynes@587
   680
	stmp = SIGNEXT16(tmp);
nkeynes@587
   681
	MEM_READ_WORD(sh4r.r[Rm], tmp);
nkeynes@587
   682
	stmp = stmp * SIGNEXT16(tmp);
nkeynes@587
   683
	sh4r.r[Rn] += 2;
nkeynes@587
   684
	sh4r.r[Rm] += 2;
nkeynes@587
   685
    }
nkeynes@359
   686
    if( sh4r.s ) {
nkeynes@359
   687
	int64_t tmpl = (int64_t)((int32_t)sh4r.mac) + (int64_t)stmp;
nkeynes@359
   688
	if( tmpl > (int64_t)0x000000007FFFFFFFLL ) {
nkeynes@359
   689
	    sh4r.mac = 0x000000017FFFFFFFLL;
nkeynes@359
   690
	} else if( tmpl < (int64_t)0xFFFFFFFF80000000LL ) {
nkeynes@359
   691
	    sh4r.mac = 0x0000000180000000LL;
nkeynes@359
   692
	} else {
nkeynes@359
   693
	    sh4r.mac = (sh4r.mac & 0xFFFFFFFF00000000LL) |
nkeynes@359
   694
		((uint32_t)(sh4r.mac + stmp));
nkeynes@359
   695
	}
nkeynes@359
   696
    } else {
nkeynes@359
   697
	sh4r.mac += SIGNEXT32(stmp);
nkeynes@359
   698
    }
nkeynes@359
   699
:}
nkeynes@359
   700
MAC.L @Rm+, @Rn+ {:
nkeynes@587
   701
    int64_t tmpl;
nkeynes@587
   702
    if( Rm == Rn ) {
nkeynes@587
   703
	CHECKRALIGN32( sh4r.r[Rn] );
nkeynes@587
   704
	MEM_READ_LONG(sh4r.r[Rn], tmp);
nkeynes@587
   705
	tmpl = SIGNEXT32(tmp);
nkeynes@587
   706
	MEM_READ_LONG(sh4r.r[Rn]+4, tmp);
nkeynes@587
   707
	tmpl = tmpl * SIGNEXT32(tmp) + sh4r.mac;
nkeynes@587
   708
	sh4r.r[Rn] += 8;
nkeynes@587
   709
    } else {
nkeynes@587
   710
	CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@587
   711
	CHECKRALIGN32( sh4r.r[Rn] );
nkeynes@587
   712
	MEM_READ_LONG(sh4r.r[Rn], tmp);
nkeynes@587
   713
	tmpl = SIGNEXT32(tmp);
nkeynes@587
   714
	MEM_READ_LONG(sh4r.r[Rm], tmp);
nkeynes@587
   715
	tmpl = tmpl * SIGNEXT32(tmp) + sh4r.mac;
nkeynes@587
   716
	sh4r.r[Rn] += 4;
nkeynes@587
   717
	sh4r.r[Rm] += 4;
nkeynes@587
   718
    }
nkeynes@359
   719
    if( sh4r.s ) {
nkeynes@359
   720
        /* 48-bit Saturation. Yuch */
nkeynes@359
   721
        if( tmpl < (int64_t)0xFFFF800000000000LL )
nkeynes@359
   722
            tmpl = 0xFFFF800000000000LL;
nkeynes@359
   723
        else if( tmpl > (int64_t)0x00007FFFFFFFFFFFLL )
nkeynes@359
   724
            tmpl = 0x00007FFFFFFFFFFFLL;
nkeynes@359
   725
    }
nkeynes@359
   726
    sh4r.mac = tmpl;
nkeynes@359
   727
:}
nkeynes@359
   728
MUL.L Rm, Rn {: sh4r.mac = (sh4r.mac&0xFFFFFFFF00000000LL) |
nkeynes@359
   729
                        (sh4r.r[Rm] * sh4r.r[Rn]); :}
nkeynes@359
   730
MULU.W Rm, Rn {:
nkeynes@359
   731
    sh4r.mac = (sh4r.mac&0xFFFFFFFF00000000LL) |
nkeynes@359
   732
               (uint32_t)((sh4r.r[Rm]&0xFFFF) * (sh4r.r[Rn]&0xFFFF));
nkeynes@359
   733
:}
nkeynes@359
   734
MULS.W Rm, Rn {:
nkeynes@359
   735
    sh4r.mac = (sh4r.mac&0xFFFFFFFF00000000LL) |
nkeynes@359
   736
               (uint32_t)(SIGNEXT32(sh4r.r[Rm]&0xFFFF) * SIGNEXT32(sh4r.r[Rn]&0xFFFF));
nkeynes@359
   737
:}
nkeynes@359
   738
NEGC Rm, Rn {:
nkeynes@359
   739
    tmp = 0 - sh4r.r[Rm];
nkeynes@359
   740
    sh4r.r[Rn] = tmp - sh4r.t;
nkeynes@359
   741
    sh4r.t = ( 0<tmp || tmp<sh4r.r[Rn] ? 1 : 0 );
nkeynes@359
   742
:}
nkeynes@359
   743
NEG Rm, Rn {: sh4r.r[Rn] = 0 - sh4r.r[Rm]; :}
nkeynes@359
   744
SUB Rm, Rn {: sh4r.r[Rn] -= sh4r.r[Rm]; :}
nkeynes@359
   745
SUBC Rm, Rn {: 
nkeynes@359
   746
    tmp = sh4r.r[Rn];
nkeynes@359
   747
    sh4r.r[Rn] = sh4r.r[Rn] - sh4r.r[Rm] - sh4r.t;
nkeynes@359
   748
    sh4r.t = (sh4r.r[Rn] > tmp || (sh4r.r[Rn] == tmp && sh4r.t == 1));
nkeynes@359
   749
:}
nkeynes@1083
   750
SUBV Rm, Rn {:
nkeynes@1083
   751
    tmp = sh4r.r[Rn] - sh4r.r[Rm];
nkeynes@1083
   752
    sh4r.t = ( (sh4r.r[Rn]>>31) != (sh4r.r[Rm]>>31) && ((sh4r.r[Rn]>>31) != (tmp>>31)) );
nkeynes@1083
   753
    sh4r.r[Rn] = tmp;
nkeynes@1083
   754
:}
nkeynes@359
   755
BRAF Rn {:
nkeynes@359
   756
     CHECKSLOTILLEGAL();
nkeynes@359
   757
     CHECKDEST( pc + 4 + sh4r.r[Rn] );
nkeynes@359
   758
     sh4r.in_delay_slot = 1;
nkeynes@359
   759
     sh4r.pc = sh4r.new_pc;
nkeynes@359
   760
     sh4r.new_pc = pc + 4 + sh4r.r[Rn];
nkeynes@359
   761
     return TRUE;
nkeynes@359
   762
:}
nkeynes@359
   763
BSRF Rn {:
nkeynes@359
   764
     CHECKSLOTILLEGAL();
nkeynes@359
   765
     CHECKDEST( pc + 4 + sh4r.r[Rn] );
nkeynes@359
   766
     sh4r.in_delay_slot = 1;
nkeynes@359
   767
     sh4r.pr = sh4r.pc + 4;
nkeynes@359
   768
     sh4r.pc = sh4r.new_pc;
nkeynes@359
   769
     sh4r.new_pc = pc + 4 + sh4r.r[Rn];
nkeynes@359
   770
     TRACE_CALL( pc, sh4r.new_pc );
nkeynes@359
   771
     return TRUE;
nkeynes@359
   772
:}
nkeynes@359
   773
BT disp {:
nkeynes@359
   774
    CHECKSLOTILLEGAL();
nkeynes@359
   775
    if( sh4r.t ) {
nkeynes@359
   776
        CHECKDEST( sh4r.pc + disp + 4 )
nkeynes@359
   777
        sh4r.pc += disp + 4;
nkeynes@359
   778
        sh4r.new_pc = sh4r.pc + 2;
nkeynes@359
   779
        return TRUE;
nkeynes@359
   780
    }
nkeynes@359
   781
:}
nkeynes@359
   782
BF disp {:
nkeynes@359
   783
    CHECKSLOTILLEGAL();
nkeynes@359
   784
    if( !sh4r.t ) {
nkeynes@359
   785
        CHECKDEST( sh4r.pc + disp + 4 )
nkeynes@359
   786
        sh4r.pc += disp + 4;
nkeynes@359
   787
        sh4r.new_pc = sh4r.pc + 2;
nkeynes@359
   788
        return TRUE;
nkeynes@359
   789
    }
nkeynes@359
   790
:}
nkeynes@359
   791
BT/S disp {:
nkeynes@359
   792
    CHECKSLOTILLEGAL();
nkeynes@359
   793
    if( sh4r.t ) {
nkeynes@359
   794
        CHECKDEST( sh4r.pc + disp + 4 )
nkeynes@359
   795
        sh4r.in_delay_slot = 1;
nkeynes@359
   796
        sh4r.pc = sh4r.new_pc;
nkeynes@359
   797
        sh4r.new_pc = pc + disp + 4;
nkeynes@359
   798
        sh4r.in_delay_slot = 1;
nkeynes@359
   799
        return TRUE;
nkeynes@359
   800
    }
nkeynes@359
   801
:}
nkeynes@359
   802
BF/S disp {:
nkeynes@359
   803
    CHECKSLOTILLEGAL();
nkeynes@359
   804
    if( !sh4r.t ) {
nkeynes@359
   805
        CHECKDEST( sh4r.pc + disp + 4 )
nkeynes@359
   806
        sh4r.in_delay_slot = 1;
nkeynes@359
   807
        sh4r.pc = sh4r.new_pc;
nkeynes@359
   808
        sh4r.new_pc = pc + disp + 4;
nkeynes@359
   809
        return TRUE;
nkeynes@359
   810
    }
nkeynes@359
   811
:}
nkeynes@359
   812
BRA disp {:
nkeynes@359
   813
    CHECKSLOTILLEGAL();
nkeynes@359
   814
    CHECKDEST( sh4r.pc + disp + 4 );
nkeynes@359
   815
    sh4r.in_delay_slot = 1;
nkeynes@359
   816
    sh4r.pc = sh4r.new_pc;
nkeynes@359
   817
    sh4r.new_pc = pc + 4 + disp;
nkeynes@359
   818
    return TRUE;
nkeynes@359
   819
:}
nkeynes@359
   820
BSR disp {:
nkeynes@359
   821
    CHECKDEST( sh4r.pc + disp + 4 );
nkeynes@359
   822
    CHECKSLOTILLEGAL();
nkeynes@359
   823
    sh4r.in_delay_slot = 1;
nkeynes@359
   824
    sh4r.pr = pc + 4;
nkeynes@359
   825
    sh4r.pc = sh4r.new_pc;
nkeynes@359
   826
    sh4r.new_pc = pc + 4 + disp;
nkeynes@359
   827
    TRACE_CALL( pc, sh4r.new_pc );
nkeynes@359
   828
    return TRUE;
nkeynes@359
   829
:}
nkeynes@359
   830
TRAPA #imm {:
nkeynes@359
   831
    CHECKSLOTILLEGAL();
nkeynes@359
   832
    sh4r.pc += 2;
nkeynes@586
   833
    sh4_raise_trap( imm );
nkeynes@586
   834
    return TRUE;
nkeynes@359
   835
:}
nkeynes@359
   836
RTS {: 
nkeynes@359
   837
    CHECKSLOTILLEGAL();
nkeynes@359
   838
    CHECKDEST( sh4r.pr );
nkeynes@359
   839
    sh4r.in_delay_slot = 1;
nkeynes@359
   840
    sh4r.pc = sh4r.new_pc;
nkeynes@359
   841
    sh4r.new_pc = sh4r.pr;
nkeynes@359
   842
    TRACE_RETURN( pc, sh4r.new_pc );
nkeynes@359
   843
    return TRUE;
nkeynes@359
   844
:}
nkeynes@359
   845
SLEEP {:
nkeynes@359
   846
    if( MMIO_READ( CPG, STBCR ) & 0x80 ) {
nkeynes@359
   847
	sh4r.sh4_state = SH4_STATE_STANDBY;
nkeynes@359
   848
    } else {
nkeynes@359
   849
	sh4r.sh4_state = SH4_STATE_SLEEP;
nkeynes@359
   850
    }
nkeynes@359
   851
    return FALSE; /* Halt CPU */
nkeynes@359
   852
:}
nkeynes@359
   853
RTE {:
nkeynes@359
   854
    CHECKPRIV();
nkeynes@359
   855
    CHECKDEST( sh4r.spc );
nkeynes@359
   856
    CHECKSLOTILLEGAL();
nkeynes@359
   857
    sh4r.in_delay_slot = 1;
nkeynes@359
   858
    sh4r.pc = sh4r.new_pc;
nkeynes@359
   859
    sh4r.new_pc = sh4r.spc;
nkeynes@374
   860
    sh4_write_sr( sh4r.ssr );
nkeynes@359
   861
    return TRUE;
nkeynes@359
   862
:}
nkeynes@359
   863
JMP @Rn {:
nkeynes@359
   864
    CHECKDEST( sh4r.r[Rn] );
nkeynes@359
   865
    CHECKSLOTILLEGAL();
nkeynes@359
   866
    sh4r.in_delay_slot = 1;
nkeynes@359
   867
    sh4r.pc = sh4r.new_pc;
nkeynes@359
   868
    sh4r.new_pc = sh4r.r[Rn];
nkeynes@359
   869
    return TRUE;
nkeynes@359
   870
:}
nkeynes@359
   871
JSR @Rn {:
nkeynes@359
   872
    CHECKDEST( sh4r.r[Rn] );
nkeynes@359
   873
    CHECKSLOTILLEGAL();
nkeynes@359
   874
    sh4r.in_delay_slot = 1;
nkeynes@359
   875
    sh4r.pc = sh4r.new_pc;
nkeynes@359
   876
    sh4r.new_pc = sh4r.r[Rn];
nkeynes@359
   877
    sh4r.pr = pc + 4;
nkeynes@359
   878
    TRACE_CALL( pc, sh4r.new_pc );
nkeynes@359
   879
    return TRUE;
nkeynes@359
   880
:}
nkeynes@359
   881
STS MACH, Rn {: sh4r.r[Rn] = (sh4r.mac>>32); :}
nkeynes@359
   882
STS.L MACH, @-Rn {:
nkeynes@587
   883
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
   884
    MEM_WRITE_LONG( sh4r.r[Rn]-4, (sh4r.mac>>32) );
nkeynes@359
   885
    sh4r.r[Rn] -= 4;
nkeynes@359
   886
:}
nkeynes@359
   887
STC.L SR, @-Rn {:
nkeynes@359
   888
    CHECKPRIV();
nkeynes@587
   889
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
   890
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4_read_sr() );
nkeynes@359
   891
    sh4r.r[Rn] -= 4;
nkeynes@359
   892
:}
nkeynes@359
   893
LDS.L @Rm+, MACH {:
nkeynes@359
   894
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
   895
    MEM_READ_LONG(sh4r.r[Rm], tmp);
nkeynes@359
   896
    sh4r.mac = (sh4r.mac & 0x00000000FFFFFFFF) |
nkeynes@586
   897
	(((uint64_t)tmp)<<32);
nkeynes@359
   898
    sh4r.r[Rm] += 4;
nkeynes@359
   899
:}
nkeynes@359
   900
LDC.L @Rm+, SR {:
nkeynes@359
   901
    CHECKSLOTILLEGAL();
nkeynes@359
   902
    CHECKPRIV();
nkeynes@359
   903
    CHECKWALIGN32( sh4r.r[Rm] );
nkeynes@586
   904
    MEM_READ_LONG(sh4r.r[Rm], tmp);
nkeynes@586
   905
    sh4_write_sr( tmp );
nkeynes@359
   906
    sh4r.r[Rm] +=4;
nkeynes@359
   907
:}
nkeynes@359
   908
LDS Rm, MACH {:
nkeynes@359
   909
    sh4r.mac = (sh4r.mac & 0x00000000FFFFFFFF) |
nkeynes@359
   910
               (((uint64_t)sh4r.r[Rm])<<32);
nkeynes@359
   911
:}
nkeynes@359
   912
LDC Rm, SR {:
nkeynes@359
   913
    CHECKSLOTILLEGAL();
nkeynes@359
   914
    CHECKPRIV();
nkeynes@374
   915
    sh4_write_sr( sh4r.r[Rm] );
nkeynes@359
   916
:}
nkeynes@359
   917
LDC Rm, SGR {:
nkeynes@359
   918
    CHECKPRIV();
nkeynes@359
   919
    sh4r.sgr = sh4r.r[Rm];
nkeynes@359
   920
:}
nkeynes@359
   921
LDC.L @Rm+, SGR {:
nkeynes@359
   922
    CHECKPRIV();
nkeynes@359
   923
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
   924
    MEM_READ_LONG(sh4r.r[Rm], sh4r.sgr);
nkeynes@359
   925
    sh4r.r[Rm] +=4;
nkeynes@359
   926
:}
nkeynes@359
   927
STS MACL, Rn {: sh4r.r[Rn] = (uint32_t)sh4r.mac; :}
nkeynes@359
   928
STS.L MACL, @-Rn {:
nkeynes@587
   929
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
   930
    MEM_WRITE_LONG( sh4r.r[Rn]-4, (uint32_t)sh4r.mac );
nkeynes@359
   931
    sh4r.r[Rn] -= 4;
nkeynes@359
   932
:}
nkeynes@359
   933
STC.L GBR, @-Rn {:
nkeynes@587
   934
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
   935
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.gbr );
nkeynes@359
   936
    sh4r.r[Rn] -= 4;
nkeynes@359
   937
:}
nkeynes@359
   938
LDS.L @Rm+, MACL {:
nkeynes@359
   939
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
   940
    MEM_READ_LONG(sh4r.r[Rm], tmp);
nkeynes@359
   941
    sh4r.mac = (sh4r.mac & 0xFFFFFFFF00000000LL) |
nkeynes@586
   942
               (uint64_t)((uint32_t)tmp);
nkeynes@359
   943
    sh4r.r[Rm] += 4;
nkeynes@359
   944
:}
nkeynes@359
   945
LDC.L @Rm+, GBR {:
nkeynes@359
   946
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
   947
    MEM_READ_LONG(sh4r.r[Rm], sh4r.gbr);
nkeynes@359
   948
    sh4r.r[Rm] +=4;
nkeynes@359
   949
:}
nkeynes@359
   950
LDS Rm, MACL {:
nkeynes@359
   951
    sh4r.mac = (sh4r.mac & 0xFFFFFFFF00000000LL) |
nkeynes@359
   952
               (uint64_t)((uint32_t)(sh4r.r[Rm]));
nkeynes@359
   953
:}
nkeynes@359
   954
LDC Rm, GBR {: sh4r.gbr = sh4r.r[Rm]; :}
nkeynes@359
   955
STS PR, Rn {: sh4r.r[Rn] = sh4r.pr; :}
nkeynes@359
   956
STS.L PR, @-Rn {:
nkeynes@587
   957
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
   958
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.pr );
nkeynes@359
   959
    sh4r.r[Rn] -= 4;
nkeynes@359
   960
:}
nkeynes@359
   961
STC.L VBR, @-Rn {:
nkeynes@359
   962
    CHECKPRIV();
nkeynes@587
   963
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
   964
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.vbr );
nkeynes@359
   965
    sh4r.r[Rn] -= 4;
nkeynes@359
   966
:}
nkeynes@359
   967
LDS.L @Rm+, PR {:
nkeynes@359
   968
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
   969
    MEM_READ_LONG( sh4r.r[Rm], sh4r.pr );
nkeynes@359
   970
    sh4r.r[Rm] += 4;
nkeynes@359
   971
:}
nkeynes@359
   972
LDC.L @Rm+, VBR {:
nkeynes@359
   973
    CHECKPRIV();
nkeynes@359
   974
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
   975
    MEM_READ_LONG(sh4r.r[Rm], sh4r.vbr);
nkeynes@359
   976
    sh4r.r[Rm] +=4;
nkeynes@359
   977
:}
nkeynes@359
   978
LDS Rm, PR {: sh4r.pr = sh4r.r[Rm]; :}
nkeynes@359
   979
LDC Rm, VBR {:
nkeynes@359
   980
    CHECKPRIV();
nkeynes@359
   981
    sh4r.vbr = sh4r.r[Rm];
nkeynes@359
   982
:}
nkeynes@359
   983
STC SGR, Rn {:
nkeynes@359
   984
    CHECKPRIV();
nkeynes@359
   985
    sh4r.r[Rn] = sh4r.sgr;
nkeynes@359
   986
:}
nkeynes@359
   987
STC.L SGR, @-Rn {:
nkeynes@359
   988
    CHECKPRIV();
nkeynes@587
   989
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
   990
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.sgr );
nkeynes@359
   991
    sh4r.r[Rn] -= 4;
nkeynes@359
   992
:}
nkeynes@359
   993
STC.L SSR, @-Rn {:
nkeynes@359
   994
    CHECKPRIV();
nkeynes@587
   995
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
   996
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.ssr );
nkeynes@359
   997
    sh4r.r[Rn] -= 4;
nkeynes@359
   998
:}
nkeynes@359
   999
LDC.L @Rm+, SSR {:
nkeynes@359
  1000
    CHECKPRIV();
nkeynes@359
  1001
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
  1002
    MEM_READ_LONG(sh4r.r[Rm], sh4r.ssr);
nkeynes@359
  1003
    sh4r.r[Rm] +=4;
nkeynes@359
  1004
:}
nkeynes@359
  1005
LDC Rm, SSR {:
nkeynes@359
  1006
    CHECKPRIV();
nkeynes@359
  1007
    sh4r.ssr = sh4r.r[Rm];
nkeynes@359
  1008
:}
nkeynes@359
  1009
STC.L SPC, @-Rn {:
nkeynes@359
  1010
    CHECKPRIV();
nkeynes@587
  1011
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
  1012
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.spc );
nkeynes@359
  1013
    sh4r.r[Rn] -= 4;
nkeynes@359
  1014
:}
nkeynes@359
  1015
LDC.L @Rm+, SPC {:
nkeynes@359
  1016
    CHECKPRIV();
nkeynes@359
  1017
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
  1018
    MEM_READ_LONG(sh4r.r[Rm], sh4r.spc);
nkeynes@359
  1019
    sh4r.r[Rm] +=4;
nkeynes@359
  1020
:}
nkeynes@359
  1021
LDC Rm, SPC {:
nkeynes@359
  1022
    CHECKPRIV();
nkeynes@359
  1023
    sh4r.spc = sh4r.r[Rm];
nkeynes@359
  1024
:}
nkeynes@626
  1025
STS FPUL, Rn {: 
nkeynes@626
  1026
    CHECKFPUEN();
nkeynes@669
  1027
    sh4r.r[Rn] = FPULi; 
nkeynes@626
  1028
:}
nkeynes@359
  1029
STS.L FPUL, @-Rn {:
nkeynes@626
  1030
    CHECKFPUEN();
nkeynes@587
  1031
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@669
  1032
    MEM_WRITE_LONG( sh4r.r[Rn]-4, FPULi );
nkeynes@359
  1033
    sh4r.r[Rn] -= 4;
nkeynes@359
  1034
:}
nkeynes@359
  1035
LDS.L @Rm+, FPUL {:
nkeynes@626
  1036
    CHECKFPUEN();
nkeynes@359
  1037
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@669
  1038
    MEM_READ_LONG(sh4r.r[Rm], FPULi);
nkeynes@359
  1039
    sh4r.r[Rm] +=4;
nkeynes@359
  1040
:}
nkeynes@626
  1041
LDS Rm, FPUL {:
nkeynes@626
  1042
    CHECKFPUEN();
nkeynes@669
  1043
    FPULi = sh4r.r[Rm]; 
nkeynes@626
  1044
:}
nkeynes@626
  1045
STS FPSCR, Rn {: 
nkeynes@626
  1046
    CHECKFPUEN();
nkeynes@626
  1047
    sh4r.r[Rn] = sh4r.fpscr; 
nkeynes@626
  1048
:}
nkeynes@359
  1049
STS.L FPSCR, @-Rn {:
nkeynes@626
  1050
    CHECKFPUEN();
nkeynes@587
  1051
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
  1052
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.fpscr );
nkeynes@359
  1053
    sh4r.r[Rn] -= 4;
nkeynes@359
  1054
:}
nkeynes@359
  1055
LDS.L @Rm+, FPSCR {:
nkeynes@626
  1056
    CHECKFPUEN();
nkeynes@359
  1057
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@669
  1058
    MEM_READ_LONG(sh4r.r[Rm], tmp);
nkeynes@359
  1059
    sh4r.r[Rm] +=4;
nkeynes@669
  1060
    sh4_write_fpscr( tmp );
nkeynes@359
  1061
:}
nkeynes@374
  1062
LDS Rm, FPSCR {: 
nkeynes@626
  1063
    CHECKFPUEN();
nkeynes@669
  1064
    sh4_write_fpscr( sh4r.r[Rm] );
nkeynes@374
  1065
:}
nkeynes@359
  1066
STC DBR, Rn {: CHECKPRIV(); sh4r.r[Rn] = sh4r.dbr; :}
nkeynes@359
  1067
STC.L DBR, @-Rn {:
nkeynes@359
  1068
    CHECKPRIV();
nkeynes@587
  1069
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
  1070
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.dbr );
nkeynes@359
  1071
    sh4r.r[Rn] -= 4;
nkeynes@359
  1072
:}
nkeynes@359
  1073
LDC.L @Rm+, DBR {:
nkeynes@359
  1074
    CHECKPRIV();
nkeynes@359
  1075
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
  1076
    MEM_READ_LONG(sh4r.r[Rm], sh4r.dbr);
nkeynes@359
  1077
    sh4r.r[Rm] +=4;
nkeynes@359
  1078
:}
nkeynes@359
  1079
LDC Rm, DBR {:
nkeynes@359
  1080
    CHECKPRIV();
nkeynes@359
  1081
    sh4r.dbr = sh4r.r[Rm];
nkeynes@359
  1082
:}
nkeynes@359
  1083
STC.L Rm_BANK, @-Rn {:
nkeynes@359
  1084
    CHECKPRIV();
nkeynes@587
  1085
    CHECKWALIGN32( sh4r.r[Rn] );
nkeynes@587
  1086
    MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.r_bank[Rm_BANK] );
nkeynes@359
  1087
    sh4r.r[Rn] -= 4;
nkeynes@359
  1088
:}
nkeynes@359
  1089
LDC.L @Rm+, Rn_BANK {:
nkeynes@359
  1090
    CHECKPRIV();
nkeynes@359
  1091
    CHECKRALIGN32( sh4r.r[Rm] );
nkeynes@586
  1092
    MEM_READ_LONG( sh4r.r[Rm], sh4r.r_bank[Rn_BANK] );
nkeynes@359
  1093
    sh4r.r[Rm] += 4;
nkeynes@359
  1094
:}
nkeynes@359
  1095
LDC Rm, Rn_BANK {:
nkeynes@359
  1096
    CHECKPRIV();
nkeynes@359
  1097
    sh4r.r_bank[Rn_BANK] = sh4r.r[Rm];
nkeynes@359
  1098
:}
nkeynes@359
  1099
STC SR, Rn {: 
nkeynes@359
  1100
    CHECKPRIV();
nkeynes@359
  1101
    sh4r.r[Rn] = sh4_read_sr();
nkeynes@359
  1102
:}
nkeynes@359
  1103
STC GBR, Rn {:
nkeynes@359
  1104
    sh4r.r[Rn] = sh4r.gbr;
nkeynes@359
  1105
:}
nkeynes@359
  1106
STC VBR, Rn {:
nkeynes@359
  1107
    CHECKPRIV();
nkeynes@359
  1108
    sh4r.r[Rn] = sh4r.vbr;
nkeynes@359
  1109
:}
nkeynes@359
  1110
STC SSR, Rn {:
nkeynes@359
  1111
    CHECKPRIV();
nkeynes@359
  1112
    sh4r.r[Rn] = sh4r.ssr;
nkeynes@359
  1113
:}
nkeynes@359
  1114
STC SPC, Rn {:
nkeynes@359
  1115
    CHECKPRIV();
nkeynes@359
  1116
    sh4r.r[Rn] = sh4r.spc;
nkeynes@359
  1117
:}
nkeynes@359
  1118
STC Rm_BANK, Rn {:
nkeynes@359
  1119
    CHECKPRIV();
nkeynes@359
  1120
    sh4r.r[Rn] = sh4r.r_bank[Rm_BANK];
nkeynes@359
  1121
:}
nkeynes@359
  1122
nkeynes@359
  1123
FADD FRm, FRn {:
nkeynes@359
  1124
    CHECKFPUEN();
nkeynes@359
  1125
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1126
	DR(FRn) += DR(FRm);
nkeynes@359
  1127
    } else {
nkeynes@359
  1128
	FR(FRn) += FR(FRm);
nkeynes@359
  1129
    }
nkeynes@359
  1130
:}
nkeynes@359
  1131
FSUB FRm, FRn {:
nkeynes@359
  1132
    CHECKFPUEN();
nkeynes@359
  1133
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1134
	DR(FRn) -= DR(FRm);
nkeynes@359
  1135
    } else {
nkeynes@359
  1136
	FR(FRn) -= FR(FRm);
nkeynes@359
  1137
    }
nkeynes@359
  1138
:}
nkeynes@359
  1139
nkeynes@359
  1140
FMUL FRm, FRn {:
nkeynes@359
  1141
    CHECKFPUEN();
nkeynes@359
  1142
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1143
	DR(FRn) *= DR(FRm);
nkeynes@359
  1144
    } else {
nkeynes@359
  1145
	FR(FRn) *= FR(FRm);
nkeynes@359
  1146
    }
nkeynes@359
  1147
:}
nkeynes@359
  1148
nkeynes@359
  1149
FDIV FRm, FRn {:
nkeynes@359
  1150
    CHECKFPUEN();
nkeynes@359
  1151
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1152
	DR(FRn) /= DR(FRm);
nkeynes@359
  1153
    } else {
nkeynes@359
  1154
	FR(FRn) /= FR(FRm);
nkeynes@359
  1155
    }
nkeynes@359
  1156
:}
nkeynes@359
  1157
nkeynes@359
  1158
FCMP/EQ FRm, FRn {:
nkeynes@359
  1159
    CHECKFPUEN();
nkeynes@359
  1160
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1161
	sh4r.t = ( DR(FRn) == DR(FRm) ? 1 : 0 );
nkeynes@359
  1162
    } else {
nkeynes@359
  1163
	sh4r.t = ( FR(FRn) == FR(FRm) ? 1 : 0 );
nkeynes@359
  1164
    }
nkeynes@359
  1165
:}
nkeynes@359
  1166
nkeynes@359
  1167
FCMP/GT FRm, FRn {:
nkeynes@359
  1168
    CHECKFPUEN();
nkeynes@359
  1169
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1170
	sh4r.t = ( DR(FRn) > DR(FRm) ? 1 : 0 );
nkeynes@359
  1171
    } else {
nkeynes@359
  1172
	sh4r.t = ( FR(FRn) > FR(FRm) ? 1 : 0 );
nkeynes@359
  1173
    }
nkeynes@359
  1174
:}
nkeynes@359
  1175
nkeynes@359
  1176
FSTS FPUL, FRn {: CHECKFPUEN(); FR(FRn) = FPULf; :}
nkeynes@359
  1177
FLDS FRm, FPUL {: CHECKFPUEN(); FPULf = FR(FRm); :}
nkeynes@359
  1178
FLOAT FPUL, FRn {: 
nkeynes@359
  1179
    CHECKFPUEN();
nkeynes@374
  1180
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@374
  1181
	if( FRn&1 ) { // No, really...
nkeynes@374
  1182
	    dtmp = (double)FPULi;
nkeynes@374
  1183
	    FR(FRn) = *(((float *)&dtmp)+1);
nkeynes@374
  1184
	} else {
nkeynes@374
  1185
	    DRF(FRn>>1) = (double)FPULi;
nkeynes@374
  1186
	}
nkeynes@374
  1187
    } else {
nkeynes@359
  1188
	FR(FRn) = (float)FPULi;
nkeynes@374
  1189
    }
nkeynes@359
  1190
:}
nkeynes@359
  1191
FTRC FRm, FPUL {:
nkeynes@359
  1192
    CHECKFPUEN();
nkeynes@359
  1193
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@374
  1194
	if( FRm&1 ) {
nkeynes@374
  1195
	    dtmp = 0;
nkeynes@374
  1196
	    *(((float *)&dtmp)+1) = FR(FRm);
nkeynes@374
  1197
	} else {
nkeynes@374
  1198
	    dtmp = DRF(FRm>>1);
nkeynes@374
  1199
	}
nkeynes@359
  1200
        if( dtmp >= MAX_INTF )
nkeynes@359
  1201
            FPULi = MAX_INT;
nkeynes@359
  1202
        else if( dtmp <= MIN_INTF )
nkeynes@359
  1203
            FPULi = MIN_INT;
nkeynes@359
  1204
        else 
nkeynes@359
  1205
            FPULi = (int32_t)dtmp;
nkeynes@359
  1206
    } else {
nkeynes@359
  1207
	ftmp = FR(FRm);
nkeynes@359
  1208
	if( ftmp >= MAX_INTF )
nkeynes@359
  1209
	    FPULi = MAX_INT;
nkeynes@359
  1210
	else if( ftmp <= MIN_INTF )
nkeynes@359
  1211
	    FPULi = MIN_INT;
nkeynes@359
  1212
	else
nkeynes@359
  1213
	    FPULi = (int32_t)ftmp;
nkeynes@359
  1214
    }
nkeynes@359
  1215
:}
nkeynes@359
  1216
FNEG FRn {:
nkeynes@359
  1217
    CHECKFPUEN();
nkeynes@359
  1218
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1219
	DR(FRn) = -DR(FRn);
nkeynes@359
  1220
    } else {
nkeynes@359
  1221
        FR(FRn) = -FR(FRn);
nkeynes@359
  1222
    }
nkeynes@359
  1223
:}
nkeynes@359
  1224
FABS FRn {:
nkeynes@359
  1225
    CHECKFPUEN();
nkeynes@359
  1226
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1227
	DR(FRn) = fabs(DR(FRn));
nkeynes@359
  1228
    } else {
nkeynes@359
  1229
        FR(FRn) = fabsf(FR(FRn));
nkeynes@359
  1230
    }
nkeynes@359
  1231
:}
nkeynes@359
  1232
FSQRT FRn {:
nkeynes@359
  1233
    CHECKFPUEN();
nkeynes@359
  1234
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1235
	DR(FRn) = sqrt(DR(FRn));
nkeynes@359
  1236
    } else {
nkeynes@359
  1237
        FR(FRn) = sqrtf(FR(FRn));
nkeynes@359
  1238
    }
nkeynes@359
  1239
:}
nkeynes@359
  1240
FLDI0 FRn {:
nkeynes@359
  1241
    CHECKFPUEN();
nkeynes@359
  1242
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1243
	DR(FRn) = 0.0;
nkeynes@359
  1244
    } else {
nkeynes@359
  1245
        FR(FRn) = 0.0;
nkeynes@359
  1246
    }
nkeynes@359
  1247
:}
nkeynes@359
  1248
FLDI1 FRn {:
nkeynes@359
  1249
    CHECKFPUEN();
nkeynes@359
  1250
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1251
	DR(FRn) = 1.0;
nkeynes@359
  1252
    } else {
nkeynes@359
  1253
        FR(FRn) = 1.0;
nkeynes@359
  1254
    }
nkeynes@359
  1255
:}
nkeynes@359
  1256
FMAC FR0, FRm, FRn {:
nkeynes@359
  1257
    CHECKFPUEN();
nkeynes@359
  1258
    if( IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1259
        DR(FRn) += DR(FRm)*DR(0);
nkeynes@359
  1260
    } else {
nkeynes@359
  1261
	FR(FRn) += FR(FRm)*FR(0);
nkeynes@359
  1262
    }
nkeynes@359
  1263
:}
nkeynes@374
  1264
FRCHG {: 
nkeynes@374
  1265
    CHECKFPUEN(); 
nkeynes@374
  1266
    sh4r.fpscr ^= FPSCR_FR; 
nkeynes@669
  1267
    sh4_switch_fr_banks();
nkeynes@374
  1268
:}
nkeynes@359
  1269
FSCHG {: CHECKFPUEN(); sh4r.fpscr ^= FPSCR_SZ; :}
nkeynes@359
  1270
FCNVSD FPUL, FRn {:
nkeynes@359
  1271
    CHECKFPUEN();
nkeynes@359
  1272
    if( IS_FPU_DOUBLEPREC() && !IS_FPU_DOUBLESIZE() ) {
nkeynes@359
  1273
	DR(FRn) = (double)FPULf;
nkeynes@359
  1274
    }
nkeynes@359
  1275
:}
nkeynes@359
  1276
FCNVDS FRm, FPUL {:
nkeynes@359
  1277
    CHECKFPUEN();
nkeynes@359
  1278
    if( IS_FPU_DOUBLEPREC() && !IS_FPU_DOUBLESIZE() ) {
nkeynes@359
  1279
	FPULf = (float)DR(FRm);
nkeynes@359
  1280
    }
nkeynes@359
  1281
:}
nkeynes@359
  1282
nkeynes@359
  1283
FSRRA FRn {:
nkeynes@359
  1284
    CHECKFPUEN();
nkeynes@359
  1285
    if( !IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1286
	FR(FRn) = 1.0/sqrtf(FR(FRn));
nkeynes@359
  1287
    }
nkeynes@359
  1288
:}
nkeynes@359
  1289
FIPR FVm, FVn {:
nkeynes@359
  1290
    CHECKFPUEN();
nkeynes@359
  1291
    if( !IS_FPU_DOUBLEPREC() ) {
nkeynes@359
  1292
        int tmp2 = FVn<<2;
nkeynes@359
  1293
        tmp = FVm<<2;
nkeynes@359
  1294
        FR(tmp2+3) = FR(tmp)*FR(tmp2) +
nkeynes@359
  1295
            FR(tmp+1)*FR(tmp2+1) +
nkeynes@359
  1296
            FR(tmp+2)*FR(tmp2+2) +
nkeynes@359
  1297
            FR(tmp+3)*FR(tmp2+3);
nkeynes@359
  1298
    }
nkeynes@359
  1299
:}
nkeynes@359
  1300
FSCA FPUL, FRn {:
nkeynes@359
  1301
    CHECKFPUEN();
nkeynes@359
  1302
    if( !IS_FPU_DOUBLEPREC() ) {
nkeynes@758
  1303
	sh4_fsca( FPULi, (float *)&(DRF(FRn>>1)) );
nkeynes@359
  1304
    }
nkeynes@359
  1305
:}
nkeynes@359
  1306
FTRV XMTRX, FVn {:
nkeynes@359
  1307
    CHECKFPUEN();
nkeynes@359
  1308
    if( !IS_FPU_DOUBLEPREC() ) {
nkeynes@758
  1309
	sh4_ftrv((float *)&(DRF(FVn<<1)) );
nkeynes@359
  1310
    }
nkeynes@359
  1311
:}
nkeynes@359
  1312
UNDEF {:
nkeynes@359
  1313
    UNDEF(ir);
nkeynes@359
  1314
:}
nkeynes@359
  1315
%%
nkeynes@359
  1316
    sh4r.pc = sh4r.new_pc;
nkeynes@359
  1317
    sh4r.new_pc += 2;
nkeynes@927
  1318
nkeynes@927
  1319
except:
nkeynes@359
  1320
    sh4r.in_delay_slot = 0;
nkeynes@359
  1321
    return TRUE;
nkeynes@359
  1322
}
.