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