Search
lxdream.org :: lxdream/src/sh4/sh4.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4.c
changeset 1067:d3c00ffccfcd
prev1065:bc1cc0c54917
prev951:63483914846f
next1071:182cfe43c09e
author nkeynes
date Sun Jul 05 13:54:48 2009 +1000 (10 years ago)
permissions -rw-r--r--
last change No-op merge lxdream-mem to tip to remove head (Long since merged in
actuality)
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@998
    26
#include "cpu.h"
nkeynes@669
    27
#include "mem.h"
nkeynes@669
    28
#include "clock.h"
nkeynes@669
    29
#include "eventq.h"
nkeynes@669
    30
#include "syscall.h"
nkeynes@669
    31
#include "sh4/intc.h"
nkeynes@968
    32
#include "sh4/mmu.h"
nkeynes@378
    33
#include "sh4/sh4core.h"
nkeynes@998
    34
#include "sh4/sh4dasm.h"
nkeynes@378
    35
#include "sh4/sh4mmio.h"
nkeynes@422
    36
#include "sh4/sh4stat.h"
nkeynes@617
    37
#include "sh4/sh4trans.h"
nkeynes@991
    38
#include "xlat/xltcache.h"
nkeynes@378
    39
nkeynes@984
    40
#ifndef M_PI
nkeynes@984
    41
#define M_PI        3.14159265358979323846264338327950288
nkeynes@984
    42
#endif
nkeynes@378
    43
nkeynes@378
    44
void sh4_init( void );
nkeynes@526
    45
void sh4_xlat_init( void );
nkeynes@951
    46
void sh4_poweron_reset( void );
nkeynes@378
    47
void sh4_start( void );
nkeynes@378
    48
void sh4_stop( void );
nkeynes@378
    49
void sh4_save_state( FILE *f );
nkeynes@378
    50
int sh4_load_state( FILE *f );
nkeynes@998
    51
size_t sh4_debug_read_phys( unsigned char *buf, uint32_t addr, size_t length );
nkeynes@998
    52
size_t sh4_debug_write_phys( uint32_t addr, unsigned char *buf, size_t length );
nkeynes@998
    53
size_t sh4_debug_read_vma( unsigned char *buf, uint32_t addr, size_t length );
nkeynes@998
    54
size_t sh4_debug_write_vma( uint32_t addr, unsigned char *buf, size_t length );
nkeynes@378
    55
nkeynes@378
    56
uint32_t sh4_run_slice( uint32_t );
nkeynes@378
    57
uint32_t sh4_xlat_run_slice( uint32_t );
nkeynes@378
    58
nkeynes@998
    59
/* Note: this must match GDB's ordering */
nkeynes@998
    60
const struct reg_desc_struct sh4_reg_map[] = 
nkeynes@998
    61
  { {"R0", REG_INT, &sh4r.r[0]}, {"R1", REG_INT, &sh4r.r[1]},
nkeynes@998
    62
    {"R2", REG_INT, &sh4r.r[2]}, {"R3", REG_INT, &sh4r.r[3]},
nkeynes@998
    63
    {"R4", REG_INT, &sh4r.r[4]}, {"R5", REG_INT, &sh4r.r[5]},
nkeynes@998
    64
    {"R6", REG_INT, &sh4r.r[6]}, {"R7", REG_INT, &sh4r.r[7]},
nkeynes@998
    65
    {"R8", REG_INT, &sh4r.r[8]}, {"R9", REG_INT, &sh4r.r[9]},
nkeynes@998
    66
    {"R10",REG_INT, &sh4r.r[10]}, {"R11",REG_INT, &sh4r.r[11]},
nkeynes@998
    67
    {"R12",REG_INT, &sh4r.r[12]}, {"R13",REG_INT, &sh4r.r[13]},
nkeynes@998
    68
    {"R14",REG_INT, &sh4r.r[14]}, {"R15",REG_INT, &sh4r.r[15]},
nkeynes@998
    69
    {"PC", REG_INT, &sh4r.pc}, {"PR", REG_INT, &sh4r.pr},
nkeynes@998
    70
    {"GBR", REG_INT, &sh4r.gbr}, {"VBR",REG_INT, &sh4r.vbr}, 
nkeynes@998
    71
    {"MACH",REG_INT, ((uint32_t *)&sh4r.mac)+1}, {"MACL",REG_INT, &sh4r.mac},
nkeynes@998
    72
    {"SR", REG_INT, &sh4r.sr},
nkeynes@998
    73
    {"FPUL", REG_INT, &sh4r.fpul.i}, {"FPSCR", REG_INT, &sh4r.fpscr},
nkeynes@998
    74
    
nkeynes@998
    75
    {"FR0", REG_FLOAT, &sh4r.fr[0][1] },{"FR1", REG_FLOAT, &sh4r.fr[0][0]},
nkeynes@998
    76
    {"FR2", REG_FLOAT, &sh4r.fr[0][3] },{"FR3", REG_FLOAT, &sh4r.fr[0][2]},
nkeynes@998
    77
    {"FR4", REG_FLOAT, &sh4r.fr[0][5] },{"FR5", REG_FLOAT, &sh4r.fr[0][4]},
nkeynes@998
    78
    {"FR6", REG_FLOAT, &sh4r.fr[0][7] },{"FR7", REG_FLOAT, &sh4r.fr[0][6]},
nkeynes@998
    79
    {"FR8", REG_FLOAT, &sh4r.fr[0][9] },{"FR9", REG_FLOAT, &sh4r.fr[0][8]},
nkeynes@998
    80
    {"FR10", REG_FLOAT, &sh4r.fr[0][11] },{"FR11", REG_FLOAT, &sh4r.fr[0][10]},
nkeynes@998
    81
    {"FR12", REG_FLOAT, &sh4r.fr[0][13] },{"FR13", REG_FLOAT, &sh4r.fr[0][12]},
nkeynes@998
    82
    {"FR14", REG_FLOAT, &sh4r.fr[0][15] },{"FR15", REG_FLOAT, &sh4r.fr[0][14]},
nkeynes@378
    83
nkeynes@998
    84
    {"SSR",REG_INT, &sh4r.ssr}, {"SPC", REG_INT, &sh4r.spc},
nkeynes@998
    85
    
nkeynes@998
    86
    {"R0B0", REG_INT, NULL}, {"R1B0", REG_INT, NULL},
nkeynes@998
    87
    {"R2B0", REG_INT, NULL}, {"R3B0", REG_INT, NULL},
nkeynes@998
    88
    {"R4B0", REG_INT, NULL}, {"R5B0", REG_INT, NULL},
nkeynes@998
    89
    {"R6B0", REG_INT, NULL}, {"R7B0", REG_INT, NULL},
nkeynes@998
    90
    {"R0B1", REG_INT, NULL}, {"R1B1", REG_INT, NULL},
nkeynes@998
    91
    {"R2B1", REG_INT, NULL}, {"R3B1", REG_INT, NULL},
nkeynes@998
    92
    {"R4B1", REG_INT, NULL}, {"R5B1", REG_INT, NULL},
nkeynes@998
    93
    {"R6B1", REG_INT, NULL}, {"R7B1", REG_INT, NULL},
nkeynes@998
    94
    
nkeynes@998
    95
    {"SGR",REG_INT, &sh4r.sgr}, {"DBR", REG_INT, &sh4r.dbr},
nkeynes@998
    96
nkeynes@998
    97
    {"XF0", REG_FLOAT, &sh4r.fr[1][1] },{"XF1", REG_FLOAT, &sh4r.fr[1][0]},
nkeynes@998
    98
    {"XF2", REG_FLOAT, &sh4r.fr[1][3] },{"XF3", REG_FLOAT, &sh4r.fr[1][2]},
nkeynes@998
    99
    {"XF4", REG_FLOAT, &sh4r.fr[1][5] },{"XF5", REG_FLOAT, &sh4r.fr[1][4]},
nkeynes@998
   100
    {"XF6", REG_FLOAT, &sh4r.fr[1][7] },{"XF7", REG_FLOAT, &sh4r.fr[1][6]},
nkeynes@998
   101
    {"XF8", REG_FLOAT, &sh4r.fr[1][9] },{"XF9", REG_FLOAT, &sh4r.fr[1][8]},
nkeynes@998
   102
    {"XF10", REG_FLOAT, &sh4r.fr[1][11] },{"XF11", REG_FLOAT, &sh4r.fr[1][10]},
nkeynes@998
   103
    {"XF12", REG_FLOAT, &sh4r.fr[1][13] },{"XF13", REG_FLOAT, &sh4r.fr[1][12]},
nkeynes@998
   104
    {"XF14", REG_FLOAT, &sh4r.fr[1][15] },{"XF15", REG_FLOAT, &sh4r.fr[1][14]},
nkeynes@998
   105
    
nkeynes@998
   106
    {NULL, 0, NULL} };
nkeynes@998
   107
nkeynes@998
   108
void *sh4_get_register( int reg )
nkeynes@998
   109
{
nkeynes@998
   110
    if( reg < 0 || reg >= 94 ) {
nkeynes@998
   111
        return NULL;
nkeynes@998
   112
    } else if( reg < 43 ) {
nkeynes@998
   113
        return sh4_reg_map[reg].value;
nkeynes@998
   114
    } else if( reg < 51 ) {
nkeynes@998
   115
        /* r0b0..r7b0 */
nkeynes@998
   116
        if( (sh4r.sr & SR_MDRB) == SR_MDRB ) {
nkeynes@998
   117
            /* bank 1 is primary */
nkeynes@998
   118
            return &sh4r.r_bank[reg-43];
nkeynes@998
   119
        } else {
nkeynes@998
   120
            return &sh4r.r[reg-43];
nkeynes@998
   121
        }
nkeynes@998
   122
    } else if( reg < 59 ) {
nkeynes@998
   123
        /* r0b1..r7b1 */
nkeynes@998
   124
        if( (sh4r.sr & SR_MDRB) == SR_MDRB ) {
nkeynes@998
   125
            /* bank 1 is primary */
nkeynes@998
   126
            return &sh4r.r[reg-43];
nkeynes@998
   127
        } else {
nkeynes@998
   128
            return &sh4r.r_bank[reg-43];
nkeynes@998
   129
        }
nkeynes@998
   130
    } else {
nkeynes@998
   131
        return NULL; /* not supported at the moment */
nkeynes@998
   132
    }
nkeynes@998
   133
}
nkeynes@998
   134
nkeynes@998
   135
nkeynes@998
   136
const struct cpu_desc_struct sh4_cpu_desc = 
nkeynes@998
   137
    { "SH4", sh4_disasm_instruction, sh4_get_register, sh4_has_page,
nkeynes@998
   138
            sh4_debug_read_phys, sh4_debug_write_phys, sh4_debug_read_vma, sh4_debug_write_vma,
nkeynes@998
   139
            sh4_execute_instruction, 
nkeynes@998
   140
      sh4_set_breakpoint, sh4_clear_breakpoint, sh4_get_breakpoint, 2,
nkeynes@998
   141
      (char *)&sh4r, sizeof(sh4r), sh4_reg_map, 23, 59,
nkeynes@998
   142
      &sh4r.pc };
nkeynes@998
   143
nkeynes@951
   144
struct dreamcast_module sh4_module = { "SH4", sh4_init, sh4_poweron_reset, 
nkeynes@736
   145
        sh4_start, sh4_run_slice, sh4_stop,
nkeynes@736
   146
        sh4_save_state, sh4_load_state };
nkeynes@378
   147
nkeynes@903
   148
struct sh4_registers sh4r __attribute__((aligned(16)));
nkeynes@378
   149
struct breakpoint_struct sh4_breakpoints[MAX_BREAKPOINTS];
nkeynes@378
   150
int sh4_breakpoint_count = 0;
nkeynes@929
   151
nkeynes@591
   152
gboolean sh4_starting = FALSE;
nkeynes@526
   153
static gboolean sh4_use_translator = FALSE;
nkeynes@740
   154
static jmp_buf sh4_exit_jmp_buf;
nkeynes@740
   155
static gboolean sh4_running = FALSE;
nkeynes@586
   156
struct sh4_icache_struct sh4_icache = { NULL, -1, -1, 0 };
nkeynes@378
   157
nkeynes@740
   158
void sh4_translate_set_enabled( gboolean use )
nkeynes@378
   159
{
nkeynes@736
   160
    // No-op if the translator was not built
nkeynes@526
   161
#ifdef SH4_TRANSLATOR
nkeynes@378
   162
    if( use ) {
nkeynes@736
   163
        sh4_translate_init();
nkeynes@378
   164
    }
nkeynes@526
   165
    sh4_use_translator = use;
nkeynes@526
   166
#endif
nkeynes@378
   167
}
nkeynes@378
   168
nkeynes@740
   169
gboolean sh4_translate_is_enabled()
nkeynes@586
   170
{
nkeynes@586
   171
    return sh4_use_translator;
nkeynes@586
   172
}
nkeynes@586
   173
nkeynes@378
   174
void sh4_init(void)
nkeynes@378
   175
{
nkeynes@378
   176
    register_io_regions( mmio_list_sh4mmio );
nkeynes@939
   177
    MMU_init();
nkeynes@619
   178
    TMU_init();
nkeynes@935
   179
    xlat_cache_init();
nkeynes@951
   180
    sh4_poweron_reset();
nkeynes@671
   181
#ifdef ENABLE_SH4STATS
nkeynes@671
   182
    sh4_stats_reset();
nkeynes@671
   183
#endif
nkeynes@378
   184
}
nkeynes@378
   185
nkeynes@591
   186
void sh4_start(void)
nkeynes@591
   187
{
nkeynes@591
   188
    sh4_starting = TRUE;
nkeynes@591
   189
}
nkeynes@591
   190
nkeynes@951
   191
void sh4_poweron_reset(void)
nkeynes@378
   192
{
nkeynes@951
   193
    /* zero everything out, for the sake of having a consistent state. */
nkeynes@951
   194
    memset( &sh4r, 0, sizeof(sh4r) );
nkeynes@526
   195
    if(	sh4_use_translator ) {
nkeynes@736
   196
        xlat_flush_cache();
nkeynes@472
   197
    }
nkeynes@472
   198
nkeynes@378
   199
    /* Resume running if we were halted */
nkeynes@378
   200
    sh4r.sh4_state = SH4_STATE_RUNNING;
nkeynes@378
   201
nkeynes@378
   202
    sh4r.pc    = 0xA0000000;
nkeynes@378
   203
    sh4r.new_pc= 0xA0000002;
nkeynes@378
   204
    sh4r.vbr   = 0x00000000;
nkeynes@378
   205
    sh4r.fpscr = 0x00040001;
nkeynes@937
   206
    sh4_write_sr(0x700000F0);
nkeynes@378
   207
nkeynes@378
   208
    /* Mem reset will do this, but if we want to reset _just_ the SH4... */
nkeynes@378
   209
    MMIO_WRITE( MMU, EXPEVT, EXC_POWER_RESET );
nkeynes@378
   210
nkeynes@378
   211
    /* Peripheral modules */
nkeynes@378
   212
    CPG_reset();
nkeynes@378
   213
    INTC_reset();
nkeynes@841
   214
    PMM_reset();
nkeynes@378
   215
    TMU_reset();
nkeynes@378
   216
    SCIF_reset();
nkeynes@971
   217
    CCN_reset();
nkeynes@951
   218
    MMU_reset();
nkeynes@378
   219
}
nkeynes@378
   220
nkeynes@378
   221
void sh4_stop(void)
nkeynes@378
   222
{
nkeynes@526
   223
    if(	sh4_use_translator ) {
nkeynes@736
   224
        /* If we were running with the translator, update new_pc and in_delay_slot */
nkeynes@736
   225
        sh4r.new_pc = sh4r.pc+2;
nkeynes@736
   226
        sh4r.in_delay_slot = FALSE;
nkeynes@502
   227
    }
nkeynes@378
   228
nkeynes@378
   229
}
nkeynes@378
   230
nkeynes@740
   231
/**
nkeynes@740
   232
 * Execute a timeslice using translated code only (ie translate/execute loop)
nkeynes@740
   233
 */
nkeynes@740
   234
uint32_t sh4_run_slice( uint32_t nanosecs ) 
nkeynes@740
   235
{
nkeynes@740
   236
    sh4r.slice_cycle = 0;
nkeynes@740
   237
nkeynes@740
   238
    if( sh4r.sh4_state != SH4_STATE_RUNNING ) {
nkeynes@740
   239
        sh4_sleep_run_slice(nanosecs);
nkeynes@740
   240
    }
nkeynes@740
   241
nkeynes@740
   242
    /* Setup for sudden vm exits */
nkeynes@740
   243
    switch( setjmp(sh4_exit_jmp_buf) ) {
nkeynes@740
   244
    case CORE_EXIT_BREAKPOINT:
nkeynes@740
   245
        sh4_clear_breakpoint( sh4r.pc, BREAK_ONESHOT );
nkeynes@740
   246
        /* fallthrough */
nkeynes@740
   247
    case CORE_EXIT_HALT:
nkeynes@740
   248
        if( sh4r.sh4_state != SH4_STATE_STANDBY ) {
nkeynes@740
   249
            TMU_run_slice( sh4r.slice_cycle );
nkeynes@740
   250
            SCIF_run_slice( sh4r.slice_cycle );
nkeynes@841
   251
            PMM_run_slice( sh4r.slice_cycle );
nkeynes@740
   252
            dreamcast_stop();
nkeynes@740
   253
            return sh4r.slice_cycle;
nkeynes@740
   254
        }
nkeynes@740
   255
    case CORE_EXIT_SYSRESET:
nkeynes@740
   256
        dreamcast_reset();
nkeynes@740
   257
        break;
nkeynes@740
   258
    case CORE_EXIT_SLEEP:
nkeynes@740
   259
        sh4_sleep_run_slice(nanosecs);
nkeynes@740
   260
        break;  
nkeynes@740
   261
    case CORE_EXIT_FLUSH_ICACHE:
nkeynes@740
   262
        xlat_flush_cache();
nkeynes@740
   263
        break;
nkeynes@740
   264
    }
nkeynes@740
   265
nkeynes@740
   266
    sh4_running = TRUE;
nkeynes@740
   267
    
nkeynes@740
   268
    /* Execute the core's real slice */
nkeynes@740
   269
#ifdef SH4_TRANSLATOR
nkeynes@740
   270
    if( sh4_use_translator ) {
nkeynes@740
   271
        sh4_translate_run_slice(nanosecs);
nkeynes@740
   272
    } else {
nkeynes@740
   273
        sh4_emulate_run_slice(nanosecs);
nkeynes@740
   274
    }
nkeynes@740
   275
#else
nkeynes@740
   276
    sh4_emulate_run_slice(nanosecs);
nkeynes@740
   277
#endif
nkeynes@740
   278
    
nkeynes@740
   279
    /* And finish off the peripherals afterwards */
nkeynes@740
   280
nkeynes@740
   281
    sh4_running = FALSE;
nkeynes@740
   282
    sh4_starting = FALSE;
nkeynes@740
   283
    sh4r.slice_cycle = nanosecs;
nkeynes@740
   284
    if( sh4r.sh4_state != SH4_STATE_STANDBY ) {
nkeynes@740
   285
        TMU_run_slice( nanosecs );
nkeynes@740
   286
        SCIF_run_slice( nanosecs );
nkeynes@841
   287
        PMM_run_slice( sh4r.slice_cycle );
nkeynes@740
   288
    }
nkeynes@740
   289
    return nanosecs;   
nkeynes@740
   290
}
nkeynes@740
   291
nkeynes@740
   292
void sh4_core_exit( int exit_code )
nkeynes@740
   293
{
nkeynes@740
   294
    if( sh4_running ) {
nkeynes@740
   295
#ifdef SH4_TRANSLATOR
nkeynes@740
   296
        if( sh4_use_translator ) {
nkeynes@941
   297
            if( exit_code == CORE_EXIT_EXCEPTION ) {
nkeynes@941
   298
                sh4_translate_exception_exit_recover();
nkeynes@941
   299
            } else {
nkeynes@941
   300
                sh4_translate_exit_recover();
nkeynes@941
   301
            }
nkeynes@740
   302
        }
nkeynes@740
   303
#endif
nkeynes@971
   304
        if( exit_code != CORE_EXIT_EXCEPTION &&
nkeynes@971
   305
            exit_code != CORE_EXIT_BREAKPOINT ) {
nkeynes@948
   306
            sh4_finalize_instruction();
nkeynes@948
   307
        }
nkeynes@740
   308
        // longjmp back into sh4_run_slice
nkeynes@740
   309
        sh4_running = FALSE;
nkeynes@740
   310
        longjmp(sh4_exit_jmp_buf, exit_code);
nkeynes@740
   311
    }
nkeynes@740
   312
}
nkeynes@740
   313
nkeynes@378
   314
void sh4_save_state( FILE *f )
nkeynes@378
   315
{
nkeynes@526
   316
    if(	sh4_use_translator ) {
nkeynes@736
   317
        /* If we were running with the translator, update new_pc and in_delay_slot */
nkeynes@736
   318
        sh4r.new_pc = sh4r.pc+2;
nkeynes@736
   319
        sh4r.in_delay_slot = FALSE;
nkeynes@401
   320
    }
nkeynes@401
   321
nkeynes@936
   322
    fwrite( &sh4r, offsetof(struct sh4_registers, xlat_sh4_mode), 1, f );
nkeynes@378
   323
    MMU_save_state( f );
nkeynes@931
   324
    CCN_save_state( f );
nkeynes@841
   325
    PMM_save_state( f );
nkeynes@378
   326
    INTC_save_state( f );
nkeynes@378
   327
    TMU_save_state( f );
nkeynes@378
   328
    SCIF_save_state( f );
nkeynes@378
   329
}
nkeynes@378
   330
nkeynes@378
   331
int sh4_load_state( FILE * f )
nkeynes@378
   332
{
nkeynes@526
   333
    if(	sh4_use_translator ) {
nkeynes@736
   334
        xlat_flush_cache();
nkeynes@472
   335
    }
nkeynes@936
   336
    fread( &sh4r, offsetof(struct sh4_registers, xlat_sh4_mode), 1, f );
nkeynes@936
   337
    sh4r.xlat_sh4_mode = (sh4r.sr & SR_MD) | (sh4r.fpscr & (FPSCR_SZ|FPSCR_PR));
nkeynes@378
   338
    MMU_load_state( f );
nkeynes@931
   339
    CCN_load_state( f );
nkeynes@841
   340
    PMM_load_state( f );
nkeynes@378
   341
    INTC_load_state( f );
nkeynes@378
   342
    TMU_load_state( f );
nkeynes@378
   343
    return SCIF_load_state( f );
nkeynes@378
   344
}
nkeynes@378
   345
nkeynes@586
   346
void sh4_set_breakpoint( uint32_t pc, breakpoint_type_t type )
nkeynes@378
   347
{
nkeynes@378
   348
    sh4_breakpoints[sh4_breakpoint_count].address = pc;
nkeynes@378
   349
    sh4_breakpoints[sh4_breakpoint_count].type = type;
nkeynes@586
   350
    if( sh4_use_translator ) {
nkeynes@736
   351
        xlat_invalidate_word( pc );
nkeynes@586
   352
    }
nkeynes@378
   353
    sh4_breakpoint_count++;
nkeynes@378
   354
}
nkeynes@378
   355
nkeynes@586
   356
gboolean sh4_clear_breakpoint( uint32_t pc, breakpoint_type_t type )
nkeynes@378
   357
{
nkeynes@378
   358
    int i;
nkeynes@378
   359
nkeynes@378
   360
    for( i=0; i<sh4_breakpoint_count; i++ ) {
nkeynes@736
   361
        if( sh4_breakpoints[i].address == pc && 
nkeynes@736
   362
                sh4_breakpoints[i].type == type ) {
nkeynes@736
   363
            while( ++i < sh4_breakpoint_count ) {
nkeynes@736
   364
                sh4_breakpoints[i-1].address = sh4_breakpoints[i].address;
nkeynes@736
   365
                sh4_breakpoints[i-1].type = sh4_breakpoints[i].type;
nkeynes@736
   366
            }
nkeynes@736
   367
            if( sh4_use_translator ) {
nkeynes@736
   368
                xlat_invalidate_word( pc );
nkeynes@736
   369
            }
nkeynes@736
   370
            sh4_breakpoint_count--;
nkeynes@736
   371
            return TRUE;
nkeynes@736
   372
        }
nkeynes@378
   373
    }
nkeynes@378
   374
    return FALSE;
nkeynes@378
   375
}
nkeynes@378
   376
nkeynes@378
   377
int sh4_get_breakpoint( uint32_t pc )
nkeynes@378
   378
{
nkeynes@378
   379
    int i;
nkeynes@378
   380
    for( i=0; i<sh4_breakpoint_count; i++ ) {
nkeynes@736
   381
        if( sh4_breakpoints[i].address == pc )
nkeynes@736
   382
            return sh4_breakpoints[i].type;
nkeynes@378
   383
    }
nkeynes@378
   384
    return 0;
nkeynes@378
   385
}
nkeynes@378
   386
nkeynes@401
   387
void sh4_set_pc( int pc )
nkeynes@401
   388
{
nkeynes@401
   389
    sh4r.pc = pc;
nkeynes@401
   390
    sh4r.new_pc = pc+2;
nkeynes@401
   391
}
nkeynes@401
   392
nkeynes@401
   393
nkeynes@401
   394
/******************************* Support methods ***************************/
nkeynes@401
   395
nkeynes@401
   396
static void sh4_switch_banks( )
nkeynes@401
   397
{
nkeynes@401
   398
    uint32_t tmp[8];
nkeynes@401
   399
nkeynes@401
   400
    memcpy( tmp, sh4r.r, sizeof(uint32_t)*8 );
nkeynes@401
   401
    memcpy( sh4r.r, sh4r.r_bank, sizeof(uint32_t)*8 );
nkeynes@401
   402
    memcpy( sh4r.r_bank, tmp, sizeof(uint32_t)*8 );
nkeynes@401
   403
}
nkeynes@401
   404
nkeynes@905
   405
void FASTCALL sh4_switch_fr_banks()
nkeynes@669
   406
{
nkeynes@669
   407
    int i;
nkeynes@669
   408
    for( i=0; i<16; i++ ) {
nkeynes@736
   409
        float tmp = sh4r.fr[0][i];
nkeynes@736
   410
        sh4r.fr[0][i] = sh4r.fr[1][i];
nkeynes@736
   411
        sh4r.fr[1][i] = tmp;
nkeynes@669
   412
    }
nkeynes@669
   413
}
nkeynes@669
   414
nkeynes@905
   415
void FASTCALL sh4_write_sr( uint32_t newval )
nkeynes@401
   416
{
nkeynes@586
   417
    int oldbank = (sh4r.sr&SR_MDRB) == SR_MDRB;
nkeynes@586
   418
    int newbank = (newval&SR_MDRB) == SR_MDRB;
nkeynes@586
   419
    if( oldbank != newbank )
nkeynes@401
   420
        sh4_switch_banks();
nkeynes@822
   421
    sh4r.sr = newval & SR_MASK;
nkeynes@401
   422
    sh4r.t = (newval&SR_T) ? 1 : 0;
nkeynes@401
   423
    sh4r.s = (newval&SR_S) ? 1 : 0;
nkeynes@401
   424
    sh4r.m = (newval&SR_M) ? 1 : 0;
nkeynes@401
   425
    sh4r.q = (newval&SR_Q) ? 1 : 0;
nkeynes@936
   426
    sh4r.xlat_sh4_mode = (sh4r.sr & SR_MD) | (sh4r.fpscr & (FPSCR_SZ|FPSCR_PR));
nkeynes@401
   427
    intc_mask_changed();
nkeynes@401
   428
}
nkeynes@401
   429
nkeynes@905
   430
void FASTCALL sh4_write_fpscr( uint32_t newval )
nkeynes@669
   431
{
nkeynes@669
   432
    if( (sh4r.fpscr ^ newval) & FPSCR_FR ) {
nkeynes@736
   433
        sh4_switch_fr_banks();
nkeynes@669
   434
    }
nkeynes@823
   435
    sh4r.fpscr = newval & FPSCR_MASK;
nkeynes@936
   436
    sh4r.xlat_sh4_mode = (sh4r.sr & SR_MD) | (sh4r.fpscr & (FPSCR_SZ|FPSCR_PR));
nkeynes@669
   437
}
nkeynes@669
   438
nkeynes@905
   439
uint32_t FASTCALL sh4_read_sr( void )
nkeynes@401
   440
{
nkeynes@401
   441
    /* synchronize sh4r.sr with the various bitflags */
nkeynes@401
   442
    sh4r.sr &= SR_MQSTMASK;
nkeynes@401
   443
    if( sh4r.t ) sh4r.sr |= SR_T;
nkeynes@401
   444
    if( sh4r.s ) sh4r.sr |= SR_S;
nkeynes@401
   445
    if( sh4r.m ) sh4r.sr |= SR_M;
nkeynes@401
   446
    if( sh4r.q ) sh4r.sr |= SR_Q;
nkeynes@401
   447
    return sh4r.sr;
nkeynes@401
   448
}
nkeynes@401
   449
nkeynes@951
   450
/**
nkeynes@951
   451
 * Raise a CPU reset exception with the specified exception code.
nkeynes@951
   452
 */
nkeynes@951
   453
void FASTCALL sh4_raise_reset( int code )
nkeynes@951
   454
{
nkeynes@951
   455
    MMIO_WRITE(MMU,EXPEVT,code);
nkeynes@951
   456
    sh4r.vbr = 0x00000000;
nkeynes@951
   457
    sh4r.pc = 0xA0000000;
nkeynes@951
   458
    sh4r.new_pc = sh4r.pc + 2;
nkeynes@951
   459
    sh4r.in_delay_slot = 0;
nkeynes@951
   460
    sh4_write_sr( (sh4r.sr|SR_MD|SR_BL|SR_RB|SR_IMASK)&(~SR_FD) );
nkeynes@951
   461
    
nkeynes@951
   462
    /* Peripheral manual reset (FIXME: incomplete) */
nkeynes@951
   463
    INTC_reset();
nkeynes@951
   464
    SCIF_reset();
nkeynes@951
   465
    MMU_reset();
nkeynes@951
   466
}
nkeynes@401
   467
nkeynes@951
   468
void FASTCALL sh4_raise_tlb_multihit( sh4vma_t vpn )
nkeynes@951
   469
{
nkeynes@951
   470
    MMIO_WRITE( MMU, TEA, vpn );
nkeynes@951
   471
    MMIO_WRITE( MMU, PTEH, ((MMIO_READ(MMU, PTEH) & 0x000003FF) | (vpn&0xFFFFFC00)) );
nkeynes@951
   472
    sh4_raise_reset( EXC_TLB_MULTI_HIT );
nkeynes@951
   473
}
nkeynes@401
   474
nkeynes@401
   475
/**
nkeynes@401
   476
 * Raise a general CPU exception for the specified exception code.
nkeynes@401
   477
 * (NOT for TRAPA or TLB exceptions)
nkeynes@401
   478
 */
nkeynes@951
   479
void FASTCALL sh4_raise_exception( int code )
nkeynes@401
   480
{
nkeynes@951
   481
    if( sh4r.sr & SR_BL ) {
nkeynes@951
   482
        sh4_raise_reset( EXC_MANUAL_RESET );
nkeynes@401
   483
    } else {
nkeynes@951
   484
        sh4r.spc = sh4r.pc;
nkeynes@951
   485
        sh4r.ssr = sh4_read_sr();
nkeynes@951
   486
        sh4r.sgr = sh4r.r[15];
nkeynes@951
   487
        MMIO_WRITE(MMU,EXPEVT, code);
nkeynes@951
   488
        sh4r.pc = sh4r.vbr + EXV_EXCEPTION;
nkeynes@951
   489
        sh4r.new_pc = sh4r.pc + 2;
nkeynes@951
   490
        sh4_write_sr( sh4r.ssr |SR_MD|SR_BL|SR_RB );
nkeynes@951
   491
        sh4r.in_delay_slot = 0;
nkeynes@401
   492
    }
nkeynes@401
   493
}
nkeynes@401
   494
nkeynes@951
   495
void FASTCALL sh4_raise_trap( int trap )
nkeynes@401
   496
{
nkeynes@951
   497
    MMIO_WRITE( MMU, TRA, trap<<2 );
nkeynes@951
   498
    MMIO_WRITE( MMU, EXPEVT, EXC_TRAP );
nkeynes@951
   499
    sh4r.spc = sh4r.pc;
nkeynes@951
   500
    sh4r.ssr = sh4_read_sr();
nkeynes@951
   501
    sh4r.sgr = sh4r.r[15];
nkeynes@951
   502
    sh4r.pc = sh4r.vbr + EXV_EXCEPTION;
nkeynes@951
   503
    sh4r.new_pc = sh4r.pc + 2;
nkeynes@951
   504
    sh4_write_sr( sh4r.ssr |SR_MD|SR_BL|SR_RB );
nkeynes@951
   505
    sh4r.in_delay_slot = 0;
nkeynes@951
   506
}
nkeynes@951
   507
nkeynes@951
   508
void FASTCALL sh4_raise_tlb_exception( int code, sh4vma_t vpn )
nkeynes@951
   509
{
nkeynes@951
   510
    MMIO_WRITE( MMU, TEA, vpn );
nkeynes@951
   511
    MMIO_WRITE( MMU, PTEH, ((MMIO_READ(MMU, PTEH) & 0x000003FF) | (vpn&0xFFFFFC00)) );
nkeynes@951
   512
    MMIO_WRITE( MMU, EXPEVT, code );
nkeynes@951
   513
    sh4r.spc = sh4r.pc;
nkeynes@951
   514
    sh4r.ssr = sh4_read_sr();
nkeynes@951
   515
    sh4r.sgr = sh4r.r[15];
nkeynes@951
   516
    sh4r.pc = sh4r.vbr + EXV_TLBMISS;
nkeynes@951
   517
    sh4r.new_pc = sh4r.pc + 2;
nkeynes@951
   518
    sh4_write_sr( sh4r.ssr |SR_MD|SR_BL|SR_RB );
nkeynes@951
   519
    sh4r.in_delay_slot = 0;
nkeynes@401
   520
}
nkeynes@401
   521
nkeynes@905
   522
void FASTCALL sh4_accept_interrupt( void )
nkeynes@401
   523
{
nkeynes@401
   524
    uint32_t code = intc_accept_interrupt();
nkeynes@951
   525
    MMIO_WRITE( MMU, INTEVT, code );
nkeynes@401
   526
    sh4r.ssr = sh4_read_sr();
nkeynes@401
   527
    sh4r.spc = sh4r.pc;
nkeynes@401
   528
    sh4r.sgr = sh4r.r[15];
nkeynes@401
   529
    sh4_write_sr( sh4r.ssr|SR_BL|SR_MD|SR_RB );
nkeynes@401
   530
    sh4r.pc = sh4r.vbr + 0x600;
nkeynes@401
   531
    sh4r.new_pc = sh4r.pc + 2;
nkeynes@975
   532
    sh4r.in_delay_slot = 0;
nkeynes@401
   533
}
nkeynes@401
   534
nkeynes@905
   535
void FASTCALL signsat48( void )
nkeynes@401
   536
{
nkeynes@401
   537
    if( ((int64_t)sh4r.mac) < (int64_t)0xFFFF800000000000LL )
nkeynes@736
   538
        sh4r.mac = 0xFFFF800000000000LL;
nkeynes@401
   539
    else if( ((int64_t)sh4r.mac) > (int64_t)0x00007FFFFFFFFFFFLL )
nkeynes@736
   540
        sh4r.mac = 0x00007FFFFFFFFFFFLL;
nkeynes@401
   541
}
nkeynes@401
   542
nkeynes@905
   543
void FASTCALL sh4_fsca( uint32_t anglei, float *fr )
nkeynes@401
   544
{
nkeynes@401
   545
    float angle = (((float)(anglei&0xFFFF))/65536.0) * 2 * M_PI;
nkeynes@401
   546
    *fr++ = cosf(angle);
nkeynes@401
   547
    *fr = sinf(angle);
nkeynes@401
   548
}
nkeynes@401
   549
nkeynes@617
   550
/**
nkeynes@617
   551
 * Enter sleep mode (eg by executing a SLEEP instruction).
nkeynes@617
   552
 * Sets sh4_state appropriately and ensures any stopping peripheral modules
nkeynes@617
   553
 * are up to date.
nkeynes@617
   554
 */
nkeynes@905
   555
void FASTCALL sh4_sleep(void)
nkeynes@401
   556
{
nkeynes@401
   557
    if( MMIO_READ( CPG, STBCR ) & 0x80 ) {
nkeynes@736
   558
        sh4r.sh4_state = SH4_STATE_STANDBY;
nkeynes@736
   559
        /* Bring all running peripheral modules up to date, and then halt them. */
nkeynes@736
   560
        TMU_run_slice( sh4r.slice_cycle );
nkeynes@736
   561
        SCIF_run_slice( sh4r.slice_cycle );
nkeynes@841
   562
        PMM_run_slice( sh4r.slice_cycle );
nkeynes@401
   563
    } else {
nkeynes@736
   564
        if( MMIO_READ( CPG, STBCR2 ) & 0x80 ) {
nkeynes@736
   565
            sh4r.sh4_state = SH4_STATE_DEEP_SLEEP;
nkeynes@736
   566
            /* Halt DMAC but other peripherals still running */
nkeynes@736
   567
nkeynes@736
   568
        } else {
nkeynes@736
   569
            sh4r.sh4_state = SH4_STATE_SLEEP;
nkeynes@736
   570
        }
nkeynes@617
   571
    }
nkeynes@740
   572
    sh4_core_exit( CORE_EXIT_SLEEP );
nkeynes@401
   573
}
nkeynes@401
   574
nkeynes@401
   575
/**
nkeynes@617
   576
 * Wakeup following sleep mode (IRQ or reset). Sets state back to running,
nkeynes@617
   577
 * and restarts any peripheral devices that were stopped.
nkeynes@617
   578
 */
nkeynes@617
   579
void sh4_wakeup(void)
nkeynes@617
   580
{
nkeynes@617
   581
    switch( sh4r.sh4_state ) {
nkeynes@617
   582
    case SH4_STATE_STANDBY:
nkeynes@736
   583
        break;
nkeynes@617
   584
    case SH4_STATE_DEEP_SLEEP:
nkeynes@736
   585
        break;
nkeynes@617
   586
    case SH4_STATE_SLEEP:
nkeynes@736
   587
        break;
nkeynes@617
   588
    }
nkeynes@617
   589
    sh4r.sh4_state = SH4_STATE_RUNNING;
nkeynes@617
   590
}
nkeynes@617
   591
nkeynes@617
   592
/**
nkeynes@617
   593
 * Run a time slice (or portion of a timeslice) while the SH4 is sleeping.
nkeynes@617
   594
 * Returns when either the SH4 wakes up (interrupt received) or the end of
nkeynes@617
   595
 * the slice is reached. Updates sh4.slice_cycle with the exit time and
nkeynes@617
   596
 * returns the same value.
nkeynes@617
   597
 */
nkeynes@617
   598
uint32_t sh4_sleep_run_slice( uint32_t nanosecs )
nkeynes@617
   599
{
nkeynes@617
   600
    int sleep_state = sh4r.sh4_state;
nkeynes@617
   601
    assert( sleep_state != SH4_STATE_RUNNING );
nkeynes@736
   602
nkeynes@617
   603
    while( sh4r.event_pending < nanosecs ) {
nkeynes@736
   604
        sh4r.slice_cycle = sh4r.event_pending;
nkeynes@736
   605
        if( sh4r.event_types & PENDING_EVENT ) {
nkeynes@736
   606
            event_execute();
nkeynes@736
   607
        }
nkeynes@736
   608
        if( sh4r.event_types & PENDING_IRQ ) {
nkeynes@736
   609
            sh4_wakeup();
nkeynes@736
   610
            return sh4r.slice_cycle;
nkeynes@736
   611
        }
nkeynes@617
   612
    }
nkeynes@617
   613
    sh4r.slice_cycle = nanosecs;
nkeynes@617
   614
    return sh4r.slice_cycle;
nkeynes@617
   615
}
nkeynes@617
   616
nkeynes@617
   617
nkeynes@617
   618
/**
nkeynes@401
   619
 * Compute the matrix tranform of fv given the matrix xf.
nkeynes@401
   620
 * Both fv and xf are word-swapped as per the sh4r.fr banks
nkeynes@401
   621
 */
nkeynes@905
   622
void FASTCALL sh4_ftrv( float *target )
nkeynes@401
   623
{
nkeynes@401
   624
    float fv[4] = { target[1], target[0], target[3], target[2] };
nkeynes@669
   625
    target[1] = sh4r.fr[1][1] * fv[0] + sh4r.fr[1][5]*fv[1] +
nkeynes@736
   626
    sh4r.fr[1][9]*fv[2] + sh4r.fr[1][13]*fv[3];
nkeynes@669
   627
    target[0] = sh4r.fr[1][0] * fv[0] + sh4r.fr[1][4]*fv[1] +
nkeynes@736
   628
    sh4r.fr[1][8]*fv[2] + sh4r.fr[1][12]*fv[3];
nkeynes@669
   629
    target[3] = sh4r.fr[1][3] * fv[0] + sh4r.fr[1][7]*fv[1] +
nkeynes@736
   630
    sh4r.fr[1][11]*fv[2] + sh4r.fr[1][15]*fv[3];
nkeynes@669
   631
    target[2] = sh4r.fr[1][2] * fv[0] + sh4r.fr[1][6]*fv[1] +
nkeynes@736
   632
    sh4r.fr[1][10]*fv[2] + sh4r.fr[1][14]*fv[3];
nkeynes@401
   633
}
nkeynes@401
   634
nkeynes@597
   635
gboolean sh4_has_page( sh4vma_t vma )
nkeynes@597
   636
{
nkeynes@597
   637
    sh4addr_t addr = mmu_vma_to_phys_disasm(vma);
nkeynes@597
   638
    return addr != MMU_VMA_ERROR && mem_has_page(addr);
nkeynes@597
   639
}
nkeynes@998
   640
nkeynes@998
   641
/**
nkeynes@998
   642
 * Go through ext_address_space page by page
nkeynes@998
   643
 */
nkeynes@998
   644
size_t sh4_debug_read_phys( unsigned char *buf, uint32_t addr, size_t length )
nkeynes@998
   645
{
nkeynes@998
   646
    /* Quick and very dirty */
nkeynes@998
   647
    unsigned char *region = mem_get_region(addr);
nkeynes@998
   648
    if( region == NULL ) {
nkeynes@998
   649
        memset( buf, 0, length );
nkeynes@998
   650
    } else {
nkeynes@998
   651
        memcpy( buf, region, length );
nkeynes@998
   652
    }
nkeynes@998
   653
    return length;
nkeynes@998
   654
}
nkeynes@998
   655
nkeynes@998
   656
size_t sh4_debug_write_phys( uint32_t addr, unsigned char *buf, size_t length )
nkeynes@998
   657
{
nkeynes@998
   658
    unsigned char *region = mem_get_region(addr);
nkeynes@998
   659
    if( region != NULL ) {
nkeynes@998
   660
        memcpy( region, buf, length );
nkeynes@998
   661
    }
nkeynes@998
   662
    return length;
nkeynes@998
   663
}
nkeynes@998
   664
nkeynes@998
   665
/**
nkeynes@998
   666
 * Read virtual memory - for now just go 1K at a time 
nkeynes@998
   667
 */
nkeynes@998
   668
size_t sh4_debug_read_vma( unsigned char *buf, uint32_t addr, size_t length )
nkeynes@998
   669
{
nkeynes@998
   670
    if( IS_TLB_ENABLED() ) {
nkeynes@998
   671
        size_t read_len = 0;
nkeynes@998
   672
        while( length > 0 ) {
nkeynes@998
   673
            sh4addr_t phys = mmu_vma_to_phys_disasm(addr);
nkeynes@998
   674
            if( phys == MMU_VMA_ERROR )
nkeynes@998
   675
                break;
nkeynes@998
   676
            int next_len = 1024 - (phys&0x000003FF);
nkeynes@998
   677
            if( next_len >= length ) {
nkeynes@998
   678
                next_len = length;
nkeynes@998
   679
            }
nkeynes@998
   680
            sh4_debug_read_phys( buf, phys, length );
nkeynes@998
   681
            buf += next_len;
nkeynes@998
   682
            addr += next_len;
nkeynes@998
   683
            read_len += next_len; 
nkeynes@998
   684
            length -= next_len;
nkeynes@998
   685
        }
nkeynes@998
   686
        return read_len;
nkeynes@998
   687
    } else {
nkeynes@998
   688
        return sh4_debug_read_phys( buf, addr, length );
nkeynes@998
   689
    }
nkeynes@998
   690
}
nkeynes@998
   691
nkeynes@998
   692
size_t sh4_debug_write_vma( uint32_t addr, unsigned char *buf, size_t length )
nkeynes@998
   693
{
nkeynes@998
   694
    if( IS_TLB_ENABLED() ) {
nkeynes@998
   695
        size_t read_len = 0;
nkeynes@998
   696
        while( length > 0 ) {
nkeynes@998
   697
            sh4addr_t phys = mmu_vma_to_phys_disasm(addr);
nkeynes@998
   698
            if( phys == MMU_VMA_ERROR )
nkeynes@998
   699
                break;
nkeynes@998
   700
            int next_len = 1024 - (phys&0x000003FF);
nkeynes@998
   701
            if( next_len >= length ) {
nkeynes@998
   702
                next_len = length;
nkeynes@998
   703
            }
nkeynes@998
   704
            sh4_debug_write_phys( phys, buf, length );
nkeynes@998
   705
            buf += next_len;
nkeynes@998
   706
            addr += next_len;
nkeynes@998
   707
            read_len += next_len; 
nkeynes@998
   708
            length -= next_len;
nkeynes@998
   709
        }
nkeynes@998
   710
    } else {
nkeynes@998
   711
        return sh4_debug_write_phys( addr, buf, length );
nkeynes@998
   712
    }
nkeynes@998
   713
}
.