diff --git a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Disassembler.cs b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Disassembler.cs
index f03b8a709f..602b1c3fb4 100644
--- a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Disassembler.cs
+++ b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Disassembler.cs
@@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 	/// <summary>
 	/// Disassembler
 	/// </summary>
-	public sealed partial class F3850 : IDisassemblable
+	public sealed partial class F3850<TLink> : IDisassemblable
 	{
 		private static string Result(string format, Func<ushort, byte> read, ref ushort addr)
 		{
diff --git a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Execute.cs b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Execute.cs
index eec20ccda7..bc33c352d5 100644
--- a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Execute.cs
+++ b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Execute.cs
@@ -2,7 +2,7 @@
 
 namespace BizHawk.Emulation.Cores.Components.FairchildF8
 {
-	public sealed partial class F3850
+	public sealed partial class F3850<TLink>
 	{
 		public const int MaxInstructionLength = 48;
 
diff --git a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Operations.cs b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Operations.cs
index 37fee2bce7..090d5ee2ff 100644
--- a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Operations.cs
+++ b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Operations.cs
@@ -5,21 +5,21 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 	/// <summary>
 	/// ALU Operations
 	/// </summary>
-	public sealed partial class F3850
+	public sealed partial class F3850<TLink>
 	{
 		public void Read_Func(byte dest, byte src_l, byte src_h)
 		{
-			Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
+			Regs[dest] = _link.ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8));
 		}
 
 		public void Write_Func(byte dest_l, byte dest_h, byte src)
 		{
-			WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), Regs[src]);
+			_link.WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), Regs[src]);
 		}
 
 		public void IN_Func(byte dest, byte src)
 		{
-			Regs[dest] = ReadHardware(Regs[src]);
+			Regs[dest] = _link.ReadHardware(Regs[src]);
 		}
 
 		/// <summary>
@@ -48,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 		{
 			// data is complemented between accumulator and I/O pins (because PINs are active-low)
 			// however for ease here we will make them active-high
-			WriteHardware(Regs[dest], Regs[src]);
+			_link.WriteHardware(Regs[dest], Regs[src]);
 		}
 
 		public void ClearFlags_Func()
diff --git a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Registers.cs b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Registers.cs
index dfae8a6e33..f3b1af4d1c 100644
--- a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Registers.cs
+++ b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Registers.cs
@@ -7,7 +7,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 	/// <summary>
 	/// Internal Registers
 	/// </summary>
-	public sealed partial class F3850
+	public sealed partial class F3850<TLink>
 	{
 		/// <summary>
 		/// Registers (counters and scratchpad)
diff --git a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Tables.cs b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Tables.cs
index 45fcba1e01..370bd5839a 100644
--- a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Tables.cs
+++ b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.Tables.cs
@@ -3,7 +3,7 @@
 	/// <summary>
 	/// Vectors of Instruction Operations
 	/// </summary>
-	public sealed partial class F3850
+	public sealed partial class F3850<TLink>
 	{
 		/// <summary>
 		/// LR - LOAD REGISTER 
diff --git a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.cs b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.cs
index 23d0ce1f01..c799cd0667 100644
--- a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.cs
+++ b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/F3850.cs
@@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 	///
 	/// Note: Programmable timer and interrupt logic from the F3851 is not currently emulated
 	/// </summary>
-	public sealed partial class F3850
+	public sealed partial class F3850<TLink> where TLink : IF3850Link
 	{
 		// operations that can take place in an instruction
 		public const byte ROMC_01 = 1;
@@ -100,8 +100,11 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 		public const byte OP_DS = 157;
 		public const byte OP_LIS = 158;
 
-		public F3850()
+		private readonly TLink _link;
+
+		public F3850(TLink link)
 		{
+			_link = link;
 			Reset();
 		}
 
@@ -133,36 +136,6 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 
 		public IMemoryCallbackSystem MemoryCallbacks { get; set; }
 
-		// Memory Access 
-		public Func<ushort, byte> ReadMemory;
-		public Action<ushort, byte> WriteMemory;
-		public Func<ushort, byte> PeekMemory;
-		public Func<ushort, byte> DummyReadMemory;
-
-		// Hardware I/O Port Access
-		public Func<ushort, byte> ReadHardware;
-		public Action<ushort, byte> WriteHardware;
-
-		public Action<ushort> OnExecFetch;
-
-		public void SetCallbacks
-		(
-			Func<ushort, byte> ReadMemory,
-			Func<ushort, byte> DummyReadMemory,
-			Func<ushort, byte> PeekMemory,
-			Action<ushort, byte> WriteMemory,
-			Func<ushort, byte> ReadHardware,
-			Action<ushort, byte> WriteHardware
-		)
-		{
-			this.ReadMemory = ReadMemory;
-			this.DummyReadMemory = DummyReadMemory;
-			this.PeekMemory = PeekMemory;
-			this.WriteMemory = WriteMemory;
-			this.ReadHardware = ReadHardware;
-			this.WriteHardware = WriteHardware;
-		}
-
 		/// <summary>
 		/// Runs a single CPU clock cycle
 		/// </summary>
@@ -180,7 +153,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 			{
 				// always the last tick within an opcode instruction cycle
 				case END:
-					OnExecFetch?.Invoke(RegPC0);
+					_link.OnExecFetch(RegPC0);
 					TraceCallback?.Invoke(State());
 					opcode = Regs[DB];
 					instr_pntr = 0;
@@ -785,12 +758,12 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 		{
 			int bytes_read = 0;
 			ushort pc = (ushort)(RegPC0 - 1);
-			string disasm = disassemble ? Disassemble(pc, ReadMemory, out bytes_read) : "---";
+			string disasm = disassemble ? Disassemble(pc, _link.ReadMemory, out bytes_read) : "---";
 			string byte_code = null;
 
 			for (ushort i = 0; i < bytes_read; i++)
 			{
-				byte_code += ReadMemory((ushort)(pc + i)).ToString("X2");
+				byte_code += _link.ReadMemory((ushort)(pc + i)).ToString("X2");
 				if (i < (bytes_read - 1))
 				{
 					byte_code += " ";
@@ -868,7 +841,7 @@ namespace BizHawk.Emulation.Cores.Components.FairchildF8
 
 		public void SyncState(Serializer ser)
 		{
-			ser.BeginSection(nameof(F3850));
+			ser.BeginSection("F3850");
 			ser.Sync(nameof(Regs), ref Regs, false);
 			ser.Sync(nameof(cur_instr), ref cur_instr, false);
 			ser.Sync(nameof(instr_pntr), ref instr_pntr);
diff --git a/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/IF3850Link.cs b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/IF3850Link.cs
new file mode 100644
index 0000000000..d6ed7d0683
--- /dev/null
+++ b/src/BizHawk.Emulation.Cores/CPUs/FairchildF8/IF3850Link.cs
@@ -0,0 +1,19 @@
+namespace BizHawk.Emulation.Cores.Components.FairchildF8
+{
+	// Interface that has all the methods required by the F3850 to talk to
+	// the emulator core.
+	// Should only be used as a generic type argument for the F3850, and
+	// implementations should be structs where possible. This combination allows
+	// the JITer to generate much faster code than calling a Func<> or Action<>.
+	public interface IF3850Link
+	{
+		byte ReadMemory(ushort address);
+		void WriteMemory(ushort address, byte value);
+
+		byte ReadHardware(ushort address);
+		void WriteHardware(ushort address, byte value);
+
+		// This only calls when the first byte of an instruction is fetched.
+		void OnExecFetch(ushort address);
+	}
+}
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_HANG.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperHANG.cs
similarity index 63%
rename from src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_HANG.cs
rename to src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperHANG.cs
index 98805ba4f7..1051e0f587 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_HANG.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperHANG.cs
@@ -2,36 +2,29 @@
 {
 	/// <summary>
 	/// Hangman ChannelF Cartridge
-	/// 2KB ROM / NO RAM
+	/// Utilises 2102 SRAM over IO
 	/// </summary>
-	public class mapper_HANG : VesCartBase
+	public class MapperHANG : VesCartBase
 	{
 		public override string BoardType => "HANG";
 
-		public mapper_HANG(byte[] rom)
+		public MapperHANG(byte[] rom)
 		{
-			ROM = new byte[0x10000 - 0x800];
-			for (int i = 0; i < rom.Length; i++)
-			{
-				ROM[i] = rom[i];
-				if (i > 3000)
-				{
-					var test = rom[i];
-				}
-			}
-
-			RAM = new byte[0x400];
+			_rom = new byte[0x10000 - 0x800];
+			Array.Copy(rom, _rom, rom.Length);
+			_rom.AsSpan(rom.Length).Fill(0xFF);
+			_ram = new byte[0x400];
 		}
 
 		public override byte ReadBus(ushort addr)
 		{
 			var off = addr - 0x800;
-			return ROM[off];
+			return _rom[off];
 		}
 
 		public override void WriteBus(ushort addr, byte value)
 		{
-			// no writeable memory
+			// no directly writeable memory
 		}
 
 		public override byte ReadPort(ushort addr)
@@ -45,6 +38,5 @@
 			var index = addr - 0x20;
 			SRAM2102_Write(index, data);
 		}
-
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_MAZE.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperMAZE.cs
similarity index 62%
rename from src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_MAZE.cs
rename to src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperMAZE.cs
index 79eab02e6f..a21e08bcc2 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_MAZE.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperMAZE.cs
@@ -1,27 +1,25 @@
 namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 {
 	/// <summary>
-	/// ChannelF Cartridge that utilises 2102 SRAM over IO
+	/// Maze ChannelF Cartridge
+	/// Utilises 2102 SRAM over IO
 	/// </summary>
-	public class mapper_MAZE : VesCartBase
+	public class MapperMAZE : VesCartBase
 	{
 		public override string BoardType => "MAZE";
 
-		public mapper_MAZE(byte[] rom)
+		public MapperMAZE(byte[] rom)
 		{
-			ROM = new byte[0x10000 - 0x800];
-			for (int i = 0; i < rom.Length; i++)
-			{
-				ROM[i] = rom[i];
-			}
-
-			RAM = new byte[0x400];
+			_rom = new byte[0x10000 - 0x800];
+			Array.Copy(rom, _rom, rom.Length);
+			_rom.AsSpan(rom.Length).Fill(0xFF);
+			_ram = new byte[0x400];
 		}
 
 		public override byte ReadBus(ushort addr)
 		{
 			var off = addr - 0x800;
-			return ROM[off];
+			return _rom[off];
 		}
 
 		public override void WriteBus(ushort addr, byte value)
@@ -38,7 +36,7 @@
 		public override void WritePort(ushort addr, byte data)
 		{
 			var index = addr - 0x24;
-			SRAM2102_Write(index, data);			
+			SRAM2102_Write(index, data);
 		}
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_RIDDLE.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperRIDDLE.cs
similarity index 63%
rename from src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_RIDDLE.cs
rename to src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperRIDDLE.cs
index 8330f555b9..a1f620193f 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_RIDDLE.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperRIDDLE.cs
@@ -3,19 +3,15 @@
 	/// <summary>
 	/// Sean Riddle's modified SCHACH cart mapper (multi-cart) (WIP)
 	/// </summary>
-	public class mapper_RIDDLE : VesCartBase
+	public class MapperRIDDLE : VesCartBase
 	{
 		public override string BoardType => "RIDDLE";
 
-		public mapper_RIDDLE(byte[] rom)
+		public MapperRIDDLE(byte[] rom)
 		{
-			ROM = new byte[rom.Length];
-			for (int i = 0; i < rom.Length; i++)
-			{
-				ROM[i] = rom[i];
-			}
-
-			RAM = new byte[0x800];
+			_rom = new byte[rom.Length];
+			Array.Copy(rom, _rom, rom.Length);
+			_ram = new byte[0x800];
 		}
 
 		public override byte ReadBus(ushort addr)
@@ -23,15 +19,15 @@
 			var result = 0xFF;
 			var off = addr - 0x800;
 
-			if (addr >= 0x2800 && addr < 0x3000)
+			if (addr is >= 0x2800 and < 0x3000)
 			{
 				// 2KB RAM
-				result = RAM[addr - 0x2800];
+				result = _ram[addr - 0x2800];
 			}
 			else
 			{
-				if (off < ROM.Length)
-					result = ROM[off + (MultiBank * 0x2000) + (MultiHalfBank * 0x1000)];
+				if (off < _rom.Length)
+					result = _rom[off + (MultiBank * 0x2000) + (MultiHalfBank * 0x1000)];
 			}
 
 			return (byte)result;
@@ -40,9 +36,9 @@
 		public override void WriteBus(ushort addr, byte value)
 		{
 			// 2KB writeable memory at 0x2800;
-			if (addr >= 0x2800 && addr < 0x3000)
+			if (addr is >= 0x2800 and < 0x3000)
 			{
-				RAM[addr - 0x2800] = value;
+				_ram[addr - 0x2800] = value;
 			}
 			else if (addr == 0x3000)
 			{
@@ -50,16 +46,10 @@
 				MultiBank = value & 0x1F;
 				MultiHalfBank = (value & 0x20) >> 5;
 			}
-			else
-			{
-				
-			}
 		}
 
 		public override byte ReadPort(ushort addr)
-		{
-			return 0xFF;
-		}
+			=> 0xFF;
 
 		public override void WritePort(ushort addr, byte data)
 		{
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_SCHACH.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperSCHACH.cs
similarity index 64%
rename from src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_SCHACH.cs
rename to src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperSCHACH.cs
index c1ac910789..49342f4f9a 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_SCHACH.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperSCHACH.cs
@@ -5,48 +5,42 @@
 	/// Any size ROM / 2KB RAM mapped at 0x2800 - 0x2FFF
 	/// Info here: http://www.seanriddle.com/chanfmulti.html
 	/// </summary>
-	public class mapper_SCHACH : VesCartBase
+	public class MapperSCHACH : VesCartBase
 	{
 		public override string BoardType => "SCHACH";
 		public override bool HasActivityLED => true;
 		public override string ActivityLEDDescription => "Chess Brain Thinking Activity";
 
-		public mapper_SCHACH(byte[] rom)
+		public MapperSCHACH(byte[] rom)
 		{
-			ROM = new byte[0x10000 - 0x800];
-			for (int i = 0; i < rom.Length; i++)
-			{
-				ROM[i] = rom[i];
-			}
-
-			RAM = new byte[0x800];
+			_rom = new byte[0x10000 - 0x800];
+			Array.Copy(rom, _rom, rom.Length);
+			_rom.AsSpan(rom.Length).Fill(0xFF);
+			_ram = new byte[0x800];
 		}
 
 		public override byte ReadBus(ushort addr)
 		{
-			var result = 0xFF;
-			var off = addr - 0x800;
-
-			if (addr >= 0x2800 && addr < 0x3000)
+			byte result;
+			if (addr is >= 0x2800 and < 0x3000)
 			{
 				// 2KB RAM
-				result = RAM[addr - 0x2800];
+				result = _ram[addr - 0x2800];
 			}
 			else
 			{
-				if (off < ROM.Length)
-					result = ROM[off];
+				result = _rom[addr - 0x800];
 			}
 
-			return (byte)result;
+			return result;
 		}
 
 		public override void WriteBus(ushort addr, byte value)
 		{
 			// 2KB writeable memory at 0x2800;
-			if (addr >= 0x2800 && addr < 0x3000)
+			if (addr is >= 0x2800 and < 0x3000)
 			{
-				RAM[addr - 0x2800] = value;
+				_ram[addr - 0x2800] = value;
 			}
 			else if (addr == 0x3800)
 			{
@@ -59,9 +53,7 @@
 		}
 
 		public override byte ReadPort(ushort addr)
-		{
-			return 0xFF;
-		}
+			=> 0xFF;
 
 		public override void WritePort(ushort addr, byte data)
 		{
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_STD.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperSTD.cs
similarity index 63%
rename from src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_STD.cs
rename to src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperSTD.cs
index 03aae45a39..80d777a445 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/mapper_STD.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/MapperSTD.cs
@@ -4,28 +4,22 @@
 	/// Standard ChannelF Cartridge
 	/// 2KB ROM / NO RAM
 	/// </summary>
-	public class mapper_STD : VesCartBase
+	public class MapperSTD : VesCartBase
 	{
 		public override string BoardType => "STD";
 
-		public mapper_STD(byte[] rom)
+		public MapperSTD(byte[] rom)
 		{
-			ROM = new byte[0x10000 - 0x800];
-			for (int i = 0; i < rom.Length; i++)
-			{
-				ROM[i] = rom[i];
-			}
-
-			RAM = new byte[0];
+			_rom = new byte[0x10000 - 0x800];
+			Array.Copy(rom, _rom, rom.Length);
+			_rom.AsSpan(rom.Length).Fill(0xFF);
+			_ram = [ ];
 		}
 
 		public override byte ReadBus(ushort addr)
 		{
 			var off = addr - 0x800;
-			if (off < ROM.Length)
-				return ROM[off];
-			else
-				return 0xFF;
+			return _rom[off];
 		}
 
 		public override void WriteBus(ushort addr, byte value)
@@ -34,9 +28,7 @@
 		}
 
 		public override byte ReadPort(ushort addr)
-		{
-			return 0xFF;
-		}
+			=> 0xFF;
 
 		public override void WritePort(ushort addr, byte data)
 		{
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/VesCartBase.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/VesCartBase.cs
index 5f55044081..4ccc57f2bf 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/VesCartBase.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Cart/VesCartBase.cs
@@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 {
 	public abstract class VesCartBase
 	{
-		public abstract string BoardType { get; }	
+		public abstract string BoardType { get; }
 
 		public virtual void SyncByteArrayDomain(ChannelF sys)
 		{
@@ -19,23 +19,11 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 			}
 		}
 
-		public virtual byte[] ROM
-		{
-			get { return _rom; }
-			protected set { _rom = value; }
-		}
-		protected byte[] _rom;		
-
-		public virtual byte[] RAM
-		{
-			get { return _ram; }
-			protected set { _ram = value; }
-		}
+		protected byte[] _rom;
 		protected byte[] _ram;
 
 		public virtual bool HasActivityLED { get; set; }
 		public virtual string ActivityLEDDescription { get; set; }
-		
 
 		public bool ActivityLED;
 		public int MultiBank;
@@ -58,38 +46,36 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		public static VesCartBase Configure(GameInfo gi, byte[] rom)
 		{
 			// get board type
-			string boardStr = gi.OptionPresent("board") ? gi.GetStringValue("board") : "STD";
-
+			var boardStr = gi.OptionPresent("board") ? gi.GetStringValue("board") : "STD";
 			switch (boardStr)
 			{
 				// The supplied ROM is actually a BIOS
 				case "BIOS":
 					// we can just pass the rom into channel f and because it does not detect a 0x55 at rom[0] it will just jump straight to onboard games
 					// (hockey and tennis)
-					return new mapper_STD(rom);
+					return new MapperSTD(rom);
 
 				// standard cart layout
-				case "STD":				
+				case "STD":
 					// any number of F3851 Program Storage Units (1KB ROM each) or F3856 Program Storage Unit (2KB ROM)
 					// no on-pcb RAM and no extra IO
-					return new mapper_STD(rom);
+					return new MapperSTD(rom);
 
 				case "MAZE":
-					return new mapper_MAZE(rom);
+					return new MapperMAZE(rom);
 
 				case "RIDDLE":
 					// Sean Riddle's modified SCHACH multi-cart
-					return new mapper_RIDDLE(rom);
+					return new MapperRIDDLE(rom);
 
 				case "SCHACH":
 				default:
 					// F3853 Memory Interface Chip, 6KB of ROM and 2KB of RAM
 					//  - default to this
-					return new mapper_SCHACH(rom);
+					return new MapperSCHACH(rom);
 
 				case "HANG":
-
-					return new mapper_HANG(rom);
+					return new MapperHANG(rom);
 			}
 		}
 
@@ -106,7 +92,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 				if (m_read_write == 0)
 				{
 					m_addr = m_addr_latch;
-					m_data0 = RAM[m_addr] & 1;
+					m_data0 = _ram[m_addr] & 1;
 					return (byte)((m_latch[0] & 0x7f) | (m_data0 << 7));
 				}
 
@@ -141,8 +127,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 				if (m_read_write == 1)
 				{
-					RAM[m_addr] = (byte)m_data0;
-				}					
+					_ram[m_addr] = (byte)m_data0;
+				}
 			}
 			else
 			{
@@ -171,7 +157,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 				b.CopyTo(resBytes, 0);
 				m_addr_latch = (ushort)(resBytes[0] | resBytes[1] << 8);
 			}
-		}		
+		}
 
 		public virtual void Reset()
 		{
@@ -187,7 +173,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		public virtual void SyncState(Serializer ser)
 		{
 			ser.BeginSection("Cart");
-			ser.Sync(nameof(RAM), ref _ram, false);
+			ser.Sync(nameof(_ram), ref _ram, false);
 			ser.Sync(nameof(m_latch), ref m_latch, false);
 			ser.Sync(nameof(m_addr_latch), ref m_addr_latch);
 			ser.Sync(nameof(m_addr), ref m_addr);
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.Controllers.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.Controllers.cs
index d4e91def2c..dd335bad0f 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.Controllers.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.Controllers.cs
@@ -1,117 +1,116 @@
-using System.Collections.Generic;
-
-using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Common;
 
 namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 {
 	public partial class ChannelF
 	{
-		public ControllerDefinition ChannelFControllerDefinition
+		private static readonly Lazy<ControllerDefinition> _channelFControllerDefinition = new(() =>
 		{
-			get
+			ControllerDefinition definition = new("ChannelF Controller");
+
+			// sticks
+
+			const string P1_PREFIX = "P1 ";
+			string[] stickR =
+			[
+				// P1 (right) stick
+				P1_PREFIX + "Forward", P1_PREFIX + "Back", P1_PREFIX + "Left", P1_PREFIX + "Right", P1_PREFIX + "CCW", P1_PREFIX + "CW", P1_PREFIX + "Pull", P1_PREFIX + "Push"
+			];
+
+			foreach (var s in stickR)
 			{
-				ControllerDefinition definition = new("ChannelF Controller");
-
-				string pre = "P1 ";
-
-				// sticks
-				var stickR = new List<string>
-				{
-					// P1 (right) stick
-					pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
-				};
-
-				foreach (var s in stickR)
-				{
-					definition.BoolButtons.Add(s);
-					definition.CategoryLabels[s] = "Right Controller";
-				}
-
-				pre = "P2 ";
-
-				var stickL = new List<string>
-				{
-					// P2 (left) stick
-					pre + "Forward", pre + "Back", pre + "Left", pre + "Right", pre + "CCW", pre + "CW", pre + "Pull", pre + "Push"
-				};
-
-				foreach (var s in stickL)
-				{
-					definition.BoolButtons.Add(s);
-					definition.CategoryLabels[s] = "Left Controller";
-				}
-
-				// console
-				var consoleButtons = new List<string>
-				{
-					"TIME", "MODE", "HOLD", "START", "RESET"
-				};
-
-				foreach (var s in consoleButtons)
-				{
-					definition.BoolButtons.Add(s);
-					definition.CategoryLabels[s] = "Console";
-				}
-
-				return definition.MakeImmutable();
+				definition.BoolButtons.Add(s);
+				definition.CategoryLabels[s] = "Right Controller";
 			}
-		}
 
-		public bool[] StateConsole = new bool[5];
-		public string[] ButtonsConsole =
-		{
+			const string P2_PREFIX = "P2 ";
+			string[] stickL =
+			[
+				// P2 (left) stick
+				P2_PREFIX + "Forward", P2_PREFIX + "Back", P2_PREFIX + "Left", P2_PREFIX + "Right", P2_PREFIX + "CCW", P2_PREFIX + "CW", P2_PREFIX + "Pull", P2_PREFIX + "Push"
+			];
+
+			foreach (var s in stickL)
+			{
+				definition.BoolButtons.Add(s);
+				definition.CategoryLabels[s] = "Left Controller";
+			}
+
+			// console
+			string[] consoleButtons =
+			[
+				"TIME", "MODE", "HOLD", "START", "RESET"
+			];
+
+			foreach (var s in consoleButtons)
+			{
+				definition.BoolButtons.Add(s);
+				definition.CategoryLabels[s] = "Console";
+			}
+
+			return definition.MakeImmutable();
+		});
+
+		private readonly string[] _buttonsConsole =
+		[
 			"TIME", "MODE", "HOLD", "START", "RESET"
-		};
+		];
 
-		public byte DataConsole
+		private bool[] _stateConsole = new bool[5];
+
+		private byte DataConsole
 		{
 			get
 			{
-				int w = 0;
-				for (int i = 0; i < 5; i++)
+				var w = 0;
+				for (var i = 0; i < 5; i++)
 				{
-					byte mask = (byte) (1 << i);
-					w = StateConsole[i] ? w | mask : w & ~mask;
+					var mask = (byte)(1 << i);
+					w = _stateConsole[i] ? w | mask : w & ~mask;
 				}
 
 				return (byte)(w & 0xFF);
 			}
 		}
 
-		public bool[] StateRight = new bool[8];
-		public string[] ButtonsRight =
-		{
-			"Right", "Left", "Back", "Forward", "CCW", "CW", "Pull", "Push"
-		};
-		public byte DataRight
+		private bool[] _stateRight = new bool[8];
+
+		private readonly string[] _buttonsRight =
+		[
+			"P1 Right", "P1 Left", "P1 Back", "P1 Forward", "P1 CCW", "P1 CW", "P1 Pull", "P1 Push"
+		];
+
+		private byte DataRight
 		{
 			get
 			{
-				int w = 0;
-				for (int i = 0; i < 8; i++)
+				var w = 0;
+				for (var i = 0; i < 8; i++)
 				{
-					byte mask = (byte)(1 << i);
-					w = StateRight[i] ? w | mask : w & ~mask;
+					var mask = (byte)(1 << i);
+					w = _stateRight[i] ? w | mask : w & ~mask;
 				}
 
 				return (byte)(w & 0xFF);
 			}
 		}
 
-		public bool[] StateLeft = new bool[8];
-		public string[] ButtonsLeft =
-		{
-			"Right", "Left", "Back", "Forward", "CCW", "CW", "Pull", "Push"
-		};
-		public byte DataLeft
+		private bool[] _stateLeft = new bool[8];
+
+		private readonly string[] _buttonsLeft =
+		[
+			"P2 Right", "P2 Left", "P2 Back", "P2 Forward", "P2 CCW", "P2 CW", "P2 Pull", "P2 Push"
+		];
+
+		private byte DataLeft
 		{
 			get
 			{
-				int w = 0;
-				for (int i = 0; i < 8; i++)
+				var w = 0;
+				for (var i = 0; i < 8; i++)
 				{
-					byte mask = (byte)(1 << i);
-					w = StateLeft[i] ? w | mask : w & ~mask;
+					var mask = (byte)(1 << i);
+					w = _stateLeft[i] ? w | mask : w & ~mask;
 				}
 
 				return (byte)(w & 0xFF);
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.CpuLink.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.CpuLink.cs
new file mode 100644
index 0000000000..f470f1d46c
--- /dev/null
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.CpuLink.cs
@@ -0,0 +1,27 @@
+using BizHawk.Emulation.Cores.Components.FairchildF8;
+
+namespace BizHawk.Emulation.Cores.Consoles.ChannelF
+{
+	public partial class ChannelF
+	{
+		public readonly struct CpuLink(ChannelF channelF) : IF3850Link
+		{
+			public byte ReadMemory(ushort address)
+				=> channelF.ReadBus(address);
+
+			public void WriteMemory(ushort address, byte value)
+				=> channelF.WriteBus(address, value);
+
+			public byte ReadHardware(ushort address)
+				=> channelF.ReadPort(address);
+
+			public void WriteHardware(ushort address, byte value)
+				=> channelF.WritePort(address, value);
+
+			public void OnExecFetch(ushort address)
+			{
+				// TODO: implement
+			}
+		}
+	}
+}
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IDebuggable.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IDebuggable.cs
index 254f197a4c..29cad4e5d8 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IDebuggable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IDebuggable.cs
@@ -7,10 +7,10 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 	public partial class ChannelF : IDebuggable
 	{
 		public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
-			=> CPU.GetCpuFlagsAndRegisters();
+			=> _cpu.GetCpuFlagsAndRegisters();
 
 		public void SetCpuRegister(string register, int value)
-			=> CPU.SetCpuRegister(register, value);
+			=> _cpu.SetCpuRegister(register, value);
 
 		public IMemoryCallbackSystem MemoryCallbacks { get; }
 
@@ -19,6 +19,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		[FeatureNotImplemented]
 		public void Step(StepType type) => throw new NotImplementedException();
 
-		public long TotalExecutedCycles => CPU.TotalExecutedCycles;
+		public long TotalExecutedCycles => _cpu.TotalExecutedCycles;
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IEmulator.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IEmulator.cs
index 8084f7e818..061883d3a7 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IEmulator.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IEmulator.cs
@@ -6,21 +6,20 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 	{
 		public IEmulatorServiceProvider ServiceProvider { get; }
 
-		public ControllerDefinition ControllerDefinition { get; set; }
+		public ControllerDefinition ControllerDefinition { get; }
 
 		public string SystemId => VSystemID.Raw.ChannelF;
 
-		public bool DeterministicEmulation { get; set; }
+		public bool DeterministicEmulation => true;
 
-		public int CpuClocksPerFrame;
-		public int FrameClock;
+		private int _cpuClocksPerFrame;
+		private int _frameClock;
 
 		private void CalcClock()
 		{
 			// CPU speeds from https://en.wikipedia.org/wiki/Fairchild_Channel_F
 			// also https://github.com/mamedev/mame/blob/c8192c898ce7f68c0c0b87e44199f0d3e710439b/src/mame/drivers/channelf.cpp
 			double cpuFreq, pixelClock;
-			int pixelClocksPerFrame;
 			if (Region == DisplayType.NTSC)
 			{
 				HTotal = 256;
@@ -37,8 +36,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 				cpuFreq = NTSC_COLORBURST / 2;
 				// NTSC pixel clock is NTSC Colorburst * 8 / 7
 				pixelClock = NTSC_COLORBURST * 8 / 7;
-				// NTSC refresh rate is (pixelclock * 8 / 7) / (256 * 264)
-				pixelClocksPerFrame = 256 * 264;
+				// NTSC refresh rate is (pixelclock * 8 / 7) / (HTotal * VTotal)
 				// (aka (1023750000 * 8) / (256 * 264 * 286 * 7)
 				// reduced to 234375 / 3872
 				VsyncNumerator = 234375;
@@ -55,19 +53,18 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 				ScanlineRepeats = 5;
 				PixelWidth = 2;
 
-				if (version == ConsoleVersion.ChannelF)
+				if (_version == ConsoleVersion.ChannelF)
 				{
 					// PAL CPU speed is 2MHz
 					cpuFreq = 2000000;
 					// PAL pixel clock is 4MHz
 					pixelClock = 4000000;
-					// PAL refresh rate is pixelclock / (256 * 312)
-					pixelClocksPerFrame = 256 * 312;
+					// PAL refresh rate is pixelclock / (HTotal * VTotal)
 					// reduced to 15625 / 312
 					VsyncNumerator = 15625;
 					VsyncDenominator = 312;
 				}
-				else if (version == ConsoleVersion.ChannelF_II)
+				else if (_version == ConsoleVersion.ChannelF_II)
 				{
 					// PAL CPU speed for gen 2 seems to be contested
 					// various sources seem to say 1.77MHz (i.e. PAL Colorburst * 2 / 5)
@@ -81,8 +78,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 					// not entirely sure what the pixel clock for PAL is here
 					// presumingly, it's just cpuFreq * 2?
 					pixelClock = PAL_COLORBURST * 8 / 9;
-					// PAL refresh rate is pixelclock / (256 * 312)
-					pixelClocksPerFrame = 256 * 312;
+					// PAL refresh rate is pixelclock / (HTotal * VTotal)
 					// (aka (4433618.75 * 8) / (256 * 312 * 9)
 					// reduced to 17734475 / 359424
 					VsyncNumerator = 17734475;
@@ -94,10 +90,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 				}
 			}
 
-			var c = cpuFreq * pixelClocksPerFrame / pixelClock;
-			CpuClocksPerFrame = (int) c;
 			PixelClocksPerCpuClock = pixelClock / cpuFreq;
-			PixelClocksPerFrame = pixelClocksPerFrame;
+			PixelClocksPerFrame = HTotal * VTotal;
+
+			var c = cpuFreq * PixelClocksPerFrame / pixelClock;
+			// note: this always results in a nice integer, no precision is lost!
+			_cpuClocksPerFrame = (int)c;
 
 			SetupAudio();
 		}
@@ -109,22 +107,22 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 			if (_tracer.IsEnabled())
 			{
-				CPU.TraceCallback = s => _tracer.Put(s);
+				_cpu.TraceCallback = s => _tracer.Put(s);
 			}
 			else
 			{
-				CPU.TraceCallback = null;
+				_cpu.TraceCallback = null;
 			}
 
 			PollInput();
 
-			while (FrameClock++ < CpuClocksPerFrame)
+			while (_frameClock++ < _cpuClocksPerFrame)
 			{
-				CPU.ExecuteOne();
+				_cpu.ExecuteOne();
 				ClockVideo();
 			}
 
-			FrameClock = 0;
+			_frameClock = 0;
 			_frame++;
 
 			if (_isLag)
@@ -134,10 +132,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		}
 
 		private int _frame;
-#pragma warning disable CS0414
-		//private int _lagcount;
-		//private bool _islag;
-#pragma warning restore CS0414
 
 		public void ResetCounters()
 		{
@@ -154,8 +148,8 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 		private void ConsoleReset()
 		{
-			CPU.Reset();
-			Cartridge.Reset();
+			_cpu.Reset();
+			_cartridge.Reset();
 		}
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.ISettable.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.ISettable.cs
index da4b8a3740..98af9cd565 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.ISettable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.ISettable.cs
@@ -25,38 +25,6 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 			return ret ? PutSettingsDirtyBits.RebootCore : PutSettingsDirtyBits.None;
 		}
 
-		[CoreSettings]
-		public class ChannelFSyncSettings
-		{
-			[DisplayName("Deterministic Emulation")]
-			[Description("If true, the core agrees to behave in a completely deterministic manner")]
-			[DefaultValue(true)]
-			public bool DeterministicEmulation { get; set; }
-			[DisplayName("Region")]
-			[Description("NTSC or PAL - Affects the CPU clock speed and refresh rate")]
-			[DefaultValue(RegionType.NTSC)]
-			public RegionType Region { get; set; }
-			[DisplayName("Version")]
-			[Description("Channel F II has a very slightly different BIOS to Channel F and a slightly slower CPU in the PAL version compared to v1")]
-			[DefaultValue(ConsoleVersion.ChannelF)]
-			public ConsoleVersion Version { get; set; }
-
-			public ChannelFSyncSettings Clone()
-			{
-				return (ChannelFSyncSettings) MemberwiseClone();
-			}
-
-			public ChannelFSyncSettings()
-			{
-				SettingsUtil.SetDefaultValues(this);
-			}
-
-			public static bool NeedsReboot(ChannelFSyncSettings x, ChannelFSyncSettings y)
-			{
-				return !DeepEquality.DeepEquals(x, y);
-			}
-		}
-
 		public enum RegionType
 		{
 			NTSC,
@@ -68,5 +36,28 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 			ChannelF,
 			ChannelF_II
 		}
+
+		[CoreSettings]
+		public class ChannelFSyncSettings
+		{
+			[DisplayName("Region")]
+			[Description("NTSC or PAL - Affects the CPU clock speed and refresh rate")]
+			[DefaultValue(RegionType.NTSC)]
+			public RegionType Region { get; set; }
+
+			[DisplayName("Version")]
+			[Description("Channel F II has a very slightly different BIOS to Channel F and a slightly slower CPU in the PAL version compared to v1")]
+			[DefaultValue(ConsoleVersion.ChannelF)]
+			public ConsoleVersion Version { get; set; }
+
+			public ChannelFSyncSettings Clone()
+				=> (ChannelFSyncSettings)MemberwiseClone();
+
+			public ChannelFSyncSettings()
+				=> SettingsUtil.SetDefaultValues(this);
+
+			public static bool NeedsReboot(ChannelFSyncSettings x, ChannelFSyncSettings y)
+				=> !DeepEquality.DeepEquals(x, y);
+		}
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.ISoundProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.ISoundProvider.cs
index 4384ac22ca..30b464c492 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.ISoundProvider.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.ISoundProvider.cs
@@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		{
 			_samplesPerFrame = (int)(SAMPLE_RATE * VsyncDenominator / VsyncNumerator);
 			// TODO: more precise audio clocking
-			_cyclesPerSample = CpuClocksPerFrame / (double)_samplesPerFrame;
+			_cyclesPerSample = _cpuClocksPerFrame / (double)_samplesPerFrame;
 			_sampleBuffer = new short[_samplesPerFrame];
 			_filteredSampleBuffer = new double[_samplesPerFrame];
 			_toneBuffer = new int[_samplesPerFrame];
@@ -37,8 +37,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 		private void AudioChange()
 		{
-			var currSample = (int)(FrameClock / _cyclesPerSample);
-
+			var currSample = (int)(_frameClock / _cyclesPerSample);
 			while (currSample < _samplesPerFrame)
 			{
 				_toneBuffer[currSample++] = _tone;
@@ -130,7 +129,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 			for (var i = 2; i < samples.Length; i++)
 			{
 				filteredSamples[i] = (b0 / a0) * samples[i] + (b1 / a0) * samples[i - 1] + (b2 / a0) * samples[i - 2]
-									 - (a1 / a0) * filteredSamples[i - 1] - (a2 / a0) * filteredSamples[i - 2];
+					- (a1 / a0) * filteredSamples[i - 1] - (a2 / a0) * filteredSamples[i - 2];
 			}
 
 			for (var i = 0; i < samples.Length; i++)
@@ -150,9 +149,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		}
 
 		public void GetSamplesAsync(short[] samples)
-		{
-			throw new NotSupportedException("Async is not available");
-		}
+			=> throw new NotSupportedException("Async is not available");
 
 		public void DiscardSamples()
 		{
@@ -166,7 +163,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 		public void GetSamplesSync(out short[] samples, out int nsamp)
 		{
-			// process tone buffer			
+			// process tone buffer
 			for (var t = 0; t < _toneBuffer.Length; t++)
 			{
 				var tValue = _toneBuffer[t];
@@ -189,7 +186,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 						_currTone = tValue;
 
 						if (_rampCounter <= 0)
-							_sampleBuffer[t] = (short)((GetWaveSample(_samplePosition++, _currTone) * _amplitude) / 30);						
+							_sampleBuffer[t] = (short)((GetWaveSample(_samplePosition++, _currTone) * _amplitude) / 30);
 					}
 				}
 				else if (_currTone > 0)
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IStatable.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IStatable.cs
index b20772fecd..6ab0cdf802 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IStatable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IStatable.cs
@@ -7,14 +7,14 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		private void SyncState(Serializer ser)
 		{
 			ser.BeginSection("ChannelF");
-			ser.Sync(nameof(VRAM), ref VRAM, false);
-			ser.Sync(nameof(_latch_colour), ref _latch_colour);
-			ser.Sync(nameof(_latch_x), ref _latch_x);
-			ser.Sync(nameof(_latch_y), ref _latch_y);
-			ser.Sync(nameof(_pixelClockCounter), ref _pixelClockCounter);	
+			ser.Sync(nameof(_vram), ref _vram, false);
+			ser.Sync(nameof(_latchColour), ref _latchColour);
+			ser.Sync(nameof(_latchX), ref _latchX);
+			ser.Sync(nameof(_latchY), ref _latchY);
+			ser.Sync(nameof(_pixelClockCounter), ref _pixelClockCounter);
 			ser.Sync(nameof(_pixelClocksRemaining), ref _pixelClocksRemaining);
 
-			ser.Sync(nameof(FrameClock), ref FrameClock);
+			ser.Sync(nameof(_frameClock), ref _frameClock);
 			ser.Sync(nameof(_frame), ref _frame);
 			ser.Sync(nameof(_isLag), ref _isLag);
 			ser.Sync(nameof(_lagCount), ref _lagCount);
@@ -30,75 +30,21 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 			ser.Sync(nameof(_currTone), ref _currTone);
 			ser.Sync(nameof(_samplePosition), ref _samplePosition);
 
-			ser.Sync(nameof(StateConsole), ref StateConsole, false);
-			ser.Sync(nameof(StateRight), ref StateRight, false);
-			ser.Sync(nameof(StateLeft), ref StateLeft, false);
+			ser.Sync(nameof(_stateConsole), ref _stateConsole, false);
+			ser.Sync(nameof(_stateRight), ref _stateRight, false);
+			ser.Sync(nameof(_stateLeft), ref _stateLeft, false);
 
-			ser.Sync(nameof(OutputLatch), ref OutputLatch, false);
+			ser.Sync(nameof(_outputLatch), ref _outputLatch, false);
 			ser.Sync(nameof(LS368Enable), ref LS368Enable);
 
-			//ser.Sync(nameof(ControllersEnabled), ref ControllersEnabled);
-			CPU.SyncState(ser);
-			Cartridge.SyncState(ser);
+			_cpu.SyncState(ser);
+			_cartridge.SyncState(ser);
 			ser.EndSection();
 
 			if (ser.IsReader)
 			{
 				SyncAllByteArrayDomains();
 			}
-
-			/*
-
-			byte[] core = null;
-			if (ser.IsWriter)
-			{
-				var ms = new MemoryStream();
-				ms.Close();
-				core = ms.ToArray();
-			}
-
-			if (ser.IsWriter)
-			{
-				ser.SyncEnum(nameof(_machineType), ref _machineType);
-
-				_cpu.SyncState(ser);
-				ser.BeginSection(nameof(ChannelF));
-				_machine.SyncState(ser);
-				ser.Sync("Frame", ref _machine.FrameCount);
-				ser.Sync("LagCount", ref _lagCount);
-				ser.Sync("IsLag", ref _isLag);
-				ser.EndSection();
-			}
-
-			if (ser.IsReader)
-			{
-				var tmpM = _machineType;
-				ser.SyncEnum(nameof(_machineType), ref _machineType);
-				if (tmpM != _machineType && _machineType.ToString() != "72")
-				{
-					string msg = "SAVESTATE FAILED TO LOAD!!\n\n";
-					msg += "Current Configuration: " + tmpM.ToString();
-					msg += "\n";
-					msg += "Saved Configuration:    " + _machineType.ToString();
-					msg += "\n\n";
-					msg += "If you wish to load this SaveState ensure that you have the correct machine configuration selected, reboot the core, then try again.";
-					CoreComm.ShowMessage(msg);
-					_machineType = tmpM;
-				}
-				else
-				{
-					_cpu.SyncState(ser);
-					ser.BeginSection(nameof(ChannelF));
-					_machine.SyncState(ser);
-					ser.Sync("Frame", ref _machine.FrameCount);
-					ser.Sync("LagCount", ref _lagCount);
-					ser.Sync("IsLag", ref _isLag);
-					ser.EndSection();
-
-					SyncAllByteArrayDomains();
-				}
-			}
-			*/
 		}
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IVideoProvider.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IVideoProvider.cs
index c253d986b5..d0f9e677ba 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IVideoProvider.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.IVideoProvider.cs
@@ -8,41 +8,38 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		/// <summary>
 		/// 128x64 pixels - 8192x2bits (2 KB)
 		/// For the purposes of this core we will use 8192 bytes and just mask 0x03
-		/// (Also adding an additional 10 rows to the RAM buffer so that it's more aligned with the actual display)
 		/// </summary>
-		public byte[] VRAM = new byte[128 * 64];
-
+		private byte[] _vram = new byte[128 * 64];
 
 		public static readonly int[] FPalette =
-		{
-			//0x101010, 0xFDFDFD, 0x5331FF, 0x5DCC02, 0xF33F4B, 0xE0E0E0, 0xA6FF91, 0xD0CEFF
-			
-			Colors.ARGB(0x10, 0x10, 0x10),		// Black
-			Colors.ARGB(0xFD, 0xFD, 0xFD),		// White
-			Colors.ARGB(0xFF, 0x31, 0x53),		// Red
-			Colors.ARGB(0x02, 0xCC, 0x5D),		// Green
-			Colors.ARGB(0x4B, 0x3F, 0xF3),		// Blue
-			Colors.ARGB(0xE0, 0xE0, 0xE0),		// Gray
-			Colors.ARGB(0x91, 0xFF, 0xA6),		// BGreen
-			Colors.ARGB(0xCE, 0xD0, 0xFF),		// BBlue			
-		};
+		[
+			// 0x101010, 0xFDFDFD, 0x5331FF, 0x5DCC02, 0xF33F4B, 0xE0E0E0, 0xA6FF91, 0xD0CEFF
+
+			Colors.ARGB(0x10, 0x10, 0x10), // Black
+			Colors.ARGB(0xFD, 0xFD, 0xFD), // White
+			Colors.ARGB(0xFF, 0x31, 0x53), // Red
+			Colors.ARGB(0x02, 0xCC, 0x5D), // Green
+			Colors.ARGB(0x4B, 0x3F, 0xF3), // Blue
+			Colors.ARGB(0xE0, 0xE0, 0xE0), // Gray
+			Colors.ARGB(0x91, 0xFF, 0xA6), // BGreen
+			Colors.ARGB(0xCE, 0xD0, 0xFF), // BBlue
+		];
 
 		public static readonly int[] CMap =
-		{
+		[
 			0, 1, 1, 1,
 			7, 4, 2, 3,
 			5, 4, 2, 3,
 			6, 4, 2, 3,
-		};
+		];
 
-		private int _latch_colour = 2;
-		private int _latch_x;
-		private int _latch_y;
-		private int[] videoBuffer;
+		private int _latchColour = 2;
+		private int _latchX;
+		private int _latchY;
+		private int[] _videoBuffer;
 		private double _pixelClockCounter;
 		private double _pixelClocksRemaining;
 
-		
 		private int ScanlineRepeats;
 		private int PixelWidth;
 		private int HTotal;
@@ -54,20 +51,18 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		private double PixelClocksPerCpuClock;
 		private double PixelClocksPerFrame;
 
-		public void SetupVideo()
-		{
-			videoBuffer = new int[HTotal * VTotal];
-		}
+		private void SetupVideo()
+			=> _videoBuffer = new int[HTotal * VTotal];
 
 		/// <summary>
 		/// Called after every CPU clock
 		/// </summary>
 		private void ClockVideo()
-		{			
+		{
 			while (_pixelClocksRemaining > 1)
 			{
 				var currScanline = (int)(_pixelClockCounter / HTotal);
-				var currPixelInLine = (int)(_pixelClockCounter % HTotal);
+				var currPixelInLine = (int)(_pixelClockCounter - currScanline * HTotal);
 				var currRowInVram = currScanline / ScanlineRepeats;
 				var currColInVram = currPixelInLine / PixelWidth;
 
@@ -84,27 +79,30 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 					// active display
 					if (currRowInVram < 64)
 					{
-						var p1 = (VRAM[(currRowInVram * 0x80) + 125]) & 0x03;
-						var p2 = (VRAM[(currRowInVram * 0x80) + 126]) & 0x03;
+						var p1 = _vram[(currRowInVram * 0x80) + 125] & 0x03;
+						var p2 = _vram[(currRowInVram * 0x80) + 126] & 0x03;
 						var pOffset = ((p2 & 0x02) | (p1 >> 1)) << 2;
 
-						var colourIndex = pOffset + (VRAM[currColInVram | (currRowInVram << 7)] & 0x03);
-						videoBuffer[(currScanline * HTotal) + currPixelInLine] = FPalette[CMap[colourIndex]];
+						var colourIndex = pOffset + (_vram[currColInVram | (currRowInVram << 7)] & 0x03);
+						_videoBuffer[(currScanline * HTotal) + currPixelInLine] = FPalette[CMap[colourIndex]];
 					}
 				}
 
 				_pixelClockCounter++;
-				_pixelClocksRemaining -= 1;				
+				_pixelClocksRemaining -= 1;
 			}
 
 			_pixelClocksRemaining += PixelClocksPerCpuClock;
-			_pixelClockCounter %= PixelClocksPerFrame;
+			while (_pixelClockCounter >= PixelClocksPerFrame)
+			{
+				_pixelClockCounter -= PixelClocksPerFrame;
+			}
 		}
 
 		private int HDisplayable => HBlankOn - HBlankOff;
 		private int VDisplayable => VBlankOn - VBlankOff;
 
-		private int[] ClampBuffer(int[] buffer, int originalWidth, int originalHeight, int trimLeft, int trimTop, int trimRight, int trimBottom)
+		private static int[] ClampBuffer(int[] buffer, int originalWidth, int originalHeight, int trimLeft, int trimTop, int trimRight, int trimBottom)
 		{
 			var newWidth = originalWidth - trimLeft - trimRight;
 			var newHeight = originalHeight - trimTop - trimBottom;
@@ -112,7 +110,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 			for (var y = 0; y < newHeight; y++)
 			{
-				for (int x = 0; x < newWidth; x++)
+				for (var x = 0; x < newWidth; x++)
 				{
 					var originalIndex = (y + trimTop) * originalWidth + (x + trimLeft);
 					var newIndex = y * newWidth + x;
@@ -139,40 +137,18 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		public int VsyncDenominator { get; private set; }
 
 
+		// https://channelf.se/veswiki/index.php?title=VRAM
+		// 'The emulator MESS uses a fixed 102x58 resolution starting at (4,4) but the safe area for a real system is about 95x58 pixels'
+		// 'Note that the pixel aspect is a lot closer to widescreen (16:9) than standard definition (4:3). On a TV from the 70's or 80's pixels are rectangular, standing up. In widescreen mode they are close to perfect squares'
+		// https://channelf.se/veswiki/index.php?title=Resolution
+		// 'Even though PAL televisions system has more lines vertically, the Channel F displays about the same as on the original NTSC video system'
+		//
+		// Right now we are just trimming based on the HBLANK and VBLANK values (we might need to go further like the other emulators)
+		// VirtualWidth is being used to force the aspect ratio into 4:3
+		// On real hardware it looks like this (so we are close): https://www.youtube.com/watch?v=ZvQA9tiEIuQ
 		public int[] GetVideoBuffer()
-		{
-			// https://channelf.se/veswiki/index.php?title=VRAM
-			// 'The emulator MESS uses a fixed 102x58 resolution starting at (4,4) but the safe area for a real system is about 95x58 pixels'
-			// 'Note that the pixel aspect is a lot closer to widescreen (16:9) than standard definition (4:3). On a TV from the 70's or 80's pixels are rectangular, standing up. In widescreen mode they are close to perfect squares'
-			// https://channelf.se/veswiki/index.php?title=Resolution
-			// 'Even though PAL televisions system has more lines vertically, the Channel F displays about the same as on the original NTSC video system'
-			//
-			// Right now we are just trimming based on the HBLANK and VBLANK values (we might need to go further like the other emulators)
-			// VirtualWidth is being used to force the aspect ratio into 4:3
-			// On real hardware it looks like this (so we are close): https://www.youtube.com/watch?v=ZvQA9tiEIuQ
-			return ClampBuffer(videoBuffer, HTotal, VTotal, HBlankOff, VBlankOff, HTotal - HBlankOn, VTotal - VBlankOn);
-		}	
+			=> ClampBuffer(_videoBuffer, HTotal, VTotal, HBlankOff, VBlankOff, HTotal - HBlankOn, VTotal - VBlankOn);
 
-		public DisplayType Region => region == RegionType.NTSC ? DisplayType.NTSC : DisplayType.PAL;
-
-		/*
-		private void BuildFrameFromRAM()
-		{
-			for (int r = 0; r < 64; r++)
-			{
-				// lines
-				var p1 = (VRAM[(r * 0x80) + 125]) & 0x03;
-				var p2 = (VRAM[(r * 0x80) + 126]) & 0x03;
-				var pOffset = ((p2 & 0x02) | (p1 >> 1)) << 2;
-
-				for (int c = 0; c < 128; c++)
-				{
-					// columns
-					var colourIndex = pOffset + (VRAM[c | (r << 7)] & 0x03);
-					frameBuffer[(r << 7) + c] = CMap[colourIndex];
-				}
-			}
-		}
-		*/
+		public DisplayType Region => _region == RegionType.NTSC ? DisplayType.NTSC : DisplayType.PAL;
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.InputPollable.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.InputPollable.cs
index 7131276af4..1319ea4793 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.InputPollable.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.InputPollable.cs
@@ -18,63 +18,48 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 		public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
 
-		private int _lagCount = 0;
-		private bool _isLag = false;
+		private int _lagCount;
+		private bool _isLag;
 
 		/// <summary>
 		/// Cycles through all the input callbacks
 		/// This should be done once per frame
 		/// </summary>
-		public bool PollInput()
+		private void PollInput()
 		{
-			bool noInput = true;
-			for (int i = 0; i < ButtonsConsole.Length; i++)
+			for (var i = 0; i < _buttonsConsole.Length; i++)
 			{
-				var key = ButtonsConsole[i];
-				bool prevState = StateConsole[i]; // CTRLConsole.Bit(i);
-				bool currState = _controller.IsPressed(key);
+				var key = _buttonsConsole[i];
+				var prevState = _stateConsole[i];
+				var currState = _controller.IsPressed(key);
 				if (currState != prevState)
 				{
-					StateConsole[i] = currState;
-					noInput = false;
+					_stateConsole[i] = currState;
 
-					if (key == "RESET" && StateConsole[i])
+					if (key == "RESET" && _stateConsole[i])
 					{
 						ConsoleReset();
-						for (int l = 0; l < OutputLatch.Length; l++)
+						for (var l = 0; l < _outputLatch.Length; l++)
 						{
-							OutputLatch[l] = 0;
+							_outputLatch[l] = 0;
 						}
-						return true;
+
+						return;
 					}
 				}
 			}
 
-			for (int i = 0; i < ButtonsRight.Length; i++)
+			for (var i = 0; i < _buttonsRight.Length; i++)
 			{
-				var key = "P1 " + ButtonsRight[i];
-				bool prevState = StateRight[i];
-				bool currState = _controller.IsPressed(key);
-				if (currState != prevState)
-				{
-					StateRight[i] = currState;
-					noInput = false;
-				}
+				var key = _buttonsRight[i];
+				_stateRight[i] = _controller.IsPressed(key);
 			}
 
-			for (int i = 0; i < ButtonsLeft.Length; i++)
+			for (var i = 0; i < _buttonsLeft.Length; i++)
 			{
-				var key = "P2 " + ButtonsLeft[i];
-				bool prevState = StateLeft[i];
-				bool currState = _controller.IsPressed(key);
-				if (currState != prevState)
-				{
-					StateLeft[i] = currState;
-					noInput = false;
-				}
+				var key = _buttonsLeft[i];
+				_stateLeft[i] = _controller.IsPressed(key);
 			}
-
-			return noInput;
 		}
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.MemoryDomains.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.MemoryDomains.cs
index 58e071710c..f28aceabc2 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.MemoryDomains.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.MemoryDomains.cs
@@ -19,12 +19,12 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 					addr =>
 					{
 						if (addr is < 0 or > 63) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
-						return CPU.Regs[addr];
+						return _cpu.Regs[addr];
 					},
 					(addr, value) =>
 					{
 						if (addr is < 0 or > 63) throw new ArgumentOutOfRangeException(paramName: nameof(addr), addr, message: "address out of range");
-						CPU.Regs[addr] = value;
+						_cpu.Regs[addr] = value;
 					}, 1),
 				new MemoryDomainDelegate("System Bus", 0x10000, MemoryDomain.Endian.Big,
 					addr =>
@@ -49,11 +49,10 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 		private void SyncAllByteArrayDomains()
 		{
-			SyncByteArrayDomain("BIOS1", BIOS01);
-			SyncByteArrayDomain("BIOS2", BIOS02);
-			Cartridge.SyncByteArrayDomain(this);
-			//SyncByteArrayDomain("ROM", Rom);
-			SyncByteArrayDomain("VRAM", VRAM);
+			SyncByteArrayDomain("BIOS1", _bios01);
+			SyncByteArrayDomain("BIOS2", _bios02);
+			_cartridge.SyncByteArrayDomain(this);
+			SyncByteArrayDomain("VRAM", _vram);
 		}
 
 		public void SyncByteArrayDomain(string name, byte[] data)
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.cs
index 789d71f0f4..991ba5b1a6 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/ChannelF.cs
@@ -1,7 +1,4 @@
-using System.Collections.Generic;
-using System.Linq;
-
-using BizHawk.Emulation.Common;
+using BizHawk.Emulation.Common;
 using BizHawk.Emulation.Cores.Components.FairchildF8;
 
 namespace BizHawk.Emulation.Cores.Consoles.ChannelF
@@ -15,71 +12,60 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 			var ser = new BasicServiceProvider(this);
 			ServiceProvider = ser;
 			CoreComm = lp.Comm;
-			_gameInfo = lp.Roms.Select(r => r.Game).ToList();
-			_files = lp.Roms.Select(r => r.RomData).ToList();
+			var gameInfo = lp.Roms[0].Game;
+			var rom = lp.Roms[0].RomData;
 
 			_syncSettings = lp.SyncSettings ?? new ChannelFSyncSettings();
-			region = _syncSettings.Region;
-			version = _syncSettings.Version;
+			_region = _syncSettings.Region;
+			_version = _syncSettings.Version;
 
 			MemoryCallbacks = new MemoryCallbackSystem([ "System Bus" ]);
 
-			ControllerDefinition = ChannelFControllerDefinition;
+			ControllerDefinition = _channelFControllerDefinition.Value;
 
-			if (version == ConsoleVersion.ChannelF)
+			if (_version == ConsoleVersion.ChannelF)
 			{
-				BIOS01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131253"));
-				BIOS02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
+				_bios01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131253"));
+				_bios02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
 			}
 			else
 			{
-				BIOS01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl90025"));
-				BIOS02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
+				_bios01 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl90025"));
+				_bios02 = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("ChannelF", "ChannelF_sl131254"));
 			}
 
-			Cartridge = VesCartBase.Configure(_gameInfo[0], _files[0]);
-
-			CPU = new F3850
+			if (_bios01.Length != 1024 || _bios02.Length != 1024)
 			{
-				ReadMemory = ReadBus,
-				WriteMemory = WriteBus,
-				ReadHardware = ReadPort,
-				WriteHardware = WritePort,
-				DummyReadMemory = ReadBus
-			};
+				throw new InvalidOperationException("BIOS must be exactly 1024 bytes!");
+			}
 
-			_tracer = new TraceBuffer(CPU.TraceHeader);			
+			_cartridge = VesCartBase.Configure(gameInfo, rom);
 
-			//var rom = _files.First();
-			//Array.Copy(rom, 0, Rom, 0, rom.Length);
+			_cpu = new F3850<CpuLink>(new CpuLink(this));
+			_tracer = new TraceBuffer(_cpu.TraceHeader);
 
 			CalcClock();
 			SetupVideo();
 
-			ser.Register<IVideoProvider>(this);
 			ser.Register<ITraceable>(_tracer);
-			ser.Register<IDisassemblable>(CPU);
-			ser.Register<ISoundProvider>(this);
+			ser.Register<IDisassemblable>(_cpu);
 			ser.Register<IStatable>(new StateSerializer(SyncState));
 			SetupMemoryDomains();
 		}
 
-		internal CoreComm CoreComm { get; }
+		private CoreComm CoreComm { get; }
 
-		public List<GameInfo> _gameInfo;
-		private readonly List<byte[]> _files;
-
-		public F3850 CPU;
+		private readonly F3850<CpuLink> _cpu;
 		private readonly TraceBuffer _tracer;
-		public IController _controller;
+		private IController _controller;
 
-		public VesCartBase Cartridge;
-		public RegionType region;
-		public ConsoleVersion version;
+		private readonly VesCartBase _cartridge;
+		private readonly RegionType _region;
+		private readonly ConsoleVersion _version;
 
-		public bool DriveLightEnabled => Cartridge.HasActivityLED;
+		public bool DriveLightEnabled => _cartridge.HasActivityLED;
 
-		public bool DriveLightOn => Cartridge.ActivityLED;
+		public bool DriveLightOn => _cartridge.ActivityLED;
 
 		public string DriveLightIconDescription => "Computer thinking activity";
 	}
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Memory.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Memory.cs
index 06976b966f..920df11212 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Memory.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Memory.cs
@@ -5,8 +5,8 @@
 	/// </summary>
 	public partial class ChannelF
 	{
-		public byte[] BIOS01 = new byte[1024];
-		public byte[] BIOS02 = new byte[1024];
+		private readonly byte[] _bios01;
+		private readonly byte[] _bios02;
 
 		/// <summary>
 		/// Simulates reading a byte of data from the address space
@@ -16,17 +16,17 @@
 			if (addr < 0x400)
 			{
 				// BIOS ROM 1
-				return BIOS01[addr];
+				return _bios01[addr];
 			}
 			else if (addr < 0x800)
 			{
 				// BIOS ROM 2
-				return BIOS02[addr - 0x400];
+				return _bios02[addr - 0x400];
 			}
 			else
 			{
 				// Cartridge Memory Space
-				return Cartridge.ReadBus(addr);
+				return _cartridge.ReadBus(addr);
 			}
 		}
 
@@ -35,8 +35,6 @@
 		/// Channel F addressable through the address space)
 		/// </summary>
 		public void WriteBus(ushort addr, byte value)
-		{
-			Cartridge.WriteBus(addr, value);
-		}		
+			=> _cartridge.WriteBus(addr, value);
 	}
 }
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Ports.cs b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Ports.cs
index 06dd4c0f9b..524597dbd3 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Ports.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Fairchild/ChannelF/Ports.cs
@@ -18,27 +18,26 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		/// Depending on the attached cartridge, there may be additional hardware on the IO bus
 		/// All CPU and PSU I/O ports are active-low with output-latches
 		/// </summary>
-		public byte[] OutputLatch = new byte[0xFF];
+		private byte[] _outputLatch = new byte[0xFF];
 
-		public bool LS368Enable;
+		private bool LS368Enable;
 
 		/// <summary>
 		/// CPU is attempting to read from a port
 		/// </summary>
-		public byte ReadPort(ushort addr)
+		private byte ReadPort(ushort addr)
 		{
-			var result = 0xFF;
-
+			int result;
 			switch (addr)
 			{
 				case 0:
-					// Console Buttons - these are connected to pins 0-3 (bits 0-3) through a 7404 Hex Inverter	
-					// b0:	TIME
-					// b1:	MODE
-					// b2:	HOLD
-					// b3:	START
-					// RESET button is connected directly to the RST pin on the CPU (this is handled here in the PollInput() method)					
-					result = (~DataConsole & 0x0F) | OutputLatch[addr];
+					// Console Buttons - these are connected to pins 0-3 (bits 0-3) through a 7404 Hex Inverter
+					// b0: TIME
+					// b1: MODE
+					// b2: HOLD
+					// b3: START
+					// RESET button is connected directly to the RST pin on the CPU (this is handled here in the PollInput() method)
+					result = (~DataConsole & 0x0F) | _outputLatch[addr];
 					InputCallbacks.Call();
 					_isLag = false;
 					break;
@@ -46,14 +45,14 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 				case 1:
 					// right controller (player 1)
 					// connected through 7404 Hex Inverter
-					// b0:	RIGHT
-					// b1:	LEFT
-					// b2:	BACK
-					// b3:	FORWARD
-					// b4:	CCW
-					// b5:	CW
+					// b0: RIGHT
+					// b1: LEFT
+					// b2: BACK
+					// b3: FORWARD
+					// b4: CCW
+					// b5: CW
 					var v1 = LS368Enable ? DataRight : DataRight | 0xC0;
-					result = (~v1) | OutputLatch[addr];
+					result = ~v1 | _outputLatch[addr];
 					InputCallbacks.Call();
 					_isLag = false;
 					break;
@@ -62,30 +61,31 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 					// left controller (player 2)
 					// connected through LS368 Hex Interting 3-State Buffer
 					// the enable pin of this IC is driven by a CPU write to pin 6 on port 0
-					// b0:	RIGHT
-					// b1:	LEFT
-					// b2:	BACK
-					// b3:	FORWARD
-					// b4:	CCW
-					// b5:	CW
-					// b6:	PULL
-					// b7:	PUSH
+					// b0: RIGHT
+					// b1: LEFT
+					// b2: BACK
+					// b3: FORWARD
+					// b4: CCW
+					// b5: CW
+					// b6: PULL
+					// b7: PUSH
 					var v2 = LS368Enable ? DataLeft : 0xFF;
-					result = (~v2) | OutputLatch[addr];
+					result = ~v2 | _outputLatch[addr];
 					if (LS368Enable)
 					{
 						InputCallbacks.Call();
 						_isLag = false;
 					}
+
 					break;
 
 				case 5:
-					result = OutputLatch[addr];
+					result = _outputLatch[addr];
 					break;
 
 				default:
 					// possible cartridge hardware IO space
-					result = (Cartridge.ReadPort(addr));
+					result = _cartridge.ReadPort(addr);
 					break;
 			}
 
@@ -95,37 +95,37 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 		/// <summary>
 		/// CPU is attempting to write to the specified IO port
 		/// </summary>
-		public void WritePort(ushort addr, byte value)
+		private void WritePort(ushort addr, byte value)
 		{
 			switch (addr)
 			{
 				case 0:
-					OutputLatch[addr] = value;
+					_outputLatch[addr] = value;
 					LS368Enable = !value.Bit(6);
 					if (value.Bit(5))
 					{
 						// WRT pulse
 						// pulse clocks the 74195 parallel access shift register which feeds inputs of 2 NAND gates
 						// writing data to both sets of even and odd VRAM chips (based on the row and column addresses latched into the 7493 ICs)
-						VRAM[((_latch_y) * 0x80) + _latch_x] = (byte)_latch_colour;						
+						_vram[_latchY * 0x80 + _latchX] = (byte)_latchColour;
 					}
 
 					break;
 
 				case 1:
-					OutputLatch[addr] = value;
-					_latch_colour = ((value ^ 0xFF) >> 6) & 0x03;
+					_outputLatch[addr] = value;
+					_latchColour = ((value ^ 0xFF) >> 6) & 0x03;
 					break;
 
 				case 4:
-					OutputLatch[addr] = value;
-					_latch_x = (value | 0x80) ^ 0xFF;
+					_outputLatch[addr] = value;
+					_latchX = (value | 0x80) ^ 0xFF;
 					break;
 
 				case 5:
-					OutputLatch[addr] = value;
-					_latch_y = (value | 0xC0) ^ 0xFF;
-					var audio = ((value) >> 6) & 0x03;
+					_outputLatch[addr] = value;
+					_latchY = (value | 0xC0) ^ 0xFF;
+					var audio = (value >> 6) & 0x03;
 					if (audio != _tone)
 					{
 						_tone = audio;
@@ -136,7 +136,7 @@ namespace BizHawk.Emulation.Cores.Consoles.ChannelF
 
 				default:
 					// possible write to cartridge hardware
-					Cartridge.WritePort(addr, value);
+					_cartridge.WritePort(addr, value);
 					break;
 			}
 		}