// // 6522Base.cpp // Clock Signal // // Created by Thomas Harte on 04/09/2017. // Copyright 2017 Thomas Harte. All rights reserved. // #include "../6522.hpp" using namespace MOS::MOS6522; void MOS6522Base::set_control_line_input(Port port, Line line, bool value) { switch(line) { case Line::One: if( value != control_inputs_[port].line_one && value == !!(registers_.peripheral_control & (port ? 0x10 : 0x01)) ) { registers_.interrupt_flags |= port ? InterruptFlag::CB1ActiveEdge : InterruptFlag::CA1ActiveEdge; reevaluate_interrupts(); } control_inputs_[port].line_one = value; break; case Line::Two: // TODO: output modes, but probably elsewhere? if( value != control_inputs_[port].line_two && // i.e. value has changed ... !(registers_.peripheral_control & (port ? 0x80 : 0x08)) && // ... and line is input ... value == !!(registers_.peripheral_control & (port ? 0x40 : 0x04)) // ... and it's either high or low, as required ) { registers_.interrupt_flags |= port ? InterruptFlag::CB2ActiveEdge : InterruptFlag::CA2ActiveEdge; reevaluate_interrupts(); } control_inputs_[port].line_two = value; break; } } void MOS6522Base::do_phase2() { registers_.last_timer[0] = registers_.timer[0]; registers_.last_timer[1] = registers_.timer[1]; if(registers_.timer_needs_reload) { registers_.timer_needs_reload = false; registers_.timer[0] = registers_.timer_latch[0]; } else { registers_.timer[0] --; } registers_.timer[1] --; if(registers_.next_timer[0] >= 0) { registers_.timer[0] = static_cast(registers_.next_timer[0]); registers_.next_timer[0] = -1; } if(registers_.next_timer[1] >= 0) { registers_.timer[1] = static_cast(registers_.next_timer[1]); registers_.next_timer[1] = -1; } } void MOS6522Base::do_phase1() { // IRQ is raised on the half cycle after overflow if((registers_.timer[1] == 0xffff) && !registers_.last_timer[1] && timer_is_running_[1]) { timer_is_running_[1] = false; registers_.interrupt_flags |= InterruptFlag::Timer2; reevaluate_interrupts(); } if((registers_.timer[0] == 0xffff) && !registers_.last_timer[0] && timer_is_running_[0]) { registers_.interrupt_flags |= InterruptFlag::Timer1; reevaluate_interrupts(); if(registers_.auxiliary_control&0x40) registers_.timer_needs_reload = true; else timer_is_running_[0] = false; } } /*! Runs for a specified number of half cycles. */ void MOS6522Base::run_for(const HalfCycles half_cycles) { int number_of_half_cycles = half_cycles.as_int(); if(is_phase2_) { do_phase2(); number_of_half_cycles--; } while(number_of_half_cycles >= 2) { do_phase1(); do_phase2(); number_of_half_cycles -= 2; } if(number_of_half_cycles) { do_phase1(); is_phase2_ = true; } else { is_phase2_ = false; } } /*! Runs for a specified number of cycles. */ void MOS6522Base::run_for(const Cycles cycles) { int number_of_cycles = cycles.as_int(); while(number_of_cycles--) { do_phase1(); do_phase2(); } } /*! @returns @c true if the IRQ line is currently active; @c false otherwise. */ bool MOS6522Base::get_interrupt_line() { uint8_t interrupt_status = registers_.interrupt_flags & registers_.interrupt_enable & 0x7f; return !!interrupt_status; }