1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include "emulator.h"
7 #include "audio/blip_buf.h"
8 #include "dbvz.h"
9 #include "m5XXBus.h"
10 #include "sed1376.h"
11 #include "ads7846.h"
12 #include "pdiUsbD12.h"
13 #include "sdCard.h"
14 #include "silkscreen.h"
15 #include "portability.h"
16 #if defined(EMU_SUPPORT_PALM_OS5)
17 #include "tungstenT3Bus.h"
18 #include "pxa260/pxa260.h"
19 #include "tps65010.h"
20 #include "tsc2101.h"
21 #include "w86l488.h"
22 #endif
23 
24 
25 //Memory map of Palm m515
26 //0x00000000<->0x00FFFFFF RAM, CSC0 as RAS0, CSC1 as RAS1, CSD0 as CAS0 and CSD1 as CAS1
27 //0x10000000<->0x103FFFFF ROM, CSA0, at address 0x00000000 during boot, palmos41-en-m515.rom, substitute "en" for your language code
28 //0x10400000<->0x10400003 USB, CSA1
29 //0x1FF80000<->0x1FF800B3 SED1376(Display Controller) Registers, CSB0
30 //0x1FFA0000<->0x1FFB3FFF SED1376(Display Controller) Framebuffer, CSB0, this is not the same as the Palm framebuffer which is always 16 bit color,
31 //this buffer must be processed depending on whats in the SED1376 registers, the result is the Palm framebuffer
32 //0xFFFFF000<->0xFFFFFDFF Hardware Registers
33 //0xFFFFFE00<->0xFFFFFFFF Bootloader, only reads from UART into RAM and jumps to it, never executed in consumer Palms
34 
35 //Memory map of Tungsten T3
36 //Boot address ranges, these are changed with the MMU after boot
37 //0x00000000<->0x003FFFFF ROM
38 //0xA0000000<->0xA3FFFFFF RAM
39 //Post boot address ranges:
40 //0x00000000<->0x003FFFFF RAM
41 //0x20000000<->0x20FFFFFF ROM
42 //TODO: add other chips
43 
44 //VGhpcyBlbXVsYXRvciBpcyBkZWRpY2F0ZWQgdG8gdGhlIGJvdmluZSBtb28gY293cyB0aGF0IG1vby4=
45 
46 
47 static bool emulatorInitialized = false;
48 
49 #if defined(EMU_SUPPORT_PALM_OS5)
50 bool      palmEmulatingTungstenT3;
51 #endif
52 bool      palmEmulatingM500;
53 uint8_t*  palmRam;
54 uint8_t*  palmRom;
55 input_t   palmInput;
56 sd_card_t palmSdCard;
57 misc_hw_t palmMisc;
58 uint16_t* palmFramebuffer;
59 uint16_t  palmFramebufferWidth;
60 uint16_t  palmFramebufferHeight;
61 int16_t*  palmAudio;
62 blip_t*   palmAudioResampler;
63 double    palmCycleCounter;//can be greater then 0 if too many cycles where run
64 double    palmClockMultiplier;//used by the emulator to overclock the emulated Palm
65 bool      palmSyncRtc;//doesnt go in save states, its a property of the session not the device
66 bool      palmAllowInvalidBehavior;//doesnt go in save states, its a property of the session not the device
67 void      (*palmIrSetPortProperties)(serial_port_properties_t* properties);//configure port I/O behavior, used for proxyed native I/R connections
68 uint32_t  (*palmIrDataSize)(void);//returns the current number of bytes in the hosts IR receive FIFO
69 uint16_t  (*palmIrDataReceive)(void);//called by the emulator to read the hosts IR receive FIFO
70 void      (*palmIrDataSend)(uint16_t data);//called by the emulator to send IR data
71 void      (*palmIrDataFlush)(void);//called by the emulator to delete all data in the hosts IR receive FIFO
72 void      (*palmSerialSetPortProperties)(serial_port_properties_t* properties);//configure port I/O behavior, used for proxyed native serial connections
73 uint32_t  (*palmSerialDataSize)(void);//returns the current number of bytes in the hosts serial receive FIFO
74 uint16_t  (*palmSerialDataReceive)(void);//called by the emulator to read the hosts serial receive FIFO
75 void      (*palmSerialDataSend)(uint16_t data);//called by the emulator to send serial data
76 void      (*palmSerialDataFlush)(void);//called by the emulator to delete all data in the hosts serial receive FIFO
77 void      (*palmGetRtcFromHost)(uint8_t* writeBack);//[0] = hours, [1] = minutes, [2] = seconds
78 
79 
patchOsRom(uint32_t address,char * patch)80 static void patchOsRom(uint32_t address, char* patch){
81    uint32_t offset;
82    uint32_t patchBytes = strlen(patch) / 2;//1 char per nibble
83    uint32_t swapBegin = address & 0xFFFFFFFE;
84    uint32_t swapSize = patchBytes / sizeof(uint16_t) + 1;
85    char conv[5] = "0xXX";
86 
87 #if defined(EMU_SUPPORT_PALM_OS5)
88    if(!palmEmulatingTungstenT3)
89 #endif
90       swap16BufferIfLittle(&palmRom[swapBegin], swapSize);
91    for(offset = 0; offset < patchBytes; offset++){
92       conv[2] = patch[offset * 2];
93       conv[3] = patch[offset * 2 + 1];
94       palmRom[address + offset] = strtol(conv, NULL, 0);
95    }
96 #if defined(EMU_SUPPORT_PALM_OS5)
97    if(!palmEmulatingTungstenT3)
98 #endif
99       swap16BufferIfLittle(&palmRom[swapBegin], swapSize);
100 }
101 
102 
emulatorInit(uint8_t emulatedDevice,uint8_t * palmRomData,uint32_t palmRomSize,uint8_t * palmBootloaderData,uint32_t palmBootloaderSize,bool syncRtc,bool allowInvalidBehavior)103 uint32_t emulatorInit(uint8_t emulatedDevice, uint8_t* palmRomData, uint32_t palmRomSize, uint8_t* palmBootloaderData, uint32_t palmBootloaderSize, bool syncRtc, bool allowInvalidBehavior){
104    if(emulatorInitialized)
105       return EMU_ERROR_RESOURCE_LOCKED;
106 
107    palmSyncRtc = syncRtc;
108    palmAllowInvalidBehavior = allowInvalidBehavior;
109 
110    if(!palmRomData || palmRomSize < 0x8)
111       return EMU_ERROR_INVALID_PARAMETER;
112 
113    palmIrSetPortProperties = NULL;
114    palmIrDataSize = NULL;
115    palmIrDataReceive = NULL;
116    palmIrDataSend = NULL;
117    palmIrDataFlush = NULL;
118    palmSerialSetPortProperties = NULL;
119    palmSerialDataSize = NULL;
120    palmSerialDataReceive = NULL;
121    palmSerialDataSend = NULL;
122    palmSerialDataFlush = NULL;
123    palmGetRtcFromHost = NULL;
124 
125 #if defined(EMU_SUPPORT_PALM_OS5)
126    palmEmulatingTungstenT3 = emulatedDevice == EMU_DEVICE_TUNGSTEN_T3;
127 
128    if(palmEmulatingTungstenT3){
129       //emulating Tungsten T3
130       bool dynarecInited = false;
131 
132       dynarecInited = pxa260Init(&palmRom, &palmRam);
133       palmFramebuffer = malloc(320 * 480 * sizeof(uint16_t));
134       palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t));
135       palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples
136       if(!palmFramebuffer || !palmAudio || !palmAudioResampler || !dynarecInited){
137          free(palmFramebuffer);
138          free(palmAudio);
139          blip_delete(palmAudioResampler);
140          pxa260Deinit();
141          return EMU_ERROR_OUT_OF_MEMORY;
142       }
143       memcpy(palmRom, palmRomData, FAST_MIN(palmRomSize, TUNGSTEN_T3_ROM_SIZE));
144       if(palmRomSize < TUNGSTEN_T3_ROM_SIZE)
145          memset(palmRom + palmRomSize, 0x00, TUNGSTEN_T3_ROM_SIZE - palmRomSize);
146       memset(palmRam, 0x00, TUNGSTEN_T3_RAM_SIZE);
147       memset(palmFramebuffer, 0x00, 320 * 480 * sizeof(uint16_t));//TODO:PXA260 code doesnt always output a picture like my SED1376 code, so clear the buffer to prevent garbage from being displayed before the first render
148       memset(palmAudio, 0x00, AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
149       memset(&palmInput, 0x00, sizeof(palmInput));
150       memset(&palmMisc, 0x00, sizeof(palmMisc));
151       memset(&palmSdCard, 0x00, sizeof(palmSdCard));
152       palmFramebufferWidth = 320;
153       palmFramebufferHeight = 480;
154       palmMisc.batteryLevel = 100;
155       palmCycleCounter = 0.0;
156       palmClockMultiplier = 1.00 - TUNGSTEN_T3_CPU_PERCENT_WAITING;
157 
158       //initialize components, I dont think theres much in a Tungsten T3
159       pxa260Framebuffer = palmFramebuffer;
160       blip_set_rates(palmAudioResampler, DBVZ_AUDIO_MAX_CLOCK_RATE, AUDIO_SAMPLE_RATE);
161 
162       patchOsRom(0x333EC6, "0000");//blocks out the slot driver
163       patchOsRom(0x205C, "0000A0E1");//blocks idle loop jump with NOP
164 
165       //reset everything
166       emulatorSoftReset();
167       pxa260SetRtc(0, 0, 0, 0);
168    }
169    else{
170 #endif
171       //emulating Palm m515 or m500
172       palmEmulatingM500 = emulatedDevice == EMU_DEVICE_PALM_M500;
173 
174       //allocate buffers, add 4 to memory regions to prevent SIGSEGV from accessing off the end
175       palmRom = malloc(M5XX_ROM_SIZE + 4);
176       palmRam = malloc((palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) + 4);
177       palmFramebuffer = malloc(160 * 220 * sizeof(uint16_t));
178       palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t));
179       palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples
180       if(!palmRom || !palmRam || !palmFramebuffer || !palmAudio || !palmAudioResampler){
181          free(palmRom);
182          free(palmRam);
183          free(palmFramebuffer);
184          free(palmAudio);
185          blip_delete(palmAudioResampler);
186          return EMU_ERROR_OUT_OF_MEMORY;
187       }
188 
189       //set default values
190       memcpy(palmRom, palmRomData, FAST_MIN(palmRomSize, M5XX_ROM_SIZE));
191       if(palmRomSize < M5XX_ROM_SIZE)
192          memset(palmRom + palmRomSize, 0x00, M5XX_ROM_SIZE - palmRomSize);
193       swap16BufferIfLittle(palmRom, M5XX_ROM_SIZE / sizeof(uint16_t));
194       memset(palmRam, 0x00, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
195       dbvzLoadBootloader(palmBootloaderData, palmBootloaderSize);
196       memcpy(palmFramebuffer + 160 * 160, silkscreen160x60, 160 * 60 * sizeof(uint16_t));
197       memset(palmAudio, 0x00, AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
198       memset(&palmInput, 0x00, sizeof(palmInput));
199       memset(&palmMisc, 0x00, sizeof(palmMisc));
200       memset(&palmSdCard, 0x00, sizeof(palmSdCard));
201       palmFramebufferWidth = 160;
202       palmFramebufferHeight = 220;
203       palmMisc.batteryLevel = 100;
204       palmCycleCounter = 0.0;
205       palmClockMultiplier = 1.00 - DBVZ_CPU_PERCENT_WAITING;
206       if(palmEmulatingM500){
207          dbvzFramebuffer = palmFramebuffer;
208          dbvzFramebufferWidth = 160;
209          dbvzFramebufferHeight = 160;
210       }
211       else{
212          sed1376Framebuffer = palmFramebuffer;
213          sed1376FramebufferWidth = 160;
214          sed1376FramebufferHeight = 160;
215       }
216 
217       //initialize components
218       blip_set_rates(palmAudioResampler, DBVZ_AUDIO_MAX_CLOCK_RATE, AUDIO_SAMPLE_RATE);
219 
220       //reset everything
221       emulatorSoftReset();
222       dbvzSetRtc(0, 0, 0, 0);//RTCTIME and DAYR are not cleared by reset, clear them manually in case the frontend doesnt set the RTC
223 #if defined(EMU_SUPPORT_PALM_OS5)
224    }
225 #endif
226 
227    emulatorInitialized = true;
228 
229    return EMU_ERROR_NONE;
230 }
231 
emulatorDeinit(void)232 void emulatorDeinit(void){
233    if(emulatorInitialized){
234 #if defined(EMU_SUPPORT_PALM_OS5)
235       if(!palmEmulatingTungstenT3){
236 #endif
237          free(palmRom);
238          free(palmRam);
239 #if defined(EMU_SUPPORT_PALM_OS5)
240       }
241 #endif
242       free(palmFramebuffer);
243       free(palmAudio);
244       blip_delete(palmAudioResampler);
245 #if defined(EMU_SUPPORT_PALM_OS5)
246       if(palmEmulatingTungstenT3)
247          pxa260Deinit();
248 #endif
249       free(palmSdCard.flashChipData);
250       emulatorInitialized = false;
251    }
252 }
253 
emulatorHardReset(void)254 void emulatorHardReset(void){
255    //equivalent to taking the battery out and putting it back in
256 #if defined(EMU_SUPPORT_PALM_OS5)
257    if(palmEmulatingTungstenT3){
258       memset(palmRam, 0x00, TUNGSTEN_T3_RAM_SIZE);
259       emulatorSoftReset();
260       sdCardReset();
261       pxa260SetRtc(0, 0, 0, 0);
262    }
263    else{
264 #endif
265       memset(palmRam, 0x00, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
266       emulatorSoftReset();
267       sdCardReset();
268       dbvzSetRtc(0, 0, 0, 0);
269 #if defined(EMU_SUPPORT_PALM_OS5)
270    }
271 #endif
272 }
273 
emulatorSoftReset(void)274 void emulatorSoftReset(void){
275    //equivalent to pushing the reset button on the back of the device
276 #if defined(EMU_SUPPORT_PALM_OS5)
277    if(palmEmulatingTungstenT3){
278       pxa260Reset();
279       tps65010Reset();
280       tsc2101Reset(true);
281       w86l488Reset();
282    }
283    else{
284 #endif
285       if(!palmEmulatingM500)
286          sed1376Reset();
287       ads7846Reset();
288       pdiUsbD12Reset();
289       dbvzReset();
290       //sdCardReset() should not be called here, the SD card does not have a reset line and should only be reset by a power cycle
291 #if defined(EMU_SUPPORT_PALM_OS5)
292    }
293 #endif
294 }
295 
emulatorSetRtc(uint16_t days,uint8_t hours,uint8_t minutes,uint8_t seconds)296 void emulatorSetRtc(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds){
297 #if defined(EMU_SUPPORT_PALM_OS5)
298    if(palmEmulatingTungstenT3)
299       pxa260SetRtc(days, hours, minutes, seconds);
300    else
301 #endif
302       dbvzSetRtc(days, hours, minutes, seconds);
303 }
304 
emulatorSetCpuSpeed(double speed)305 void emulatorSetCpuSpeed(double speed){
306 #if defined(EMU_SUPPORT_PALM_OS5)
307    if(palmEmulatingTungstenT3)
308       palmClockMultiplier = speed * (1.00 - TUNGSTEN_T3_CPU_PERCENT_WAITING);
309    else
310 #endif
311       palmClockMultiplier = speed * (1.00 - DBVZ_CPU_PERCENT_WAITING);
312 }
313 
emulatorGetStateSize(void)314 uint32_t emulatorGetStateSize(void){
315    uint32_t size = 0;
316 
317    size += sizeof(uint32_t);//save state version
318    size += sizeof(uint32_t);//palmEmuFeatures.info
319    size += sizeof(uint64_t);//palmSdCard.flashChipSize, needs to be done first to verify the malloc worked
320    size += sizeof(uint16_t) * 2;//palmFramebuffer(Width/Height)
321 #if defined(EMU_SUPPORT_PALM_OS5)
322    if(palmEmulatingTungstenT3){
323       size += pxa260StateSize();
324       size += TUNGSTEN_T3_RAM_SIZE;//system RAM buffer
325    }
326    else{
327 #endif
328       size += dbvzStateSize();
329       if(!palmEmulatingM500)
330          size += sed1376StateSize();
331       size += ads7846StateSize();
332       size += pdiUsbD12StateSize();
333       size += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;//system RAM buffer
334 #if defined(EMU_SUPPORT_PALM_OS5)
335    }
336 #endif
337    size += sizeof(uint8_t) * 7;//palmMisc
338    size += sizeof(uint32_t) * 4;//palmEmuFeatures.(src/dst/size/value)
339    size += sizeof(uint64_t);//palmSdCard.command
340    size += sizeof(uint8_t) * 7;//palmSdCard.(commandBitsRemaining/runningCommand/commandIsAcmd/allowInvalidCrc/chipSelect/receivingCommand/inIdleState)
341    size += sizeof(uint16_t) * 2;//palmSdCard.response(Read/Write)Position
342    size += sizeof(int8_t);//palmSdCard.responseReadPositionBit
343    size += sizeof(uint32_t) * 3;//palmSdCard.runningCommandVars
344    size += SD_CARD_BLOCK_DATA_PACKET_SIZE;//palmSdCard.runningCommandPacket
345    size += SD_CARD_RESPONSE_FIFO_SIZE;//palmSdCard.responseFifo
346    size += 16 * 2;//palmSdCard.sdInfo.csd/cid
347    size += 8;//palmSdCard.sdInfo.scr
348    size += sizeof(uint32_t);//palmSdCard.sdInfo.ocr
349    size += sizeof(uint8_t);//palmSdCard.sdInfo.writeProtectSwitch
350    size += palmSdCard.flashChipSize;//palmSdCard.flashChipData
351 
352    return size;
353 }
354 
emulatorSaveState(uint8_t * data,uint32_t size)355 bool emulatorSaveState(uint8_t* data, uint32_t size){
356    uint32_t offset = 0;
357    uint8_t index;
358 
359    if(size < emulatorGetStateSize())
360       return false;//state cant fit
361 
362    //state validation, wont load states that are not from the same state version
363 #if defined(EMU_SUPPORT_PALM_OS5)
364    writeStateValue32(data + offset, SAVE_STATE_VERSION | palmEmulatingTungstenT3 * SAVE_STATE_FOR_TUNGSTEN_T3 | palmEmulatingM500 * SAVE_STATE_FOR_M500);
365 #else
366    writeStateValue32(data + offset, SAVE_STATE_VERSION | palmEmulatingM500 * SAVE_STATE_FOR_M500);
367 #endif
368    offset += sizeof(uint32_t);
369 
370    //SD card size
371    writeStateValue64(data + offset, palmSdCard.flashChipSize);
372    offset += sizeof(uint64_t);
373 
374    //screen state
375    writeStateValue16(data + offset, palmFramebufferWidth);
376    offset += sizeof(uint16_t);
377    writeStateValue16(data + offset, palmFramebufferHeight);
378    offset += sizeof(uint16_t);
379 
380 #if defined(EMU_SUPPORT_PALM_OS5)
381    if(palmEmulatingTungstenT3){
382       //chips
383       pxa260SaveState(data + offset);
384       offset += pxa260StateSize();
385 
386       //memory
387       memcpy(data + offset, palmRam, TUNGSTEN_T3_RAM_SIZE);
388       offset += TUNGSTEN_T3_RAM_SIZE;
389    }
390    else{
391 #endif
392       //chips
393       dbvzSaveState(data + offset);
394       offset += dbvzStateSize();
395       if(!palmEmulatingM500){
396          sed1376SaveState(data + offset);
397          offset += sed1376StateSize();
398       }
399       ads7846SaveState(data + offset);
400       offset += ads7846StateSize();
401       pdiUsbD12SaveState(data + offset);
402       offset += pdiUsbD12StateSize();
403 
404       //memory
405       memcpy(data + offset, palmRam, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
406       swap16BufferIfLittle(data + offset, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
407       offset += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
408 #if defined(EMU_SUPPORT_PALM_OS5)
409    }
410 #endif
411 
412    //misc
413    writeStateValue8(data + offset, palmMisc.greenLed);
414    offset += sizeof(uint8_t);
415    writeStateValue8(data + offset, palmMisc.lcdOn);
416    offset += sizeof(uint8_t);
417    writeStateValue8(data + offset, palmMisc.backlightLevel);
418    offset += sizeof(uint8_t);
419    writeStateValue8(data + offset, palmMisc.vibratorOn);
420    offset += sizeof(uint8_t);
421    writeStateValue8(data + offset, palmMisc.batteryCharging);
422    offset += sizeof(uint8_t);
423    writeStateValue8(data + offset, palmMisc.batteryLevel);
424    offset += sizeof(uint8_t);
425    writeStateValue8(data + offset, palmMisc.dataPort);
426    offset += sizeof(uint8_t);
427 
428    //SD card
429    writeStateValue64(data + offset, palmSdCard.command);
430    offset += sizeof(uint64_t);
431    writeStateValue8(data + offset, palmSdCard.commandBitsRemaining);
432    offset += sizeof(uint8_t);
433    writeStateValue8(data + offset, palmSdCard.runningCommand);
434    offset += sizeof(uint8_t);
435    for(index = 0; index < 3; index++){
436       writeStateValue32(data + offset, palmSdCard.runningCommandVars[index]);
437       offset += sizeof(uint32_t);
438    }
439    memcpy(data + offset, palmSdCard.runningCommandPacket, SD_CARD_BLOCK_DATA_PACKET_SIZE);
440    offset += SD_CARD_BLOCK_DATA_PACKET_SIZE;
441    memcpy(data + offset, palmSdCard.responseFifo, SD_CARD_RESPONSE_FIFO_SIZE);
442    offset += SD_CARD_RESPONSE_FIFO_SIZE;
443    writeStateValue16(data  + offset, palmSdCard.responseReadPosition);
444    offset += sizeof(uint16_t);
445    writeStateValue8(data + offset, palmSdCard.responseReadPositionBit);
446    offset += sizeof(int8_t);
447    writeStateValue16(data  + offset, palmSdCard.responseWritePosition);
448    offset += sizeof(uint16_t);
449    writeStateValue8(data + offset, palmSdCard.commandIsAcmd);
450    offset += sizeof(uint8_t);
451    writeStateValue8(data + offset, palmSdCard.allowInvalidCrc);
452    offset += sizeof(uint8_t);
453    writeStateValue8(data + offset, palmSdCard.chipSelect);
454    offset += sizeof(uint8_t);
455    writeStateValue8(data + offset, palmSdCard.receivingCommand);
456    offset += sizeof(uint8_t);
457    writeStateValue8(data + offset, palmSdCard.inIdleState);
458    offset += sizeof(uint8_t);
459    memcpy(data + offset, palmSdCard.sdInfo.csd, 16);
460    offset += 16;
461    memcpy(data + offset, palmSdCard.sdInfo.cid, 16);
462    offset += 16;
463    memcpy(data + offset, palmSdCard.sdInfo.scr, 8);
464    offset += 8;
465    writeStateValue32(data + offset, palmSdCard.sdInfo.ocr);
466    offset += sizeof(uint32_t);
467    writeStateValue8(data + offset, palmSdCard.sdInfo.writeProtectSwitch);
468    offset += sizeof(uint8_t);
469    memcpy(data + offset, palmSdCard.flashChipData, palmSdCard.flashChipSize);
470    offset += palmSdCard.flashChipSize;
471 
472    return true;
473 }
474 
emulatorLoadState(uint8_t * data,uint32_t size)475 bool emulatorLoadState(uint8_t* data, uint32_t size){
476    uint32_t offset = 0;
477    uint8_t index;
478    uint32_t stateSdCardSize;
479    uint8_t* stateSdCardBuffer;
480 
481    //state validation, wont load states that are not from the same state version
482 #if defined(EMU_SUPPORT_PALM_OS5)
483    if(readStateValue32(data + offset) != (SAVE_STATE_VERSION | palmEmulatingTungstenT3 * SAVE_STATE_FOR_TUNGSTEN_T3 | palmEmulatingM500 * SAVE_STATE_FOR_M500))
484       return false;
485 #else
486    if(readStateValue32(data + offset) != (SAVE_STATE_VERSION | palmEmulatingM500 * SAVE_STATE_FOR_M500))
487       return false;
488 #endif
489    offset += sizeof(uint32_t);
490 
491    //SD card size, the malloc when loading can make it fail, make sure if it fails the emulator state doesnt change
492    stateSdCardSize = readStateValue64(data + offset);
493    stateSdCardBuffer = stateSdCardSize > 0 ? malloc(stateSdCardSize) : NULL;
494    if(stateSdCardSize > 0 && !stateSdCardBuffer)
495       return false;
496    offset += sizeof(uint64_t);
497 
498    //screen state
499    palmFramebufferWidth = readStateValue16(data + offset);
500    offset += sizeof(uint16_t);
501    palmFramebufferHeight = readStateValue16(data + offset);
502    offset += sizeof(uint16_t);
503 
504 #if defined(EMU_SUPPORT_PALM_OS5)
505    if(palmEmulatingTungstenT3){
506       //chips
507       pxa260LoadState(data + offset);
508       offset += pxa260StateSize();
509 
510       //memory
511       memcpy(palmRam, data + offset, TUNGSTEN_T3_RAM_SIZE);
512       offset += TUNGSTEN_T3_RAM_SIZE;
513    }
514    else{
515 #endif
516       //chips
517       dbvzLoadState(data + offset);
518       offset += dbvzStateSize();
519       if(!palmEmulatingM500){
520          sed1376LoadState(data + offset);
521          offset += sed1376StateSize();
522       }
523       ads7846LoadState(data + offset);
524       offset += ads7846StateSize();
525       pdiUsbD12LoadState(data + offset);
526       offset += pdiUsbD12StateSize();
527 
528       //memory
529       memcpy(palmRam, data + offset, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
530       swap16BufferIfLittle(palmRam, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
531       offset += palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
532 #if defined(EMU_SUPPORT_PALM_OS5)
533    }
534 #endif
535 
536    //misc
537    palmMisc.greenLed = readStateValue8(data + offset);
538    offset += sizeof(uint8_t);
539    palmMisc.lcdOn = readStateValue8(data + offset);
540    offset += sizeof(uint8_t);
541    palmMisc.backlightLevel = readStateValue8(data + offset);
542    offset += sizeof(uint8_t);
543    palmMisc.vibratorOn = readStateValue8(data + offset);
544    offset += sizeof(uint8_t);
545    palmMisc.batteryCharging = readStateValue8(data + offset);
546    offset += sizeof(uint8_t);
547    palmMisc.batteryLevel = readStateValue8(data + offset);
548    offset += sizeof(uint8_t);
549    palmMisc.dataPort = readStateValue8(data + offset);
550    offset += sizeof(uint8_t);
551 
552    //SD card
553    palmSdCard.command = readStateValue64(data + offset);
554    offset += sizeof(uint64_t);
555    palmSdCard.commandBitsRemaining = readStateValue8(data + offset);
556    offset += sizeof(uint8_t);
557    palmSdCard.runningCommand = readStateValue8(data + offset);
558    offset += sizeof(uint8_t);
559    for(index = 0; index < 3; index++){
560       palmSdCard.runningCommandVars[index] = readStateValue32(data + offset);
561       offset += sizeof(uint32_t);
562    }
563    memcpy(palmSdCard.runningCommandPacket, data + offset, SD_CARD_BLOCK_DATA_PACKET_SIZE);
564    offset += SD_CARD_BLOCK_DATA_PACKET_SIZE;
565    memcpy(palmSdCard.responseFifo, data + offset, SD_CARD_RESPONSE_FIFO_SIZE);
566    offset += SD_CARD_RESPONSE_FIFO_SIZE;
567    palmSdCard.responseReadPosition = readStateValue16(data  + offset);
568    offset += sizeof(uint16_t);
569    palmSdCard.responseReadPositionBit = readStateValue8(data + offset);
570    offset += sizeof(int8_t);
571    palmSdCard.responseWritePosition = readStateValue16(data  + offset);
572    offset += sizeof(uint16_t);
573    palmSdCard.commandIsAcmd = readStateValue8(data + offset);
574    offset += sizeof(uint8_t);
575    palmSdCard.allowInvalidCrc = readStateValue8(data + offset);
576    offset += sizeof(uint8_t);
577    palmSdCard.chipSelect = readStateValue8(data + offset);
578    offset += sizeof(uint8_t);
579    palmSdCard.receivingCommand = readStateValue8(data + offset);
580    offset += sizeof(uint8_t);
581    palmSdCard.inIdleState = readStateValue8(data + offset);
582    offset += sizeof(uint8_t);
583    memcpy(palmSdCard.sdInfo.csd, data + offset, 16);
584    offset += 16;
585    memcpy(palmSdCard.sdInfo.cid, data + offset, 16);
586    offset += 16;
587    memcpy(palmSdCard.sdInfo.scr, data + offset, 8);
588    offset += 8;
589    palmSdCard.sdInfo.ocr = readStateValue32(data + offset);
590    offset += sizeof(uint32_t);
591    palmSdCard.sdInfo.writeProtectSwitch = readStateValue8(data + offset);
592    offset += sizeof(uint8_t);
593    if(palmSdCard.flashChipData)
594       free(palmSdCard.flashChipData);
595    palmSdCard.flashChipData = stateSdCardBuffer;
596    palmSdCard.flashChipSize = stateSdCardSize;
597    memcpy(palmSdCard.flashChipData, data + offset, stateSdCardSize);
598    offset += stateSdCardSize;
599 
600    //some modules depend on all the state memory being loaded before certian required actions can occur(refreshing cached data, freeing memory blocks)
601    dbvzLoadStateFinished();
602 
603    return true;
604 }
605 
emulatorGetRamSize(void)606 uint32_t emulatorGetRamSize(void){
607 #if defined(EMU_SUPPORT_PALM_OS5)
608    if(palmEmulatingTungstenT3)
609       return TUNGSTEN_T3_RAM_SIZE;
610 #endif
611    return palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE;
612 }
613 
emulatorSaveRam(uint8_t * data,uint32_t size)614 bool emulatorSaveRam(uint8_t* data, uint32_t size){
615 #if defined(EMU_SUPPORT_PALM_OS5)
616    if(palmEmulatingTungstenT3){
617       if(size < TUNGSTEN_T3_RAM_SIZE)
618          return false;
619 
620       memcpy(data, palmRam, TUNGSTEN_T3_RAM_SIZE);
621    }
622    else{
623 #endif
624       if(size < (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE))
625          return false;
626 
627       memcpy(data, palmRam, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
628       swap16BufferIfLittle(data, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
629 #if defined(EMU_SUPPORT_PALM_OS5)
630    }
631 #endif
632 
633    return true;
634 }
635 
emulatorLoadRam(uint8_t * data,uint32_t size)636 bool emulatorLoadRam(uint8_t* data, uint32_t size){
637 #if defined(EMU_SUPPORT_PALM_OS5)
638    if(palmEmulatingTungstenT3){
639       if(size < TUNGSTEN_T3_RAM_SIZE)
640          return false;
641 
642       memcpy(palmRam, data, TUNGSTEN_T3_RAM_SIZE);
643    }
644    else{
645 #endif
646       if(size < (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE))
647          return false;
648 
649       memcpy(palmRam, data, palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE);
650       swap16BufferIfLittle(palmRam, (palmEmulatingM500 ? M500_RAM_SIZE : M515_RAM_SIZE) / sizeof(uint16_t));
651 #if defined(EMU_SUPPORT_PALM_OS5)
652    }
653 #endif
654 
655    return true;
656 }
657 
emulatorInsertSdCard(uint8_t * data,uint32_t size,sd_card_info_t * sdInfo)658 uint32_t emulatorInsertSdCard(uint8_t* data, uint32_t size, sd_card_info_t* sdInfo){
659    //from the no name SD card that came instered in my test device
660    static const sd_card_info_t defaultSdInfo = {
661       {0x00, 0x2F, 0x00, 0x32, 0x5F, 0x59, 0x83, 0xB8, 0x6D, 0xB7, 0xFF, 0x9F, 0x96, 0x40, 0x00, 0x00},//csd
662       {0x1D, 0x41, 0x44, 0x53, 0x44, 0x20, 0x20, 0x20, 0x10, 0xA0, 0x50, 0x33, 0xA4, 0x00, 0x81, 0x00},//cid
663       {0x01, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//scr
664       0x01FF8000,//ocr
665       false//writeProtectSwitch
666    };
667 
668    //SD card is currently inserted
669    if(palmSdCard.flashChipData)
670       return EMU_ERROR_RESOURCE_LOCKED;
671 
672    //no 0 sized chips, max out at 2gb SD card, Palms cant handle higher than that anyway because of incompatibility with FAT32 and SDHC
673    if(size == 0x00000000 || size > 0x20000000)
674       return EMU_ERROR_INVALID_PARAMETER;
675 
676    //add SD_CARD_BLOCK_SIZE to buffer to prevent buffer overflows
677    palmSdCard.flashChipSize = size;
678    palmSdCard.flashChipData = malloc(palmSdCard.flashChipSize + SD_CARD_BLOCK_SIZE);
679    if(!palmSdCard.flashChipData){
680       palmSdCard.flashChipSize = 0x00000000;
681       return EMU_ERROR_OUT_OF_MEMORY;
682    }
683 
684    //copy over buffer data
685    if(data)
686       memcpy(palmSdCard.flashChipData, data, size);
687    else
688       memset(palmSdCard.flashChipData, 0x00, size);
689 
690    //clear the padding block
691    memset(palmSdCard.flashChipData + palmSdCard.flashChipSize, 0x00, SD_CARD_BLOCK_SIZE);
692 
693    //reinit SD card
694    if(sdInfo)
695       palmSdCard.sdInfo = *sdInfo;
696    else
697       palmSdCard.sdInfo = defaultSdInfo;
698    sdCardReset();
699 
700    return EMU_ERROR_NONE;
701 }
702 
emulatorGetSdCardSize(void)703 uint32_t emulatorGetSdCardSize(void){
704    if(!palmSdCard.flashChipData)
705       return 0;
706 
707    return palmSdCard.flashChipSize;
708 }
709 
emulatorGetSdCardData(uint8_t * data,uint32_t size)710 uint32_t emulatorGetSdCardData(uint8_t* data, uint32_t size){
711    if(!palmSdCard.flashChipData)
712       return EMU_ERROR_RESOURCE_LOCKED;
713 
714    if(size < palmSdCard.flashChipSize)
715       return EMU_ERROR_OUT_OF_MEMORY;
716 
717    memcpy(data, palmSdCard.flashChipData, palmSdCard.flashChipSize);
718 
719    return EMU_ERROR_NONE;
720 }
721 
emulatorEjectSdCard(void)722 void emulatorEjectSdCard(void){
723    //clear SD flash chip, this disables the SD card control chip too
724    if(palmSdCard.flashChipData){
725       free(palmSdCard.flashChipData);
726       palmSdCard.flashChipData = NULL;
727       palmSdCard.flashChipSize = 0x00000000;
728    }
729 }
730 
emulatorRunFrame(void)731 void emulatorRunFrame(void){
732    uint16_t index;
733 
734 #if defined(EMU_SUPPORT_PALM_OS5)
735    if(palmEmulatingTungstenT3){
736       pxa260Execute(true);
737 
738       /*
739       //backlight level, 0% = 1/4 color intensity, 50% = 1/2 color intensity, 100% = full color intensity
740       switch(palmMisc.backlightLevel){
741          case 0:
742             MULTITHREAD_LOOP(index) for(index = 0; index < 320 * 480; index++){
743                palmFramebuffer[index] >>= 2;
744                palmFramebuffer[index] &= 0x39E7;
745             }
746             break;
747 
748          case 50:
749             MULTITHREAD_LOOP(index) for(index = 0; index < 320 * 480; index++){
750                palmFramebuffer[index] >>= 1;
751                palmFramebuffer[index] &= 0x7BEF;
752             }
753             break;
754 
755          case 100:
756             //nothing
757             break;
758 
759          default:
760             //TODO: the T3 supports full range backlight intensity, need to calculate the value here
761             debugLog("Unsupported backlight value\n");
762             break;
763       }
764       */
765    }
766    else{
767 #endif
768       //CPU
769       dbvzExecute();
770 
771       //LCD controller
772       if(palmEmulatingM500){
773          dbvzLcdRender();
774 
775          if(palmMisc.backlightLevel == 100){
776             MULTITHREAD_LOOP(index) for(index = 0; index < 160 * 160; index++){
777                uint16_t greenChannel = (palmFramebuffer[index] & 0x07E0) + 0x00C0;
778                palmFramebuffer[index] = palmFramebuffer[index] & 0xF81F | FAST_MIN(greenChannel, 0x07E0);
779             }
780          }
781       }
782       else{
783          sed1376Render();
784 
785          //backlight level, 0% = 1/4 color intensity, 50% = 1/2 color intensity, 100% = full color intensity
786          switch(palmMisc.backlightLevel){
787             case 0:
788                MULTITHREAD_LOOP(index) for(index = 0; index < 160 * 160; index++){
789                   palmFramebuffer[index] >>= 2;
790                   palmFramebuffer[index] &= 0x39E7;
791                }
792                break;
793 
794             case 50:
795                MULTITHREAD_LOOP(index) for(index = 0; index < 160 * 160; index++){
796                   palmFramebuffer[index] >>= 1;
797                   palmFramebuffer[index] &= 0x7BEF;
798                }
799                break;
800 
801             case 100:
802                //nothing
803                break;
804 
805             default:
806                debugLog("Invalid backlight value\n");
807                break;
808          }
809       }
810 
811 #if defined(EMU_SUPPORT_PALM_OS5)
812    }
813 #endif
814 }
815 
emulatorSkipFrame(void)816 void emulatorSkipFrame(void){
817    //runs frame without rendering the screen
818 #if defined(EMU_SUPPORT_PALM_OS5)
819    if(palmEmulatingTungstenT3){
820       pxa260Execute(false);
821    }
822    else{
823 #endif
824       //CPU
825       dbvzExecute();
826 
827       //LCD controller, skip this
828 #if defined(EMU_SUPPORT_PALM_OS5)
829    }
830 #endif
831 }
832