From 60cf8486bb6c4b4c8095a795c76731798f0ff967 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 15 Jun 2021 18:57:14 -0400 Subject: [PATCH] Makes a genuine attempt at real line counting. No output yet though. --- Machines/Enterprise/Nick.cpp | 60 ++++++++++++++++++++++++++++++++++-- Machines/Enterprise/Nick.hpp | 9 ++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/Machines/Enterprise/Nick.cpp b/Machines/Enterprise/Nick.cpp index 3cd39de86..0641b85da 100644 --- a/Machines/Enterprise/Nick.cpp +++ b/Machines/Enterprise/Nick.cpp @@ -36,8 +36,13 @@ void Nick::write(uint16_t address, uint8_t value) { // Still a mystery to me: the exact meaning of the top two bits here. For now // just treat a 0 -> 1 transition of the MSB as a forced frame restart. if((value^line_parameter_control_) & value & 0x80) { - // TODO: restart frame. printf("Should restart frame from %04x\n", line_parameter_base_); + + // For now: just force this to be the final line of this mode block. + // I'm unclear whether I should also reset the horizontal counter + // (i.e. completely abandon current video phase). + lines_remaining_ = 0xff; + line_parameters_[1] |= 1; } line_parameter_control_ = value & 0xc0; break; @@ -48,7 +53,58 @@ uint8_t Nick::read([[maybe_unused]] uint16_t address) { return 0xff; } -void Nick::run_for(HalfCycles) { +void Nick::run_for(HalfCycles duration) { + constexpr int line_length = 912; + + int clocks_remaining = duration.as(); + while(clocks_remaining) { + // Determine how many cycles are left this line. + const int clocks_this_line = std::min(clocks_remaining, line_length - horizontal_counter_); + + // Convert that into a [start/current] and end window. + int window = horizontal_counter_ >> 4; + const int end_window = (horizontal_counter_ + clocks_this_line) >> 4; + + // Advance the line counters. + clocks_remaining -= clocks_this_line; + horizontal_counter_ = (horizontal_counter_ + clocks_this_line) % line_length; + + // Do nothing if a window boundary isn't crossed. + if(window == end_window) continue; + + // If this is within the first 8 cycles of the line, [possibly] fetch + // the relevant part of the line parameters. + if(should_reload_line_parameters_ && window < 8) { + int fetch_spot = window; + while(fetch_spot < end_window && fetch_spot < 8) { + line_parameters_[(fetch_spot << 1)] = ram_[line_parameter_pointer_]; + line_parameters_[(fetch_spot << 1) + 1] = ram_[line_parameter_pointer_ + 1]; + line_parameter_pointer_ += 2; + ++fetch_spot; + } + + // If all parameters have been loaded, set appropriate fields. + if(fetch_spot == 8) { + should_reload_line_parameters_ = false; + + // Set length of mode line. + lines_remaining_ = line_parameters_[0]; + } + } + + // Check for end of line. + if(!horizontal_counter_) { + ++lines_remaining_; + if(!lines_remaining_) { + should_reload_line_parameters_ = true; + + // Check for end-of-frame. + if(line_parameters_[1] & 1) { + line_parameter_pointer_ = line_parameter_base_; + } + } + } + } } // MARK: - CRT passthroughs. diff --git a/Machines/Enterprise/Nick.hpp b/Machines/Enterprise/Nick.hpp index d38aa59a3..a5088cc6f 100644 --- a/Machines/Enterprise/Nick.hpp +++ b/Machines/Enterprise/Nick.hpp @@ -31,9 +31,18 @@ class Nick { Outputs::CRT::CRT crt_; const uint8_t *const ram_; + // CPU-provided state. uint8_t line_parameter_control_ = 0xc0; uint16_t line_parameter_base_ = 0x0000; + + // Ephemerals, related to current video position. int horizontal_counter_ = 0; + uint16_t line_parameter_pointer_ = 0x0000; + uint8_t line_parameters_[16]; + bool should_reload_line_parameters_ = false; + + // Current mode line parameters. + uint8_t lines_remaining_ = 0x00; };