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;