mirror of
https://github.com/libretro/Mu.git
synced 2026-10-04 04:19:33 +00:00
498 lines
18 KiB
C
498 lines
18 KiB
C
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include <boolean.h>
|
|
|
|
#include "m68k/m68k.h"
|
|
#include "68328Functions.h"
|
|
#include "emulator.h"
|
|
#include "hardwareRegisters.h"
|
|
#include "memoryAccess.h"
|
|
#include "sed1376.h"
|
|
#include "sdcard.h"
|
|
#include "silkscreen.h"
|
|
#include "portability.h"
|
|
#include "emuFeatureRegistersSpec.h"
|
|
|
|
|
|
//Memory Map of Palm m515
|
|
//0x00000000-0x00FFFFFF RAM, the first 256(0x100) bytes is copyed from the first 256 bytes of ROM before boot, this applys to all Palms with the 68k architecture
|
|
//0x10000000-0x103FFFFF ROM, palmos41-en-m515.rom, substitute "en" for your language code
|
|
//0x1FF80000-0x1FF800B3 SED1376(Display Controller) Registers
|
|
//0x1FFA0000-0x1FFB3FFF SED1376(Display Controller) Framebuffer, 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
|
|
//0xFFFFFF00-0xFFFFFFFF Bootloader, only reads from UART into RAM and jumps to it, never executed in consumer Palms
|
|
|
|
|
|
uint8_t palmRam[RAM_SIZE];
|
|
uint8_t palmRom[ROM_SIZE];
|
|
uint8_t palmReg[REG_SIZE];
|
|
input_t palmInput;
|
|
sdcard_t palmSdCard;
|
|
misc_hw_t palmMisc;
|
|
uint16_t palmFramebuffer[160 * (160 + 60)];//really 160*160, the extra pixels are the silkscreened digitizer area
|
|
uint32_t palmSpecialFeatures;
|
|
double palmCrystalCycles;//how many 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
|
|
|
|
|
|
uint64_t (*emulatorGetSysTime)();
|
|
uint64_t* (*emulatorGetSdCardStateChunkList)(uint64_t sessionId, uint64_t stateId);//returns the bps chunkIds for a stateId in the order they need to be applied
|
|
void (*emulatorSetSdCardStateChunkList)(uint64_t sessionId, uint64_t stateId, uint64_t* data);//sets the bps chunkIds for a stateId in the order they need to be applied
|
|
uint8_t* (*emulatorGetSdCardChunk)(uint64_t sessionId, uint64_t chunkId);
|
|
void (*emulatorSetSdCardChunk)(uint64_t sessionId, uint64_t chunkId, uint8_t* data, uint64_t size);
|
|
|
|
|
|
static inline bool allSdCardCallbacksPresent(){
|
|
if(emulatorGetSysTime && emulatorGetSdCardStateChunkList && emulatorSetSdCardStateChunkList && emulatorGetSdCardChunk && emulatorSetSdCardChunk)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
//debug
|
|
#ifdef EMU_OPCODE_LEVEL_DEBUG
|
|
#define LOGGED_OPCODES 100
|
|
static bool invalidBehaviorAbort;
|
|
static char disassemblyBuffer[LOGGED_OPCODES][100];//store the opcode and program counter for the last 10 opcodes
|
|
|
|
const char* lookupTrap(uint16_t trap);
|
|
|
|
static char* takeStackDump(uint32_t bytes){
|
|
char* textBytes = malloc(bytes * 2);
|
|
uint32_t textBytesOffset = 0;
|
|
uint32_t stackAddress = m68k_get_reg(NULL, M68K_REG_SP);
|
|
|
|
textBytes[0] = '\0';
|
|
|
|
for(uint32_t count = 0; count < bytes; count++){
|
|
sprintf(textBytes + textBytesOffset, "%02X", m68k_read_memory_8(stackAddress + count));
|
|
textBytesOffset = strlen(textBytes);
|
|
}
|
|
|
|
return textBytes;
|
|
}
|
|
|
|
static void invalidBehaviorCheck(){
|
|
char opcodeName[100];
|
|
uint32_t lastProgramCounter = m68k_get_reg(NULL, M68K_REG_PPC);
|
|
uint32_t programCounter = m68k_get_reg(NULL, M68K_REG_PC);
|
|
uint16_t instruction = m68k_get_reg(NULL, M68K_REG_IR);
|
|
bool invalidInstruction = !m68k_is_valid_instruction(instruction, M68K_CPU_TYPE_68000);
|
|
bool invalidBank = (bankType[START_BANK(programCounter)] == CHIP_NONE);
|
|
|
|
//get current opcode
|
|
if(!invalidBank){
|
|
//must dissasemble as 68020 to prevent address masking, is also more descriptive for invalid opcodes
|
|
m68k_disassemble(opcodeName, lastProgramCounter, M68K_CPU_TYPE_68020);
|
|
}
|
|
else{
|
|
strcpy(opcodeName, "Invalid bank, cant read");
|
|
}
|
|
sprintf(opcodeName + strlen(opcodeName), " at PC:0x%08X", lastProgramCounter);
|
|
|
|
//shift opcode buffer
|
|
for(uint32_t i = 0; i < LOGGED_OPCODES - 1; i++)
|
|
strcpy(disassemblyBuffer[i], disassemblyBuffer[i + 1]);
|
|
|
|
//add to opcode buffer
|
|
strcpy(disassemblyBuffer[LOGGED_OPCODES - 1], opcodeName);
|
|
|
|
if(invalidInstruction || invalidBank || (instruction == 0x0000 && lastProgramCounter != 0x00000000)){
|
|
//0x0000 is "ori.b #$0, D0", effectivly NOP but still a valid opcode
|
|
//usualy never encountered unless executing empty address space, so it still triggers debug abort
|
|
m68k_end_timeslice();
|
|
invalidBehaviorAbort = true;
|
|
|
|
for(uint32_t i = 0; i < LOGGED_OPCODES; i++)
|
|
debugLog("%s\n", disassemblyBuffer[i]);
|
|
//currently CPU32 opcodes will be listed as "unknown", I cant change that properly unless I directly edit musashi source, something I want to avoid doing
|
|
debugLog("Instruction:\"%s\", instruction value:0x%04X, bank type:%d\n", invalidInstruction ? "unknown" : opcodeName, instruction, bankType[START_BANK(lastProgramCounter)]);
|
|
}
|
|
|
|
//custom debug operations
|
|
switch(programCounter){
|
|
/*
|
|
//case 0x10000566:
|
|
case 0x100003F8:
|
|
{
|
|
//failing on executing first trap "HwrPreDebugInit"
|
|
char* data = takeStackDump(32);
|
|
debugLog("Stack dump:%s\n", data);
|
|
free(data);
|
|
}
|
|
break;
|
|
*/
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(instruction == 0x4E4F){
|
|
//Trap F/api call
|
|
uint16_t trap = m68k_read_memory_16(lastProgramCounter + 2);
|
|
debugLog("Trap F API:%s, API number:0x%04X, PC:0x%08X\n", lookupTrap(trap), trap, lastProgramCounter);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
void emulatorInit(uint8_t* palmRomDump, uint8_t* palmBootDump, uint32_t specialFeatures){
|
|
//CPU
|
|
m68k_init();
|
|
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
|
patchTo68328();
|
|
m68k_set_reset_instr_callback(emulatorReset);
|
|
m68k_set_int_ack_callback(interruptAcknowledge);
|
|
#ifdef EMU_OPCODE_LEVEL_DEBUG
|
|
for(uint32_t i = 0; i < LOGGED_OPCODES; i++)
|
|
strcpy(disassemblyBuffer[i], "Not an opcode.\n");
|
|
m68k_set_instr_hook_callback(invalidBehaviorCheck);
|
|
#endif
|
|
resetHwRegisters();
|
|
lowPowerStopActive = false;
|
|
palmCrystalCycles = 2.0 * (14.0 * (71.0/*p*/ + 1.0) + 3.0/*q*/ + 1.0) / 2.0/*prescaler1*/;
|
|
palmCycleCounter = 0.0;
|
|
|
|
//memory
|
|
memset(palmRam, 0x00, RAM_SIZE);
|
|
memcpy(palmRom, palmRomDump, ROM_SIZE);
|
|
if(palmBootDump)
|
|
memcpy(palmReg + REG_SIZE - 1 - BOOTLOADER_SIZE, palmBootDump, BOOTLOADER_SIZE);
|
|
else
|
|
memset(palmReg + REG_SIZE - 1 - BOOTLOADER_SIZE, 0x00, BOOTLOADER_SIZE);
|
|
memcpy(&palmFramebuffer[160 * 160], silkscreenData, SILKSCREEN_WIDTH * SILKSCREEN_HEIGHT * (SILKSCREEN_BPP / 8));
|
|
resetAddressSpace();
|
|
sed1376Reset();
|
|
sdCardInit();
|
|
|
|
//input
|
|
palmInput.buttonUp = false;
|
|
palmInput.buttonDown = false;
|
|
palmInput.buttonLeft = false;//only used in hybrid mode
|
|
palmInput.buttonRight = false;//only used in hybrid mode
|
|
palmInput.buttonSelect = false;//only used in hybrid mode
|
|
|
|
palmInput.buttonCalender = false;
|
|
palmInput.buttonAddress = false;
|
|
palmInput.buttonTodo = false;
|
|
palmInput.buttonNotes = false;
|
|
|
|
palmInput.buttonPower = false;
|
|
palmInput.buttonContrast = false;
|
|
|
|
palmInput.touchscreenX = 0;
|
|
palmInput.touchscreenY = 0;
|
|
palmInput.touchscreenTouched = false;
|
|
|
|
//sdcard
|
|
palmSdCard.sessionId = 0x0000000000000000;
|
|
palmSdCard.stateId = 0x0000000000000000;
|
|
palmSdCard.size = 0;
|
|
palmSdCard.type = CARD_NONE;
|
|
palmSdCard.inserted = false;
|
|
|
|
//misc settable attributes
|
|
palmMisc.batteryCharging = false;
|
|
palmMisc.batteryLevel = 100;
|
|
palmMisc.inDock = false;
|
|
|
|
//config
|
|
palmClockMultiplier = (specialFeatures & FEATURE_FAST_CPU) ? 2.0 : 1.0;//overclock
|
|
palmSpecialFeatures = specialFeatures;
|
|
|
|
//start running
|
|
m68k_pulse_reset();
|
|
|
|
/*
|
|
double test = 342553325.13436322;
|
|
uint64_t fixed3232 = getUint64FromDouble(test);
|
|
double rebuilt = getDoubleFromUint64(fixed3232);
|
|
debugLog("Original double:%f\n", test);
|
|
debugLog("Fixed 32.32:0x%08lX\n", fixed3232);
|
|
debugLog("Rebuilt double:%f\n", rebuilt);
|
|
*/
|
|
}
|
|
|
|
void emulatorExit(){
|
|
sdCardExit();
|
|
}
|
|
|
|
void emulatorReset(){
|
|
//reset doesnt clear RAM or sdcard, all programs are stored in RAM or on sdcard
|
|
debugLog("Reset triggered, PC:0x%08X\n", m68k_get_reg(NULL, M68K_REG_PC));
|
|
resetHwRegisters();
|
|
resetAddressSpace();//address space must be reset after hardware registers because it is dependant on them
|
|
sed1376Reset();
|
|
m68k_pulse_reset();
|
|
}
|
|
|
|
void emulatorSetRtc(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds){
|
|
setRtc(days, hours, minutes, seconds);
|
|
}
|
|
|
|
uint32_t emulatorSetSdCard(uint64_t size, uint8_t type){
|
|
if(!allSdCardCallbacksPresent())
|
|
return EMU_ERROR_CALLBACKS_NOT_SET;
|
|
|
|
palmSdCard.sessionId = emulatorGetSysTime();
|
|
palmSdCard.stateId = 0x0000000000000000;//set when saving state
|
|
palmSdCard.size = size;
|
|
palmSdCard.type = type;
|
|
palmSdCard.inserted = true;
|
|
|
|
return EMU_ERROR_NONE;
|
|
}
|
|
|
|
uint32_t emulatorGetStateSize(){
|
|
uint32_t size = 0;
|
|
|
|
size += sizeof(uint32_t) * (M68K_REG_CAAR + 1);//CPU registers
|
|
size += sizeof(uint8_t);//lowPowerStopActive
|
|
size += RAM_SIZE;//system RAM buffer
|
|
size += REG_SIZE;//hardware registers
|
|
size += TOTAL_MEMORY_BANKS;//bank handlers
|
|
size += sizeof(uint32_t) * 4 * CHIP_END;//chip select states
|
|
size += sizeof(uint8_t) * 5 * CHIP_END;//chip select states
|
|
size += sizeof(uint64_t) * 3;//palmSdCard
|
|
size += sizeof(uint8_t) * 2;//palmSdCard
|
|
size += sizeof(uint64_t) * 4;//32.32 fixed point double, timerXCycleCounter and CPU cycle timers
|
|
size += sizeof(int32_t);//pllWakeWait
|
|
size += sizeof(uint32_t);//clk32Counter
|
|
size += sizeof(uint8_t) * 7;//palmMisc
|
|
size += sizeof(uint32_t);//palmSpecialFeatures
|
|
|
|
return size;
|
|
}
|
|
|
|
void emulatorSaveState(uint8_t* data){
|
|
uint32_t offset = 0;
|
|
|
|
//update sdcard struct and save sdcard data
|
|
if(allSdCardCallbacksPresent() && palmSdCard.type != CARD_NONE){
|
|
uint64_t stateId = emulatorGetSysTime();
|
|
sdCardSaveState(palmSdCard.sessionId, stateId);
|
|
palmSdCard.stateId = stateId;
|
|
}
|
|
|
|
//CPU
|
|
for(uint32_t cpuReg = 0; cpuReg <= M68K_REG_CAAR; cpuReg++){
|
|
writeStateValueUint32(data + offset, m68k_get_reg(NULL, cpuReg));
|
|
offset += sizeof(uint32_t);
|
|
}
|
|
writeStateValueBool(data + offset, lowPowerStopActive);
|
|
offset += sizeof(uint8_t);
|
|
|
|
//memory
|
|
memcpy(data + offset, palmRam, RAM_SIZE);
|
|
offset += RAM_SIZE;
|
|
memcpy(data + offset, palmReg, REG_SIZE);
|
|
offset += REG_SIZE;
|
|
memcpy(data + offset, bankType, TOTAL_MEMORY_BANKS);
|
|
offset += TOTAL_MEMORY_BANKS;
|
|
for(uint32_t chip = CHIP_BEGIN; chip < CHIP_END; chip++){
|
|
writeStateValueBool(data + offset, chips[chip].enable);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueUint32(data + offset, chips[chip].start);
|
|
offset += sizeof(uint32_t);
|
|
writeStateValueUint32(data + offset, chips[chip].size);
|
|
offset += sizeof(uint32_t);
|
|
writeStateValueUint32(data + offset, chips[chip].mask);
|
|
offset += sizeof(uint32_t);
|
|
writeStateValueBool(data + offset, chips[chip].inBootMode);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueBool(data + offset, chips[chip].readOnly);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueBool(data + offset, chips[chip].readOnlyForProtectedMemory);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueBool(data + offset, chips[chip].supervisorOnlyProtectedMemory);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueUint32(data + offset, chips[chip].unprotectedSize);
|
|
offset += sizeof(uint32_t);
|
|
}
|
|
|
|
//sdcard
|
|
writeStateValueUint64(data + offset, palmSdCard.sessionId);
|
|
offset += sizeof(uint64_t);
|
|
writeStateValueUint64(data + offset, palmSdCard.stateId);
|
|
offset += sizeof(uint64_t);
|
|
writeStateValueUint64(data + offset, palmSdCard.size);
|
|
offset += sizeof(uint64_t);
|
|
writeStateValueUint8(data + offset, palmSdCard.type);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueBool(data + offset, palmSdCard.inserted);
|
|
offset += sizeof(uint8_t);
|
|
|
|
//timing
|
|
writeStateValueDouble(data + offset, palmCrystalCycles);
|
|
offset += sizeof(uint64_t);
|
|
writeStateValueDouble(data + offset, palmCycleCounter);
|
|
offset += sizeof(uint64_t);
|
|
writeStateValueInt32(data + offset, pllWakeWait);
|
|
offset += sizeof(int32_t);
|
|
writeStateValueUint32(data + offset, clk32Counter);
|
|
offset += sizeof(uint32_t);
|
|
writeStateValueDouble(data + offset, timer1CycleCounter);
|
|
offset += sizeof(uint64_t);
|
|
writeStateValueDouble(data + offset, timer2CycleCounter);
|
|
offset += sizeof(uint64_t);
|
|
|
|
//misc
|
|
writeStateValueBool(data + offset, palmMisc.alarmLed);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueBool(data + offset, palmMisc.lcdOn);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueBool(data + offset, palmMisc.backlightOn);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueBool(data + offset, palmMisc.vibratorOn);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueBool(data + offset, palmMisc.batteryCharging);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueUint8(data + offset, palmMisc.batteryLevel);
|
|
offset += sizeof(uint8_t);
|
|
writeStateValueUint8(data + offset, palmMisc.inDock);
|
|
offset += sizeof(uint8_t);
|
|
|
|
//features
|
|
writeStateValueUint32(data + offset, palmSpecialFeatures);
|
|
offset += sizeof(uint32_t);
|
|
}
|
|
|
|
void emulatorLoadState(uint8_t* data){
|
|
uint32_t offset = 0;
|
|
|
|
//CPU
|
|
for(uint32_t cpuReg = 0; cpuReg <= M68K_REG_CAAR; cpuReg++){
|
|
m68k_set_reg(cpuReg, readStateValueUint32(data + offset));
|
|
offset += sizeof(uint32_t);
|
|
}
|
|
lowPowerStopActive = readStateValueBool(data + offset);
|
|
offset += 1;
|
|
|
|
//memory
|
|
memcpy(palmRam, data + offset, RAM_SIZE);
|
|
offset += RAM_SIZE;
|
|
memcpy(palmReg, data + offset, REG_SIZE);
|
|
offset += REG_SIZE;
|
|
memcpy(bankType, data + offset, TOTAL_MEMORY_BANKS);
|
|
offset += TOTAL_MEMORY_BANKS;
|
|
for(uint32_t chip = CHIP_BEGIN; chip < CHIP_END; chip++){
|
|
chips[chip].enable = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
chips[chip].start = readStateValueUint32(data + offset);
|
|
offset += sizeof(uint32_t);
|
|
chips[chip].size = readStateValueUint32(data + offset);
|
|
offset += sizeof(uint32_t);
|
|
chips[chip].mask = readStateValueUint32(data + offset);
|
|
offset += sizeof(uint32_t);
|
|
chips[chip].inBootMode = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
chips[chip].readOnly = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
chips[chip].readOnlyForProtectedMemory = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
chips[chip].supervisorOnlyProtectedMemory = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
chips[chip].unprotectedSize = readStateValueUint32(data + offset);
|
|
offset += sizeof(uint32_t);
|
|
}
|
|
|
|
//sdcard
|
|
palmSdCard.sessionId = readStateValueUint64(data + offset);
|
|
offset += sizeof(uint64_t);
|
|
palmSdCard.stateId = readStateValueUint64(data + offset);
|
|
offset += sizeof(uint64_t);
|
|
palmSdCard.size = readStateValueUint64(data + offset);
|
|
offset += sizeof(uint64_t);
|
|
palmSdCard.type = readStateValueUint8(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
palmSdCard.inserted = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
|
|
//timing
|
|
palmCrystalCycles = readStateValueDouble(data + offset);
|
|
offset += sizeof(uint64_t);
|
|
palmCycleCounter = readStateValueDouble(data + offset);
|
|
offset += sizeof(uint64_t);
|
|
pllWakeWait = readStateValueInt32(data + offset);
|
|
offset += sizeof(int32_t);
|
|
clk32Counter = readStateValueUint32(data + offset);
|
|
offset += sizeof(uint32_t);
|
|
timer1CycleCounter = readStateValueDouble(data + offset);
|
|
offset += sizeof(uint64_t);
|
|
timer2CycleCounter = readStateValueDouble(data + offset);
|
|
offset += sizeof(uint64_t);
|
|
|
|
//misc
|
|
palmMisc.alarmLed = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
palmMisc.lcdOn = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
palmMisc.backlightOn = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
palmMisc.vibratorOn = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
palmMisc.batteryCharging = readStateValueBool(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
palmMisc.batteryLevel = readStateValueUint8(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
palmMisc.inDock = readStateValueUint8(data + offset);
|
|
offset += sizeof(uint8_t);
|
|
|
|
//features
|
|
palmSpecialFeatures = readStateValueUint32(data + offset);
|
|
offset += sizeof(uint32_t);
|
|
|
|
//update sdcard data from sdcard struct
|
|
if(allSdCardCallbacksPresent() && palmSdCard.type != CARD_NONE){
|
|
sdCardLoadState(palmSdCard.sessionId, palmSdCard.stateId);
|
|
}
|
|
}
|
|
|
|
uint32_t emulatorInstallPrcPdb(uint8_t* data, uint32_t size){
|
|
//pretend to pass for now
|
|
//return EMU_ERROR_NOT_IMPLEMENTED;
|
|
return EMU_ERROR_NONE;
|
|
}
|
|
|
|
void emulateFrame(){
|
|
refreshButtonState();
|
|
while(palmCycleCounter < CPU_FREQUENCY / EMU_FPS){
|
|
if(cpuIsOn())
|
|
palmCycleCounter += m68k_execute(palmCrystalCycles * palmClockMultiplier) / palmClockMultiplier;//normaly 33mhz / 60fps
|
|
else
|
|
palmCycleCounter += palmCrystalCycles;
|
|
clk32();
|
|
}
|
|
palmCycleCounter -= CPU_FREQUENCY / EMU_FPS;
|
|
|
|
memcpy(palmFramebuffer, sed1376Framebuffer, 160 * 160 * sizeof(uint16_t));
|
|
|
|
//debugLog("Ran frame, executed %f cycles.\n", palmCycleCounter + CPU_FREQUENCY / EMU_FPS);
|
|
}
|
|
|
|
bool emulateUntilDebugEventOrFrameEnd(){
|
|
#ifdef EMU_OPCODE_LEVEL_DEBUG
|
|
invalidBehaviorAbort = false;
|
|
|
|
refreshButtonState();
|
|
while(palmCycleCounter < CPU_FREQUENCY / EMU_FPS){
|
|
if(cpuIsOn())
|
|
palmCycleCounter += m68k_execute(palmCrystalCycles * palmClockMultiplier) / palmClockMultiplier;//normaly 33mhz / 60fps
|
|
else
|
|
palmCycleCounter += palmCrystalCycles;
|
|
clk32();
|
|
if(invalidBehaviorAbort)
|
|
break;
|
|
}
|
|
palmCycleCounter -= CPU_FREQUENCY / EMU_FPS;
|
|
|
|
return invalidBehaviorAbort;
|
|
#else
|
|
emulateFrame();
|
|
return false;
|
|
#endif
|
|
}
|