1 //both timer functions can call eachother define them here
2 static void timer1(uint8_t reason, double sysclks);
3 static void timer2(uint8_t reason, double sysclks);
4
timer1(uint8_t reason,double sysclks)5 static void timer1(uint8_t reason, double sysclks){
6 uint16_t timer1Control = registerArrayRead16(TCTL1);
7 uint16_t timer1Compare = registerArrayRead16(TCMP1);
8 double timer1OldCount = timerCycleCounter[0];
9 double timer1Prescaler = (registerArrayRead16(TPRER1) & 0x00FF) + 1;
10 bool timer1Enabled = timer1Control & 0x0001;
11
12 if(timer1Enabled){
13 switch((timer1Control & 0x000E) >> 1){
14 case 0x0000://stop counter
15 //do nothing
16 return;
17
18 case 0x0001://SYSCLK / timer prescaler
19 if(reason != DBVZ_TIMER_REASON_SYSCLK)
20 return;
21 timerCycleCounter[0] += sysclks / timer1Prescaler;
22 break;
23
24 case 0x0002://SYSCLK / 16 / timer prescaler
25 if(reason != DBVZ_TIMER_REASON_SYSCLK)
26 return;
27 timerCycleCounter[0] += sysclks / 16.0 / timer1Prescaler;
28 break;
29
30 case 0x0003://TIN/TOUT pin / timer prescaler, the other timer can be attached to TIN/TOUT
31 if(reason != DBVZ_TIMER_REASON_TIN)
32 return;
33 timerCycleCounter[0] += 1.0 / timer1Prescaler;
34 break;
35
36 default://CLK32 / timer prescaler
37 if(reason != DBVZ_TIMER_REASON_CLK32)
38 return;
39 timerCycleCounter[0] += 1.0 / timer1Prescaler;
40 break;
41 }
42
43 if(timer1OldCount < timer1Compare && timerCycleCounter[0] >= timer1Compare){
44 //the comparison against the old value is to prevent an interrupt on every increment in free running mode
45 //the timer is not cycle accurate and may not hit the value in the compare register perfectly so check if it would have during in the emulated time
46 uint8_t pcrTinToutConfig = registerArrayRead8(PCR) & 0x03;//TIN/TOUT seems not to be physicaly connected but cascaded timers still need to be supported
47
48 //interrupt enabled
49 if(timer1Control & 0x0010)
50 setIprIsrBit(DBVZ_INT_TMR1);
51 //checkInterrupts() is run when the clock that called this function is finished
52
53 //set timer triggered bit
54 registerArrayWrite16(TSTAT1, registerArrayRead16(TSTAT1) | 0x0001);
55 timerStatusReadAcknowledge[0] &= 0xFFFE;//lock bit until next read
56
57 //increment other timer if enabled
58 if(pcrTinToutConfig == 0x03)
59 timer2(DBVZ_TIMER_REASON_TIN, 0);
60
61 //not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
62 if(!(timer1Control & 0x0100))
63 timerCycleCounter[0] -= timer1Compare;
64 }
65
66 if(timerCycleCounter[0] > 0xFFFF)
67 timerCycleCounter[0] -= 0xFFFF;
68 registerArrayWrite16(TCN1, (uint16_t)timerCycleCounter[0]);
69 }
70 }
71
timer2(uint8_t reason,double sysclks)72 static void timer2(uint8_t reason, double sysclks){
73 uint16_t timer2Control = registerArrayRead16(TCTL2);
74 uint16_t timer2Compare = registerArrayRead16(TCMP2);
75 double timer2OldCount = timerCycleCounter[1];
76 double timer2Prescaler = (registerArrayRead16(TPRER2) & 0x00FF) + 1;
77 bool timer2Enabled = timer2Control & 0x0001;
78
79 if(timer2Enabled){
80 switch((timer2Control & 0x000E) >> 1){
81 case 0x0000://stop counter
82 //do nothing
83 return;
84
85 case 0x0001://SYSCLK / timer prescaler
86 if(reason != DBVZ_TIMER_REASON_SYSCLK)
87 return;
88 timerCycleCounter[1] += sysclks / timer2Prescaler;
89 break;
90
91 case 0x0002://SYSCLK / 16 / timer prescaler
92 if(reason != DBVZ_TIMER_REASON_SYSCLK)
93 return;
94 timerCycleCounter[1] += sysclks / 16.0 / timer2Prescaler;
95 break;
96
97 case 0x0003://TIN/TOUT pin / timer prescaler, the other timer can be attached to TIN/TOUT
98 if(reason != DBVZ_TIMER_REASON_TIN)
99 return;
100 timerCycleCounter[1] += 1.0 / timer2Prescaler;
101 break;
102
103 default://CLK32 / timer prescaler
104 if(reason != DBVZ_TIMER_REASON_CLK32)
105 return;
106 timerCycleCounter[1] += 1.0 / timer2Prescaler;
107 break;
108 }
109
110 if(timer2OldCount < timer2Compare && timerCycleCounter[1] >= timer2Compare){
111 //the comparison against the old value is to prevent an interrupt on every increment in free running mode
112 //the timer is not cycle accurate and may not hit the value in the compare register perfectly so check if it would have during in the emulated time
113 uint8_t pcrTinToutConfig = registerArrayRead8(PCR) & 0x03;//TIN/TOUT seems not to be physicaly connected but cascaded timers still need to be supported
114
115 //interrupt enabled
116 if(timer2Control & 0x0010)
117 setIprIsrBit(DBVZ_INT_TMR2);
118 //checkInterrupts() is run when the clock that called this function is finished
119
120 //set timer triggered bit
121 registerArrayWrite16(TSTAT2, registerArrayRead16(TSTAT2) | 0x0001);
122 timerStatusReadAcknowledge[1] &= 0xFFFE;//lock bit until next read
123
124 //increment other timer if enabled
125 if(pcrTinToutConfig == 0x02)
126 timer1(DBVZ_TIMER_REASON_TIN, 0);
127
128 //not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
129 if(!(timer2Control & 0x0100))
130 timerCycleCounter[1] -= timer2Compare;
131 }
132
133 if(timerCycleCounter[1] > 0xFFFF)
134 timerCycleCounter[1] -= 0xFFFF;
135 registerArrayWrite16(TCN2, (uint16_t)timerCycleCounter[1]);
136 }
137 }
138
dmaclksPerClk32(void)139 static double dmaclksPerClk32(void){
140 uint16_t pllcr = registerArrayRead16(PLLCR);
141 uint16_t pllfsr = registerArrayRead16(PLLFSR);
142 uint8_t p = pllfsr & 0x00FF;
143 uint8_t q = pllfsr >> 8 & 0x000F;
144 double dmaclks = 2.0 * (14.0 * (p + 1.0) + q + 1.0);
145
146 //prescaler 1 enabled, divide by 2
147 if(pllcr & 0x0080)
148 dmaclks /= 2.0;
149
150 //prescaler 2 enabled, divides value from prescaler 1 by 2
151 if(pllcr & 0x0020)
152 dmaclks /= 2.0;
153
154 return dmaclks;
155 }
156
sysclksPerClk32(void)157 static double sysclksPerClk32(void){
158 uint8_t sysclkSelect = registerArrayRead16(PLLCR) >> 8 & 0x0007;
159
160 //>= 4 means run at full speed, no divider
161 if(sysclkSelect >= 4)
162 return dmaclksPerClk32();
163
164 //divide DMACLK by 2 to the power of PLLCR SYSCLKSEL
165 return dmaclksPerClk32() / (2 << sysclkSelect);
166 }
167
rtiInterruptClk32(void)168 static void rtiInterruptClk32(void){
169 //this function is part of endClk32();
170 uint16_t triggeredRtiInterrupts = 0x0000;
171
172 if(clk32Counter % (M5XX_CRYSTAL_FREQUENCY / 512) == 0){
173 //RIS7 - 512HZ
174 triggeredRtiInterrupts |= 0x8000;
175 }
176 if(clk32Counter % (M5XX_CRYSTAL_FREQUENCY / 256) == 0){
177 //RIS6 - 256HZ
178 triggeredRtiInterrupts |= 0x4000;
179 }
180 if(clk32Counter % (M5XX_CRYSTAL_FREQUENCY / 128) == 0){
181 //RIS5 - 128HZ
182 triggeredRtiInterrupts |= 0x2000;
183 }
184 if(clk32Counter % (M5XX_CRYSTAL_FREQUENCY / 64) == 0){
185 //RIS4 - 64HZ
186 triggeredRtiInterrupts |= 0x1000;
187 }
188 if(clk32Counter % (M5XX_CRYSTAL_FREQUENCY / 32) == 0){
189 //RIS3 - 32HZ
190 triggeredRtiInterrupts |= 0x0800;
191 }
192 if(clk32Counter % (M5XX_CRYSTAL_FREQUENCY / 16) == 0){
193 //RIS2 - 16HZ
194 triggeredRtiInterrupts |= 0x0400;
195 }
196 if(clk32Counter % (M5XX_CRYSTAL_FREQUENCY / 8) == 0){
197 //RIS1 - 8HZ
198 triggeredRtiInterrupts |= 0x0200;
199 }
200 if(clk32Counter % (M5XX_CRYSTAL_FREQUENCY / 4) == 0){
201 //RIS0 - 4HZ
202 triggeredRtiInterrupts |= 0x0100;
203 }
204
205 triggeredRtiInterrupts &= registerArrayRead16(RTCIENR);
206 if(triggeredRtiInterrupts){
207 registerArrayWrite16(RTCISR, registerArrayRead16(RTCISR) | triggeredRtiInterrupts);
208 setIprIsrBit(DBVZ_INT_RTI);
209 }
210 }
211
watchdogSecondTickClk32(void)212 static void watchdogSecondTickClk32(void){
213 //this function is part of endClk32();
214 uint16_t watchdogState = registerArrayRead16(WATCHDOG);
215
216 if(watchdogState & 0x0001){
217 //watchdog enabled
218 watchdogState += 0x0100;//add second to watchdog timer
219 watchdogState &= 0x0383;//cap overflow
220 if((watchdogState & 0x0200) == 0x0200){
221 //time expired
222 if(watchdogState & 0x0002){
223 //interrupt
224 watchdogState |= 0x0080;
225 setIprIsrBit(DBVZ_INT_WDT);
226 }
227 else{
228 //reset
229 debugLog("Watchdog reset triggered, PC:0x%08X\n", flx68000GetPc());
230 emulatorSoftReset();
231 return;
232 }
233 }
234 registerArrayWrite16(WATCHDOG, watchdogState);
235 }
236 }
237
rtcAddSecondClk32(void)238 static void rtcAddSecondClk32(void){
239 //this function is part of endClk32();
240 if(registerArrayRead16(RTCCTL) & 0x0080){
241 //RTC enable bit set
242 uint16_t rtcInterruptEvents = 0x0000;
243 uint32_t newRtcTime;
244 uint32_t oldRtcTime = registerArrayRead32(RTCTIME);
245 uint32_t rtcAlrm = registerArrayRead32(RTCALRM);
246 uint16_t dayAlrm = registerArrayRead16(DAYALRM);
247 uint16_t days = registerArrayRead16(DAYR);
248 uint8_t hours = oldRtcTime >> 24;
249 uint8_t minutes = oldRtcTime >> 16 & 0x0000003F;
250 uint8_t seconds = oldRtcTime & 0x0000003F;
251
252 if(palmSyncRtc && palmGetRtcFromHost){
253 //get new RTC value from system
254 uint16_t stopwatch = registerArrayRead16(STPWCH);
255 uint8_t alarmHours = rtcAlrm >> 24;
256 uint8_t alarmMinutes = rtcAlrm >> 16 & 0x0000003F;
257 uint8_t alarmSeconds = rtcAlrm & 0x0000003F;
258 uint8_t time[3];
259
260 palmGetRtcFromHost(time);
261
262 //day rollover happened
263 if(hours > time[0]){
264 days++;
265 rtcInterruptEvents |= 0x0008;
266 }
267
268 if(time[0] != hours)
269 rtcInterruptEvents |= 0x0020;
270
271 if(time[1] != minutes)
272 rtcInterruptEvents |= 0x0002;
273
274 if(time[2] != seconds)
275 rtcInterruptEvents |= 0x0010;
276
277 if(stopwatch != 0x003F){
278 stopwatch -= FAST_ABS(time[1] - minutes);
279
280 if(stopwatch <= 0x0000)
281 stopwatch = 0x003F;
282 registerArrayWrite16(STPWCH, stopwatch);
283 }
284
285 //if stopwatch ran out above or was enabled with 0x003F in the register trigger interrupt
286 if(stopwatch == 0x003F)
287 rtcInterruptEvents |= 0x0001;
288
289 newRtcTime = time[2];//seconds
290 newRtcTime |= time[1] << 16;//minutes
291 newRtcTime |= time[0] << 24;//hours
292
293 //check alarm range to see if it triggered in the time that has passed
294 if(days == dayAlrm){
295 if(hours < alarmHours || hours == alarmHours && minutes < alarmMinutes || hours == alarmHours && minutes == alarmMinutes && seconds < alarmSeconds){
296 //old time is before alarm
297 if(time[0] > alarmHours || time[0] == alarmHours && time[1] > alarmMinutes || time[0] == alarmHours && time[1] == alarmMinutes && time[0] >= alarmSeconds){
298 //new time is after alarm
299 rtcInterruptEvents |= 0x0040;
300 }
301 }
302 }
303 }
304 else{
305 //standard frame based time increment
306
307 seconds++;
308 rtcInterruptEvents |= 0x0010;
309 if(seconds >= 60){
310 uint16_t stopwatch = registerArrayRead16(STPWCH);
311
312 if(stopwatch != 0x003F){
313 if(stopwatch == 0x0000)
314 stopwatch = 0x003F;
315 else
316 stopwatch--;
317 registerArrayWrite16(STPWCH, stopwatch);
318 }
319
320 //if stopwatch ran out above or was enabled with 0x003F in the register trigger interrupt
321 if(stopwatch == 0x003F)
322 rtcInterruptEvents |= 0x0001;
323
324 minutes++;
325 seconds = 0;
326 rtcInterruptEvents |= 0x0002;
327 if(minutes >= 60){
328 hours++;
329 minutes = 0;
330 rtcInterruptEvents |= 0x0020;
331 if(hours >= 24){
332 hours = 0;
333 days++;
334 rtcInterruptEvents |= 0x0008;
335 }
336 }
337 }
338
339 newRtcTime = seconds;
340 newRtcTime |= minutes << 16;
341 newRtcTime |= hours << 24;
342
343 if(newRtcTime == rtcAlrm && days == dayAlrm)
344 rtcInterruptEvents |= 0x0040;
345 }
346
347 rtcInterruptEvents &= registerArrayRead16(RTCIENR);
348 if(rtcInterruptEvents){
349 registerArrayWrite16(RTCISR, registerArrayRead16(RTCISR) | rtcInterruptEvents);
350 setIprIsrBit(DBVZ_INT_RTC);
351 }
352
353 registerArrayWrite32(RTCTIME, newRtcTime);
354 registerArrayWrite16(DAYR, days & 0x01FF);
355 }
356
357 watchdogSecondTickClk32();
358 }
359
dbvzBeginClk32(void)360 static void dbvzBeginClk32(void){
361 dbvzClk32Sysclks = 0.0;
362 }
363
dbvzEndClk32(void)364 static void dbvzEndClk32(void){
365 //second position counter
366 if(clk32Counter >= M5XX_CRYSTAL_FREQUENCY - 1){
367 clk32Counter = 0;
368 rtcAddSecondClk32();
369 }
370 else{
371 clk32Counter++;
372 }
373
374 //disabled if both the watchdog timer AND the RTC timer are disabled
375 if(registerArrayRead16(RTCCTL) & 0x0080 || registerArrayRead16(WATCHDOG) & 0x01)
376 rtiInterruptClk32();
377
378 timer1(DBVZ_TIMER_REASON_CLK32, 0);
379 timer2(DBVZ_TIMER_REASON_CLK32, 0);
380 samplePwm1(true/*forClk32*/, 0.0);
381
382 //PLLCR sleep wait
383 if(pllSleepWait != -1){
384 if(pllSleepWait == 0){
385 //disable PLL and CPU
386 dbvzSysclksPerClk32 = 0.0;
387 debugLog("PLL disabled, CPU is off!\n");
388 }
389 pllSleepWait--;
390 }
391
392 //PLLCR wake select wait
393 if(pllWakeWait != -1){
394 if(pllWakeWait == 0){
395 //reenable PLL and CPU
396 registerArrayWrite16(PLLCR, registerArrayRead16(PLLCR) & 0xFFF7);
397 dbvzSysclksPerClk32 = sysclksPerClk32();
398 debugLog("PLL reenabled, CPU is on!\n");
399 }
400 pllWakeWait--;
401 }
402
403 //UART1/2, these are polled to remain thread safe
404 updateUart1Interrupt();
405 updateUart2Interrupt();
406
407 checkInterrupts();
408 }
409
dbvzAddSysclks(double count)410 static void dbvzAddSysclks(double count){
411 timer1(DBVZ_TIMER_REASON_SYSCLK, count);
412 timer2(DBVZ_TIMER_REASON_SYSCLK, count);
413 samplePwm1(false/*forClk32*/, count);
414
415 checkInterrupts();
416 dbvzClk32Sysclks += count;
417 }
418
audioGetFramePercentIncrementFromClk32s(int32_t count)419 static int32_t audioGetFramePercentIncrementFromClk32s(int32_t count){
420 return (double)count / ((double)M5XX_CRYSTAL_FREQUENCY / EMU_FPS) * DBVZ_AUDIO_END_OF_FRAME;
421 }
422
audioGetFramePercentIncrementFromSysclks(double count)423 static int32_t audioGetFramePercentIncrementFromSysclks(double count){
424 return count / (dbvzSysclksPerClk32 * ((double)M5XX_CRYSTAL_FREQUENCY / EMU_FPS)) * DBVZ_AUDIO_END_OF_FRAME;
425 }
426
audioGetFramePercentage(void)427 static int32_t audioGetFramePercentage(void){
428 //returns how much of the frame has executed
429 //0% = 0, 100% = DBVZ_AUDIO_END_OF_FRAME
430 return audioGetFramePercentIncrementFromClk32s(dbvzFrameClk32s) + (dbvzIsPllOn() ? audioGetFramePercentIncrementFromSysclks(dbvzClk32Sysclks) : 0);
431 }
432