# HG changeset patch # User nkeynes # Date 1135338295 0 # Node ID 1ec3acd0594df7e88e8469a11e0329403e7edeef # Parent f0703013049f15ae3d5c3988cf338d758d761064 Start of "real" time slices, general structure in place now --- a/src/Makefile.am Thu Dec 22 13:57:26 2005 +0000 +++ b/src/Makefile.am Fri Dec 23 11:44:55 2005 +0000 @@ -18,7 +18,7 @@ asic.c asic.h pvr2.c pvr2.h ide.c ide.h \ video.c dreamcast.c dreamcast.h \ maple.c maple.h maple/controller.c maple/controller.h \ - sh4/intc.c sh4/intc.h sh4/sh4mem.c \ + sh4/intc.c sh4/intc.h sh4/sh4mem.c sh4/timer.c \ sh4/sh4core.c sh4/sh4core.h sh4/sh4dasm.c sh4/sh4dasm.h \ sh4/sh4mmio.c sh4/sh4mmio.h sh4/scif.c sh4/watch.c \ aica/armcore.c aica/armcore.h aica/armdasm.c aica/armmem.c \ --- a/src/Makefile.in Thu Dec 22 13:57:26 2005 +0000 +++ b/src/Makefile.in Fri Dec 23 11:44:55 2005 +0000 @@ -145,7 +145,7 @@ asic.c asic.h pvr2.c pvr2.h ide.c ide.h \ video.c dreamcast.c dreamcast.h \ maple.c maple.h maple/controller.c maple/controller.h \ - sh4/intc.c sh4/intc.h sh4/sh4mem.c \ + sh4/intc.c sh4/intc.h sh4/sh4mem.c sh4/timer.c \ sh4/sh4core.c sh4/sh4core.h sh4/sh4dasm.c sh4/sh4dasm.h \ sh4/sh4mmio.c sh4/sh4mmio.h sh4/scif.c sh4/watch.c \ aica/armcore.c aica/armcore.h aica/armdasm.c aica/armmem.c \ @@ -169,11 +169,11 @@ debug_win.$(OBJEXT) dump_win.$(OBJEXT) mem.$(OBJEXT) \ asic.$(OBJEXT) pvr2.$(OBJEXT) ide.$(OBJEXT) video.$(OBJEXT) \ dreamcast.$(OBJEXT) maple.$(OBJEXT) controller.$(OBJEXT) \ - intc.$(OBJEXT) sh4mem.$(OBJEXT) sh4core.$(OBJEXT) \ - sh4dasm.$(OBJEXT) sh4mmio.$(OBJEXT) scif.$(OBJEXT) \ - watch.$(OBJEXT) armcore.$(OBJEXT) armdasm.$(OBJEXT) \ - armmem.$(OBJEXT) aica.$(OBJEXT) fileio.$(OBJEXT) \ - ipbin.$(OBJEXT) util.$(OBJEXT) + intc.$(OBJEXT) sh4mem.$(OBJEXT) timer.$(OBJEXT) \ + sh4core.$(OBJEXT) sh4dasm.$(OBJEXT) sh4mmio.$(OBJEXT) \ + scif.$(OBJEXT) watch.$(OBJEXT) armcore.$(OBJEXT) \ + armdasm.$(OBJEXT) armmem.$(OBJEXT) aica.$(OBJEXT) \ + fileio.$(OBJEXT) ipbin.$(OBJEXT) util.$(OBJEXT) dream_OBJECTS = $(am_dream_OBJECTS) dream_DEPENDENCIES = dream_LDFLAGS = @@ -194,8 +194,9 @@ @AMDEP_TRUE@ ./$(DEPDIR)/pvr2.Po ./$(DEPDIR)/scif.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/sh4core.Po ./$(DEPDIR)/sh4dasm.Po \ @AMDEP_TRUE@ ./$(DEPDIR)/sh4mem.Po ./$(DEPDIR)/sh4mmio.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/support.Po ./$(DEPDIR)/util.Po \ -@AMDEP_TRUE@ ./$(DEPDIR)/video.Po ./$(DEPDIR)/watch.Po +@AMDEP_TRUE@ ./$(DEPDIR)/support.Po ./$(DEPDIR)/timer.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/util.Po ./$(DEPDIR)/video.Po \ +@AMDEP_TRUE@ ./$(DEPDIR)/watch.Po COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) @@ -274,6 +275,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sh4mem.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sh4mmio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/support.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/video.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watch.Po@am__quote@ @@ -366,6 +368,28 @@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o sh4mem.obj `if test -f 'sh4/sh4mem.c'; then $(CYGPATH_W) 'sh4/sh4mem.c'; else $(CYGPATH_W) '$(srcdir)/sh4/sh4mem.c'; fi` +timer.o: sh4/timer.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT timer.o -MD -MP -MF "$(DEPDIR)/timer.Tpo" \ +@am__fastdepCC_TRUE@ -c -o timer.o `test -f 'sh4/timer.c' || echo '$(srcdir)/'`sh4/timer.c; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/timer.Tpo" "$(DEPDIR)/timer.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/timer.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sh4/timer.c' object='timer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/timer.Po' tmpdepfile='$(DEPDIR)/timer.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o timer.o `test -f 'sh4/timer.c' || echo '$(srcdir)/'`sh4/timer.c + +timer.obj: sh4/timer.c +@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT timer.obj -MD -MP -MF "$(DEPDIR)/timer.Tpo" \ +@am__fastdepCC_TRUE@ -c -o timer.obj `if test -f 'sh4/timer.c'; then $(CYGPATH_W) 'sh4/timer.c'; else $(CYGPATH_W) '$(srcdir)/sh4/timer.c'; fi`; \ +@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/timer.Tpo" "$(DEPDIR)/timer.Po"; \ +@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/timer.Tpo"; exit 1; \ +@am__fastdepCC_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sh4/timer.c' object='timer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/timer.Po' tmpdepfile='$(DEPDIR)/timer.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o timer.obj `if test -f 'sh4/timer.c'; then $(CYGPATH_W) 'sh4/timer.c'; else $(CYGPATH_W) '$(srcdir)/sh4/timer.c'; fi` + sh4core.o: sh4/sh4core.c @am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT sh4core.o -MD -MP -MF "$(DEPDIR)/sh4core.Tpo" \ @am__fastdepCC_TRUE@ -c -o sh4core.o `test -f 'sh4/sh4core.c' || echo '$(srcdir)/'`sh4/sh4core.c; \ --- a/src/aica/aica.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/aica/aica.c Fri Dec 23 11:44:55 2005 +0000 @@ -1,5 +1,5 @@ /** - * $Id: aica.c,v 1.3 2005-12-13 12:17:26 nkeynes Exp $ + * $Id: aica.c,v 1.4 2005-12-23 11:44:55 nkeynes Exp $ * * This is the core sound system (ie the bit which does the actual work) * @@ -27,8 +27,16 @@ MMIO_REGION_READ_DEFFN( AICA1 ) MMIO_REGION_READ_DEFFN( AICA2 ) -struct dreamcast_module aica_module = { "AICA", aica_init, aica_reset, NULL, NULL, - NULL, NULL }; +void aica_init( void ); +void aica_reset( void ); +void aica_start( void ); +void aica_stop( void ); +void aica_run_slice( int ); + + +struct dreamcast_module aica_module = { "AICA", aica_init, aica_reset, + aica_start, aica_run_slice, aica_stop, + NULL, NULL, NULL }; /** * Initialize the AICA subsystem. Note requires that @@ -46,6 +54,22 @@ } +void aica_start( void ) +{ + +} + +void aica_run_slice( int microsecs ) +{ + /* Run arm instructions */ + /* Generate audio buffer */ +} + +void aica_stop( void ) +{ + +} + /** Channel register structure: * 00 * 04 --- a/src/asic.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/asic.c Fri Dec 23 11:44:55 2005 +0000 @@ -20,7 +20,7 @@ */ struct dreamcast_module asic_module = { "ASIC", asic_init, NULL, NULL, NULL, - NULL, NULL }; + NULL, NULL, NULL }; void asic_check_cleared_events( void ); --- a/src/clock.h Thu Dec 22 13:57:26 2005 +0000 +++ b/src/clock.h Fri Dec 23 11:44:55 2005 +0000 @@ -1,5 +1,5 @@ /** - * $Id: clock.h,v 1.1 2005-12-22 07:38:06 nkeynes Exp $ + * $Id: clock.h,v 1.2 2005-12-23 11:44:50 nkeynes Exp $ * External interface to the dreamcast serial port, implemented by * sh4/scif.c * @@ -24,15 +24,14 @@ extern "C" { #endif -#define MHZ * 1000000 - +#define MHZ #define SH4_BASE_RATE 200 MHZ #define ARM_BASE_RATE 33 MHZ - extern uint32_t sh4_freq; - extern uint32_t sh4_peripheral_freq; - extern uint32_t sh4_bus_freq; - extern uint32_t arm_freq; +extern uint32_t sh4_freq; +extern uint32_t sh4_peripheral_freq; +extern uint32_t sh4_bus_freq; +extern uint32_t arm_freq; #ifdef __cplusplus } --- a/src/dreamcast.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/dreamcast.c Fri Dec 23 11:44:55 2005 +0000 @@ -16,6 +16,13 @@ static char *dreamcast_config = "DEFAULT"; dreamcast_module_t modules[MAX_MODULES]; +struct save_state_header { + char magic[16]; + uint32_t version; + uint32_t module_count; +}; + + /** * This function is responsible for defining how all the pieces of the * dreamcast actually fit together. Among other things, this lets us @@ -64,6 +71,7 @@ void dreamcast_init( void ) { dreamcast_configure(); + dreamcast_state = STATE_STOPPED; } void dreamcast_reset( void ) @@ -75,29 +83,37 @@ } } -void dreamcast_start( void ) +void dreamcast_run( void ) { int i; - for( i=0; istart != NULL ) - modules[i]->start(); + if( dreamcast_state != STATE_RUNNING ) { + for( i=0; istart != NULL ) + modules[i]->start(); + } } -} -void dreamcast_stop( void ) -{ - int i; + dreamcast_state = STATE_RUNNING; + while( dreamcast_state == STATE_RUNNING ) { + for( i=0; irun_time_slice != NULL ) + modules[i]->run_time_slice( TIMESLICE_LENGTH ); + } + + } + for( i=0; istop != NULL ) modules[i]->stop(); } + dreamcast_state = STATE_STOPPED; + update_gui(); } -struct save_state_header { - char magic[16]; - uint32_t version; - uint32_t module_count; -}; - +void dreamcast_stop( void ) +{ + if( dreamcast_state == STATE_RUNNING ) + dreamcast_state = STATE_STOPPING; +} int dreamcast_load_state( const gchar *filename ) { --- a/src/dreamcast.h Thu Dec 22 13:57:26 2005 +0000 +++ b/src/dreamcast.h Fri Dec 23 11:44:55 2005 +0000 @@ -10,13 +10,20 @@ extern "C" { #endif +#define DREAMCAST_SAVE_MAGIC "%!-DreamOn!Save\0" +#define DREAMCAST_SAVE_VERSION 0x00010000 + +#define TIMESLICE_LENGTH 1000 /* microseconds */ + +#define STATE_RUNNING 1 +#define STATE_STOPPING 2 +#define STATE_STOPPED 3 + void dreamcast_init(void); void dreamcast_reset(void); +void dreamcast_run(void); void dreamcast_stop(void); -#define DREAMCAST_SAVE_MAGIC "%!-DreamOn!Save\0" -#define DREAMCAST_SAVE_VERSION 0x00010000 - int dreamcast_save_state( const gchar *filename ); int dreamcast_load_state( const gchar *filename ); --- a/src/gdrom/ide.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/gdrom/ide.c Fri Dec 23 11:44:55 2005 +0000 @@ -14,7 +14,7 @@ void ide_init( void ); struct dreamcast_module ide_module = { "IDE", ide_init, ide_reset, NULL, NULL, - NULL, NULL }; + NULL, NULL, NULL }; struct ide_registers idereg; --- a/src/gui/callbacks.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/gui/callbacks.c Fri Dec 23 11:44:55 2005 +0000 @@ -107,29 +107,12 @@ } -void run( debug_info_t data, uint32_t target ) { - if( ! sh4_isrunning() ) { - do { - if( target == -1 ) - sh4_runfor(1000000); - else - sh4_runto(target, 1000000); - update_icount(data); - run_timers(1000000); - SCIF_clock_tick(); - while( gtk_events_pending() ) - gtk_main_iteration(); - pvr2_next_frame(); - } while( sh4_isrunning() ); - update_gui(); - } -} void on_run_btn_clicked (GtkButton *button, gpointer user_data) { debug_info_t data = get_debug_info(GTK_WIDGET(button)); - run(data,-1); + dreamcast_run(); } @@ -142,7 +125,8 @@ WARN( "No address selected, so can't run to it", NULL ); else { INFO( "Running until %08X...", selected_pc ); - run( data, selected_pc ); + sh4_set_breakpoint( selected_pc, BREAK_ONESHOT ); + dreamcast_run(); } } --- a/src/gui/gui.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/gui/gui.c Fri Dec 23 11:44:55 2005 +0000 @@ -43,6 +43,13 @@ fixed_list_font = pango_font_description_from_string("Courier 10"); } +void gui_run_slice( int millisecs ) +{ + while( gtk_events_pending() ) + gtk_main_iteration(); + update_icount(main_debug); +} + void update_gui(void) { update_registers(main_debug); update_icount(main_debug); --- a/src/maple/maple.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/maple/maple.c Fri Dec 23 11:44:55 2005 +0000 @@ -8,7 +8,7 @@ void maple_init( void ); struct dreamcast_module maple_module = { "Maple", maple_init, NULL, NULL, NULL, - NULL, NULL }; + NULL, NULL, NULL }; void maple_init( void ) { --- a/src/mem.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/mem.c Fri Dec 23 11:44:55 2005 +0000 @@ -1,5 +1,5 @@ /** - * $Id: mem.c,v 1.6 2005-12-22 07:38:06 nkeynes Exp $ + * $Id: mem.c,v 1.7 2005-12-23 11:44:51 nkeynes Exp $ * mem.c is responsible for creating and maintaining the overall system memory * map, as visible from the SH4 processor. * @@ -38,7 +38,7 @@ int mem_load(FILE *f); void mem_save(FILE *f); struct dreamcast_module mem_module = - { "MEM", mem_init, mem_reset, NULL, NULL, mem_save, mem_load }; + { "MEM", mem_init, mem_reset, NULL, NULL, NULL, mem_save, mem_load }; struct mem_region mem_rgn[MAX_MEM_REGIONS]; struct mmio_region *io_rgn[MAX_IO_REGIONS]; --- a/src/modules.h Thu Dec 22 13:57:26 2005 +0000 +++ b/src/modules.h Fri Dec 23 11:44:55 2005 +0000 @@ -30,6 +30,11 @@ */ void (*start)(); /** + * Execute one time-slice worth of operations, for the given number of + * micro-seconds. + */ + void (*run_time_slice)( int microsecs ); + /** * Set the module into a stopped state (may be NULL) */ void (*stop)(); --- a/src/pvr2/pvr2.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/pvr2/pvr2.c Fri Dec 23 11:44:55 2005 +0000 @@ -10,8 +10,11 @@ char *video_base; void pvr2_init( void ); +void pvr2_run_slice( int ); +void pvr2_next_frame( void ); -struct dreamcast_module pvr2_module = { "PVR2", pvr2_init, NULL, NULL, NULL, +struct dreamcast_module pvr2_module = { "PVR2", pvr2_init, NULL, NULL, + pvr2_run_slice, NULL, NULL, NULL }; void pvr2_init( void ) @@ -20,6 +23,18 @@ video_base = mem_get_region_by_name( MEM_REGION_VIDEO ); } +uint32_t pvr2_time_counter = 0; +uint32_t pvr2_time_per_frame = 20000; + +void pvr2_run_slice( int microsecs ) +{ + pvr2_time_counter += microsecs; + if( pvr2_time_counter >= pvr2_time_per_frame ) { + pvr2_next_frame(); + pvr2_time_counter -= pvr2_time_per_frame; + } +} + uint32_t vid_stride, vid_lpf, vid_ppl, vid_hres, vid_vres, vid_col; int interlaced, bChanged = 1, bEnabled = 0, vid_size = 0; char *frame_start; /* current video start address (in real memory) */ --- a/src/sh4/scif.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/sh4/scif.c Fri Dec 23 11:44:55 2005 +0000 @@ -1,5 +1,5 @@ /** - * $Id: scif.c,v 1.3 2005-12-22 13:57:26 nkeynes Exp $ + * $Id: scif.c,v 1.4 2005-12-23 11:44:55 nkeynes Exp $ * SCIF (Serial Communication Interface with FIFO) implementation - part of the * SH4 standard on-chip peripheral set. The SCIF is hooked up to the DCs * external serial port @@ -609,3 +609,9 @@ } SCIF_rcvd_last_tick = rcvd; } + +void SCIF_run_slice( int microsecs ) +{ + /* TODO */ + SCIF_clock_tick(); +} --- a/src/sh4/sh4core.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/sh4/sh4core.c Fri Dec 23 11:44:55 2005 +0000 @@ -1,17 +1,48 @@ +/** + * $Id: sh4core.c,v 1.9 2005-12-23 11:44:55 nkeynes Exp $ + * + * SH4 emulation core, and parent module for all the SH4 peripheral + * modules. + * + * Copyright (c) 2005 Nathan Keynes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + #include #include "dream.h" #include "modules.h" #include "sh4core.h" #include "sh4mmio.h" #include "mem.h" +#include "clock.h" #include "intc.h" -void sh4_save( FILE *f ); -int sh4_load( FILE *f ); +uint32_t sh4_freq = SH4_BASE_RATE; +uint32_t sh4_bus_freq = SH4_BASE_RATE; +uint32_t sh4_peripheral_freq = SH4_BASE_RATE / 2; + +/********************** SH4 Module Definition ****************************/ + +void sh4_init( void ); +void sh4_reset( void ); +void sh4_run_slice( int ); +void sh4_start( void ); +void sh4_stop( void ); +void sh4_save_state( FILE *f ); +int sh4_load_state( FILE *f ); struct dreamcast_module sh4_module = { "SH4", sh4_init, sh4_reset, - NULL, sh4_stop, - sh4_save, sh4_load }; + NULL, sh4_run_slice, sh4_stop, + sh4_save_state, sh4_load_state }; struct sh4_registers sh4r; static int running = 0; @@ -34,10 +65,16 @@ intc_reset(); } -void sh4_set_pc( int pc ) +void sh4_run_slice( int microsecs ) { - sh4r.pc = pc; - sh4r.new_pc = pc+2; + int count = sh4_freq * microsecs; + int i; + + for( i=0; i +#include #ifdef __cplusplus extern "C" { @@ -60,6 +61,10 @@ void sh4_set_pc( int ); void sh4_execute_instruction( void ); void sh4_raise_exception( int, int ); +void sh4_set_breakpoint( uint32_t pc, int type ); + +#define BREAK_ONESHOT 1 +#define BREAK_PERM 2 /* SH4 Memory */ int32_t sh4_read_long( uint32_t addr ); @@ -70,7 +75,12 @@ void sh4_write_byte( uint32_t addr, uint32_t val ); int32_t sh4_read_phys_word( uint32_t addr ); -void run_timers( int ); +/* Peripheral functions */ +void DMAC_run_slice( int ); +void TMU_run_slice( int ); +void SCIF_run_slice( int ); +void SCIF_save_state( FILE *f ); +int SCIF_load_state( FILE *f ); #define SIGNEXT4(n) ((((int32_t)(n))<<28)>>28) #define SIGNEXT8(n) ((int32_t)((int8_t)(n))) --- a/src/sh4/sh4mmio.c Thu Dec 22 13:57:26 2005 +0000 +++ b/src/sh4/sh4mmio.c Fri Dec 23 11:44:55 2005 +0000 @@ -134,97 +134,12 @@ MMIO_REGION_STUBFNS( UBC ) -/********************************* CPG *************************************/ - -uint32_t sh4_freq = SH4_BASE_RATE; -uint32_t sh4_bus_freq = SH4_BASE_RATE; -uint32_t sh4_peripheral_freq = SH4_BASE_RATE / 2; - - -MMIO_REGION_STUBFNS( CPG ) /********************************* DMAC *************************************/ MMIO_REGION_STUBFNS( DMAC ) -/********************************** RTC *************************************/ -MMIO_REGION_STUBFNS( RTC ) - -/********************************** TMU *************************************/ - -int timer_divider[3] = {16,16,16}; -MMIO_REGION_READ_DEFFN( TMU ) - -int get_timer_div( int val ) -{ - switch( val & 0x07 ) { - case 0: return 16; /* assume peripheral clock is IC/4 */ - case 1: return 64; - case 2: return 256; - case 3: return 1024; - case 4: return 4096; - } - return 1; -} - -void mmio_region_TMU_write( uint32_t reg, uint32_t val ) -{ - switch( reg ) { - case TCR0: - timer_divider[0] = get_timer_div(val); - break; - case TCR1: - timer_divider[1] = get_timer_div(val); - break; - case TCR2: - timer_divider[2] = get_timer_div(val); - break; - } - MMIO_WRITE( TMU, reg, val ); -} - -void run_timers( int cycles ) -{ - int tcr = MMIO_READ( TMU, TSTR ); - cycles *= 16; - if( tcr & 0x01 ) { - int count = cycles / timer_divider[0]; - int *val = MMIO_REG( TMU, TCNT0 ); - if( *val < count ) { - MMIO_READ( TMU, TCR0 ) |= 0x100; - /* interrupt goes here */ - count -= *val; - *val = MMIO_READ( TMU, TCOR0 ) - count; - } else { - *val -= count; - } - } - if( tcr & 0x02 ) { - int count = cycles / timer_divider[1]; - int *val = MMIO_REG( TMU, TCNT1 ); - if( *val < count ) { - MMIO_READ( TMU, TCR1 ) |= 0x100; - /* interrupt goes here */ - count -= *val; - *val = MMIO_READ( TMU, TCOR1 ) - count; - } else { - *val -= count; - } - } - if( tcr & 0x04 ) { - int count = cycles / timer_divider[2]; - int *val = MMIO_REG( TMU, TCNT2 ); - if( *val < count ) { - MMIO_READ( TMU, TCR2 ) |= 0x100; - /* interrupt goes here */ - count -= *val; - *val = MMIO_READ( TMU, TCOR2 ) - count; - } else { - *val -= count; - } - } -} /********************************** SCI *************************************/ --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sh4/timer.c Fri Dec 23 11:44:55 2005 +0000 @@ -0,0 +1,128 @@ +/** + * $Id: timer.c,v 1.1 2005-12-23 11:44:55 nkeynes Exp $ + * + * SH4 Timer/Clock peripheral modules (CPG, TMU, RTC), combined together to + * keep things simple (they intertwine a bit). + * + * Copyright (c) 2005 Nathan Keynes. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "dream.h" +#include "mem.h" +#include "clock.h" +#include "sh4core.h" +#include "sh4mmio.h" + +/********************************* CPG *************************************/ + +int32_t mmio_region_CPG_read( uint32_t reg ) +{ + return MMIO_READ( CPG, reg ); +} + +void mmio_region_CPG_write( uint32_t reg, uint32_t val ) +{ + MMIO_WRITE( CPG, reg, val ); +} + +/********************************** RTC *************************************/ + +int32_t mmio_region_RTC_read( uint32_t reg ) +{ + return MMIO_READ( RTC, reg ); +} + +void mmio_region_RTC_write( uint32_t reg, uint32_t val ) +{ + MMIO_WRITE( RTC, reg, val ); +} + +/********************************** TMU *************************************/ + +int timer_divider[3] = {16,16,16}; + +int32_t mmio_region_TMU_read( uint32_t reg ) +{ + return MMIO_READ( TMU, reg ); +} + + +int get_timer_div( int val ) +{ + switch( val & 0x07 ) { + case 0: return 16; /* assume peripheral clock is IC/4 */ + case 1: return 64; + case 2: return 256; + case 3: return 1024; + case 4: return 4096; + } + return 1; +} + +void mmio_region_TMU_write( uint32_t reg, uint32_t val ) +{ + switch( reg ) { + case TCR0: + timer_divider[0] = get_timer_div(val); + break; + case TCR1: + timer_divider[1] = get_timer_div(val); + break; + case TCR2: + timer_divider[2] = get_timer_div(val); + break; + } + MMIO_WRITE( TMU, reg, val ); +} + +void TMU_run_slice( int microsecs ) +{ + int tcr = MMIO_READ( TMU, TSTR ); + int cycles = microsecs * 16 * 200; + if( tcr & 0x01 ) { + int count = cycles / timer_divider[0]; + int *val = MMIO_REG( TMU, TCNT0 ); + if( *val < count ) { + MMIO_READ( TMU, TCR0 ) |= 0x100; + /* interrupt goes here */ + count -= *val; + *val = MMIO_READ( TMU, TCOR0 ) - count; + } else { + *val -= count; + } + } + if( tcr & 0x02 ) { + int count = cycles / timer_divider[1]; + int *val = MMIO_REG( TMU, TCNT1 ); + if( *val < count ) { + MMIO_READ( TMU, TCR1 ) |= 0x100; + /* interrupt goes here */ + count -= *val; + *val = MMIO_READ( TMU, TCOR1 ) - count; + } else { + *val -= count; + } + } + if( tcr & 0x04 ) { + int count = cycles / timer_divider[2]; + int *val = MMIO_REG( TMU, TCNT2 ); + if( *val < count ) { + MMIO_READ( TMU, TCR2 ) |= 0x100; + /* interrupt goes here */ + count -= *val; + *val = MMIO_READ( TMU, TCOR2 ) - count; + } else { + *val -= count; + } + } +}