1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-01-11 08:30:55 +00:00

Started trying to clean up, including commuting the C1540 source file name to match its class name but mainly by adding documentation.

This commit is contained in:
Thomas Harte 2016-07-10 07:46:20 -04:00
parent c0ab45a73d
commit d8334edf4a
8 changed files with 108 additions and 22 deletions

View File

@ -6,7 +6,7 @@
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#include "Commodore1540.hpp"
#include "C1540.hpp"
#include <string.h>
using namespace Commodore::C1540;

View File

@ -16,6 +16,21 @@
namespace Commodore {
namespace C1540 {
/*!
An implementation of the serial-port VIA in a Commodore 1540 the VIA that facilitates all
IEC bus communications.
It is wired up such that Port B contains:
Bit 0: data input; 1 if the line is low, 0 if it is high;
Bit 1: data output; 1 if the line should be low, 0 if it should be high;
Bit 2: clock input; 1 if the line is low, 0 if it is high;
Bit 3: clock output; 1 if the line is low, 0 if it is high;
Bit 4: attention acknowledge output; exclusive ORd with the attention input and ORd onto the data output;
Bits 5/6: device select input; the 1540 will act as device 8 + [value of bits]
Bit 7: attention input; 1 if the line is low, 0 if it is high
The attention input is also connected to CA1, similarly inverted the CA1 wire will be high when the bus is low and vice versa.
*/
class SerialPortVIA: public MOS::MOS6522<SerialPortVIA>, public MOS::MOS6522IRQDelegate {
public:
using MOS6522IRQDelegate::set_interrupt_status;
@ -34,28 +49,21 @@ class SerialPortVIA: public MOS::MOS6522<SerialPortVIA>, public MOS::MOS6522IRQD
if(port) {
std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock();
if(serialPort) {
// printf("1540 output: %02x\n", value);
// "ATNA (Attention Acknowledge) is an output from PB4 which is sensed on the serial data line after being exclusively "ored" by the attention line and inverted"
_attention_acknowledge_level = !(value&0x10);
_data_level_output = (value&0x02);
serialPort->set_output(::Commodore::Serial::Line::Clock, (::Commodore::Serial::LineLevel)!(value&0x08));
update_data_line();
}
// printf("1540 serial port VIA port B: %02x\n", value);
}
// else
// printf("1540 serial port VIA port A: %02x\n", value);
}
void set_serial_line_state(::Commodore::Serial::Line line, bool value) {
// printf("1540 Serial port line %d: %s\n", line, value ? "on" : "off");
switch(line) {
default: break;
case ::Commodore::Serial::Line::Data: _portB = (_portB & ~0x01) | (value ? 0x00 : 0x01); break;
case ::Commodore::Serial::Line::Clock: _portB = (_portB & ~0x04) | (value ? 0x00 : 0x04); break;
case ::Commodore::Serial::Line::Attention:
// "ATN (Attention) is an input on pin 3 of P2 and P3 that is sensed at PB7 and CA1 of UC3 after being inverted by UA1"
_attention_level_input = !value;
_portB = (_portB & ~0x80) | (value ? 0x00 : 0x80);
set_control_line_input(Port::A, Line::One, !value);
@ -77,6 +85,7 @@ class SerialPortVIA: public MOS::MOS6522<SerialPortVIA>, public MOS::MOS6522IRQD
{
std::shared_ptr<::Commodore::Serial::Port> serialPort = _serialPort.lock();
if(serialPort) {
// "ATN (Attention) is an input on pin 3 of P2 and P3 that is sensed at PB7 and CA1 of UC3 after being inverted by UA1"
serialPort->set_output(::Commodore::Serial::Line::Data,
(::Commodore::Serial::LineLevel)(!_data_level_output
&& (_attention_level_input != _attention_acknowledge_level)));
@ -84,6 +93,22 @@ class SerialPortVIA: public MOS::MOS6522<SerialPortVIA>, public MOS::MOS6522IRQD
}
};
/*!
An implementation of the drive VIA in a Commodore 1540 the VIA that is used to interface with the disk.
It is wired up such that Port B contains:
Bits 0/1: head step direction (TODO)
Bit 2: motor control (TODO)
Bit 3: LED control (TODO)
Bit 4: write protect photocell status (TODO)
Bits 5/6: write density (TODO)
Bit 7: 0 if sync marks are currently being detected, 1 otherwise;
... and Port A contains the byte most recently read from the disk or the byte next to write to the disk, depending on data direction.
It is implied that CA2 might be used to set processor overflow, CA1 a strobe for data input, and one of the CBs being definitive on
whether the disk head is being told to read or write, but it's unclear and I've yet to investigate. So, TODO.
*/
class DriveVIA: public MOS::MOS6522<DriveVIA>, public MOS::MOS6522IRQDelegate {
public:
using MOS6522IRQDelegate::set_interrupt_status;
@ -110,6 +135,9 @@ class DriveVIA: public MOS::MOS6522<DriveVIA>, public MOS::MOS6522IRQDelegate {
}
};
/*!
An implementation of the C1540's serial port; this connects incoming line levels to the serial-port VIA.
*/
class SerialPort : public ::Commodore::Serial::Port {
public:
void set_input(::Commodore::Serial::Line line, ::Commodore::Serial::LineLevel level) {
@ -125,17 +153,29 @@ class SerialPort : public ::Commodore::Serial::Port {
std::weak_ptr<SerialPortVIA> _serialPortVIA;
};
/*!
Provides an emulation of the C1540.
*/
class Machine:
public CPU6502::Processor<Machine>,
public MOS::MOS6522IRQDelegate::Delegate {
public:
Machine();
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
/*!
Sets the ROM image to use for this drive; it is assumed that the buffer provided will be at least 16 kb in size.
*/
void set_rom(const uint8_t *rom);
/*!
Sets the serial bus to which this drive should attach itself.
*/
void set_serial_bus(std::shared_ptr<::Commodore::Serial::Bus> serial_bus);
// to satisfy CPU6502::Processor
unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value);
// to satisfy MOS::MOS6522::Delegate
virtual void mos6522_did_change_interrupt_status(void *mos6522);

View File

@ -22,6 +22,12 @@ const char *::Commodore::Serial::StringForLine(Line line)
}
}
void ::Commodore::Serial::AttachPortAndBus(std::shared_ptr<Port> port, std::shared_ptr<Bus> bus)
{
port->set_serial_bus(bus);
bus->add_port(port);
}
void Bus::add_port(std::shared_ptr<Port> port)
{
_ports.push_back(port);

View File

@ -27,15 +27,38 @@ namespace Serial {
Low = false
};
class Port;
class Bus;
/*!
Returns a C string giving a human-readable name for the supplied line.
*/
const char *StringForLine(Line line);
class Port;
/*!
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.
*/
void AttachPortAndBus(std::shared_ptr<Port> port, std::shared_ptr<Bus> bus);
/*!
A serial bus is responsible for retaining a weakly-held collection of attached ports and for deciding the
current bus levels based upon the net result of each port's output, and for communicating changes in bus
levels to every port.
*/
class Bus {
public:
Bus() : _line_levels{High, High, High, High, High} {}
/*!
Adds the supplied port to the bus.
*/
void add_port(std::shared_ptr<Port> port);
/*!
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 set_line_output_did_change(Line line);
private:
@ -43,10 +66,17 @@ namespace Serial {
std::vector<std::weak_ptr<Port>> _ports;
};
/*!
A serial port is an endpoint on a serial bus; this class provides a direct setter for current line outputs and
expects to be subclassed in order for specific port-housing devices to deal with input.
*/
class Port {
public:
Port() : _line_levels{High, High, High, High, High} {}
/*!
Sets the current level of an output line on this serial port.
*/
void set_output(Line line, LineLevel level) {
if(_line_levels[line] != level)
{
@ -56,12 +86,21 @@ namespace Serial {
}
}
/*!
Gets the previously set level of an output line.
*/
LineLevel get_output(Line line) {
return _line_levels[line];
}
/*!
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;
/*!
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) {
_serial_bus = serial_bus;
}
@ -71,6 +110,9 @@ namespace Serial {
LineLevel _line_levels[5];
};
/*!
A debugging port, which makes some attempt to log bus activity. Incomplete. TODO: complete.
*/
class DebugPort: public Port {
public:
void set_input(Line line, LineLevel value);

View File

@ -22,8 +22,7 @@ Machine::Machine() :
_serialBus.reset(new ::Commodore::Serial::Bus);
// wire up the serial bus and serial port
_serialBus->add_port(_serialPort);
_serialPort->set_serial_bus(_serialBus);
Commodore::Serial::AttachPortAndBus(_serialPort, _serialBus);
// wire up 6522s and serial port
_userPortVIA->set_serial_port(_serialPort);

View File

@ -13,7 +13,7 @@
#include "../../../Storage/Tape/Tape.hpp"
#include "../../../Components/6560/6560.hpp"
#include "../../../Components/6522/6522.hpp"
#include "../1540/Commodore1540.hpp"
#include "../1540/C1540.hpp"
#include "../SerialBus.hpp"
#include "../../CRTMachine.hpp"

View File

@ -30,7 +30,7 @@
4B3BA0D01D318B44005DD7A7 /* MOS6532Bridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CB1D318B44005DD7A7 /* MOS6532Bridge.mm */; };
4B3BA0D11D318B44005DD7A7 /* TestMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B3BA0CD1D318B44005DD7A7 /* TestMachine.mm */; };
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */; };
4B4DC8281D2C2470003C5BF8 /* Commodore1540.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8261D2C2470003C5BF8 /* Commodore1540.cpp */; };
4B4DC8281D2C2470003C5BF8 /* C1540.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8261D2C2470003C5BF8 /* C1540.cpp */; };
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */; };
4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE561C3B7D360093A61B /* Atari2600Document.swift */; };
4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE571C3B7D360093A61B /* ElectronDocument.swift */; };
@ -398,8 +398,8 @@
4B3BA0CD1D318B44005DD7A7 /* TestMachine.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestMachine.mm; sourceTree = "<group>"; };
4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Vic20.cpp; sourceTree = "<group>"; };
4B4DC8201D2C2425003C5BF8 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Vic20.hpp; sourceTree = "<group>"; };
4B4DC8261D2C2470003C5BF8 /* Commodore1540.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Commodore1540.cpp; sourceTree = "<group>"; };
4B4DC8271D2C2470003C5BF8 /* Commodore1540.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Commodore1540.hpp; sourceTree = "<group>"; };
4B4DC8261D2C2470003C5BF8 /* C1540.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = C1540.cpp; sourceTree = "<group>"; };
4B4DC8271D2C2470003C5BF8 /* C1540.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = C1540.hpp; sourceTree = "<group>"; };
4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SerialBus.cpp; sourceTree = "<group>"; };
4B4DC82A1D2C27A4003C5BF8 /* SerialBus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SerialBus.hpp; sourceTree = "<group>"; };
4B55CE561C3B7D360093A61B /* Atari2600Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atari2600Document.swift; sourceTree = "<group>"; };
@ -909,8 +909,8 @@
4B4DC8251D2C2470003C5BF8 /* 1540 */ = {
isa = PBXGroup;
children = (
4B4DC8261D2C2470003C5BF8 /* Commodore1540.cpp */,
4B4DC8271D2C2470003C5BF8 /* Commodore1540.hpp */,
4B4DC8261D2C2470003C5BF8 /* C1540.cpp */,
4B4DC8271D2C2470003C5BF8 /* C1540.hpp */,
);
path = 1540;
sourceTree = "<group>";
@ -1836,7 +1836,7 @@
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */,
4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */,
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */,
4B4DC8281D2C2470003C5BF8 /* Commodore1540.cpp in Sources */,
4B4DC8281D2C2470003C5BF8 /* C1540.cpp in Sources */,
4B1E85751D170228001EF87D /* Typer.cpp in Sources */,
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */,
4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */,

View File

@ -7,7 +7,7 @@
//
#import "C1540Bridge.h"
#include "Commodore1540.hpp"
#include "C1540.hpp"
class VanillaSerialPort: public Commodore::Serial::Port {
public:
@ -35,8 +35,7 @@ class VanillaSerialPort: public Commodore::Serial::Port {
_serialPort.reset(new VanillaSerialPort);
_c1540.set_serial_bus(_serialBus);
_serialBus->add_port(_serialPort);
_serialPort->set_serial_bus(_serialBus);
Commodore::Serial::AttachPortAndBus(_serialPort, _serialBus);
}
return self;
}