revision 265:5daf59b7f31b
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 265:5daf59b7f31b |
parent | 264:e3b8a3ab32b8 |
child | 266:2f811793bd0a |
author | nkeynes |
date | Sat Jan 06 04:06:36 2007 +0000 (17 years ago) |
Implement event queue.
Fix pvr2 timing (yes, again).
Fix pvr2 timing (yes, again).
src/Makefile.am | view | annotate | diff | log | ||
src/Makefile.in | view | annotate | diff | log | ||
src/asic.h | view | annotate | diff | log | ||
src/clock.h | view | annotate | diff | log | ||
src/dream.h | view | annotate | diff | log | ||
src/dreamcast.c | view | annotate | diff | log | ||
src/eventq.c | view | annotate | diff | log | ||
src/eventq.h | view | annotate | diff | log | ||
src/pvr2/pvr2.c | view | annotate | diff | log | ||
src/sh4/intc.c | view | annotate | diff | log | ||
src/sh4/sh4core.c | view | annotate | diff | log | ||
src/sh4/sh4core.h | view | annotate | diff | log |
1.1 --- a/src/Makefile.am Sat Jan 06 04:05:32 2007 +00001.2 +++ b/src/Makefile.am Sat Jan 06 04:06:36 2007 +00001.3 @@ -15,7 +15,7 @@1.4 syscall.c syscall.h bios.c dcload.c \1.5 gdrom/ide.c gdrom/ide.h gdrom/packet.h \1.6 gdrom/gdrom.c gdrom/gdrom.h gdrom/nrg.c gdrom/cdi.c gdrom/linux.c \1.7 - dreamcast.c dreamcast.h \1.8 + dreamcast.c dreamcast.h eventq.c eventq.h \1.9 sh4/intc.c sh4/intc.h sh4/sh4mem.c sh4/timer.c sh4/dmac.c \1.10 sh4/sh4core.c sh4/sh4core.h sh4/sh4dasm.c sh4/sh4dasm.h \1.11 sh4/sh4mmio.c sh4/sh4mmio.h sh4/scif.c \
2.1 --- a/src/Makefile.in Sat Jan 06 04:05:32 2007 +00002.2 +++ b/src/Makefile.in Sat Jan 06 04:06:36 2007 +00002.3 @@ -149,7 +149,7 @@2.4 syscall.c syscall.h bios.c dcload.c \2.5 gdrom/ide.c gdrom/ide.h gdrom/packet.h \2.6 gdrom/gdrom.c gdrom/gdrom.h gdrom/nrg.c gdrom/cdi.c gdrom/linux.c \2.7 - dreamcast.c dreamcast.h \2.8 + dreamcast.c dreamcast.h eventq.c eventq.h \2.9 sh4/intc.c sh4/intc.h sh4/sh4mem.c sh4/timer.c sh4/dmac.c \2.10 sh4/sh4core.c sh4/sh4core.h sh4/sh4dasm.c sh4/sh4dasm.h \2.11 sh4/sh4mmio.c sh4/sh4mmio.h sh4/scif.c \2.12 @@ -187,18 +187,19 @@2.13 asic.$(OBJEXT) syscall.$(OBJEXT) bios.$(OBJEXT) \2.14 dcload.$(OBJEXT) ide.$(OBJEXT) gdrom.$(OBJEXT) nrg.$(OBJEXT) \2.15 cdi.$(OBJEXT) linux.$(OBJEXT) dreamcast.$(OBJEXT) \2.16 - intc.$(OBJEXT) sh4mem.$(OBJEXT) timer.$(OBJEXT) dmac.$(OBJEXT) \2.17 - sh4core.$(OBJEXT) sh4dasm.$(OBJEXT) sh4mmio.$(OBJEXT) \2.18 - scif.$(OBJEXT) armcore.$(OBJEXT) armdasm.$(OBJEXT) \2.19 - armmem.$(OBJEXT) aica.$(OBJEXT) audio.$(OBJEXT) pvr2.$(OBJEXT) \2.20 - tacore.$(OBJEXT) render.$(OBJEXT) rendcore.$(OBJEXT) \2.21 - rendbkg.$(OBJEXT) rendsort.$(OBJEXT) texcache.$(OBJEXT) \2.22 - maple.$(OBJEXT) controller.$(OBJEXT) support.$(OBJEXT) \2.23 - interface.$(OBJEXT) callbacks.$(OBJEXT) gui.$(OBJEXT) \2.24 - mmr_win.$(OBJEXT) debug_win.$(OBJEXT) dump_win.$(OBJEXT) \2.25 - loader.$(OBJEXT) bootstrap.$(OBJEXT) util.$(OBJEXT) \2.26 - display.$(OBJEXT) audio_null.$(OBJEXT) audio_esd.$(OBJEXT) \2.27 - video_null.$(OBJEXT) video_gtk.$(OBJEXT) video_x11.$(OBJEXT)2.28 + eventq.$(OBJEXT) intc.$(OBJEXT) sh4mem.$(OBJEXT) \2.29 + timer.$(OBJEXT) dmac.$(OBJEXT) sh4core.$(OBJEXT) \2.30 + sh4dasm.$(OBJEXT) sh4mmio.$(OBJEXT) scif.$(OBJEXT) \2.31 + armcore.$(OBJEXT) armdasm.$(OBJEXT) armmem.$(OBJEXT) \2.32 + aica.$(OBJEXT) audio.$(OBJEXT) pvr2.$(OBJEXT) tacore.$(OBJEXT) \2.33 + render.$(OBJEXT) rendcore.$(OBJEXT) rendbkg.$(OBJEXT) \2.34 + rendsort.$(OBJEXT) texcache.$(OBJEXT) maple.$(OBJEXT) \2.35 + controller.$(OBJEXT) support.$(OBJEXT) interface.$(OBJEXT) \2.36 + callbacks.$(OBJEXT) gui.$(OBJEXT) mmr_win.$(OBJEXT) \2.37 + debug_win.$(OBJEXT) dump_win.$(OBJEXT) loader.$(OBJEXT) \2.38 + bootstrap.$(OBJEXT) util.$(OBJEXT) display.$(OBJEXT) \2.39 + audio_null.$(OBJEXT) audio_esd.$(OBJEXT) video_null.$(OBJEXT) \2.40 + video_gtk.$(OBJEXT) video_x11.$(OBJEXT)2.41 lxdream_OBJECTS = $(am_lxdream_OBJECTS)2.42 lxdream_DEPENDENCIES =2.43 lxdream_LDFLAGS =2.44 @@ -215,23 +216,23 @@2.45 @AMDEP_TRUE@ ./$(DEPDIR)/controller.Po ./$(DEPDIR)/dcload.Po \2.46 @AMDEP_TRUE@ ./$(DEPDIR)/debug_win.Po ./$(DEPDIR)/display.Po \2.47 @AMDEP_TRUE@ ./$(DEPDIR)/dmac.Po ./$(DEPDIR)/dreamcast.Po \2.48 -@AMDEP_TRUE@ ./$(DEPDIR)/dump_win.Po ./$(DEPDIR)/gdrom.Po \2.49 -@AMDEP_TRUE@ ./$(DEPDIR)/gui.Po ./$(DEPDIR)/ide.Po \2.50 -@AMDEP_TRUE@ ./$(DEPDIR)/intc.Po ./$(DEPDIR)/interface.Po \2.51 -@AMDEP_TRUE@ ./$(DEPDIR)/linux.Po ./$(DEPDIR)/loader.Po \2.52 -@AMDEP_TRUE@ ./$(DEPDIR)/main.Po ./$(DEPDIR)/maple.Po \2.53 -@AMDEP_TRUE@ ./$(DEPDIR)/mem.Po ./$(DEPDIR)/mmr_win.Po \2.54 -@AMDEP_TRUE@ ./$(DEPDIR)/nrg.Po ./$(DEPDIR)/pvr2.Po \2.55 -@AMDEP_TRUE@ ./$(DEPDIR)/rendbkg.Po ./$(DEPDIR)/rendcore.Po \2.56 -@AMDEP_TRUE@ ./$(DEPDIR)/render.Po ./$(DEPDIR)/rendsort.Po \2.57 -@AMDEP_TRUE@ ./$(DEPDIR)/scif.Po ./$(DEPDIR)/sh4core.Po \2.58 -@AMDEP_TRUE@ ./$(DEPDIR)/sh4dasm.Po ./$(DEPDIR)/sh4mem.Po \2.59 -@AMDEP_TRUE@ ./$(DEPDIR)/sh4mmio.Po ./$(DEPDIR)/support.Po \2.60 -@AMDEP_TRUE@ ./$(DEPDIR)/syscall.Po ./$(DEPDIR)/tacore.Po \2.61 -@AMDEP_TRUE@ ./$(DEPDIR)/texcache.Po ./$(DEPDIR)/timer.Po \2.62 -@AMDEP_TRUE@ ./$(DEPDIR)/util.Po ./$(DEPDIR)/video_gtk.Po \2.63 -@AMDEP_TRUE@ ./$(DEPDIR)/video_null.Po ./$(DEPDIR)/video_x11.Po \2.64 -@AMDEP_TRUE@ ./$(DEPDIR)/watch.Po2.65 +@AMDEP_TRUE@ ./$(DEPDIR)/dump_win.Po ./$(DEPDIR)/eventq.Po \2.66 +@AMDEP_TRUE@ ./$(DEPDIR)/gdrom.Po ./$(DEPDIR)/gui.Po \2.67 +@AMDEP_TRUE@ ./$(DEPDIR)/ide.Po ./$(DEPDIR)/intc.Po \2.68 +@AMDEP_TRUE@ ./$(DEPDIR)/interface.Po ./$(DEPDIR)/linux.Po \2.69 +@AMDEP_TRUE@ ./$(DEPDIR)/loader.Po ./$(DEPDIR)/main.Po \2.70 +@AMDEP_TRUE@ ./$(DEPDIR)/maple.Po ./$(DEPDIR)/mem.Po \2.71 +@AMDEP_TRUE@ ./$(DEPDIR)/mmr_win.Po ./$(DEPDIR)/nrg.Po \2.72 +@AMDEP_TRUE@ ./$(DEPDIR)/pvr2.Po ./$(DEPDIR)/rendbkg.Po \2.73 +@AMDEP_TRUE@ ./$(DEPDIR)/rendcore.Po ./$(DEPDIR)/render.Po \2.74 +@AMDEP_TRUE@ ./$(DEPDIR)/rendsort.Po ./$(DEPDIR)/scif.Po \2.75 +@AMDEP_TRUE@ ./$(DEPDIR)/sh4core.Po ./$(DEPDIR)/sh4dasm.Po \2.76 +@AMDEP_TRUE@ ./$(DEPDIR)/sh4mem.Po ./$(DEPDIR)/sh4mmio.Po \2.77 +@AMDEP_TRUE@ ./$(DEPDIR)/support.Po ./$(DEPDIR)/syscall.Po \2.78 +@AMDEP_TRUE@ ./$(DEPDIR)/tacore.Po ./$(DEPDIR)/texcache.Po \2.79 +@AMDEP_TRUE@ ./$(DEPDIR)/timer.Po ./$(DEPDIR)/util.Po \2.80 +@AMDEP_TRUE@ ./$(DEPDIR)/video_gtk.Po ./$(DEPDIR)/video_null.Po \2.81 +@AMDEP_TRUE@ ./$(DEPDIR)/video_x11.Po ./$(DEPDIR)/watch.Po2.82 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \2.83 $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)2.84 CCLD = $(CC)2.85 @@ -302,6 +303,7 @@2.86 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dmac.Po@am__quote@2.87 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dreamcast.Po@am__quote@2.88 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump_win.Po@am__quote@2.89 +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eventq.Po@am__quote@2.90 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdrom.Po@am__quote@2.91 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gui.Po@am__quote@2.92 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ide.Po@am__quote@
3.1 --- a/src/asic.h Sat Jan 06 04:05:32 2007 +00003.2 +++ b/src/asic.h Sat Jan 06 04:06:36 2007 +00003.3 @@ -1,5 +1,5 @@3.4 /**3.5 - * $Id: asic.h,v 1.14 2006-12-19 09:51:35 nkeynes Exp $3.6 + * $Id: asic.h,v 1.15 2007-01-06 04:06:36 nkeynes Exp $3.7 *3.8 * Support for the miscellaneous ASIC functions (Primarily event multiplexing,3.9 * and DMA). Includes MMIO definitions for the 5f6000 and 5f7000 regions,3.10 @@ -173,8 +173,8 @@3.11 MMIO_REGION_END3.13 #define EVENT_PVR_RENDER_DONE 23.14 -#define EVENT_SCANLINE1 33.15 -#define EVENT_SCANLINE2 43.16 +#define EVENT_SCANLINE2 33.17 +#define EVENT_SCANLINE1 43.18 #define EVENT_RETRACE 53.19 #define EVENT_PVR_UNK 63.20 #define EVENT_PVR_OPAQUE_DONE 7
4.1 --- a/src/clock.h Sat Jan 06 04:05:32 2007 +00004.2 +++ b/src/clock.h Sat Jan 06 04:06:36 2007 +00004.3 @@ -1,5 +1,5 @@4.4 /**4.5 - * $Id: clock.h,v 1.4 2007-01-03 09:01:51 nkeynes Exp $4.6 + * $Id: clock.h,v 1.5 2007-01-06 04:06:36 nkeynes Exp $4.7 * External interface to the dreamcast serial port, implemented by4.8 * sh4/scif.c4.9 *4.10 @@ -25,9 +25,10 @@4.11 #endif4.13 #define MHZ4.14 +#define KHZ4.15 #define SH4_BASE_RATE 200 MHZ4.16 #define ARM_BASE_RATE 33 MHZ4.17 -#define PVR2_DOT_CLOCK 27 MHZ4.18 +#define PVR2_DOT_CLOCK 27068 KHZ4.20 extern uint32_t sh4_freq;4.21 extern uint32_t sh4_peripheral_freq;
5.1 --- a/src/dream.h Sat Jan 06 04:05:32 2007 +00005.2 +++ b/src/dream.h Sat Jan 06 04:06:36 2007 +00005.3 @@ -1,5 +1,5 @@5.4 /**5.5 - * $Id: dream.h,v 1.11 2006-09-12 08:36:09 nkeynes Exp $5.6 + * $Id: dream.h,v 1.12 2007-01-06 04:06:36 nkeynes Exp $5.7 *5.8 * Miscellaneous application-wide declarations (mainly logging atm)5.9 *5.10 @@ -86,6 +86,7 @@5.11 extern struct dreamcast_module maple_module;5.12 extern struct dreamcast_module pvr2_module;5.13 extern struct dreamcast_module gui_module;5.14 +extern struct dreamcast_module eventq_module;5.15 extern struct dreamcast_module unknown_module;5.17 /*************************** Logging **************************/
6.1 --- a/src/dreamcast.c Sat Jan 06 04:05:32 2007 +00006.2 +++ b/src/dreamcast.c Sat Jan 06 04:06:36 2007 +00006.3 @@ -1,5 +1,5 @@6.4 /**6.5 - * $Id: dreamcast.c,v 1.18 2006-07-02 04:59:00 nkeynes Exp $6.6 + * $Id: dreamcast.c,v 1.19 2007-01-06 04:06:36 nkeynes Exp $6.7 * Central switchboard for the system. This pulls all the individual modules6.8 * together into some kind of coherent structure. This is also where you'd6.9 * add Naomi support, if I ever get a board to play with...6.10 @@ -58,6 +58,7 @@6.11 */6.12 void dreamcast_configure( )6.13 {6.14 + dreamcast_register_module( &eventq_module );6.15 /* Register the memory framework */6.16 dreamcast_register_module( &mem_module );
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00007.2 +++ b/src/eventq.c Sat Jan 06 04:06:36 2007 +00007.3 @@ -0,0 +1,341 @@7.4 +/**7.5 + * $Id: eventq.c,v 1.1 2007-01-06 04:06:36 nkeynes Exp $7.6 + *7.7 + * Simple implementation of one-shot timers. Effectively this allows IO7.8 + * devices to wait until a particular time before completing. We expect7.9 + * there to be at least half a dozen or so continually scheduled events7.10 + * (TMU and PVR2), peaking around 20+.7.11 + *7.12 + * Copyright (c) 2005 Nathan Keynes.7.13 + *7.14 + * This program is free software; you can redistribute it and/or modify7.15 + * it under the terms of the GNU General Public License as published by7.16 + * the Free Software Foundation; either version 2 of the License, or7.17 + * (at your option) any later version.7.18 + *7.19 + * This program is distributed in the hope that it will be useful,7.20 + * but WITHOUT ANY WARRANTY; without even the implied warranty of7.21 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the7.22 + * GNU General Public License for more details.7.23 + */7.24 +7.25 +#include <assert.h>7.26 +#include "dreamcast.h"7.27 +#include "eventq.h"7.28 +#include "sh4core.h"7.29 +7.30 +#define LONG_SCAN_PERIOD 1000000000 /* 1 second */7.31 +7.32 +typedef struct event {7.33 + uint32_t id;7.34 + uint32_t seconds;7.35 + uint32_t nanosecs;7.36 + event_func_t func;7.37 +7.38 + struct event *next;7.39 +} *event_t;7.40 +7.41 +static struct event events[MAX_EVENT_ID];7.42 +7.43 +/**7.44 + * Countdown to the next scan of the long-duration list (greater than 1 second).7.45 + */7.46 +static int long_scan_time_remaining;7.47 +7.48 +static event_t event_head;7.49 +static event_t long_event_head;7.50 +7.51 +void event_reset();7.52 +void event_init();7.53 +uint32_t event_run_slice( uint32_t nanosecs );7.54 +void event_save_state( FILE *f );7.55 +int event_load_state( FILE * f );7.56 +7.57 +struct dreamcast_module eventq_module = { "EVENTQ", event_init, event_reset, NULL, event_run_slice,7.58 + NULL, event_save_state, event_load_state };7.59 +7.60 +static void event_update_pending( )7.61 +{7.62 + if( event_head == NULL ) {7.63 + if( !(sh4r.event_types & PENDING_IRQ) ) {7.64 + sh4r.event_pending = NOT_SCHEDULED;7.65 + }7.66 + sh4r.event_types &= (~PENDING_EVENT);7.67 + } else {7.68 + if( !(sh4r.event_types & PENDING_IRQ) ) {7.69 + sh4r.event_pending = event_head->nanosecs;7.70 + }7.71 + sh4r.event_types |= PENDING_EVENT;7.72 + }7.73 +}7.74 +7.75 +uint32_t event_get_next_time( )7.76 +{7.77 + if( event_head == NULL ) {7.78 + return NOT_SCHEDULED;7.79 + } else {7.80 + return event_head->nanosecs;7.81 + }7.82 +}7.83 +7.84 +/**7.85 + * Add the event to the short queue.7.86 + */7.87 +static void event_enqueue( event_t event )7.88 +{7.89 + if( event_head == NULL || event->nanosecs < event_head->nanosecs ) {7.90 + event->next = event_head;7.91 + event_head = event;7.92 + event_update_pending();7.93 + } else {7.94 + event_t cur = event_head;7.95 + event_t next = cur->next;7.96 + while( next != NULL && event->nanosecs >= next->nanosecs ) {7.97 + cur = next;7.98 + next = cur->next;7.99 + }7.100 + event->next = next;7.101 + cur->next = event;7.102 + }7.103 +}7.104 +7.105 +static void event_dequeue( event_t event )7.106 +{7.107 + if( event_head == NULL ) {7.108 + ERROR( "Empty event queue but should contain event %d", event->id );7.109 + } else if( event_head == event ) {7.110 + /* removing queue head */7.111 + event_head = event_head->next;7.112 + event_update_pending();7.113 + } else {7.114 + event_t cur = event_head;7.115 + event_t next = cur->next;7.116 + while( next != NULL ) {7.117 + if( next == event ) {7.118 + cur->next = next->next;7.119 + break;7.120 + }7.121 + cur = next;7.122 + next = cur->next;7.123 + }7.124 + }7.125 +}7.126 +7.127 +static void event_dequeue_long( event_t event )7.128 +{7.129 + if( long_event_head == NULL ) {7.130 + ERROR( "Empty long event queue but should contain event %d", event->id );7.131 + } else if( long_event_head == event ) {7.132 + /* removing queue head */7.133 + long_event_head = long_event_head->next;7.134 + } else {7.135 + event_t cur = long_event_head;7.136 + event_t next = cur->next;7.137 + while( next != NULL ) {7.138 + if( next == event ) {7.139 + cur->next = next->next;7.140 + break;7.141 + }7.142 + cur = next;7.143 + next = cur->next;7.144 + }7.145 + }7.146 +}7.147 +7.148 +void register_event_callback( int eventid, event_func_t func )7.149 +{7.150 + events[eventid].func = func;7.151 +}7.152 +7.153 +void event_schedule( int eventid, uint32_t nanosecs )7.154 +{7.155 + int i;7.156 +7.157 + nanosecs += sh4r.slice_cycle;7.158 +7.159 + event_t event = &events[eventid];7.160 +7.161 + if( event->nanosecs != NOT_SCHEDULED ) {7.162 + /* Event is already scheduled. Remove it from the list first */7.163 + event_cancel(eventid);7.164 + }7.165 +7.166 + event->id = eventid;7.167 + event->seconds = 0;7.168 + event->nanosecs = nanosecs;7.169 +7.170 + event_enqueue( event );7.171 +}7.172 +7.173 +void event_schedule_long( int eventid, uint32_t seconds, uint32_t nanosecs ) {7.174 + if( seconds == 0 ) {7.175 + event_schedule( eventid, nanosecs );7.176 + } else {7.177 + event_t event = &events[eventid];7.178 +7.179 + if( event->nanosecs != NOT_SCHEDULED ) {7.180 + /* Event is already scheduled. Remove it from the list first */7.181 + event_cancel(eventid);7.182 + }7.183 +7.184 + event->id = eventid;7.185 + event->seconds = seconds;7.186 + event->nanosecs = nanosecs;7.187 + event->next = long_event_head;7.188 + long_event_head = event;7.189 + }7.190 +7.191 +}7.192 +7.193 +void event_cancel( int eventid )7.194 +{7.195 + event_t event = &events[eventid];7.196 + if( event->nanosecs == NOT_SCHEDULED ) {7.197 + return; /* not scheduled */7.198 + } else {7.199 + event->nanosecs = NOT_SCHEDULED;7.200 + if( event->seconds != 0 ) { /* long term event */7.201 + event_dequeue_long( event );7.202 + } else {7.203 + event_dequeue( event );7.204 + }7.205 + }7.206 +}7.207 +7.208 +7.209 +void event_execute()7.210 +{7.211 + /* Loop in case we missed some or got a couple scheduled for the same time */7.212 + while( event_head != NULL && event_head->nanosecs <= sh4r.slice_cycle ) {7.213 + event_t event = event_head;7.214 + event_head = event->next;7.215 + event->nanosecs = NOT_SCHEDULED;7.216 + // Note: Make sure the internal state is consistent before calling the7.217 + // user function, as it will (quite likely) enqueue another event.7.218 + event->func( event->id );7.219 + }7.220 +7.221 + event_update_pending();7.222 +}7.223 +7.224 +void event_asic_callback( int eventid )7.225 +{7.226 + asic_event( eventid );7.227 +}7.228 +7.229 +void event_init()7.230 +{7.231 + int i;7.232 + for( i=0; i<MAX_EVENT_ID; i++ ) {7.233 + events[i].id = i;7.234 + events[i].nanosecs = NOT_SCHEDULED;7.235 + if( i < 96 ) {7.236 + events[i].func = event_asic_callback;7.237 + } else {7.238 + events[i].func = NULL;7.239 + }7.240 + events[i].next = NULL;7.241 + }7.242 + event_head = NULL;7.243 + long_event_head = NULL;7.244 + long_scan_time_remaining = LONG_SCAN_PERIOD;7.245 +}7.246 +7.247 +7.248 +7.249 +void event_reset()7.250 +{7.251 + int i;7.252 + event_head = NULL;7.253 + long_event_head = NULL;7.254 + long_scan_time_remaining = LONG_SCAN_PERIOD;7.255 + for( i=0; i<MAX_EVENT_ID; i++ ) {7.256 + events[i].nanosecs = NOT_SCHEDULED;7.257 + }7.258 +}7.259 +7.260 +void event_save_state( FILE *f )7.261 +{7.262 + int id, i;7.263 + id = event_head == NULL ? -1 : event_head->id;7.264 + fwrite( &id, sizeof(id), 1, f );7.265 + id = long_event_head == NULL ? -1 : long_event_head->id;7.266 + fwrite( &id, sizeof(id), 1, f );7.267 + fwrite( &long_scan_time_remaining, sizeof(long_scan_time_remaining), 1, f );7.268 + for( i=0; i<MAX_EVENT_ID; i++ ) {7.269 + fwrite( &events[i].id, sizeof(uint32_t), 3, f ); /* First 3 words from structure */7.270 + id = events[i].next == NULL ? -1 : events[i].next->id;7.271 + fwrite( &id, sizeof(id), 1, f );7.272 + }7.273 +}7.274 +7.275 +int event_load_state( FILE *f )7.276 +{7.277 + int id, i;7.278 + fread( &id, sizeof(id), 1, f );7.279 + event_head = id == -1 ? NULL : &events[id];7.280 + fread( &id, sizeof(id), 1, f );7.281 + long_event_head = id == -1 ? NULL : &events[id];7.282 + fread( &long_scan_time_remaining, sizeof(long_scan_time_remaining), 1, f );7.283 + for( i=0; i<MAX_EVENT_ID; i++ ) {7.284 + fread( &events[i].id, sizeof(uint32_t), 3, f );7.285 + fread( &id, sizeof(id), 1, f );7.286 + events[i].next = id == -1 ? NULL : &events[id];7.287 + }7.288 + return 0;7.289 +}7.290 +7.291 +/**7.292 + * Scan all entries in the long queue, decrementing each by 1 second. Entries7.293 + * that are now < 1 second are moved to the short queue.7.294 + */7.295 +static void event_scan_long()7.296 +{7.297 + while( long_event_head != NULL && --long_event_head->seconds == 0 ) {7.298 + event_t event = long_event_head;7.299 + long_event_head = event->next;7.300 + event_enqueue(event);7.301 + }7.302 +7.303 + if( long_event_head != NULL ) {7.304 + event_t last = long_event_head;7.305 + event_t cur = last->next;7.306 + while( cur != NULL ) {7.307 + if( --cur->seconds == 0 ) {7.308 + last->next = cur->next;7.309 + event_enqueue(cur);7.310 + } else {7.311 + last = cur;7.312 + }7.313 + cur = last->next;7.314 + }7.315 + }7.316 +}7.317 +7.318 +/**7.319 + * Decrement the event time on all pending events by the supplied nanoseconds.7.320 + * It may or may not be faster to wrap around instead, but this has the benefit7.321 + * of simplicity.7.322 + */7.323 +uint32_t event_run_slice( uint32_t nanosecs )7.324 +{7.325 + event_t event = event_head;7.326 + while( event != NULL ) {7.327 + if( event->nanosecs <= nanosecs ) {7.328 + event->nanosecs = 0;7.329 + } else {7.330 + event->nanosecs -= nanosecs;7.331 + }7.332 + event = event->next;7.333 + }7.334 +7.335 + long_scan_time_remaining -= nanosecs;7.336 + if( long_scan_time_remaining <= 0 ) {7.337 + long_scan_time_remaining += LONG_SCAN_PERIOD;7.338 + event_scan_long();7.339 + }7.340 +7.341 + event_update_pending();7.342 + return nanosecs;7.343 +}7.344 +
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00008.2 +++ b/src/eventq.h Sat Jan 06 04:06:36 2007 +00008.3 @@ -0,0 +1,71 @@8.4 +/**8.5 + * $Id: eventq.h,v 1.1 2007-01-06 04:06:36 nkeynes Exp $8.6 + *8.7 + * Simple implementation of one-shot timers. Effectively this allows IO8.8 + * devices to wait until a particular time before completing. We expect8.9 + * there to be at least half a dozen or so continually scheduled events8.10 + * (TMU and PVR2), peaking around 20+.8.11 + *8.12 + * Copyright (c) 2005 Nathan Keynes.8.13 + *8.14 + * This program is free software; you can redistribute it and/or modify8.15 + * it under the terms of the GNU General Public License as published by8.16 + * the Free Software Foundation; either version 2 of the License, or8.17 + * (at your option) any later version.8.18 + *8.19 + * This program is distributed in the hope that it will be useful,8.20 + * but WITHOUT ANY WARRANTY; without even the implied warranty of8.21 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the8.22 + * GNU General Public License for more details.8.23 + */8.24 +8.25 +#include "dream.h"8.26 +8.27 +#define NOT_SCHEDULED 0xFFFFFFFF /* Sentinel value */8.28 +8.29 +8.30 +typedef void (*event_func_t)(int eventid);8.31 +8.32 +/**8.33 + * Register the callback to be associated with the given event ID.8.34 + * Note: These should be registered at init time and never changed.8.35 + */8.36 +void register_event_callback( int eventid, event_func_t func );8.37 +8.38 +/**8.39 + * Schedule a new pending event.8.40 + * @param eventid Unique ID identifying the event in question (used to remove it8.41 + * at a later time). If the eventid is scheduled more than once, only the lastest8.42 + * schedule for that ID will be valid.8.43 + * @param nanosecs Nanoseconds from the current SH4 time at which the event8.44 + * should occur.8.45 + */8.46 +void event_schedule( int eventid, uint32_t nanosecs );8.47 +8.48 +/**8.49 + * Schedule a long-duration pending event8.50 + */8.51 +void event_schedule_long( int eventid, uint32_t seconds, uint32_t nanosecs );8.52 +8.53 +/**8.54 + * Remove a previously created event without triggering it. This is usually8.55 + * only used when an operation is aborted.8.56 + */8.57 +void event_cancel( int eventid );8.58 +8.59 +/**8.60 + * Return the slice cycle time of the next event, or NOT_SCHEDULED8.61 + * if no events are scheduled for this time slice.8.62 + */8.63 +uint32_t event_get_next_time();8.64 +8.65 +/**8.66 + * Execute the event on the top of the queue, and remove it.8.67 + */8.68 +void event_execute();8.69 +8.70 +#define MAX_EVENT_ID 1288.71 +8.72 +/* Events 1..96 are defined as the corresponding ASIC events. */8.73 +8.74 +
9.1 --- a/src/pvr2/pvr2.c Sat Jan 06 04:05:32 2007 +00009.2 +++ b/src/pvr2/pvr2.c Sat Jan 06 04:06:36 2007 +00009.3 @@ -1,5 +1,5 @@9.4 /**9.5 - * $Id: pvr2.c,v 1.34 2007-01-03 09:01:51 nkeynes Exp $9.6 + * $Id: pvr2.c,v 1.35 2007-01-06 04:06:36 nkeynes Exp $9.7 *9.8 * PVR2 (Video) Core module implementation and MMIO registers.9.9 *9.10 @@ -18,6 +18,7 @@9.11 #define MODULE pvr2_module9.13 #include "dream.h"9.14 +#include "eventq.h"9.15 #include "display.h"9.16 #include "mem.h"9.17 #include "asic.h"9.18 @@ -34,6 +35,10 @@9.19 static uint32_t pvr2_run_slice( uint32_t );9.20 static void pvr2_save_state( FILE *f );9.21 static int pvr2_load_state( FILE *f );9.22 +static void pvr2_update_raster_posn( uint32_t nanosecs );9.23 +static void pvr2_schedule_line_event( int eventid, int line );9.24 +static void pvr2_schedule_scanline_event( int eventid, int line );9.25 +uint32_t pvr2_get_sync_status();9.27 void pvr2_display_frame( void );9.29 @@ -60,10 +65,10 @@9.30 uint32_t frame_count;9.31 uint32_t line_count;9.32 uint32_t line_remainder;9.33 + uint32_t cycles_run; /* Cycles already executed prior to main time slice */9.34 uint32_t irq_vpos1;9.35 uint32_t irq_vpos2;9.36 uint32_t odd_even_field; /* 1 = odd, 0 = even */9.37 - gboolean retrace;9.39 /* timing */9.40 uint32_t dot_clock;9.41 @@ -74,6 +79,8 @@9.42 uint32_t hsync_width_ns;9.43 uint32_t front_porch_ns;9.44 uint32_t back_porch_ns;9.45 + uint32_t retrace_start_line;9.46 + uint32_t retrace_end_line;9.47 gboolean interlaced;9.48 struct video_timing timing;9.49 } pvr2_state;9.50 @@ -81,20 +88,39 @@9.51 struct video_buffer video_buffer[2];9.52 int video_buffer_idx = 0;9.54 +/**9.55 + * Event handler for the retrace callback (fires on line 0 normally)9.56 + */9.57 +static void pvr2_retrace_callback( int eventid ) {9.58 + asic_event( eventid );9.59 + pvr2_update_raster_posn(sh4r.slice_cycle);9.60 + pvr2_schedule_line_event( EVENT_RETRACE, 0 );9.61 +}9.62 +9.63 +/**9.64 + * Event handler for the scanline callbacks. Fires the corresponding9.65 + * ASIC event, and resets the timer for the next field.9.66 + */9.67 +static void pvr2_scanline_callback( int eventid ) {9.68 + asic_event( eventid );9.69 + pvr2_update_raster_posn(sh4r.slice_cycle);9.70 + if( eventid == EVENT_SCANLINE1 ) {9.71 + pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos1 );9.72 + } else {9.73 + pvr2_schedule_scanline_event( eventid, pvr2_state.irq_vpos2 );9.74 + }9.75 +}9.76 +9.77 static void pvr2_init( void )9.78 {9.79 register_io_region( &mmio_region_PVR2 );9.80 register_io_region( &mmio_region_PVR2PAL );9.81 register_io_region( &mmio_region_PVR2TA );9.82 + register_event_callback( EVENT_RETRACE, pvr2_retrace_callback );9.83 + register_event_callback( EVENT_SCANLINE1, pvr2_scanline_callback );9.84 + register_event_callback( EVENT_SCANLINE2, pvr2_scanline_callback );9.85 video_base = mem_get_region_by_name( MEM_REGION_VIDEO );9.86 texcache_init();9.87 - pvr2_state.dot_clock = 27069;9.88 - pvr2_state.total_lines = pal_timing.total_lines;9.89 - pvr2_state.line_time_ns = pal_timing.line_time_ns;9.90 - pvr2_state.front_porch_ns = 12000;9.91 - pvr2_state.back_porch_ns = 4000;9.92 - pvr2_state.hsync_width_ns = 4000;9.93 - pvr2_state.vsync_lines = 5;9.94 pvr2_reset();9.95 pvr2_ta_reset();9.96 }9.97 @@ -103,10 +129,14 @@9.98 {9.99 pvr2_state.line_count = 0;9.100 pvr2_state.line_remainder = 0;9.101 + pvr2_state.cycles_run = 0;9.102 pvr2_state.irq_vpos1 = 0;9.103 pvr2_state.irq_vpos2 = 0;9.104 - pvr2_state.retrace = FALSE;9.105 pvr2_state.timing = ntsc_timing;9.106 + pvr2_state.dot_clock = PVR2_DOT_CLOCK;9.107 + pvr2_state.back_porch_ns = 4000;9.108 + mmio_region_PVR2_write( DISP_TOTAL, 0x0270035F );9.109 + mmio_region_PVR2_write( DISP_SYNCTIME, 0x07D6A53F );9.110 video_buffer_idx = 0;9.112 pvr2_ta_init();9.113 @@ -127,33 +157,41 @@9.114 return pvr2_ta_load_state(f);9.115 }9.117 +/**9.118 + * Update the current raster position to the given number of nanoseconds,9.119 + * relative to the last time slice. (ie the raster will be adjusted forward9.120 + * by nanosecs - nanosecs_already_run_this_timeslice)9.121 + */9.122 +static void pvr2_update_raster_posn( uint32_t nanosecs )9.123 +{9.124 + uint32_t old_line_count = pvr2_state.line_count;9.125 + if( pvr2_state.line_time_ns == 0 ) {9.126 + return; /* do nothing */9.127 + }9.128 + pvr2_state.line_remainder += (nanosecs - pvr2_state.cycles_run);9.129 + pvr2_state.cycles_run = nanosecs;9.130 + while( pvr2_state.line_remainder >= pvr2_state.line_time_ns ) {9.131 + pvr2_state.line_count ++;9.132 + pvr2_state.line_remainder -= pvr2_state.line_time_ns;9.133 + }9.134 +9.135 + if( pvr2_state.line_count >= pvr2_state.total_lines ) {9.136 + pvr2_state.line_count -= pvr2_state.total_lines;9.137 + if( pvr2_state.interlaced ) {9.138 + pvr2_state.odd_even_field = !pvr2_state.odd_even_field;9.139 + }9.140 + }9.141 + if( pvr2_state.line_count >= pvr2_state.retrace_end_line &&9.142 + (old_line_count < pvr2_state.retrace_end_line ||9.143 + old_line_count > pvr2_state.line_count) ) {9.144 + pvr2_display_frame();9.145 + }9.146 +}9.147 +9.148 static uint32_t pvr2_run_slice( uint32_t nanosecs )9.149 {9.150 - pvr2_state.line_remainder += nanosecs;9.151 - while( pvr2_state.line_remainder >= pvr2_state.line_time_ns ) {9.152 - pvr2_state.line_remainder -= pvr2_state.line_time_ns;9.153 -9.154 - pvr2_state.line_count++;9.155 - if( pvr2_state.line_count == pvr2_state.total_lines ) {9.156 - asic_event( EVENT_RETRACE );9.157 - pvr2_state.line_count = 0;9.158 - pvr2_state.retrace = TRUE;9.159 - }9.160 -9.161 - if( pvr2_state.line_count == pvr2_state.irq_vpos1 ) {9.162 - asic_event( EVENT_SCANLINE1 );9.163 - }9.164 - if( pvr2_state.line_count == pvr2_state.irq_vpos2 ) {9.165 - asic_event( EVENT_SCANLINE2 );9.166 - }9.167 -9.168 - if( pvr2_state.line_count == pvr2_state.timing.retrace_lines ) {9.169 - if( pvr2_state.retrace ) {9.170 - pvr2_display_frame();9.171 - pvr2_state.retrace = FALSE;9.172 - }9.173 - }9.174 - }9.175 + pvr2_update_raster_posn( nanosecs );9.176 + pvr2_state.cycles_run = 0;9.177 return nanosecs;9.178 }9.180 @@ -273,9 +311,10 @@9.181 case DISP_ADDR1:9.182 val &= 0x00FFFFFC;9.183 MMIO_WRITE( PVR2, reg, val );9.184 - if( pvr2_state.retrace ) {9.185 + pvr2_update_raster_posn(sh4r.slice_cycle);9.186 + if( pvr2_state.line_count >= pvr2_state.retrace_start_line ||9.187 + pvr2_state.line_count < pvr2_state.retrace_end_line ) {9.188 pvr2_display_frame();9.189 - pvr2_state.retrace = FALSE;9.190 }9.191 break;9.192 case DISP_ADDR2:9.193 @@ -301,6 +340,9 @@9.194 val = val & 0x03FF03FF;9.195 pvr2_state.irq_vpos1 = (val >> 16);9.196 pvr2_state.irq_vpos2 = val & 0x03FF;9.197 + pvr2_update_raster_posn(sh4r.slice_cycle);9.198 + pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1 );9.199 + pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2 );9.200 MMIO_WRITE( PVR2, reg, val );9.201 break;9.202 case RENDER_NEARCLIP:9.203 @@ -359,9 +401,15 @@9.204 case DISP_TOTAL:9.205 val = val & 0x03FF03FF;9.206 MMIO_WRITE( PVR2, reg, val );9.207 + pvr2_update_raster_posn(sh4r.slice_cycle);9.208 pvr2_state.total_lines = (val >> 16) + 1;9.209 pvr2_state.line_size = (val & 0x03FF) + 1;9.210 pvr2_state.line_time_ns = 1000000 * pvr2_state.line_size / pvr2_state.dot_clock;9.211 + pvr2_state.retrace_end_line = 0x2A;9.212 + pvr2_state.retrace_start_line = pvr2_state.total_lines - 6;9.213 + pvr2_schedule_line_event( EVENT_RETRACE, 0 );9.214 + pvr2_schedule_scanline_event( EVENT_SCANLINE1, pvr2_state.irq_vpos1 );9.215 + pvr2_schedule_scanline_event( EVENT_SCANLINE2, pvr2_state.irq_vpos2 );9.216 break;9.217 case DISP_SYNCCFG:9.218 MMIO_WRITE( PVR2, reg, val&0x000003FF );9.219 @@ -456,50 +504,82 @@9.220 * 12 Horizontal sync off9.221 * 13 Vertical sync off9.222 * Note this method is probably incorrect for anything other than straight9.223 - * interlaced PAL, and needs further testing.9.224 + * interlaced PAL/NTSC, and needs further testing.9.225 */9.226 uint32_t pvr2_get_sync_status()9.227 {9.228 - uint32_t tmp = pvr2_state.line_remainder + sh4r.slice_cycle;9.229 - uint32_t line = pvr2_state.line_count + (tmp / pvr2_state.line_time_ns);9.230 - uint32_t remainder = tmp % pvr2_state.line_time_ns;9.231 - uint32_t field = pvr2_state.odd_even_field;9.232 - uint32_t result;9.233 + pvr2_update_raster_posn(sh4r.slice_cycle);9.234 + uint32_t result = pvr2_state.line_count;9.236 - if( line >= pvr2_state.total_lines ) {9.237 - line -= pvr2_state.total_lines;9.238 - if( pvr2_state.interlaced ) {9.239 - field == 1 ? 0 : 1;9.240 - }9.241 - }9.242 -9.243 - result = line;9.244 -9.245 - if( field ) {9.246 + if( pvr2_state.odd_even_field ) {9.247 result |= 0x0400;9.248 }9.249 - if( (line & 0x01) == field ) {9.250 - if( remainder > pvr2_state.hsync_width_ns ) {9.251 + if( (pvr2_state.line_count & 0x01) == pvr2_state.odd_even_field ) {9.252 + if( pvr2_state.line_remainder > pvr2_state.hsync_width_ns ) {9.253 result |= 0x1000; /* !HSYNC */9.254 }9.255 - if( line >= pvr2_state.vsync_lines ) {9.256 - if( remainder > pvr2_state.front_porch_ns ) {9.257 + if( pvr2_state.line_count >= pvr2_state.vsync_lines ) {9.258 + if( pvr2_state.line_remainder > pvr2_state.front_porch_ns ) {9.259 result |= 0x2800; /* Display active */9.260 } else {9.261 result |= 0x2000; /* Front porch */9.262 }9.263 }9.264 } else {9.265 - if( remainder < (pvr2_state.line_time_ns - pvr2_state.back_porch_ns) &&9.266 - line >= pvr2_state.vsync_lines ) {9.267 + if( pvr2_state.line_remainder < (pvr2_state.line_time_ns - pvr2_state.back_porch_ns) &&9.268 + pvr2_state.line_count >= pvr2_state.vsync_lines ) {9.269 result |= 0x3800; /* Display active */9.270 } else {9.271 result |= 0x1000; /* Back porch */9.272 }9.273 }9.274 +9.275 return result;9.276 }9.278 +/**9.279 + * Schedule an event for the start of the given line. If the line is actually9.280 + * the current line, schedules it for the next field.9.281 + * The raster position should be updated before calling this method.9.282 + */9.283 +static void pvr2_schedule_line_event( int eventid, int line )9.284 +{9.285 + uint32_t time;9.286 + if( line <= pvr2_state.line_count ) {9.287 + time = (pvr2_state.total_lines - pvr2_state.line_count + line) * pvr2_state.line_time_ns9.288 + - pvr2_state.line_remainder;9.289 + } else {9.290 + time = (line - pvr2_state.line_count) * pvr2_state.line_time_ns - pvr2_state.line_remainder;9.291 + }9.292 +9.293 + if( line < pvr2_state.total_lines ) {9.294 + event_schedule( eventid, time );9.295 + } else {9.296 + event_cancel( eventid );9.297 + }9.298 +}9.299 +9.300 +/**9.301 + * Schedule a "scanline" event. This actually goes off at9.302 + * 2 * line in even fields and 2 * line + 1 in odd fields.9.303 + * Otherwise this behaves as per pvr2_schedule_line_event().9.304 + * The raster position should be updated before calling this9.305 + * method.9.306 + */9.307 +static void pvr2_schedule_scanline_event( int eventid, int line )9.308 +{9.309 + uint32_t field = pvr2_state.odd_even_field;9.310 + if( line <= pvr2_state.line_count && pvr2_state.interlaced ) {9.311 + field = !field;9.312 + }9.313 +9.314 + line <<= 1;9.315 + if( field ) {9.316 + line += 1;9.317 + }9.318 + pvr2_schedule_line_event( eventid, line );9.319 +}9.320 +9.321 MMIO_REGION_READ_FN( PVR2, reg )9.322 {9.323 switch( reg ) {
10.1 --- a/src/sh4/intc.c Sat Jan 06 04:05:32 2007 +000010.2 +++ b/src/sh4/intc.c Sat Jan 06 04:06:36 2007 +000010.3 @@ -1,5 +1,5 @@10.4 /**10.5 - * $Id: intc.c,v 1.6 2006-06-15 10:27:10 nkeynes Exp $10.6 + * $Id: intc.c,v 1.7 2007-01-06 04:06:36 nkeynes Exp $10.7 *10.8 * SH4 onboard interrupt controller (INTC) implementation10.9 *10.10 @@ -20,6 +20,7 @@10.11 #include "sh4mmio.h"10.12 #include "sh4core.h"10.13 #include "intc.h"10.14 +#include "eventq.h"10.16 struct intc_sources_t {10.17 char *name;10.18 @@ -106,7 +107,8 @@10.19 intc_state.num_pending = 0;10.20 for( i=0; i<INT_NUM_SOURCES; i++ )10.21 intc_state.priority[i] = intc_default_priority[i];10.22 - sh4r.int_pending = 0;10.23 + sh4r.event_pending = event_get_next_time();10.24 + sh4r.event_types &= (~PENDING_IRQ);10.25 }10.28 @@ -123,7 +125,7 @@10.29 }10.31 /* We basically maintain a priority queue here, raise_interrupt adds an entry,10.32 - * accept_interrupt takes it off. At the moment this is does as a simple10.33 + * accept_interrupt takes it off. At the moment this is done as a simple10.34 * ordered array, on the basis that in practice there's unlikely to be more10.35 * than one at a time. There are lots of ways to optimize this if it turns out10.36 * to be necessary, but I'd doubt it will be...10.37 @@ -148,8 +150,10 @@10.38 intc_state.pending[j] = intc_state.pending[j-1];10.39 intc_state.pending[i] = which;10.41 - if( i == intc_state.num_pending && (sh4r.sr&SR_BL)==0 && SH4_INTMASK() < pri )10.42 - sh4r.int_pending = 1;10.43 + if( i == intc_state.num_pending && (sh4r.sr&SR_BL)==0 && SH4_INTMASK() < pri ) {10.44 + sh4r.event_pending = 0;10.45 + sh4r.event_types |= PENDING_IRQ;10.46 + }10.48 intc_state.num_pending++;10.49 }10.50 @@ -180,9 +184,14 @@10.51 void intc_mask_changed( void )10.52 {10.53 if( intc_state.num_pending > 0 && (sh4r.sr&SR_BL)==0 &&10.54 - SH4_INTMASK() < PRIORITY(intc_state.pending[intc_state.num_pending-1]) )10.55 - sh4r.int_pending = 1;10.56 - else sh4r.int_pending = 0;10.57 + SH4_INTMASK() < PRIORITY(intc_state.pending[intc_state.num_pending-1]) ) {10.58 + sh4r.event_pending = 0;10.59 + sh4r.event_types |= PENDING_IRQ ;10.60 + }10.61 + else {10.62 + sh4r.event_pending = event_get_next_time();10.63 + sh4r.event_types &= (~PENDING_IRQ);10.64 + }10.65 }
11.1 --- a/src/sh4/sh4core.c Sat Jan 06 04:05:32 2007 +000011.2 +++ b/src/sh4/sh4core.c Sat Jan 06 04:06:36 2007 +000011.3 @@ -1,5 +1,5 @@11.4 /**11.5 - * $Id: sh4core.c,v 1.36 2007-01-03 09:00:17 nkeynes Exp $11.6 + * $Id: sh4core.c,v 1.37 2007-01-06 04:06:36 nkeynes Exp $11.7 *11.8 * SH4 emulation core, and parent module for all the SH4 peripheral11.9 * modules.11.10 @@ -58,6 +58,7 @@11.11 void sh4_stop( void );11.12 void sh4_save_state( FILE *f );11.13 int sh4_load_state( FILE *f );11.14 +static void sh4_accept_interrupt( void );11.16 struct dreamcast_module sh4_module = { "SH4", sh4_init, sh4_reset,11.17 NULL, sh4_run_slice, sh4_stop,11.18 @@ -138,24 +139,43 @@11.20 uint32_t sh4_run_slice( uint32_t nanosecs )11.21 {11.22 - int target = sh4r.icount + nanosecs / sh4_cpu_period;11.23 - int start = sh4r.icount;11.24 int i;11.25 + sh4r.slice_cycle = 0;11.27 if( sh4r.sh4_state != SH4_STATE_RUNNING ) {11.28 - if( sh4r.int_pending != 0 )11.29 - sh4r.sh4_state = SH4_STATE_RUNNING;;11.30 + if( sh4r.event_pending < nanosecs ) {11.31 + sh4r.sh4_state = SH4_STATE_RUNNING;11.32 + sh4r.slice_cycle = sh4r.event_pending;11.33 + }11.34 }11.36 if( sh4_breakpoint_count == 0 ) {11.37 - for( sh4r.slice_cycle = 0; sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) {11.38 + for( ; sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) {11.39 + if( SH4_EVENT_PENDING() ) {11.40 + if( sh4r.event_types & PENDING_EVENT ) {11.41 + event_execute();11.42 + }11.43 + /* Eventq execute may (quite likely) deliver an immediate IRQ */11.44 + if( sh4r.event_types & PENDING_IRQ ) {11.45 + sh4_accept_interrupt();11.46 + }11.47 + }11.48 if( !sh4_execute_instruction() ) {11.49 break;11.50 }11.51 }11.52 } else {11.53 -11.54 - for( sh4r.slice_cycle = 0; sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) {11.55 + for( ;sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) {11.56 + if( SH4_EVENT_PENDING() ) {11.57 + if( sh4r.event_types & PENDING_EVENT ) {11.58 + event_execute();11.59 + }11.60 + /* Eventq execute may (quite likely) deliver an immediate IRQ */11.61 + if( sh4r.event_types & PENDING_IRQ ) {11.62 + sh4_accept_interrupt();11.63 + }11.64 + }11.65 +11.66 if( !sh4_execute_instruction() )11.67 break;11.68 #ifdef ENABLE_DEBUG_MODE11.69 @@ -444,9 +464,6 @@11.70 #define FPULf *((float *)&sh4r.fpul)11.71 #define FPULi (sh4r.fpul)11.73 - if( SH4_INT_PENDING() )11.74 - sh4_accept_interrupt();11.75 -11.76 pc = sh4r.pc;11.77 if( pc > 0xFFFFFF00 ) {11.78 /* SYSCALL Magic */
12.1 --- a/src/sh4/sh4core.h Sat Jan 06 04:05:32 2007 +000012.2 +++ b/src/sh4/sh4core.h Sat Jan 06 04:06:36 2007 +000012.3 @@ -1,5 +1,5 @@12.4 /**12.5 - * $Id: sh4core.h,v 1.15 2007-01-03 09:00:17 nkeynes Exp $12.6 + * $Id: sh4core.h,v 1.16 2007-01-06 04:06:36 nkeynes Exp $12.7 *12.8 * This file defines the internal functions exported/used by the SH4 core,12.9 * except for disassembly functions defined in sh4dasm.h12.10 @@ -53,6 +53,9 @@12.11 */12.12 #define SH4_STATE_STANDBY 412.14 +#define PENDING_IRQ 112.15 +#define PENDING_EVENT 212.16 +12.17 struct sh4_registers {12.18 uint32_t r[16];12.19 uint32_t r_bank[8]; /* hidden banked registers */12.20 @@ -67,7 +70,9 @@12.22 uint32_t new_pc; /* Not a real register, but used to handle delay slots */12.23 uint32_t icount; /* Also not a real register, instruction counter */12.24 - uint32_t int_pending; /* flag set by the INTC = pending priority level */12.25 + uint32_t event_pending; /* slice cycle time of the next pending event, or FFFFFFFF12.26 + when no events are pending */12.27 + uint32_t event_types; /* bit 0 = IRQ pending, bit 1 = general event pending */12.28 int in_delay_slot; /* flag to indicate the current instruction is in12.29 * a delay slot (certain rules apply) */12.30 uint32_t slice_cycle; /* Current cycle within the timeslice */12.31 @@ -147,7 +152,7 @@12.33 #define IS_SH4_PRIVMODE() (sh4r.sr&SR_MD)12.34 #define SH4_INTMASK() ((sh4r.sr&SR_IMASK)>>4)12.35 -#define SH4_INT_PENDING() (sh4r.int_pending && !sh4r.in_delay_slot)12.36 +#define SH4_EVENT_PENDING() (sh4r.event_pending <= sh4r.slice_cycle && !sh4r.in_delay_slot)12.38 #define FPSCR_FR 0x00200000 /* FPU register bank */12.39 #define FPSCR_SZ 0x00100000 /* FPU transfer size (0=32 bits, 1=64 bits) */
.