From 76a64d13a0bf0f09086ce437268751b2fc21a629 Mon Sep 17 00:00:00 2001 From: Thomas Harte <thomas.harte@gmail.com> Date: Tue, 13 Jun 2017 21:25:55 -0400 Subject: [PATCH] Made a first attempt at ZX81 emulation. --- Machines/ZX8081/ZX8081.cpp | 56 +++++++++++++++++++++++--------------- Machines/ZX8081/ZX8081.hpp | 2 ++ 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index ace532409..a1ab3ecd5 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -20,6 +20,7 @@ namespace { Machine::Machine() : vsync_(false), hsync_(false), + nmi_is_enabled_(false), tape_player_(ZX8081ClockRate) { set_clock_rate(ZX8081ClockRate); tape_player_.set_motor_control(true); @@ -27,30 +28,34 @@ Machine::Machine() : } int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { - const int vsync_length = 16; + int wait_cycles = 0; int previous_counter = horizontal_counter_; horizontal_counter_ += cycle.length; - if(is_zx81_) { - } else { - const int vsync_start_cycle = 13; - const int vsync_end_cycle = vsync_start_cycle + vsync_length; - - if(previous_counter < vsync_start_cycle && horizontal_counter_ >= vsync_start_cycle) { - video_->run_for_cycles(vsync_start_cycle - previous_counter); - set_hsync(true); - video_->run_for_cycles(horizontal_counter_ - vsync_start_cycle); - } else if(previous_counter < vsync_end_cycle && horizontal_counter_ >= vsync_end_cycle) { - video_->run_for_cycles(vsync_end_cycle - previous_counter); - set_hsync(false); - video_->run_for_cycles(horizontal_counter_ - vsync_end_cycle); - } else { - video_->run_for_cycles(cycle.length); + if(previous_counter < vsync_start_cycle_ && horizontal_counter_ >= vsync_start_cycle_) { + video_->run_for_cycles(vsync_start_cycle_ - previous_counter); + set_hsync(true); + if(nmi_is_enabled_) { + set_non_maskable_interrupt_line(true); + if(get_halt_line()) { + wait_cycles = vsync_start_cycle_ - horizontal_counter_; + } } + video_->run_for_cycles(horizontal_counter_ - vsync_start_cycle_ + wait_cycles); + } else if(previous_counter < vsync_end_cycle_ && horizontal_counter_ >= vsync_end_cycle_) { + video_->run_for_cycles(vsync_end_cycle_ - previous_counter); + set_hsync(false); + if(nmi_is_enabled_) set_non_maskable_interrupt_line(false); + video_->run_for_cycles(horizontal_counter_ - vsync_end_cycle_); + } else { + video_->run_for_cycles(cycle.length); } -// tape_player_.run_for_cycles(cycle.length); + horizontal_counter_ += wait_cycles; + if(is_zx81_) horizontal_counter_ %= 207; + +// tape_player_.run_for_cycles(cycle.length + wait_cycles); uint16_t refresh = 0; uint16_t address = cycle.address ? *cycle.address : 0; @@ -58,6 +63,12 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { case CPU::Z80::BusOperation::Output: set_vsync(false); line_counter_ = 0; + + switch(address & 7) { + default: break; + case 0x5: nmi_is_enabled_ = false; break; + case 0x6: nmi_is_enabled_ = is_zx81_; break; + } break; case CPU::Z80::BusOperation::Input: { @@ -77,15 +88,12 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { } break; case CPU::Z80::BusOperation::Interrupt: -// set_hsync(true); line_counter_ = (line_counter_ + 1) & 7; *cycle.value = 0xff; - horizontal_counter_ = 0; // TODO: more than this? + horizontal_counter_ = 0; break; case CPU::Z80::BusOperation::ReadOpcode: -// set_hsync(false); - // The ZX80 and 81 signal an interrupt while refresh is active and bit 6 of the refresh // address is low. The Z80 signals a refresh, providing the refresh address during the // final two cycles of an opcode fetch. Therefore communicate a transient signalling @@ -137,7 +145,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::MachineCycle &cycle) { default: break; } - return 0; + return wait_cycles; } void Machine::flush() { @@ -170,10 +178,14 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) { rom_ = zx81_rom_; tape_trap_address_ = 0x37c; tape_return_address_ = 0x380; + vsync_start_cycle_ = 13; + vsync_end_cycle_ = 33; } else { rom_ = zx80_rom_; tape_trap_address_ = 0x220; tape_return_address_ = 0x248; + vsync_start_cycle_ = 16; + vsync_end_cycle_ = 32; } rom_mask_ = (uint16_t)(rom_.size() - 1); diff --git a/Machines/ZX8081/ZX8081.hpp b/Machines/ZX8081/ZX8081.hpp index c921fd79a..5778b85fe 100644 --- a/Machines/ZX8081/ZX8081.hpp +++ b/Machines/ZX8081/ZX8081.hpp @@ -87,6 +87,8 @@ class Machine: int horizontal_counter_; bool is_zx81_; + bool nmi_is_enabled_; + int vsync_start_cycle_, vsync_end_cycle_; }; }