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