From 49ec644f7125c2fdcd7dd3c832fc178fb951913d Mon Sep 17 00:00:00 2001
From: alyosha-tas <alexei.f.k@gmail.com>
Date: Tue, 24 Sep 2019 13:09:17 -0400
Subject: [PATCH] GBHawk: Add in IR transfer support

---
 .../Consoles/Nintendo/GBHawk/Audio.cs         |  4 +-
 .../Nintendo/GBHawk/GBHawk.IEmulator.cs       |  2 +-
 .../Nintendo/GBHawk/GBHawk.IStatable.cs       |  6 +++
 .../Consoles/Nintendo/GBHawk/GBHawk.cs        |  5 +++
 .../Consoles/Nintendo/GBHawk/HW_Registers.cs  | 44 +++++++++++++++++++
 .../GBHawkLink/GBHawkLink.IEmulator.cs        | 29 ++++++------
 .../GBHawkLink3x/GBHawkLink3x.IEmulator.cs    | 12 +++++
 7 files changed, 85 insertions(+), 17 deletions(-)

diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs
index e10e1f9b22..ea55349bc8 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/Audio.cs
@@ -277,7 +277,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 							}
 
 							if ((SQ1_vol_state == 0) && !SQ1_env_add) { SQ1_enable = SQ1_swp_enable = false; SQ1_output = 0; }
-							if ((SQ1_vol_state == 0) && (SQ1_per == 0) && SQ1_env_add) { SQ1_vol_state = 16; }
+							//if ((SQ1_vol_state == 0) && (SQ1_per == 0) && SQ1_env_add) { SQ1_vol_state = 16; }
 						}
 
 						SQ1_len_en = (value & 0x40) > 0;
@@ -337,7 +337,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 							SQ2_vol_state = SQ2_st_vol;
 							SQ2_vol_per = (SQ2_per > 0) ? SQ2_per : 8;
 							if ((SQ2_vol_state == 0) && !SQ2_env_add) { SQ2_enable = false; SQ2_output = 0; }
-							if ((SQ2_vol_state == 0) && (SQ2_per == 0) && SQ2_env_add) { SQ2_vol_state = 16; }
+							//if ((SQ2_vol_state == 0) && (SQ2_per == 0) && SQ2_env_add) { SQ2_vol_state = 16; }
 						}
 
 						SQ2_len_en = (value & 0x40) > 0;
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs
index 113a8d9c9a..614aa4830e 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IEmulator.cs
@@ -226,7 +226,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 				if (speed_switch)
 				{
 					speed_switch = false;
-					Console.WriteLine(cpu.TotalExecutedCycles);
+					Console.WriteLine("Speed Switch: " + cpu.TotalExecutedCycles);
 					int ret = double_speed ? 70224 * 2 : 70224 * 2; // actual time needs checking
 					double_speed = !double_speed;
 					return ret;
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs
index 21d9aa4794..d7ca270d54 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.IStatable.cs
@@ -90,6 +90,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 			ser.Sync(nameof(speed_switch), ref speed_switch);
 			ser.Sync(nameof(HDMA_transfer), ref HDMA_transfer);
 
+			ser.Sync(nameof(IR_reg), ref IR_reg);
+			ser.Sync(nameof(IR_mask), ref IR_mask);
+			ser.Sync(nameof(IR_signal), ref IR_signal);
+			ser.Sync(nameof(IR_receive), ref IR_receive);
+			ser.Sync(nameof(IR_self), ref IR_self);
+
 			ser.Sync(nameof(undoc_6C), ref undoc_6C);
 			ser.Sync(nameof(undoc_72), ref undoc_72);
 			ser.Sync(nameof(undoc_73), ref undoc_73);
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs
index 9267548b4e..615b4da28c 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.cs
@@ -54,6 +54,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 		public bool double_speed;
 		public bool speed_switch;
 		public bool HDMA_transfer; // stalls CPU when in progress
+		public byte IR_reg, IR_mask, IR_signal, IR_receive, IR_self;
 
 		// several undocumented GBC Registers
 		public byte undoc_6C, undoc_72, undoc_73, undoc_74, undoc_75, undoc_76, undoc_77;
@@ -144,6 +145,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 
 			_bios = Bios;
 
+			// set up IR register to off state
+			if (is_GBC) { IR_mask = 0; IR_reg = 0x3E; IR_receive = 2; IR_self = 2; IR_signal = 2; }
+
 			// Here we modify the BIOS if GBA mode is set (credit to ExtraTricky)
 			if (is_GBC && _syncSettings.GBACGB)
 			{
@@ -151,6 +155,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 				{
 					_bios[i + 0xF3] = (byte)((GBA_override[i] + _bios[i + 0xF3]) & 0xFF);
 				}
+				IR_mask = 2;
 			}
 
 			// CPU needs to know about GBC status too
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs
index 6c386b1d92..3df28da035 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/HW_Registers.cs
@@ -133,6 +133,36 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 				case 0xFF53:
 				case 0xFF54:
 				case 0xFF55:
+					if (GBC_compat)
+					{
+						ret = ppu.ReadReg(addr);
+					}
+					else
+					{
+						ret = 0xFF;
+					}
+					break;
+
+				case 0xFF56:
+					if (is_GBC)
+					{
+						// can receive data
+						if ((IR_reg & 0xC0) == 0xC0)
+						{
+							ret = (byte)(IR_reg | (IR_self | IR_receive | IR_mask));
+						}
+						else
+						{
+							ret = (byte)(IR_reg | 2);
+						}
+							
+					}
+					else
+					{
+						ret = 0xFF;
+					}
+					break;
+
 				case 0xFF68:
 				case 0xFF69:
 				case 0xFF6A:
@@ -392,6 +422,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
 					ppu.WriteReg(addr, value);
 					}
 					break;
+
+				case 0xFF56:
+					if (is_GBC)
+					{
+						IR_reg = (byte)((value & 0xC1) | (IR_reg & 0x3E));
+
+						// send IR signal out
+						if ((IR_reg & 0x1) == 0x1) { IR_signal = (byte)(0 | IR_mask); } else { IR_signal = 2; }
+						
+						// receive own signal if IR on and receive on
+						if ((IR_reg & 0xC1) == 0xC1) { IR_self = 0; } else { IR_self = 2; }
+					}
+					break;
+
 				case 0xFF68:
 				case 0xFF69:
 				case 0xFF6A:
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs
index d8756b766b..cdc8cd3b39 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.IEmulator.cs
@@ -100,10 +100,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
 				L.do_single_step();
 				R.do_single_step();
 
-				// the signal to shift out a bit is when serial_clock = 1
-				if (((L.serialport.serial_clock == 1) || (L.serialport.serial_clock == 2)) && !do_r_next)
+				if (_cableconnected)
 				{
-					if (_cableconnected)
+					// the signal to shift out a bit is when serial_clock = 1
+					if (((L.serialport.serial_clock == 1) || (L.serialport.serial_clock == 2)) && !do_r_next)
 					{
 						L.serialport.send_external_bit((byte)(L.serialport.serial_data & 0x80));
 
@@ -116,13 +116,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
 
 						L.serialport.coming_in = R.serialport.going_out;
 					}
-				}
-				else if ((R.serialport.serial_clock == 1) || (R.serialport.serial_clock == 2))
-				{
-					do_r_next = false;
-
-					if (_cableconnected)
+					else if ((R.serialport.serial_clock == 1) || (R.serialport.serial_clock == 2))
 					{
+						do_r_next = false;
+
 						R.serialport.send_external_bit((byte)(R.serialport.serial_data & 0x80));
 
 						if ((L.serialport.clk_rate == -1) && L.serialport.serial_start)
@@ -133,13 +130,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
 						}
 
 						R.serialport.coming_in = L.serialport.going_out;
+
+						if (R.serialport.serial_clock == 2) { do_r_next = true; }
+					}
+					else
+					{
+						do_r_next = false;
 					}
 
-					if (R.serialport.serial_clock == 2) { do_r_next = true; }
-				}
-				else
-				{
-					do_r_next = false;
+					// do IR transfer
+					L.IR_receive = R.IR_signal;
+					R.IR_receive = L.IR_signal;
 				}
 
 				// if we hit a frame boundary, update video
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.IEmulator.cs
index 4bb30e5a79..b769d41ce7 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.IEmulator.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.IEmulator.cs
@@ -172,6 +172,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
 					{
 						do_2_next = false;
 					}
+
+					// do IR transfer
+					L.IR_receive = C.IR_signal;
+					C.IR_receive = L.IR_signal;
 				}
 				else if (_cableconnected_CR)
 				{
@@ -210,6 +214,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
 					{
 						do_2_next = false;
 					}
+
+					// do IR transfer
+					C.IR_receive = R.IR_signal;
+					R.IR_receive = C.IR_signal;
 				}
 				else if (_cableconnected_RL)
 				{
@@ -248,6 +256,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
 					{
 						do_2_next = false;
 					}
+
+					// do IR transfer
+					R.IR_receive = L.IR_signal;
+					L.IR_receive = R.IR_signal;					
 				}