C64: Implement more CIA features and CIA/VIA defaults.
This commit is contained in:
parent
32d59e8514
commit
2dd80eb0f4
|
@ -28,7 +28,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
private int Cia1_ReadPortB()
|
||||
{
|
||||
return 0xFF;
|
||||
// Ordinarily these are connected to the userport.
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
private int Cpu_ReadPort()
|
||||
|
@ -111,16 +112,19 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
|
|||
|
||||
private bool SerPort_ReadAtnOut()
|
||||
{
|
||||
// inverted PA3 (input NOT pulled up)
|
||||
return !((Cia1.DdrA & 0x08) != 0 && (Cia1.PrA & 0x08) != 0);
|
||||
}
|
||||
|
||||
private bool SerPort_ReadClockOut()
|
||||
{
|
||||
// inverted PA4 (input NOT pulled up)
|
||||
return !((Cia1.DdrA & 0x10) != 0 && (Cia1.PrA & 0x10) != 0);
|
||||
}
|
||||
|
||||
private bool SerPort_ReadDataOut()
|
||||
{
|
||||
// inverted PA5 (input NOT pulled up)
|
||||
return !((Cia1.DdrA & 0x20) != 0 && (Cia1.PrA & 0x20) != 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,27 +9,27 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
// * A low RES pin is emulated via HardReset().
|
||||
public static class Chip6526
|
||||
{
|
||||
public static Cia Create(C64.CiaType type, Func<int> readIec)
|
||||
public static Cia Create(C64.CiaType type, Func<int> readIec, Func<int> readUserPort)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case C64.CiaType.Ntsc:
|
||||
return new Cia(14318181, 14 * 60, readIec)
|
||||
return new Cia(14318181, 14 * 60, readIec, readUserPort)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.NtscRevA:
|
||||
return new Cia(14318181, 14 * 60, readIec)
|
||||
return new Cia(14318181, 14 * 60, readIec, readUserPort)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
case C64.CiaType.Pal:
|
||||
return new Cia(17734472, 18 * 50, readIec)
|
||||
return new Cia(17734472, 18 * 50, readIec, readUserPort)
|
||||
{
|
||||
DelayedInterrupts = true
|
||||
};
|
||||
case C64.CiaType.PalRevA:
|
||||
return new Cia(17734472, 18 * 50, readIec)
|
||||
return new Cia(17734472, 18 * 50, readIec, readUserPort)
|
||||
{
|
||||
DelayedInterrupts = false
|
||||
};
|
||||
|
|
|
@ -131,10 +131,12 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
private sealed class IecPort : IPort
|
||||
{
|
||||
private readonly Func<int> _readIec;
|
||||
private readonly Func<int> _readUserPort;
|
||||
|
||||
public IecPort(Func<int> readIec)
|
||||
public IecPort(Func<int> readIec, Func<int> readUserPort)
|
||||
{
|
||||
_readIec = readIec;
|
||||
_readUserPort = readUserPort;
|
||||
}
|
||||
|
||||
public int ReadPra(int pra, int ddra, int prb, int ddrb)
|
||||
|
@ -144,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
|
||||
public int ReadPrb(int pra, int ddra, int prb, int ddrb)
|
||||
{
|
||||
return (prb | ~ddrb) & 0xFF;
|
||||
return (prb | ~ddrb) | (~ddrb & _readUserPort());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -252,15 +252,16 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
case 0xE:
|
||||
_hasNewCra = true;
|
||||
_newCra = val;
|
||||
_taCntPhi2 = ((val & 0x20) == 0);
|
||||
_taCntCnt = ((val & 0x20) == 0x20);
|
||||
_taCntPhi2 = (val & 0x20) == 0;
|
||||
_taCntCnt = (val & 0x20) == 0x20;
|
||||
break;
|
||||
case 0xF:
|
||||
_hasNewCrb = true;
|
||||
_newCrb = val;
|
||||
_tbCntPhi2 = ((val & 0x60) == 0);
|
||||
_tbCntTa = ((val & 0x40) == 0x40);
|
||||
_tbCntCnt = ((val & 0x20) == 0x20);
|
||||
_tbCntPhi2 = (val & 0x60) == 0;
|
||||
_tbCntCnt = (val & 0x60) == 0x20;
|
||||
_tbCntTa = (val & 0x60) == 0x40;
|
||||
_tbCntTaCnt = (val & 0x60) == 0x60;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
}
|
||||
|
||||
public Func<bool> ReadFlag = () => true;
|
||||
public Func<bool> ReadCnt = () => true;
|
||||
public Func<bool> ReadSp = () => true;
|
||||
public bool DelayedInterrupts = true;
|
||||
|
||||
private int _pra;
|
||||
|
@ -79,6 +81,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
private bool _flagLatch;
|
||||
private bool _flagInput;
|
||||
private bool _taUnderflow;
|
||||
private bool _lastCnt;
|
||||
private bool _thisCnt;
|
||||
private bool _tbCntTaCnt;
|
||||
|
||||
private readonly IPort _port;
|
||||
private int _todlo;
|
||||
|
@ -98,438 +103,417 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
_port = new JoystickKeyboardPort(joysticks, keyboard);
|
||||
}
|
||||
|
||||
public Cia(int todNum, int todDen, Func<int> readIec) : this(todNum, todDen)
|
||||
public Cia(int todNum, int todDen, Func<int> readIec, Func<int> readUserPort) : this(todNum, todDen)
|
||||
{
|
||||
_port = new IecPort(readIec);
|
||||
_port = new IecPort(readIec, readUserPort);
|
||||
}
|
||||
|
||||
public void HardReset()
|
||||
{
|
||||
_pra = 0;
|
||||
_prb = 0;
|
||||
_ddra = 0;
|
||||
_ddrb = 0;
|
||||
_ta = 0xFFFF;
|
||||
_tb = 0xFFFF;
|
||||
_latcha = 1;
|
||||
_latchb = 1;
|
||||
_tod10Ths = 0;
|
||||
_todSec = 0;
|
||||
_todMin = 0;
|
||||
_todHr = 0;
|
||||
_alm10Ths = 0;
|
||||
_almSec = 0;
|
||||
_almMin = 0;
|
||||
_almHr = 0;
|
||||
_sdr = 0;
|
||||
_icr = 0;
|
||||
_cra = 0;
|
||||
_crb = 0;
|
||||
_intMask = 0;
|
||||
_todLatch = false;
|
||||
_taCntPhi2 = false;
|
||||
_taCntCnt = false;
|
||||
_tbCntPhi2 = false;
|
||||
_tbCntTa = false;
|
||||
_tbCntCnt = false;
|
||||
_taIrqNextCycle = false;
|
||||
_tbIrqNextCycle = false;
|
||||
_taState = TimerState.Stop;
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
public void HardReset()
|
||||
{
|
||||
_pra = 0;
|
||||
_prb = 0;
|
||||
_ddra = 0;
|
||||
_ddrb = 0;
|
||||
_ta = 0xFFFF;
|
||||
_tb = 0xFFFF;
|
||||
_latcha = 1;
|
||||
_latchb = 1;
|
||||
_tod10Ths = 0;
|
||||
_todSec = 0;
|
||||
_todMin = 0;
|
||||
_todHr = 0;
|
||||
_alm10Ths = 0;
|
||||
_almSec = 0;
|
||||
_almMin = 0;
|
||||
_almHr = 0;
|
||||
_sdr = 0;
|
||||
_icr = 0;
|
||||
_cra = 0;
|
||||
_crb = 0;
|
||||
_intMask = 0;
|
||||
_todLatch = false;
|
||||
_taCntPhi2 = false;
|
||||
_taCntCnt = false;
|
||||
_tbCntPhi2 = false;
|
||||
_tbCntTa = false;
|
||||
_tbCntCnt = false;
|
||||
_taIrqNextCycle = false;
|
||||
_tbIrqNextCycle = false;
|
||||
_taState = TimerState.Stop;
|
||||
_tbState = TimerState.Stop;
|
||||
_lastCnt = true;
|
||||
}
|
||||
|
||||
private void CheckIrqs()
|
||||
{
|
||||
if (_taIrqNextCycle)
|
||||
{
|
||||
_taIrqNextCycle = false;
|
||||
TriggerInterrupt(1);
|
||||
}
|
||||
private void CheckIrqs()
|
||||
{
|
||||
if (_taIrqNextCycle)
|
||||
{
|
||||
_taIrqNextCycle = false;
|
||||
TriggerInterrupt(1);
|
||||
}
|
||||
if (_tbIrqNextCycle)
|
||||
{
|
||||
_tbIrqNextCycle = false;
|
||||
TriggerInterrupt(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (_tbIrqNextCycle)
|
||||
{
|
||||
_tbIrqNextCycle = false;
|
||||
TriggerInterrupt(2);
|
||||
}
|
||||
}
|
||||
public void ExecutePhase()
|
||||
{
|
||||
_thisCnt = ReadCnt();
|
||||
_taUnderflow = false;
|
||||
if (DelayedInterrupts)
|
||||
{
|
||||
CheckIrqs();
|
||||
}
|
||||
|
||||
public void ExecutePhase()
|
||||
{
|
||||
_taUnderflow = false;
|
||||
if (DelayedInterrupts)
|
||||
{
|
||||
CheckIrqs();
|
||||
}
|
||||
if (_taPrb6NegativeNextCycle)
|
||||
{
|
||||
_prb &= 0xBF;
|
||||
_taPrb6NegativeNextCycle = false;
|
||||
}
|
||||
if (_tbPrb7NegativeNextCycle)
|
||||
{
|
||||
_prb &= 0x7F;
|
||||
_tbPrb7NegativeNextCycle = false;
|
||||
}
|
||||
|
||||
if (_taPrb6NegativeNextCycle)
|
||||
{
|
||||
_prb &= 0xBF;
|
||||
_taPrb6NegativeNextCycle = false;
|
||||
}
|
||||
|
||||
if (_tbPrb7NegativeNextCycle)
|
||||
{
|
||||
_prb &= 0x7F;
|
||||
_tbPrb7NegativeNextCycle = false;
|
||||
}
|
||||
switch (_taState)
|
||||
{
|
||||
case TimerState.WaitThenCount:
|
||||
_taState = TimerState.Count;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.Stop:
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenStop:
|
||||
_taState = TimerState.Stop;
|
||||
_ta = _latcha;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
_taState = TimerState.Count;
|
||||
_ta = _latcha;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenWaitThenCount:
|
||||
_taState = TimerState.WaitThenCount;
|
||||
if (_ta == 1)
|
||||
{
|
||||
Ta_Interrupt();
|
||||
_taUnderflow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ta = _latcha;
|
||||
}
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.Count:
|
||||
Ta_Count();
|
||||
break;
|
||||
case TimerState.CountThenStop:
|
||||
_taState = TimerState.Stop;
|
||||
Ta_Count();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_taState)
|
||||
{
|
||||
case TimerState.WaitThenCount:
|
||||
_taState = TimerState.Count;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.Stop:
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenStop:
|
||||
_taState = TimerState.Stop;
|
||||
_ta = _latcha;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
_taState = TimerState.Count;
|
||||
_ta = _latcha;
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenWaitThenCount:
|
||||
_taState = TimerState.WaitThenCount;
|
||||
if (_ta == 1)
|
||||
{
|
||||
Ta_Interrupt();
|
||||
_taUnderflow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ta = _latcha;
|
||||
}
|
||||
switch (_tbState)
|
||||
{
|
||||
case TimerState.WaitThenCount:
|
||||
_tbState = TimerState.Count;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.Stop:
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenStop:
|
||||
_tbState = TimerState.Stop;
|
||||
_tb = _latchb;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
_tbState = TimerState.Count;
|
||||
_tb = _latchb;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenWaitThenCount:
|
||||
_tbState = TimerState.WaitThenCount;
|
||||
if (_tb == 1)
|
||||
{
|
||||
Tb_Interrupt();
|
||||
}
|
||||
else
|
||||
{
|
||||
_tb = _latchb;
|
||||
}
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.Count:
|
||||
Tb_Count();
|
||||
break;
|
||||
case TimerState.CountThenStop:
|
||||
_tbState = TimerState.Stop;
|
||||
Tb_Count();
|
||||
break;
|
||||
}
|
||||
|
||||
Ta_Idle();
|
||||
break;
|
||||
case TimerState.Count:
|
||||
Ta_Count();
|
||||
break;
|
||||
case TimerState.CountThenStop:
|
||||
_taState = TimerState.Stop;
|
||||
Ta_Count();
|
||||
break;
|
||||
}
|
||||
CountTod();
|
||||
|
||||
switch (_tbState)
|
||||
{
|
||||
case TimerState.WaitThenCount:
|
||||
_tbState = TimerState.Count;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.Stop:
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenStop:
|
||||
_tbState = TimerState.Stop;
|
||||
_tb = _latchb;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
_tbState = TimerState.Count;
|
||||
_tb = _latchb;
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.LoadThenWaitThenCount:
|
||||
_tbState = TimerState.WaitThenCount;
|
||||
if (_tb == 1)
|
||||
{
|
||||
Tb_Interrupt();
|
||||
}
|
||||
else
|
||||
{
|
||||
_tb = _latchb;
|
||||
}
|
||||
if (!_todLatch)
|
||||
{
|
||||
_latch10Ths = _tod10Ths;
|
||||
_latchSec = _todSec;
|
||||
_latchMin = _todMin;
|
||||
_latchHr = _todHr;
|
||||
}
|
||||
|
||||
Tb_Idle();
|
||||
break;
|
||||
case TimerState.Count:
|
||||
Tb_Count();
|
||||
break;
|
||||
case TimerState.CountThenStop:
|
||||
_tbState = TimerState.Stop;
|
||||
Tb_Count();
|
||||
break;
|
||||
}
|
||||
_flagInput = ReadFlag();
|
||||
if (!_flagInput && _flagLatch)
|
||||
{
|
||||
TriggerInterrupt(16);
|
||||
}
|
||||
_flagLatch = _flagInput;
|
||||
|
||||
CountTod();
|
||||
if (!DelayedInterrupts)
|
||||
{
|
||||
CheckIrqs();
|
||||
}
|
||||
|
||||
if (!_todLatch)
|
||||
{
|
||||
_latch10Ths = _tod10Ths;
|
||||
_latchSec = _todSec;
|
||||
_latchMin = _todMin;
|
||||
_latchHr = _todHr;
|
||||
}
|
||||
if ((_cra & 0x02) != 0)
|
||||
_ddra |= 0x40;
|
||||
if ((_crb & 0x02) != 0)
|
||||
_ddrb |= 0x80;
|
||||
|
||||
_flagInput = ReadFlag();
|
||||
if (!_flagInput && _flagLatch)
|
||||
{
|
||||
TriggerInterrupt(16);
|
||||
}
|
||||
_lastCnt = _thisCnt;
|
||||
}
|
||||
|
||||
_flagLatch = _flagInput;
|
||||
private void Ta_Count()
|
||||
{
|
||||
if (_taCntPhi2 || (_taCntCnt && !_lastCnt && _thisCnt))
|
||||
{
|
||||
if (_ta <= 0 || --_ta == 0)
|
||||
{
|
||||
if (_taState != TimerState.Stop)
|
||||
{
|
||||
Ta_Interrupt();
|
||||
}
|
||||
_taUnderflow = true;
|
||||
}
|
||||
}
|
||||
Ta_Idle();
|
||||
}
|
||||
|
||||
if (!DelayedInterrupts)
|
||||
{
|
||||
CheckIrqs();
|
||||
}
|
||||
private void Ta_Interrupt()
|
||||
{
|
||||
_ta = _latcha;
|
||||
_taIrqNextCycle = true;
|
||||
_icr |= 1;
|
||||
|
||||
if ((_cra & 0x02) != 0)
|
||||
{
|
||||
_ddra |= 0x40;
|
||||
}
|
||||
if ((_cra & 0x08) != 0)
|
||||
{
|
||||
_cra &= 0xFE;
|
||||
_newCra &= 0xFE;
|
||||
_taState = TimerState.LoadThenStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = TimerState.LoadThenCount;
|
||||
}
|
||||
|
||||
if ((_crb & 0x02) != 0)
|
||||
{
|
||||
_ddrb |= 0x80;
|
||||
}
|
||||
}
|
||||
if ((_cra & 0x02) != 0)
|
||||
{
|
||||
if ((_cra & 0x04) != 0)
|
||||
{
|
||||
_taPrb6NegativeNextCycle = true;
|
||||
_prb |= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prb ^= 0x40;
|
||||
}
|
||||
_ddrb |= 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
private void Ta_Count()
|
||||
{
|
||||
if (_taCntPhi2)
|
||||
{
|
||||
if (_ta <= 0 || --_ta == 0)
|
||||
{
|
||||
if (_taState != TimerState.Stop)
|
||||
{
|
||||
Ta_Interrupt();
|
||||
}
|
||||
private void Ta_Idle()
|
||||
{
|
||||
if (_hasNewCra)
|
||||
{
|
||||
switch (_taState)
|
||||
{
|
||||
case TimerState.Stop:
|
||||
case TimerState.LoadThenStop:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
_taState = (_newCra & 0x10) != 0
|
||||
? TimerState.LoadThenWaitThenCount
|
||||
: TimerState.WaitThenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenStop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TimerState.Count:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = (_newCra & 0x10) != 0
|
||||
? TimerState.LoadThenStop
|
||||
: TimerState.CountThenStop;
|
||||
}
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
case TimerState.WaitThenCount:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
if ((_newCra & 0x08) != 0)
|
||||
{
|
||||
_newCra &= 0xFE;
|
||||
_taState = TimerState.Stop;
|
||||
}
|
||||
else if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = TimerState.Stop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_cra = _newCra & 0xEF;
|
||||
_hasNewCra = false;
|
||||
}
|
||||
}
|
||||
|
||||
_taUnderflow = true;
|
||||
}
|
||||
}
|
||||
private void Tb_Count()
|
||||
{
|
||||
if (_tbCntPhi2 || (_tbCntTa && _taUnderflow) || (_tbCntTaCnt && _taUnderflow && _thisCnt) || (_tbCntCnt && !_lastCnt && _thisCnt))
|
||||
{
|
||||
if (_tb <= 0 || --_tb == 0)
|
||||
{
|
||||
if (_tbState != TimerState.Stop)
|
||||
{
|
||||
Tb_Interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
Tb_Idle();
|
||||
}
|
||||
|
||||
Ta_Idle();
|
||||
}
|
||||
private void Tb_Interrupt()
|
||||
{
|
||||
_tb = _latchb;
|
||||
_tbIrqNextCycle = true;
|
||||
_icr |= 2;
|
||||
|
||||
private void Ta_Interrupt()
|
||||
{
|
||||
_ta = _latcha;
|
||||
_taIrqNextCycle = true;
|
||||
_icr |= 1;
|
||||
if ((_crb & 0x08) != 0)
|
||||
{
|
||||
_crb &= 0xFE;
|
||||
_newCrb &= 0xFE;
|
||||
_tbState = TimerState.LoadThenStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = TimerState.LoadThenCount;
|
||||
}
|
||||
|
||||
if ((_cra & 0x08) != 0)
|
||||
{
|
||||
_cra &= 0xFE;
|
||||
_newCra &= 0xFE;
|
||||
_taState = TimerState.LoadThenStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = TimerState.LoadThenCount;
|
||||
}
|
||||
if ((_crb & 0x02) != 0)
|
||||
{
|
||||
if ((_crb & 0x04) != 0)
|
||||
{
|
||||
_tbPrb7NegativeNextCycle = true;
|
||||
_prb |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prb ^= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((_cra & 0x02) != 0)
|
||||
{
|
||||
if ((_cra & 0x04) != 0)
|
||||
{
|
||||
_taPrb6NegativeNextCycle = true;
|
||||
_prb |= 0x40;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prb ^= 0x40;
|
||||
}
|
||||
private void Tb_Idle()
|
||||
{
|
||||
if (_hasNewCrb)
|
||||
{
|
||||
switch (_tbState)
|
||||
{
|
||||
case TimerState.Stop:
|
||||
case TimerState.LoadThenStop:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
_tbState = (_newCrb & 0x10) != 0
|
||||
? TimerState.LoadThenWaitThenCount
|
||||
: TimerState.WaitThenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenStop;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TimerState.Count:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = (_newCrb & 0x10) != 0
|
||||
? TimerState.LoadThenStop
|
||||
: TimerState.CountThenStop;
|
||||
}
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
case TimerState.WaitThenCount:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
if ((_newCrb & 0x08) != 0)
|
||||
{
|
||||
_newCrb &= 0xFE;
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
else if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_crb = _newCrb & 0xEF;
|
||||
_hasNewCrb = false;
|
||||
}
|
||||
}
|
||||
|
||||
_ddrb |= 0x40;
|
||||
}
|
||||
}
|
||||
|
||||
private void Ta_Idle()
|
||||
{
|
||||
if (_hasNewCra)
|
||||
{
|
||||
switch (_taState)
|
||||
{
|
||||
case TimerState.Stop:
|
||||
case TimerState.LoadThenStop:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
_taState = (_newCra & 0x10) != 0
|
||||
? TimerState.LoadThenWaitThenCount
|
||||
: TimerState.WaitThenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenStop;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case TimerState.Count:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = (_newCra & 0x10) != 0
|
||||
? TimerState.LoadThenStop
|
||||
: TimerState.CountThenStop;
|
||||
}
|
||||
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
case TimerState.WaitThenCount:
|
||||
if ((_newCra & 0x01) != 0)
|
||||
{
|
||||
if ((_newCra & 0x08) != 0)
|
||||
{
|
||||
_newCra &= 0xFE;
|
||||
_taState = TimerState.Stop;
|
||||
}
|
||||
else if ((_newCra & 0x10) != 0)
|
||||
{
|
||||
_taState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_taState = TimerState.Stop;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
_cra = _newCra & 0xEF;
|
||||
_hasNewCra = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Tb_Count()
|
||||
{
|
||||
if (_tbCntPhi2 || (_tbCntTa && _taUnderflow))
|
||||
{
|
||||
if (_tb <= 0 || --_tb == 0)
|
||||
{
|
||||
if (_tbState != TimerState.Stop)
|
||||
{
|
||||
Tb_Interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tb_Idle();
|
||||
}
|
||||
|
||||
private void Tb_Interrupt()
|
||||
{
|
||||
_tb = _latchb;
|
||||
_tbIrqNextCycle = true;
|
||||
_icr |= 2;
|
||||
|
||||
if ((_crb & 0x08) != 0)
|
||||
{
|
||||
_crb &= 0xFE;
|
||||
_newCrb &= 0xFE;
|
||||
_tbState = TimerState.LoadThenStop;
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = TimerState.LoadThenCount;
|
||||
}
|
||||
|
||||
if ((_crb & 0x02) != 0)
|
||||
{
|
||||
if ((_crb & 0x04) != 0)
|
||||
{
|
||||
_tbPrb7NegativeNextCycle = true;
|
||||
_prb |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
_prb ^= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Tb_Idle()
|
||||
{
|
||||
if (_hasNewCrb)
|
||||
{
|
||||
switch (_tbState)
|
||||
{
|
||||
case TimerState.Stop:
|
||||
case TimerState.LoadThenStop:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
_tbState = (_newCrb & 0x10) != 0
|
||||
? TimerState.LoadThenWaitThenCount
|
||||
: TimerState.WaitThenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenStop;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case TimerState.Count:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = (_newCrb & 0x10) != 0
|
||||
? TimerState.LoadThenStop
|
||||
: TimerState.CountThenStop;
|
||||
}
|
||||
|
||||
break;
|
||||
case TimerState.LoadThenCount:
|
||||
case TimerState.WaitThenCount:
|
||||
if ((_newCrb & 0x01) != 0)
|
||||
{
|
||||
if ((_newCrb & 0x08) != 0)
|
||||
{
|
||||
_newCrb &= 0xFE;
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
else if ((_newCrb & 0x10) != 0)
|
||||
{
|
||||
_tbState = TimerState.LoadThenWaitThenCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_tbState = TimerState.Stop;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
_crb = _newCrb & 0xEF;
|
||||
_hasNewCrb = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void TriggerInterrupt(int bit)
|
||||
{
|
||||
_icr |= bit;
|
||||
if ((_intMask & bit) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_icr |= 0x80;
|
||||
}
|
||||
private void TriggerInterrupt(int bit)
|
||||
{
|
||||
_icr |= bit;
|
||||
if ((_intMask & bit) == 0) return;
|
||||
_icr |= 0x80;
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
|
@ -578,6 +562,8 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
ser.Sync(nameof(_flagLatch), ref _flagLatch);
|
||||
|
||||
ser.Sync(nameof(_todCounter), ref _todCounter);
|
||||
ser.Sync(nameof(_lastCnt), ref _lastCnt);
|
||||
ser.Sync(nameof(_thisCnt), ref _thisCnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,11 +110,11 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS
|
|||
_prb = 0;
|
||||
_ddra = 0;
|
||||
_ddrb = 0;
|
||||
_t1C = 0;
|
||||
_t1L = 0;
|
||||
_t2C = 0;
|
||||
_t2L = 0;
|
||||
_sr = 0;
|
||||
_t1C = 0xFFFF;
|
||||
_t1L = 0xFFFF;
|
||||
_t2C = 0xFFFF;
|
||||
_t2L = 0xFFFF;
|
||||
_sr = 0xFF;
|
||||
_acr = 0;
|
||||
_pcr = 0;
|
||||
_ifr = 0;
|
||||
|
|
|
@ -163,8 +163,11 @@
|
|||
|
||||
public override bool ReadDeviceData()
|
||||
{
|
||||
// PB1 (input not pulled up)
|
||||
var viaOutputData = (Via0.DdrB & 0x02) != 0 && (Via0.PrB & 0x02) != 0;
|
||||
// inverted from c64, input, not pulled up to PB7/CA1
|
||||
var viaInputAtn = ViaReadAtn();
|
||||
// PB4 (input not pulled up)
|
||||
var viaOutputAtna = (Via0.DdrB & 0x10) != 0 && (Via0.PrB & 0x10) != 0;
|
||||
|
||||
return !(viaOutputAtna ^ viaInputAtn) && !viaOutputData;
|
||||
|
|
Loading…
Reference in New Issue