mirror of
https://github.com/libretro/Mu.git
synced 2026-09-24 15:46:20 +00:00
SYSCLKs are now separeate from CLK32
This commit is contained in:
@@ -43,7 +43,7 @@ uint16_t* palmExtendedFramebuffer;
|
||||
int16_t palmAudio[AUDIO_SAMPLES * 2];
|
||||
uint32_t palmAudioSampleIndex;
|
||||
uint32_t palmSpecialFeatures;
|
||||
double palmCrystalCycles;//how many cycles before toggling the 32.768 kHz crystal
|
||||
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
|
||||
|
||||
@@ -167,6 +167,7 @@ uint64_t emulatorGetStateSize(){
|
||||
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(uint64_t);//pctlrCpuClockDivider
|
||||
size += sizeof(uint16_t) * 2;//timerStatusReadAcknowledge
|
||||
size += sizeof(uint32_t);//interruptEdgeTriggered
|
||||
size += sizeof(uint16_t) * 9;//RX 8 * 16 SPI1 FIFO, 1 index is for FIFO full
|
||||
@@ -247,7 +248,7 @@ bool emulatorSaveState(buffer_t buffer){
|
||||
}
|
||||
|
||||
//timing
|
||||
writeStateValueDouble(buffer.data + offset, palmCrystalCycles);
|
||||
writeStateValueDouble(buffer.data + offset, palmSysclksPerClk32);
|
||||
offset += sizeof(uint64_t);
|
||||
writeStateValueDouble(buffer.data + offset, palmCycleCounter);
|
||||
offset += sizeof(uint64_t);
|
||||
@@ -255,6 +256,8 @@ bool emulatorSaveState(buffer_t buffer){
|
||||
offset += sizeof(int32_t);
|
||||
writeStateValueUint32(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]);
|
||||
@@ -392,7 +395,7 @@ bool emulatorLoadState(buffer_t buffer){
|
||||
}
|
||||
|
||||
//timing
|
||||
palmCrystalCycles = readStateValueDouble(buffer.data + offset);
|
||||
palmSysclksPerClk32 = readStateValueDouble(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
palmCycleCounter = readStateValueDouble(buffer.data + offset);
|
||||
offset += sizeof(uint64_t);
|
||||
@@ -400,6 +403,8 @@ bool emulatorLoadState(buffer_t buffer){
|
||||
offset += sizeof(int32_t);
|
||||
clk32Counter = readStateValueUint32(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);
|
||||
@@ -525,8 +530,8 @@ void emulateFrame(){
|
||||
palmAudioSampleIndex = 0;
|
||||
|
||||
while(palmCycleCounter < (double)CRYSTAL_FREQUENCY / EMU_FPS){
|
||||
if(palmCrystalCycles > 0.0)
|
||||
m68k_execute(palmCrystalCycles * palmClockMultiplier);
|
||||
m68k_execute(palmSysclksPerClk32 * pctlrCpuClockDivider * palmClockMultiplier);
|
||||
sysclks(palmSysclksPerClk32);
|
||||
clk32();
|
||||
palmCycleCounter += 1.0;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ extern uint16_t* palmExtendedFramebuffer;//read allowed if FEATURE_320x320 is on
|
||||
extern int16_t palmAudio[];//read allowed, 2 channel signed 16 bit audio
|
||||
extern uint32_t palmAudioSampleIndex;//dont touch
|
||||
extern uint32_t palmSpecialFeatures;//read allowed
|
||||
extern double palmCrystalCycles;//dont touch
|
||||
extern double palmSysclksPerClk32;//dont touch
|
||||
extern double palmCycleCounter;//dont touch
|
||||
extern double palmClockMultiplier;//read/write allowed
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
chip_t chips[CHIP_END];
|
||||
int32_t pllWakeWait;
|
||||
uint32_t clk32Counter;
|
||||
double pctlrCpuClockDivider;
|
||||
double timerCycleCounter[2];
|
||||
uint16_t timerStatusReadAcknowledge[2];
|
||||
uint32_t interruptEdgeTriggered;
|
||||
@@ -35,8 +36,8 @@ uint8_t pwm1WritePosition;
|
||||
|
||||
static void checkInterrupts();
|
||||
static void checkPortDInterrupts();
|
||||
static void recalculateCpuSpeed();
|
||||
static void pllWakeCpuIfOff();
|
||||
static double sysclksPerClk32();
|
||||
|
||||
#include "hardwareRegistersAccessors.c.h"
|
||||
#include "hardwareRegistersTiming.c.h"
|
||||
@@ -112,30 +113,6 @@ void setWriteProtectViolation(uint32_t address){
|
||||
m68328BusError(address, true);
|
||||
}
|
||||
|
||||
static void recalculateCpuSpeed(){
|
||||
double newCpuSpeed = sysclksPerClk32();
|
||||
uint8_t pctlr = registerArrayRead8(PCTLR);
|
||||
|
||||
//power control burst mode
|
||||
if(pctlr & 0x80)
|
||||
newCpuSpeed *= (pctlr & 0x1F) / 31.0;
|
||||
|
||||
/*
|
||||
if(newCpuSpeed != palmCrystalCycles){
|
||||
debugLog("New CPU frequency of:%f cycles per second.\n", newCpuSpeed * CRYSTAL_FREQUENCY);
|
||||
debugLog("New CLK32 cycle count of:%f.\n", newCpuSpeed);
|
||||
if(newCpuSpeed == 0.0){
|
||||
if(pllIsOn())
|
||||
debugLog("CPU turned off with PCTLR.\n");
|
||||
else
|
||||
debugLog("CPU turned off with DISPLL bit.\n");
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
palmCrystalCycles = newCpuSpeed;
|
||||
}
|
||||
|
||||
static void pllWakeCpuIfOff(){
|
||||
if(!pllIsOn() && pllWakeWait == -1){
|
||||
//PLL is off and not already in the process of waking up
|
||||
@@ -214,7 +191,7 @@ static void checkInterrupts(){
|
||||
//even masked interrupts turn off PCTLR, Chapter 4.5.4 MC68VZ328UM.pdf
|
||||
if(intLevel > 0 && registerArrayRead8(PCTLR) & 0x80){
|
||||
registerArrayWrite8(PCTLR, registerArrayRead8(PCTLR) & 0x1F);
|
||||
recalculateCpuSpeed();
|
||||
pctlrCpuClockDivider = 1.0;
|
||||
}
|
||||
|
||||
m68k_set_irq(intLevel);//should be called even if intLevel is 0, that is how the interrupt state gets cleared
|
||||
@@ -647,7 +624,8 @@ void setHwRegister8(uint32_t address, uint8_t value){
|
||||
|
||||
case PCTLR:
|
||||
registerArrayWrite8(address, value & 0x9F);
|
||||
recalculateCpuSpeed();
|
||||
if(value & 0x80)
|
||||
pctlrCpuClockDivider = (value & 0x1F) / 31.0;
|
||||
break;
|
||||
|
||||
case IVR:
|
||||
@@ -836,7 +814,7 @@ void setHwRegister16(uint32_t address, uint16_t value){
|
||||
case PLLCR:
|
||||
//CLKEN is required for SED1376 operation
|
||||
registerArrayWrite16(PLLCR, value & 0x3FBB);
|
||||
recalculateCpuSpeed();
|
||||
palmSysclksPerClk32 = sysclksPerClk32();
|
||||
setSed1376Attached(sed1376ClockConnected());
|
||||
|
||||
if(value & 0x0008){
|
||||
@@ -1090,8 +1068,9 @@ void resetHwRegisters(){
|
||||
uint16_t oldDayr = registerArrayRead16(DAYR);//preserve DAYR
|
||||
|
||||
memset(palmReg, 0x00, REG_SIZE - BOOTLOADER_SIZE);
|
||||
palmCrystalCycles = 0.0;
|
||||
palmSysclksPerClk32 = 0.0;
|
||||
clk32Counter = 0;
|
||||
pctlrCpuClockDivider = 1.0;
|
||||
pllWakeWait = -1;
|
||||
timerCycleCounter[0] = 0.0;
|
||||
timerCycleCounter[1] = 0.0;
|
||||
@@ -1230,7 +1209,7 @@ void resetHwRegisters(){
|
||||
updateAds7846ChipSelectStatus();
|
||||
updateBacklightAmplifierStatus();
|
||||
|
||||
recalculateCpuSpeed();
|
||||
palmSysclksPerClk32 = sysclksPerClk32();
|
||||
}
|
||||
|
||||
void setRtc(uint16_t days, uint8_t hours, uint8_t minutes, uint8_t seconds){
|
||||
|
||||
@@ -28,11 +28,9 @@
|
||||
#define INT_SPI2 0x00000001//level 4
|
||||
|
||||
//reasons a timer is triggered
|
||||
#define TIMER_REASON_STOP 0x0000
|
||||
#define TIMER_REASON_SYSCLK 0x0001
|
||||
#define TIMER_REASON_SYSCLK16 0x0002
|
||||
#define TIMER_REASON_TIN 0x0003
|
||||
#define TIMER_REASON_CLK32 0x0004
|
||||
#define TIMER_REASON_SYSCLK 0x0000
|
||||
#define TIMER_REASON_TIN 0x0001
|
||||
#define TIMER_REASON_CLK32 0x0002
|
||||
|
||||
//chip names
|
||||
enum{
|
||||
@@ -67,6 +65,7 @@ typedef struct{
|
||||
extern chip_t chips[];
|
||||
extern int32_t pllWakeWait;
|
||||
extern uint32_t clk32Counter;
|
||||
extern double pctlrCpuClockDivider;
|
||||
extern double timerCycleCounter[];
|
||||
extern uint16_t timerStatusReadAcknowledge[];
|
||||
extern uint32_t interruptEdgeTriggered;
|
||||
@@ -82,7 +81,8 @@ extern uint8_t pwm1ReadPosition;
|
||||
extern uint8_t pwm1WritePosition;
|
||||
|
||||
//timing
|
||||
void clk32();//also checks all interrupts
|
||||
void clk32();
|
||||
void sysclks(double value);
|
||||
|
||||
//CPU
|
||||
bool pllIsOn();
|
||||
|
||||
@@ -230,7 +230,7 @@ static inline void setPllfsr(uint16_t value){
|
||||
if(!(oldPllfsr & 0x4000)){
|
||||
//frequency protect bit not set
|
||||
registerArrayWrite16(PLLFSR, (value & 0x4FFF) | (oldPllfsr & 0x8000));//preserve CLK32 bit
|
||||
recalculateCpuSpeed();
|
||||
palmSysclksPerClk32 = sysclksPerClk32();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,139 @@
|
||||
static void timer1(uint8_t reason, double sysclks);
|
||||
static void timer2(uint8_t reason, double sysclks)
|
||||
static void timer2(uint8_t reason, double sysclks);
|
||||
|
||||
static inline double dmaclksPerClk32(){
|
||||
static void timer1(uint8_t reason, double sysclks){
|
||||
uint16_t timer1Control = registerArrayRead16(TCTL1);
|
||||
uint16_t timer1Compare = registerArrayRead16(TCMP1);
|
||||
double timer1OldCount = timerCycleCounter[0];
|
||||
double timer1Prescaler = (registerArrayRead16(TPRER1) & 0x00FF) + 1;
|
||||
bool timer1Enabled = timer1Control & 0x0001;
|
||||
|
||||
if(timer1Enabled){
|
||||
switch((timer1Control & 0x000E) >> 1){
|
||||
case 0x0000://stop counter
|
||||
//do nothing
|
||||
return;
|
||||
|
||||
case 0x0001://SYSCLK / timer prescaler
|
||||
if(reason != TIMER_REASON_SYSCLK)
|
||||
return;
|
||||
timerCycleCounter[0] += sysclks / timer1Prescaler;
|
||||
break;
|
||||
|
||||
case 0x0002://SYSCLK / 16 / timer prescaler
|
||||
if(reason != TIMER_REASON_SYSCLK)
|
||||
return;
|
||||
timerCycleCounter[0] += sysclks / 16.0 / timer1Prescaler;
|
||||
break;
|
||||
|
||||
case 0x0003://TIN/TOUT pin / timer prescaler, the other timer can be attached to TIN/TOUT
|
||||
if(reason != TIMER_REASON_TIN)
|
||||
return;
|
||||
timerCycleCounter[0] += 1.0 / timer1Prescaler;
|
||||
break;
|
||||
|
||||
default://CLK32 / timer prescaler
|
||||
if(reason != TIMER_REASON_CLK32)
|
||||
return;
|
||||
timerCycleCounter[0] += 1.0 / timer1Prescaler;
|
||||
break;
|
||||
}
|
||||
|
||||
if(timer1OldCount < timer1Compare && timerCycleCounter[0] >= timer1Compare){
|
||||
//the comparison against the old value is to prevent an interrupt on every increment in free running mode
|
||||
//the timer is not cycle accurate and may not hit the value in the compare register perfectly so check if it would have during in the emulated time
|
||||
uint8_t pcrTinToutConfig = registerArrayRead8(PCR) & 0x03;//TIN/TOUT seems not to be physicaly connected but cascaded timers still need to be supported
|
||||
|
||||
//interrupt enabled
|
||||
if(timer1Control & 0x0010)
|
||||
setIprIsrBit(INT_TMR1);
|
||||
|
||||
//set timer triggered bit
|
||||
registerArrayWrite16(TSTAT1, registerArrayRead16(TSTAT1) | 0x0001);
|
||||
timerStatusReadAcknowledge[0] &= 0xFFFE;//lock bit until next read
|
||||
|
||||
//increment other timer if enabled
|
||||
if(pcrTinToutConfig == 0x03)
|
||||
timer2(TIMER_REASON_TIN, 0);
|
||||
|
||||
//not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
|
||||
if(!(timer1Control & 0x0100))
|
||||
timerCycleCounter[0] -= timer1Compare;
|
||||
}
|
||||
|
||||
if(timerCycleCounter[0] > 0xFFFF)
|
||||
timerCycleCounter[0] -= 0xFFFF;
|
||||
registerArrayWrite16(TCN1, (uint16_t)timerCycleCounter[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static void timer2(uint8_t reason, double sysclks){
|
||||
uint16_t timer2Control = registerArrayRead16(TCTL2);
|
||||
uint16_t timer2Compare = registerArrayRead16(TCMP2);
|
||||
double timer2OldCount = timerCycleCounter[1];
|
||||
double timer2Prescaler = (registerArrayRead16(TPRER2) & 0x00FF) + 1;
|
||||
bool timer2Enabled = timer2Control & 0x0001;
|
||||
|
||||
if(timer2Enabled){
|
||||
switch((timer2Control & 0x000E) >> 1){
|
||||
case 0x0000://stop counter
|
||||
//do nothing
|
||||
return;
|
||||
|
||||
case 0x0001://SYSCLK / timer prescaler
|
||||
if(reason != TIMER_REASON_SYSCLK)
|
||||
return;
|
||||
timerCycleCounter[1] += sysclks / timer2Prescaler;
|
||||
break;
|
||||
|
||||
case 0x0002://SYSCLK / 16 / timer prescaler
|
||||
if(reason != TIMER_REASON_SYSCLK)
|
||||
return;
|
||||
timerCycleCounter[1] += sysclks / 16.0 / timer2Prescaler;
|
||||
break;
|
||||
|
||||
case 0x0003://TIN/TOUT pin / timer prescaler, the other timer can be attached to TIN/TOUT
|
||||
if(reason != TIMER_REASON_TIN)
|
||||
return;
|
||||
timerCycleCounter[1] += 1.0 / timer2Prescaler;
|
||||
break;
|
||||
|
||||
default://CLK32 / timer prescaler
|
||||
if(reason != TIMER_REASON_CLK32)
|
||||
return;
|
||||
timerCycleCounter[1] += 1.0 / timer2Prescaler;
|
||||
break;
|
||||
}
|
||||
|
||||
if(timer2OldCount < timer2Compare && timerCycleCounter[1] >= timer2Compare){
|
||||
//the comparison against the old value is to prevent an interrupt on every increment in free running mode
|
||||
//the timer is not cycle accurate and may not hit the value in the compare register perfectly so check if it would have during in the emulated time
|
||||
uint8_t pcrTinToutConfig = registerArrayRead8(PCR) & 0x03;//TIN/TOUT seems not to be physicaly connected but cascaded timers still need to be supported
|
||||
|
||||
//interrupt enabled
|
||||
if(timer2Control & 0x0010)
|
||||
setIprIsrBit(INT_TMR2);
|
||||
|
||||
//set timer triggered bit
|
||||
registerArrayWrite16(TSTAT2, registerArrayRead16(TSTAT2) | 0x0001);
|
||||
timerStatusReadAcknowledge[1] &= 0xFFFE;//lock bit until next read
|
||||
|
||||
//increment other timer if enabled
|
||||
if(pcrTinToutConfig == 0x02)
|
||||
timer1(TIMER_REASON_TIN, 0);
|
||||
|
||||
//not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
|
||||
if(!(timer2Control & 0x0100))
|
||||
timerCycleCounter[1] -= timer2Compare;
|
||||
}
|
||||
|
||||
if(timerCycleCounter[1] > 0xFFFF)
|
||||
timerCycleCounter[1] -= 0xFFFF;
|
||||
registerArrayWrite16(TCN2, (uint16_t)timerCycleCounter[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static double dmaclksPerClk32(){
|
||||
double dmaclks;
|
||||
|
||||
if(pllIsOn()){
|
||||
@@ -26,7 +158,7 @@ static inline double dmaclksPerClk32(){
|
||||
return dmaclks;
|
||||
}
|
||||
|
||||
static inline double sysclksPerClk32(){
|
||||
static double sysclksPerClk32(){
|
||||
uint8_t sysclkSelect = registerArrayRead16(PLLCR) >> 8 & 0x0003;
|
||||
|
||||
//> 4 means run at full speed, no divider
|
||||
@@ -81,265 +213,6 @@ static inline void rtiInterruptClk32(){
|
||||
}
|
||||
}
|
||||
|
||||
static void timer1(uint8_t reason, double sysclks){
|
||||
uint16_t timer1Control = registerArrayRead16(TCTL1);
|
||||
uint16_t timer1Compare = registerArrayRead16(TCMP1);
|
||||
double timer1OldCount = timerCycleCounter[0];
|
||||
double timer1Prescaler = (registerArrayRead16(TPRER1) & 0x00FF) + 1;
|
||||
bool timer1Enabled = timer1Control & 0x0001;
|
||||
|
||||
if(timer1Enabled){
|
||||
uint8_t timer1Source = (timer1Control & 0x000E) >> 1;
|
||||
|
||||
//all CLK32 modes compare to 0x0004
|
||||
if(timer1Source > 0x0004)
|
||||
timer1Source = TIMER_REASON_CLK32;
|
||||
|
||||
if(timer1Source != reason)
|
||||
return;
|
||||
|
||||
switch(timer1Source){
|
||||
case TIMER_REASON_STOP://stop counter
|
||||
//do nothing
|
||||
return;
|
||||
|
||||
case TIMER_REASON_SYSCLK://SYSCLK / timer prescaler
|
||||
timerCycleCounter[0] += sysclks / timer1Prescaler;
|
||||
break;
|
||||
|
||||
case TIMER_REASON_SYSCLK16://SYSCLK / 16 / timer prescaler
|
||||
timerCycleCounter[0] += sysclks / 16.0 / timer1Prescaler;
|
||||
break;
|
||||
|
||||
case TIMER_REASON_TIN://TIN/TOUT pin / timer prescaler, the other timer can be attached to TIN/TOUT
|
||||
case TIMER_REASON_CLK32://CLK32 / timer prescaler
|
||||
timerCycleCounter[0] += 1.0 / timer1Prescaler;
|
||||
break;
|
||||
}
|
||||
|
||||
if(timer1OldCount < timer1Compare && timerCycleCounter[0] >= timer1Compare){
|
||||
//the comparison against the old value is to prevent an interrupt on every increment in free running mode
|
||||
//the timer is not cycle accurate and may not hit the value in the compare register perfectly so check if it would have during in the emulated time
|
||||
uint8_t pcrTinToutConfig = registerArrayRead8(PCR) & 0x03;//TIN/TOUT seems not to be physicaly connected but cascaded timers still need to be supported
|
||||
|
||||
//interrupt enabled
|
||||
if(timer1Control & 0x0010)
|
||||
setIprIsrBit(INT_TMR1);
|
||||
|
||||
//set timer triggered bit
|
||||
registerArrayWrite16(TSTAT1, registerArrayRead16(TSTAT1) | 0x0001);
|
||||
timerStatusReadAcknowledge[0] &= 0xFFFE;//lock bit until next read
|
||||
|
||||
if(pcrTinToutConfig == 0x03)
|
||||
timer2(TIMER_REASON_TIN, 0);
|
||||
|
||||
//not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
|
||||
if(!(timer1Control & 0x0100))
|
||||
timerCycleCounter[0] -= timer1Compare;
|
||||
}
|
||||
|
||||
if(timerCycleCounter[0] > 0xFFFF)
|
||||
timerCycleCounter[0] -= 0xFFFF;
|
||||
registerArrayWrite16(TCN1, (uint16_t)timerCycleCounter[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static void timer2(uint8_t reason, double sysclks){
|
||||
uint16_t timer2Control = registerArrayRead16(TCTL2);
|
||||
uint16_t timer2Compare = registerArrayRead16(TCMP2);
|
||||
double timer2OldCount = timerCycleCounter[1];
|
||||
double timer2Prescaler = (registerArrayRead16(TPRER2) & 0x00FF) + 1;
|
||||
bool timer2Enabled = timer2Control & 0x0001;
|
||||
|
||||
if(timer2Enabled){
|
||||
uint8_t timer2Source = (timer2Control & 0x000E) >> 1;
|
||||
|
||||
//all CLK32 modes compare to 0x0004
|
||||
if(timer2Source > 0x0004)
|
||||
timer2Source = 0x0004;
|
||||
|
||||
if(timer2Source != reason)
|
||||
return;
|
||||
|
||||
switch(timer2Source){
|
||||
case TIMER_REASON_STOP://stop counter
|
||||
//do nothing
|
||||
return;
|
||||
|
||||
case TIMER_REASON_SYSCLK://SYSCLK / timer prescaler
|
||||
timerCycleCounter[1] += sysclks / timer2Prescaler;
|
||||
break;
|
||||
|
||||
case TIMER_REASON_SYSCLK16://SYSCLK / 16 / timer prescaler
|
||||
timerCycleCounter[1] += sysclks / 16.0 / timer2Prescaler;
|
||||
break;
|
||||
|
||||
case TIMER_REASON_TIN://TIN/TOUT pin / timer prescaler, the other timer can be attached to TIN/TOUT
|
||||
case TIMER_REASON_CLK32://CLK32 / timer prescaler
|
||||
timerCycleCounter[1] += 1.0 / timer2Prescaler;
|
||||
break;
|
||||
}
|
||||
|
||||
if(timer2OldCount < timer2Compare && timerCycleCounter[1] >= timer2Compare){
|
||||
//the comparison against the old value is to prevent an interrupt on every increment in free running mode
|
||||
//the timer is not cycle accurate and may not hit the value in the compare register perfectly so check if it would have during in the emulated time
|
||||
uint8_t pcrTinToutConfig = registerArrayRead8(PCR) & 0x03;//TIN/TOUT seems not to be physicaly connected but cascaded timers still need to be supported
|
||||
|
||||
//interrupt enabled
|
||||
if(timer2Control & 0x0010)
|
||||
setIprIsrBit(INT_TMR2);
|
||||
|
||||
//set timer triggered bit
|
||||
registerArrayWrite16(TSTAT2, registerArrayRead16(TSTAT2) | 0x0001);
|
||||
timerStatusReadAcknowledge[1] &= 0xFFFE;//lock bit until next read
|
||||
|
||||
if(pcrTinToutConfig == 0x02)
|
||||
timer1(TIMER_REASON_TIN, 0);
|
||||
|
||||
//not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
|
||||
if(!(timer2Control & 0x0100))
|
||||
timerCycleCounter[1] -= timer2Compare;
|
||||
}
|
||||
|
||||
if(timerCycleCounter[1] > 0xFFFF)
|
||||
timerCycleCounter[1] -= 0xFFFF;
|
||||
registerArrayWrite16(TCN2, (uint16_t)timerCycleCounter[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void timer12Clk32(){
|
||||
//this function is part of clk32();
|
||||
uint16_t timer1Control = registerArrayRead16(TCTL1);
|
||||
uint16_t timer1Compare = registerArrayRead16(TCMP1);
|
||||
double timer1OldCount = timerCycleCounter[0];
|
||||
double timer1Prescaler = (registerArrayRead16(TPRER1) & 0x00FF) + 1;
|
||||
bool timer1Enabled = timer1Control & 0x0001;
|
||||
uint16_t timer2Control = registerArrayRead16(TCTL2);
|
||||
uint16_t timer2Compare = registerArrayRead16(TCMP2);
|
||||
double timer2OldCount = timerCycleCounter[0];
|
||||
double timer2Prescaler = (registerArrayRead16(TPRER2) & 0x00FF) + 1;
|
||||
bool timer2Enabled = timer2Control & 0x0001;
|
||||
uint8_t pcrTinToutConfig = registerArrayRead8(PCR) & 0x03;//TIN/TOUT seems not to be physicaly connected but cascaded timers still need to be supported
|
||||
double sysclks = sysclksPerClk32();
|
||||
|
||||
if(timer1Enabled && pcrTinToutConfig != 0x02){
|
||||
switch((timer1Control & 0x000E) >> 1){
|
||||
case 0x0000://stop counter
|
||||
//do nothing
|
||||
break;
|
||||
|
||||
case 0x0001://SYSCLK / timer prescaler
|
||||
timerCycleCounter[0] += sysclks / timer1Prescaler;
|
||||
break;
|
||||
|
||||
case 0x0002://SYSCLK / 16 / timer prescaler
|
||||
timerCycleCounter[0] += sysclks / 16.0 / timer1Prescaler;
|
||||
break;
|
||||
|
||||
case 0x0003://TIN/TOUT pin / timer prescaler, nothing is attached to TIN/TOUT
|
||||
//do nothing
|
||||
break;
|
||||
|
||||
default://CLK32 / timer prescaler
|
||||
timerCycleCounter[0] += 1.0 / timer1Prescaler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(timer2Enabled && pcrTinToutConfig != 0x03){
|
||||
switch((timer2Control & 0x000E) >> 1){
|
||||
case 0x0000://stop counter
|
||||
//do nothing
|
||||
break;
|
||||
|
||||
case 0x0001://SYSCLK / timer prescaler
|
||||
timerCycleCounter[1] += sysclks / timer2Prescaler;
|
||||
break;
|
||||
|
||||
case 0x0002://SYSCLK / 16 / timer prescaler
|
||||
timerCycleCounter[1] += sysclks / 16.0 / timer2Prescaler;
|
||||
break;
|
||||
|
||||
case 0x0003://TIN/TOUT pin / timer prescaler, nothing is attached to TIN/TOUT
|
||||
//do nothing
|
||||
break;
|
||||
|
||||
default://CLK32 / timer prescaler
|
||||
timerCycleCounter[1] += 1.0 / timer2Prescaler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(timer1Enabled && timer1OldCount < timer1Compare && timerCycleCounter[0] >= timer1Compare){
|
||||
//the comparison against the old value is to prevent an interrupt on every increment in free running mode
|
||||
//the timer is not cycle accurate and may not hit the value in the compare register perfectly so check if it would have during in the emulated time
|
||||
|
||||
//interrupt enabled
|
||||
if(timer1Control & 0x0010)
|
||||
setIprIsrBit(INT_TMR1);
|
||||
|
||||
//set timer triggered bit
|
||||
registerArrayWrite16(TSTAT1, registerArrayRead16(TSTAT1) | 0x0001);
|
||||
timerStatusReadAcknowledge[0] &= 0xFFFE;//lock bit until next read
|
||||
|
||||
//not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
|
||||
if(!(timer1Control & 0x0100))
|
||||
timerCycleCounter[0] -= timer1Compare;
|
||||
}
|
||||
|
||||
if(timer2Enabled && timer2OldCount < timer2Compare && timerCycleCounter[1] >= timer2Compare){
|
||||
//the comparison against the old value is to prevent an interrupt on every increment in free running mode
|
||||
//the timer is not cycle accurate and may not hit the value in the compare register perfectly so check if it would have during in the emulated time
|
||||
|
||||
//interrupt enabled
|
||||
if(timer2Control & 0x0010)
|
||||
setIprIsrBit(INT_TMR2);
|
||||
|
||||
//set timer triggered bit
|
||||
registerArrayWrite16(TSTAT2, registerArrayRead16(TSTAT2) | 0x0001);
|
||||
timerStatusReadAcknowledge[1] &= 0xFFFE;//lock bit until next read
|
||||
|
||||
//not free running, reset to 0, to prevent loss of ticks after compare event just subtract timerXCompare
|
||||
if(!(timer2Control & 0x0100))
|
||||
timerCycleCounter[1] -= timer2Compare;
|
||||
}
|
||||
|
||||
if(timer1Enabled && timer2Enabled){
|
||||
switch(pcrTinToutConfig){
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
//do nothing
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
//PCR T field, 0x02 = Timer 2 OUT -> Timer 1 IN; TIN -> Timer 2 (DIR6 = 0), or TOUT -> Timer 1 (DIR6 = 1).
|
||||
if(timerCycleCounter[1] > 0xFFFF)
|
||||
timerCycleCounter[0] += 1.0;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
//PCR T field, 0x03 = Timer 1 OUT -> Timer 2 IN; TIN -> Timer 1 (DIR6 = 0), or TOUT -> Timer 2 (DIR6 = 1)
|
||||
if(timerCycleCounter[0] > 0xFFFF)
|
||||
timerCycleCounter[1] += 1.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if timer chaining causes an interrupt the actual interrupt takes place the next time this function is called
|
||||
|
||||
if(timer1Enabled){
|
||||
if(timerCycleCounter[0] > 0xFFFF)
|
||||
timerCycleCounter[0] -= 0xFFFF;
|
||||
registerArrayWrite16(TCN1, (uint16_t)timerCycleCounter[0]);
|
||||
}
|
||||
|
||||
if(timer2Enabled){
|
||||
if(timerCycleCounter[1] > 0xFFFF)
|
||||
timerCycleCounter[1] -= 0xFFFF;
|
||||
registerArrayWrite16(TCN2, (uint16_t)timerCycleCounter[1]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void watchdogSecondTickClk32(){
|
||||
//this function is part of clk32();
|
||||
uint16_t watchdogState = registerArrayRead16(WATCHDOG);
|
||||
@@ -447,7 +320,8 @@ void clk32(){
|
||||
if(registerArrayRead16(RTCCTL) & 0x0080 || registerArrayRead16(WATCHDOG) & 0x01)
|
||||
rtiInterruptClk32();
|
||||
|
||||
timer12Clk32();
|
||||
timer1(TIMER_REASON_CLK32, 0);
|
||||
timer2(TIMER_REASON_CLK32, 0);
|
||||
samplePwmXClk32();
|
||||
|
||||
//PLLCR wake select wait
|
||||
@@ -455,7 +329,7 @@ void clk32(){
|
||||
if(pllWakeWait == 0){
|
||||
//reenable PLL and CPU
|
||||
registerArrayWrite16(PLLCR, registerArrayRead16(PLLCR) & 0xFFF7);
|
||||
recalculateCpuSpeed();
|
||||
palmSysclksPerClk32 = sysclksPerClk32();
|
||||
debugLog("PLL reenabled, CPU is on!\n");
|
||||
}
|
||||
pllWakeWait--;
|
||||
@@ -463,3 +337,8 @@ void clk32(){
|
||||
|
||||
checkInterrupts();
|
||||
}
|
||||
|
||||
void sysclks(double count){
|
||||
timer1(TIMER_REASON_SYSCLK, count);
|
||||
timer2(TIMER_REASON_SYSCLK, count);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user