2 // System time handlers
5 // (C) 2010 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- -------------------------------------------------------------
11 // JLH 01/16/2010 Created this log ;-)
17 // - Handling for an event that occurs NOW
26 //#define EVENT_LIST_SIZE 512
27 #define EVENT_LIST_SIZE 32
30 // Now, a bit of weirdness: It seems that the number of lines displayed on the screen
31 // makes the effective refresh rate either 30 or 25 Hz!
33 // NOTE ABOUT TIMING SYSTEM DATA STRUCTURES:
35 // A queue won't work for this system because we can't guarantee that an event will go
36 // in with a time that is later than the ones already queued up. So we just use a simple
39 // Although if we used an insertion sort we could, but it wouldn't work for adjusting
40 // times... (For that, you would have to remove the event then reinsert it.)
47 void (* timerCallback)(void);
51 static Event eventList[EVENT_LIST_SIZE];
52 static Event eventListJERRY[EVENT_LIST_SIZE];
53 static uint32_t nextEvent;
54 static uint32_t nextEventJERRY;
55 static uint32_t numberOfEvents;
58 void InitializeEventList(void)
60 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
62 eventList[i].valid = false;
63 eventListJERRY[i].valid = false;
67 WriteLog("EVENT: Cleared event list.\n");
71 // Set callback time in µs. This is fairly arbitrary, but works well enough for our purposes.
72 //We just slap the next event into the list in the first available slot, no checking, no nada...
73 void SetCallbackTime(void (* callback)(void), double time, int type/*= EVENT_MAIN*/)
75 if (type == EVENT_MAIN)
77 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
79 if (!eventList[i].valid)
81 //WriteLog("EVENT: Found callback slot #%u...\n", i);
82 eventList[i].timerCallback = callback;
83 eventList[i].eventTime = time;
84 eventList[i].eventType = type;
85 eventList[i].valid = true;
92 WriteLog("EVENT: SetCallbackTime() failed to find an empty slot in the main list (%u events)!\n", numberOfEvents);
96 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
98 if (!eventListJERRY[i].valid)
100 //WriteLog("EVENT: Found callback slot #%u...\n", i);
101 eventListJERRY[i].timerCallback = callback;
102 eventListJERRY[i].eventTime = time;
103 eventListJERRY[i].eventType = type;
104 eventListJERRY[i].valid = true;
111 WriteLog("EVENT: SetCallbackTime() failed to find an empty slot in the main list (%u events)!\n", numberOfEvents);
116 void RemoveCallback(void (* callback)(void))
118 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
120 if (eventList[i].valid && eventList[i].timerCallback == callback)
122 eventList[i].valid = false;
127 else if (eventListJERRY[i].valid && eventListJERRY[i].timerCallback == callback)
129 eventListJERRY[i].valid = false;
138 void AdjustCallbackTime(void (* callback)(void), double time)
140 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
142 if (eventList[i].valid && eventList[i].timerCallback == callback)
144 eventList[i].eventTime = time;
148 else if (eventListJERRY[i].valid && eventListJERRY[i].timerCallback == callback)
150 eventListJERRY[i].eventTime = time;
159 // Since our list is unordered WRT time, we have to search it to find the next event
160 // Returns time to next event & sets nextEvent to that event
162 double GetTimeToNextEvent(int type/*= EVENT_MAIN*/)
166 bool firstTime = true;
168 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
170 if (eventList[i].valid)
173 time = eventList[i].eventTime, nextEvent = i, firstTime = false;
176 if (eventList[i].eventTime < time)
177 time = eventList[i].eventTime, nextEvent = i;
182 if (type == EVENT_MAIN)
184 double time = eventList[0].eventTime;
187 for(uint32_t i=1; i<EVENT_LIST_SIZE; i++)
189 if (eventList[i].valid && (eventList[i].eventTime < time))
191 time = eventList[i].eventTime;
200 double time = eventListJERRY[0].eventTime;
203 for(uint32_t i=1; i<EVENT_LIST_SIZE; i++)
205 if (eventListJERRY[i].valid && (eventListJERRY[i].eventTime < time))
207 time = eventListJERRY[i].eventTime;
218 void HandleNextEvent(int type/*= EVENT_MAIN*/)
220 if (type == EVENT_MAIN)
222 double elapsedTime = eventList[nextEvent].eventTime;
223 void (* event)(void) = eventList[nextEvent].timerCallback;
225 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
227 //We can skip the check & just subtract from everything, since the check is probably
228 //just as heavy as the code after and we won't use the elapsed time from an invalid event anyway.
229 // if (eventList[i].valid)
230 eventList[i].eventTime -= elapsedTime;
233 eventList[nextEvent].valid = false; // Remove event from list...
240 double elapsedTime = eventListJERRY[nextEventJERRY].eventTime;
241 void (* event)(void) = eventListJERRY[nextEventJERRY].timerCallback;
243 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
245 //We can skip the check & just subtract from everything, since the check is probably
246 //just as heavy as the code after and we won't use the elapsed time from an invalid event anyway.
247 // if (eventList[i].valid)
248 eventListJERRY[i].eventTime -= elapsedTime;
251 eventListJERRY[nextEventJERRY].valid = false; // Remove event from list...
260 void OPCallback(void)
262 DoFunkyOPStuffHere();
264 SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
267 void VICallback(void)
269 double oneFrameInUsec = 16666.66666666;
270 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
273 void JaguarInit(void)
275 double oneFrameInUsec = 16666.66666666;
276 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
277 SetCallbackTime(OPCallback, );
280 void JaguarExec(void)
284 double timeToNextEvent = GetTimeToNextEvent();
286 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
287 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
288 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
290 if (!HandleNextEvent())
295 // NOTES: The timers count RISC cycles, and when the dividers count down to zero they can interrupt either the DSP and/or CPU.
298 // TOM Programmable Interrupt Timer handler
299 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
300 // The PIT only generates an interrupt when it counts down to zero, not when loaded!
304 // Need to remove previous timer from the queue, if it exists...
305 RemoveCallback(TOMPITCallback);
309 double usecs = (TOMPITPrescaler + 1) * (TOMPITDivider + 1) * RISC_CYCLE_IN_USEC;
310 SetCallbackTime(TOMPITCallback, usecs);
314 void TOMPITCallback(void)
316 INT1_RREG |= 0x08; // Set TOM PIT interrupt pending
317 GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking
319 if (INT1_WREG & 0x08)
320 m68k_set_irq(2); // Generate 68K NMI
325 // Small problem with this approach: If a timer interrupt is already pending,
326 // the pending timer needs to be replaced with the new one! (Taken care of above, BTW...)
328 TOMWriteWord(uint32 address, uint16 data)
332 TOMPITPrescaler = data;
335 else if (address == PIT1)
337 TOMPITDivider = data;