implement all types of RTC IRQ
This commit is contained in:
parent
9ccdc23fa0
commit
b90576b757
154
src/RTC.cpp
154
src/RTC.cpp
|
@ -249,7 +249,7 @@ void SetIRQ(u8 irq)
|
||||||
if ((!(oldstat & 0x30)) && (State.IRQFlag & 0x30))
|
if ((!(oldstat & 0x30)) && (State.IRQFlag & 0x30))
|
||||||
{
|
{
|
||||||
if ((NDS::RCnt & 0xC100) == 0x8100)
|
if ((NDS::RCnt & 0xC100) == 0x8100)
|
||||||
{printf("IRQ\n");
|
{
|
||||||
// CHECKME: is the IRQ status readable in RCNT?
|
// CHECKME: is the IRQ status readable in RCNT?
|
||||||
NDS::SetIRQ(1, NDS::IRQ_RTC);
|
NDS::SetIRQ(1, NDS::IRQ_RTC);
|
||||||
}
|
}
|
||||||
|
@ -261,6 +261,125 @@ void ClearIRQ(u8 irq)
|
||||||
State.IRQFlag &= ~irq;
|
State.IRQFlag &= ~irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessIRQ(int type) // 0=minute carry 1=periodic 2=status reg write
|
||||||
|
{
|
||||||
|
// INT1
|
||||||
|
|
||||||
|
switch (State.StatusReg2 & 0x0F)
|
||||||
|
{
|
||||||
|
case 0b0000: // none
|
||||||
|
if (type == 2)
|
||||||
|
{
|
||||||
|
ClearIRQ(0x10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b0001:
|
||||||
|
case 0b0101: // selected frequency steady interrupt
|
||||||
|
if ((type == 1 && (!(ClockCount & 0x3FF))) || (type == 2))
|
||||||
|
{
|
||||||
|
u32 mask = 0;
|
||||||
|
if (State.Alarm1[2] & (1<<0)) mask |= 0x4000;
|
||||||
|
if (State.Alarm1[2] & (1<<1)) mask |= 0x2000;
|
||||||
|
if (State.Alarm1[2] & (1<<2)) mask |= 0x1000;
|
||||||
|
if (State.Alarm1[2] & (1<<3)) mask |= 0x0800;
|
||||||
|
if (State.Alarm1[2] & (1<<4)) mask |= 0x0400;
|
||||||
|
|
||||||
|
if (mask && ((ClockCount & mask) != mask))
|
||||||
|
SetIRQ(0x10);
|
||||||
|
else
|
||||||
|
ClearIRQ(0x10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b0010:
|
||||||
|
case 0b0110: // per-minute edge interrupt
|
||||||
|
if ((type == 0) || (type == 2 && (State.IRQFlag & 0x01)))
|
||||||
|
{
|
||||||
|
SetIRQ(0x10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b0011: // per-minute steady interrupt 1 (duty 30s)
|
||||||
|
if ((type == 0) || (type == 2 && (State.IRQFlag & 0x01)))
|
||||||
|
{
|
||||||
|
SetIRQ(0x10);
|
||||||
|
}
|
||||||
|
else if ((type == 1) && (State.DateTime[6] == 0x30))
|
||||||
|
{
|
||||||
|
ClearIRQ(0x10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b0111: // per-minute steady interrupt 2 (duty 256 cycles)
|
||||||
|
if ((type == 0) || (type == 2 && (State.IRQFlag & 0x01)))
|
||||||
|
{
|
||||||
|
SetIRQ(0x10);
|
||||||
|
}
|
||||||
|
else if ((type == 1) && (State.DateTime[6] == 0x00) && ((ClockCount & 0x7FFF) == 256))
|
||||||
|
{
|
||||||
|
ClearIRQ(0x10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b0100: // alarm interrupt
|
||||||
|
if (type == 0)
|
||||||
|
{
|
||||||
|
bool cond = true;
|
||||||
|
if (State.Alarm1[0] & (1<<7))
|
||||||
|
cond = cond && ((State.Alarm1[0] & 0x07) == State.DateTime[3]);
|
||||||
|
if (State.Alarm1[1] & (1<<7))
|
||||||
|
cond = cond && ((State.Alarm1[1] & 0x7F) == State.DateTime[4]);
|
||||||
|
if (State.Alarm1[2] & (1<<7))
|
||||||
|
cond = cond && ((State.Alarm1[2] & 0x7F) == State.DateTime[5]);
|
||||||
|
|
||||||
|
if (cond)
|
||||||
|
SetIRQ(0x10);
|
||||||
|
else
|
||||||
|
ClearIRQ(0x10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: // 32KHz output
|
||||||
|
if (type == 1)
|
||||||
|
{
|
||||||
|
SetIRQ(0x10);
|
||||||
|
ClearIRQ(0x10);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// INT2
|
||||||
|
|
||||||
|
if (State.StatusReg2 & (1<<6))
|
||||||
|
{
|
||||||
|
// alarm interrupt
|
||||||
|
|
||||||
|
if (type == 0)
|
||||||
|
{
|
||||||
|
bool cond = true;
|
||||||
|
if (State.Alarm2[0] & (1<<7))
|
||||||
|
cond = cond && ((State.Alarm2[0] & 0x07) == State.DateTime[3]);
|
||||||
|
if (State.Alarm2[1] & (1<<7))
|
||||||
|
cond = cond && ((State.Alarm2[1] & 0x7F) == State.DateTime[4]);
|
||||||
|
if (State.Alarm2[2] & (1<<7))
|
||||||
|
cond = cond && ((State.Alarm2[2] & 0x7F) == State.DateTime[5]);
|
||||||
|
|
||||||
|
if (cond)
|
||||||
|
SetIRQ(0x20);
|
||||||
|
else
|
||||||
|
ClearIRQ(0x20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (type == 2)
|
||||||
|
{
|
||||||
|
ClearIRQ(0x20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
u8 DaysInMonth()
|
u8 DaysInMonth()
|
||||||
{
|
{
|
||||||
|
@ -382,6 +501,9 @@ void CountMinute()
|
||||||
State.DateTime[5] = 0;
|
State.DateTime[5] = 0;
|
||||||
CountHour();
|
CountHour();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
State.IRQFlag |= 0x01; // store minute carry flag
|
||||||
|
ProcessIRQ(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CountSecond()
|
void CountSecond()
|
||||||
|
@ -417,29 +539,13 @@ void ClockTimer(u32 param)
|
||||||
// count up one second
|
// count up one second
|
||||||
CountSecond();
|
CountSecond();
|
||||||
}
|
}
|
||||||
|
else if ((ClockCount & 0x7FFF) == 4)
|
||||||
if (State.StatusReg2 & (1<<3))
|
|
||||||
{
|
{
|
||||||
// 32KHz IRQ output
|
// minute-carry flag lasts 4 cycles
|
||||||
SetIRQ(0x10);
|
State.IRQFlag &= ~0x01;
|
||||||
ClearIRQ(0x10);
|
|
||||||
}
|
}
|
||||||
else if ((State.StatusReg2 & 0x03) == 0x01)
|
|
||||||
{
|
|
||||||
// selected frequency steady interrupt
|
|
||||||
|
|
||||||
u32 mask = 0;
|
ProcessIRQ(1);
|
||||||
if (State.Alarm1[2] & (1<<0)) mask |= 0x4000;
|
|
||||||
if (State.Alarm1[2] & (1<<1)) mask |= 0x2000;
|
|
||||||
if (State.Alarm1[2] & (1<<2)) mask |= 0x1000;
|
|
||||||
if (State.Alarm1[2] & (1<<3)) mask |= 0x0800;
|
|
||||||
if (State.Alarm1[2] & (1<<4)) mask |= 0x0400;
|
|
||||||
|
|
||||||
if (mask && ((ClockCount & mask) != mask))
|
|
||||||
SetIRQ(0x10);
|
|
||||||
else
|
|
||||||
ClearIRQ(0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
ScheduleTimer(false);
|
ScheduleTimer(false);
|
||||||
}
|
}
|
||||||
|
@ -647,11 +753,7 @@ void CmdWrite(u8 val)
|
||||||
if (InputPos == 1)
|
if (InputPos == 1)
|
||||||
{
|
{
|
||||||
State.StatusReg2 = val;
|
State.StatusReg2 = val;
|
||||||
if (State.StatusReg2 & 0x4F)
|
ProcessIRQ(2);
|
||||||
Log(LogLevel::Debug, "RTC INTERRUPT ON: %02X, %02X %02X %02X, %02X %02X %02X\n",
|
|
||||||
State.StatusReg2,
|
|
||||||
State.Alarm1[0], State.Alarm1[1], State.Alarm1[2],
|
|
||||||
State.Alarm2[0], State.Alarm2[1], State.Alarm2[2]);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue