From 21afc70261d39e38bf7567eb994a902507468990 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 17 Sep 2020 19:00:46 -0400 Subject: [PATCH 1/3] Adds formal data-sheet names. --- .../Implementation/6522Implementation.hpp | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/Components/6522/Implementation/6522Implementation.hpp b/Components/6522/Implementation/6522Implementation.hpp index 54c8f2bbd..34a21d7f2 100644 --- a/Components/6522/Implementation/6522Implementation.hpp +++ b/Components/6522/Implementation/6522Implementation.hpp @@ -34,7 +34,7 @@ template void MOS6522::write(int address, uint8_t value) { address &= 0xf; access(address); switch(address) { - case 0x0: // Write Port B. + case 0x0: // Write Port B. ('ORB') // Store locally and communicate outwards. registers_.output[1] = value; @@ -45,7 +45,7 @@ template void MOS6522::write(int address, uint8_t value) { reevaluate_interrupts(); break; case 0xf: - case 0x1: // Write Port A. + case 0x1: // Write Port A. ('ORA') registers_.output[0] = value; bus_handler_.run_for(time_since_bus_handler_call_.flush()); @@ -59,16 +59,18 @@ template void MOS6522::write(int address, uint8_t value) { reevaluate_interrupts(); break; - case 0x2: // Port B direction. + case 0x2: // Port B direction ('DDRB'). registers_.data_direction[1] = value; break; - case 0x3: // Port A direction. + case 0x3: // Port A direction ('DDRA'). registers_.data_direction[0] = value; break; // Timer 1 - case 0x6: case 0x4: registers_.timer_latch[0] = (registers_.timer_latch[0]&0xff00) | value; break; - case 0x5: case 0x7: + case 0x6: case 0x4: // ('T1L-L' and 'T1C-L') + registers_.timer_latch[0] = (registers_.timer_latch[0]&0xff00) | value; + break; + case 0x5: case 0x7: // ('T1L-H' and 'T1C-H') registers_.timer_latch[0] = (registers_.timer_latch[0]&0x00ff) | uint16_t(value << 8); registers_.interrupt_flags &= ~InterruptFlag::Timer1; if(address == 0x05) { @@ -79,8 +81,10 @@ template void MOS6522::write(int address, uint8_t value) { break; // Timer 2 - case 0x8: registers_.timer_latch[1] = value; break; - case 0x9: + case 0x8: // ('T2C-L') + registers_.timer_latch[1] = value; + break; + case 0x9: // ('T2C-H') registers_.interrupt_flags &= ~InterruptFlag::Timer2; registers_.next_timer[1] = registers_.timer_latch[1] | uint16_t(value << 8); timer_is_running_[1] = true; @@ -88,7 +92,7 @@ template void MOS6522::write(int address, uint8_t value) { break; // Shift - case 0xa: + case 0xa: // ('SR') registers_.shift = value; shift_bits_remaining_ = 8; registers_.interrupt_flags &= ~InterruptFlag::ShiftRegister; @@ -96,11 +100,11 @@ template void MOS6522::write(int address, uint8_t value) { break; // Control - case 0xb: + case 0xb: // Auxiliary control ('ACR'). registers_.auxiliary_control = value; evaluate_cb2_output(); break; - case 0xc: { + case 0xc: { // Peripheral control ('PCR'). // const auto old_peripheral_control = registers_.peripheral_control; registers_.peripheral_control = value; @@ -141,11 +145,11 @@ template void MOS6522::write(int address, uint8_t value) { } break; // Interrupt control - case 0xd: + case 0xd: // Interrupt flag regiser ('IFR'). registers_.interrupt_flags &= ~value; reevaluate_interrupts(); break; - case 0xe: + case 0xe: // Interrupt enable register ('IER'). if(value&0x80) registers_.interrupt_enable |= value; else @@ -159,46 +163,46 @@ template uint8_t MOS6522::read(int address) { address &= 0xf; access(address); switch(address) { - case 0x0: + case 0x0: // Read Port B ('IRB'). registers_.interrupt_flags &= ~(InterruptFlag::CB1ActiveEdge | InterruptFlag::CB2ActiveEdge); reevaluate_interrupts(); return get_port_input(Port::B, registers_.data_direction[1], registers_.output[1]); case 0xf: - case 0x1: + case 0x1: // Read Port A ('IRA'). registers_.interrupt_flags &= ~(InterruptFlag::CA1ActiveEdge | InterruptFlag::CA2ActiveEdge); reevaluate_interrupts(); return get_port_input(Port::A, registers_.data_direction[0], registers_.output[0]); - case 0x2: return registers_.data_direction[1]; - case 0x3: return registers_.data_direction[0]; + case 0x2: return registers_.data_direction[1]; // Port B direction ('DDRB'). + case 0x3: return registers_.data_direction[0]; // Port A direction ('DDRA'). // Timer 1 - case 0x4: + case 0x4: // Timer 1 low-order latches ('T1L-L'). registers_.interrupt_flags &= ~InterruptFlag::Timer1; reevaluate_interrupts(); return registers_.timer[0] & 0x00ff; - case 0x5: return registers_.timer[0] >> 8; - case 0x6: return registers_.timer_latch[0] & 0x00ff; - case 0x7: return registers_.timer_latch[0] >> 8; + case 0x5: return registers_.timer[0] >> 8; // Timer 1 high-order counter ('T1C-H') + case 0x6: return registers_.timer_latch[0] & 0x00ff; // Timer 1 low-order latches ('T1L-L'). + case 0x7: return registers_.timer_latch[0] >> 8; // Timer 1 high-order latches ('T1L-H'). // Timer 2 - case 0x8: + case 0x8: // Timer 2 low-order counter ('T2C-L'). registers_.interrupt_flags &= ~InterruptFlag::Timer2; reevaluate_interrupts(); return registers_.timer[1] & 0x00ff; - case 0x9: return registers_.timer[1] >> 8; + case 0x9: return registers_.timer[1] >> 8; // Timer 2 high-order counter ('T2C-H'). - case 0xa: + case 0xa: // Shift register ('SR'). shift_bits_remaining_ = 8; registers_.interrupt_flags &= ~InterruptFlag::ShiftRegister; reevaluate_interrupts(); return registers_.shift; - case 0xb: return registers_.auxiliary_control; - case 0xc: return registers_.peripheral_control; + case 0xb: return registers_.auxiliary_control; // Auxiliary control ('ACR'). + case 0xc: return registers_.peripheral_control; // Peripheral control ('PCR'). - case 0xd: return registers_.interrupt_flags | (get_interrupt_line() ? 0x80 : 0x00); - case 0xe: return registers_.interrupt_enable | 0x80; + case 0xd: return registers_.interrupt_flags | (get_interrupt_line() ? 0x80 : 0x00); // Interrupt flag register ('IFR'). + case 0xe: return registers_.interrupt_enable | 0x80; // Interrupt enable register ('IER'). } return 0xff; From 18790a90ae7e9b7b6324c2ec931748ad832126cc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 17 Sep 2020 21:09:32 -0400 Subject: [PATCH 2/3] Ensures timer 2 doesn't use timed behaviour when in pulse mode. --- Components/6522/Implementation/6522Implementation.hpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Components/6522/Implementation/6522Implementation.hpp b/Components/6522/Implementation/6522Implementation.hpp index 34a21d7f2..df3e22042 100644 --- a/Components/6522/Implementation/6522Implementation.hpp +++ b/Components/6522/Implementation/6522Implementation.hpp @@ -8,6 +8,10 @@ #include "../../../Outputs/Log.hpp" +// As-yet unimplemented (incomplete list): +// +// PB6 count-down mode for timer 2. + namespace MOS { namespace MOS6522 { @@ -280,10 +284,13 @@ template void MOS6522::do_phase2() { registers_.timer_needs_reload = false; registers_.timer[0] = registers_.timer_latch[0]; } else { - registers_.timer[0] --; + -- registers_.timer[0]; } - registers_.timer[1] --; + // Count down timer 2 if it is in timed interrupt mode (i.e. auxiliary control bit 5 is clear). + // TODO: implement count down on PB6 if this bit isn't set. + registers_.timer[1] -= 1 ^ ((registers_.auxiliary_control >> 5)&1); + if(registers_.next_timer[0] >= 0) { registers_.timer[0] = uint16_t(registers_.next_timer[0]); registers_.next_timer[0] = -1; From e807a462a194d1f2dffa97f1c94bfd484d1ad0c4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 17 Sep 2020 21:31:29 -0400 Subject: [PATCH 3/3] My new reading is that only a write to the counter should affect the interrupt flag. --- .../6522/Implementation/6522Implementation.hpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Components/6522/Implementation/6522Implementation.hpp b/Components/6522/Implementation/6522Implementation.hpp index df3e22042..533b8d1be 100644 --- a/Components/6522/Implementation/6522Implementation.hpp +++ b/Components/6522/Implementation/6522Implementation.hpp @@ -74,13 +74,19 @@ template void MOS6522::write(int address, uint8_t value) { case 0x6: case 0x4: // ('T1L-L' and 'T1C-L') registers_.timer_latch[0] = (registers_.timer_latch[0]&0xff00) | value; break; - case 0x5: case 0x7: // ('T1L-H' and 'T1C-H') + case 0x7: // Timer 1 latch, high ('T1L-H'). registers_.timer_latch[0] = (registers_.timer_latch[0]&0x00ff) | uint16_t(value << 8); + break; + case 0x5: // Timer 1 counter, high ('T1C-H'). + // Fill latch. + registers_.timer_latch[0] = (registers_.timer_latch[0]&0x00ff) | uint16_t(value << 8); + + // Restart timer. + registers_.next_timer[0] = registers_.timer_latch[0]; + timer_is_running_[0] = true; + + // Clear existing interrupt flag. registers_.interrupt_flags &= ~InterruptFlag::Timer1; - if(address == 0x05) { - registers_.next_timer[0] = registers_.timer_latch[0]; - timer_is_running_[0] = true; - } reevaluate_interrupts(); break;