Allow the src\m68000\obj directory in the repository
[clinton/Virtual-Jaguar-Rx.git] / src / event.cpp
CommitLineData
cf76e892
JPM
1//
2// System time handlers
3//
4// by James Hammons
5// (C) 2010 Underground Software
6//
7// JLH = James Hammons <jlhamm@acm.org>
8//
9// Who When What
10// --- ---------- -------------------------------------------------------------
11// JLH 01/16/2010 Created this log ;-)
12//
13
14//
15// STILL TO DO:
16//
17// - Handling for an event that occurs NOW
18//
19
20#include "event.h"
21
22#include <stdint.h>
23#include "log.h"
24
25
26//#define EVENT_LIST_SIZE 512
27#define EVENT_LIST_SIZE 32
28
29
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!
32
33// NOTE ABOUT TIMING SYSTEM DATA STRUCTURES:
34
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
37// list.
38
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.)
41
42struct Event
43{
44 bool valid;
45 int eventType;
46 double eventTime;
47 void (* timerCallback)(void);
48};
49
50
51static Event eventList[EVENT_LIST_SIZE];
52static Event eventListJERRY[EVENT_LIST_SIZE];
53static uint32_t nextEvent;
54static uint32_t nextEventJERRY;
55static uint32_t numberOfEvents;
56
57
58void InitializeEventList(void)
59{
60 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
61 {
62 eventList[i].valid = false;
63 eventListJERRY[i].valid = false;
64 }
65
66 numberOfEvents = 0;
67 WriteLog("EVENT: Cleared event list.\n");
68}
69
70
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...
73void SetCallbackTime(void (* callback)(void), double time, int type/*= EVENT_MAIN*/)
74{
75 if (type == EVENT_MAIN)
76 {
77 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
78 {
79 if (!eventList[i].valid)
80 {
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;
86 numberOfEvents++;
87
88 return;
89 }
90 }
91
92 WriteLog("EVENT: SetCallbackTime() failed to find an empty slot in the main list (%u events)!\n", numberOfEvents);
93 }
94 else
95 {
96 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
97 {
98 if (!eventListJERRY[i].valid)
99 {
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;
105 numberOfEvents++;
106
107 return;
108 }
109 }
110
111 WriteLog("EVENT: SetCallbackTime() failed to find an empty slot in the main list (%u events)!\n", numberOfEvents);
112 }
113}
114
115
116void RemoveCallback(void (* callback)(void))
117{
118 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
119 {
120 if (eventList[i].valid && eventList[i].timerCallback == callback)
121 {
122 eventList[i].valid = false;
123 numberOfEvents--;
124
125 return;
126 }
127 else if (eventListJERRY[i].valid && eventListJERRY[i].timerCallback == callback)
128 {
129 eventListJERRY[i].valid = false;
130 numberOfEvents--;
131
132 return;
133 }
134 }
135}
136
137
138void AdjustCallbackTime(void (* callback)(void), double time)
139{
140 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
141 {
142 if (eventList[i].valid && eventList[i].timerCallback == callback)
143 {
144 eventList[i].eventTime = time;
145
146 return;
147 }
148 else if (eventListJERRY[i].valid && eventListJERRY[i].timerCallback == callback)
149 {
150 eventListJERRY[i].eventTime = time;
151
152 return;
153 }
154 }
155}
156
157
158//
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
161//
162double GetTimeToNextEvent(int type/*= EVENT_MAIN*/)
163{
164#if 0
165 double time = 0;
166 bool firstTime = true;
167
168 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
169 {
170 if (eventList[i].valid)
171 {
172 if (firstTime)
173 time = eventList[i].eventTime, nextEvent = i, firstTime = false;
174 else
175 {
176 if (eventList[i].eventTime < time)
177 time = eventList[i].eventTime, nextEvent = i;
178 }
179 }
180 }
181#else
182 if (type == EVENT_MAIN)
183 {
184 double time = eventList[0].eventTime;
185 nextEvent = 0;
186
187 for(uint32_t i=1; i<EVENT_LIST_SIZE; i++)
188 {
189 if (eventList[i].valid && (eventList[i].eventTime < time))
190 {
191 time = eventList[i].eventTime;
192 nextEvent = i;
193 }
194 }
195
196 return time;
197 }
198 else
199 {
200 double time = eventListJERRY[0].eventTime;
201 nextEventJERRY = 0;
202
203 for(uint32_t i=1; i<EVENT_LIST_SIZE; i++)
204 {
205 if (eventListJERRY[i].valid && (eventListJERRY[i].eventTime < time))
206 {
207 time = eventListJERRY[i].eventTime;
208 nextEventJERRY = i;
209 }
210 }
211
212 return time;
213 }
214#endif
215}
216
217
218void HandleNextEvent(int type/*= EVENT_MAIN*/)
219{
220 if (type == EVENT_MAIN)
221 {
222 double elapsedTime = eventList[nextEvent].eventTime;
223 void (* event)(void) = eventList[nextEvent].timerCallback;
224
225 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
226 {
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;
231 }
232
233 eventList[nextEvent].valid = false; // Remove event from list...
234 numberOfEvents--;
235
236 (*event)();
237 }
238 else
239 {
240 double elapsedTime = eventListJERRY[nextEventJERRY].eventTime;
241 void (* event)(void) = eventListJERRY[nextEventJERRY].timerCallback;
242
243 for(uint32_t i=0; i<EVENT_LIST_SIZE; i++)
244 {
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;
249 }
250
251 eventListJERRY[nextEventJERRY].valid = false; // Remove event from list...
252 numberOfEvents--;
253
254 (*event)();
255 }
256}
257
258
259/*
260void OPCallback(void)
261{
262 DoFunkyOPStuffHere();
263
264 SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
265}
266
267void VICallback(void)
268{
269 double oneFrameInUsec = 16666.66666666;
270 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
271}
272
273void JaguarInit(void)
274{
275 double oneFrameInUsec = 16666.66666666;
276 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
277 SetCallbackTime(OPCallback, );
278}
279
280void JaguarExec(void)
281{
282 while (true)
283 {
284 double timeToNextEvent = GetTimeToNextEvent();
285
286 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
287 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
288 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
289
290 if (!HandleNextEvent())
291 break;
292 }
293}
294
295// NOTES: The timers count RISC cycles, and when the dividers count down to zero they can interrupt either the DSP and/or CPU.
296
297// NEW:
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!
301
302void TOMResetPIT()
303{
304 // Need to remove previous timer from the queue, if it exists...
305 RemoveCallback(TOMPITCallback);
306
307 if (TOMPITPrescaler)
308 {
309 double usecs = (TOMPITPrescaler + 1) * (TOMPITDivider + 1) * RISC_CYCLE_IN_USEC;
310 SetCallbackTime(TOMPITCallback, usecs);
311 }
312}
313
314void TOMPITCallback(void)
315{
316 INT1_RREG |= 0x08; // Set TOM PIT interrupt pending
317 GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking
318
319 if (INT1_WREG & 0x08)
320 m68k_set_irq(2); // Generate 68K NMI
321
322 TOMResetPIT();
323}
324
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...)
327
328TOMWriteWord(uint32 address, uint16 data)
329{
330 if (address == PIT0)
331 {
332 TOMPITPrescaler = data;
333 TOMResetPIT();
334 }
335 else if (address == PIT1)
336 {
337 TOMPITDivider = data;
338 TOMResetPIT();
339 }
340}
341
342*/