1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <string.h>
4
5 #include "dbvz.h"
6 #include "emulator.h"
7 #include "m5XXBus.h"
8 #include "portability.h"
9 #include "flx68000.h"
10 #include "ads7846.h"
11 #include "sdCard.h"
12 #include "sed1376.h"
13 #include "audio/blip_buf.h"
14 #include "m68k/m68k.h"
15
16
17 #include "dbvzRegisterNames.c.h"
18
19
20 dbvz_chip_t dbvzChipSelects[DBVZ_CHIP_END];
21 uint8_t dbvzReg[DBVZ_REG_SIZE];
22 uint16_t* dbvzFramebuffer;
23 uint16_t dbvzFramebufferWidth;
24 uint16_t dbvzFramebufferHeight;
25
26 static double dbvzSysclksPerClk32;//how many SYSCLK cycles before toggling the 32.768 kHz crystal
27 static uint32_t dbvzFrameClk32s;//how many CLK32s have happened in the current frame
28 static double dbvzClk32Sysclks;//how many SYSCLKs have happened in the current CLK32
29 static int8_t pllSleepWait;
30 static int8_t pllWakeWait;
31 static uint32_t clk32Counter;
32 static double pctlrCpuClockDivider;
33 static double timerCycleCounter[2];
34 static uint16_t timerStatusReadAcknowledge[2];
35 static uint8_t portDInterruptLastValue;//used for edge triggered interrupt timing
36 static uint16_t spi1RxFifo[9];
37 static uint16_t spi1TxFifo[9];
38 static uint8_t spi1RxReadPosition;
39 static uint8_t spi1RxWritePosition;
40 static bool spi1RxOverflowed;
41 static uint8_t spi1TxReadPosition;
42 static uint8_t spi1TxWritePosition;
43 static int32_t pwm1ClocksToNextSample;
44 static uint8_t pwm1Fifo[6];
45 static uint8_t pwm1ReadPosition;
46 static uint8_t pwm1WritePosition;
47
48
49 static void checkInterrupts(void);
50 static void checkPortDInterrupts(void);
51 static void pllWakeCpuIfOff(void);
52 static double sysclksPerClk32(void);
53 static int32_t audioGetFramePercentIncrementFromClk32s(int32_t count);
54 static int32_t audioGetFramePercentIncrementFromSysclks(double count);
55 static int32_t audioGetFramePercentage(void);
56
57 #include "dbvzRegisterAccessors.c.h"
58 #include "dbvzTiming.c.h"
59
dbvzLcdRender(void)60 void dbvzLcdRender(void){
61 static const uint16_t masterColorLut[16] = {0x746D, 0x6C0C, 0x63CB, 0x5B8A, 0x534A, 0x4AE9, 0x42A8, 0x3A67, 0x3A27, 0x31C6, 0x2985, 0x2144, 0x1904, 0x10A3, 0x0862, 0x0000};
62 static const uint8_t bppLut[4] = {1, 2, 4, 0};
63 uint16_t colorLut2Bpp[4];//stores indexes to masterColorLut
64 uint32_t startAddress = registerArrayRead32(LSSA);
65 uint8_t bitsPerPixel = bppLut[registerArrayRead8(LPICF) & 0x03];
66 uint16_t pageWidth = registerArrayRead8(LVPW) * 2;//in bytes
67 bool invertColors = registerArrayRead8(LPOLCF) & 0x01;
68 uint8_t pixelShift = registerArrayRead8(LPOSR);
69 uint16_t width = registerArrayRead16(LXMAX);
70 uint16_t height = registerArrayRead16(LYMAX) + 1;
71 uint16_t y;
72 uint16_t x;
73
74 //dont render if LCD controller is disabled
75 if(!(registerArrayRead8(LCKCON) & 0x80)){
76 memset(dbvzFramebuffer, 0x00, dbvzFramebufferWidth * dbvzFramebufferHeight * sizeof(uint16_t));
77 return;
78 }
79
80 width = FAST_MIN(width, dbvzFramebufferWidth);
81 height = FAST_MIN(height, dbvzFramebufferHeight);
82
83 //TODO: cursor not implemented, not that anything will use a hardware terminal cursor on Palm OS
84 //m500 ROM I am using has the hardware feature bit for inverting color when backlight is on disabled, the backlight does not invert the colors even though HW supports it
85
86 switch(bitsPerPixel){
87 case 1:
88 for(y = 0; y < height; y++){
89 for(x = 0; x < width / 16; x++){
90 uint16_t dataUnit = m68k_read_memory_16(startAddress + y * pageWidth + x * 2);
91 uint8_t index;
92
93 for(index = 0; index < 16; index++)
94 if(x * 16 + index >= pixelShift)
95 dbvzFramebuffer[y * dbvzFramebufferWidth + x * 16 + index - pixelShift] = !!(dataUnit & 1 << 15 - index) == invertColors ? masterColorLut[0] : masterColorLut[15];
96 }
97 }
98 break;
99
100 case 2:
101 colorLut2Bpp[0] = 0;
102 colorLut2Bpp[1] = registerArrayRead8(LGPMR) & 0x0F;
103 colorLut2Bpp[2] = registerArrayRead8(LGPMR) >> 4;
104 colorLut2Bpp[3] = 15;
105
106 for(y = 0; y < height; y++){
107 for(x = 0; x < width / 8; x++){
108 uint16_t dataUnit = m68k_read_memory_16(startAddress + y * pageWidth + x * 2);
109 uint8_t index;
110
111 for(index = 0; index < 8; index++)
112 if(x * 8 + index >= pixelShift)
113 dbvzFramebuffer[y * dbvzFramebufferWidth + x * 8 + index - pixelShift] = invertColors ? masterColorLut[15 - colorLut2Bpp[dataUnit >> 14 - index * 2 & 0x03]] : masterColorLut[colorLut2Bpp[dataUnit >> 14 - index * 2 & 0x03]];
114 }
115 }
116 break;
117
118 case 4:
119 for(y = 0; y < height; y++){
120 for(x = 0; x < width / 4; x++){
121 uint16_t dataUnit = m68k_read_memory_16(startAddress + y * pageWidth + x * 2);
122 uint8_t index;
123
124 for(index = 0; index < 4; index++)
125 if(x * 4 + index >= pixelShift)
126 dbvzFramebuffer[y * dbvzFramebufferWidth + x * 4 + index - pixelShift] = invertColors ? masterColorLut[15 - (dataUnit >> 12 - index * 4 & 0x0F)] : masterColorLut[dataUnit >> 12 - index * 4 & 0x0F];
127 }
128 }
129 break;
130
131 default:
132 debugLog("Invalid DBVZ LCD controller pixel depth %d!\n", bitsPerPixel);
133 break;
134 }
135 }
136
dbvzIsPllOn(void)137 bool dbvzIsPllOn(void){
138 return !(dbvzSysclksPerClk32 < 1.0);
139 }
140
m515BacklightAmplifierState(void)141 bool m515BacklightAmplifierState(void){
142 return !!(getPortKValue() & 0x02);
143 }
144
dbvzAreRegistersXXFFMapped(void)145 bool dbvzAreRegistersXXFFMapped(void){
146 return !!(registerArrayRead8(SCR) & 0x04);
147 }
148
sed1376ClockConnected(void)149 bool sed1376ClockConnected(void){
150 //this is the clock output pin for the SED1376, if its disabled so is the LCD controller
151 //port f pin 2 is not GPIO and PLLCR CLKEN is false enabling clock output on port f pin 2
152 return !(registerArrayRead8(PFSEL) & 0x04) && !(registerArrayRead16(PLLCR) & 0x0010);
153 }
154
ads7846OverridePenState(bool value)155 void ads7846OverridePenState(bool value){
156 //causes a temporary override of the touchscreen value, used to trigger fake interrupts from line noise when reading from the ADS7846
157 if(value != (ads7846PenIrqEnabled ? !palmInput.touchscreenTouched : true)){
158 if(!(registerArrayRead8(PFSEL) & registerArrayRead8(PFDIR) & 0x02)){
159 if(value == !!(registerArrayRead16(ICR) & 0x0080))
160 setIprIsrBit(DBVZ_INT_IRQ5);
161 else
162 clearIprIsrBit(DBVZ_INT_IRQ5);
163 checkInterrupts();
164 }
165
166 //override over, put back real state
167 updateTouchState();
168 checkInterrupts();
169 }
170 }
171
m5XXRefreshTouchState(void)172 void m5XXRefreshTouchState(void){
173 //called when ads7846PenIrqEnabled is changed
174 updateTouchState();
175 checkInterrupts();
176 }
177
m5XXRefreshInputState(void)178 void m5XXRefreshInputState(void){
179 //update power button LED state incase palmMisc.batteryCharging changed
180 updatePowerButtonLedStatus();
181
182 //update touchscreen
183 updateTouchState();
184
185 //check for button presses and interrupts
186 checkPortDInterrupts();//this calls checkInterrupts() so it doesnt need to be called above
187 }
188
interruptAcknowledge(int32_t intLevel)189 int32_t interruptAcknowledge(int32_t intLevel){
190 uint8_t vectorOffset = registerArrayRead8(IVR);
191 int32_t vector;
192
193 //If an interrupt occurs before the IVR has been programmed, interrupt vector 15 is returned to the CPU as an uninitialized interrupt.
194 if(vectorOffset)
195 vector = vectorOffset | intLevel;
196 else
197 vector = 15;//EXCEPTION_UNINITIALIZED_INTERRUPT
198
199 //only active interrupts should wake the CPU if the PLL is off
200 pllWakeCpuIfOff();
201
202 //the interrupt should only be cleared after its been handled
203 return vector;
204 }
205
dbvzSetBusErrorTimeOut(uint32_t address,bool isWrite)206 void dbvzSetBusErrorTimeOut(uint32_t address, bool isWrite){
207 uint8_t scr = registerArrayRead8(SCR);
208 debugLog("Bus error timeout at:0x%08X, PC:0x%08X\n", address, flx68000GetPc());
209 registerArrayWrite8(SCR, scr | 0x80);
210 if(scr & 0x10)
211 flx68000BusError(address, isWrite);
212 }
213
dbvzSetPrivilegeViolation(uint32_t address,bool isWrite)214 void dbvzSetPrivilegeViolation(uint32_t address, bool isWrite){
215 uint8_t scr = registerArrayRead8(SCR);
216 debugLog("Privilege violation at:0x%08X, PC:0x%08X\n", address, flx68000GetPc());
217 registerArrayWrite8(SCR, scr | 0x20);
218 if(scr & 0x10)
219 flx68000BusError(address, isWrite);
220 }
221
dbvzSetWriteProtectViolation(uint32_t address)222 void dbvzSetWriteProtectViolation(uint32_t address){
223 uint8_t scr = registerArrayRead8(SCR);
224 debugLog("Write protect violation at:0x%08X, PC:0x%08X\n", address, flx68000GetPc());
225 registerArrayWrite8(SCR, scr | 0x40);
226 if(scr & 0x10)
227 flx68000BusError(address, true);
228 }
229
pllWakeCpuIfOff(void)230 static void pllWakeCpuIfOff(void){
231 static const int8_t pllWaitTable[4] = {32, 48, 64, 96};
232
233 //PLL is off and not already in the process of waking up
234 if(!dbvzIsPllOn() && pllWakeWait == -1)
235 pllWakeWait = pllWaitTable[registerArrayRead16(PLLCR) & 0x0003];
236 }
237
checkInterrupts(void)238 static void checkInterrupts(void){
239 //reduces time wasted on checking interrupts that where updated to a new value identical to the old one, does not need to be in states
240 static uint32_t dbvzCachedInterrupts;
241
242 uint32_t activeInterrupts = registerArrayRead32(ISR);
243 uint16_t interruptLevelControlRegister = registerArrayRead16(ILCR);
244 uint8_t spi1IrqLevel = interruptLevelControlRegister >> 12;
245 uint8_t uart2IrqLevel = interruptLevelControlRegister >> 8 & 0x0007;
246 uint8_t pwm2IrqLevel = interruptLevelControlRegister >> 4 & 0x0007;
247 uint8_t timer2IrqLevel = interruptLevelControlRegister & 0x0007;
248 uint8_t intLevel = 0;
249
250 //even masked interrupts turn off PCTLR, 4.5.4 Power Control Register MC68VZ328UM.pdf
251 if(registerArrayRead32(IPR) && registerArrayRead8(PCTLR) & 0x80){
252 registerArrayWrite8(PCTLR, registerArrayRead8(PCTLR) & 0x1F);
253 pctlrCpuClockDivider = 1.0;
254 }
255
256 //dont waste time if nothing changed
257 if(activeInterrupts == dbvzCachedInterrupts)
258 return;
259
260 //static interrupts
261 if(activeInterrupts & DBVZ_INT_EMIQ)
262 intLevel = 7;//EMIQ - Emulator IRQ, has nothing to do with emulation, used for debugging on a dev board
263
264 if(intLevel < 6 && activeInterrupts & (DBVZ_INT_TMR1 | DBVZ_INT_PWM1 | DBVZ_INT_IRQ6))
265 intLevel = 6;
266
267 if(intLevel < 5 && activeInterrupts & DBVZ_INT_IRQ5)
268 intLevel = 5;
269
270 if(intLevel < 4 && activeInterrupts & (DBVZ_INT_SPI2 | DBVZ_INT_UART1 | DBVZ_INT_WDT | DBVZ_INT_RTC | DBVZ_INT_KB | DBVZ_INT_RTI | DBVZ_INT_INT0 | DBVZ_INT_INT1 | DBVZ_INT_INT2 | DBVZ_INT_INT3))
271 intLevel = 4;
272
273 if(intLevel < 3 && activeInterrupts & DBVZ_INT_IRQ3)
274 intLevel = 3;
275
276 if(intLevel < 2 && activeInterrupts & DBVZ_INT_IRQ2)
277 intLevel = 2;
278
279 if(intLevel < 1 && activeInterrupts & DBVZ_INT_IRQ1)
280 intLevel = 1;
281
282 //configureable interrupts
283 if(intLevel < spi1IrqLevel && activeInterrupts & DBVZ_INT_SPI1)
284 intLevel = spi1IrqLevel;
285
286 if(intLevel < uart2IrqLevel && activeInterrupts & DBVZ_INT_UART2)
287 intLevel = uart2IrqLevel;
288
289 if(intLevel < pwm2IrqLevel && activeInterrupts & DBVZ_INT_PWM2)
290 intLevel = pwm2IrqLevel;
291
292 if(intLevel < timer2IrqLevel && activeInterrupts & DBVZ_INT_TMR2)
293 intLevel = timer2IrqLevel;
294
295 //should be called even if intLevel is 0, that is how the interrupt state gets cleared
296 flx68000SetIrq(intLevel);
297
298 //no interrupts have changed since the last call to this function, which is now
299 dbvzCachedInterrupts = activeInterrupts;
300 }
301
checkPortDInterrupts(void)302 static void checkPortDInterrupts(void){
303 uint16_t icr = registerArrayRead16(ICR);
304 uint8_t icrPolSwap = (!!(icr & 0x1000) << 7 | !!(icr & 0x2000) << 6 | !!(icr & 0x4000) << 5 | !!(icr & 0x8000) << 4) ^ 0xF0;//shifted to match port d layout
305 uint8_t icrEdgeTriggered = !!(icr & 0x0100) << 7 | !!(icr & 0x0200) << 6 | !!(icr & 0x0400) << 5 | !!(icr & 0x0800) << 4;//shifted to match port d layout
306 uint8_t portDInterruptValue = getPortDValue() ^ icrPolSwap;//not the same as the actual pin values, this already has all polarity swaps applied
307 uint8_t portDInterruptEdgeTriggered = icrEdgeTriggered | registerArrayRead8(PDIRQEG);
308 uint8_t portDInterruptEnabled = (~registerArrayRead8(PDSEL) & 0xF0) | registerArrayRead8(PDIRQEN);
309 uint8_t portDIsInput = ~registerArrayRead8(PDDIR);
310 uint8_t portDInterruptTriggered = portDInterruptValue & portDInterruptEnabled & portDIsInput & (~portDInterruptEdgeTriggered | ~portDInterruptLastValue & (dbvzIsPllOn() ? 0xFF : 0xF0));
311
312 if(portDInterruptTriggered & 0x01)
313 setIprIsrBit(DBVZ_INT_INT0);
314 else if(!(portDInterruptEdgeTriggered & 0x01))
315 clearIprIsrBit(DBVZ_INT_INT0);
316
317 if(portDInterruptTriggered & 0x02)
318 setIprIsrBit(DBVZ_INT_INT1);
319 else if(!(portDInterruptEdgeTriggered & 0x02))
320 clearIprIsrBit(DBVZ_INT_INT1);
321
322 if(portDInterruptTriggered & 0x04)
323 setIprIsrBit(DBVZ_INT_INT2);
324 else if(!(portDInterruptEdgeTriggered & 0x04))
325 clearIprIsrBit(DBVZ_INT_INT2);
326
327 if(portDInterruptTriggered & 0x08)
328 setIprIsrBit(DBVZ_INT_INT3);
329 else if(!(portDInterruptEdgeTriggered & 0x08))
330 clearIprIsrBit(DBVZ_INT_INT3);
331
332 if(portDInterruptTriggered & 0x10)
333 setIprIsrBit(DBVZ_INT_IRQ1);
334 else if(!(portDInterruptEdgeTriggered & 0x10))
335 clearIprIsrBit(DBVZ_INT_IRQ1);
336
337 if(portDInterruptTriggered & 0x20)
338 setIprIsrBit(DBVZ_INT_IRQ2);
339 else if(!(portDInterruptEdgeTriggered & 0x20))
340 clearIprIsrBit(DBVZ_INT_IRQ2);
341
342 if(portDInterruptTriggered & 0x40)
343 setIprIsrBit(DBVZ_INT_IRQ3);
344 else if(!(portDInterruptEdgeTriggered & 0x40))
345 clearIprIsrBit(DBVZ_INT_IRQ3);
346
347 if(portDInterruptTriggered & 0x80)
348 setIprIsrBit(DBVZ_INT_IRQ6);
349 else if(!(portDInterruptEdgeTriggered & 0x80))
350 clearIprIsrBit(DBVZ_INT_IRQ6);
351
352 //active low/off level triggered interrupt(triggers on 0, not a pull down resistor)
353 //The SELx, POLx, IQENx, and IQEGx bits have no effect on the functionality of KBENx, 10.4.5.8 Port D Keyboard Enable Register MC68VZ328UM.pdf
354 //the above has finally been verified to be correct!
355 if(registerArrayRead8(PDKBEN) & ~(getPortDValue() ^ registerArrayRead8(PDPOL)) & portDIsInput)
356 setIprIsrBit(DBVZ_INT_KB);
357 else
358 clearIprIsrBit(DBVZ_INT_KB);
359
360 //save to check against next time this function is called
361 portDInterruptLastValue = portDInterruptTriggered;
362
363 checkInterrupts();
364 }
365
printHwRegAccess(uint32_t address,uint32_t value,uint32_t size,bool isWrite)366 static void printHwRegAccess(uint32_t address, uint32_t value, uint32_t size, bool isWrite){
367 if(isWrite)
368 debugLog("CPU wrote %d bits of 0x%08X to register 0x%03X, PC:0x%08X.\n", size, value, address, flx68000GetPc());
369 else
370 debugLog("CPU read %d bits from register 0x%03X, PC:0x%08X.\n", size, address, flx68000GetPc());
371 }
372
dbvzGetRegister8(uint32_t address)373 uint8_t dbvzGetRegister8(uint32_t address){
374 #if !defined(EMU_NO_SAFETY)
375 if((address & 0x0000F000) != 0x0000F000){
376 dbvzSetBusErrorTimeOut(address, false);
377 return 0x00;
378 }
379 #endif
380
381 address &= 0x00000FFF;
382
383 switch(address){
384 case PADATA:
385 return getPortAValue();
386
387 case PBDATA:
388 return getPortBValue();
389
390 case PCDATA:
391 return getPortCValue();
392
393 case PDDATA:
394 return getPortDValue();
395
396 case PEDATA:
397 return getPortEValue();
398
399 case PFDATA:
400 return getPortFValue();
401
402 case PGDATA:
403 return getPortGValue();
404
405 case PJDATA:
406 return getPortJValue();
407
408 case PKDATA:
409 return getPortKValue();
410
411 case PMDATA:
412 return getPortMValue();
413
414 case PWMCNT1:
415 debugLog("PWMCNT1 not implimented\n");
416 return 0x00;
417
418 //16 bit registers being read as 8 bit
419 case SPICONT1:
420 case SPICONT1 + 1:
421 case SPIINTCS:
422 case SPIINTCS + 1:
423 case PLLFSR:
424 case PLLFSR + 1:
425
426 //basic non GPIO functions
427 case SCR:
428 case LCKCON:
429 case IVR:
430 case PWMP1:
431 case LGPMR:
432
433 //LCD controller
434 case LPICF:
435 case LPOLCF:
436
437 //port d special functions
438 case PDPOL:
439 case PDIRQEN:
440 case PDIRQEG:
441 case PDKBEN:
442
443 //I/O direction
444 case PBDIR:
445 case PDDIR:
446 case PEDIR:
447 case PFDIR:
448 case PJDIR:
449 case PKDIR:
450
451 //select between GPIO or special function
452 case PBSEL:
453 case PCSEL:
454 case PDSEL:
455 case PESEL:
456 case PFSEL:
457 case PGSEL:
458 case PJSEL:
459 case PKSEL:
460 case PMSEL:
461
462 //pull up/down enable
463 case PAPUEN:
464 case PBPUEN:
465 case PCPDEN:
466 case PDPUEN:
467 case PEPUEN:
468 case PFPUEN:
469 case PGPUEN:
470 case PJPUEN:
471 case PKPUEN:
472 case PMPUEN:
473 //simple read, no actions needed
474 //PGPUEN, PGSEL PMSEL and PMPUEN lack the top 2 bits but that is handled on write
475 //PDSEL lacks the bottom 4 bits but that is handled on write
476 return registerArrayRead8(address);
477
478 default:
479 //bootloader
480 if(address >= 0xE00)
481 return registerArrayRead8(address);
482
483 printHwRegAccess(address, 0, 8, false);
484 return 0x00;
485 }
486 }
487
dbvzGetRegister16(uint32_t address)488 uint16_t dbvzGetRegister16(uint32_t address){
489 #if !defined(EMU_NO_SAFETY)
490 if((address & 0x0000F000) != 0x0000F000){
491 dbvzSetBusErrorTimeOut(address, false);
492 return 0x0000;
493 }
494 #endif
495
496 address &= 0x00000FFF;
497
498 switch(address){
499 case TSTAT1:
500 timerStatusReadAcknowledge[0] |= registerArrayRead16(TSTAT1);//active bits acknowledged
501 return registerArrayRead16(TSTAT1);
502
503 case TSTAT2:
504 timerStatusReadAcknowledge[1] |= registerArrayRead16(TSTAT2);//active bits acknowledged
505 return registerArrayRead16(TSTAT2);
506
507 case PWMC1:
508 return getPwmc1();
509
510 case SPITEST:
511 //SSTATUS is unemulated because the datasheet has no descrption of how it works
512 return spi1RxFifoEntrys() << 4 | spi1TxFifoEntrys();
513
514 case SPIRXD:{
515 uint16_t fifoVal = spi1RxFifoRead();
516 //check if SPI1 interrupts changed
517 setSpiIntCs(registerArrayRead16(SPIINTCS));
518 //debugLog("SPIRXD read, FIFO value:0x%04X, SPIINTCS:0x%04X\n", fifoVal, registerArrayRead16(SPIINTCS));
519 return fifoVal;
520 }
521
522 case UTX1:{
523 uint16_t uart1TxStatus = registerArrayRead16(UTX1);
524 uint8_t entrys = uart1TxFifoEntrys();
525
526 uart1TxStatus |= (entrys == 0) << 15;
527 uart1TxStatus |= (entrys < 4) << 14;
528 uart1TxStatus |= (entrys < 8) << 13;
529
530 return uart1TxStatus;
531 }
532
533 case UTX2:{
534 uint16_t uart2TxStatus = registerArrayRead16(UTX2);
535 uint8_t entrys = uart2TxFifoEntrys();
536
537 uart2TxStatus |= (entrys == 0) << 15;
538 uart2TxStatus |= (entrys < 4) << 14;
539 uart2TxStatus |= (entrys < 8) << 13;
540
541 return uart2TxStatus;
542 }
543
544 case PLLFSR:
545 return registerArrayRead16(PLLFSR);
546
547 //32 bit registers accessed as 16 bit
548 case IDR:
549 case IDR + 2:
550 case IMR:
551 case IMR + 2:
552 case IPR:
553 case IPR + 2:
554 case ISR:
555 case ISR + 2:
556
557 case CSA:
558 case CSB:
559 case CSC:
560 case CSD:
561 case CSGBA:
562 case CSGBB:
563 case CSGBC:
564 case CSGBD:
565 case CSUGBA:
566 case PLLCR:
567 case DRAMC:
568 case SDCTRL:
569 case RTCISR:
570 case RTCCTL:
571 case RTCIENR:
572 case ILCR:
573 case ICR:
574 case TCMP1:
575 case TCMP2:
576 case TPRER1:
577 case TPRER2:
578 case TCTL1:
579 case TCTL2:
580 case SPICONT1:
581 case SPIINTCS:
582 case SPISPC:
583 case SPICONT2:
584 case SPIDATA2:
585 case USTCNT1:
586 case UBAUD1:
587 case UMISC1:
588 case NIPR1:
589 case USTCNT2:
590 case UBAUD2:
591 case UMISC2:
592 case NIPR2:
593 case HMARK:
594 case LCXP:
595 case PWMR:
596 case LXMAX:
597 case LYMAX:
598 //simple read, no actions needed
599 return registerArrayRead16(address);
600
601 default:
602 //bootloader
603 if(address >= 0xE00)
604 return registerArrayRead16(address);
605
606 printHwRegAccess(address, 0, 16, false);
607 return 0x0000;
608 }
609 }
610
dbvzGetRegister32(uint32_t address)611 uint32_t dbvzGetRegister32(uint32_t address){
612 #if !defined(EMU_NO_SAFETY)
613 if((address & 0x0000F000) != 0x0000F000){
614 dbvzSetBusErrorTimeOut(address, false);
615 return 0x00000000;
616 }
617 #endif
618
619 address &= 0x00000FFF;
620
621 switch(address){
622 case ISR:
623 case IPR:
624 case IMR:
625 case RTCTIME:
626 case IDR:
627 case LSSA:
628 //simple read, no actions needed
629 return registerArrayRead32(address);
630
631 default:
632 //bootloader
633 if(address >= 0xE00)
634 return registerArrayRead32(address);
635
636 printHwRegAccess(address, 0, 32, false);
637 return 0x00000000;
638 }
639 }
640
dbvzSetRegister8(uint32_t address,uint8_t value)641 void dbvzSetRegister8(uint32_t address, uint8_t value){
642 #if !defined(EMU_NO_SAFETY)
643 if((address & 0x0000F000) != 0x0000F000){
644 dbvzSetBusErrorTimeOut(address, true);
645 return;
646 }
647 #endif
648
649 address &= 0x00000FFF;
650
651 switch(address){
652 case SCR:
653 setScr(value);
654 return;
655
656 case UTX1 + 1:
657 //this is a 16 bit register but Palm OS writes to the 8 bit FIFO section alone
658 //send byte and update interrupts if enabled
659 if((registerArrayRead16(USTCNT1) & 0xA000) == 0xA000){
660 uart1TxFifoWrite(value);
661 updateUart1Interrupt();
662 }
663 return;
664
665 case UTX2 + 1:
666 //this is a 16 bit register but Palm OS writes to the 8 bit FIFO section alone
667 //send byte and update interrupts if enabled
668 if((registerArrayRead16(USTCNT2) & 0xA000) == 0xA000){
669 uart2TxFifoWrite(value);
670 updateUart2Interrupt();
671 }
672 return;
673
674 case PWMS1 + 1:
675 //write only if PWM1 enabled
676 if(registerArrayRead16(PWMC1) & 0x0010)
677 pwm1FifoWrite(value);
678 return;
679
680 case PWMP1:
681 //write only if PWM1 enabled
682 if(registerArrayRead16(PWMC1) & 0x0010)
683 registerArrayWrite8(address, value);
684 return;
685
686 case PCTLR:
687 registerArrayWrite8(address, value & 0x9F);
688 if(value & 0x80)
689 pctlrCpuClockDivider = (value & 0x1F) / 31.0;
690 checkInterrupts();//may need to turn PCTLR off right after its turned on(could be in an interrupt)
691 return;
692
693 case IVR:
694 //write without the bottom 3 bits
695 registerArrayWrite8(address, value & 0xF8);
696 return;
697
698 case LPICF:
699 case LPOLCF:
700 case LPOSR:
701 registerArrayWrite8(address, value & 0x0F);
702 return;
703
704 case LPXCD:
705 registerArrayWrite8(LPXCD, value & 0x3F);
706 return;
707
708 case PBSEL:
709 case PBDIR:
710 case PBDATA:
711 registerArrayWrite8(address, value);
712 updatePowerButtonLedStatus();
713 return;
714
715 case PDSEL:
716 //write without the bottom 4 bits
717 registerArrayWrite8(address, value & 0xF0);
718 checkPortDInterrupts();
719 return;
720
721 case PDPOL:
722 case PDIRQEN:
723 case PDIRQEG:
724 //write without the top 4 bits
725 registerArrayWrite8(address, value & 0x0F);
726 checkPortDInterrupts();
727 return;
728
729 case PDDATA:
730 case PDKBEN:
731 //can change interrupt state
732 registerArrayWrite8(address, value);
733 checkPortDInterrupts();
734 return;
735
736 case PFSEL:
737 //this register controls the clock output pin for the SED1376 and IRQ line for PENIRQ
738 registerArrayWrite8(PFSEL, value);
739 m515SetSed1376Attached(sed1376ClockConnected());
740 #if !defined(EMU_NO_SAFETY)
741 updateTouchState();
742 checkInterrupts();
743 #endif
744 return;
745
746 case PFDIR:
747 //this register controls the IRQ line for PENIRQ
748 registerArrayWrite8(PFDIR, value);
749 #if !defined(EMU_NO_SAFETY)
750 updateTouchState();
751 checkInterrupts();
752 #endif
753 return;
754
755 case PGSEL:
756 case PGDIR:
757 case PGDATA:
758 //write without the top 2 bits
759 registerArrayWrite8(address, value & 0x3F);
760 updateAds7846ChipSelectStatus();
761 if(palmEmulatingM500)
762 palmMisc.backlightLevel = !!(getPortGValue() & 0x02) * 100;
763 return;
764
765 case PJSEL:
766 case PJDIR:
767 case PJDATA:
768 registerArrayWrite8(address, value);
769 updateSdCardChipSelectStatus();
770 return;
771
772 case PKSEL:
773 case PKDIR:
774 case PKDATA:
775 registerArrayWrite8(address, value);
776 checkPortDInterrupts();
777 updateVibratorStatus();
778 if(!palmEmulatingM500)
779 sed1376UpdateLcdStatus();
780 return;
781
782 case PMSEL:
783 case PMDIR:
784 case PMDATA:
785 //unemulated
786 //infrared shutdown
787 registerArrayWrite8(address, value & 0x3F);
788 return;
789
790 case PMPUEN:
791 case PGPUEN:
792 //write without the top 2 bits
793 registerArrayWrite8(address, value & 0x3F);
794 return;
795
796 //select between GPIO or special function
797 case PCSEL:
798 case PESEL:
799
800 //direction select
801 case PADIR:
802 case PCDIR:
803 case PDDIR:
804 case PEDIR:
805
806 //pull up/down enable
807 case PAPUEN:
808 case PBPUEN:
809 case PCPDEN:
810 case PDPUEN:
811 case PEPUEN:
812 case PFPUEN:
813 case PJPUEN:
814 case PKPUEN:
815
816 //port data value, nothing known is attached to port
817 case PCDATA:
818 case PEDATA:
819 case PFDATA:
820
821 //dragonball LCD controller
822 case LVPW:
823 case LCKCON:
824 case LBLKC:
825 case LACDRC:
826 case LGPMR:
827 //simple write, no actions needed
828 registerArrayWrite8(address, value);
829 return;
830
831 default:
832 //writeable bootloader region
833 if(address >= 0xFC0){
834 registerArrayWrite32(address, value);
835 return;
836 }
837
838 printHwRegAccess(address, value, 8, true);
839 return;
840 }
841 }
842
dbvzSetRegister16(uint32_t address,uint16_t value)843 void dbvzSetRegister16(uint32_t address, uint16_t value){
844 #if !defined(EMU_NO_SAFETY)
845 if((address & 0x0000F000) != 0x0000F000){
846 dbvzSetBusErrorTimeOut(address, true);
847 return;
848 }
849 #endif
850
851 address &= 0x00000FFF;
852
853 switch(address){
854 case RTCIENR:
855 //missing bits 6 and 7
856 registerArrayWrite16(address, value & 0xFF3F);
857 return;
858
859 case RTCCTL:
860 registerArrayWrite16(address, value & 0x00A0);
861 return;
862
863 case IMR:
864 //this is a 32 bit register but Palm OS writes to it as 16 bit chunks
865 registerArrayWrite16(IMR, value & 0x00FF);
866 registerArrayWrite16(ISR, registerArrayRead16(IPR) & ~registerArrayRead16(IMR));
867 checkInterrupts();
868 return;
869 case IMR + 2:
870 //this is a 32 bit register but Palm OS writes to it as 16 bit chunks
871 registerArrayWrite16(IMR + 2, value & 0xFFFF);//Palm OS writes to reserved bits 14 and 15
872 registerArrayWrite16(ISR + 2, registerArrayRead16(IPR + 2) & ~registerArrayRead16(IMR + 2));
873 checkInterrupts();
874 return;
875
876 case ISR:
877 setIsr(value << 16, true, false);
878 return;
879 case ISR + 2:
880 setIsr(value, false, true);
881 return;
882
883 case TCTL1:
884 case TCTL2:
885 registerArrayWrite16(address, value & 0x01FF);
886 return;
887
888 case TSTAT1:
889 setTstat1(value);
890 return;
891
892 case TSTAT2:
893 setTstat2(value);
894 return;
895
896 case WATCHDOG:
897 //writing to the watchdog resets the counter bits(8 and 9) to 0
898 //1 must be written to clear INTF
899 registerArrayWrite16(WATCHDOG, (value & 0x0003) | (registerArrayRead16(WATCHDOG) & (~value & 0x0080)));
900 if(!(registerArrayRead16(WATCHDOG) & 0x0080))
901 clearIprIsrBit(DBVZ_INT_WDT);
902 return;
903
904 case RTCISR:
905 registerArrayWrite16(RTCISR, registerArrayRead16(RTCISR) & ~value);
906 if(!(registerArrayRead16(RTCISR) & 0xFF00))
907 clearIprIsrBit(DBVZ_INT_RTI);
908 if(!(registerArrayRead16(RTCISR) & 0x003F))
909 clearIprIsrBit(DBVZ_INT_RTC);
910 checkInterrupts();
911 return;
912
913 case PLLFSR:
914 setPllfsr(value);
915 return;
916
917 case PLLCR:
918 //CLKEN is required for SED1376 operation
919 registerArrayWrite16(PLLCR, value & 0x3FBB);
920 dbvzSysclksPerClk32 = sysclksPerClk32();
921 m515SetSed1376Attached(sed1376ClockConnected());
922
923 if(value & 0x0008)
924 pllSleepWait = 30;//The PLL shuts down 30 clocks of CLK32 after the DISPLL bit is set in the PLLCR
925 else
926 pllSleepWait = -1;//allow the CPU to cancel the shut down
927 return;
928
929 case ICR:
930 registerArrayWrite16(ICR, value & 0xFF80);
931 updateTouchState();
932 checkPortDInterrupts();//this calls checkInterrupts() so it doesnt need to be called above
933 return;
934
935 case ILCR:
936 setIlcr(value);
937 return;
938
939 case DRAMC:
940 //somewhat unemulated
941 //missing bit 7 and 6
942 //debugLog("Set DRAMC, old value:0x%04X, new value:0x%04X, PC:0x%08X\n", registerArrayRead16(address), value, flx68000GetPc());
943 registerArrayWrite16(DRAMC, value & 0xFF3F);
944 updateCsdAddressLines();//the EDO bit can disable SDRAM access
945 return;
946
947 case DRAMMC:
948 //unemulated, address line remapping, too CPU intensive to emulate
949 registerArrayWrite16(address, value);
950 return;
951
952 case SDCTRL:
953 //missing bits 13, 9, 8 and 7
954 //debugLog("Set SDCTRL, old value:0x%04X, new value:0x%04X, PC:0x%08X\n", registerArrayRead16(address), value, flx68000GetPc());
955 registerArrayWrite16(SDCTRL, value & 0xDC7F);
956 updateCsdAddressLines();
957 return;
958
959 case CSA:{
960 uint16_t oldCsa = registerArrayRead16(CSA);
961 bool oldBootMode = dbvzChipSelects[DBVZ_CHIP_A0_ROM].inBootMode;
962
963 setCsa(value);
964
965 //only reset address space if size changed, enabled/disabled or exiting boot mode
966 if((value & 0x000F) != (oldCsa & 0x000F) || dbvzChipSelects[DBVZ_CHIP_A0_ROM].inBootMode != oldBootMode)
967 dbvzResetAddressSpace();
968 }
969 return;
970
971 case CSB:{
972 uint16_t oldCsb = registerArrayRead16(CSB);
973
974 setCsb(value);
975
976 //only reset address space if size changed or enabled/disabled
977 if((value & 0x000F) != (oldCsb & 0x000F))
978 dbvzResetAddressSpace();
979 }
980 return;
981
982 case CSC:
983 registerArrayWrite16(CSC, value & 0xF9FF);
984 return;
985
986 case CSD:{
987 uint16_t oldCsd = registerArrayRead16(CSD);
988
989 setCsd(value);
990
991 //CSD DRAM bit changed
992 if((value & 0x0200) != (oldCsd & 0x0200))
993 updateCsdAddressLines();
994
995
996 //only reset address space if size changed, enabled/disabled or DRAM bit changed
997 if((value & 0x020F) != (oldCsd & 0x020F))
998 dbvzResetAddressSpace();
999 }
1000 return;
1001
1002 case CSGBA:
1003 //sets the starting location of ROM(0x10000000) and the PDIUSBD12 chip
1004 if((value & 0xFFFE) != registerArrayRead16(CSGBA)){
1005 setCsgba(value);
1006 dbvzResetAddressSpace();
1007 }
1008 return;
1009
1010 case CSGBB:
1011 //sets the starting location of the SED1376(0x1FF80000)
1012 if((value & 0xFFFE) != registerArrayRead16(CSGBB)){
1013 setCsgbb(value);
1014 dbvzResetAddressSpace();
1015 }
1016 return;
1017
1018 case CSGBC:
1019 registerArrayWrite16(CSGBC, value & 0xFFFE);
1020 return;
1021
1022 case CSGBD:
1023 //sets the starting location of RAM(0x00000000)
1024 if((value & 0xFFFE) != registerArrayRead16(CSGBD)){
1025 setCsgbd(value);
1026 dbvzResetAddressSpace();
1027 }
1028 return;
1029
1030 case CSUGBA:
1031 if((value & 0xF777) != registerArrayRead16(CSUGBA)){
1032 registerArrayWrite16(CSUGBA, value & 0xF777);
1033 //refresh all chip select address lines
1034 setCsgba(registerArrayRead16(CSGBA));
1035 setCsgbb(registerArrayRead16(CSGBB));
1036 setCsgbd(registerArrayRead16(CSGBD));
1037 dbvzResetAddressSpace();
1038 }
1039 return;
1040
1041 case CSCTRL1:{
1042 uint16_t oldCsctrl1 = registerArrayRead16(CSCTRL1);
1043
1044 registerArrayWrite16(CSCTRL1, value & 0x7F55);
1045
1046 if((value & 0x4055) != (oldCsctrl1 & 0x4055)){
1047 //something important changed, update all chip selects
1048 //CSA is not dependent on CSCTRL1
1049 setCsb(registerArrayRead16(CSB));
1050 setCsd(registerArrayRead16(CSD));
1051 dbvzResetAddressSpace();
1052 }
1053 }
1054 return;
1055
1056 case SPICONT1:
1057 setSpiCont1(value);
1058 return;
1059
1060 case SPIINTCS:
1061 setSpiIntCs(value);
1062 return;
1063
1064 case SPITEST:
1065 debugLog("SPITEST write not implented yet\n");
1066 return;
1067
1068 case SPITXD:
1069 if(registerArrayRead16(SPICONT1) & 0x0200){
1070 spi1TxFifoWrite(value);
1071 //check if SPI1 interrupts changed
1072 setSpiIntCs(registerArrayRead16(SPIINTCS));
1073 }
1074 return;
1075
1076 case SPICONT2:
1077 setSpiCont2(value);
1078 return;
1079
1080 case SPIDATA2:
1081 //ignore writes when SPICONT2 ENABLE is not set
1082 if(registerArrayRead16(SPICONT2) & 0x0200)
1083 registerArrayWrite16(SPIDATA2, value);
1084 return;
1085
1086 case USTCNT1:
1087 setUstcnt1(value);
1088 return;
1089
1090 case UBAUD1:
1091 //just does timing stuff, should be OK to ignore
1092 registerArrayWrite16(UBAUD1, value & 0x2F3F);
1093 return;
1094
1095 case UMISC1:
1096 //TODO: most of the bits here are for factory testing and can be ignored but not all of them can be
1097 registerArrayWrite16(UMISC1, value & 0xFCFC);
1098 return;
1099
1100 case UTX1:
1101 registerArrayWrite16(UTX1, value & 0x1F00);
1102
1103 //send byte and update interrupts if enabled
1104 if((registerArrayRead16(USTCNT1) & 0xA000) == 0xA000){
1105 uart1TxFifoWrite(value & 0x1000 ? value & 0xFF : EMU_SERIAL_BREAK);
1106 updateUart1Interrupt();
1107 }
1108 return;
1109
1110 case USTCNT2:
1111 setUstcnt2(value);
1112 return;
1113
1114 case UBAUD2:
1115 //just does timing stuff, should be OK to ignore
1116 registerArrayWrite16(UBAUD2, value & 0x2F3F);
1117 return;
1118
1119 case UMISC2:
1120 //TODO: most of the bits here are for factory testing and can be ignored but not all of them can be
1121 registerArrayWrite16(UMISC2, value & 0xFCFC);
1122 return;
1123
1124 case UTX2:
1125 registerArrayWrite16(UTX2, value & 0x1F00);
1126
1127 //send byte and update interrupts if enabled
1128 if((registerArrayRead16(USTCNT2) & 0xA000) == 0xA000){
1129 uart2TxFifoWrite(value & 0x1000 ? value & 0xFF : EMU_SERIAL_BREAK);
1130 updateUart2Interrupt();
1131 }
1132 return;
1133
1134 case HMARK:
1135 registerArrayWrite16(HMARK, value & 0x0F0F);
1136 updateUart2Interrupt();
1137 return;
1138
1139 case PWMC1:
1140 setPwmc1(value);
1141 return;
1142
1143 case PWMS1:
1144 //write only if PWM1 enabled
1145 if(registerArrayRead16(PWMC1) & 0x0010){
1146 pwm1FifoWrite(value >> 8);
1147 pwm1FifoWrite(value & 0xFF);
1148 }
1149 return;
1150
1151 case NIPR1:
1152 //just does timing stuff, should be OK to ignore
1153 registerArrayWrite16(NIPR1, value & 0x87FF);
1154 return;
1155
1156 case LXMAX:
1157 registerArrayWrite16(LXMAX, value & 0x03F0);
1158 return;
1159
1160 case LYMAX:
1161 registerArrayWrite16(LYMAX, value & 0x01FF);
1162 return;
1163
1164 case LCXP:
1165 registerArrayWrite16(LCXP, value & 0xC3FF);
1166 return;
1167
1168 case LCYP:
1169 registerArrayWrite16(LCYP, value & 0x01FF);
1170 return;
1171
1172 case LCWCH:
1173 registerArrayWrite16(LCWCH, value & 0x1F1F);
1174 return;
1175
1176 case LRRA:
1177 registerArrayWrite16(LRRA, value & 0x03FF);
1178 return;
1179
1180 case PWMR:
1181 registerArrayWrite16(PWMR, value & 0x07FF);
1182 return;
1183
1184 case SPISPC:
1185 case TCMP1:
1186 case TCMP2:
1187 case TPRER1:
1188 case TPRER2:
1189 //simple write, no actions needed
1190 registerArrayWrite16(address, value);
1191 return;
1192
1193 default:
1194 //writeable bootloader region
1195 if(address >= 0xFC0){
1196 registerArrayWrite16(address, value);
1197 return;
1198 }
1199
1200 printHwRegAccess(address, value, 16, true);
1201 return;
1202 }
1203 }
1204
dbvzSetRegister32(uint32_t address,uint32_t value)1205 void dbvzSetRegister32(uint32_t address, uint32_t value){
1206 #if !defined(EMU_NO_SAFETY)
1207 if((address & 0x0000F000) != 0x0000F000){
1208 dbvzSetBusErrorTimeOut(address, true);
1209 return;
1210 }
1211 #endif
1212
1213 address &= 0x00000FFF;
1214
1215 switch(address){
1216 case RTCTIME:
1217 case RTCALRM:
1218 registerArrayWrite32(address, value & 0x1F3F003F);
1219 return;
1220
1221 case IDR:
1222 case IPR:
1223 //write to read only register, do nothing
1224 return;
1225
1226 case ISR:
1227 setIsr(value, true, true);
1228 return;
1229
1230 case IMR:
1231 registerArrayWrite32(IMR, value & 0x00FFFFFF);//Palm OS writes to reserved bits 14 and 15
1232 registerArrayWrite32(ISR, registerArrayRead32(IPR) & ~registerArrayRead32(IMR));
1233 checkInterrupts();
1234 return;
1235
1236 case LSSA:
1237 registerArrayWrite32(address, value & 0xFFFFFFFE);
1238 return;
1239
1240 default:
1241 //writeable bootloader region
1242 if(address >= 0xFC0){
1243 registerArrayWrite32(address, value);
1244 return;
1245 }
1246
1247 printHwRegAccess(address, value, 32, true);
1248 return;
1249 }
1250 }
1251
dbvzReset(void)1252 void dbvzReset(void){
1253 uint32_t oldRtc = registerArrayRead32(RTCTIME);//preserve RTCTIME
1254 uint16_t oldDayr = registerArrayRead16(DAYR);//preserve DAYR
1255
1256 memset(dbvzReg, 0x00, DBVZ_REG_SIZE - DBVZ_BOOTLOADER_SIZE);
1257 dbvzSysclksPerClk32 = 0.0;
1258 clk32Counter = 0;
1259 pctlrCpuClockDivider = 1.0;
1260 pllSleepWait = -1;
1261 pllWakeWait = -1;
1262 timerCycleCounter[0] = 0.0;
1263 timerCycleCounter[1] = 0.0;
1264 timerStatusReadAcknowledge[0] = 0x0000;
1265 timerStatusReadAcknowledge[1] = 0x0000;
1266 portDInterruptLastValue = 0x00;
1267 memset(spi1RxFifo, 0x00, sizeof(spi1RxFifo));
1268 memset(spi1TxFifo, 0x00, sizeof(spi1TxFifo));
1269 spi1RxReadPosition = 0;
1270 spi1RxWritePosition = 0;
1271 spi1RxOverflowed = false;
1272 spi1TxReadPosition = 0;
1273 spi1TxWritePosition = 0;
1274 pwm1ClocksToNextSample = 0;
1275 memset(pwm1Fifo, 0x00, sizeof(pwm1Fifo));
1276 pwm1ReadPosition = 0;
1277 pwm1WritePosition = 0;
1278
1279 memset(dbvzChipSelects, 0x00, sizeof(dbvzChipSelects));
1280 //all chip selects are disabled at boot and CSA0 is mapped to 0x00000000 and covers the entire address range until CSA is set enabled
1281 dbvzChipSelects[DBVZ_CHIP_A0_ROM].inBootMode = true;
1282
1283 //default sizes
1284 dbvzChipSelects[DBVZ_CHIP_A0_ROM].lineSize = 0x20000;
1285 dbvzChipSelects[DBVZ_CHIP_A1_USB].lineSize = 0x20000;
1286 dbvzChipSelects[DBVZ_CHIP_B0_SED].lineSize = 0x20000;
1287 dbvzChipSelects[DBVZ_CHIP_DX_RAM].lineSize = 0x8000;
1288
1289 //masks for reading and writing
1290 dbvzChipSelects[DBVZ_CHIP_A0_ROM].mask = 0x003FFFFF;//4mb
1291 dbvzChipSelects[DBVZ_CHIP_A1_USB].mask = 0x00000002;//A1 is used as USB chip A0
1292 dbvzChipSelects[DBVZ_CHIP_B0_SED].mask = 0x0001FFFF;
1293 dbvzChipSelects[DBVZ_CHIP_DX_RAM].mask = 0x00000000;//16mb, no RAM enabled until the DRAM module is initialized
1294
1295 //system control
1296 registerArrayWrite8(SCR, 0x1C);
1297
1298 //CPU ID
1299 registerArrayWrite32(IDR, 0x57000000);//value of IDR on actual hardware
1300
1301 //I/O drive control //probably unused
1302 registerArrayWrite16(IODCR, 0x1FFF);
1303
1304 //chip selects
1305 registerArrayWrite16(CSA, 0x00B0);
1306 registerArrayWrite16(CSD, 0x0200);
1307 registerArrayWrite16(EMUCS, 0x0060);
1308 registerArrayWrite16(CSCTRL2, 0x1000);
1309 registerArrayWrite16(CSCTRL3, 0x9C00);
1310
1311 //phase lock loop
1312 registerArrayWrite16(PLLCR, 0x24B3);
1313 registerArrayWrite16(PLLFSR, 0x0347);
1314
1315 //power control
1316 registerArrayWrite8(PCTLR, 0x1F);
1317
1318 //interrupts
1319 registerArrayWrite32(IMR, 0x00FFFFFF);//the data sheet says 0x00FFFFFF and 0x00FF3FFF, using 0x00FFFFFF because thats how its set on the device
1320 registerArrayWrite16(ILCR, 0x6533);
1321
1322 //GPIO ports
1323 registerArrayWrite8(PADATA, 0xFF);
1324 registerArrayWrite8(PAPUEN, 0xFF);
1325
1326 registerArrayWrite8(PBDATA, 0xFF);
1327 registerArrayWrite8(PBPUEN, 0xFF);
1328 registerArrayWrite8(PBSEL, 0xFF);
1329
1330 registerArrayWrite8(PCPDEN, 0xFF);
1331 registerArrayWrite8(PCSEL, 0xFF);
1332
1333 registerArrayWrite8(PDDATA, 0xFF);
1334 registerArrayWrite8(PDPUEN, 0xFF);
1335 registerArrayWrite8(PDSEL, 0xF0);
1336
1337 registerArrayWrite8(PEDATA, 0xFF);
1338 registerArrayWrite8(PEPUEN, 0xFF);
1339 registerArrayWrite8(PESEL, 0xFF);
1340
1341 registerArrayWrite8(PFDATA, 0xFF);
1342 registerArrayWrite8(PFPUEN, 0xFF);
1343 registerArrayWrite8(PFSEL, 0x87);
1344
1345 registerArrayWrite8(PGDATA, 0x3F);
1346 registerArrayWrite8(PGPUEN, 0x3D);
1347 registerArrayWrite8(PGSEL, 0x08);
1348
1349 registerArrayWrite8(PJDATA, 0xFF);
1350 registerArrayWrite8(PJPUEN, 0xFF);
1351 registerArrayWrite8(PJSEL, 0xEF);
1352
1353 registerArrayWrite8(PKDATA, 0x0F);
1354 registerArrayWrite8(PKPUEN, 0xFF);
1355 registerArrayWrite8(PKSEL, 0xFF);
1356
1357 registerArrayWrite8(PMDATA, 0x20);
1358 registerArrayWrite8(PMPUEN, 0x3F);
1359 registerArrayWrite8(PMSEL, 0x3F);
1360
1361 //pulse width modulation control
1362 //registerArrayWrite16(PWMC1, 0x0020);//FIFOAV is controlled by getPwmc1()
1363 registerArrayWrite8(PWMP1, 0xFE);
1364
1365 //timers
1366 registerArrayWrite16(TCMP1, 0xFFFF);
1367 registerArrayWrite16(TCMP2, 0xFFFF);
1368
1369 //serial I/O
1370 registerArrayWrite16(UBAUD1, 0x0002);
1371 registerArrayWrite16(UBAUD2, 0x0002);
1372 registerArrayWrite16(HMARK, 0x0102);
1373
1374 //LCD control registers, unused since the SED1376 controls the LCD
1375 registerArrayWrite8(LVPW, 0xFF);
1376 registerArrayWrite16(LXMAX, 0x03F0);
1377 registerArrayWrite16(LYMAX, 0x01FF);
1378 registerArrayWrite16(LCWCH, 0x0101);
1379 registerArrayWrite8(LBLKC, 0x7F);
1380 registerArrayWrite16(LRRA, 0x00FF);
1381 registerArrayWrite8(LGPMR, 0x84);
1382 registerArrayWrite8(DMACR, 0x62);
1383
1384 //realtime clock
1385 registerArrayWrite32(RTCTIME, oldRtc);//RTCTIME is not changed on reset
1386 registerArrayWrite16(WATCHDOG, 0x0001);
1387 registerArrayWrite16(RTCCTL, 0x0080);//conflicting size in datasheet, it says its 8 bit but provides 16 bit values
1388 registerArrayWrite16(STPWCH, 0x003F);//conflicting size in datasheet, it says its 8 bit but provides 16 bit values
1389 registerArrayWrite16(DAYR, oldDayr);//DAYR is not changed on reset
1390
1391 //SDRAM control, unused since RAM refresh is unemulated
1392 registerArrayWrite16(SDCTRL, 0x003C);
1393
1394 //move register settings to other I/O
1395 updatePowerButtonLedStatus();
1396 updateVibratorStatus();
1397 updateAds7846ChipSelectStatus();
1398 updateSdCardChipSelectStatus();
1399 if(!palmEmulatingM500)
1400 sed1376UpdateLcdStatus();
1401
1402 dbvzSysclksPerClk32 = sysclksPerClk32();
1403
1404 dbvzResetAddressSpace();
1405 checkInterrupts();
1406 flx68000Reset();
1407 }
1408
dbvzLoadBootloader(uint8_t * data,uint32_t size)1409 void dbvzLoadBootloader(uint8_t* data, uint32_t size){
1410 uint16_t index;
1411
1412 if(!data)
1413 size = 0;
1414
1415 size = FAST_MIN(size, DBVZ_BOOTLOADER_SIZE);
1416
1417 //copy size bytes from buffer to bootloader area
1418 for(index = 0; index < size; index++)
1419 registerArrayWrite8(DBVZ_REG_SIZE - DBVZ_BOOTLOADER_SIZE + index, data[index]);
1420
1421 //fill remainig space with 0x00
1422 for(; index < DBVZ_BOOTLOADER_SIZE; index++)
1423 registerArrayWrite8(DBVZ_REG_SIZE - DBVZ_BOOTLOADER_SIZE + index, 0x00);
1424 }
1425
dbvzSetRtc(uint16_t days,uint8_t hours,uint8_t minutes,uint8_t seconds)1426 void dbvzSetRtc(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds){
1427 registerArrayWrite32(RTCTIME, hours << 24 & 0x1F000000 | minutes << 16 & 0x003F0000 | seconds & 0x0000003F);
1428 registerArrayWrite16(DAYR, days & 0x01FF);
1429 }
1430
dbvzStateSize(void)1431 uint32_t dbvzStateSize(void){
1432 uint32_t size = 0;
1433
1434 size += flx68000StateSize();
1435 size += DBVZ_REG_SIZE;//hardware registers
1436 size += DBVZ_TOTAL_MEMORY_BANKS;
1437 size += sizeof(uint32_t) * 4 * DBVZ_CHIP_END;//chip select states
1438 size += sizeof(uint8_t) * 5 * DBVZ_CHIP_END;//chip select states
1439 size += sizeof(uint64_t) * 5;//32.32 fixed point double, timerXCycleCounter and CPU cycle timers
1440 size += sizeof(int8_t);//pllSleepWait
1441 size += sizeof(int8_t);//pllWakeWait
1442 size += sizeof(uint32_t);//clk32Counter
1443 size += sizeof(uint64_t);//pctlrCpuClockDivider
1444 size += sizeof(uint16_t) * 2;//timerStatusReadAcknowledge
1445 size += sizeof(uint8_t);//portDInterruptLastValue
1446 size += sizeof(uint16_t) * 9;//RX 8 * 16 SPI1 FIFO, 1 index is for FIFO full
1447 size += sizeof(uint16_t) * 9;//TX 8 * 16 SPI1 FIFO, 1 index is for FIFO full
1448 size += sizeof(uint8_t) * 5;//spi1(R/T)x(Read/Write)Position / spi1RxOverflowed
1449 size += sizeof(int32_t);//pwm1ClocksToNextSample
1450 size += sizeof(uint8_t) * 6;//pwm1Fifo[6]
1451 size += sizeof(uint8_t) * 2;//pwm1(Read/Write)
1452
1453 return size;
1454 }
1455
dbvzSaveState(uint8_t * data)1456 void dbvzSaveState(uint8_t* data){
1457 uint32_t offset = 0;
1458 uint8_t index;
1459
1460 //CPU core
1461 flx68000SaveState(data + offset);
1462 offset += flx68000StateSize();
1463
1464 //memory
1465 memcpy(data + offset, dbvzReg, DBVZ_REG_SIZE);
1466 swap16BufferIfLittle(data + offset, DBVZ_REG_SIZE / sizeof(uint16_t));
1467 offset += DBVZ_REG_SIZE;
1468 memcpy(data + offset, dbvzBankType, DBVZ_TOTAL_MEMORY_BANKS);
1469 offset += DBVZ_TOTAL_MEMORY_BANKS;
1470 for(index = DBVZ_CHIP_BEGIN; index < DBVZ_CHIP_END; index++){
1471 writeStateValue8(data + offset, dbvzChipSelects[index].enable);
1472 offset += sizeof(uint8_t);
1473 writeStateValue32(data + offset, dbvzChipSelects[index].start);
1474 offset += sizeof(uint32_t);
1475 writeStateValue32(data + offset, dbvzChipSelects[index].lineSize);
1476 offset += sizeof(uint32_t);
1477 writeStateValue32(data + offset, dbvzChipSelects[index].mask);
1478 offset += sizeof(uint32_t);
1479 writeStateValue8(data + offset, dbvzChipSelects[index].inBootMode);
1480 offset += sizeof(uint8_t);
1481 writeStateValue8(data + offset, dbvzChipSelects[index].readOnly);
1482 offset += sizeof(uint8_t);
1483 writeStateValue8(data + offset, dbvzChipSelects[index].readOnlyForProtectedMemory);
1484 offset += sizeof(uint8_t);
1485 writeStateValue8(data + offset, dbvzChipSelects[index].supervisorOnlyProtectedMemory);
1486 offset += sizeof(uint8_t);
1487 writeStateValue32(data + offset, dbvzChipSelects[index].unprotectedSize);
1488 offset += sizeof(uint32_t);
1489 }
1490
1491 //timing
1492 writeStateValueDouble(data + offset, dbvzSysclksPerClk32);
1493 offset += sizeof(uint64_t);
1494 writeStateValueDouble(data + offset, palmCycleCounter);
1495 offset += sizeof(uint64_t);
1496 writeStateValueDouble(data + offset, palmClockMultiplier);
1497 offset += sizeof(uint64_t);
1498 writeStateValue8(data + offset, pllSleepWait);
1499 offset += sizeof(int8_t);
1500 writeStateValue8(data + offset, pllWakeWait);
1501 offset += sizeof(int8_t);
1502 writeStateValue32(data + offset, clk32Counter);
1503 offset += sizeof(uint32_t);
1504 writeStateValueDouble(data + offset, pctlrCpuClockDivider);
1505 offset += sizeof(uint64_t);
1506 writeStateValueDouble(data + offset, timerCycleCounter[0]);
1507 offset += sizeof(uint64_t);
1508 writeStateValueDouble(data + offset, timerCycleCounter[1]);
1509 offset += sizeof(uint64_t);
1510 writeStateValue16(data + offset, timerStatusReadAcknowledge[0]);
1511 offset += sizeof(uint16_t);
1512 writeStateValue16(data + offset, timerStatusReadAcknowledge[1]);
1513 offset += sizeof(uint16_t);
1514 writeStateValue8(data + offset, portDInterruptLastValue);
1515 offset += sizeof(uint8_t);
1516
1517 //SPI1
1518 for(index = 0; index < 9; index++){
1519 writeStateValue16(data + offset, spi1RxFifo[index]);
1520 offset += sizeof(uint16_t);
1521 }
1522 for(index = 0; index < 9; index++){
1523 writeStateValue16(data + offset, spi1TxFifo[index]);
1524 offset += sizeof(uint16_t);
1525 }
1526 writeStateValue8(data + offset, spi1RxReadPosition);
1527 offset += sizeof(uint8_t);
1528 writeStateValue8(data + offset, spi1RxWritePosition);
1529 offset += sizeof(uint8_t);
1530 writeStateValue8(data + offset, spi1RxOverflowed);
1531 offset += sizeof(uint8_t);
1532 writeStateValue8(data + offset, spi1TxReadPosition);
1533 offset += sizeof(uint8_t);
1534 writeStateValue8(data + offset, spi1TxWritePosition);
1535 offset += sizeof(uint8_t);
1536
1537 //PWM1, audio
1538 writeStateValue32(data + offset, pwm1ClocksToNextSample);
1539 offset += sizeof(int32_t);
1540 for(index = 0; index < 6; index++){
1541 writeStateValue8(data + offset, pwm1Fifo[index]);
1542 offset += sizeof(uint8_t);
1543 }
1544 writeStateValue8(data + offset, pwm1ReadPosition);
1545 offset += sizeof(uint8_t);
1546 writeStateValue8(data + offset, pwm1WritePosition);
1547 offset += sizeof(uint8_t);
1548 }
1549
dbvzLoadState(uint8_t * data)1550 void dbvzLoadState(uint8_t* data){
1551 uint32_t offset = 0;
1552 uint8_t index;
1553
1554 //CPU core
1555 flx68000LoadState(data + offset);
1556 offset += flx68000StateSize();
1557
1558 //memory
1559 memcpy(dbvzReg, data + offset, DBVZ_REG_SIZE);
1560 swap16BufferIfLittle(dbvzReg, DBVZ_REG_SIZE / sizeof(uint16_t));
1561 offset += DBVZ_REG_SIZE;
1562 memcpy(dbvzBankType, data + offset, DBVZ_TOTAL_MEMORY_BANKS);
1563 offset += DBVZ_TOTAL_MEMORY_BANKS;
1564 for(index = DBVZ_CHIP_BEGIN; index < DBVZ_CHIP_END; index++){
1565 dbvzChipSelects[index].enable = readStateValue8(data + offset);
1566 offset += sizeof(uint8_t);
1567 dbvzChipSelects[index].start = readStateValue32(data + offset);
1568 offset += sizeof(uint32_t);
1569 dbvzChipSelects[index].lineSize = readStateValue32(data + offset);
1570 offset += sizeof(uint32_t);
1571 dbvzChipSelects[index].mask = readStateValue32(data + offset);
1572 offset += sizeof(uint32_t);
1573 dbvzChipSelects[index].inBootMode = readStateValue8(data + offset);
1574 offset += sizeof(uint8_t);
1575 dbvzChipSelects[index].readOnly = readStateValue8(data + offset);
1576 offset += sizeof(uint8_t);
1577 dbvzChipSelects[index].readOnlyForProtectedMemory = readStateValue8(data + offset);
1578 offset += sizeof(uint8_t);
1579 dbvzChipSelects[index].supervisorOnlyProtectedMemory = readStateValue8(data + offset);
1580 offset += sizeof(uint8_t);
1581 dbvzChipSelects[index].unprotectedSize = readStateValue32(data + offset);
1582 offset += sizeof(uint32_t);
1583 }
1584
1585 //timing
1586 dbvzSysclksPerClk32 = readStateValueDouble(data + offset);
1587 offset += sizeof(uint64_t);
1588 palmCycleCounter = readStateValueDouble(data + offset);
1589 offset += sizeof(uint64_t);
1590 palmClockMultiplier = readStateValueDouble(data + offset);
1591 offset += sizeof(uint64_t);
1592 pllSleepWait = readStateValue8(data + offset);
1593 offset += sizeof(int8_t);
1594 pllWakeWait = readStateValue8(data + offset);
1595 offset += sizeof(int8_t);
1596 clk32Counter = readStateValue32(data + offset);
1597 offset += sizeof(uint32_t);
1598 pctlrCpuClockDivider = readStateValueDouble(data + offset);
1599 offset += sizeof(uint64_t);
1600 timerCycleCounter[0] = readStateValueDouble(data + offset);
1601 offset += sizeof(uint64_t);
1602 timerCycleCounter[1] = readStateValueDouble(data + offset);
1603 offset += sizeof(uint64_t);
1604 timerStatusReadAcknowledge[0] = readStateValue16(data + offset);
1605 offset += sizeof(uint16_t);
1606 timerStatusReadAcknowledge[1] = readStateValue16(data + offset);
1607 offset += sizeof(uint16_t);
1608 portDInterruptLastValue = readStateValue8(data + offset);
1609 offset += sizeof(uint8_t);
1610
1611 //SPI1
1612 for(index = 0; index < 9; index++){
1613 spi1RxFifo[index] = readStateValue16(data + offset);
1614 offset += sizeof(uint16_t);
1615 }
1616 for(index = 0; index < 9; index++){
1617 spi1TxFifo[index] = readStateValue16(data + offset);
1618 offset += sizeof(uint16_t);
1619 }
1620 spi1RxReadPosition = readStateValue8(data + offset);
1621 offset += sizeof(uint8_t);
1622 spi1RxWritePosition = readStateValue8(data + offset);
1623 offset += sizeof(uint8_t);
1624 spi1RxOverflowed = readStateValue8(data + offset);
1625 offset += sizeof(uint8_t);
1626 spi1TxReadPosition = readStateValue8(data + offset);
1627 offset += sizeof(uint8_t);
1628 spi1TxWritePosition = readStateValue8(data + offset);
1629 offset += sizeof(uint8_t);
1630
1631 //PWM1, audio
1632 pwm1ClocksToNextSample = readStateValue32(data + offset);
1633 offset += sizeof(int32_t);
1634 for(index = 0; index < 6; index++){
1635 pwm1Fifo[index] = readStateValue8(data + offset);
1636 offset += sizeof(uint8_t);
1637 }
1638 pwm1ReadPosition = readStateValue8(data + offset);
1639 offset += sizeof(uint8_t);
1640 pwm1WritePosition = readStateValue8(data + offset);
1641 offset += sizeof(uint8_t);
1642
1643 //UART1, cant load state while beaming
1644 uart1RxFifoFlush();
1645
1646 //UART2, cant load state while syncing
1647 uart2RxFifoFlush();
1648 }
1649
dbvzLoadStateFinished(void)1650 void dbvzLoadStateFinished(void){
1651 flx68000LoadStateFinished();
1652 }
1653
dbvzExecute(void)1654 void dbvzExecute(void){
1655 uint32_t samples;
1656
1657 //I/O
1658 m5XXRefreshInputState();
1659
1660 //CPU
1661 dbvzFrameClk32s = 0;
1662 for(; palmCycleCounter < (double)M5XX_CRYSTAL_FREQUENCY / EMU_FPS; palmCycleCounter += 1.0){
1663 uint8_t cpuTimeSegments;
1664
1665 dbvzBeginClk32();
1666
1667 for(cpuTimeSegments = 0; cpuTimeSegments < 2; cpuTimeSegments++){
1668 double cyclesRemaining = dbvzSysclksPerClk32 / 2.0;
1669
1670 while(cyclesRemaining >= 1.0){
1671 double sysclks = FAST_MIN(cyclesRemaining, DBVZ_SYSCLK_PRECISION);
1672 int32_t cpuCycles = sysclks * pctlrCpuClockDivider * palmClockMultiplier;
1673
1674 if(cpuCycles > 0)
1675 flx68000Execute(cpuCycles);
1676 dbvzAddSysclks(sysclks);
1677
1678 cyclesRemaining -= sysclks;
1679 }
1680
1681 //toggle CLK32 bit in PLLFSR, it indicates the current state of CLK32 so it must start false and be changed to true in the middle of CLK32
1682 registerArrayWrite16(PLLFSR, registerArrayRead16(PLLFSR) ^ 0x8000);
1683 }
1684
1685 dbvzEndClk32();
1686 dbvzFrameClk32s++;
1687 }
1688 palmCycleCounter -= (double)M5XX_CRYSTAL_FREQUENCY / EMU_FPS;
1689
1690 //audio
1691 blip_end_frame(palmAudioResampler, blip_clocks_needed(palmAudioResampler, AUDIO_SAMPLES_PER_FRAME));
1692 blip_read_samples(palmAudioResampler, palmAudio, AUDIO_SAMPLES_PER_FRAME, true);
1693 MULTITHREAD_LOOP(samples) for(samples = 0; samples < AUDIO_SAMPLES_PER_FRAME * 2; samples += 2)
1694 palmAudio[samples + 1] = palmAudio[samples];
1695 }
1696