2 // System time handlers
5 // (C) 2010 Underground Software
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- -------------------------------------------------------------
11 // JLH 01/16/2010 Created this log ;-)
17 // - Handling for an event that occurs NOW
24 #define EVENT_LIST_SIZE 512
27 // Current execution path:
35 for(int i=0; i<numLines; i++)
50 // What we need to do:
52 Set up timers (frame [for native render--on vblank interval?], OP line, PITs)
56 double timeToNextEvent = GetTimeToNextEvent();
58 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
59 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
60 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
69 // Now, a bit of weirdness: It seems that the number of lines displayed on the screen
70 // makes the effective refresh rate either 30 or 25 Hz!
72 // NOTE ABOUT TIMING SYSTEM DATA STRUCTURES:
74 // A queue won't work for this system because we can't guarantee that an event will go
75 // in with a time that is later than the ones already queued up. So we just use a simple
78 // Although if we used an insertion sort we could, but it wouldn't work for adjusting
85 void (* timerCallback)(void);
88 Event eventList[EVENT_LIST_SIZE];
91 void InitializeEventList(void)
93 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
94 eventList[i].valid = false;
97 //We just slap the next event into the list, no checking, no nada...
98 void SetCallbackTime(void (* callback)(void), double time)
100 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
102 if (!eventList[i].valid)
104 //WriteLog("SCT: Found callback slot #%u...\n", i);
105 eventList[i].timerCallback = callback;
106 eventList[i].eventTime = time;
107 eventList[i].valid = true;
113 WriteLog("SetCallbackTime() failed to find an empty slot in the list!\n");
116 void RemoveCallback(void (* callback)(void))
118 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
120 if (eventList[i].valid && eventList[i].timerCallback == callback)
122 eventList[i].valid = false;
129 void AdjustCallbackTime(void (* callback)(void), double time)
131 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
133 if (eventList[i].valid && eventList[i].timerCallback == callback)
135 eventList[i].eventTime = time;
142 double GetTimeToNextEvent(void)
145 bool firstTime = true;
147 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
149 if (eventList[i].valid)
152 time = eventList[i].eventTime, nextEvent = i, firstTime = false;
155 if (eventList[i].eventTime < time)
156 time = eventList[i].eventTime, nextEvent = i;
164 void HandleNextEvent(void)
166 double elapsedTime = eventList[nextEvent].eventTime;
167 void (* event)(void) = eventList[nextEvent].timerCallback;
169 for(uint32 i=0; i<EVENT_LIST_SIZE; i++)
170 if (eventList[i].valid)
171 eventList[i].eventTime -= elapsedTime;
173 eventList[nextEvent].valid = false; // Remove event from list...
180 void OPCallback(void)
182 DoFunkyOPStuffHere();
184 SetCallbackTime(OPCallback, HORIZ_PERIOD_IN_USEC);
187 void VICallback(void)
189 double oneFrameInUsec = 16666.66666666;
190 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
193 void JaguarInit(void)
195 double oneFrameInUsec = 16666.66666666;
196 SetCallbackTime(VICallback, oneFrameInUsec / numberOfLines);
197 SetCallbackTime(OPCallback, );
200 void JaguarExec(void)
204 double timeToNextEvent = GetTimeToNextEvent();
206 m68k_execute(USEC_TO_M68K_CYCLES(timeToNextEvent));
207 GPUExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
208 DSPExec(USEC_TO_RISC_CYCLES(timeToNextEvent));
210 if (!HandleNextEvent())
215 // NOTES: The timers count RISC cycles, and when the dividers count down to zero they can interrupt either the DSP and/or CPU.
218 // TOM Programmable Interrupt Timer handler
219 // NOTE: TOM's PIT is only enabled if the prescaler is != 0
220 // The PIT only generates an interrupt when it counts down to zero, not when loaded!
224 // Need to remove previous timer from the queue, if it exists...
225 RemoveCallback(TOMPITCallback);
229 double usecs = (TOMPITPrescaler + 1) * (TOMPITDivider + 1) * RISC_CYCLE_IN_USEC;
230 SetCallbackTime(TOMPITCallback, usecs);
234 void TOMPITCallback(void)
236 INT1_RREG |= 0x08; // Set TOM PIT interrupt pending
237 GPUSetIRQLine(GPUIRQ_TIMER, ASSERT_LINE); // It does the 'IRQ enabled' checking
239 if (INT1_WREG & 0x08)
240 m68k_set_irq(2); // Generate 68K NMI
245 // Small problem with this approach: If a timer interrupt is already pending,
246 // the pending timer needs to be replaced with the new one! (Taken care of above, BTW...)
248 TOMWriteWord(uint32 address, uint16 data)
252 TOMPITPrescaler = data;
255 else if (address == PIT1)
257 TOMPITDivider = data;