From 2eda0b3c868cf862af1aa8b14f30ea6056db01d1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 27 Oct 2016 21:06:31 -0400 Subject: [PATCH 1/2] Attempted to simplify the logic behind the most common 6522 usage. --- Components/6522/6522.hpp | 89 +++++++++++++++++++++++----------------- Machines/Oric/Video.cpp | 3 +- 2 files changed, 54 insertions(+), 38 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 4ec1fde0a..42aea3a7e 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -242,46 +242,61 @@ template class MOS6522 { */ inline void run_for_half_cycles(unsigned int number_of_cycles) { - while(number_of_cycles--) +#define 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] --; + + // IRQ is raised on the half cycle after overflow +#define phase1() \ + 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;\ + } + + if(_is_phase2) { - if(_is_phase2) - { - _registers.last_timer[0] = _registers.timer[0]; - _registers.last_timer[1] = _registers.timer[1]; + phase2(); + number_of_cycles--; + } - if(_registers.timer_needs_reload) - { - _registers.timer_needs_reload = false; - _registers.timer[0] = _registers.timer_latch[0]; - } - else - _registers.timer[0] --; + while(number_of_cycles > 2) + { + phase1(); + phase2(); + number_of_cycles -= 2; + } - _registers.timer[1] --; - } - else - { - // 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; - } - } - - _is_phase2 ^= true; + if(number_of_cycles) + { + phase1(); + _is_phase2 = true; + } + else + { + _is_phase2 = false; } } diff --git a/Machines/Oric/Video.cpp b/Machines/Oric/Video.cpp index ec31bd1a6..620b3da7c 100644 --- a/Machines/Oric/Video.cpp +++ b/Machines/Oric/Video.cpp @@ -51,7 +51,7 @@ std::shared_ptr VideoOutput::get_crt() void VideoOutput::run_for_cycles(int number_of_cycles) { - // Vertical: 0–39: pixels; otherwise blank; 48–53 sync + // Vertical: 0–39: pixels; otherwise blank; 48–53 sync, 54–56 colour burst // Horizontal: 0–223: pixels; otherwise blank; 256–259 sync while(number_of_cycles--) @@ -78,6 +78,7 @@ void VideoOutput::run_for_cycles(int number_of_cycles) } } + State new_state = Blank; if( (h_counter >= 48 && h_counter <= 53) || From 4fab794747eecb718ee9ea8c3dd5ca0a7bb0ecd3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 27 Oct 2016 21:13:25 -0400 Subject: [PATCH 2/2] Added a direct-to-two-cycles emulation path for 6522 owners. --- Components/6522/6522.hpp | 45 +++++++++++++++++++++-------- Machines/Commodore/1540/C1540.cpp | 4 +-- Machines/Commodore/Vic-20/Vic20.cpp | 8 ++--- Machines/Oric/Oric.cpp | 2 +- 4 files changed, 40 insertions(+), 19 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 42aea3a7e..1175a6488 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -230,18 +230,6 @@ template class MOS6522 { } } - /*! - Runs for a specified number of half cycles. - - Although the original chip accepts only a phase-2 input, timer reloads are specified as occuring - 1.5 cycles after the timer hits zero. It is therefore necessary to emulate at half-cycle precision. - - The first emulated half-cycle will be the period between the trailing edge of a phase-2 input and the - next rising edge. So it should align with a full system's phase-1. The next emulated half-cycle will be - that which occurs during phase-2. - */ - inline void run_for_half_cycles(unsigned int number_of_cycles) - { #define phase2() \ _registers.last_timer[0] = _registers.timer[0];\ _registers.last_timer[1] = _registers.timer[1];\ @@ -276,6 +264,21 @@ template class MOS6522 { _timer_is_running[0] = false;\ } + /*! + Runs for a specified number of half cycles. + + Although the original chip accepts only a phase-2 input, timer reloads are specified as occuring + 1.5 cycles after the timer hits zero. It therefore may be necessary to emulate at half-cycle precision. + + The first emulated half-cycle will be the period between the trailing edge of a phase-2 input and the + next rising edge. So it should align with a full system's phase-1. The next emulated half-cycle will be + that which occurs during phase-2. + + Callers should decide whether they are going to use @c run_for_half_cycles or @c run_for_cycles, and not + intermingle usage. + */ + inline void run_for_half_cycles(unsigned int number_of_cycles) + { if(_is_phase2) { phase2(); @@ -300,6 +303,24 @@ template class MOS6522 { } } + /*! + Runs for a specified number of cycles. + + Callers should decide whether they are going to use @c run_for_half_cycles or @c run_for_cycles, and not + intermingle usage. + */ + inline void run_for_cycles(unsigned int number_of_cycles) + { + while(number_of_cycles--) + { + phase1(); + phase2(); + } + } + +#undef phase1 +#undef phase2 + /*! @returns @c true if the IRQ line is currently active; @c false otherwise. */ inline bool get_interrupt_line() { diff --git a/Machines/Commodore/1540/C1540.cpp b/Machines/Commodore/1540/C1540.cpp index e5324ba93..7aedc15a4 100644 --- a/Machines/Commodore/1540/C1540.cpp +++ b/Machines/Commodore/1540/C1540.cpp @@ -91,8 +91,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin _driveVIA.set_register(address, *value); } - _serialPortVIA->run_for_half_cycles(2); - _driveVIA.run_for_half_cycles(2); + _serialPortVIA->run_for_cycles(1); + _driveVIA.run_for_cycles(1); return 1; } diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index e72ff238f..ea221d001 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -139,8 +139,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { while(!_userPortVIA->get_interrupt_line() && !_keyboardVIA->get_interrupt_line() && !_tape.get_tape()->is_at_end()) { - _userPortVIA->run_for_half_cycles(2); - _keyboardVIA->run_for_half_cycles(2); + _userPortVIA->run_for_cycles(1); + _keyboardVIA->run_for_cycles(1); _tape.run_for_cycles(1); } } @@ -157,8 +157,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } } - _userPortVIA->run_for_half_cycles(2); - _keyboardVIA->run_for_half_cycles(2); + _userPortVIA->run_for_cycles(1); + _keyboardVIA->run_for_cycles(1); if(_typer && operation == CPU6502::BusOperation::ReadOpcode && address == 0xEB1E) { if(!_typer->type_next_character()) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index a69c1596e..67e84e892 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -61,7 +61,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } } - _via.run_for_half_cycles(2); + _via.run_for_cycles(1); _via.tape->run_for_cycles(1); _cycles_since_video_update++; return 1;