From c8beb59172dddb0ca65fb0e9b449952eea012d90 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 25 Jan 2021 17:43:22 -0500 Subject: [PATCH] Attempts properly to track ADB bus activity. Output is not yet a valid ADB stream. Work to do. --- InstructionSets/M50740/Executor.cpp | 17 +++++++++-- InstructionSets/M50740/Executor.hpp | 5 ++++ Machines/Apple/AppleIIgs/ADB.cpp | 40 ++++++++++++++++++++++---- Machines/Apple/AppleIIgs/ADB.hpp | 5 ++++ Machines/Apple/AppleIIgs/AppleIIgs.cpp | 3 +- 5 files changed, 62 insertions(+), 8 deletions(-) diff --git a/InstructionSets/M50740/Executor.cpp b/InstructionSets/M50740/Executor.cpp index 3e9339bda..f216f38f0 100644 --- a/InstructionSets/M50740/Executor.cpp +++ b/InstructionSets/M50740/Executor.cpp @@ -42,7 +42,8 @@ void Executor::set_rom(const std::vector &rom) { } void Executor::run_for(Cycles cycles) { - // The incoming clock is divided by four. + // The incoming clock is divided by four; the local cycles_ count + // ensures that fractional parts are kept track of. cycles_ += cycles; CachingExecutor::run_for(cycles_.divide(Cycles(4)).as()); } @@ -54,8 +55,13 @@ void Executor::reset() { uint8_t Executor::read(uint16_t address) { address &= 0x1fff; + if(address < 0x60) { + return memory_[address]; + } + + port_handler_.run_ports_for(cycles_since_port_handler_.flush()); switch(address) { - default: return memory_[address]; + default: return 0xff; // TODO: external IO ports. @@ -89,6 +95,8 @@ void Executor::write(uint16_t address, uint8_t value) { return; } + port_handler_.run_ports_for(cycles_since_port_handler_.flush()); + // TODO: all external IO ports. switch(address) { default: break; @@ -706,3 +714,8 @@ template void Executor::perform(uint8_t *operand [[maybe_u } #undef set_nz } + +inline void Executor::subtract_duration(int duration) { + cycles_since_port_handler_ += Cycles(duration); + CachingExecutor::subtract_duration(duration); +} diff --git a/InstructionSets/M50740/Executor.hpp b/InstructionSets/M50740/Executor.hpp index a15fa73de..e1b47461b 100644 --- a/InstructionSets/M50740/Executor.hpp +++ b/InstructionSets/M50740/Executor.hpp @@ -25,6 +25,7 @@ class Executor; using CachingExecutor = CachingExecutor; struct PortHandler { + virtual void run_ports_for(Cycles) = 0; virtual void set_port_output(int port, uint8_t value) = 0; virtual uint8_t get_port_input(int port) = 0; }; @@ -143,8 +144,12 @@ class Executor: public CachingExecutor { inline uint8_t flags(); template inline void perform_interrupt(); + // MARK: - Execution time + Cycles cycles_; + Cycles cycles_since_port_handler_; PortHandler &port_handler_; + inline void subtract_duration(int duration); }; } diff --git a/Machines/Apple/AppleIIgs/ADB.cpp b/Machines/Apple/AppleIIgs/ADB.cpp index 0247211ba..619107b65 100644 --- a/Machines/Apple/AppleIIgs/ADB.cpp +++ b/Machines/Apple/AppleIIgs/ADB.cpp @@ -240,13 +240,36 @@ void GLU::set_port_output(int port, uint8_t value) { // printf("IIe keyboard reset line: %d\n", (value >> 6)&1); // printf("IIgs reset line: %d\n", (value >> 5)&1); // printf("GLU strobe: %d\n", (value >> 4)&1); - printf("Select GLU register: %d [%02x]\n", value & 0xf, value); +// printf("Select GLU register: %d [%02x]\n", value & 0xf, value); register_address_ = value & 0xf; break; - case 3: + case 3: { // printf("IIe KWS: %d\n", (value >> 6)&3); - printf("ADB data line output: %d\n", (value >> 3)&1); - break; +// printf("ADB data line output: %d\n", (value >> 3)&1); + + const bool new_adb_level = value & 0x08; + if(new_adb_level != adb_level_) { + if(!new_adb_level) { + // Transition to low. + constexpr float clock_rate = 894886.25; + const float seconds = float(total_period_.as()) / clock_rate; + + // Check for a valid bit length — 70 to 130 microseconds. + // (Plus a little). + if(seconds >= 0.000'56 && seconds <= 0.001'04) { + printf("Attention\n"); + } else if(seconds >= 0.000'06 && seconds <= 0.000'14) { + printf("bit: %d\n", (low_period_.as() * 2) < total_period_.as()); +// printf("tested: %0.2f\n", float(low_period_.as()) / float(total_period_.as())); + } else { + printf("Rejected %d microseconds\n", int(seconds * 1'000'000.0f)); + } + + total_period_ = low_period_ = Cycles(0); + } + adb_level_ = new_adb_level; + } + } break; default: assert(false); } @@ -261,7 +284,7 @@ uint8_t GLU::get_port_input(int port) { // printf("IIe keyboard read\n"); return 0x06; case 2: - printf("ADB data line input, etc\n"); +// printf("ADB data line input, etc\n"); return ports_[2]; case 3: // printf("ADB data line output, etc\n"); @@ -271,3 +294,10 @@ uint8_t GLU::get_port_input(int port) { } return 0xff; } + +void GLU::run_ports_for(Cycles cycles) { + total_period_ += cycles; + if(!adb_level_) { + low_period_ += cycles; + } +} diff --git a/Machines/Apple/AppleIIgs/ADB.hpp b/Machines/Apple/AppleIIgs/ADB.hpp index 4239bdb75..5dc5552d4 100644 --- a/Machines/Apple/AppleIIgs/ADB.hpp +++ b/Machines/Apple/AppleIIgs/ADB.hpp @@ -62,12 +62,17 @@ class GLU: public InstructionSet::M50740::PortHandler { InstructionSet::M50740::Executor executor_; + void run_ports_for(Cycles) override; void set_port_output(int port, uint8_t value) override; uint8_t get_port_input(int port) override; uint8_t registers_[16]; uint8_t register_address_; uint8_t ports_[4]; + + // TODO: this should be per peripheral. But I'm putting it here for now as an exploratory step. + bool adb_level_ = true; + Cycles low_period_, total_period_; }; } diff --git a/Machines/Apple/AppleIIgs/AppleIIgs.cpp b/Machines/Apple/AppleIIgs/AppleIIgs.cpp index 47156da16..69d62a635 100644 --- a/Machines/Apple/AppleIIgs/AppleIIgs.cpp +++ b/Machines/Apple/AppleIIgs/AppleIIgs.cpp @@ -186,6 +186,7 @@ class ConcreteMachine: void flush() { video_.flush(); iwm_.flush(); + adb_glu_.flush(); AudioUpdater updater(this); audio_queue_.perform(); @@ -916,7 +917,7 @@ class ConcreteMachine: Apple::Clock::ParallelClock clock_; JustInTimeActor video_; // i.e. run video at 7Mhz. - JustInTimeActor adb_glu_; + JustInTimeActor adb_glu_; // i.e. 3,579,545Mhz. Zilog::SCC::z8530 scc_; JustInTimeActor iwm_; Cycles cycles_since_clock_tick_;