Version 1.0a - fix for TOD clock not running (fixes some utilities). Slight VIC refactor for additional speed (1-2 frames).

This commit is contained in:
Dave Bernazzani 2025-05-10 10:16:33 -04:00
parent 12cad5f3fa
commit 26d89638b1
5 changed files with 108 additions and 34 deletions

Binary file not shown.

View File

@ -9,7 +9,7 @@ include $(DEVKITARM)/ds_rules
export TARGET := GimliDS export TARGET := GimliDS
export TOPDIR := $(CURDIR) export TOPDIR := $(CURDIR)
export VERSION := 1.0 export VERSION := 1.0a
ICON := -b $(CURDIR)/C64_icon.bmp "GimliDS $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/GimliDS" ICON := -b $(CURDIR)/C64_icon.bmp "GimliDS $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/GimliDS"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -86,13 +86,15 @@ void MOS6526::Reset(void)
ta = tb = 0xffff; ta = tb = 0xffff;
latcha = latchb = 1; latcha = latchb = 1;
tod_10ths = tod_sec = tod_min = tod_hr = 0; tod_10ths = tod_sec = tod_min = 0; tod_hr = 1;
alm_10ths = alm_sec = alm_min = alm_hr = 0; alm_10ths = alm_sec = alm_min = alm_hr = 0;
sdr = icr = cra = crb = int_mask = 0; sdr = icr = cra = crb = int_mask = 0;
tod_halt = ta_cnt_phi2 = tb_cnt_phi2 = tb_cnt_ta = false; ta_cnt_phi2 = tb_cnt_phi2 = tb_cnt_ta = false;
tod_divider = 0; tod_divider = 0;
tod_alarm = false;
tod_halt = true;
} }
void MOS6526_1::Reset(void) void MOS6526_1::Reset(void)
@ -231,12 +233,13 @@ uint8 MOS6526_1::ReadRegister(uint16 adr)
case 0x05: return ta >> 8; case 0x05: return ta >> 8;
case 0x06: return tb; case 0x06: return tb;
case 0x07: return tb >> 8; case 0x07: return tb >> 8;
case 0x08: tod_halt = false; return tod_10ths; case 0x08: return tod_10ths; // TODO: unlatch
case 0x09: return tod_sec; case 0x09: return tod_sec;
case 0x0a: return tod_min; case 0x0a: return tod_min;
case 0x0b: tod_halt = true; return tod_hr; case 0x0b: return tod_hr; // TODO: latch
case 0x0c: return sdr; case 0x0c: return sdr;
case 0x0d: { case 0x0d:
{
uint8 ret = icr; // Read and clear ICR uint8 ret = icr; // Read and clear ICR
icr = 0; icr = 0;
the_cpu->ClearCIAIRQ(); // Clear IRQ the_cpu->ClearCIAIRQ(); // Clear IRQ
@ -265,12 +268,13 @@ uint8 MOS6526_2::ReadRegister(uint16 adr)
case 0x05: return ta >> 8; case 0x05: return ta >> 8;
case 0x06: return tb; case 0x06: return tb;
case 0x07: return tb >> 8; case 0x07: return tb >> 8;
case 0x08: tod_halt = false; return tod_10ths; case 0x08: return tod_10ths; // TODO: unlatch
case 0x09: return tod_sec; case 0x09: return tod_sec;
case 0x0a: return tod_min; case 0x0a: return tod_min;
case 0x0b: tod_halt = true; return tod_hr; case 0x0b: return tod_hr; // TODO: latch
case 0x0c: return sdr; case 0x0c: return sdr;
case 0x0d: { case 0x0d:
{
uint8 ret = icr; // Read and clear ICR uint8 ret = icr; // Read and clear ICR
icr = 0; icr = 0;
the_cpu->ClearNMI(); // Clear NMI the_cpu->ClearNMI(); // Clear NMI
@ -324,28 +328,49 @@ void MOS6526_1::WriteRegister(uint16 adr, uint8 byte)
break; break;
case 0x8: case 0x8:
byte &= 0x0f;
if (crb & 0x80) if (crb & 0x80)
alm_10ths = byte & 0x0f; {
if (alm_10ths != byte)
{
check_tod_alarm();
}
alm_10ths = byte;
}
else else
tod_10ths = byte & 0x0f; {
if (tod_10ths != byte)
{
check_tod_alarm();
}
tod_10ths = byte;
tod_halt = false;
}
check_tod_alarm();
break; break;
case 0x9: case 0x9:
if (crb & 0x80) if (crb & 0x80)
alm_sec = byte & 0x7f; alm_sec = byte & 0x7f;
else else
tod_sec = byte & 0x7f; tod_sec = byte & 0x7f;
check_tod_alarm();
break; break;
case 0xa: case 0xa:
if (crb & 0x80) if (crb & 0x80)
alm_min = byte & 0x7f; alm_min = byte & 0x7f;
else else
tod_min = byte & 0x7f; tod_min = byte & 0x7f;
check_tod_alarm();
break; break;
case 0xb: case 0xb:
if (crb & 0x80) if (crb & 0x80)
alm_hr = byte & 0x9f; alm_hr = byte & 0x9f;
else else
{
tod_hr = byte & 0x9f; tod_hr = byte & 0x9f;
tod_halt = true;
}
check_tod_alarm();
break; break;
case 0xc: case 0xc:
@ -357,8 +382,8 @@ void MOS6526_1::WriteRegister(uint16 adr, uint8 byte)
if (ThePrefs.CIAIRQHack) // Hack for addressing modes that read from the address if (ThePrefs.CIAIRQHack) // Hack for addressing modes that read from the address
icr = 0; icr = 0;
if (byte & 0x80) { if (byte & 0x80) {
int_mask |= byte & 0x7f; int_mask |= byte & 0x1f;
if (icr & int_mask & 0x1f) { // Trigger IRQ if pending if (icr & int_mask) { // Trigger IRQ if pending
icr |= 0x80; icr |= 0x80;
the_cpu->TriggerCIAIRQ(); the_cpu->TriggerCIAIRQ();
} }
@ -393,7 +418,8 @@ inline void MOS6526_2::write_pa(uint8_t byte)
| ((byte << 2) & 0x40) // CLK | ((byte << 2) & 0x40) // CLK
| ((byte << 1) & 0x10); // ATN | ((byte << 1) & 0x10); // ATN
if ((IECLines ^ old_lines) & 0x10) { // ATN changed if ((IECLines ^ old_lines) & 0x10) // ATN changed
{
the_cpu_1541->NewATNState(); the_cpu_1541->NewATNState();
if (old_lines & 0x10) // ATN 1->0 if (old_lines & 0x10) // ATN 1->0
the_cpu_1541->TriggerIECInterrupt(); the_cpu_1541->TriggerIECInterrupt();
@ -438,28 +464,48 @@ void MOS6526_2::WriteRegister(uint16 adr, uint8 byte)
break; break;
case 0x8: case 0x8:
byte &= 0x0f;
if (crb & 0x80) if (crb & 0x80)
alm_10ths = byte & 0x0f; {
if (alm_10ths != byte)
{
check_tod_alarm();
}
alm_10ths = byte;
}
else else
tod_10ths = byte & 0x0f; {
break; if (tod_10ths != byte)
{
check_tod_alarm();
}
tod_10ths = byte;
tod_halt = false;
}
check_tod_alarm();
case 0x9: case 0x9:
if (crb & 0x80) if (crb & 0x80)
alm_sec = byte & 0x7f; alm_sec = byte & 0x7f;
else else
tod_sec = byte & 0x7f; tod_sec = byte & 0x7f;
check_tod_alarm();
break; break;
case 0xa: case 0xa:
if (crb & 0x80) if (crb & 0x80)
alm_min = byte & 0x7f; alm_min = byte & 0x7f;
else else
tod_min = byte & 0x7f; tod_min = byte & 0x7f;
check_tod_alarm();
break; break;
case 0xb: case 0xb:
if (crb & 0x80) if (crb & 0x80)
alm_hr = byte & 0x9f; alm_hr = byte & 0x9f;
else else
{
tod_hr = byte & 0x9f; tod_hr = byte & 0x9f;
tod_halt = true;
}
check_tod_alarm();
break; break;
case 0xc: case 0xc:
@ -506,10 +552,13 @@ void MOS6526::CountTOD(void)
{ {
uint8 lo, hi; uint8 lo, hi;
if (tod_halt) return; // Clock halted - skip clocking
// Decrement frequency divider // Decrement frequency divider
if (tod_divider) if (tod_divider)
tod_divider--; tod_divider--;
else { else
{
// Reload divider according to 50/60 Hz flag // Reload divider according to 50/60 Hz flag
if (cra & 0x80) if (cra & 0x80)
@ -519,27 +568,32 @@ void MOS6526::CountTOD(void)
// 1/10 seconds // 1/10 seconds
tod_10ths++; tod_10ths++;
if (tod_10ths > 9) { if (tod_10ths > 9)
{
tod_10ths = 0; tod_10ths = 0;
// Seconds // Seconds
lo = (tod_sec & 0x0f) + 1; lo = (tod_sec & 0x0f) + 1;
hi = tod_sec >> 4; hi = tod_sec >> 4;
if (lo > 9) { if (lo > 9)
{
lo = 0; lo = 0;
hi++; hi++;
} }
if (hi > 5) { if (hi > 5)
{
tod_sec = 0; tod_sec = 0;
// Minutes // Minutes
lo = (tod_min & 0x0f) + 1; lo = (tod_min & 0x0f) + 1;
hi = tod_min >> 4; hi = tod_min >> 4;
if (lo > 9) { if (lo > 9)
{
lo = 0; lo = 0;
hi++; hi++;
} }
if (hi > 5) { if (hi > 5)
{
tod_min = 0; tod_min = 0;
// Hours // Hours
@ -559,10 +613,7 @@ void MOS6526::CountTOD(void)
tod_sec = (hi << 4) | lo; tod_sec = (hi << 4) | lo;
} }
// Alarm time reached? Trigger interrupt if enabled check_tod_alarm();
if (tod_10ths == alm_10ths && tod_sec == alm_sec &&
tod_min == alm_min && tod_hr == alm_hr)
TriggerInterrupt(4);
} }
} }
@ -574,7 +625,8 @@ void MOS6526::CountTOD(void)
void MOS6526_1::TriggerInterrupt(int bit) void MOS6526_1::TriggerInterrupt(int bit)
{ {
icr |= bit; icr |= bit;
if (int_mask & bit) { if (int_mask & bit)
{
icr |= 0x80; icr |= 0x80;
the_cpu->TriggerCIAIRQ(); the_cpu->TriggerCIAIRQ();
} }
@ -588,7 +640,8 @@ void MOS6526_1::TriggerInterrupt(int bit)
void MOS6526_2::TriggerInterrupt(int bit) void MOS6526_2::TriggerInterrupt(int bit)
{ {
icr |= bit; icr |= bit;
if (int_mask & bit) { if (int_mask & bit)
{
icr |= 0x80; icr |= 0x80;
the_cpu->TriggerNMI(); the_cpu->TriggerNMI();
} }

View File

@ -77,6 +77,9 @@ protected:
ta_cnt_phi2, // Flag: Timer A is counting Phi 2 ta_cnt_phi2, // Flag: Timer A is counting Phi 2
tb_cnt_phi2, // Flag: Timer B is counting Phi 2 tb_cnt_phi2, // Flag: Timer B is counting Phi 2
tb_cnt_ta; // Flag: Timer B is counting underflows of Timer A tb_cnt_ta; // Flag: Timer B is counting underflows of Timer A
bool tod_alarm; // Flag: TOD in alarm state
void check_tod_alarm();
}; };
@ -151,6 +154,24 @@ struct MOS6526State {
uint8 int_mask; // Enabled interrupts uint8 int_mask; // Enabled interrupts
}; };
/*
* Check for TOD alarm
*/
inline void MOS6526::check_tod_alarm()
{
bool alarm_match = (tod_10ths == alm_10ths && tod_sec == alm_sec &&
tod_min == alm_min && tod_hr == alm_hr);
// Raise interrupt on positive edge of alarm match
if (alarm_match && !tod_alarm)
{
TriggerInterrupt(4);
}
tod_alarm = alarm_match;
}
/* /*
* Emulate CIA for one cycle/raster line * Emulate CIA for one cycle/raster line