diff --git a/Machines/Enterprise/Enterprise.cpp b/Machines/Enterprise/Enterprise.cpp index 418c06de2..a01608751 100644 --- a/Machines/Enterprise/Enterprise.cpp +++ b/Machines/Enterprise/Enterprise.cpp @@ -225,26 +225,38 @@ template class ConcreteMachine: using PartialMachineCycle = CPU::Z80::PartialMachineCycle; const uint16_t address = cycle.address ? *cycle.address : 0x0000; - // TODO: possibly apply an access penalty. + // Calculate an access penalty, if applicable. HalfCycles penalty; - if(is_video_[address >> 14]) { - // TODO. - } else { - switch(cycle.operation) { - default: break; + switch(cycle.operation) { + default: break; - case CPU::Z80::PartialMachineCycle::ReadStart: - case CPU::Z80::PartialMachineCycle::WriteStart: - if(wait_mode_ == WaitMode::OnAllAccesses) { - penalty = HalfCycles(2); - } - break; + // For non-video pauses, insert during the initial part of the bus cycle. + case CPU::Z80::PartialMachineCycle::ReadStart: + case CPU::Z80::PartialMachineCycle::WriteStart: + if(!is_video_[address >> 14] && wait_mode_ == WaitMode::OnAllAccesses) { + penalty = HalfCycles(2); + } + break; + case CPU::Z80::PartialMachineCycle::ReadOpcodeStart: + if(!is_video_[address >> 14] && wait_mode_ != WaitMode::None) { + penalty = HalfCycles(2); + } + break; - case CPU::Z80::PartialMachineCycle::ReadOpcodeStart: - if(wait_mode_ != WaitMode::None) { - penalty = HalfCycles(2); - } - break; + // Video pauses: insert right at the end of the bus cycle. + case CPU::Z80::PartialMachineCycle::ReadOpcode: + case CPU::Z80::PartialMachineCycle::Read: + case CPU::Z80::PartialMachineCycle::Write: + if(is_video_[address >> 14]) { + // TODO. + } + break; + + case CPU::Z80::PartialMachineCycle::Input: + case CPU::Z80::PartialMachineCycle::Output: { + if((address & 0xf0) == 0x80) { + // TODO. + } } } diff --git a/Machines/Enterprise/Nick.cpp b/Machines/Enterprise/Nick.cpp index be9bfd0c1..139285e49 100644 --- a/Machines/Enterprise/Nick.cpp +++ b/Machines/Enterprise/Nick.cpp @@ -92,7 +92,17 @@ uint8_t Nick::read([[maybe_unused]] uint16_t address) { return 0xff; } -//int c; +Cycles Nick::get_time_until_z80_slot() const { + // Place Z80 accesses as the first six cycles in each sixteen-cycle window. + // That models video accesses as being the final ten. Which has the net effect + // of responding to the line parameter table interrupt flag as soon as it's + // loaded. + + // i.e. 0 -> 0, 1 -> 15 ... 15 -> 1. + return Cycles( + 15 ^ ((horizontal_counter_ + 15) & 15) + ); +} void Nick::run_for(Cycles duration) { constexpr int line_length = 912; @@ -455,7 +465,7 @@ void Nick::set_output_type(OutputType type, bool force_flush) { // MARK: - Sequence points. -Cycles Nick::get_next_sequence_point() { +Cycles Nick::get_next_sequence_point() const { // TODO: the below is incorrect; unit test and correct. // Changing to e.g. Cycles(1) reveals the relevant discrepancy. // return Cycles(1); diff --git a/Machines/Enterprise/Nick.hpp b/Machines/Enterprise/Nick.hpp index 31911e90d..75b220c12 100644 --- a/Machines/Enterprise/Nick.hpp +++ b/Machines/Enterprise/Nick.hpp @@ -23,11 +23,12 @@ class Nick { uint8_t read(uint16_t address); void run_for(Cycles); + Cycles get_time_until_z80_slot() const; void set_scan_target(Outputs::Display::ScanTarget *scan_target); Outputs::Display::ScanStatus get_scaled_scan_status() const; - Cycles get_next_sequence_point(); + Cycles get_next_sequence_point() const; /*! @returns The current state of the interrupt line — @c true for active;