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