From 46fff8e8a233b642630307dbbd6184bd532c1927 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 6 Jul 2017 22:48:48 -0400 Subject: [PATCH 1/5] Ensured bit 8 is uniquely from the latched video byte, not an OR of that with the refresh address. --- Machines/ZX8081/ZX8081.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index cf3c24ed0..39bfdd862 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -113,7 +113,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { set_interrupt_line(false); } if(latched_video_byte_) { - size_t char_address = (size_t)((address & 0xff00) | ((latched_video_byte_ & 0x3f) << 3) | line_counter_); + size_t char_address = (size_t)((address & 0xfe00) | ((latched_video_byte_ & 0x3f) << 3) | line_counter_); uint8_t mask = (latched_video_byte_ & 0x80) ? 0x00 : 0xff; if(char_address < ram_base_) { latched_video_byte_ = rom_[char_address & rom_mask_] ^ mask; @@ -156,7 +156,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { uint8_t value = ram_[address & ram_mask_]; // If this is an M1 cycle reading from above the 32kb mark and HALT is not - // currently active, perform a video output and return a NOP. Otherwise, + // currently active, latch for video output and return a NOP. Otherwise, // just return the value as read. if(is_opcode_read && address&0x8000 && !(value & 0x40) && !get_halt_line()) { latched_video_byte_ = value; From d6b87053bf645caeb4eba22ae9b99d2182bfd1c2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 8 Jul 2017 20:40:19 -0400 Subject: [PATCH 2/5] Introduced an explicit record of whether a video byte is latched. It's definitely incorrect to treat the latching of 0 as equivalent to no latching, as the byte that will eventually become video is not strongly implied. --- Machines/ZX8081/ZX8081.cpp | 8 +++++--- Machines/ZX8081/ZX8081.hpp | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index b8bbae15a..f9edf8815 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -25,7 +25,8 @@ Machine::Machine() : use_fast_tape_hack_(false), tape_advance_delay_(0), tape_is_automatically_playing_(false), - tape_is_playing_(false) { + tape_is_playing_(false), + has_latched_video_byte_(false) { set_clock_rate(ZX8081ClockRate); tape_player_.set_motor_control(true); clear_all_keys(); @@ -114,7 +115,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { set_interrupt_line(true, -2); set_interrupt_line(false); } - if(latched_video_byte_) { + if(has_latched_video_byte_) { size_t char_address = (size_t)((address & 0xfe00) | ((latched_video_byte_ & 0x3f) << 3) | line_counter_); uint8_t mask = (latched_video_byte_ & 0x80) ? 0x00 : 0xff; if(char_address < ram_base_) { @@ -124,7 +125,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { } video_->output_byte(latched_video_byte_); - latched_video_byte_ = 0; + has_latched_video_byte_ = false; } break; @@ -165,6 +166,7 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { // just return the value as read. if(is_opcode_read && address&0x8000 && !(value & 0x40) && !get_halt_line()) { latched_video_byte_ = value; + has_latched_video_byte_ = true; *cycle.value = 0; } else *cycle.value = value; } diff --git a/Machines/ZX8081/ZX8081.hpp b/Machines/ZX8081/ZX8081.hpp index 2d8ea8ba6..2e87be5d8 100644 --- a/Machines/ZX8081/ZX8081.hpp +++ b/Machines/ZX8081/ZX8081.hpp @@ -98,7 +98,9 @@ class Machine: bool is_zx81_; bool nmi_is_enabled_; int vsync_start_cycle_, vsync_end_cycle_; + uint8_t latched_video_byte_; + bool has_latched_video_byte_; bool use_fast_tape_hack_; bool use_automatic_tape_motor_control_; From 30e93979d2e092edc140a9a8b2b6d06aeb979d61 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 8 Jul 2017 21:01:07 -0400 Subject: [PATCH 3/5] Removed data work if sync is enabled; in that case no data is output. --- Machines/ZX8081/Video.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Machines/ZX8081/Video.cpp b/Machines/ZX8081/Video.cpp index 5102cdffd..0f9f64b0c 100644 --- a/Machines/ZX8081/Video.cpp +++ b/Machines/ZX8081/Video.cpp @@ -76,6 +76,7 @@ void Video::set_sync(bool sync) { void Video::output_byte(uint8_t byte) { // Complete whatever was going on. + if(sync_) return; flush(); // Grab a buffer if one isn't already available. From 4509c3ce34ffe27771dc5af50c4b147262d26448 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 8 Jul 2017 21:01:52 -0400 Subject: [PATCH 4/5] By observation, it appears that disabling vsync occurs on any port output whatsoever, as long as NMI isn't blocking it. --- Machines/ZX8081/ZX8081.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index f9edf8815..af5a1928e 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -77,11 +77,9 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { case CPU::Z80::PartialMachineCycle::Output: if(!(address & 2)) nmi_is_enabled_ = false; if(!(address & 1)) nmi_is_enabled_ = is_zx81_; - if((address&3) == 3) { - if(!nmi_is_enabled_) { - set_vsync(false); - line_counter_ = 0; - } + if((address&3) == 3) line_counter_ = 0; + if(!nmi_is_enabled_) { + set_vsync(false); } break; From 87658e83c123b073fd98b2b166a9cc489d8b4af3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 9 Jul 2017 00:05:30 -0400 Subject: [PATCH 5/5] Moved line counter reset logic; I think this is actually correct. --- Machines/ZX8081/ZX8081.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index af5a1928e..c0df523be 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -77,8 +77,10 @@ int Machine::perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { case CPU::Z80::PartialMachineCycle::Output: if(!(address & 2)) nmi_is_enabled_ = false; if(!(address & 1)) nmi_is_enabled_ = is_zx81_; - if((address&3) == 3) line_counter_ = 0; if(!nmi_is_enabled_) { + // Line counter reset is held low while vsync is active; simulate that lazily by performing + // an instant reset upon the transition from active to inactive. + if(vsync_) line_counter_ = 0; set_vsync(false); } break;