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 OPCallback(void)
181 DoFunkyOPStuffHere();
183 SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
186 void VICallback(void)
188 double oneFrameInUsec = 16666.66666666;
189 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
192 void JaguarInit(void)
194 double oneFrameInUsec = 16666.66666666;
195 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
196 SetCallbackTime(OPCallback, );
199 void JaguarExec(void)
203 double timeToNextEvent = GetTimeToNextEvent();
205 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
206 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
207 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
209 if (!HandleNextEvent())
214 // NOTES: The timers count RISC cycles, and when the dividers count down to zero they can interrupt either the DSP and/or CPU.
217 // TOM Programmable Interrupt Timer handler
218 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
219 // The PIT only generates an interrupt when it counts down to zero, not when loaded!
223 // Need to remove previous timer from the queue, if it exists...
224 RemoveCallback(TOMPITCallback);
228 double usecs = (TOMPITPrescaler + 1) * (TOMPITDivider + 1) * RISC_CYCLE_IN_USEC;
229 SetCallbackTime(TOMPITCallback, usecs);
233 void TOMPITCallback(void)
235 INT1_RREG |= 0x08; // Set TOM PIT interrupt pending
236 GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking
238 if (INT1_WREG & 0x08)
239 m68k_set_irq(7); // Generate 68K NMI
244 // Small problem with this approach: If a timer interrupt is already pending,
245 // the pending timer needs to be replaced with the new one! (Taken care of above, BTW...)
247 TOMWriteWord(uint32 address, uint16 data)
251 TOMPITPrescaler = data;
254 else if (address == PIT1)
256 TOMPITDivider = data;