From 06edeea866646c4144b4fd8a9a1f9ccc81712325 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 19 Nov 2019 22:24:32 -0500 Subject: [PATCH 1/2] Adds reload during event count mode. Plus a helpful bit of TODO. --- Components/68901/MFP68901.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Components/68901/MFP68901.cpp b/Components/68901/MFP68901.cpp index ffe2402cb..9d495f4bb 100644 --- a/Components/68901/MFP68901.cpp +++ b/Components/68901/MFP68901.cpp @@ -239,6 +239,15 @@ void MFP68901::set_timer_event_input(int channel, bool value) { // If the edge bit associated with the TAI or TBI input is a one, it will be active high. decrement_timer(channel, 1); } + + // TODO: + // + // Altering the edge bit while the timer is in the event count mode can produce a count pulse. + // The interrupt channel associated with the input (I3 for I4 for TAI) is allowed to function normally. + // To count transitions reliably, the input must remain in each state (1/O) for a length of time equal + // to four periods of the timer clock. + // + // (the final bit probably explains 13 cycles of the DE to interrupt latency; not sure about the other ~15) } void MFP68901::decrement_timer(int timer, int amount) { @@ -251,7 +260,10 @@ void MFP68901::decrement_timer(int timer, int amount) { case 2: begin_interrupts(Interrupt::TimerC); break; case 3: begin_interrupts(Interrupt::TimerD); break; } - if(timers_[timer].mode == TimerMode::Delay) { + + // Re: reloading when in event counting mode; I found the data sheet thoroughly unclear on + // this, but it appears empirically to be correct. See e.g. Pompey Pirates menu 27. + if(timers_[timer].mode == TimerMode::Delay || timers_[timer].mode == TimerMode::EventCount) { timers_[timer].value += timers_[timer].reload_value; // TODO: properly. } } From 7ff57f8cdf98154f31b71f83c82c34d69a6a0e6f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 19 Nov 2019 22:32:07 -0500 Subject: [PATCH 2/2] Starts to flesh out documentation. --- Components/68901/MFP68901.cpp | 2 +- Components/68901/MFP68901.hpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Components/68901/MFP68901.cpp b/Components/68901/MFP68901.cpp index 9d495f4bb..b68b8be9b 100644 --- a/Components/68901/MFP68901.cpp +++ b/Components/68901/MFP68901.cpp @@ -277,7 +277,7 @@ void MFP68901::set_port_input(uint8_t input) { } uint8_t MFP68901::get_port_output() { - return 0xff; + return 0xff; // TODO. } void MFP68901::reevaluate_gpip_interrupts() { diff --git a/Components/68901/MFP68901.hpp b/Components/68901/MFP68901.hpp index 2933a8eaf..d49fe55bb 100644 --- a/Components/68901/MFP68901.hpp +++ b/Components/68901/MFP68901.hpp @@ -21,28 +21,58 @@ class PortHandler { // TODO: announce changes in output. }; +/*! + Models the Motorola 68901 Multi-Function Peripheral ('MFP'). +*/ class MFP68901: public ClockingHint::Source { public: + /// @returns the result of a read from @c address. uint8_t read(int address); + + /// Performs a write of @c value to @c address. void write(int address, uint8_t value); + /// Advances the MFP by the supplied number of HalfCycles. void run_for(HalfCycles); + + /// @returns the number of cycles until the next possible sequence point — the next time + /// at which the interrupt line _might_ change. This object conforms to ClockingHint::Source + /// so that mechanism can also be used to reduce the quantity of calls into this class. + /// + /// @discussion TODO, alas. HalfCycles get_next_sequence_point(); + /// Sets the current level of either of the timer event inputs — TAI and TBI in datasheet terms. void set_timer_event_input(int channel, bool value); + /// Sets a port handler, a receiver that will be notified upon any change in GPIP output. + /// + /// @discussion TODO. void set_port_handler(PortHandler *); + + /// Sets the current input GPIP values. void set_port_input(uint8_t); + + /// @returns the current GPIP output values. + /// + /// @discussion TODO. uint8_t get_port_output(); + /// @returns @c true if the interrupt output is currently active; @c false otherwise.s bool get_interrupt_line(); static const int NoAcknowledgement = 0x100; + + /// Communicates an interrupt acknowledge cycle. + /// + /// @returns the vector placed on the bus if any; @c NoAcknowledgement if nothing is loaded. int acknowledge_interrupt(); struct InterruptDelegate { + /// Informs the delegate of a change in the interrupt line of the nominated MFP. virtual void mfp68901_did_change_interrupt_status(MFP68901 *) = 0; }; + /// Sets a delegate that will be notified upon any change in the interrupt line. void set_interrupt_delegate(InterruptDelegate *delegate); // ClockingHint::Source.