Search
lxdream.org :: lxdream/src/sh4/sh4.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4.c
changeset 936:f394309c399a
prev935:45246788ca00
next937:81b0c79d9788
author nkeynes
date Sat Dec 27 02:59:35 2008 +0000 (13 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change Replace fpscr_mask/fpscr flags in xlat_cache_block with a single xlat_sh4_mode,
which tracks the field of the same name in sh4r - actually a little faster this way.
Now depends on SR.MD, FPSCR.PR and FPSCR.SZ (although it doesn't benefit from the SR
flag yet).

Also fixed the failure to check the flags in the common case (code address returned
by previous block) which took away the performance benefits, but oh well.
file annotate diff log raw
nkeynes@378
     1
/**
nkeynes@586
     2
 * $Id$
nkeynes@378
     3
 * 
nkeynes@378
     4
 * SH4 parent module for all CPU modes and SH4 peripheral
nkeynes@378
     5
 * modules.
nkeynes@378
     6
 *
nkeynes@378
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@378
     8
 *
nkeynes@378
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@378
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@378
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@378
    12
 * (at your option) any later version.
nkeynes@378
    13
 *
nkeynes@378
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@378
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@378
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@378
    17
 * GNU General Public License for more details.
nkeynes@378
    18
 */
nkeynes@378
    19
nkeynes@378
    20
#define MODULE sh4_module
nkeynes@378
    21
#include <math.h>
nkeynes@740
    22
#include <setjmp.h>
nkeynes@617
    23
#include <assert.h>
nkeynes@671
    24
#include "lxdream.h"
nkeynes@422
    25
#include "dreamcast.h"
nkeynes@669
    26
#include "mem.h"
nkeynes@669
    27
#include "clock.h"
nkeynes@669
    28
#include "eventq.h"
nkeynes@669
    29
#include "syscall.h"
nkeynes@669
    30
#include "sh4/intc.h"
nkeynes@378
    31
#include "sh4/sh4core.h"
nkeynes@378
    32
#include "sh4/sh4mmio.h"
nkeynes@422
    33
#include "sh4/sh4stat.h"
nkeynes@617
    34
#include "sh4/sh4trans.h"
nkeynes@669
    35
#include "sh4/xltcache.h"
nkeynes@378
    36
nkeynes@378
    37
void sh4_init( void );
nkeynes@526
    38
void sh4_xlat_init( void );
nkeynes@378
    39
void sh4_reset( void );
nkeynes@378
    40
void sh4_start( void );
nkeynes@378
    41
void sh4_stop( void );
nkeynes@378
    42
void sh4_save_state( FILE *f );
nkeynes@378
    43
int sh4_load_state( FILE *f );
nkeynes@378
    44
nkeynes@378
    45
uint32_t sh4_run_slice( uint32_t );
nkeynes@378
    46
uint32_t sh4_xlat_run_slice( uint32_t );
nkeynes@378
    47
nkeynes@378
    48
struct dreamcast_module sh4_module = { "SH4", sh4_init, sh4_reset, 
nkeynes@736
    49
        sh4_start, sh4_run_slice, sh4_stop,
nkeynes@736
    50
        sh4_save_state, sh4_load_state };
nkeynes@378
    51
nkeynes@903
    52
struct sh4_registers sh4r __attribute__((aligned(16)));
nkeynes@378
    53
struct breakpoint_struct sh4_breakpoints[MAX_BREAKPOINTS];
nkeynes@378
    54
int sh4_breakpoint_count = 0;
nkeynes@929
    55
nkeynes@591
    56
gboolean sh4_starting = FALSE;
nkeynes@526
    57
static gboolean sh4_use_translator = FALSE;
nkeynes@740
    58
static jmp_buf sh4_exit_jmp_buf;
nkeynes@740
    59
static gboolean sh4_running = FALSE;
nkeynes@586
    60
struct sh4_icache_struct sh4_icache = { NULL, -1, -1, 0 };
nkeynes@378
    61
nkeynes@740
    62
void sh4_translate_set_enabled( gboolean use )
nkeynes@378
    63
{
nkeynes@736
    64
    // No-op if the translator was not built
nkeynes@526
    65
#ifdef SH4_TRANSLATOR
nkeynes@378
    66
    if( use ) {
nkeynes@736
    67
        sh4_translate_init();
nkeynes@378
    68
    }
nkeynes@526
    69
    sh4_use_translator = use;
nkeynes@526
    70
#endif
nkeynes@378
    71
}
nkeynes@378
    72
nkeynes@740
    73
gboolean sh4_translate_is_enabled()
nkeynes@586
    74
{
nkeynes@586
    75
    return sh4_use_translator;
nkeynes@586
    76
}
nkeynes@586
    77
nkeynes@378
    78
void sh4_init(void)
nkeynes@378
    79
{
nkeynes@378
    80
    register_io_regions( mmio_list_sh4mmio );
nkeynes@619
    81
    TMU_init();
nkeynes@935
    82
    xlat_cache_init();
nkeynes@931
    83
    sh4_mem_init();
nkeynes@378
    84
    sh4_reset();
nkeynes@671
    85
#ifdef ENABLE_SH4STATS
nkeynes@671
    86
    sh4_stats_reset();
nkeynes@671
    87
#endif
nkeynes@378
    88
}
nkeynes@378
    89
nkeynes@591
    90
void sh4_start(void)
nkeynes@591
    91
{
nkeynes@591
    92
    sh4_starting = TRUE;
nkeynes@591
    93
}
nkeynes@591
    94
nkeynes@378
    95
void sh4_reset(void)
nkeynes@378
    96
{
nkeynes@526
    97
    if(	sh4_use_translator ) {
nkeynes@736
    98
        xlat_flush_cache();
nkeynes@472
    99
    }
nkeynes@472
   100
nkeynes@378
   101
    /* zero everything out, for the sake of having a consistent state. */
nkeynes@378
   102
    memset( &sh4r, 0, sizeof(sh4r) );
nkeynes@378
   103
nkeynes@378
   104
    /* Resume running if we were halted */
nkeynes@378
   105
    sh4r.sh4_state = SH4_STATE_RUNNING;
nkeynes@378
   106
nkeynes@378
   107
    sh4r.pc    = 0xA0000000;
nkeynes@378
   108
    sh4r.new_pc= 0xA0000002;
nkeynes@378
   109
    sh4r.vbr   = 0x00000000;
nkeynes@378
   110
    sh4r.fpscr = 0x00040001;
nkeynes@378
   111
    sh4r.sr    = 0x700000F0;
nkeynes@378
   112
nkeynes@378
   113
    /* Mem reset will do this, but if we want to reset _just_ the SH4... */
nkeynes@378
   114
    MMIO_WRITE( MMU, EXPEVT, EXC_POWER_RESET );
nkeynes@378
   115
nkeynes@378
   116
    /* Peripheral modules */
nkeynes@378
   117
    CPG_reset();
nkeynes@378
   118
    INTC_reset();
nkeynes@378
   119
    MMU_reset();
nkeynes@841
   120
    PMM_reset();
nkeynes@378
   121
    TMU_reset();
nkeynes@378
   122
    SCIF_reset();
nkeynes@671
   123
nkeynes@671
   124
#ifdef ENABLE_SH4STATS
nkeynes@401
   125
    sh4_stats_reset();
nkeynes@671
   126
#endif
nkeynes@378
   127
}
nkeynes@378
   128
nkeynes@378
   129
void sh4_stop(void)
nkeynes@378
   130
{
nkeynes@526
   131
    if(	sh4_use_translator ) {
nkeynes@736
   132
        /* If we were running with the translator, update new_pc and in_delay_slot */
nkeynes@736
   133
        sh4r.new_pc = sh4r.pc+2;
nkeynes@736
   134
        sh4r.in_delay_slot = FALSE;
nkeynes@502
   135
    }
nkeynes@378
   136
nkeynes@378
   137
}
nkeynes@378
   138
nkeynes@740
   139
/**
nkeynes@740
   140
 * Execute a timeslice using translated code only (ie translate/execute loop)
nkeynes@740
   141
 */
nkeynes@740
   142
uint32_t sh4_run_slice( uint32_t nanosecs ) 
nkeynes@740
   143
{
nkeynes@740
   144
    sh4r.slice_cycle = 0;
nkeynes@740
   145
nkeynes@740
   146
    if( sh4r.sh4_state != SH4_STATE_RUNNING ) {
nkeynes@740
   147
        sh4_sleep_run_slice(nanosecs);
nkeynes@740
   148
    }
nkeynes@740
   149
nkeynes@740
   150
    /* Setup for sudden vm exits */
nkeynes@740
   151
    switch( setjmp(sh4_exit_jmp_buf) ) {
nkeynes@740
   152
    case CORE_EXIT_BREAKPOINT:
nkeynes@740
   153
        sh4_clear_breakpoint( sh4r.pc, BREAK_ONESHOT );
nkeynes@740
   154
        /* fallthrough */
nkeynes@740
   155
    case CORE_EXIT_HALT:
nkeynes@740
   156
        if( sh4r.sh4_state != SH4_STATE_STANDBY ) {
nkeynes@740
   157
            TMU_run_slice( sh4r.slice_cycle );
nkeynes@740
   158
            SCIF_run_slice( sh4r.slice_cycle );
nkeynes@841
   159
            PMM_run_slice( sh4r.slice_cycle );
nkeynes@740
   160
            dreamcast_stop();
nkeynes@740
   161
            return sh4r.slice_cycle;
nkeynes@740
   162
        }
nkeynes@740
   163
    case CORE_EXIT_SYSRESET:
nkeynes@740
   164
        dreamcast_reset();
nkeynes@740
   165
        break;
nkeynes@740
   166
    case CORE_EXIT_SLEEP:
nkeynes@740
   167
        sh4_sleep_run_slice(nanosecs);
nkeynes@740
   168
        break;  
nkeynes@740
   169
    case CORE_EXIT_FLUSH_ICACHE:
nkeynes@740
   170
#ifdef SH4_TRANSLATOR
nkeynes@740
   171
        xlat_flush_cache();
nkeynes@740
   172
#endif
nkeynes@740
   173
        break;
nkeynes@740
   174
    }
nkeynes@740
   175
nkeynes@740
   176
    sh4_running = TRUE;
nkeynes@740
   177
    
nkeynes@740
   178
    /* Execute the core's real slice */
nkeynes@740
   179
#ifdef SH4_TRANSLATOR
nkeynes@740
   180
    if( sh4_use_translator ) {
nkeynes@740
   181
        sh4_translate_run_slice(nanosecs);
nkeynes@740
   182
    } else {
nkeynes@740
   183
        sh4_emulate_run_slice(nanosecs);
nkeynes@740
   184
    }
nkeynes@740
   185
#else
nkeynes@740
   186
    sh4_emulate_run_slice(nanosecs);
nkeynes@740
   187
#endif
nkeynes@740
   188
    
nkeynes@740
   189
    /* And finish off the peripherals afterwards */
nkeynes@740
   190
nkeynes@740
   191
    sh4_running = FALSE;
nkeynes@740
   192
    sh4_starting = FALSE;
nkeynes@740
   193
    sh4r.slice_cycle = nanosecs;
nkeynes@740
   194
    if( sh4r.sh4_state != SH4_STATE_STANDBY ) {
nkeynes@740
   195
        TMU_run_slice( nanosecs );
nkeynes@740
   196
        SCIF_run_slice( nanosecs );
nkeynes@841
   197
        PMM_run_slice( sh4r.slice_cycle );
nkeynes@740
   198
    }
nkeynes@740
   199
    return nanosecs;   
nkeynes@740
   200
}
nkeynes@740
   201
nkeynes@740
   202
void sh4_core_exit( int exit_code )
nkeynes@740
   203
{
nkeynes@740
   204
    if( sh4_running ) {
nkeynes@740
   205
#ifdef SH4_TRANSLATOR
nkeynes@740
   206
        if( sh4_use_translator ) {
nkeynes@740
   207
            sh4_translate_exit_recover();
nkeynes@740
   208
        }
nkeynes@740
   209
#endif
nkeynes@740
   210
        // longjmp back into sh4_run_slice
nkeynes@740
   211
        sh4_running = FALSE;
nkeynes@740
   212
        longjmp(sh4_exit_jmp_buf, exit_code);
nkeynes@740
   213
    }
nkeynes@740
   214
}
nkeynes@740
   215
nkeynes@740
   216
void sh4_flush_icache()
nkeynes@740
   217
{
nkeynes@740
   218
#ifdef SH4_TRANSLATOR
nkeynes@740
   219
    // FIXME: Special case needs to be generalized
nkeynes@790
   220
    if( sh4_use_translator ) {
nkeynes@790
   221
        if( sh4_translate_flush_cache() ) {
nkeynes@790
   222
            longjmp(sh4_exit_jmp_buf, CORE_EXIT_CONTINUE);
nkeynes@790
   223
        }
nkeynes@740
   224
    }
nkeynes@740
   225
#endif
nkeynes@740
   226
}
nkeynes@740
   227
nkeynes@378
   228
void sh4_save_state( FILE *f )
nkeynes@378
   229
{
nkeynes@526
   230
    if(	sh4_use_translator ) {
nkeynes@736
   231
        /* If we were running with the translator, update new_pc and in_delay_slot */
nkeynes@736
   232
        sh4r.new_pc = sh4r.pc+2;
nkeynes@736
   233
        sh4r.in_delay_slot = FALSE;
nkeynes@401
   234
    }
nkeynes@401
   235
nkeynes@936
   236
    fwrite( &sh4r, offsetof(struct sh4_registers, xlat_sh4_mode), 1, f );
nkeynes@378
   237
    MMU_save_state( f );
nkeynes@931
   238
    CCN_save_state( f );
nkeynes@841
   239
    PMM_save_state( f );
nkeynes@378
   240
    INTC_save_state( f );
nkeynes@378
   241
    TMU_save_state( f );
nkeynes@378
   242
    SCIF_save_state( f );
nkeynes@378
   243
}
nkeynes@378
   244
nkeynes@378
   245
int sh4_load_state( FILE * f )
nkeynes@378
   246
{
nkeynes@526
   247
    if(	sh4_use_translator ) {
nkeynes@736
   248
        xlat_flush_cache();
nkeynes@472
   249
    }
nkeynes@936
   250
    fread( &sh4r, offsetof(struct sh4_registers, xlat_sh4_mode), 1, f );
nkeynes@936
   251
    sh4r.xlat_sh4_mode = (sh4r.sr & SR_MD) | (sh4r.fpscr & (FPSCR_SZ|FPSCR_PR));
nkeynes@378
   252
    MMU_load_state( f );
nkeynes@931
   253
    CCN_load_state( f );
nkeynes@841
   254
    PMM_load_state( f );
nkeynes@378
   255
    INTC_load_state( f );
nkeynes@378
   256
    TMU_load_state( f );
nkeynes@378
   257
    return SCIF_load_state( f );
nkeynes@378
   258
}
nkeynes@378
   259
nkeynes@586
   260
void sh4_set_breakpoint( uint32_t pc, breakpoint_type_t type )
nkeynes@378
   261
{
nkeynes@378
   262
    sh4_breakpoints[sh4_breakpoint_count].address = pc;
nkeynes@378
   263
    sh4_breakpoints[sh4_breakpoint_count].type = type;
nkeynes@586
   264
    if( sh4_use_translator ) {
nkeynes@736
   265
        xlat_invalidate_word( pc );
nkeynes@586
   266
    }
nkeynes@378
   267
    sh4_breakpoint_count++;
nkeynes@378
   268
}
nkeynes@378
   269
nkeynes@586
   270
gboolean sh4_clear_breakpoint( uint32_t pc, breakpoint_type_t type )
nkeynes@378
   271
{
nkeynes@378
   272
    int i;
nkeynes@378
   273
nkeynes@378
   274
    for( i=0; i<sh4_breakpoint_count; i++ ) {
nkeynes@736
   275
        if( sh4_breakpoints[i].address == pc && 
nkeynes@736
   276
                sh4_breakpoints[i].type == type ) {
nkeynes@736
   277
            while( ++i < sh4_breakpoint_count ) {
nkeynes@736
   278
                sh4_breakpoints[i-1].address = sh4_breakpoints[i].address;
nkeynes@736
   279
                sh4_breakpoints[i-1].type = sh4_breakpoints[i].type;
nkeynes@736
   280
            }
nkeynes@736
   281
            if( sh4_use_translator ) {
nkeynes@736
   282
                xlat_invalidate_word( pc );
nkeynes@736
   283
            }
nkeynes@736
   284
            sh4_breakpoint_count--;
nkeynes@736
   285
            return TRUE;
nkeynes@736
   286
        }
nkeynes@378
   287
    }
nkeynes@378
   288
    return FALSE;
nkeynes@378
   289
}
nkeynes@378
   290
nkeynes@378
   291
int sh4_get_breakpoint( uint32_t pc )
nkeynes@378
   292
{
nkeynes@378
   293
    int i;
nkeynes@378
   294
    for( i=0; i<sh4_breakpoint_count; i++ ) {
nkeynes@736
   295
        if( sh4_breakpoints[i].address == pc )
nkeynes@736
   296
            return sh4_breakpoints[i].type;
nkeynes@378
   297
    }
nkeynes@378
   298
    return 0;
nkeynes@378
   299
}
nkeynes@378
   300
nkeynes@401
   301
void sh4_set_pc( int pc )
nkeynes@401
   302
{
nkeynes@401
   303
    sh4r.pc = pc;
nkeynes@401
   304
    sh4r.new_pc = pc+2;
nkeynes@401
   305
}
nkeynes@401
   306
nkeynes@401
   307
nkeynes@401
   308
/******************************* Support methods ***************************/
nkeynes@401
   309
nkeynes@401
   310
static void sh4_switch_banks( )
nkeynes@401
   311
{
nkeynes@401
   312
    uint32_t tmp[8];
nkeynes@401
   313
nkeynes@401
   314
    memcpy( tmp, sh4r.r, sizeof(uint32_t)*8 );
nkeynes@401
   315
    memcpy( sh4r.r, sh4r.r_bank, sizeof(uint32_t)*8 );
nkeynes@401
   316
    memcpy( sh4r.r_bank, tmp, sizeof(uint32_t)*8 );
nkeynes@401
   317
}
nkeynes@401
   318
nkeynes@905
   319
void FASTCALL sh4_switch_fr_banks()
nkeynes@669
   320
{
nkeynes@669
   321
    int i;
nkeynes@669
   322
    for( i=0; i<16; i++ ) {
nkeynes@736
   323
        float tmp = sh4r.fr[0][i];
nkeynes@736
   324
        sh4r.fr[0][i] = sh4r.fr[1][i];
nkeynes@736
   325
        sh4r.fr[1][i] = tmp;
nkeynes@669
   326
    }
nkeynes@669
   327
}
nkeynes@669
   328
nkeynes@905
   329
void FASTCALL sh4_write_sr( uint32_t newval )
nkeynes@401
   330
{
nkeynes@586
   331
    int oldbank = (sh4r.sr&SR_MDRB) == SR_MDRB;
nkeynes@586
   332
    int newbank = (newval&SR_MDRB) == SR_MDRB;
nkeynes@586
   333
    if( oldbank != newbank )
nkeynes@401
   334
        sh4_switch_banks();
nkeynes@822
   335
    sh4r.sr = newval & SR_MASK;
nkeynes@401
   336
    sh4r.t = (newval&SR_T) ? 1 : 0;
nkeynes@401
   337
    sh4r.s = (newval&SR_S) ? 1 : 0;
nkeynes@401
   338
    sh4r.m = (newval&SR_M) ? 1 : 0;
nkeynes@401
   339
    sh4r.q = (newval&SR_Q) ? 1 : 0;
nkeynes@936
   340
    sh4r.xlat_sh4_mode = (sh4r.sr & SR_MD) | (sh4r.fpscr & (FPSCR_SZ|FPSCR_PR));
nkeynes@401
   341
    intc_mask_changed();
nkeynes@401
   342
}
nkeynes@401
   343
nkeynes@905
   344
void FASTCALL sh4_write_fpscr( uint32_t newval )
nkeynes@669
   345
{
nkeynes@669
   346
    if( (sh4r.fpscr ^ newval) & FPSCR_FR ) {
nkeynes@736
   347
        sh4_switch_fr_banks();
nkeynes@669
   348
    }
nkeynes@823
   349
    sh4r.fpscr = newval & FPSCR_MASK;
nkeynes@936
   350
    sh4r.xlat_sh4_mode = (sh4r.sr & SR_MD) | (sh4r.fpscr & (FPSCR_SZ|FPSCR_PR));
nkeynes@669
   351
}
nkeynes@669
   352
nkeynes@905
   353
uint32_t FASTCALL sh4_read_sr( void )
nkeynes@401
   354
{
nkeynes@401
   355
    /* synchronize sh4r.sr with the various bitflags */
nkeynes@401
   356
    sh4r.sr &= SR_MQSTMASK;
nkeynes@401
   357
    if( sh4r.t ) sh4r.sr |= SR_T;
nkeynes@401
   358
    if( sh4r.s ) sh4r.sr |= SR_S;
nkeynes@401
   359
    if( sh4r.m ) sh4r.sr |= SR_M;
nkeynes@401
   360
    if( sh4r.q ) sh4r.sr |= SR_Q;
nkeynes@401
   361
    return sh4r.sr;
nkeynes@401
   362
}
nkeynes@401
   363
nkeynes@401
   364
nkeynes@401
   365
nkeynes@401
   366
#define RAISE( x, v ) do{			\
nkeynes@401
   367
    if( sh4r.vbr == 0 ) { \
nkeynes@401
   368
        ERROR( "%08X: VBR not initialized while raising exception %03X, halting", sh4r.pc, x ); \
nkeynes@740
   369
        sh4_core_exit(CORE_EXIT_HALT); return FALSE;	\
nkeynes@401
   370
    } else { \
nkeynes@401
   371
        sh4r.spc = sh4r.pc;	\
nkeynes@401
   372
        sh4r.ssr = sh4_read_sr(); \
nkeynes@401
   373
        sh4r.sgr = sh4r.r[15]; \
nkeynes@401
   374
        MMIO_WRITE(MMU,EXPEVT,x); \
nkeynes@401
   375
        sh4r.pc = sh4r.vbr + v; \
nkeynes@401
   376
        sh4r.new_pc = sh4r.pc + 2; \
nkeynes@401
   377
        sh4_write_sr( sh4r.ssr |SR_MD|SR_BL|SR_RB ); \
nkeynes@736
   378
        if( sh4r.in_delay_slot ) { \
nkeynes@736
   379
            sh4r.in_delay_slot = 0; \
nkeynes@736
   380
            sh4r.spc -= 2; \
nkeynes@736
   381
        } \
nkeynes@401
   382
    } \
nkeynes@401
   383
    return TRUE; } while(0)
nkeynes@401
   384
nkeynes@401
   385
/**
nkeynes@401
   386
 * Raise a general CPU exception for the specified exception code.
nkeynes@401
   387
 * (NOT for TRAPA or TLB exceptions)
nkeynes@401
   388
 */
nkeynes@905
   389
gboolean FASTCALL sh4_raise_exception( int code )
nkeynes@401
   390
{
nkeynes@401
   391
    RAISE( code, EXV_EXCEPTION );
nkeynes@401
   392
}
nkeynes@401
   393
nkeynes@586
   394
/**
nkeynes@586
   395
 * Raise a CPU reset exception with the specified exception code.
nkeynes@586
   396
 */
nkeynes@905
   397
gboolean FASTCALL sh4_raise_reset( int code )
nkeynes@586
   398
{
nkeynes@586
   399
    // FIXME: reset modules as per "manual reset"
nkeynes@586
   400
    sh4_reset();
nkeynes@586
   401
    MMIO_WRITE(MMU,EXPEVT,code);
nkeynes@586
   402
    sh4r.vbr = 0;
nkeynes@586
   403
    sh4r.pc = 0xA0000000;
nkeynes@586
   404
    sh4r.new_pc = sh4r.pc + 2;
nkeynes@586
   405
    sh4_write_sr( (sh4r.sr|SR_MD|SR_BL|SR_RB|SR_IMASK)
nkeynes@736
   406
                  &(~SR_FD) );
nkeynes@669
   407
    return TRUE;
nkeynes@586
   408
}
nkeynes@586
   409
nkeynes@905
   410
gboolean FASTCALL sh4_raise_trap( int trap )
nkeynes@401
   411
{
nkeynes@401
   412
    MMIO_WRITE( MMU, TRA, trap<<2 );
nkeynes@586
   413
    RAISE( EXC_TRAP, EXV_EXCEPTION );
nkeynes@401
   414
}
nkeynes@401
   415
nkeynes@905
   416
gboolean FASTCALL sh4_raise_slot_exception( int normal_code, int slot_code ) {
nkeynes@401
   417
    if( sh4r.in_delay_slot ) {
nkeynes@736
   418
        return sh4_raise_exception(slot_code);
nkeynes@401
   419
    } else {
nkeynes@736
   420
        return sh4_raise_exception(normal_code);
nkeynes@401
   421
    }
nkeynes@401
   422
}
nkeynes@401
   423
nkeynes@905
   424
gboolean FASTCALL sh4_raise_tlb_exception( int code )
nkeynes@401
   425
{
nkeynes@401
   426
    RAISE( code, EXV_TLBMISS );
nkeynes@401
   427
}
nkeynes@401
   428
nkeynes@905
   429
void FASTCALL sh4_accept_interrupt( void )
nkeynes@401
   430
{
nkeynes@401
   431
    uint32_t code = intc_accept_interrupt();
nkeynes@401
   432
    sh4r.ssr = sh4_read_sr();
nkeynes@401
   433
    sh4r.spc = sh4r.pc;
nkeynes@401
   434
    sh4r.sgr = sh4r.r[15];
nkeynes@401
   435
    sh4_write_sr( sh4r.ssr|SR_BL|SR_MD|SR_RB );
nkeynes@401
   436
    MMIO_WRITE( MMU, INTEVT, code );
nkeynes@401
   437
    sh4r.pc = sh4r.vbr + 0x600;
nkeynes@401
   438
    sh4r.new_pc = sh4r.pc + 2;
nkeynes@401
   439
    //    WARN( "Accepting interrupt %03X, from %08X => %08X", code, sh4r.spc, sh4r.pc );
nkeynes@401
   440
}
nkeynes@401
   441
nkeynes@905
   442
void FASTCALL signsat48( void )
nkeynes@401
   443
{
nkeynes@401
   444
    if( ((int64_t)sh4r.mac) < (int64_t)0xFFFF800000000000LL )
nkeynes@736
   445
        sh4r.mac = 0xFFFF800000000000LL;
nkeynes@401
   446
    else if( ((int64_t)sh4r.mac) > (int64_t)0x00007FFFFFFFFFFFLL )
nkeynes@736
   447
        sh4r.mac = 0x00007FFFFFFFFFFFLL;
nkeynes@401
   448
}
nkeynes@401
   449
nkeynes@905
   450
void FASTCALL sh4_fsca( uint32_t anglei, float *fr )
nkeynes@401
   451
{
nkeynes@401
   452
    float angle = (((float)(anglei&0xFFFF))/65536.0) * 2 * M_PI;
nkeynes@401
   453
    *fr++ = cosf(angle);
nkeynes@401
   454
    *fr = sinf(angle);
nkeynes@401
   455
}
nkeynes@401
   456
nkeynes@617
   457
/**
nkeynes@617
   458
 * Enter sleep mode (eg by executing a SLEEP instruction).
nkeynes@617
   459
 * Sets sh4_state appropriately and ensures any stopping peripheral modules
nkeynes@617
   460
 * are up to date.
nkeynes@617
   461
 */
nkeynes@905
   462
void FASTCALL sh4_sleep(void)
nkeynes@401
   463
{
nkeynes@401
   464
    if( MMIO_READ( CPG, STBCR ) & 0x80 ) {
nkeynes@736
   465
        sh4r.sh4_state = SH4_STATE_STANDBY;
nkeynes@736
   466
        /* Bring all running peripheral modules up to date, and then halt them. */
nkeynes@736
   467
        TMU_run_slice( sh4r.slice_cycle );
nkeynes@736
   468
        SCIF_run_slice( sh4r.slice_cycle );
nkeynes@841
   469
        PMM_run_slice( sh4r.slice_cycle );
nkeynes@401
   470
    } else {
nkeynes@736
   471
        if( MMIO_READ( CPG, STBCR2 ) & 0x80 ) {
nkeynes@736
   472
            sh4r.sh4_state = SH4_STATE_DEEP_SLEEP;
nkeynes@736
   473
            /* Halt DMAC but other peripherals still running */
nkeynes@736
   474
nkeynes@736
   475
        } else {
nkeynes@736
   476
            sh4r.sh4_state = SH4_STATE_SLEEP;
nkeynes@736
   477
        }
nkeynes@617
   478
    }
nkeynes@740
   479
    sh4_core_exit( CORE_EXIT_SLEEP );
nkeynes@401
   480
}
nkeynes@401
   481
nkeynes@401
   482
/**
nkeynes@617
   483
 * Wakeup following sleep mode (IRQ or reset). Sets state back to running,
nkeynes@617
   484
 * and restarts any peripheral devices that were stopped.
nkeynes@617
   485
 */
nkeynes@617
   486
void sh4_wakeup(void)
nkeynes@617
   487
{
nkeynes@617
   488
    switch( sh4r.sh4_state ) {
nkeynes@617
   489
    case SH4_STATE_STANDBY:
nkeynes@736
   490
        break;
nkeynes@617
   491
    case SH4_STATE_DEEP_SLEEP:
nkeynes@736
   492
        break;
nkeynes@617
   493
    case SH4_STATE_SLEEP:
nkeynes@736
   494
        break;
nkeynes@617
   495
    }
nkeynes@617
   496
    sh4r.sh4_state = SH4_STATE_RUNNING;
nkeynes@617
   497
}
nkeynes@617
   498
nkeynes@617
   499
/**
nkeynes@617
   500
 * Run a time slice (or portion of a timeslice) while the SH4 is sleeping.
nkeynes@617
   501
 * Returns when either the SH4 wakes up (interrupt received) or the end of
nkeynes@617
   502
 * the slice is reached. Updates sh4.slice_cycle with the exit time and
nkeynes@617
   503
 * returns the same value.
nkeynes@617
   504
 */
nkeynes@617
   505
uint32_t sh4_sleep_run_slice( uint32_t nanosecs )
nkeynes@617
   506
{
nkeynes@617
   507
    int sleep_state = sh4r.sh4_state;
nkeynes@617
   508
    assert( sleep_state != SH4_STATE_RUNNING );
nkeynes@736
   509
nkeynes@617
   510
    while( sh4r.event_pending < nanosecs ) {
nkeynes@736
   511
        sh4r.slice_cycle = sh4r.event_pending;
nkeynes@736
   512
        if( sh4r.event_types & PENDING_EVENT ) {
nkeynes@736
   513
            event_execute();
nkeynes@736
   514
        }
nkeynes@736
   515
        if( sh4r.event_types & PENDING_IRQ ) {
nkeynes@736
   516
            sh4_wakeup();
nkeynes@736
   517
            return sh4r.slice_cycle;
nkeynes@736
   518
        }
nkeynes@617
   519
    }
nkeynes@617
   520
    sh4r.slice_cycle = nanosecs;
nkeynes@617
   521
    return sh4r.slice_cycle;
nkeynes@617
   522
}
nkeynes@617
   523
nkeynes@617
   524
nkeynes@617
   525
/**
nkeynes@401
   526
 * Compute the matrix tranform of fv given the matrix xf.
nkeynes@401
   527
 * Both fv and xf are word-swapped as per the sh4r.fr banks
nkeynes@401
   528
 */
nkeynes@905
   529
void FASTCALL sh4_ftrv( float *target )
nkeynes@401
   530
{
nkeynes@401
   531
    float fv[4] = { target[1], target[0], target[3], target[2] };
nkeynes@669
   532
    target[1] = sh4r.fr[1][1] * fv[0] + sh4r.fr[1][5]*fv[1] +
nkeynes@736
   533
    sh4r.fr[1][9]*fv[2] + sh4r.fr[1][13]*fv[3];
nkeynes@669
   534
    target[0] = sh4r.fr[1][0] * fv[0] + sh4r.fr[1][4]*fv[1] +
nkeynes@736
   535
    sh4r.fr[1][8]*fv[2] + sh4r.fr[1][12]*fv[3];
nkeynes@669
   536
    target[3] = sh4r.fr[1][3] * fv[0] + sh4r.fr[1][7]*fv[1] +
nkeynes@736
   537
    sh4r.fr[1][11]*fv[2] + sh4r.fr[1][15]*fv[3];
nkeynes@669
   538
    target[2] = sh4r.fr[1][2] * fv[0] + sh4r.fr[1][6]*fv[1] +
nkeynes@736
   539
    sh4r.fr[1][10]*fv[2] + sh4r.fr[1][14]*fv[3];
nkeynes@401
   540
}
nkeynes@401
   541
nkeynes@597
   542
gboolean sh4_has_page( sh4vma_t vma )
nkeynes@597
   543
{
nkeynes@597
   544
    sh4addr_t addr = mmu_vma_to_phys_disasm(vma);
nkeynes@597
   545
    return addr != MMU_VMA_ERROR && mem_has_page(addr);
nkeynes@597
   546
}
.