2 // System time handlers
8 // - Handling for an event that occurs NOW
15 #define EVENT_LIST_SIZE 512
18 // Current execution path:
26 for(int i=0; i<numLines; i++)
41 // What we need to do:
43 Set up timers (frame [for native render--on vblank interval?], OP line, PITs)
47 double timeToNextEvent = GetTimeToNextEvent();
49 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
50 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
51 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
60 // Now, a bit of weirdness: It seems that the number of lines displayed on the screen
61 // makes the effective refresh rate either 30 or 25 Hz!
63 // NOTE ABOUT TIMING SYSTEM DATA STRUCTURES:
65 // A queue won't work for this system because we can't guarantee that an event will go
66 // in with a time that is later than the ones already queued up. So we just use a simple
69 // Although if we used an insertion sort we could, but it wouldn't work for adjusting
76 void (* timerCallback)(void);
79 Event eventList[EVENT_LIST_SIZE];
82 void InitializeEventList(void)
84 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
85 eventList[i].valid = false;
88 //We just slap the next event into the list, no checking, no nada...
89 void SetCallbackTime(void (* callback)(void), double time)
91 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
93 if (!eventList[i].valid)
95 //WriteLog("SCT: Found callback slot #%u...\n", i);
96 eventList[i].timerCallback = callback;
97 eventList[i].eventTime = time;
98 eventList[i].valid = true;
104 WriteLog("SetCallbackTime() failed to find an empty slot in the list!\n");
107 void RemoveCallback(void (* callback)(void))
109 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
111 if (eventList[i].valid && eventList[i].timerCallback == callback)
113 eventList[i].valid = false;
120 void AdjustCallbackTime(void (* callback)(void), double time)
122 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
124 if (eventList[i].valid && eventList[i].timerCallback == callback)
126 eventList[i].eventTime = time;
133 double GetTimeToNextEvent(void)
136 bool firstTime = true;
138 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
140 if (eventList[i].valid)
143 time = eventList[i].eventTime, nextEvent = i, firstTime = false;
146 if (eventList[i].eventTime < time)
147 time = eventList[i].eventTime, nextEvent = i;
155 void HandleNextEvent(void)
157 double elapsedTime = eventList[nextEvent].eventTime;
158 void (* event)(void) = eventList[nextEvent].timerCallback;
160 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
161 if (eventList[i].valid)
162 eventList[i].eventTime -= elapsedTime;
164 eventList[nextEvent].valid = false; // Remove event from list...
171 void OPCallback(void)
173 DoFunkyOPStuffHere();
175 SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
178 void VICallback(void)
180 double oneFrameInUsec = 16666.66666666;
181 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
184 void JaguarInit(void)
186 double oneFrameInUsec = 16666.66666666;
187 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
188 SetCallbackTime(OPCallback, );
191 void JaguarExec(void)
195 double timeToNextEvent = GetTimeToNextEvent();
197 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
198 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
199 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
201 if (!HandleNextEvent())
206 // NOTES: The timers count RISC cycles, and when the dividers count down to zero they can interrupt either the DSP and/or CPU.
209 // TOM Programmable Interrupt Timer handler
210 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
211 // The PIT only generates an interrupt when it counts down to zero, not when loaded!
215 // Need to remove previous timer from the queue, if it exists...
216 RemoveCallback(TOMPITCallback);
220 double usecs = (TOMPITPrescaler + 1) * (TOMPITDivider + 1) * RISC_CYCLE_IN_USEC;
221 SetCallbackTime(TOMPITCallback, usecs);
225 void TOMPITCallback(void)
227 INT1_RREG |= 0x08; // Set TOM PIT interrupt pending
228 GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking
230 if (INT1_WREG & 0x08)
231 m68k_set_irq(7); // Generate 68K NMI
236 // Small problem with this approach: If a timer interrupt is already pending,
237 // the pending timer needs to be replaced with the new one! (Taken care of above, BTW...)
239 TOMWriteWord(uint32 address, uint16 data)
243 TOMPITPrescaler = data;
246 else if (address == PIT1)
248 TOMPITDivider = data;