1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-25 09:30:14 +00:00

Start normalising Commodore serial bus interface.

This commit is contained in:
Thomas Harte 2024-12-28 20:11:27 -05:00
parent b4b216de84
commit c92b0dc886
2 changed files with 102 additions and 94 deletions

View File

@ -13,7 +13,7 @@
using namespace Commodore::Serial; using namespace Commodore::Serial;
const char *::Commodore::Serial::StringForLine(Line line) { const char *::Commodore::Serial::to_string(Line line) {
switch(line) { switch(line) {
case ServiceRequest: return "Service request"; case ServiceRequest: return "Service request";
case Attention: return "Attention"; case Attention: return "Attention";

View File

@ -14,115 +14,123 @@
namespace Commodore::Serial { namespace Commodore::Serial {
enum Line { enum class Line {
ServiceRequest = 0, ServiceRequest = 0,
Attention, Attention,
Clock, Clock,
Data, Data,
Reset Reset
}; };
const char *to_string(Line line);
enum LineLevel: bool { enum class LineLevel: bool {
High = true, High = true,
Low = false Low = false
}; };
const char *to_string(LineLevel line);
class Port; class Port;
class Bus; class Bus;
/*! /*!
Returns a C string giving a human-readable name for the supplied line. Calls both of the necessary methods to (i) set @c bus as the target for @c port outputs; and
*/ (ii) add @c port as one of the targets to which @c bus propagates line changes.
const char *StringForLine(Line line); */
void attach(Port &port, Bus &bus);
/*! /*!
Calls both of the necessary methods to (i) set @c bus as the target for @c port outputs; and A serial bus is responsible for retaining a weakly-held collection of attached ports and for deciding the
(ii) add @c port as one of the targets to which @c bus propagates line changes. current bus levels based upon the net result of each port's output, and for communicating changes in bus
*/ levels to every port.
void AttachPortAndBus(std::shared_ptr<Port> port, std::shared_ptr<Bus> bus); */
class Bus {
public:
Bus() : line_levels_{
LineLevel::High,
LineLevel::High,
LineLevel::High,
LineLevel::High,
LineLevel::High
} {}
/*! /*!
A serial bus is responsible for retaining a weakly-held collection of attached ports and for deciding the Adds the supplied port to the bus.
current bus levels based upon the net result of each port's output, and for communicating changes in bus */
levels to every port. void add_port(Port &port);
*/
class Bus {
public:
Bus() : line_levels_{High, High, High, High, High} {}
/*! /*!
Adds the supplied port to the bus. Communicates to the bus that one of its attached port has changed its output level for the given line.
*/ The bus will therefore recalculate bus state and propagate as necessary.
void add_port(std::shared_ptr<Port> port); */
void set_line_output_did_change(Line line);
/*! private:
Communicates to the bus that one of its attached port has changed its output level for the given line. LineLevel line_levels_[5];
The bus will therefore recalculate bus state and propagate as necessary. std::vector<Port &> ports_;
*/ };
void set_line_output_did_change(Line line);
private: /*!
LineLevel line_levels_[5]; A serial port is an endpoint on a serial bus; this class provides a direct setter for current line outputs and
std::vector<std::weak_ptr<Port>> ports_; expects to be subclassed in order for specific port-housing devices to deal with input.
}; */
class Port {
public:
Port() : line_levels_{
LineLevel::High,
LineLevel::High,
LineLevel::High,
LineLevel::High,
LineLevel::High
} {}
virtual ~Port() = default;
/*! /*!
A serial port is an endpoint on a serial bus; this class provides a direct setter for current line outputs and Sets the current level of an output line on this serial port.
expects to be subclassed in order for specific port-housing devices to deal with input. */
*/ void set_output(Line line, LineLevel level) {
class Port { if(line_levels_[size_t(line)] != level) {
public: line_levels_[size_t(line)] = level;
Port() : line_levels_{High, High, High, High, High} {} if(serial_bus_) serial_bus_->set_line_output_did_change(line);
virtual ~Port() = default;
/*!
Sets the current level of an output line on this serial port.
*/
void set_output(Line line, LineLevel level) {
if(line_levels_[line] != level) {
line_levels_[line] = level;
std::shared_ptr<Bus> bus = serial_bus_.lock();
if(bus) bus->set_line_output_did_change(line);
}
} }
}
/*! /*!
Gets the previously set level of an output line. Gets the previously set level of an output line.
*/ */
LineLevel get_output(Line line) { LineLevel get_output(Line line) {
return line_levels_[line]; return line_levels_[size_t(line)];
} }
/*! /*!
Called by the bus to signal a change in any input line level. Subclasses should implement this. Called by the bus to signal a change in any input line level. Subclasses should implement this.
*/ */
virtual void set_input(Line line, LineLevel value) = 0; virtual void set_input(Line line, LineLevel value) = 0;
/*! /*!
Sets the supplied serial bus as that to which line levels will be communicated. Sets the supplied serial bus as that to which line levels will be communicated.
*/ */
inline void set_serial_bus(std::shared_ptr<Bus> serial_bus) { inline void set_bus(Bus &serial_bus) {
serial_bus_ = serial_bus; serial_bus_ = &serial_bus;
} }
private: private:
std::weak_ptr<Bus> serial_bus_; Bus *serial_bus_ = nullptr;
LineLevel line_levels_[5]; LineLevel line_levels_[5];
}; };
/*! /*!
A debugging port, which makes some attempt to log bus activity. Incomplete. TODO: complete. A debugging port, which makes some attempt to log bus activity. Incomplete. TODO: complete.
*/ */
class DebugPort: public Port { class DebugPort: public Port {
public: public:
void set_input(Line line, LineLevel value); void set_input(Line line, LineLevel value);
DebugPort() : incoming_count_(0) {} DebugPort() : incoming_count_(0) {}
private: private:
uint8_t incoming_byte_; uint8_t incoming_byte_;
int incoming_count_; int incoming_count_;
LineLevel input_levels_[5]; LineLevel input_levels_[5];
}; };
} }