]> Shamusworld >> Repos - virtualjaguar/blob - src/event.cpp
6951d16fc32fc679db7278dd6b13b668baa8f567
[virtualjaguar] / src / event.cpp
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...
41
42 struct Event
43 {
44         bool valid;
45         int eventType;
46         double eventTime;
47         void (* timerCallback)(void);
48 };
49
50
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;
56
57
58 void 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...
73 void 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
116 void 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
138 void 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 //
162 double 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
218 void 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 /*
260 void OPCallback(void)
261 {
262         DoFunkyOPStuffHere();
263
264         SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
265 }
266
267 void VICallback(void)
268 {
269         double oneFrameInUsec = 16666.66666666;
270         SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
271 }
272
273 void JaguarInit(void)
274 {
275         double oneFrameInUsec = 16666.66666666;
276         SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
277         SetCallbackTime(OPCallback, );
278 }
279
280 void 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
302 void 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
314 void 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
328 TOMWriteWord(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 */