1 //declare I/O port functions in advance
2 static uint8_t getPortAValue(void);
3 static uint8_t getPortBValue(void);
4 static uint8_t getPortCValue(void);
5 static uint8_t getPortDValue(void);
6 static uint8_t getPortEValue(void);
7 static uint8_t getPortFValue(void);
8 static uint8_t getPortGValue(void);
9 static uint8_t getPortJValue(void);
10 static uint8_t getPortKValue(void);
11 static uint8_t getPortMValue(void);
12
13 //basic accessors
registerArrayRead8(uint32_t address)14 static uint8_t registerArrayRead8(uint32_t address){return M68K_BUFFER_READ_8(dbvzReg, address, 0xFFF);}
registerArrayRead16(uint32_t address)15 static uint16_t registerArrayRead16(uint32_t address){return M68K_BUFFER_READ_16(dbvzReg, address, 0xFFF);}
registerArrayRead32(uint32_t address)16 static uint32_t registerArrayRead32(uint32_t address){return M68K_BUFFER_READ_32(dbvzReg, address, 0xFFF);}
registerArrayWrite8(uint32_t address,uint8_t value)17 static void registerArrayWrite8(uint32_t address, uint8_t value){M68K_BUFFER_WRITE_8(dbvzReg, address, 0xFFF, value);}
registerArrayWrite16(uint32_t address,uint16_t value)18 static void registerArrayWrite16(uint32_t address, uint16_t value){M68K_BUFFER_WRITE_16(dbvzReg, address, 0xFFF, value);}
registerArrayWrite32(uint32_t address,uint32_t value)19 static void registerArrayWrite32(uint32_t address, uint32_t value){M68K_BUFFER_WRITE_32(dbvzReg, address, 0xFFF, value);}
20
21 //interrupt setters, used for setting an interrupt with masking by IMR and logging in IPR
setIprIsrBit(uint32_t interruptBit)22 static void setIprIsrBit(uint32_t interruptBit){
23 uint32_t newIpr = registerArrayRead32(IPR) | interruptBit;
24 registerArrayWrite32(IPR, newIpr);
25 registerArrayWrite32(ISR, newIpr & ~registerArrayRead32(IMR));
26 }
27
clearIprIsrBit(uint32_t interruptBit)28 static void clearIprIsrBit(uint32_t interruptBit){
29 uint32_t newIpr = registerArrayRead32(IPR) & ~interruptBit;
30 registerArrayWrite32(IPR, newIpr);
31 registerArrayWrite32(ISR, newIpr & ~registerArrayRead32(IMR));
32 }
33
34 //SPI1 FIFO accessors
spi1RxFifoEntrys(void)35 static uint8_t spi1RxFifoEntrys(void){
36 //check for wraparound
37 if(spi1RxWritePosition < spi1RxReadPosition)
38 return spi1RxWritePosition + 9 - spi1RxReadPosition;
39 return spi1RxWritePosition - spi1RxReadPosition;
40 }
41
spi1RxFifoRead(void)42 static uint16_t spi1RxFifoRead(void){
43 if(spi1RxFifoEntrys() > 0)
44 spi1RxReadPosition = (spi1RxReadPosition + 1) % 9;
45 spi1RxOverflowed = false;
46 return spi1RxFifo[spi1RxReadPosition];
47 }
48
spi1RxFifoWrite(uint16_t value)49 static void spi1RxFifoWrite(uint16_t value){
50 if(spi1RxFifoEntrys() < 8){
51 spi1RxWritePosition = (spi1RxWritePosition + 1) % 9;
52 }
53 else{
54 spi1RxOverflowed = true;
55 debugLog("SPI1 RX FIFO overflowed\n");
56 }
57 spi1RxFifo[spi1RxWritePosition] = value;
58 }
59
spi1RxFifoFlush(void)60 static void spi1RxFifoFlush(void){
61 spi1RxReadPosition = spi1RxWritePosition;
62 }
63
spi1TxFifoEntrys(void)64 static uint8_t spi1TxFifoEntrys(void){
65 //check for wraparound
66 if(spi1TxWritePosition < spi1TxReadPosition)
67 return spi1TxWritePosition + 9 - spi1TxReadPosition;
68 return spi1TxWritePosition - spi1TxReadPosition;
69 }
70
spi1TxFifoRead(void)71 static uint16_t spi1TxFifoRead(void){
72 //dont need a safety check here, the emulator will always check that data is present before trying to access it
73 spi1TxReadPosition = (spi1TxReadPosition + 1) % 9;
74 return spi1TxFifo[spi1TxReadPosition];
75 }
76
spi1TxFifoWrite(uint16_t value)77 static void spi1TxFifoWrite(uint16_t value){
78 if(spi1TxFifoEntrys() < 8){
79 spi1TxWritePosition = (spi1TxWritePosition + 1) % 9;
80 spi1TxFifo[spi1TxWritePosition] = value;
81 }
82 }
83
spi1TxFifoFlush(void)84 static void spi1TxFifoFlush(void){
85 spi1TxReadPosition = spi1TxWritePosition;
86 }
87
88 //UART1 FIFO accessors
uart1RxFifoEntrys(void)89 static uint8_t uart1RxFifoEntrys(void){
90 if(palmIrDataSize){
91 uint32_t fifoEntrys = palmIrDataSize();
92
93 return FAST_MIN(fifoEntrys, 12);
94 }
95 return 0x00;
96 }
97
uart1RxFifoRead(void)98 static uint16_t uart1RxFifoRead(void){
99 if(palmIrDataReceive)
100 return palmIrDataReceive();
101 return 0x0000;
102 }
103
104 //no uart1RxFifoWrite, RX FIFO is written to externally
105
uart1RxFifoFlush(void)106 static void uart1RxFifoFlush(void){
107 if(palmIrDataFlush)
108 palmIrDataFlush();
109 }
110
uart1TxFifoEntrys(void)111 static uint8_t uart1TxFifoEntrys(void){
112 return 0;//all entrys are transmitted instantly so none are left inside the CPU
113 }
114
115 //no uart1TxFifoRead, TX FIFO is read externally
116
uart1TxFifoWrite(uint16_t value)117 static void uart1TxFifoWrite(uint16_t value){
118 if(palmIrDataSend)
119 palmIrDataSend(value);
120 }
121
uart1TxFifoFlush(void)122 static void uart1TxFifoFlush(void){
123 //do nothing, its always empty
124 }
125
126 //UART2 FIFO accessors
uart2RxFifoEntrys(void)127 static uint8_t uart2RxFifoEntrys(void){
128 if(palmSerialDataSize){
129 uint32_t fifoEntrys = palmSerialDataSize();
130
131 return FAST_MIN(fifoEntrys, 64);
132 }
133 return 0x00;
134 }
135
uart2RxFifoRead(void)136 static uint16_t uart2RxFifoRead(void){
137 if(palmSerialDataReceive)
138 return palmSerialDataReceive();
139 return 0x0000;
140 }
141
142 //no uart2RxFifoWrite, RX FIFO is written to externally
143
uart2RxFifoFlush(void)144 static void uart2RxFifoFlush(void){
145 if(palmSerialDataFlush)
146 palmSerialDataFlush();
147 }
148
uart2TxFifoEntrys(void)149 static uint8_t uart2TxFifoEntrys(void){
150 return 0;//all entrys are transmitted instantly so none are left inside the CPU
151 }
152
153 //no uart2TxFifoRead, TX FIFO is read externally
154
uart2TxFifoWrite(uint16_t value)155 static void uart2TxFifoWrite(uint16_t value){
156 if(palmSerialDataSend)
157 palmSerialDataSend(value);
158 }
159
uart2TxFifoFlush(void)160 static void uart2TxFifoFlush(void){
161 //do nothing, its always empty
162 }
163
164 //PWM1 FIFO accessors
pwm1FifoEntrys(void)165 static uint8_t pwm1FifoEntrys(void){
166 //check for wraparound
167 if(pwm1WritePosition < pwm1ReadPosition)
168 return pwm1WritePosition + 6 - pwm1ReadPosition;
169 return pwm1WritePosition - pwm1ReadPosition;
170 }
171
pwm1FifoRunSample(int32_t now,int32_t clockOffset)172 int32_t pwm1FifoRunSample(int32_t now, int32_t clockOffset){
173 uint16_t period = registerArrayRead8(PWMP1) + 2;
174 uint16_t pwmc1 = registerArrayRead16(PWMC1);
175 uint8_t prescaler = (pwmc1 >> 8 & 0x7F) + 1;
176 uint8_t clockDivider = 2 << (pwmc1 & 0x03);
177 uint8_t repeat = 1 << (pwmc1 >> 2 & 0x03);
178 int32_t audioNow = now + clockOffset;
179 int32_t audioSampleDuration = (pwmc1 & 0x8000)/*CLKSRC*/ ? audioGetFramePercentIncrementFromClk32s(period * prescaler * clockDivider) : audioGetFramePercentIncrementFromSysclks(period * prescaler * clockDivider);
180 float dutyCycle;
181 uint8_t index;
182
183 //try to get next sample, if none are available play old sample
184 if(pwm1FifoEntrys() > 0)
185 pwm1ReadPosition = (pwm1ReadPosition + 1) % 6;
186 dutyCycle = FAST_MIN((float)pwm1Fifo[pwm1ReadPosition] / period, 1.00);
187
188 for(index = 0; index < repeat; index++){
189 #if !defined(EMU_NO_SAFETY)
190 if(audioNow + audioSampleDuration >= DBVZ_AUDIO_MAX_CLOCK_RATE)
191 break;
192 #endif
193
194 blip_add_delta(palmAudioResampler, audioNow, dutyCycle * AUDIO_SPEAKER_RANGE);
195 blip_add_delta(palmAudioResampler, audioNow + audioSampleDuration * dutyCycle, (dutyCycle - 1.00) * AUDIO_SPEAKER_RANGE);
196 audioNow += audioSampleDuration;
197 }
198
199 //check for interrupt
200 if(pwm1FifoEntrys() < 2){
201 //trigger interrupt if enabled
202 if(pwmc1 & 0x0040)
203 setIprIsrBit(DBVZ_INT_PWM1);
204 //checkInterrupts() is run when the clock that called this function is finished
205
206 registerArrayWrite16(PWMC1, pwmc1 | 0x0080);//set IRQ bit
207 }
208
209 return audioSampleDuration * repeat;
210 }
211
pwm1FifoWrite(uint8_t value)212 static void pwm1FifoWrite(uint8_t value){
213 if(pwm1FifoEntrys() < 5){
214 pwm1WritePosition = (pwm1WritePosition + 1) % 6;
215 pwm1Fifo[pwm1WritePosition] = value;
216 }
217 }
218
pwm1FifoFlush(void)219 static void pwm1FifoFlush(void){
220 pwm1ReadPosition = pwm1WritePosition;
221 pwm1Fifo[pwm1WritePosition] = 0x00;
222 }
223
224 //register setters
setCsa(uint16_t value)225 static void setCsa(uint16_t value){
226 dbvzChipSelects[DBVZ_CHIP_A0_ROM].enable = value & 0x0001;
227 dbvzChipSelects[DBVZ_CHIP_A0_ROM].readOnly = !!(value & 0x8000);
228 dbvzChipSelects[DBVZ_CHIP_A0_ROM].lineSize = 0x20000/*128kb*/ << (value >> 1 & 0x0007);
229
230 //CSA is now just a normal chip select
231 if(dbvzChipSelects[DBVZ_CHIP_A0_ROM].enable && dbvzChipSelects[DBVZ_CHIP_A0_ROM].inBootMode)
232 dbvzChipSelects[DBVZ_CHIP_A0_ROM].inBootMode = false;
233
234 dbvzChipSelects[DBVZ_CHIP_A1_USB].enable = dbvzChipSelects[DBVZ_CHIP_A0_ROM].enable;
235 dbvzChipSelects[DBVZ_CHIP_A1_USB].readOnly = dbvzChipSelects[DBVZ_CHIP_A0_ROM].readOnly;
236 dbvzChipSelects[DBVZ_CHIP_A1_USB].start = dbvzChipSelects[DBVZ_CHIP_A0_ROM].start + dbvzChipSelects[DBVZ_CHIP_A0_ROM].lineSize;
237 dbvzChipSelects[DBVZ_CHIP_A1_USB].lineSize = dbvzChipSelects[DBVZ_CHIP_A0_ROM].lineSize;
238
239 registerArrayWrite16(CSA, value & 0x81FF);
240 }
241
setCsb(uint16_t value)242 static void setCsb(uint16_t value){
243 uint16_t csControl1 = registerArrayRead16(CSCTRL1);
244
245 dbvzChipSelects[DBVZ_CHIP_B0_SED].enable = value & 0x0001;
246 dbvzChipSelects[DBVZ_CHIP_B0_SED].readOnly = !!(value & 0x8000);
247 dbvzChipSelects[DBVZ_CHIP_B0_SED].lineSize = 0x20000/*128kb*/ << (value >> 1 & 0x0007);
248
249 //attributes
250 dbvzChipSelects[DBVZ_CHIP_B0_SED].supervisorOnlyProtectedMemory = !!(value & 0x4000);
251 dbvzChipSelects[DBVZ_CHIP_B0_SED].readOnlyForProtectedMemory = !!(value & 0x2000);
252 if(csControl1 & 0x4000 && csControl1 & 0x0001)
253 dbvzChipSelects[DBVZ_CHIP_B0_SED].unprotectedSize = dbvzChipSelects[DBVZ_CHIP_B0_SED].lineSize / (1 << 7 - ((value >> 11 & 0x0003) | 0x0004));
254 else
255 dbvzChipSelects[DBVZ_CHIP_B0_SED].unprotectedSize = dbvzChipSelects[DBVZ_CHIP_B0_SED].lineSize / (1 << 7 - (value >> 11 & 0x0003));
256
257 dbvzChipSelects[DBVZ_CHIP_B1_NIL].enable = dbvzChipSelects[DBVZ_CHIP_B0_SED].enable;
258 dbvzChipSelects[DBVZ_CHIP_B1_NIL].readOnly = dbvzChipSelects[DBVZ_CHIP_B0_SED].readOnly;
259 dbvzChipSelects[DBVZ_CHIP_B1_NIL].start = dbvzChipSelects[DBVZ_CHIP_B0_SED].start + dbvzChipSelects[DBVZ_CHIP_B0_SED].lineSize;
260 dbvzChipSelects[DBVZ_CHIP_B1_NIL].lineSize = dbvzChipSelects[DBVZ_CHIP_B0_SED].lineSize;
261 dbvzChipSelects[DBVZ_CHIP_B1_NIL].supervisorOnlyProtectedMemory = dbvzChipSelects[DBVZ_CHIP_B0_SED].supervisorOnlyProtectedMemory;
262 dbvzChipSelects[DBVZ_CHIP_B1_NIL].readOnlyForProtectedMemory = dbvzChipSelects[DBVZ_CHIP_B0_SED].readOnlyForProtectedMemory;
263 dbvzChipSelects[DBVZ_CHIP_B1_NIL].unprotectedSize = dbvzChipSelects[DBVZ_CHIP_B0_SED].unprotectedSize;
264
265 registerArrayWrite16(CSB, value & 0xF9FF);
266 }
267
setCsd(uint16_t value)268 static void setCsd(uint16_t value){
269 uint16_t csControl1 = registerArrayRead16(CSCTRL1);
270
271 dbvzChipSelects[DBVZ_CHIP_DX_RAM].enable = value & 0x0001;
272 dbvzChipSelects[DBVZ_CHIP_DX_RAM].readOnly = !!(value & 0x8000);
273 if(csControl1 & 0x0040 && value & 0x0200)
274 dbvzChipSelects[DBVZ_CHIP_DX_RAM].lineSize = 0x800000/*8mb*/ << (value >> 1 & 0x0001);
275 else
276 dbvzChipSelects[DBVZ_CHIP_DX_RAM].lineSize = 0x8000/*32kb*/ << (value >> 1 & 0x0007);
277
278 //attributes
279 dbvzChipSelects[DBVZ_CHIP_DX_RAM].supervisorOnlyProtectedMemory = !!(value & 0x4000);
280 dbvzChipSelects[DBVZ_CHIP_DX_RAM].readOnlyForProtectedMemory = !!(value & 0x2000);
281 if(csControl1 & 0x4000 && csControl1 & 0x0010)
282 dbvzChipSelects[DBVZ_CHIP_DX_RAM].unprotectedSize = dbvzChipSelects[DBVZ_CHIP_DX_RAM].lineSize / (1 << 7 - ((value >> 11 & 0x0003) | 0x0004));
283 else
284 dbvzChipSelects[DBVZ_CHIP_DX_RAM].unprotectedSize = dbvzChipSelects[DBVZ_CHIP_DX_RAM].lineSize / (1 << 7 - (value >> 11 & 0x0003));
285
286 //debugLog("RAM unprotected size:0x%08X, bits:0x%02X\n", dbvzChipSelects[DBVZ_CHIP_DX_RAM].unprotectedSize, ((value >> 11 & 0x0003) | (csControl1 & 0x4000 && csControl1 & 0x0010) * 0x0004));
287
288 registerArrayWrite16(CSD, value);
289 }
290
setCsgba(uint16_t value)291 static void setCsgba(uint16_t value){
292 uint16_t csugba = registerArrayRead16(CSUGBA);
293
294 //add extra address bits if enabled
295 if(csugba & 0x8000)
296 dbvzChipSelects[DBVZ_CHIP_A0_ROM].start = (csugba >> 12 & 0x0007) << 29 | value >> 1 << 14;
297 else
298 dbvzChipSelects[DBVZ_CHIP_A0_ROM].start = value >> 1 << 14;
299
300 dbvzChipSelects[DBVZ_CHIP_A1_USB].start = dbvzChipSelects[DBVZ_CHIP_A0_ROM].start + dbvzChipSelects[DBVZ_CHIP_A0_ROM].lineSize;
301
302 registerArrayWrite16(CSGBA, value & 0xFFFE);
303 }
304
setCsgbb(uint16_t value)305 static void setCsgbb(uint16_t value){
306 uint16_t csugba = registerArrayRead16(CSUGBA);
307
308 //add extra address bits if enabled
309 if(csugba & 0x8000)
310 dbvzChipSelects[DBVZ_CHIP_B0_SED].start = (csugba >> 8 & 0x0007) << 29 | value >> 1 << 14;
311 else
312 dbvzChipSelects[DBVZ_CHIP_B0_SED].start = value >> 1 << 14;
313
314 dbvzChipSelects[DBVZ_CHIP_B1_NIL].start = dbvzChipSelects[DBVZ_CHIP_B0_SED].start + dbvzChipSelects[DBVZ_CHIP_B0_SED].lineSize;
315
316 registerArrayWrite16(CSGBB, value & 0xFFFE);
317 }
318
setCsgbd(uint16_t value)319 static void setCsgbd(uint16_t value){
320 uint16_t csugba = registerArrayRead16(CSUGBA);
321
322 //add extra address bits if enabled
323 if(csugba & 0x8000)
324 dbvzChipSelects[DBVZ_CHIP_DX_RAM].start = (csugba & 0x0007) << 29 | value >> 1 << 14;
325 else
326 dbvzChipSelects[DBVZ_CHIP_DX_RAM].start = value >> 1 << 14;
327
328 registerArrayWrite16(CSGBD, value & 0xFFFE);
329 }
330
updateCsdAddressLines(void)331 static void updateCsdAddressLines(void){
332 uint16_t dramc = registerArrayRead16(DRAMC);
333 uint16_t sdctrl = registerArrayRead16(SDCTRL);
334
335 if(registerArrayRead16(CSD) & 0x0200 && sdctrl & 0x8000 && dramc & 0x8000 && !(dramc & 0x0400)){
336 //this register can remap address lines, that behavior is way too CPU intensive and complicated so only the "memory testing" and "correct" behavior is being emulated
337 dbvzChipSelects[DBVZ_CHIP_DX_RAM].mask = 0x003FFFFF;
338
339 //address line 23 is enabled
340 if(!palmEmulatingM500 && (sdctrl & 0x000C) == 0x0008)
341 dbvzChipSelects[DBVZ_CHIP_DX_RAM].mask |= 0x00800000;
342
343 //address line 22 is enabled
344 if(palmEmulatingM500 || (sdctrl & 0x0030) == 0x0010)
345 dbvzChipSelects[DBVZ_CHIP_DX_RAM].mask |= 0x00400000;
346 }
347 else{
348 //RAM is not enabled properly
349 dbvzChipSelects[DBVZ_CHIP_DX_RAM].mask = 0x00000000;
350 }
351 }
352
setPllfsr(uint16_t value)353 static void setPllfsr(uint16_t value){
354 uint16_t oldPllfsr = registerArrayRead16(PLLFSR);
355
356 //change frequency if frequency protect bit isnt set
357 if(!(oldPllfsr & 0x4000)){
358 registerArrayWrite16(PLLFSR, (value & 0x4CFF) | (oldPllfsr & 0x8000));//preserve CLK32 bit
359 dbvzSysclksPerClk32 = sysclksPerClk32();
360 }
361 }
362
setScr(uint8_t value)363 static void setScr(uint8_t value){
364 uint8_t oldScr = registerArrayRead8(SCR);
365 uint8_t newScr = value & 0x1F;
366
367 //preserve privilege violation, write protect violation and bus error timeout
368 newScr |= oldScr & 0xE0;
369
370 //clear violations on writing 1 to them
371 newScr &= ~(value & 0xE0);
372
373 dbvzChipSelects[DBVZ_CHIP_REGISTERS].supervisorOnlyProtectedMemory = value & 0x08;
374
375 registerArrayWrite8(SCR, newScr);//must be written before calling setRegisterFFFFAccessMode
376 if((newScr & 0x04) != (oldScr & 0x04)){
377 if(newScr & 0x04)
378 dbvzSetRegisterXXFFAccessMode();
379 else
380 dbvzSetRegisterFFFFAccessMode();
381 }
382 }
383
setIlcr(uint16_t value)384 static void setIlcr(uint16_t value){
385 uint16_t oldIlcr = registerArrayRead16(ILCR);
386 uint16_t newIlcr = 0x0000;
387
388 //SPI1, interrupt level 0 an 7 are invalid values that cause the register not to update
389 if((value & 0x7000) != 0x0000 && (value & 0x7000) != 0x7000)
390 newIlcr |= value & 0x7000;
391 else
392 newIlcr |= oldIlcr & 0x7000;
393
394 //UART2, interrupt level 0 an 7 are invalid values that cause the register not to update
395 if((value & 0x0700) != 0x0000 && (value & 0x0700) != 0x0700)
396 newIlcr |= value & 0x0700;
397 else
398 newIlcr |= oldIlcr & 0x0700;
399
400 //PWM2, interrupt level 0 an 7 are invalid values that cause the register not to update
401 if((value & 0x0070) != 0x0000 && (value & 0x0070) != 0x0070)
402 newIlcr |= value & 0x0070;
403 else
404 newIlcr |= oldIlcr & 0x0070;
405
406 //TMR2, interrupt level 0 an 7 are invalid values that cause the register not to update
407 if((value & 0x0007) != 0x0000 && (value & 0x0007) != 0x0007)
408 newIlcr |= value & 0x0007;
409 else
410 newIlcr |= oldIlcr & 0x0007;
411
412 registerArrayWrite16(ILCR, newIlcr);
413 }
414
setSpiIntCs(uint16_t value)415 static void setSpiIntCs(uint16_t value){
416 uint16_t oldSpiIntCs = registerArrayRead16(SPIINTCS);
417 uint16_t newSpiIntCs = value & 0xFF00;
418 uint8_t rxEntrys = spi1RxFifoEntrys();
419 uint8_t txEntrys = spi1TxFifoEntrys();
420
421 //newSpiIntCs |= spi1TxOverflowed << 7;//BO, slave mode not supported
422 newSpiIntCs |= spi1RxOverflowed << 6;//RO
423 newSpiIntCs |= (rxEntrys == 8) << 5;//RF
424 newSpiIntCs |= (rxEntrys >= 4) << 4;//RH
425 newSpiIntCs |= (rxEntrys > 0) << 3;//RR
426 newSpiIntCs |= (txEntrys == 8) << 2;//TF
427 newSpiIntCs |= (txEntrys >= 4) << 1;//TH, TODO: the datasheet contradicts itself on whether its more than or equal to 4 empty or full slots
428 newSpiIntCs |= txEntrys == 0;//TE
429
430 //if interrupt state changed update interrupts too, top 8 bits are just the enable bits for the bottom 8
431 if(!!(newSpiIntCs >> 8 & newSpiIntCs) != !!(oldSpiIntCs >> 8 & oldSpiIntCs)){
432 if(newSpiIntCs >> 8 & newSpiIntCs)
433 setIprIsrBit(DBVZ_INT_SPI1);
434 else
435 clearIprIsrBit(DBVZ_INT_SPI1);
436 checkInterrupts();
437 }
438
439 registerArrayWrite16(SPIINTCS, newSpiIntCs);
440 }
441
setSpiCont1(uint16_t value)442 static void setSpiCont1(uint16_t value){
443 //only master mode is implemented(even then only partially)!!!
444 uint16_t oldSpiCont1 = registerArrayRead16(SPICONT1);
445
446 //debugLog("SPICONT1 write, old value:0x%04X, value:0x%04X\n", oldSpiCont1, value);
447
448 //SPI1 disabled
449 if(oldSpiCont1 & 0x0200 && !(value & 0x0200)){
450 spi1RxFifoFlush();
451 spi1TxFifoFlush();
452 }
453
454 //slave mode and enabled, dont know what to do
455 //if(!(value & 0x0400) && value & 0x0200)
456 // debugLog("SPI1 set to slave mode, PC:0x%08X\n", flx68000GetPc());
457
458 //do a transfer if enabled(this register write and last) and exchange set
459 if(value & oldSpiCont1 & 0x0200 && value & 0x0100){
460 while(spi1TxFifoEntrys() > 0){
461 uint16_t currentTxFifoEntry = spi1TxFifoRead();
462 uint16_t newRxFifoEntry;// = 0x0000;
463 uint8_t bitCount = (value & 0x000F) + 1;
464 //uint16_t startBit = 1 << (bitCount - 1);
465 //uint8_t bits;
466
467 //debugLog("SPI1 transfer, bitCount:%d, PC:0x%08X\n", bitCount, flx68000GetPc());
468
469 //The most significant bit is output when the CPU loads the transmitted data, 13.2.3 SPI 1 Phase and Polarity Configurations MC68VZ328UM.pdf
470 /*
471 for(bits = 0; bits < bitCount; bits++){
472 newRxFifoEntry <<= 1;
473 newRxFifoEntry |= sdCardExchangeBit(!!(currentTxFifoEntry & startBit));
474 currentTxFifoEntry <<= 1;
475 }
476 */
477 newRxFifoEntry = sdCardExchangeXBitsOptimized(currentTxFifoEntry, bitCount);
478
479 //add received data back to RX FIFO
480 spi1RxFifoWrite(newRxFifoEntry);
481
482 //overflow occured, remove 1 FIFO entry
483 //I do not currently know if the FIFO entry is removed from the back or front of the FIFO, going with the back for now
484 //if(spi1RxFifoEntrys() == 0)
485 // spi1RxFifoRead();
486 }
487 }
488
489 //update SPIINTCS interrupt bits
490 setSpiIntCs(registerArrayRead16(SPIINTCS));
491
492 //unset XCH, transfers are instant since timing is not emulated
493 value &= 0xFEFF;
494
495 //debugLog("Transfer complete, SPIINTCS:0x%04X\n", registerArrayRead16(SPIINTCS));
496
497 registerArrayWrite16(SPICONT1, value);
498 }
499
setSpiCont2(uint16_t value)500 static void setSpiCont2(uint16_t value){
501 //the ENABLE bit must be set before the transfer and in the transfer command
502 //important bits are ENABLE, XCH, IRQ, IRQEN and BITCOUNT
503 uint16_t oldSpiCont2 = registerArrayRead16(SPICONT2);
504
505 //force or clear an interrupt
506 if((value & 0x00C0) == 0x00C0)
507 setIprIsrBit(DBVZ_INT_SPI2);
508 else
509 clearIprIsrBit(DBVZ_INT_SPI2);
510
511 //do a transfer if enabled(this register write and last) and exchange set
512 if(value & oldSpiCont2 & 0x0200 && value & 0x0100){
513 uint8_t bitCount = (value & 0x000F) + 1;
514 uint16_t startBit = 1 << (bitCount - 1);
515 uint16_t spi2Data = registerArrayRead16(SPIDATA2);
516 bool spiClk2Enabled = !(registerArrayRead8(PESEL) & 0x04);
517 //uint16_t oldSpi2Data = spi2Data;
518
519 //the input data is shifted into the unused bits if the transfer is less than 16 bits
520 if(spiClk2Enabled){
521 uint8_t bits;
522
523 //shift in valid data
524 for(bits = 0; bits < bitCount; bits++){
525 bool newBit = ads7846ExchangeBit(!!(spi2Data & startBit));
526 spi2Data <<= 1;
527 spi2Data |= newBit;
528 }
529 }
530 else{
531 //shift in 0s, this is inaccurate, it should be whatever the last bit on SPIRXD(the SPI2 pin, not the SPI1 register) was
532 spi2Data <<= bitCount;
533 }
534 registerArrayWrite16(SPIDATA2, spi2Data);
535
536 //debugLog("SPI2 transfer, ENABLE:%s, XCH:%s, IRQ:%s, IRQEN:%s, BITCOUNT:%d\n", boolString(value & 0x0200), boolString(value & 0x0100), boolString(value & 0x0080), boolString(value & 0x0400), (value & 0x000F) + 1);
537 //debugLog("SPI2 transfer, before:0x%04X, after:0x%04X, PC:0x%08X\n", oldSpi2Data, spi2Data, m68k_get_reg(NULL, M68K_REG_PPC));
538
539 //unset XCH, transfers are instant since timing is not emulated
540 value &= 0xFEFF;
541
542 //acknowledge transfer finished, transfers are instant since timing is not emulated
543 value |= 0x0080;
544
545 //IRQEN set, send an interrupt after transfer
546 if(value & 0x0040)
547 setIprIsrBit(DBVZ_INT_SPI2);
548 }
549
550 //check for any interrupts from the transfer
551 checkInterrupts();
552
553 registerArrayWrite16(SPICONT2, value & 0xE3FF);
554 }
555
updateUart1PortState(void)556 static void updateUart1PortState(void){
557 if(palmIrSetPortProperties){
558 uint16_t ustcnt1 = registerArrayRead16(USTCNT1);
559 uint16_t ubaud1 = registerArrayRead16(UBAUD1);
560 uint8_t divider = 1 << (ubaud1 >> 8 & 0x07);
561 uint8_t prescaler = 65 - (ubaud1 & 0x001F);
562 bool baudSrc = !!(ubaud1 & 0x0800);
563 serial_port_properties_t properties;
564
565 properties.enable = !!(ustcnt1 & 0x8000);
566 properties.enableParity = !!(ustcnt1 & 0x0800);
567 properties.oddParity = !!(ustcnt1 & 0x0400);
568 properties.stopBits = !!(ustcnt1 & 0x0200) ? 2 : 1;
569 properties.use8BitMode = !!(ustcnt1 & 0x0100);
570 properties.baudRate = (baudSrc ? EMU_SERIAL_USE_EXTERNAL_CLOCK_SOURCE : sysclksPerClk32() * M5XX_CRYSTAL_FREQUENCY) / prescaler / divider;
571
572 palmIrSetPortProperties(&properties);
573 }
574 }
575
updateUart1Interrupt(void)576 static void updateUart1Interrupt(void){
577 //the UART1 interrupt has a rather complex set of trigger methods so they all have to be checked after one changes to prevent clearing a valid interrupt thats on the same line
578 uint16_t ustcnt1 = registerArrayRead16(USTCNT1);
579 bool interruptState = false;
580
581 //is enabled
582 if(ustcnt1 & 0x8000){
583 //RX is enabled
584 if(ustcnt1 & 0x4000){
585 uint16_t urx1 = registerArrayRead16(URX1);
586 uint8_t entrys = uart1RxFifoEntrys();
587
588 //TODO: old data timer is unemualted
589 //if(ustcnt1 & 0x0080 && entrys > 0)
590 // interruptState = true;
591
592 if(ustcnt1 & 0x0020 && entrys == 12)
593 interruptState = true;
594 if(ustcnt1 & 0x0010 && entrys > 6)
595 interruptState = true;
596 if(ustcnt1 & 0x0008 && entrys > 0)
597 interruptState = true;
598 }
599
600 //TX is enabled
601 if(ustcnt1 & 0x2000){
602 uint16_t utx1 = registerArrayRead16(UTX1);
603 uint8_t entrys = uart1TxFifoEntrys();
604
605 if(ustcnt1 & 0x0004 && entrys == 0)
606 interruptState = true;
607 if(ustcnt1 & 0x0002 && entrys < 4)
608 interruptState = true;
609 if(ustcnt1 & 0x0001 && entrys < 8)
610 interruptState = true;
611 }
612 }
613
614 if(interruptState)
615 setIprIsrBit(DBVZ_INT_UART1);
616 else
617 clearIprIsrBit(DBVZ_INT_UART1);
618 checkInterrupts();
619 }
620
setUstcnt1(uint16_t value)621 static void setUstcnt1(uint16_t value){
622 //flush RX FIFO if disabled
623 if(!((value & 0xC000) == 0xC000))
624 uart1RxFifoFlush();
625
626 //flush TX FIFO if disabled
627 if(!((value & 0xA000) == 0xA000))
628 uart1TxFifoFlush();
629
630 registerArrayWrite16(USTCNT1, value);
631 updateUart1Interrupt();
632 }
633
updateUart2PortState(void)634 static void updateUart2PortState(void){
635 if(palmSerialSetPortProperties){
636 uint16_t ustcnt2 = registerArrayRead16(USTCNT2);
637 uint16_t ubaud2 = registerArrayRead16(UBAUD2);
638 uint8_t divider = 1 << (ubaud2 >> 8 & 0x07);
639 uint8_t prescaler = 65 - (ubaud2 & 0x001F);
640 bool baudSrc = !!(ubaud2 & 0x0800);
641 serial_port_properties_t properties;
642
643 properties.enable = !!(ustcnt2 & 0x8000);
644 properties.enableParity = !!(ustcnt2 & 0x0800);
645 properties.oddParity = !!(ustcnt2 & 0x0400);
646 properties.stopBits = !!(ustcnt2 & 0x0200) ? 2 : 1;
647 properties.use8BitMode = !!(ustcnt2 & 0x0100);
648 properties.baudRate = (baudSrc ? EMU_SERIAL_USE_EXTERNAL_CLOCK_SOURCE : sysclksPerClk32() * M5XX_CRYSTAL_FREQUENCY) / prescaler / divider;
649
650 palmSerialSetPortProperties(&properties);
651 }
652 }
653
updateUart2Interrupt(void)654 static void updateUart2Interrupt(void){
655 //the UART2 interrupt has a rather complex set of trigger methods so they all have to be checked after one changes to prevent clearing a valid interrupt thats on the same line
656 uint16_t ustcnt2 = registerArrayRead16(USTCNT2);
657 uint16_t hmark = registerArrayRead16(HMARK);
658 uint8_t hmarkRx = (hmark & 0x0F) * 4;
659 uint8_t hmarkTx = (hmark >> 8) * 4;
660 bool interruptState = false;
661
662 //is enabled
663 if(ustcnt2 & 0x8000){
664 //RX is enabled
665 if(ustcnt2 & 0x4000){
666 uint16_t urx2 = registerArrayRead16(URX2);
667 uint8_t entrys = uart2RxFifoEntrys();
668
669 //TODO: old data timer is unemualted
670 //if(ustcnt2 & 0x0080 && entrys > 0)
671 // interruptState = true;
672
673 if(ustcnt2 & 0x0020 && entrys == 64)
674 interruptState = true;
675 if(ustcnt2 & 0x0010 && entrys > hmarkRx && hmarkRx != 0x00)
676 interruptState = true;
677 if(ustcnt2 & 0x0008 && entrys > 0)
678 interruptState = true;
679 }
680
681 //TX is enabled
682 if(ustcnt2 & 0x2000){
683 uint16_t utx2 = registerArrayRead16(UTX2);
684 uint8_t entrys = uart2TxFifoEntrys();
685
686 if(ustcnt2 & 0x0004 && entrys == 0)
687 interruptState = true;
688 if(ustcnt2 & 0x0002 && entrys < hmarkTx && hmarkTx != 0x00)
689 interruptState = true;
690 if(ustcnt2 & 0x0001 && entrys < 64)
691 interruptState = true;
692 }
693 }
694
695 if(interruptState)
696 setIprIsrBit(DBVZ_INT_UART2);
697 else
698 clearIprIsrBit(DBVZ_INT_UART2);
699 checkInterrupts();
700 }
701
setUstcnt2(uint16_t value)702 static void setUstcnt2(uint16_t value){
703 //flush RX FIFO if disabled
704 if(!((value & 0xC000) == 0xC000))
705 uart2RxFifoFlush();
706
707 //flush TX FIFO if disabled
708 if(!((value & 0xA000) == 0xA000))
709 uart2TxFifoFlush();
710
711 registerArrayWrite16(USTCNT2, value);
712 updateUart2Interrupt();
713 }
714
setTstat1(uint16_t value)715 static void setTstat1(uint16_t value){
716 uint16_t oldTstat1 = registerArrayRead16(TSTAT1);
717 uint16_t newTstat1 = (value & timerStatusReadAcknowledge[0]) | (oldTstat1 & ~timerStatusReadAcknowledge[0]);
718
719 //debugLog("TSTAT1 write, old value:0x%04X, new value:0x%04X, write value:0x%04X\n", oldTstat1, newTstat1, value);
720
721 if(!(newTstat1 & 0x0001) && (oldTstat1 & 0x0001)){
722 //debugLog("Timer 1 interrupt cleared.\n");
723 clearIprIsrBit(DBVZ_INT_TMR1);
724 checkInterrupts();
725 }
726 timerStatusReadAcknowledge[0] &= newTstat1;//clear acknowledged reads cleared bits
727 registerArrayWrite16(TSTAT1, newTstat1);
728 }
729
setTstat2(uint16_t value)730 static void setTstat2(uint16_t value){
731 uint16_t oldTstat2 = registerArrayRead16(TSTAT2);
732 uint16_t newTstat2 = (value & timerStatusReadAcknowledge[1]) | (oldTstat2 & ~timerStatusReadAcknowledge[1]);
733
734 //debugLog("TSTAT2 write, old value:0x%04X, new value:0x%04X, write value:0x%04X\n", oldTstat2, newTstat2, value);
735
736 if(!(newTstat2 & 0x0001) && (oldTstat2 & 0x0001)){
737 //debugLog("Timer 2 interrupt cleared.\n");
738 clearIprIsrBit(DBVZ_INT_TMR2);
739 checkInterrupts();
740 }
741 timerStatusReadAcknowledge[1] &= newTstat2;//clear acknowledged reads for cleared bits
742 registerArrayWrite16(TSTAT2, newTstat2);
743 }
744
setPwmc1(uint16_t value)745 static void setPwmc1(uint16_t value){
746 uint16_t oldPwmc1 = registerArrayRead16(PWMC1);
747
748 //dont allow manually setting FIFOAV
749 value &= 0xFFDF;
750
751 //PWM1 enabled, set IRQ
752 if(!(oldPwmc1 & 0x0010) && value & 0x0010){
753 value |= 0x0080;//enable IRQ
754 pwm1ClocksToNextSample = 0;//when first sample is written output it immediately
755 }
756
757 //clear interrupt by write(reading can also clear the interrupt)
758 if(oldPwmc1 & 0x0080 && !(value & 0x0080)){
759 clearIprIsrBit(DBVZ_INT_PWM1);
760 checkInterrupts();
761 }
762
763 //interrupt enabled and interrupt set
764 if((value & 0x00C0) == 0x00C0){
765 //this register also allows forcing an interrupt by writing a 1 to its IRQ bit when IRQEN is enabled
766 setIprIsrBit(DBVZ_INT_PWM1);
767 checkInterrupts();
768 }
769
770 //PWM1 disabled
771 if(oldPwmc1 & 0x0010 && !(value & 0x0010)){
772 pwm1FifoFlush();
773 value &= 0x80FF;//clear PWM prescaler value
774 }
775
776 registerArrayWrite16(PWMC1, value);
777 }
778
setIsr(uint32_t value,bool useTopWord,bool useBottomWord)779 static void setIsr(uint32_t value, bool useTopWord, bool useBottomWord){
780 //Palm OS uses this 32 bit register as 2 16 bit registers
781
782 //prevent any internal hardware interrupts from being cleared
783 value &= 0x000F0F00;//IRQ5 is always level triggered
784
785 if(useTopWord){
786 uint16_t interruptControlRegister = registerArrayRead16(ICR);
787
788 //IRQ1 is not edge triggered
789 if(!(interruptControlRegister & 0x0800))
790 value &= ~DBVZ_INT_IRQ1;
791
792 //IRQ2 is not edge triggered
793 if(!(interruptControlRegister & 0x0400))
794 value &= ~DBVZ_INT_IRQ2;
795
796 //IRQ3 is not edge triggered
797 if(!(interruptControlRegister & 0x0200))
798 value &= ~DBVZ_INT_IRQ3;
799
800 //IRQ6 is not edge triggered
801 if(!(interruptControlRegister & 0x0100))
802 value &= ~DBVZ_INT_IRQ6;
803
804 registerArrayWrite16(IPR, registerArrayRead16(IPR) & ~(value >> 16));
805 registerArrayWrite16(ISR, registerArrayRead16(ISR) & ~(value >> 16));
806 }
807 if(useBottomWord){
808 uint8_t portDEdgeSelect = registerArrayRead8(PDIRQEG);
809
810 registerArrayWrite16(IPR + 2, registerArrayRead16(IPR + 2) & ~(value & 0xFFFF & portDEdgeSelect << 8));
811 registerArrayWrite16(ISR + 2, registerArrayRead16(ISR + 2) & ~(value & 0xFFFF & portDEdgeSelect << 8));
812 }
813
814 checkInterrupts();
815 }
816
817 //register getters
getPortDInputPinValues(void)818 static uint8_t getPortDInputPinValues(void){
819 uint8_t requestedRow = ~getPortKValue();
820 uint8_t portDInputValues = 0x00;
821
822 //portDInputValues |= 0x80;//battery dead bit, dont know the proper level to set this
823
824 if(palmSdCard.flashChipData)
825 portDInputValues |= 0x20;
826
827 //kbd row 0
828 if(requestedRow & 0x20)
829 portDInputValues |= palmInput.buttonCalendar | palmInput.buttonAddress << 1 | palmInput.buttonTodo << 2 | palmInput.buttonNotes << 3;
830
831 //kbd row 1
832 if(requestedRow & 0x40)
833 portDInputValues |= palmInput.buttonUp | palmInput.buttonDown << 1;
834
835 //kbd row 2
836 if(requestedRow & 0x80)
837 portDInputValues |= palmInput.buttonPower;
838
839 //the port d pins state is high for false, invert them on return, Palm OS uses PDPOL to swap back to pressed == 1
840 return ~portDInputValues;
841 }
842
getPortAValue(void)843 static uint8_t getPortAValue(void){
844 //not attached, used as CPU data lines
845 return 0x00;
846 }
847
getPortBValue(void)848 static uint8_t getPortBValue(void){
849 return ((registerArrayRead8(PBDATA) & registerArrayRead8(PBDIR)) | ~registerArrayRead8(PBDIR)) & registerArrayRead8(PBSEL);
850 }
851
getPortCValue(void)852 static uint8_t getPortCValue(void){
853 //port c uses pull downs not pull ups
854 return registerArrayRead8(PCDATA) & registerArrayRead8(PCDIR) & registerArrayRead8(PCSEL);
855 }
856
getPortDValue(void)857 static uint8_t getPortDValue(void){
858 uint8_t portDValue = getPortDInputPinValues();
859 uint8_t portDData = registerArrayRead8(PDDATA);
860 uint8_t portDDir = registerArrayRead8(PDDIR);
861 uint8_t portDPolarity = registerArrayRead8(PDPOL);
862
863 portDValue ^= portDPolarity;//only input polarity is affected by PDPOL
864 portDValue &= ~portDDir;//only use above pin values for inputs, port d allows using special function pins as inputs while active unlike other ports
865 portDValue |= portDData & portDDir;//if a pin is an output and has its data bit set return that too
866
867 return portDValue;
868 }
869
getPortEValue(void)870 static uint8_t getPortEValue(void){
871 return ((registerArrayRead8(PEDATA) & registerArrayRead8(PEDIR)) | ~registerArrayRead8(PEDIR)) & registerArrayRead8(PESEL);
872 }
873
getPortFValue(void)874 static uint8_t getPortFValue(void){
875 uint8_t portFValue = 0x00;
876 uint8_t portFData = registerArrayRead8(PFDATA);
877 uint8_t portFDir = registerArrayRead8(PFDIR);
878 uint8_t portFSel = registerArrayRead8(PFSEL);
879 bool penIrqPin = ads7846PenIrqEnabled ? !palmInput.touchscreenTouched : true;//penIrqPin pulled low on touch
880
881 portFValue |= penIrqPin << 1;
882 portFValue |= 0x85;//bit 7 & 2<->0 have pull ups, bits 6<->3 have pull downs, bit 2 is occupied by PENIRQ
883 portFValue &= ~portFDir & (portFSel | 0x02);//IRQ5 is readable even when PFSEL bit 2 is false
884 portFValue |= portFData & portFDir & portFSel;
885
886 return portFValue;
887 }
888
getPortGValue(void)889 static uint8_t getPortGValue(void){
890 //port g only has 6 pins not 8
891 uint8_t portGValue = 0x00;
892 uint8_t portGData = registerArrayRead8(PGDATA);
893 uint8_t portGDir = registerArrayRead8(PGDIR);
894 uint8_t portGSel = registerArrayRead8(PGSEL);
895
896 portGValue |= (palmMisc.backlightLevel > 0) << 1;
897 portGValue |= 0x3D;//floating pins are high
898 portGValue &= ~portGDir & portGSel;
899 portGValue |= portGData & portGDir & portGSel;
900
901 return portGValue;
902 }
903
getPortJValue(void)904 static uint8_t getPortJValue(void){
905 return ((registerArrayRead8(PJDATA) & registerArrayRead8(PJDIR)) | ~registerArrayRead8(PJDIR)) & registerArrayRead8(PJSEL);
906 }
907
getPortKValue(void)908 static uint8_t getPortKValue(void){
909 uint8_t portKValue = 0x00;
910 uint8_t portKData = registerArrayRead8(PKDATA);
911 uint8_t portKDir = registerArrayRead8(PKDIR);
912 uint8_t portKSel = registerArrayRead8(PKSEL);
913
914 portKValue |= !palmMisc.batteryCharging << 2;//false if chargeing
915 portKValue |= 0xFB;//floating pins are high
916 portKValue &= ~portKDir & portKSel;
917 portKValue |= portKData & portKDir & portKSel;
918
919 return portKValue;
920 }
921
getPortMValue(void)922 static uint8_t getPortMValue(void){
923 //bit 5 has a pull up not pull down, bits 4<->0 have a pull down, bit 7<->6 are not active at all
924 return ((registerArrayRead8(PMDATA) & registerArrayRead8(PMDIR)) | (~registerArrayRead8(PMDIR) & 0x20)) & registerArrayRead8(PMSEL);
925 }
926
samplePwm1(bool forClk32,double sysclks)927 static void samplePwm1(bool forClk32, double sysclks){
928 uint16_t pwmc1 = registerArrayRead16(PWMC1);
929
930 //validate clock mode
931 if(forClk32 != !!(pwmc1 & 0x8000))
932 return;
933
934 if(pwmc1 & 0x0010){
935 int32_t audioNow = audioGetFramePercentage();
936
937 //add cycles
938 pwm1ClocksToNextSample -= forClk32 ? audioGetFramePercentIncrementFromClk32s(1) : audioGetFramePercentIncrementFromSysclks(sysclks);
939
940 //use samples
941 while(pwm1ClocksToNextSample <= 0){
942 //play samples until waiting(pwm1ClocksToNextSample is positive), if no new samples are available the newest old sample will be played
943 int32_t audioUsed = pwm1FifoRunSample(audioNow, pwm1ClocksToNextSample);
944 pwm1ClocksToNextSample += audioUsed;
945 audioNow += audioUsed;
946 }
947 }
948 }
949
getPwmc1(void)950 static uint16_t getPwmc1(void){
951 uint16_t returnValue = registerArrayRead16(PWMC1);
952
953 //have FIFOAV set if a slot is available
954 if(pwm1FifoEntrys() < 5)
955 returnValue |= 0x0020;
956
957 //clear INT_PWM1 if active
958 if(returnValue & 0x0080){
959 clearIprIsrBit(DBVZ_INT_PWM1);
960 checkInterrupts();
961 registerArrayWrite16(PWMC1, returnValue & 0xFF5F);
962 }
963
964 //the REPEAT field is write only
965 returnValue &= 0xFFF3;
966
967 return returnValue;
968 }
969
970 //updaters
updatePowerButtonLedStatus(void)971 static void updatePowerButtonLedStatus(void){
972 palmMisc.greenLed = !!(getPortBValue() & 0x40) != palmMisc.batteryCharging;
973 }
974
updateVibratorStatus(void)975 static void updateVibratorStatus(void){
976 palmMisc.vibratorOn = !!(getPortKValue() & 0x10);
977 }
978
updateAds7846ChipSelectStatus(void)979 static void updateAds7846ChipSelectStatus(void){
980 ads7846SetChipSelect(!!(getPortGValue() & 0x04));
981 }
982
updateSdCardChipSelectStatus(void)983 static void updateSdCardChipSelectStatus(void){
984 sdCardSetChipSelect(!!(getPortJValue() & 0x08));
985 }
986
updateTouchState(void)987 static void updateTouchState(void){
988 if(!(registerArrayRead8(PFSEL) & registerArrayRead8(PFDIR) & 0x02)){
989 if((ads7846PenIrqEnabled ? !palmInput.touchscreenTouched : true) == !!(registerArrayRead16(ICR) & 0x0080))
990 setIprIsrBit(DBVZ_INT_IRQ5);
991 else
992 clearIprIsrBit(DBVZ_INT_IRQ5);
993 }
994 }
995