2 // System time handlers
8 // - Handling for an event that occurs NOW
13 //#include "SDL_opengl.h"
18 //#include "settings.h"
23 #define EVENT_LIST_SIZE 512
26 // Current execution path:
34 for(int i=0; i<numLines; i++)
49 // What we need to do:
51 Set up timers (frame [for native render--on vblank interval?], OP line, PITs)
55 double timeToNextEvent = GetTimeToNextEvent();
57 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
58 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
59 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
68 // Now, a bit of weirdness: It seems that the number of lines displayed on the screen
69 // makes the effective refresh rate either 30 or 25 Hz!
71 // NOTE ABOUT TIMING SYSTEM DATA STRUCTURES:
73 // A queue won't work for this system because we can't guarantee that an event will go
74 // in with a time that is later than the ones already queued up. So we just use a simple
77 // Although if we used an insertion sort we could, but it wouldn't work for adjusting
84 void (* timerCallback)(void);
87 Event eventList[EVENT_LIST_SIZE];
90 void InitializeEventList(void)
92 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
93 eventList[i].valid = false;
96 //We just slap the next event into the list, no checking, no nada...
97 void SetCallbackTime(void (* callback)(void), double time)
99 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
101 if (!eventList[i].valid)
103 //WriteLog("SCT: Found callback slot #%u...\n", i);
104 eventList[i].timerCallback = callback;
105 eventList[i].eventTime = time;
106 eventList[i].valid = true;
112 WriteLog("SetCallbackTime() failed to find an empty slot in the list!\n");
115 void RemoveCallback(void (* callback)(void))
117 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
119 if (eventList[i].valid && eventList[i].timerCallback == callback)
121 eventList[i].valid = false;
128 void AdjustCallbackTime(void (* callback)(void), double time)
130 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
132 if (eventList[i].valid && eventList[i].timerCallback == callback)
134 eventList[i].eventTime = time;
141 double GetTimeToNextEvent(void)
144 bool firstTime = true;
146 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
148 if (eventList[i].valid)
151 time = eventList[i].eventTime, nextEvent = i, firstTime = false;
154 if (eventList[i].eventTime < time)
155 time = eventList[i].eventTime, nextEvent = i;
163 void HandleNextEvent(void)
165 double elapsedTime = eventList[nextEvent].eventTime;
166 void (* event)(void) = eventList[nextEvent].timerCallback;
168 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
169 if (eventList[i].valid)
170 eventList[i].eventTime -= elapsedTime;
172 eventList[nextEvent].valid = false; // Remove event from list...
179 /*void clock_reset(void)
183 void clock_init(void)
188 void clock_done(void)
192 void clock_byte_write(uint32 offset, uint8 data)
196 void clock_word_write(uint32 offset, uint16 data)
200 uint8 clock_byte_read(uint32 offset)
205 uint16 clock_word_read(uint32 offset)
212 void OPCallback(void)
214 DoFunkyOPStuffHere();
216 SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
219 void VICallback(void)
221 double oneFrameInUsec = 16666.66666666;
222 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
225 void JaguarInit(void)
227 double oneFrameInUsec = 16666.66666666;
228 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
229 SetCallbackTime(OPCallback, );
232 void JaguarExec(void)
236 double timeToNextEvent = GetTimeToNextEvent();
238 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
239 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
240 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
242 if (!HandleNextEvent())
247 // NOTES: The timers count RISC cycles, and when the dividers count down to zero they can interrupt either the DSP and/or CPU.
250 // TOM Programmable Interrupt Timer handler
251 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
252 // The PIT only generates an interrupt when it counts down to zero, not when loaded!
256 // Need to remove previous timer from the queue, if it exists...
257 RemoveCallback(TOMPITCallback);
261 double usecs = (TOMPITPrescaler + 1) * (TOMPITDivider + 1) * RISC_CYCLE_IN_USEC;
262 SetCallbackTime(TOMPITCallback, usecs);
266 void TOMPITCallback(void)
268 INT1_RREG |= 0x08; // Set TOM PIT interrupt pending
269 GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking
271 if (INT1_WREG & 0x08)
272 m68k_set_irq(7); // Generate 68K NMI
277 // Small problem with this approach: If a timer interrupt is already pending,
278 // the pending timer needs to be replaced with the new one! (Taken care of above, BTW...)
280 TOMWriteWord(uint32 address, uint16 data)
284 TOMPITPrescaler = data;
287 else if (address == PIT1)
289 TOMPITDivider = data;