diff --git a/BizHawk.Client.EmuHawk/tools/PCE/PCECDL.cs b/BizHawk.Client.EmuHawk/tools/PCE/PCECDL.cs
index 991c6e1950..dc69b2c02a 100644
--- a/BizHawk.Client.EmuHawk/tools/PCE/PCECDL.cs
+++ b/BizHawk.Client.EmuHawk/tools/PCE/PCECDL.cs
@@ -6,6 +6,8 @@ using System.Windows.Forms;
 
 using BizHawk.Emulation.Common;
 using BizHawk.Emulation.Common.IEmulatorExtensions;
+
+using BizHawk.Emulation.Cores.Nintendo.Gameboy;
 using BizHawk.Emulation.Cores.Components.H6280;
 using BizHawk.Emulation.Cores.PCEngine;
 
@@ -17,7 +19,7 @@ namespace BizHawk.Client.EmuHawk
 	public partial class PCECDL : Form, IToolFormAutoConfig
 	{
 		[RequiredService]
-		private PCEngine _emu { get; set; }
+		public IEmulator _emu { get; private set; }
 		private CodeDataLog _cdl;
 
 		private RecentFiles _recent_fld = new RecentFiles();
@@ -59,9 +61,18 @@ namespace BizHawk.Client.EmuHawk
 
 		public void Restart()
 		{
-			LoggingActiveCheckbox.Checked = _emu.Cpu.CDLLoggingActive;
-			_cdl = _emu.Cpu.CDL;
-			_emu.InitCDLMappings();
+			if (_emu.SystemId == "PCE")
+			{
+				var pce = _emu as PCEngine;
+				LoggingActiveCheckbox.Checked = pce.Cpu.CDLLoggingActive;
+				_cdl = pce.Cpu.CDL;
+				pce.InitCDLMappings();
+			}
+			else if(_emu.SystemId == "GB")
+			{
+				var gambatte = _emu as Gameboy;
+				_cdl = gambatte.CDL;
+			}
 			UpdateDisplay();
 		}
 
@@ -116,17 +127,32 @@ namespace BizHawk.Client.EmuHawk
 			using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
 			{
 				var newCDL = CodeDataLog.Load(fs);
-				if (!newCDL.CheckConsistency(_emu.Cpu.Mappings))
+
+				//this check may be inadequate in the future
+				if(newCDL.SubType != _emu.SystemId)
+					throw new InvalidDataException("File is a CDL file of the wrong target core (like, a different game console)!");
+
+				_cdl = newCDL;
+				if (_emu.SystemId == "PCE")
 				{
-					MessageBox.Show(this, "CDL file does not match emulator's current memory map!");
+					var pce = _emu as PCEngine;
+					var cdl_pce = newCDL as CodeDataLog_PCE;
+					if (!cdl_pce.CheckConsistency(pce.Cpu.Mappings))
+					{
+						MessageBox.Show(this, "CDL file does not match emulator's current memory map!");
+						return;
+					}
+					pce.Cpu.CDL = _cdl;
 				}
-				else
+				else if (_emu.SystemId == "GB")
 				{
-					_cdl = newCDL;
-					_emu.Cpu.CDL = _cdl;
-					UpdateDisplay();
+					var gambatte = _emu as Gameboy;
+					var cdl_gb = newCDL as CodeDataLog_GB;
+					gambatte.CDL = cdl_gb;
 				}
 			}
+
+			UpdateDisplay();
 		}
 
 		#region Events
@@ -154,8 +180,21 @@ namespace BizHawk.Client.EmuHawk
 			var result = MessageBox.Show(this, "OK to create new CDL?", "Query", MessageBoxButtons.YesNo);
 			if (result == DialogResult.Yes)
 			{
-				_cdl = CodeDataLog.Create(_emu.Cpu.Mappings);
-				_emu.Cpu.CDL = _cdl;
+				if (_emu.SystemId == "PCE")
+				{
+					var pce = _emu as PCEngine;
+					_cdl = CodeDataLog_PCE.Create(pce.Cpu.Mappings);
+					pce.Cpu.CDL = _cdl;
+				}
+				else if (_emu.SystemId == "GB")
+				{
+					var gambatte = _emu as Gameboy;
+					var memd = gambatte.AsMemoryDomains();
+					var cdl_gb = CodeDataLog_GB.Create(memd);
+					gambatte.CDL = cdl_gb;
+					_cdl = cdl_gb;
+				}
+				
 				UpdateDisplay();
 			}
 		}
@@ -173,22 +212,7 @@ namespace BizHawk.Client.EmuHawk
 
 				if (file != null)
 				{
-					using (var fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
-					{
-						var newCDL = CodeDataLog.Load(fs);
-						if (!newCDL.CheckConsistency(_emu.Cpu.Mappings))
-						{
-							MessageBox.Show(this, "CDL file does not match emulator's current memory map!");
-						}
-						else
-						{
-							_cdl = newCDL;
-							_emu.Cpu.CDL = _cdl;
-							UpdateDisplay();
-							_recent.Add(file.FullName);
-							_currentFileName = file.FullName;
-						}
-					}
+					LoadFile(file.FullName);
 				}
 			}
 		}
@@ -314,7 +338,14 @@ namespace BizHawk.Client.EmuHawk
 				LoggingActiveCheckbox.Checked = false;
 			}
 
-			_emu.Cpu.CDLLoggingActive = LoggingActiveCheckbox.Checked;
+			if (_emu.SystemId == "PCE")
+			{
+				//set a special flag on the CPU to indicate CDL is running, maybe it's faster, who knows
+				var pce = _emu as PCEngine;
+				pce.Cpu.CDLLoggingActive = LoggingActiveCheckbox.Checked;
+			}
+
+			_cdl.Active = LoggingActiveCheckbox.Checked;
 		}
 
 		private void PCECDL_DragEnter(object sender, DragEventArgs e)
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index 5389945b1c..e2993af865 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -173,6 +173,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
 				TimeCallback = new LibGambatte.RTCCallback(GetCurrentTime);
 				LibGambatte.gambatte_setrtccallback(GambatteState, TimeCallback);
 
+				//seems to have near negligable speed impact. lets always use it, for now.
+				//someone who cares can make it controllable
+				CDCallback = new LibGambatte.CDCallback(CDCallbackProc);
+				LibGambatte.gambatte_setcdcallback(GambatteState, CDCallback);
+
 				NewSaveCoreSetBuff();
 			}
 			catch
@@ -182,6 +187,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
 			}
 		}
 
+		public CodeDataLog_GB CDL;
+		LibGambatte.CDCallback CDCallback;
+		void CDCallbackProc(int addr, LibGambatte.CDLog_AddrType addrtype, LibGambatte.CDLog_Flags flags)
+		{
+			if (CDL == null) return;
+			if (!CDL.Active) return;
+			string key;
+			switch (addrtype)
+			{
+				case LibGambatte.CDLog_AddrType.ROM: key = "ROM"; break;
+				case LibGambatte.CDLog_AddrType.HRAM: key = "HRAM"; break;
+				case LibGambatte.CDLog_AddrType.WRAM: key = "WRAM"; break;
+				case LibGambatte.CDLog_AddrType.CartRAM: key = "CartRAM"; break;
+				default: throw new InvalidOperationException("Juniper lightbulb proxy");
+			}
+			CDL[key][addr] |= (byte)flags;
+		}
+
 		public IEmulatorServiceProvider ServiceProvider { get; private set; }
 
         #region ALL SAVESTATEABLE STATE GOES HERE
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
index 6d17f87db7..cdd3b43e27 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
@@ -34,6 +34,19 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
 			MULTICART_COMPAT = 4
 		}
 
+		public enum CDLog_AddrType : int
+		{
+			ROM, HRAM, WRAM, CartRAM
+		}
+
+		[Flags]
+		public enum CDLog_Flags : int
+		{
+			ExecFirst = 1,
+			ExecOperand = 2,
+			Data = 4
+		}
+
 		/// <summary>
 		/// Load ROM image.
 		/// </summary>
@@ -161,6 +174,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
 		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
 		public delegate void MemoryCallback(uint address);
 
+		/// <summary>
+		/// type of the CDLogger callback
+		/// </summary>
+		[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+		public delegate void CDCallback(int addr, CDLog_AddrType addrtype, CDLog_Flags flags);
+
 		/// <summary>
 		/// set a callback to occur immediately BEFORE EVERY cpu read, except for opcode first byte fetches
 		/// </summary>
@@ -185,6 +204,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
 		[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
 		public static extern void gambatte_setexeccallback(IntPtr core, MemoryCallback callback);
 
+		/// <summary>
+		/// set a callback whicih enables CD Logger feedback
+		/// </summary>
+		[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
+		public static extern void gambatte_setcdcallback(IntPtr core, CDCallback callback);
+
 		/// <summary>
 		/// type of the cpu trace callback
 		/// </summary>
diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h
index 990d3f9a64..f36121ca23 100644
--- a/libgambatte/include/gambatte.h
+++ b/libgambatte/include/gambatte.h
@@ -28,6 +28,21 @@
 namespace gambatte {
 enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 };
 
+typedef void (*CDCallback)(int32_t addr, int32_t addrtype, int32_t flags);
+
+enum eCDLog_AddrType
+{
+	eCDLog_AddrType_ROM, eCDLog_AddrType_HRAM, eCDLog_AddrType_WRAM, eCDLog_AddrType_CartRAM,
+	eCDLog_AddrType_None
+};
+
+enum eCDLog_Flags
+{
+	eCDLog_Flags_ExecFirst = 1,
+	eCDLog_Flags_ExecOperand = 2,
+	eCDLog_Flags_Data = 4,
+};
+
 class GB {
 public:
 	GB();
@@ -88,6 +103,7 @@ public:
 	void setReadCallback(void (*callback)(unsigned));
 	void setWriteCallback(void (*callback)(unsigned));
 	void setExecCallback(void (*callback)(unsigned));
+	void setCDCallback(CDCallback);
 	void setTraceCallback(void (*callback)(void *));
 	void setScanlineCallback(void (*callback)(), int sl);
 	void setRTCCallback(std::uint32_t (*callback)());
diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp
index e9c52041bc..77eaf09f01 100644
--- a/libgambatte/src/cinterface.cpp
+++ b/libgambatte/src/cinterface.cpp
@@ -83,6 +83,12 @@ GBEXPORT void gambatte_setexeccallback(GB *g, void (*callback)(unsigned))
 	g->setExecCallback(callback);
 }
 
+GBEXPORT void gambatte_setcdcallback(GB *g, CDCallback cdc)
+{
+	g->setCDCallback(cdc);
+}
+
+
 GBEXPORT void gambatte_settracecallback(GB *g, void (*callback)(void *))
 {
 	g->setTraceCallback(callback);
diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp
index e1674bebb1..3f6619eb78 100644
--- a/libgambatte/src/cpu.cpp
+++ b/libgambatte/src/cpu.cpp
@@ -112,7 +112,8 @@ void CPU::loadState(const SaveState &state) {
 
 #define READ(dest, addr) do { (dest) = memory.read(addr, cycleCounter); cycleCounter += 4; } while (0)
 // #define PC_READ(dest, addr) do { (dest) = memory.pc_read(addr, cycleCounter); cycleCounter += 4; } while (0)
-#define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
+#define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter, false); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
+#define PC_READ_FIRST(dest) do { (dest) = memory.read_excb(PC, cycleCounter, true); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
 #define FF_READ(dest, addr) do { (dest) = memory.ff_read(addr, cycleCounter); cycleCounter += 4; } while (0)
 
 #define WRITE(addr, data) do { memory.write(addr, data, cycleCounter); cycleCounter += 4; } while (0)
@@ -518,13 +519,13 @@ void CPU::process(const unsigned long cycles) {
 				result[9] = H;
 				result[10] = L;
 				result[11] = skip;
-				PC_READ(opcode);
+				PC_READ_FIRST(opcode);
 				result[12] = opcode;
 				result[13] = memory.debugGetLY();
 				tracecallback((void *)result);
 			}
 			else {
-				PC_READ(opcode);
+				PC_READ_FIRST(opcode);
 			}
 			
 			if (skip) {
diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h
index a55fb07ca6..09c966ccbb 100644
--- a/libgambatte/src/cpu.h
+++ b/libgambatte/src/cpu.h
@@ -79,6 +79,10 @@ public:
 		memory.setExecCallback(callback);
 	}
 
+	void setCDCallback(CDCallback cdc) {
+		memory.setCDCallback(cdc);
+	}
+
 	void setTraceCallback(void (*callback)(void *)) {
 		tracecallback = callback;
 	}
diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp
index 1c7dcc1f62..7f20278da2 100644
--- a/libgambatte/src/gambatte.cpp
+++ b/libgambatte/src/gambatte.cpp
@@ -114,6 +114,10 @@ void GB::setExecCallback(void (*callback)(unsigned)) {
 	p_->cpu.setExecCallback(callback);
 }
 
+void GB::setCDCallback(CDCallback cdc) {
+	p_->cpu.setCDCallback(cdc);
+}
+
 void GB::setTraceCallback(void (*callback)(void *)) {
 	p_->cpu.setTraceCallback(callback);
 }
diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h
index f6ea99bfa9..4038593d23 100644
--- a/libgambatte/src/mem/cartridge.h
+++ b/libgambatte/src/mem/cartridge.h
@@ -29,12 +29,26 @@
 
 namespace gambatte {
 
+	//DOOM
+//enum eAddressMappingType
+//{
+//	eAddressMappingType_ROM,
+//	eAddressMappingType_RAM
+//};
+//
+//struct AddressMapping
+//{
+//	int32_t address;
+//	eAddressMappingType type;
+//};
+
 class Mbc {
 public:
 	virtual ~Mbc() {}
 	virtual void romWrite(unsigned P, unsigned data) = 0;
 	virtual void loadState(const SaveState::Mem &ss) = 0;
 	virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0;
+	//virtual void mapAddress(AddressMapping* mapping, unsigned address) const = 0; //DOOM
 
 	template<bool isReader>void SyncState(NewState *ns)
 	{
diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp
index f1881eccb2..4bae856679 100644
--- a/libgambatte/src/memory.cpp
+++ b/libgambatte/src/memory.cpp
@@ -28,6 +28,7 @@ Memory::Memory(const Interrupter &interrupter_in)
 : readCallback(0),
   writeCallback(0),
   execCallback(0),
+  cdCallback(0),
   getInput(0),
   divLastUpdate(0),
   lastOamDmaUpdate(DISABLED_TIME),
diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h
index 8ffd355c31..b6a4bafd24 100644
--- a/libgambatte/src/memory.h
+++ b/libgambatte/src/memory.h
@@ -25,6 +25,7 @@
 #include "interrupter.h"
 #include "tima.h"
 #include "newstate.h"
+#include "gambatte.h"
 
 namespace gambatte {
 class InputGetter;
@@ -37,6 +38,7 @@ class Memory {
 	void (*readCallback)(unsigned);
 	void (*writeCallback)(unsigned);
 	void (*execCallback)(unsigned);
+	CDCallback cdCallback;
 
 	unsigned (*getInput)();
 	unsigned long divLastUpdate;
@@ -117,15 +119,78 @@ public:
 		return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : ioamhram[P - 0xFE00];
 	}
 
+	struct CDMapResult
+	{
+		eCDLog_AddrType type;
+		unsigned addr;
+	};
+
+	CDMapResult CDMap(const unsigned P) const
+	{
+		if(P<0x4000)
+		{
+			CDMapResult ret = { eCDLog_AddrType_ROM, P };
+			return ret;
+		}
+		else if(P<0x8000) 
+		{
+			unsigned bank = cart.rmem(P>>12) - cart.rmem(0);
+			unsigned addr = P+bank;
+			CDMapResult ret = { eCDLog_AddrType_ROM, addr };
+			return ret;
+		}
+		else if(P<0xA000) {}
+		else if(P<0xC000)
+		{
+			if(cart.wsrambankptr())
+			{
+				//not bankable
+				unsigned addr = P&0x1FFF;
+				CDMapResult ret = { eCDLog_AddrType_CartRAM, addr };
+				return ret;
+			}
+		}
+		else if(P<0xE000)
+		{
+			unsigned bank = cart.wramdata(P >> 12 & 1) - cart.wramdata(0);
+			unsigned addr = (P&0xFFF)+bank;
+			CDMapResult ret = { eCDLog_AddrType_WRAM, addr };
+			return ret;
+		}
+		else if(P<0xFF80) {}
+		else 
+		{
+			////this is just for debugging, really, it's pretty useless
+			//CDMapResult ret = { eCDLog_AddrType_HRAM, (P-0xFF80) };
+			//return ret;
+		}
+
+		CDMapResult ret = { eCDLog_AddrType_None };
+		return ret;
+	}
+
+
 	unsigned read(const unsigned P, const unsigned long cycleCounter) {
 		if (readCallback)
 			readCallback(P);
+		if(cdCallback)
+		{
+			CDMapResult map = CDMap(P);
+			if(map.type != eCDLog_AddrType_None)
+				cdCallback(map.addr,map.type,eCDLog_Flags_Data);
+		}
 		return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
 	}
 
-	unsigned read_excb(const unsigned P, const unsigned long cycleCounter) {
+	unsigned read_excb(const unsigned P, const unsigned long cycleCounter, bool first) {
 		if (execCallback)
 			execCallback(P);
+		if(cdCallback)
+		{
+			CDMapResult map = CDMap(P);
+			if(map.type != eCDLog_AddrType_None)
+				cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand);
+		}
 		return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
 	}
 
@@ -147,6 +212,12 @@ public:
 			nontrivial_write(P, data, cycleCounter);
 		if (writeCallback)
 			writeCallback(P);
+		if(cdCallback)
+		{
+			CDMapResult map = CDMap(P);
+			if(map.type != eCDLog_AddrType_None)
+				cdCallback(map.addr,map.type,eCDLog_Flags_Data);
+		}
 	}
 	
 	void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
@@ -154,6 +225,12 @@ public:
 			ioamhram[P - 0xFE00] = data;
 		} else
 			nontrivial_ff_write(P, data, cycleCounter);
+		if(cdCallback)
+		{
+			CDMapResult map = CDMap(P);
+			if(map.type != eCDLog_AddrType_None)
+				cdCallback(map.addr,map.type,eCDLog_Flags_Data);
+		}
 	}
 
 	unsigned long event(unsigned long cycleCounter);
@@ -174,6 +251,9 @@ public:
 	void setExecCallback(void (*callback)(unsigned)) {
 		this->execCallback = callback;
 	}
+	void setCDCallback(CDCallback cdc) {
+		this->cdCallback = cdc;
+	}
 
 	void setScanlineCallback(void (*callback)(), int sl) {
 		display.setScanlineCallback(callback, sl);
diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll
index 381b65d829..bb85ac5da6 100644
Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ