diff --git a/Machines/Amiga/Blitter.cpp b/Machines/Amiga/Blitter.cpp
index 4795f4cbc..1e4d38a69 100644
--- a/Machines/Amiga/Blitter.cpp
+++ b/Machines/Amiga/Blitter.cpp
@@ -14,8 +14,6 @@
 
 using namespace Amiga;
 
-Blitter::Blitter(uint16_t *ram, size_t size) : ram_(ram), ram_mask_(uint32_t(size-1)) {}
-
 void Blitter::set_control(int index, uint16_t value) {
 	LOG("Set control " << index << " to " << PADHEX(4) << value);
 }
@@ -61,6 +59,6 @@ uint16_t Blitter::get_status() {
 }
 
 bool Blitter::advance() {
-	ram_[addresses_[3] & ram_mask_] = 0xffff;
+	ram_[(pointer_[3] >> 1) & ram_mask_] = 0xffff;
 	return false;
 }
diff --git a/Machines/Amiga/Blitter.hpp b/Machines/Amiga/Blitter.hpp
index b8a372dcf..af182152c 100644
--- a/Machines/Amiga/Blitter.hpp
+++ b/Machines/Amiga/Blitter.hpp
@@ -13,12 +13,13 @@
 #include <cstdint>
 
 #include "../../ClockReceiver/ClockReceiver.hpp"
+#include "DMADevice.hpp"
 
 namespace Amiga {
 
-class Blitter {
+class Blitter: public DMADevice<4> {
 	public:
-		Blitter(uint16_t *ram, size_t size);
+		using DMADevice::DMADevice;
 
 		// Various setters; it's assumed that address decoding is handled externally.
 		//
@@ -28,10 +29,6 @@ class Blitter {
 		void set_first_word_mask(uint16_t value);
 		void set_last_word_mask(uint16_t value);
 
-		template <int id, int shift> void set_pointer(uint16_t value) {
-			addresses_[id] = (addresses_[id] & (0xffff'0000 >> shift)) | uint32_t(value << shift);
-		}
-
 		void set_size(uint16_t value);
 		void set_minterms(uint16_t value);
 		void set_vertical_size(uint16_t value);
@@ -44,10 +41,6 @@ class Blitter {
 		bool advance();
 
 	private:
-		uint16_t *const ram_;
-		const uint32_t ram_mask_;
-
-		uint32_t addresses_[4];
 		uint8_t minterms_;
 		int width_ = 0, height_ = 0;
 };
diff --git a/Machines/Amiga/Chipset.cpp b/Machines/Amiga/Chipset.cpp
index 12895da07..dc775ffa6 100644
--- a/Machines/Amiga/Chipset.cpp
+++ b/Machines/Amiga/Chipset.cpp
@@ -33,7 +33,7 @@ template <DMAFlag... Flags> struct DMAMask: Mask<DMAFlag, Flags...> {};
 }
 
 Chipset::Chipset(uint16_t *ram, size_t size) :
-	blitter_(ram, size),
+	blitter_(*this, ram, size),
 	bitplanes_(*this, ram, size),
 	copper_(*this, ram, size),
 	disk_(*this, ram, size),
diff --git a/Machines/Amiga/Chipset.hpp b/Machines/Amiga/Chipset.hpp
index 271a19106..fd4f02a4b 100644
--- a/Machines/Amiga/Chipset.hpp
+++ b/Machines/Amiga/Chipset.hpp
@@ -15,6 +15,7 @@
 #include "../../Processors/68000/68000.hpp"
 #include "../../Outputs/CRT/CRT.hpp"
 
+#include "DMADevice.hpp"
 #include "Blitter.hpp"
 
 namespace Amiga {
@@ -94,33 +95,7 @@ class Chipset {
 		Outputs::Display::DisplayType get_display_type() const;
 
 	private:
-		// MARK: - Common base for DMA components.
-
-		class DMADeviceBase {
-			public:
-				DMADeviceBase(Chipset &chipset, uint16_t *ram, size_t size) : chipset_(chipset), ram_(ram), ram_mask_(uint32_t(size - 1)) {}
-
-			protected:
-				Chipset &chipset_;
-				uint16_t *ram_ = nullptr;
-				uint32_t ram_mask_ = 0;
-		};
-		friend DMADeviceBase;
-
-		template <size_t num_addresses> class DMADevice: public DMADeviceBase {
-			public:
-				using DMADeviceBase::DMADeviceBase;
-
-				/// Writes the word @c value to the address register @c id, shifting it by @c shift (0 or 16) first.
-				template <int id, int shift> void set_pointer(uint16_t value) {
-					static_assert(id < num_addresses);
-					static_assert(shift == 0 || shift == 16);
-					pointer_[id] = (pointer_[id] & (0xffff'0000 >> shift)) | uint32_t(value << shift);
-				}
-
-			protected:
-				std::array<uint32_t, num_addresses> pointer_{};
-		};
+		friend class DMADeviceBase;
 
 		// MARK: - Interrupts.
 
diff --git a/Machines/Amiga/DMADevice.hpp b/Machines/Amiga/DMADevice.hpp
new file mode 100644
index 000000000..9b1fe10ec
--- /dev/null
+++ b/Machines/Amiga/DMADevice.hpp
@@ -0,0 +1,48 @@
+//
+//  DMADevice.hpp
+//  Clock Signal
+//
+//  Created by Thomas Harte on 14/09/2021.
+//  Copyright © 2021 Thomas Harte. All rights reserved.
+//
+
+#ifndef DMADevice_hpp
+#define DMADevice_hpp
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+
+namespace Amiga {
+
+class Chipset;
+
+class DMADeviceBase {
+	public:
+		DMADeviceBase(Chipset &chipset, uint16_t *ram, size_t size) :
+			chipset_(chipset), ram_(ram), ram_mask_(uint32_t((size - 1) >> 1)) {}
+
+	protected:
+		Chipset &chipset_;
+		uint16_t *const ram_ = nullptr;
+		const uint32_t ram_mask_ = 0;
+};
+
+template <size_t num_addresses> class DMADevice: public DMADeviceBase {
+	public:
+		using DMADeviceBase::DMADeviceBase;
+
+		/// Writes the word @c value to the address register @c id, shifting it by @c shift (0 or 16) first.
+		template <int id, int shift> void set_pointer(uint16_t value) {
+			static_assert(id < num_addresses);
+			static_assert(shift == 0 || shift == 16);
+			pointer_[id] = (pointer_[id] & (0xffff'0000 >> shift)) | uint32_t(value << shift);
+		}
+
+	protected:
+		std::array<uint32_t, num_addresses> pointer_{};
+};
+
+}
+
+#endif /* DMADevice_hpp */
diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj
index 8fa9ea1c8..29f7af521 100644
--- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj	
+++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj	
@@ -1961,6 +1961,7 @@
 		4BC57CD82436A62900FBC404 /* State.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = State.cpp; sourceTree = "<group>"; };
 		4BC5C3DF22C994CC00795658 /* 68000MoveTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000MoveTests.mm; sourceTree = "<group>"; };
 		4BC5FC2F20CDDDEE00410AA0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/AppleIIOptions.xib"; sourceTree = SOURCE_ROOT; };
+		4BC6236A26F178DA00F83DFE /* DMADevice.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DMADevice.hpp; sourceTree = "<group>"; };
 		4BC751B11D157E61006C31D9 /* 6522Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = 6522Tests.swift; sourceTree = "<group>"; };
 		4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FIRFilter.cpp; sourceTree = "<group>"; };
 		4BC76E681C98E31700E6EF73 /* FIRFilter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FIRFilter.hpp; sourceTree = "<group>"; };
@@ -4284,6 +4285,7 @@
 				4BC080D726A25ADA00D03FD8 /* Amiga.hpp */,
 				4B9EC0E026AA260C0060A31F /* Blitter.hpp */,
 				4B9EC0E526AA4A660060A31F /* Chipset.hpp */,
+				4BC6236A26F178DA00F83DFE /* DMADevice.hpp */,
 				4B9EC0E926B384080060A31F /* Keyboard.hpp */,
 			);
 			path = Amiga;