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:
parent
c0ab45a73d
commit
d8334edf4a
@ -6,7 +6,7 @@
|
||||
// Copyright © 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Commodore1540.hpp"
|
||||
#include "C1540.hpp"
|
||||
#include <string.h>
|
||||
|
||||
using namespace Commodore::C1540;
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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 */,
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user