commodore64: time of day counter implemented in CIA timer

This commit is contained in:
saxxonpike 2012-11-12 19:06:09 +00:00
parent e95efcb91b
commit 2a4a4bbc57
2 changed files with 126 additions and 16 deletions

View File

@ -33,6 +33,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
public int TODHR; // time of day hour
public int TODMIN; // time of day minute
public bool TODPM; // time of day AM/PM
public bool TODREADLATCH; // read latch (internal)
public int TODREADLATCH10; // tod read latch (internal)
public int TODREADLATCHSEC; // tod read latch (internal)
public int TODREADLATCHMIN; // tod read latch (internal)
public int TODREADLATCHHR; // tod read latch (internal)
public int TODSEC; // time of day seconds
private ChipSignals signal;
@ -203,6 +208,8 @@ namespace BizHawk.Emulation.Computers.Commodore64
public CiaRegs regs;
public ChipSignals signal;
public bool thisCNT;
public int todCounter;
public int todFrequency;
public bool[] underflow;
public Func<bool> ReadSerial;
@ -213,15 +220,86 @@ namespace BizHawk.Emulation.Computers.Commodore64
signal = newSignal;
ReadSerial = ReadSerialDummy;
WriteSerial = WriteSerialDummy;
switch (newRegion)
{
case Region.NTSC:
todFrequency = 14318181 / 14 / 10;
break;
case Region.PAL:
todFrequency = 14318181 / 18 / 10;
break;
}
HardReset();
}
private void AdvanceTOD()
{
bool overflow;
int tenths = regs.TOD10;
int seconds = regs.TODSEC;
int minutes = regs.TODMIN;
int hours = regs.TODHR;
bool ampm = regs.TODPM;
todCounter = todFrequency;
tenths = BCDAdd(tenths, 1, out overflow);
if (tenths >= 10)
{
tenths = 0;
seconds = BCDAdd(seconds, 1, out overflow);
if (overflow)
{
seconds = 0;
minutes = BCDAdd(minutes, 1, out overflow);
if (overflow)
{
minutes = 0;
hours = BCDAdd(hours, 1, out overflow);
if (hours > 12)
{
hours = 1;
ampm = !ampm;
}
}
}
}
regs.TOD10 = tenths;
regs.TODSEC = seconds;
regs.TODMIN = minutes;
regs.TODHR = hours;
regs.TODPM = ampm;
}
private int BCDAdd(int i, int j, out bool overflow)
{
int lo;
int hi;
int result;
lo = (i & 0x0F) + (j & 0x0F);
hi = (i & 0x70) + (j & 0x70);
if (lo > 0x09)
{
hi += 0x10;
lo += 0x06;
}
if (hi > 0x50)
{
hi += 0xA0;
}
overflow = hi >= 0x60;
result = (hi & 0x70) + (lo & 0x0F);
return result;
}
public void HardReset()
{
outputBitMask = new byte[] { 0x40, 0x80 };
ports = new DirectionalDataPort[2];
regs = new CiaRegs(signal);
underflow = new bool[2];
todCounter = todFrequency;
}
public byte Peek(int addr)
@ -247,6 +325,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
lastCNT = thisCNT;
thisCNT = ReadSerial();
// process time of day counter
todCounter--;
if (todCounter <= 0)
AdvanceTOD();
for (int i = 0; i < 2; i++)
{
if (regs.START[i])
@ -317,6 +400,26 @@ namespace BizHawk.Emulation.Computers.Commodore64
return ports[0].Direction;
case 0x03:
return ports[1].Direction;
case 0x08:
regs.TODREADLATCH = false;
return (byte)regs.TODREADLATCH10;
case 0x09:
if (!regs.TODREADLATCH)
return regs[addr];
else
return (byte)regs.TODREADLATCHSEC;
case 0x0A:
if (!regs.TODREADLATCH)
return regs[addr];
else
return (byte)regs.TODREADLATCHMIN;
case 0x0B:
regs.TODREADLATCH = true;
regs.TODREADLATCH10 = regs.TOD10;
regs.TODREADLATCHSEC = regs.TODSEC;
regs.TODREADLATCHMIN = regs.TODMIN;
regs.TODREADLATCHHR = regs.TODHR;
return (byte)regs.TODREADLATCHHR;
case 0x0D:
// reading this reg clears it
result = regs[0x0D];
@ -442,7 +545,9 @@ namespace BizHawk.Emulation.Computers.Commodore64
regs.ALARMPM = ((val & 0x80) != 0x00);
}
else
{
regs[addr] = val;
}
break;
case 0x0D:
intMask &= ~val;

View File

@ -43,9 +43,11 @@ namespace BizHawk.Emulation.Computers.Commodore64
public bool[] MxMC = new bool[8]; // sprite multicolor
public int[] MxX = new int[8]; // sprite X coordinate
public bool[] MxXE = new bool[8]; // sprite X expansion
public bool[] MxXEToggle = new bool[8]; // (internal)
public int[] MxXLatch = new int[8]; // (internal)
public int[] MxY = new int[8]; // sprite Y coordinate
public bool[] MxYE = new bool[8]; // sprite Y expansion
public bool[] MYE = new bool[8]; // (internal)
public bool[] MxYEToggle = new bool[8]; // (internal)
public int RASTER; // current raster line
public int RC; // (internal)
public bool RES; // reset bit (does nothing in this version of the VIC)
@ -705,7 +707,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
// sprite Y stretch flipflop
for (int i = 0; i < 8; i++)
if (!regs.MxYE[i])
regs.MYE[i] = true;
regs.MxYEToggle[i] = true;
}
// operations timed to NTSC
@ -965,19 +967,14 @@ namespace BizHawk.Emulation.Computers.Commodore64
// sprite comparison
for (int i = 0; i < 8; i++)
{
if (regs.MYE[i] && regs.MCBASE[i] == 63)
{
regs.MD[i] = false;
regs.MDMA[i] = false;
}
if (regs.MxE[i] == true && regs.MxY[i] == (regs.RASTER & 0xFF) && regs.MDMA[i] == false)
{
regs.MDMA[i] = true;
regs.MCBASE[i] = 0;
if (regs.MxYE[i])
regs.MYE[i] = false;
regs.MxYEToggle[i] = false;
}
regs.MxXEToggle[i] = false;
}
}
@ -1002,7 +999,10 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
regs.MC[i] = regs.MCBASE[i];
if (regs.MDMA[i] && regs.MxY[i] == (regs.RASTER & 0xFF))
{
regs.MD[i] = true;
regs.MxXEToggle[i] = false;
}
}
}
@ -1010,11 +1010,13 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
for (int i = 0; i < 8; i++)
{
if (regs.MYE[i])
if (regs.MxYEToggle[i])
{
if (regs.MD[i])
regs.MCBASE[i] += 3;
if (regs.MxYEToggle[i] && regs.MCBASE[i] == 63)
{
regs.MCBASE[i] += 3;
regs.MD[i] = false;
regs.MDMA[i] = false;
}
}
}
@ -1040,7 +1042,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
{
for (int i = 0; i < 8; i++)
if (regs.MxYE[i])
regs.MYE[i] = !regs.MYE[i];
regs.MxYEToggle[i] = !regs.MxYEToggle[i];
}
private void PerformVCReset()
@ -1293,6 +1295,7 @@ namespace BizHawk.Emulation.Computers.Commodore64
if (regs.MxX[j] == rasterOffsetX)
{
regs.MSRA[j] = true;
regs.MxXLatch[j] = rasterOffsetX;
}
if (regs.MSRA[j])
{
@ -1300,23 +1303,25 @@ namespace BizHawk.Emulation.Computers.Commodore64
if (regs.MxMC[j])
{
spriteBits = (int)((regs.MSR[j] >> 22) & 0x3);
if ((rasterOffsetX & 0x1) != (regs.MxX[j] & 0x1))
if ((rasterOffsetX & 0x1) != (regs.MxXLatch[j] & 0x1))
{
if ((!regs.MxXE[j]) || ((rasterOffsetX & 0x2) != (regs.MxX[j] & 0x2)))
if (!regs.MxXE[j] || regs.MxXEToggle[j])
{
regs.MSR[j] <<= 2;
regs.MSRC[j]--;
}
regs.MxXEToggle[j] = !regs.MxXEToggle[j];
}
}
else
{
spriteBits = (int)((regs.MSR[j] >> 22) & 0x2);
if ((!regs.MxXE[j]) || ((rasterOffsetX & 0x1) != (regs.MxX[j] & 0x1)))
if (!regs.MxXE[j] || regs.MxXEToggle[j])
{
regs.MSR[j] <<= 1;
regs.MSRC[j]--;
}
regs.MxXEToggle[j] = !regs.MxXEToggle[j];
}
// if not transparent, process collisions and color