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