diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.Motherboard.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.Motherboard.cs index 7c66ee50d1..d288c463de 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.Motherboard.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.Motherboard.cs @@ -156,7 +156,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 public void Execute() { - _vicBank = (0x3 - (Cia1.EffectivePrA & 0x3)) << 14; + _vicBank = (0x3 - ((Cia1.PrA | ~Cia1.DdrA) & 0x3)) << 14; Vic.ExecutePhase(); Cassette.ExecutePhase(); diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.MotherboardInterface.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.MotherboardInterface.cs index d48708c6b8..95f99362c2 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.MotherboardInterface.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.MotherboardInterface.cs @@ -10,7 +10,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 private int _lastReadVicAddress = 0x3FFF; private int _lastReadVicData = 0xFF; private int _vicBank = 0xC000; - private int _tempCia1Cra; private bool CassPort_ReadDataOutput() { diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.Registers.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.Registers.cs index be694fc3d0..84119b3062 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.Registers.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.Registers.cs @@ -102,10 +102,18 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS { case 0x0: _ifr &= 0xE7; + if (_pcrCb2Control == PCR_CONTROL_HANDSHAKE_OUTPUT || _pcrCb2Control == PCR_CONTROL_PULSE_OUTPUT) + { + _handshakeCb2NextClock = true; + } WriteRegister(addr, val); break; case 0x1: _ifr &= 0xFC; + if (_pcrCa2Control == PCR_CONTROL_HANDSHAKE_OUTPUT || _pcrCa2Control == PCR_CONTROL_PULSE_OUTPUT) + { + _handshakeCa2NextClock = true; + } WriteRegister(addr, val); break; case 0x4: diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.cs index b9cc6f4eb3..5110e3eb94 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/MOS/Via.cs @@ -9,70 +9,118 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS { public sealed partial class Via { - private const int PCR_INT_CONTROL_NEGATIVE_EDGE = 0x00; - private const int PCR_INT_CONTROL_POSITIVE_EDGE = 0x01; - private const int PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE = 0x00; - private const int PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE = 0x02; - private const int PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE = 0x04; - private const int PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE = 0x06; - private const int PCR_CONTROL_HANDSHAKE_OUTPUT = 0x08; - private const int PCR_CONTROL_PULSE_OUTPUT = 0x0A; - private const int PCR_CONTROL_LOW_OUTPUT = 0x0C; - private const int PCR_CONTROL_HIGH_OUTPUT = 0x0E; - private const int ACR_SR_CONTROL_DISABLED = 0x00; - private const int ACR_SR_CONTROL_SHIFT_IN_T2_ONCE = 0x04; - private const int ACR_SR_CONTROL_SHIFT_IN_PHI2 = 0x08; - private const int ACR_SR_CONTROL_SHIFT_IN_CLOCK = 0x0C; - private const int ACR_SR_CONTROL_SHIFT_OUT_T2 = 0x10; - private const int ACR_SR_CONTROL_SHIFT_OUT_T2_ONCE = 0x14; - private const int ACR_SR_CONTROL_SHIFT_OUT_PHI2 = 0x18; - private const int ACR_SR_CONTROL_SHIFT_OUT_CLOCK = 0x1C; - private const int ACR_T2_CONTROL_TIMED = 0x00; - private const int ACR_T2_CONTROL_COUNT_ON_PB6 = 0x20; - private const int ACR_T1_CONTROL_INTERRUPT_ON_LOAD = 0x00; - private const int ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS = 0x40; - private const int ACR_T1_CONTROL_INTERRUPT_ON_LOAD_AND_ONESHOT_PB7 = 0x80; - private const int ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7 = 0xC0; + [SaveState.DoNotSave] private const int PCR_INT_CONTROL_NEGATIVE_EDGE = 0x00; + [SaveState.DoNotSave] private const int PCR_INT_CONTROL_POSITIVE_EDGE = 0x01; + [SaveState.DoNotSave] private const int PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE = 0x00; + [SaveState.DoNotSave] private const int PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE = 0x02; + [SaveState.DoNotSave] private const int PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE = 0x04; + [SaveState.DoNotSave] private const int PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE = 0x06; + [SaveState.DoNotSave] private const int PCR_CONTROL_HANDSHAKE_OUTPUT = 0x08; + [SaveState.DoNotSave] private const int PCR_CONTROL_PULSE_OUTPUT = 0x0A; + [SaveState.DoNotSave] private const int PCR_CONTROL_LOW_OUTPUT = 0x0C; + [SaveState.DoNotSave] private const int PCR_CONTROL_HIGH_OUTPUT = 0x0E; + [SaveState.DoNotSave] private const int ACR_SR_CONTROL_DISABLED = 0x00; + [SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_T2_ONCE = 0x04; + [SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_PHI2 = 0x08; + [SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_IN_CLOCK = 0x0C; + [SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_T2 = 0x10; + [SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_T2_ONCE = 0x14; + [SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_PHI2 = 0x18; + [SaveState.DoNotSave] private const int ACR_SR_CONTROL_SHIFT_OUT_CLOCK = 0x1C; + [SaveState.DoNotSave] private const int ACR_T2_CONTROL_TIMED = 0x00; + [SaveState.DoNotSave] private const int ACR_T2_CONTROL_COUNT_ON_PB6 = 0x20; + [SaveState.DoNotSave] private const int ACR_T1_CONTROL_INTERRUPT_ON_LOAD = 0x00; + [SaveState.DoNotSave] private const int ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS = 0x40; + [SaveState.DoNotSave] private const int ACR_T1_CONTROL_INTERRUPT_ON_LOAD_AND_ONESHOT_PB7 = 0x80; + [SaveState.DoNotSave] private const int ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7 = 0xC0; + [SaveState.SaveWithName("PortOutputA")] private int _pra; + [SaveState.SaveWithName("PortDirectionA")] private int _ddra; + [SaveState.SaveWithName("PortOutputB")] private int _prb; + [SaveState.SaveWithName("PortDirectionB")] private int _ddrb; + [SaveState.SaveWithName("Timer1Counter")] private int _t1C; + [SaveState.SaveWithName("Timer1Latch")] private int _t1L; + [SaveState.SaveWithName("Timer2Counter")] private int _t2C; + [SaveState.SaveWithName("Timer2Latch")] private int _t2L; + [SaveState.SaveWithName("ShiftRegister")] private int _sr; + [SaveState.SaveWithName("AuxiliaryControlRegister")] private int _acr; + [SaveState.SaveWithName("PeripheralControlRegister")] private int _pcr; + [SaveState.SaveWithName("InterruptFlagRegister")] private int _ifr; + [SaveState.SaveWithName("InterruptEnableRegister")] private int _ier; + [SaveState.SaveWithName("Port")] private readonly Port _port; + [SaveState.SaveWithName("PortLatchA")] private int _paLatch; + [SaveState.SaveWithName("PortLatchB")] private int _pbLatch; + [SaveState.SaveWithName("CA1InterruptControl")] private int _pcrCa1IntControl; + [SaveState.SaveWithName("CA2Control")] private int _pcrCa2Control; + [SaveState.SaveWithName("CB1InterruptControl")] private int _pcrCb1IntControl; + [SaveState.SaveWithName("CB2Control")] private int _pcrCb2Control; + [SaveState.SaveWithName("PortLatchEnableA")] private bool _acrPaLatchEnable; + [SaveState.SaveWithName("PortLatchEnableB")] private bool _acrPbLatchEnable; + [SaveState.SaveWithName("ShiftRegisterControl")] private int _acrSrControl; + [SaveState.SaveWithName("Timer1Control")] private int _acrT1Control; + [SaveState.SaveWithName("Timer2Control")] private int _acrT2Control; + [SaveState.SaveWithName("PreviousCA1")] private bool _ca1L; + [SaveState.SaveWithName("PreviousCA2")] private bool _ca2L; + [SaveState.SaveWithName("PreviousCB1")] private bool _cb1L; + [SaveState.SaveWithName("PreviousCB2")] private bool _cb2L; + [SaveState.SaveWithName("PreviousPB6")] + private bool _pb6L; + [SaveState.SaveWithName("ResetCa2NextClock")] + private bool _resetCa2NextClock; + [SaveState.SaveWithName("ResetCb2NextClock")] + private bool _resetCb2NextClock; + + [SaveState.SaveWithName("HandshakeCa2NextClock")] + private bool _handshakeCa2NextClock; + [SaveState.SaveWithName("HandshakeCb2NextClock")] + private bool _handshakeCb2NextClock; + + [SaveState.SaveWithName("ShiftRegisterCounter")] private int _shiftCount; + [SaveState.SaveWithName("CA1")] public bool Ca1; + [SaveState.SaveWithName("CA2")] public bool Ca2; + [SaveState.SaveWithName("CB1")] public bool Cb1; + [SaveState.SaveWithName("CB2")] public bool Cb2; + [SaveState.SaveWithName("PB6")] + private bool _pb6; public Via() { @@ -128,78 +176,157 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.MOS Ca2 = false; Cb1 = false; Cb2 = false; - } - private bool ProcessC2(bool c2, int control) - { - switch (control) - { - case PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE: - return c2; - case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE: - return c2; - case PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE: - return c2; - case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE: - return c2; - case PCR_CONTROL_HANDSHAKE_OUTPUT: - return c2; - case PCR_CONTROL_PULSE_OUTPUT: - return c2; - case PCR_CONTROL_LOW_OUTPUT: - return false; - case PCR_CONTROL_HIGH_OUTPUT: - return true; - } - return c2; + _pb6L = false; + _pb6 = false; + _resetCa2NextClock = false; + _resetCb2NextClock = false; + _handshakeCa2NextClock = false; + _handshakeCb2NextClock = false; } public void ExecutePhase() { + // Process 'pulse' and 'handshake' outputs on CA2 and CB2 + + if (_resetCa2NextClock) + { + Ca2 = true; + _resetCa2NextClock = false; + } + else if (_handshakeCa2NextClock) + { + Ca2 = false; + _resetCa2NextClock = _pcrCa2Control == PCR_CONTROL_PULSE_OUTPUT; + _handshakeCa2NextClock = false; + } + + if (_resetCb2NextClock) + { + Cb2 = true; + _resetCb2NextClock = false; + } + else if (_handshakeCb2NextClock) + { + Cb2 = false; + _resetCb2NextClock = _pcrCb2Control == PCR_CONTROL_PULSE_OUTPUT; + _handshakeCb2NextClock = false; + } + + // Count timers + _t1C--; if (_t1C < 0) { - if (_acrT1Control == ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS || - _acrT1Control == ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7) + switch (_acrT1Control) { - _t1C = _t1L; + case ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS: + _t1C = _t1L; + break; + case ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7: + _t1C = _t1L; + _prb ^= 0x80; + break; + default: + _t1C = 0xFFFF; + break; } _ifr |= 0x40; } - if (_acrT2Control == ACR_T2_CONTROL_TIMED) + switch (_acrT2Control) { - _t2C--; - if (_t2C < 0) - { - _ifr |= 0x20; - _t2C = _t2L; - } + case ACR_T2_CONTROL_TIMED: + _t2C--; + if (_t2C < 0) + { + _ifr |= 0x20; + _t2C = 0xFFFF; + } + break; + case ACR_T2_CONTROL_COUNT_ON_PB6: + _pb6L = _pb6; + _pb6 = (_port.ReadExternalPrb() & 0x40) != 0; + if (!_pb6 && _pb6L) + { + _t2C--; + if (_t2C < 0) + { + _ifr |= 0x20; + _t2C = 0xFFFF; + } + } + break; } - Ca2 = ProcessC2(Ca2, _pcrCa2Control); - Cb2 = ProcessC2(Cb2, _pcrCb2Control); + // Process CA2 - // unknown behavior - - if (_acrT1Control != ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS && - _acrT1Control != ACR_T1_CONTROL_CONTINUOUS_INTERRUPTS_AND_OUTPUT_ON_PB7) + switch (_pcrCa2Control) { - // unknown ACR T1 control + case PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE: + case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE: + if (_ca2L && !Ca2) + _ifr |= 0x01; + break; + case PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE: + case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE: + if (!_ca2L && Ca2) + _ifr |= 0x01; + break; + case PCR_CONTROL_HANDSHAKE_OUTPUT: + if (_ca1L && !Ca1) + { + Ca2 = true; + _ifr |= 0x01; + } + break; + case PCR_CONTROL_PULSE_OUTPUT: + break; + case PCR_CONTROL_LOW_OUTPUT: + Ca2 = false; + break; + case PCR_CONTROL_HIGH_OUTPUT: + Ca2 = true; + break; } - if (_acrT2Control != ACR_T2_CONTROL_TIMED) - { - // unknown ACR T2 control - } + // Process CB2 + switch (_pcrCb2Control) + { + case PCR_CONTROL_INPUT_NEGATIVE_ACTIVE_EDGE: + case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_NEGATIVE_EDGE: + if (_cb2L && !Cb2) + _ifr |= 0x08; + break; + case PCR_CONTROL_INPUT_POSITIVE_ACTIVE_EDGE: + case PCR_CONTROL_INDEPENDENT_INTERRUPT_INPUT_POSITIVE_EDGE: + if (!_cb2L && Cb2) + _ifr |= 0x08; + break; + case PCR_CONTROL_HANDSHAKE_OUTPUT: + if (_cb1L && !Cb1) + { + Cb2 = true; + _ifr |= 0x08; + } + break; + case PCR_CONTROL_PULSE_OUTPUT: + break; + case PCR_CONTROL_LOW_OUTPUT: + Cb2 = false; + break; + case PCR_CONTROL_HIGH_OUTPUT: + Cb2 = true; + break; + } // interrupt generation if ((_pcrCb1IntControl == PCR_INT_CONTROL_POSITIVE_EDGE && Cb1 && !_cb1L) || (_pcrCb1IntControl == PCR_INT_CONTROL_NEGATIVE_EDGE && !Cb1 && _cb1L)) { - _ifr |= 0x01; + _ifr |= 0x10; if (_acrPbLatchEnable) { _pbLatch = _port.ReadExternalPrb();