Files
Mu/src/emulator.c
meepingsnesroms f7c1dacba4 Start tunring m515 and dragonball stuff into modules
Prepareing for tungsten c support.
2019-04-19 09:35:14 -07:00

708 lines
28 KiB
C

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "audio/blip_buf.h"
#include "flx68000.h"
#include "emulator.h"
#include "dbvzRegisters.h"
#include "expansionHardware.h"
#include "m515Bus.h"
#include "sed1376.h"
#include "ads7846.h"
#include "pdiUsbD12.h"
#include "sdCard.h"
#include "silkscreen.h"
#include "portability.h"
#include "debug/sandbox.h"
#include "specs/emuFeatureRegisterSpec.h"
//Memory Map of Palm m515
//0x00000000<->0x00FFFFFF RAM, CSC0 as RAS0, CSC1 as RAS1, CSD0 as CAS0 and CSD1 as CAS1
//0x10000000<->0x103FFFFF ROM, CSA0, at address 0x00000000 during boot, palmos41-en-m515.rom, substitute "en" for your language code
//0x10400000<->0x10400003 USB, CSA1
//0x1FF80000<->0x1FF800B3 SED1376(Display Controller) Registers, CSB0
//0x1FFA0000<->0x1FFB3FFF SED1376(Display Controller) Framebuffer, CSB0, this is not the same as the Palm framebuffer which is always 16 bit color,
//this buffer must be processed depending on whats in the SED1376 registers, the result is the Palm framebuffer
//0xFFFFF000<->0xFFFFFDFF Hardware Registers
//0xFFFFFE00<->0xFFFFFFFF Bootloader, only reads from UART into RAM and jumps to it, never executed in consumer Palms
//VGhpcyBlbXVsYXRvciBpcyBkZWRpY2F0ZWQgdG8gdGhlIGJvdmluZSBtb28gY293cyB0aGF0IG1vby4=
static bool emulatorInitialized = false;
uint8_t* palmRam;
uint8_t* palmRom;
uint8_t* palmReg;
input_t palmInput;
sd_card_t palmSdCard;
misc_hw_t palmMisc;
emu_reg_t palmEmuFeatures;
uint16_t* palmFramebuffer;
uint16_t palmFramebufferWidth;
uint16_t palmFramebufferHeight;
int16_t* palmAudio;
blip_t* palmAudioResampler;
double palmSysclksPerClk32;//how many SYSCLK cycles before toggling the 32.768 kHz crystal
double palmCycleCounter;//can be greater then 0 if too many cycles where run
double palmClockMultiplier;//used by the emulator to overclock the emulated Palm
uint32_t palmFrameClk32s;//how many CLK32s have happened in the current frame
double palmClk32Sysclks;//how many SYSCLKs have happened in the current CLK32
uint32_t emulatorInit(buffer_t palmRomDump, buffer_t palmBootDump, uint32_t enabledEmuFeatures){
//only accept valid non debug features from the user
enabledEmuFeatures &= FEATURE_FAST_CPU | FEATURE_SYNCED_RTC | FEATURE_HLE_APIS | FEATURE_DURABLE;
#if defined(EMU_DEBUG)
//enable debug features if compiled in debug mode
enabledEmuFeatures |= FEATURE_DEBUG;
#endif
if(emulatorInitialized)
return EMU_ERROR_RESOURCE_LOCKED;
if(!palmRomDump.data)
return EMU_ERROR_INVALID_PARAMETER;
//allocate buffers, add 4 to memory regions to prevent SIGSEGV from accessing off the end
palmRam = malloc(M515_RAM_SIZE + 4);
palmRom = malloc(M515_ROM_SIZE + 4);
palmReg = malloc(DBVZ_REG_SIZE + 4);
palmFramebuffer = malloc(160 * 220 * sizeof(uint16_t));
palmAudio = malloc(AUDIO_SAMPLES_PER_FRAME * 2 * sizeof(int16_t));
palmAudioResampler = blip_new(AUDIO_SAMPLE_RATE);//have 1 second of samples
if(!palmRam || !palmRom || !palmReg || !palmFramebuffer || !palmAudio || !palmAudioResampler){
free(palmRam);
free(palmRom);
free(palmReg);
free(palmFramebuffer);
free(palmAudio);
blip_delete(palmAudioResampler);
return EMU_ERROR_OUT_OF_MEMORY;
}
//set default values
memset(palmRam, 0x00, M515_RAM_SIZE);
memcpy(palmRom, palmRomDump.data, u32Min(palmRomDump.size, M515_ROM_SIZE));
if(palmRomDump.size < M515_ROM_SIZE)
memset(palmRom + palmRomDump.size, 0x00, M515_ROM_SIZE - palmRomDump.size);
swap16BufferIfLittle(palmRom, M515_ROM_SIZE / sizeof(uint16_t));
if(palmBootDump.data){
memcpy(palmReg + DBVZ_REG_SIZE - 1 - DBVZ_BOOTLOADER_SIZE, palmBootDump.data, u32Min(palmBootDump.size, DBVZ_BOOTLOADER_SIZE));
if(palmBootDump.size < DBVZ_BOOTLOADER_SIZE)
memset(palmReg + DBVZ_REG_SIZE - 1 - DBVZ_BOOTLOADER_SIZE + palmBootDump.size, 0x00, DBVZ_BOOTLOADER_SIZE - palmBootDump.size);
swap16BufferIfLittle(palmReg + DBVZ_REG_SIZE - 1 - DBVZ_BOOTLOADER_SIZE, DBVZ_BOOTLOADER_SIZE / sizeof(uint16_t));
}
else{
memset(palmReg + DBVZ_REG_SIZE - 1 - DBVZ_BOOTLOADER_SIZE, 0x00, DBVZ_BOOTLOADER_SIZE);
}
memset(palmAudio, 0x00, AUDIO_SAMPLES_PER_FRAME * 2/*channels*/ * sizeof(int16_t));
memset(&palmInput, 0x00, sizeof(palmInput));
memset(&palmMisc, 0x00, sizeof(palmMisc));
memset(&palmSdCard, 0x00, sizeof(palmSdCard));
memset(&palmEmuFeatures, 0x00, sizeof(palmEmuFeatures));
palmMisc.batteryLevel = 100;
palmCycleCounter = 0.0;
palmEmuFeatures.info = enabledEmuFeatures;
//initialize components
blip_set_rates(palmAudioResampler, AUDIO_CLOCK_RATE, AUDIO_SAMPLE_RATE);
flx68000Init();
sandboxInit();
//reset everything
emulatorSoftReset();
dbvzSetRtc(0, 0, 0, 0);//RTCTIME and DAYR are not cleared by reset, clear them manually in case the frontend doesnt set the RTC
emulatorInitialized = true;
return EMU_ERROR_NONE;
}
void emulatorExit(void){
if(emulatorInitialized){
free(palmRam);
free(palmRom);
free(palmReg);
free(palmFramebuffer);
free(palmAudio);
blip_delete(palmAudioResampler);
free(palmSdCard.flashChip.data);
emulatorInitialized = false;
}
}
void emulatorHardReset(void){
//equivalent to taking the battery out and putting it back in
memset(palmRam, 0x00, M515_RAM_SIZE);
emulatorSoftReset();
sdCardReset();
dbvzSetRtc(0, 0, 0, 0);
}
void emulatorSoftReset(void){
//equivalent to pushing the reset button on the back of the device
palmFramebufferWidth = 160;
palmFramebufferHeight = 220;
palmEmuFeatures.value = 0x00000000;
palmClockMultiplier = 1.00 - EMU_CPU_PERCENT_WAITING;
sed1376Reset();
ads7846Reset();
pdiUsbD12Reset();
expansionHardwareReset();
flx68000Reset();
sandboxReset();
//sdCardReset() should not be called here, the SD card does not have a reset line and should only be reset by a power cycle
}
void emulatorSetRtc(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds){
dbvzSetRtc(days, hours, minutes, seconds);
}
uint32_t emulatorGetStateSize(void){
uint32_t size = 0;
size += sizeof(uint32_t);//save state version
size += sizeof(uint32_t);//palmEmuFeatures.info
size += sizeof(uint64_t);//palmSdCard.flashChip.size, needs to be done first to verify the malloc worked
size += sizeof(uint16_t) * 2;//palmFramebuffer(Width/Height)
size += flx68000StateSize();
size += sed1376StateSize();
size += ads7846StateSize();
size += pdiUsbD12StateSize();
size += expansionHardwareStateSize();
size += sandboxStateSize();
size += M515_RAM_SIZE;//system RAM buffer
size += DBVZ_REG_SIZE;//hardware registers
size += DBVZ_TOTAL_MEMORY_BANKS;//bank handlers
size += sizeof(uint32_t) * 4 * DBVZ_CHIP_END;//chip select states
size += sizeof(uint8_t) * 5 * DBVZ_CHIP_END;//chip select states
size += sizeof(uint64_t) * 5;//32.32 fixed point double, timerXCycleCounter and CPU cycle timers
size += sizeof(int8_t);//pllSleepWait
size += sizeof(int8_t);//pllWakeWait
size += sizeof(uint32_t);//clk32Counter
size += sizeof(uint64_t);//pctlrCpuClockDivider
size += sizeof(uint16_t) * 2;//timerStatusReadAcknowledge
size += sizeof(uint8_t);//portDInterruptLastValue
size += sizeof(uint16_t) * 9;//RX 8 * 16 SPI1 FIFO, 1 index is for FIFO full
size += sizeof(uint16_t) * 9;//TX 8 * 16 SPI1 FIFO, 1 index is for FIFO full
size += sizeof(uint8_t) * 5;//spi1(R/T)x(Read/Write)Position / spi1RxOverflowed
size += sizeof(int32_t);//pwm1ClocksToNextSample
size += sizeof(uint8_t) * 6;//pwm1Fifo[6]
size += sizeof(uint8_t) * 2;//pwm1(Read/Write)
size += sizeof(uint8_t) * 7;//palmMisc
size += sizeof(uint32_t) * 4;//palmEmuFeatures.(src/dst/size/value)
size += sizeof(uint64_t);//palmSdCard.command
size += sizeof(uint8_t) * 8;//palmSdCard.(commandBitsRemaining/runningCommand/commandIsAcmd/allowInvalidCrc/chipSelect/receivingCommand/inIdleState/writeProtectSwitch)
size += sizeof(uint16_t) * 2;//palmSdCard.response(Read/Write)Position
size += sizeof(int8_t);//palmSdCard.responseReadPositionBit
size += sizeof(uint32_t) * 3;//palmSdCard.runningCommandVars
size += SD_CARD_BLOCK_DATA_PACKET_SIZE;//palmSdCard.runningCommandPacket
size += SD_CARD_RESPONSE_FIFO_SIZE;//palmSdCard.responseFifo
size += palmSdCard.flashChip.size;//palmSdCard.flashChip.data
return size;
}
bool emulatorSaveState(buffer_t buffer){
uint32_t offset = 0;
uint8_t index;
if(buffer.size < emulatorGetStateSize())
return false;//state cant fit
//state validation, wont load states that are not from the same state version
writeStateValue32(buffer.data + offset, SAVE_STATE_VERSION);
offset += sizeof(uint32_t);
//features, hotpluging emulated hardware is not supported
writeStateValue32(buffer.data + offset, palmEmuFeatures.info);
offset += sizeof(uint32_t);
//SD card size
writeStateValue64(buffer.data + offset, palmSdCard.flashChip.size);
offset += sizeof(uint64_t);
//screen state
writeStateValue16(buffer.data + offset, palmFramebufferWidth);
offset += sizeof(uint16_t);
writeStateValue16(buffer.data + offset, palmFramebufferHeight);
offset += sizeof(uint16_t);
//chips
flx68000SaveState(buffer.data + offset);
offset += flx68000StateSize();
sed1376SaveState(buffer.data + offset);
offset += sed1376StateSize();
ads7846SaveState(buffer.data + offset);
offset += ads7846StateSize();
pdiUsbD12SaveState(buffer.data + offset);
offset += pdiUsbD12StateSize();
expansionHardwareSaveState(buffer.data + offset);
offset += expansionHardwareStateSize();
//sandbox, does nothing when disabled
sandboxSaveState(buffer.data + offset);
offset += sandboxStateSize();
//memory
memcpy(buffer.data + offset, palmRam, M515_RAM_SIZE);
swap16BufferIfLittle(buffer.data + offset, M515_RAM_SIZE / sizeof(uint16_t));
offset += M515_RAM_SIZE;
memcpy(buffer.data + offset, palmReg, DBVZ_REG_SIZE);
swap16BufferIfLittle(buffer.data + offset, DBVZ_REG_SIZE / sizeof(uint16_t));
offset += DBVZ_REG_SIZE;
memcpy(buffer.data + offset, dbvzBankType, DBVZ_TOTAL_MEMORY_BANKS);
offset += DBVZ_TOTAL_MEMORY_BANKS;
for(index = DBVZ_CHIP_BEGIN; index < DBVZ_CHIP_END; index++){
writeStateValue8(buffer.data + offset, chips[index].enable);
offset += sizeof(uint8_t);
writeStateValue32(buffer.data + offset, chips[index].start);
offset += sizeof(uint32_t);
writeStateValue32(buffer.data + offset, chips[index].lineSize);
offset += sizeof(uint32_t);
writeStateValue32(buffer.data + offset, chips[index].mask);
offset += sizeof(uint32_t);
writeStateValue8(buffer.data + offset, chips[index].inBootMode);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, chips[index].readOnly);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, chips[index].readOnlyForProtectedMemory);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, chips[index].supervisorOnlyProtectedMemory);
offset += sizeof(uint8_t);
writeStateValue32(buffer.data + offset, chips[index].unprotectedSize);
offset += sizeof(uint32_t);
}
//timing
writeStateValueDouble(buffer.data + offset, palmSysclksPerClk32);
offset += sizeof(uint64_t);
writeStateValueDouble(buffer.data + offset, palmCycleCounter);
offset += sizeof(uint64_t);
writeStateValueDouble(buffer.data + offset, palmClockMultiplier);
offset += sizeof(uint64_t);
writeStateValue8(buffer.data + offset, pllSleepWait);
offset += sizeof(int8_t);
writeStateValue8(buffer.data + offset, pllWakeWait);
offset += sizeof(int8_t);
writeStateValue32(buffer.data + offset, clk32Counter);
offset += sizeof(uint32_t);
writeStateValueDouble(buffer.data + offset, pctlrCpuClockDivider);
offset += sizeof(uint64_t);
writeStateValueDouble(buffer.data + offset, timerCycleCounter[0]);
offset += sizeof(uint64_t);
writeStateValueDouble(buffer.data + offset, timerCycleCounter[1]);
offset += sizeof(uint64_t);
writeStateValue16(buffer.data + offset, timerStatusReadAcknowledge[0]);
offset += sizeof(uint16_t);
writeStateValue16(buffer.data + offset, timerStatusReadAcknowledge[1]);
offset += sizeof(uint16_t);
writeStateValue8(buffer.data + offset, portDInterruptLastValue);
offset += sizeof(uint8_t);
//SPI1
for(index = 0; index < 9; index++){
writeStateValue16(buffer.data + offset, spi1RxFifo[index]);
offset += sizeof(uint16_t);
}
for(index = 0; index < 9; index++){
writeStateValue16(buffer.data + offset, spi1TxFifo[index]);
offset += sizeof(uint16_t);
}
writeStateValue8(buffer.data + offset, spi1RxReadPosition);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, spi1RxWritePosition);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, spi1RxOverflowed);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, spi1TxReadPosition);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, spi1TxWritePosition);
offset += sizeof(uint8_t);
//PWM1, audio
writeStateValue32(buffer.data + offset, pwm1ClocksToNextSample);
offset += sizeof(int32_t);
for(index = 0; index < 6; index++){
writeStateValue8(buffer.data + offset, pwm1Fifo[index]);
offset += sizeof(uint8_t);
}
writeStateValue8(buffer.data + offset, pwm1ReadPosition);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, pwm1WritePosition);
offset += sizeof(uint8_t);
//misc
writeStateValue8(buffer.data + offset, palmMisc.powerButtonLed);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmMisc.lcdOn);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmMisc.backlightLevel);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmMisc.vibratorOn);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmMisc.batteryCharging);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmMisc.batteryLevel);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmMisc.dataPort);
offset += sizeof(uint8_t);
//emu features
writeStateValue32(buffer.data + offset, palmEmuFeatures.src);
offset += sizeof(uint32_t);
writeStateValue32(buffer.data + offset, palmEmuFeatures.dst);
offset += sizeof(uint32_t);
writeStateValue32(buffer.data + offset, palmEmuFeatures.size);
offset += sizeof(uint32_t);
writeStateValue32(buffer.data + offset, palmEmuFeatures.value);
offset += sizeof(uint32_t);
//SD card
writeStateValue64(buffer.data + offset, palmSdCard.command);
offset += sizeof(uint64_t);
writeStateValue8(buffer.data + offset, palmSdCard.commandBitsRemaining);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmSdCard.runningCommand);
offset += sizeof(uint8_t);
for(index = 0; index < 3; index++){
writeStateValue32(buffer.data + offset, palmSdCard.runningCommandVars[index]);
offset += sizeof(uint32_t);
}
memcpy(buffer.data + offset, palmSdCard.runningCommandPacket, SD_CARD_BLOCK_DATA_PACKET_SIZE);
offset += SD_CARD_BLOCK_DATA_PACKET_SIZE;
memcpy(buffer.data + offset, palmSdCard.responseFifo, SD_CARD_RESPONSE_FIFO_SIZE);
offset += SD_CARD_RESPONSE_FIFO_SIZE;
writeStateValue16(buffer.data + offset, palmSdCard.responseReadPosition);
offset += sizeof(uint16_t);
writeStateValue8(buffer.data + offset, palmSdCard.responseReadPositionBit);
offset += sizeof(int8_t);
writeStateValue16(buffer.data + offset, palmSdCard.responseWritePosition);
offset += sizeof(uint16_t);
writeStateValue8(buffer.data + offset, palmSdCard.commandIsAcmd);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmSdCard.allowInvalidCrc);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmSdCard.chipSelect);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmSdCard.receivingCommand);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmSdCard.inIdleState);
offset += sizeof(uint8_t);
writeStateValue8(buffer.data + offset, palmSdCard.writeProtectSwitch);
offset += sizeof(uint8_t);
memcpy(buffer.data + offset, palmSdCard.flashChip.data, palmSdCard.flashChip.size);
offset += palmSdCard.flashChip.size;
return true;
}
bool emulatorLoadState(buffer_t buffer){
uint32_t offset = 0;
uint8_t index;
uint32_t stateSdCardSize;
uint8_t* stateSdCardBuffer;
//state validation, wont load states that are not from the same state version
if(readStateValue32(buffer.data + offset) != SAVE_STATE_VERSION)
return false;
offset += sizeof(uint32_t);
//features, hotpluging emulated hardware is not supported
if(readStateValue32(buffer.data + offset) != palmEmuFeatures.info)
return false;
offset += sizeof(uint32_t);
//SD card size, the malloc when loading can make it fail, make sure if it fails the emulator state doesnt change
stateSdCardSize = readStateValue64(buffer.data + offset);
stateSdCardBuffer = stateSdCardSize > 0 ? malloc(stateSdCardSize) : NULL;
if(stateSdCardSize > 0 && !stateSdCardBuffer)
return false;
offset += sizeof(uint64_t);
//screen state
palmFramebufferWidth = readStateValue16(buffer.data + offset);
offset += sizeof(uint16_t);
palmFramebufferHeight = readStateValue16(buffer.data + offset);
offset += sizeof(uint16_t);
//chips
flx68000LoadState(buffer.data + offset);
offset += flx68000StateSize();
sed1376LoadState(buffer.data + offset);
offset += sed1376StateSize();
ads7846LoadState(buffer.data + offset);
offset += ads7846StateSize();
pdiUsbD12LoadState(buffer.data + offset);
offset += pdiUsbD12StateSize();
expansionHardwareLoadState(buffer.data + offset);
offset += expansionHardwareStateSize();
//sandbox, does nothing when disabled
sandboxLoadState(buffer.data + offset);
offset += sandboxStateSize();
//memory
memcpy(palmRam, buffer.data + offset, M515_RAM_SIZE);
swap16BufferIfLittle(palmRam, M515_RAM_SIZE / sizeof(uint16_t));
offset += M515_RAM_SIZE;
memcpy(palmReg, buffer.data + offset, DBVZ_REG_SIZE);
swap16BufferIfLittle(palmReg, DBVZ_REG_SIZE / sizeof(uint16_t));
offset += DBVZ_REG_SIZE;
memcpy(dbvzBankType, buffer.data + offset, DBVZ_TOTAL_MEMORY_BANKS);
offset += DBVZ_TOTAL_MEMORY_BANKS;
for(index = DBVZ_CHIP_BEGIN; index < DBVZ_CHIP_END; index++){
chips[index].enable = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
chips[index].start = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
chips[index].lineSize = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
chips[index].mask = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
chips[index].inBootMode = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
chips[index].readOnly = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
chips[index].readOnlyForProtectedMemory = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
chips[index].supervisorOnlyProtectedMemory = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
chips[index].unprotectedSize = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
}
//timing
palmSysclksPerClk32 = readStateValueDouble(buffer.data + offset);
offset += sizeof(uint64_t);
palmCycleCounter = readStateValueDouble(buffer.data + offset);
offset += sizeof(uint64_t);
palmClockMultiplier = readStateValueDouble(buffer.data + offset);
offset += sizeof(uint64_t);
pllSleepWait = readStateValue8(buffer.data + offset);
offset += sizeof(int8_t);
pllWakeWait = readStateValue8(buffer.data + offset);
offset += sizeof(int8_t);
clk32Counter = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
pctlrCpuClockDivider = readStateValueDouble(buffer.data + offset);
offset += sizeof(uint64_t);
timerCycleCounter[0] = readStateValueDouble(buffer.data + offset);
offset += sizeof(uint64_t);
timerCycleCounter[1] = readStateValueDouble(buffer.data + offset);
offset += sizeof(uint64_t);
timerStatusReadAcknowledge[0] = readStateValue16(buffer.data + offset);
offset += sizeof(uint16_t);
timerStatusReadAcknowledge[1] = readStateValue16(buffer.data + offset);
offset += sizeof(uint16_t);
portDInterruptLastValue = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
//SPI1
for(index = 0; index < 9; index++){
spi1RxFifo[index] = readStateValue16(buffer.data + offset);
offset += sizeof(uint16_t);
}
for(index = 0; index < 9; index++){
spi1TxFifo[index] = readStateValue16(buffer.data + offset);
offset += sizeof(uint16_t);
}
spi1RxReadPosition = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
spi1RxWritePosition = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
spi1RxOverflowed = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
spi1TxReadPosition = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
spi1TxWritePosition = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
//PWM1, audio
pwm1ClocksToNextSample = readStateValue32(buffer.data + offset);
offset += sizeof(int32_t);
for(index = 0; index < 6; index++){
pwm1Fifo[index] = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
}
pwm1ReadPosition = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
pwm1WritePosition = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
//misc
palmMisc.powerButtonLed = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmMisc.lcdOn = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmMisc.backlightLevel = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmMisc.vibratorOn = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmMisc.batteryCharging = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmMisc.batteryLevel = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmMisc.dataPort = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
//emu features
palmEmuFeatures.src = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
palmEmuFeatures.dst = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
palmEmuFeatures.size = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
palmEmuFeatures.value = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
//SD card
palmSdCard.command = readStateValue64(buffer.data + offset);
offset += sizeof(uint64_t);
palmSdCard.commandBitsRemaining = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmSdCard.runningCommand = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
for(index = 0; index < 3; index++){
palmSdCard.runningCommandVars[index] = readStateValue32(buffer.data + offset);
offset += sizeof(uint32_t);
}
memcpy(palmSdCard.runningCommandPacket, buffer.data + offset, SD_CARD_BLOCK_DATA_PACKET_SIZE);
offset += SD_CARD_BLOCK_DATA_PACKET_SIZE;
memcpy(palmSdCard.responseFifo, buffer.data + offset, SD_CARD_RESPONSE_FIFO_SIZE);
offset += SD_CARD_RESPONSE_FIFO_SIZE;
palmSdCard.responseReadPosition = readStateValue16(buffer.data + offset);
offset += sizeof(uint16_t);
palmSdCard.responseReadPositionBit = readStateValue8(buffer.data + offset);
offset += sizeof(int8_t);
palmSdCard.responseWritePosition = readStateValue16(buffer.data + offset);
offset += sizeof(uint16_t);
palmSdCard.commandIsAcmd = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmSdCard.allowInvalidCrc = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmSdCard.chipSelect = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmSdCard.receivingCommand = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmSdCard.inIdleState = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
palmSdCard.writeProtectSwitch = readStateValue8(buffer.data + offset);
offset += sizeof(uint8_t);
if(palmSdCard.flashChip.data)
free(palmSdCard.flashChip.data);
palmSdCard.flashChip.data = stateSdCardBuffer;
palmSdCard.flashChip.size = stateSdCardSize;
memcpy(palmSdCard.flashChip.data, buffer.data + offset, stateSdCardSize);
offset += stateSdCardSize;
//some modules depend on all the state memory being loaded before certian required actions can occur(refreshing cached data, freeing memory blocks)
flx68000LoadStateFinished();
return true;
}
uint32_t emulatorGetRamSize(void){
return M515_RAM_SIZE;
}
bool emulatorSaveRam(buffer_t buffer){
if(buffer.size < M515_RAM_SIZE)
return false;
memcpy(buffer.data, palmRam, M515_RAM_SIZE);
swap16BufferIfLittle(buffer.data, M515_RAM_SIZE / sizeof(uint16_t));
return true;
}
bool emulatorLoadRam(buffer_t buffer){
if(buffer.size < M515_RAM_SIZE)
return false;
memcpy(palmRam, buffer.data, M515_RAM_SIZE);
swap16BufferIfLittle(palmRam, M515_RAM_SIZE / sizeof(uint16_t));
return true;
}
buffer_t emulatorGetSdCardBuffer(void){
return palmSdCard.flashChip;
}
uint32_t emulatorInsertSdCard(buffer_t image, bool writeProtectSwitch){
//SD card is currently inserted
if(palmSdCard.flashChip.data)
return EMU_ERROR_RESOURCE_LOCKED;
//no 0 sized chips, max out at 2gb SD card, Palms cant handle higher than that anyway because of incompatibility with FAT32 and SDHC
if(image.size == 0x00000000 || image.size > 0x20000000)
return EMU_ERROR_INVALID_PARAMETER;
//round up to nearest mb, prevents issues with buffer size and too small SD cards
palmSdCard.flashChip.size = (image.size & 0xFFF00000) + (image.size & 0x000FFFFF ? 0x00100000 : 0x00000000);
palmSdCard.flashChip.data = malloc(palmSdCard.flashChip.size);
if(!palmSdCard.flashChip.data){
palmSdCard.flashChip.size = 0x00000000;
return EMU_ERROR_OUT_OF_MEMORY;
}
//copy over buffer data
if(image.data)
memcpy(palmSdCard.flashChip.data, image.data, image.size);
else
memset(palmSdCard.flashChip.data, 0x00, image.size);
//0 out the unused part of the chip
memset(palmSdCard.flashChip.data + image.size, 0x00, palmSdCard.flashChip.size - image.size);
//reinit SD card
palmSdCard.writeProtectSwitch = writeProtectSwitch;
sdCardReset();
return EMU_ERROR_NONE;
}
void emulatorEjectSdCard(void){
//clear SD flash chip, this disables the SD card control chip too
if(palmSdCard.flashChip.data){
free(palmSdCard.flashChip.data);
palmSdCard.flashChip.data = NULL;
palmSdCard.flashChip.size = 0x00000000;
}
}
void emulatorRunFrame(void){
uint32_t samples;
//I/O
m515RefreshInputState();
//CPU
palmFrameClk32s = 0;
for(; palmCycleCounter < (double)CRYSTAL_FREQUENCY / EMU_FPS; palmCycleCounter += 1.0){
flx68000Execute();
palmFrameClk32s++;
}
palmCycleCounter -= (double)CRYSTAL_FREQUENCY / EMU_FPS;
//audio
blip_end_frame(palmAudioResampler, blip_clocks_needed(palmAudioResampler, AUDIO_SAMPLES_PER_FRAME));
blip_read_samples(palmAudioResampler, palmAudio, AUDIO_SAMPLES_PER_FRAME, true);
MULTITHREAD_LOOP(samples) for(samples = 0; samples < AUDIO_SAMPLES_PER_FRAME * 2; samples += 2)
palmAudio[samples + 1] = palmAudio[samples];
//video
sed1376Render();
memcpy(palmFramebuffer, sed1376Framebuffer, 160 * 160 * sizeof(uint16_t));
memcpy(palmFramebuffer + 160 * 160, silkscreen160x60, 160 * 60 * sizeof(uint16_t));
#if defined(EMU_SANDBOX)
sandboxOnFrameRun();
#endif
}