diff --git a/Machines/Commodore/1540/Commodore1540.cpp b/Machines/Commodore/1540/C1540.cpp
similarity index 98%
rename from Machines/Commodore/1540/Commodore1540.cpp
rename to Machines/Commodore/1540/C1540.cpp
index fa7bb49e9..69672ddb5 100644
--- a/Machines/Commodore/1540/Commodore1540.cpp
+++ b/Machines/Commodore/1540/C1540.cpp
@@ -6,7 +6,7 @@
 //  Copyright © 2016 Thomas Harte. All rights reserved.
 //
 
-#include "Commodore1540.hpp"
+#include "C1540.hpp"
 #include <string.h>
 
 using namespace Commodore::C1540;
diff --git a/Machines/Commodore/1540/Commodore1540.hpp b/Machines/Commodore/1540/C1540.hpp
similarity index 65%
rename from Machines/Commodore/1540/Commodore1540.hpp
rename to Machines/Commodore/1540/C1540.hpp
index 2d0fffec3..92ceccb6e 100644
--- a/Machines/Commodore/1540/Commodore1540.hpp
+++ b/Machines/Commodore/1540/C1540.hpp
@@ -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);
 
diff --git a/Machines/Commodore/SerialBus.cpp b/Machines/Commodore/SerialBus.cpp
index 13ee704b3..69b187472 100644
--- a/Machines/Commodore/SerialBus.cpp
+++ b/Machines/Commodore/SerialBus.cpp
@@ -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);
diff --git a/Machines/Commodore/SerialBus.hpp b/Machines/Commodore/SerialBus.hpp
index 78ee5be70..324ef235e 100644
--- a/Machines/Commodore/SerialBus.hpp
+++ b/Machines/Commodore/SerialBus.hpp
@@ -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);
diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp
index 454b061ee..e417c2849 100644
--- a/Machines/Commodore/Vic-20/Vic20.cpp
+++ b/Machines/Commodore/Vic-20/Vic20.cpp
@@ -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);
diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp
index a6ad74501..fcbac0fbf 100644
--- a/Machines/Commodore/Vic-20/Vic20.hpp
+++ b/Machines/Commodore/Vic-20/Vic20.hpp
@@ -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"
diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj
index 2602afa7e..302bceebd 100644
--- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj	
+++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj	
@@ -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 */,
diff --git a/OSBindings/Mac/Clock SignalTests/Bridges/C1540Bridge.mm b/OSBindings/Mac/Clock SignalTests/Bridges/C1540Bridge.mm
index 72339ef4d..b062016c5 100644
--- a/OSBindings/Mac/Clock SignalTests/Bridges/C1540Bridge.mm	
+++ b/OSBindings/Mac/Clock SignalTests/Bridges/C1540Bridge.mm	
@@ -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;
 }