mirror of
https://github.com/libretro/Mu.git
synced 2026-09-24 07:35:55 +00:00
Support reenabling PLL, Fix coding style that was broken by Qt creator
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.6.0, 2018-04-12T22:26:46. -->
|
||||
<!-- Written by QtCreator 4.6.0, 2018-04-14T13:46:18. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
|
||||
@@ -164,7 +164,8 @@ uint32_t emulatorGetStateSize(){
|
||||
size += TOTAL_MEMORY_BANKS;//bank handlers
|
||||
size += sizeof(uint64_t) * 3;//palmSdCard
|
||||
size += sizeof(uint8_t) * 2;//palmSdCard
|
||||
size += sizeof(uint64_t) * 4;//32.32 fixed point double precision timers
|
||||
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
|
||||
@@ -215,6 +216,8 @@ void emulatorSaveState(uint8_t* data){
|
||||
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);
|
||||
@@ -279,6 +282,8 @@ void emulatorLoadState(uint8_t* data){
|
||||
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);
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
#include "m68k/m68k.h"
|
||||
|
||||
|
||||
int32_t pllWakeWait;
|
||||
uint32_t clk32Counter;
|
||||
double timer1CycleCounter;
|
||||
double timer2CycleCounter;
|
||||
double timer1CycleCounter;
|
||||
double timer2CycleCounter;
|
||||
|
||||
|
||||
static inline uint8_t registerArrayRead8(uint32_t address){return BUFFER_READ_8(palmReg, address, 0);}
|
||||
@@ -23,7 +24,6 @@ static inline void registerArrayWrite8(uint32_t address, uint8_t value){BUFFER_W
|
||||
static inline void registerArrayWrite16(uint32_t address, uint16_t value){BUFFER_WRITE_16(palmReg, address, 0, value);}
|
||||
static inline void registerArrayWrite32(uint32_t address, uint32_t value){BUFFER_WRITE_32(palmReg, address, 0, value);}
|
||||
|
||||
|
||||
static inline void setIprIsrBit(uint32_t interruptBit){
|
||||
//allows for setting an interrupt with masking by IMR and logging in IPR
|
||||
registerArrayWrite32(IPR, registerArrayRead32(IPR) | interruptBit);
|
||||
@@ -35,6 +35,31 @@ static inline void clearIprIsrBit(uint32_t interruptBit){
|
||||
registerArrayWrite32(ISR, registerArrayRead32(ISR) & ~interruptBit);
|
||||
}
|
||||
|
||||
static inline void pllWakeCpuIfOff(){
|
||||
uint16_t pllcr = registerArrayRead16(PLLCR);
|
||||
if(pllcr & 0x0008 && pllWakeWait == -1){
|
||||
//CPU is off and not already in the process of waking up
|
||||
switch(pllcr & 0x0003){
|
||||
|
||||
case 0x0000:
|
||||
pllWakeWait = 32;
|
||||
break;
|
||||
|
||||
case 0x0001:
|
||||
pllWakeWait = 48;
|
||||
break;
|
||||
|
||||
case 0x0002:
|
||||
pllWakeWait = 64;
|
||||
break;
|
||||
|
||||
case 0x0003:
|
||||
pllWakeWait = 96;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printUnknownHwAccess(unsigned int address, unsigned int value, unsigned int size, bool isWrite){
|
||||
if(isWrite){
|
||||
@@ -49,49 +74,59 @@ void printUnknownHwAccess(unsigned int address, unsigned int value, unsigned int
|
||||
void checkInterrupts(){
|
||||
uint32_t activeInterrupts = registerArrayRead32(ISR);
|
||||
uint16_t interruptLevelControlRegister = registerArrayRead16(ILCR);
|
||||
uint16_t portDEdgeSelect = registerArrayRead16(PDIRQEG);
|
||||
uint32_t intLevel = 0;
|
||||
bool reenablePllIfOff = false;
|
||||
|
||||
if(activeInterrupts & INT_EMIQ){
|
||||
//EMIQ - Emulator Irq, has nothing to do with emulation, used for debugging on a dev board
|
||||
intLevel = 7;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_SPI1){
|
||||
uint32_t spi1IrqLevel = interruptLevelControlRegister >> 12;
|
||||
if(intLevel < spi1IrqLevel)
|
||||
intLevel = spi1IrqLevel;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_IRQ5){
|
||||
if(intLevel < 5)
|
||||
intLevel = 5;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_IRQ3){
|
||||
if(intLevel < 3)
|
||||
intLevel = 3;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_IRQ2){
|
||||
if(intLevel < 2)
|
||||
intLevel = 2;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_IRQ1){
|
||||
if(intLevel < 1)
|
||||
intLevel = 1;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_PWM2){
|
||||
uint32_t pwm2IrqLevel = (interruptLevelControlRegister >> 4) & 0x0007;
|
||||
if(intLevel < pwm2IrqLevel)
|
||||
intLevel = pwm2IrqLevel;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_UART2){
|
||||
uint32_t uart2IrqLevel = (interruptLevelControlRegister >> 8) & 0x0007;
|
||||
if(intLevel < uart2IrqLevel)
|
||||
intLevel = uart2IrqLevel;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_TMR2){
|
||||
@@ -99,20 +134,58 @@ void checkInterrupts(){
|
||||
uint32_t timer2IrqLevel = interruptLevelControlRegister & 0x0007;
|
||||
if(intLevel < timer2IrqLevel)
|
||||
intLevel = timer2IrqLevel;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & (INT_TMR1 | INT_PWM1 | INT_IRQ6)){
|
||||
//All Fixed Level 6 Interrupts
|
||||
if(intLevel < 6)
|
||||
intLevel = 6;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & (INT_SPI2 | INT_UART1 | INT_WDT | INT_RTC | INT_KB | INT_INT0 | INT_INT1 | INT_INT2 | INT_INT3 | INT_RTI)){
|
||||
if(activeInterrupts & (INT_SPI2 | INT_UART1 | INT_WDT | INT_RTC | INT_KB | INT_RTI)){
|
||||
//All Fixed Level 4 Interrupts
|
||||
if(intLevel < 4)
|
||||
intLevel = 4;
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_INT0){
|
||||
//INTx, only reenable the PLL if interrupt is set to level sensitive
|
||||
if(intLevel < 4)
|
||||
intLevel = 4;
|
||||
if(!(portDEdgeSelect & 0x01))
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_INT1){
|
||||
//INTx, only reenable the PLL if interrupt is set to level sensitive
|
||||
if(intLevel < 4)
|
||||
intLevel = 4;
|
||||
if(!(portDEdgeSelect & 0x02))
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_INT2){
|
||||
//INTx, only reenable the PLL if interrupt is set to level sensitive
|
||||
if(intLevel < 4)
|
||||
intLevel = 4;
|
||||
if(!(portDEdgeSelect & 0x04))
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(activeInterrupts & INT_INT3){
|
||||
//INTx, only reenable the PLL if interrupt is set to level sensitive
|
||||
if(intLevel < 4)
|
||||
intLevel = 4;
|
||||
if(!(portDEdgeSelect & 0x08))
|
||||
reenablePllIfOff = true;
|
||||
}
|
||||
|
||||
if(reenablePllIfOff)
|
||||
pllWakeCpuIfOff();
|
||||
|
||||
m68k_set_irq(intLevel);//should be called even if intLevel is 0, that is how the interrupt state gets cleared
|
||||
}
|
||||
|
||||
@@ -152,15 +225,15 @@ static inline uint8_t getPortDValue(){
|
||||
}
|
||||
|
||||
static inline uint8_t getPortKValue(){
|
||||
uint8_t portKValue = 0x00;//ports always read the chip pins even if they are set to output
|
||||
uint8_t portKData = registerArrayRead8(PKDATA);
|
||||
uint8_t portKDir = registerArrayRead8(PKDIR);
|
||||
uint8_t portKSel = registerArrayRead8(PKSEL);
|
||||
uint8_t portKValue = 0x00;//ports always read the chip pins even if they are set to output
|
||||
uint8_t portKData = registerArrayRead8(PKDATA);
|
||||
uint8_t portKDir = registerArrayRead8(PKDIR);
|
||||
uint8_t portKSel = registerArrayRead8(PKSEL);
|
||||
|
||||
portKValue |= !palmMisc.inDock << 2 & ~portKDir & portKSel;
|
||||
portKValue |= portKData & portKDir & portKSel;
|
||||
portKValue |= !palmMisc.inDock << 2 & ~portKDir & portKSel;
|
||||
portKValue |= portKData & portKDir & portKSel;
|
||||
|
||||
return portKValue;
|
||||
return portKValue;
|
||||
}
|
||||
|
||||
static inline void checkPortDInts(){
|
||||
@@ -270,9 +343,9 @@ static inline void setPllcr(uint16_t value){
|
||||
debugLog("New clk32 cycle count of:%f.\n", palmCrystalCycles);
|
||||
|
||||
if(value & 0x0008){
|
||||
//the PLL is disabled, the CPU is off, end execution now
|
||||
m68k_end_timeslice();
|
||||
debugLog("Disable PLL set, CPU is off!\n");
|
||||
//The PLL shuts down 30 clock cycles of SYSCLK after the DISPLL bit is set in the PLLCR
|
||||
m68k_modify_timeslice(-m68k_cycles_remaining() + 30);
|
||||
debugLog("Disable PLL set, CPU off in 30 cycles!\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,8 +535,8 @@ static inline void timer12Clk32(){
|
||||
}
|
||||
|
||||
if(!(timer2Control & 0x0100)){
|
||||
//not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
|
||||
timer2Count -= timer2Compare;
|
||||
//not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
|
||||
timer2Count -= timer2Compare;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,7 +613,8 @@ static inline void rtcAddSecondClk32(){
|
||||
|
||||
void clk32(){
|
||||
registerArrayWrite16(PLLFSR, registerArrayRead16(PLLFSR) ^ 0x8000);
|
||||
//rolls over every second
|
||||
|
||||
//second position counter
|
||||
if(clk32Counter >= CRYSTAL_FREQUENCY - 1){
|
||||
clk32Counter = 0;
|
||||
rtcAddSecondClk32();
|
||||
@@ -548,6 +622,16 @@ void clk32(){
|
||||
else{
|
||||
clk32Counter++;
|
||||
}
|
||||
|
||||
//PLLCR wake select wait
|
||||
if(pllWakeWait != -1){
|
||||
if(pllWakeWait == 0){
|
||||
//reenable PLL and CPU
|
||||
registerArrayWrite16(PLLCR, registerArrayRead16(PLLCR) & 0xFFF7);
|
||||
debugLog("PLL reenabled, CPU is on!\n");
|
||||
}
|
||||
pllWakeWait--;
|
||||
}
|
||||
|
||||
rtiInterruptClk32();
|
||||
timer12Clk32();
|
||||
@@ -581,12 +665,10 @@ int interruptAcknowledge(int intLevel){
|
||||
vector = 15/*EXCEPTION_UNINITIALIZED_INTERRUPT*/;
|
||||
else
|
||||
vector = vectorOffset | intLevel;
|
||||
|
||||
//dont know if interrupts reenable the PLL if disabled, but they exit low power stop mode
|
||||
|
||||
lowPowerStopActive = false;
|
||||
|
||||
//the interrupt is not cleared until the handler writes a 1 to its source register, or manages the calling hardware
|
||||
//m68k_set_irq(0);//the interrupt should only be set to 0 after its been handled
|
||||
//the interrupt should only be cleared after its been handled
|
||||
|
||||
return vector;
|
||||
}
|
||||
@@ -1008,6 +1090,7 @@ void setHwRegister32(unsigned int address, unsigned int value){
|
||||
void resetHwRegisters(){
|
||||
memset(palmReg, 0x00, REG_SIZE);
|
||||
clk32Counter = 0;
|
||||
pllWakeWait = -1;
|
||||
timer1CycleCounter = 0.0;
|
||||
timer2CycleCounter = 0.0;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define INT_SPI2 0x00000001 //level 4
|
||||
|
||||
//variables
|
||||
extern int32_t pllWakeWait;
|
||||
extern uint32_t clk32Counter;
|
||||
extern double timer1CycleCounter;
|
||||
extern double timer2CycleCounter;
|
||||
|
||||
@@ -44,6 +44,14 @@ static inline void writeStateValueUint64(uint8_t* where, uint64_t value){
|
||||
*(uint64_t*)where = swap_if_little64(value);
|
||||
}
|
||||
|
||||
static inline int64_t readStateValueInt64(uint8_t* where){
|
||||
return swap_if_little64(*(uint64_t*)where);
|
||||
}
|
||||
|
||||
static inline void writeStateValueInt64(uint8_t* where, int64_t value){
|
||||
*(uint64_t*)where = swap_if_little64(value);
|
||||
}
|
||||
|
||||
static inline uint32_t readStateValueUint32(uint8_t* where){
|
||||
return swap_if_little32(*(uint32_t*)where);
|
||||
}
|
||||
@@ -52,6 +60,14 @@ static inline void writeStateValueUint32(uint8_t* where, uint32_t value){
|
||||
*(uint32_t*)where = swap_if_little32(value);
|
||||
}
|
||||
|
||||
static inline int32_t readStateValueInt32(uint8_t* where){
|
||||
return swap_if_little32(*(uint32_t*)where);
|
||||
}
|
||||
|
||||
static inline void writeStateValueInt32(uint8_t* where, int32_t value){
|
||||
*(uint32_t*)where = swap_if_little32(value);
|
||||
}
|
||||
|
||||
static inline uint16_t readStateValueUint16(uint8_t* where){
|
||||
return swap_if_little16(*(uint16_t*)where);
|
||||
}
|
||||
@@ -60,6 +76,14 @@ static inline void writeStateValueUint16(uint8_t* where, uint16_t value){
|
||||
*(uint16_t*)where = swap_if_little16(value);
|
||||
}
|
||||
|
||||
static inline int16_t readStateValueInt16(uint8_t* where){
|
||||
return swap_if_little16(*(uint16_t*)where);
|
||||
}
|
||||
|
||||
static inline void writeStateValueInt16(uint8_t* where, int16_t value){
|
||||
*(uint16_t*)where = swap_if_little16(value);
|
||||
}
|
||||
|
||||
static inline uint8_t readStateValueUint8(uint8_t* where){
|
||||
return *where;
|
||||
}
|
||||
@@ -68,6 +92,14 @@ static inline void writeStateValueUint8(uint8_t* where, uint8_t value){
|
||||
*where = value;
|
||||
}
|
||||
|
||||
static inline int8_t readStateValueInt8(uint8_t* where){
|
||||
return *where;
|
||||
}
|
||||
|
||||
static inline void writeStateValueInt8(uint8_t* where, int8_t value){
|
||||
*where = value;
|
||||
}
|
||||
|
||||
static inline bool readStateValueBool(uint8_t* where){
|
||||
return *where;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
Timer capture events, I don't think there possible though with the palms hardware
|
||||
sed1376 register access
|
||||
storage ram protect
|
||||
Timer capture events, I don't think there possible though with the Palms hardware
|
||||
SED1376 register access
|
||||
storage RAM protect
|
||||
sysTrapPceNativeCall, ARM Emulator
|
||||
cpu32 table lookup opcodes
|
||||
PLL Control Register, Wake Select
|
||||
Check if interrupts restart PLL when its disabled
|
||||
Peripheral Control Register, audio ppm mixing selection
|
||||
Port D level sensitive interrupts
|
||||
The data sheet says LRRA is 0xFFFFFA29 and 0xFFFFFA28 but its only 8bits?
|
||||
The boot memory mapping where rom starts at 0x00000000 and ram is swapped in
|
||||
Port D edge sensitive interrupts(currently always level sensitive), currently always triggers an interrupt when a button is pressed
|
||||
The data sheet says LRRA is 0xFFFFFA29 and 0xFFFFFA28 but its only 8 bits?
|
||||
The boot memory mapping where ROM starts at 0x00000000 and RAM is swapped in
|
||||
(debug tools)missing icons
|
||||
Port G spi stuff
|
||||
Ram location and size setting, Dragonball VZ can set the page mapping SDCTRL
|
||||
Port G SPI stuff
|
||||
RAM location and size setting, Dragonball VZ can set the page mapping SDCTRL
|
||||
DRAMC write enable
|
||||
All of DRAMMC
|
||||
All Chip select registers
|
||||
All chip select registers
|
||||
Setting the battery dead bit(PDDATA 0x80) if the emulated battery percent gets too low
|
||||
endian safe savestates
|
||||
sdcard can't be read or written to
|
||||
sdcard can't be inserted or removed
|
||||
sdcard has no error handling in save/load state
|
||||
Port m Infrared shutdown (PMDATA 0x20)
|
||||
Sdcard can't be read or written to
|
||||
Sdcard can't be inserted or removed
|
||||
Sdcard has no error handling in save/load state
|
||||
Port M Infrared shutdown (PMDATA 0x20)
|
||||
Disabling PLL also turns off all timers except the realtime clock unless they are set to use clk32 as there source
|
||||
|
||||
Fixed:
|
||||
System Control Register, 0xXXFFF000 all upper banks are registers mode
|
||||
Port D keyboard enable register
|
||||
(HW verified)PDPOL inverts interrupts by inverting PDDATA bits, the data register is affected by PDPOL
|
||||
(HW verified)PDPOL inverts interrupts by inverting PDDATA bits, the data register is affected by PDPOL
|
||||
Endian safe savestates
|
||||
PLL Control Register, Wake Select
|
||||
|
||||
Reference in New Issue
Block a user