diff --git a/Components/68901/MFP68901.cpp b/Components/68901/MFP68901.cpp
new file mode 100644
index 000000000..be1b48a86
--- /dev/null
+++ b/Components/68901/MFP68901.cpp
@@ -0,0 +1,28 @@
+//
+//  MFP68901.cpp
+//  Clock Signal
+//
+//  Created by Thomas Harte on 06/10/2019.
+//  Copyright © 2019 Thomas Harte. All rights reserved.
+//
+
+#include "MFP68901.hpp"
+
+using namespace Motorola::MFP68901;
+
+uint8_t MFP68901::read(int address) {
+	/* TODO */
+	return 0xff;
+}
+
+void MFP68901::write(int address, uint8_t value) {
+	/* TODO */
+}
+
+void MFP68901::run_for(HalfCycles) {
+	/* TODO */
+}
+
+HalfCycles MFP68901::get_next_sequence_point() {
+	return HalfCycles(-1);
+}
diff --git a/Components/68901/MFP68901.hpp b/Components/68901/MFP68901.hpp
new file mode 100644
index 000000000..fbecb5c0b
--- /dev/null
+++ b/Components/68901/MFP68901.hpp
@@ -0,0 +1,30 @@
+//
+//  MFP68901.hpp
+//  Clock Signal
+//
+//  Created by Thomas Harte on 06/10/2019.
+//  Copyright © 2019 Thomas Harte. All rights reserved.
+//
+
+#ifndef MFP68901_hpp
+#define MFP68901_hpp
+
+#include <cstdint>
+#include "../../ClockReceiver/ClockReceiver.hpp"
+
+namespace Motorola {
+namespace MFP68901 {
+
+class MFP68901 {
+	public:
+		uint8_t read(int address);
+		void write(int address, uint8_t value);
+
+		void run_for(HalfCycles);
+		HalfCycles get_next_sequence_point();
+};
+
+}
+}
+
+#endif /* MFP68901_hpp */
diff --git a/Machines/AtariST/AtariST.cpp b/Machines/AtariST/AtariST.cpp
index 1cda5e5a6..b7bef6755 100644
--- a/Machines/AtariST/AtariST.cpp
+++ b/Machines/AtariST/AtariST.cpp
@@ -13,6 +13,7 @@
 #include "../../Processors/68000/68000.hpp"
 
 #include "../../Components/AY38910/AY38910.hpp"
+#include "../../Components/68901/MFP68901.hpp"
 
 #include "Video.hpp"
 #include "../../ClockReceiver/JustInTime.hpp"
@@ -173,7 +174,55 @@ class ConcreteMachine:
 									ay_.set_control_lines(GI::AY38910::ControlLines(0));
 								}
 							}
+
+							/*
+								TODO: Port A:
+									b7: reserved
+									b6: "freely usable output (monitor jack)"
+									b5: centronics strobe
+									b4: RS-232 DTR output
+									b3: RS-232 RTS output
+									b2: select floppy drive 1
+									b1: select floppy drive 0
+									b0: "page choice signal for double-sided floppy drive"
+							*/
 						return HalfCycles(2);
+
+						// The MFP block:
+						case 0x7ffd00:	case 0x7ffd01:	case 0x7ffd02:	case 0x7ffd03:
+						case 0x7ffd04:	case 0x7ffd05:	case 0x7ffd06:	case 0x7ffd07:
+						case 0x7ffd08:	case 0x7ffd09:	case 0x7ffd0a:	case 0x7ffd0b:
+						case 0x7ffd0c:	case 0x7ffd0d:	case 0x7ffd0e:	case 0x7ffd0f:
+						case 0x7ffd10:	case 0x7ffd11:	case 0x7ffd12:	case 0x7ffd13:
+						case 0x7ffd14:	case 0x7ffd15:	case 0x7ffd16:	case 0x7ffd17:
+						case 0x7ffd18:	case 0x7ffd19:	case 0x7ffd1a:	case 0x7ffd1b:
+						case 0x7ffd1c:	case 0x7ffd1d:	case 0x7ffd1e:	case 0x7ffd1f:
+							if(!cycle.data_select_active()) return HalfCycles(0);
+
+							// The lower data lines aren't connected.
+							if(!cycle.upper_data_select()) {
+								if(cycle.operation & Microcycle::Read) {
+									cycle.value->halves.low = 0xff;
+								}
+								return HalfCycles(0);
+							}
+
+							if(cycle.operation & Microcycle::Read) {
+								const uint8_t value = mfp_->read(int(address));
+								if(cycle.operation & Microcycle::SelectByte) {
+									cycle.value->halves.low = value;
+								} else {
+									cycle.value->halves.high = value;
+									cycle.value->halves.low = 0xff;
+								}
+							} else {
+								if(cycle.operation & Microcycle::SelectByte) {
+									mfp_->write(int(address), cycle.value->halves.low);
+								} else {
+									mfp_->write(int(address), cycle.value->halves.high);
+								}
+							}
+						break;
 					}
 				return HalfCycles(0);
 			}
@@ -211,6 +260,7 @@ class ConcreteMachine:
 		forceinline void advance_time(HalfCycles length) {
 			video_ += length;
 			cycles_since_audio_update_ += length;
+			mfp_ += length;
 		}
 
 		void update_audio() {
@@ -219,6 +269,7 @@ class ConcreteMachine:
 
 		CPU::MC68000::Processor<ConcreteMachine, true> mc68000_;
 		JustInTimeActor<Video, HalfCycles> video_;
+		JustInTimeActor<Motorola::MFP68901::MFP68901, HalfCycles> mfp_;
 
 		Concurrency::DeferringAsyncTaskQueue audio_queue_;
 		GI::AY38910::AY38910 ay_;
diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj
index 26fcce5e6..e8ab56003 100644
--- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj	
+++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj	
@@ -317,6 +317,8 @@
 		4B90467622C6FD6E000E2074 /* 68000ArithmeticTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B90467522C6FD6E000E2074 /* 68000ArithmeticTests.mm */; };
 		4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */; };
 		4B9252CE1E74D28200B76AF1 /* Atari ROMs in Resources */ = {isa = PBXBuildFile; fileRef = 4B9252CD1E74D28200B76AF1 /* Atari ROMs */; };
+		4B92E26A234AE35100CD6D1B /* MFP68901.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B92E268234AE35000CD6D1B /* MFP68901.cpp */; };
+		4B92E26B234AE35100CD6D1B /* MFP68901.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B92E268234AE35000CD6D1B /* MFP68901.cpp */; };
 		4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; };
 		4B9378E422A199C600973513 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9378E222A199C600973513 /* Audio.cpp */; };
 		4B98A05E1FFAD3F600ADF63B /* CSROMFetcher.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B98A05D1FFAD3F600ADF63B /* CSROMFetcher.mm */; };
@@ -1108,6 +1110,8 @@
 		4B92294A22B064FD00A1458F /* QuadratureMouse.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = QuadratureMouse.hpp; sourceTree = "<group>"; };
 		4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AtariStaticAnalyserTests.mm; sourceTree = "<group>"; };
 		4B9252CD1E74D28200B76AF1 /* Atari ROMs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Atari ROMs"; sourceTree = "<group>"; };
+		4B92E268234AE35000CD6D1B /* MFP68901.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MFP68901.cpp; sourceTree = "<group>"; };
+		4B92E269234AE35000CD6D1B /* MFP68901.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MFP68901.hpp; sourceTree = "<group>"; };
 		4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6502TimingTests.swift; sourceTree = "<group>"; };
 		4B9378E222A199C600973513 /* Audio.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Audio.cpp; sourceTree = "<group>"; };
 		4B9378E322A199C600973513 /* Audio.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Audio.hpp; sourceTree = "<group>"; };
@@ -2629,6 +2633,15 @@
 			path = QuadratureMouse;
 			sourceTree = "<group>";
 		};
+		4B92E267234AE35000CD6D1B /* 68901 */ = {
+			isa = PBXGroup;
+			children = (
+				4B92E268234AE35000CD6D1B /* MFP68901.cpp */,
+				4B92E269234AE35000CD6D1B /* MFP68901.hpp */,
+			);
+			path = 68901;
+			sourceTree = "<group>";
+		};
 		4B9F11C72272375400701480 /* QL Startup */ = {
 			isa = PBXGroup;
 			children = (
@@ -3224,8 +3237,8 @@
 		4BC9DF4A1D04691600F44158 /* Components */ = {
 			isa = PBXGroup;
 			children = (
-				4BDACBE922FFA5B50045EF7E /* 5380 */,
 				4BD468F81D8DF4290084958B /* 1770 */,
+				4BDACBE922FFA5B50045EF7E /* 5380 */,
 				4BC9DF4B1D04691600F44158 /* 6522 */,
 				4B1E85791D174DEC001EF87D /* 6532 */,
 				4BC9DF4C1D04691600F44158 /* 6560 */,
@@ -3234,6 +3247,7 @@
 				4BBC951F1F368D87008F4C34 /* 8272 */,
 				4BB244D222AABAF500BE20E5 /* 8530 */,
 				4B0E04F71FC9F2C800F43484 /* 9918 */,
+				4B92E267234AE35000CD6D1B /* 68901 */,
 				4B595FAA2086DFBA0083CAA8 /* AudioToggle */,
 				4B4A762D1DB1A35C007AAE2E /* AY38910 */,
 				4B302181208A550100773308 /* DiskII */,
@@ -4035,6 +4049,7 @@
 				4B89452F201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
 				4B894531201967B4007DE474 /* StaticAnalyser.cpp in Sources */,
 				4B894539201967B4007DE474 /* Tape.cpp in Sources */,
+				4B92E26B234AE35100CD6D1B /* MFP68901.cpp in Sources */,
 				4B7F1898215486A200388727 /* StaticAnalyser.cpp in Sources */,
 				4B15A9FD208249BB005E6C8D /* StaticAnalyser.cpp in Sources */,
 				4B055AD31FAE9B0B0060FFFF /* Microdisc.cpp in Sources */,
@@ -4231,6 +4246,7 @@
 				4BB4BFB022A42F290069048D /* MacintoshIMG.cpp in Sources */,
 				4B05401E219D1618001BF69C /* ScanTarget.cpp in Sources */,
 				4B4518861F75E91A00926311 /* MFMDiskController.cpp in Sources */,
+				4B92E26A234AE35100CD6D1B /* MFP68901.cpp in Sources */,
 				4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */,
 				4B3FE75E1F3CF68B00448EE4 /* CPM.cpp in Sources */,
 				4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */,