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