From 087586bc4910d9d263b7014a083eeb339ec600a0 Mon Sep 17 00:00:00 2001
From: alyosha-tas <alexei.f.k@gmail.com>
Date: Sat, 18 Nov 2017 19:45:11 -0500
Subject: [PATCH] GBHawk: pass new IRQ test

---
 .../CPUs/LR35902/Interrupts.cs                | 10 +-
 .../CPUs/LR35902/LR35902.cs                   | 98 ++++++++++++++-----
 2 files changed, 79 insertions(+), 29 deletions(-)

diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs
index ec93ae031e..24685ad908 100644
--- a/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs
+++ b/BizHawk.Emulation.Cores/CPUs/LR35902/Interrupts.cs
@@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
 			set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; }
 		}
 
-		private void INTERRUPT_(ushort src)
+		private void INTERRUPT_()
 		{
 			cur_instr = new ushort[]
 						{IDLE,
@@ -40,19 +40,21 @@ namespace BizHawk.Emulation.Common.Components.LR35902
 						DEC16, SPl, SPh,
 						IDLE,
 						WR, SPl, SPh, PCh,
-						IDLE,
+						INT_GET, // NOTE: here is where we check for a cancelled IRQ
 						DEC16, SPl, SPh,
 						IDLE,
 						WR, SPl, SPh, PCl,
 						IDLE,
-						ASGN, PCl, INT_vectors[src],
 						IDLE,
+						TR, PCl, W,
 						ASGN, PCh, 0,
 						IDLE,
 						OP };
 		}
 
-		private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60};
+		private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60, 0x00};
+
+		public ushort int_src;
 
 		private void ResetInterrupts()
 		{
diff --git a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs
index f1aa8bf317..6ca017c6d8 100644
--- a/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs
+++ b/BizHawk.Emulation.Cores/CPUs/LR35902/LR35902.cs
@@ -56,6 +56,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
 		public const ushort JAM = 41;  // all undocumented opcodes jam the machine
 		public const ushort RD_F = 42; // special read case to pop value into F
 		public const ushort EI_RETI = 43; // reti has no delay in interrupt enable
+		public const ushort INT_GET = 44;
 
 		public LR35902()
 		{
@@ -134,20 +135,20 @@ namespace BizHawk.Emulation.Common.Components.LR35902
 							});
 						}
 
-						// call interrupt processor with the appropriate source
+						// call interrupt processor 
 						// lowest bit set is highest priority
-						ushort priority = 0;
-
-						if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { priority = 0; interrupt_src -= 1; }
-						else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { priority = 1; interrupt_src -= 2; }
-						else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { priority = 2; interrupt_src -= 4; }
-						else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { priority = 3; interrupt_src -= 8; }
-						else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { priority = 4; interrupt_src -= 16; }
-						else { /*Console.WriteLine("No source"); }*/throw new Exception("Interrupt without Source"); }
+						
+						if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; }
+						else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; }
+						else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; }
+						else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; }
+						else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; }
+						else { /*Console.WriteLine("No source"); }*/ throw new Exception("Interrupt without Source"); }
+						
 
 						if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
 
-						INTERRUPT_(priority);
+						INTERRUPT_();
 					}
 					else
 					{
@@ -284,22 +285,20 @@ namespace BizHawk.Emulation.Common.Components.LR35902
 							});
 						}
 						halted = false;
-						// call interrupt processor with the appropriate source
-						// lowest bit set is highest priority
-						// call interrupt processor with the appropriate source
-						// lowest bit set is highest priority
-						ushort priority = 0;
-
-						if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { priority = 0; interrupt_src -= 1; }
-						else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { priority = 1; interrupt_src -= 2; }
-						else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { priority = 2; interrupt_src -= 4; }
-						else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { priority = 3; interrupt_src -= 8; }
-						else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { priority = 4; interrupt_src -= 16; }
-						else { /*Console.WriteLine("No source"); }*/throw new Exception("Interrupt without Source"); }
-
-						if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
+						// call interrupt processor 
 						instr_pntr = 0;
-						INTERRUPT_(priority);
+						// lowest bit set is highest priority
+						
+						if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; }
+						else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; }
+						else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; }
+						else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; }
+						else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; }
+						else { /*Console.WriteLine("No source"); } */throw new Exception("Interrupt without Source"); }
+						
+						if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
+
+						INTERRUPT_();
 					}
 					else if (FlagI)
 					{
@@ -384,6 +383,54 @@ namespace BizHawk.Emulation.Common.Components.LR35902
 					break;
 				case EI_RETI:
 					EI_pending = 1;
+					break;
+				case INT_GET:
+					// check if any interrupts got cancelled along the way
+					// interrupt src = 5 sets the PC to zero as observed
+
+					Console.WriteLine(int_src);
+					
+					if (int_src == 0) 
+					{
+						if (interrupt_enable.Bit(0)) { interrupt_src -= 1; }
+						else { int_src = 5; }
+					}
+					if (int_src == 1)
+					{
+						if (interrupt_enable.Bit(1)) { interrupt_src -= 2; }
+						else { int_src = 5; }
+					}
+					if (int_src == 2)
+					{
+						if (interrupt_enable.Bit(2)) { interrupt_src -= 4; }
+						else { int_src = 5; }
+					}
+					if (int_src == 3)
+					{
+						if (interrupt_enable.Bit(3)) { interrupt_src -= 8; }
+						else { int_src = 5; }
+					}
+					if (int_src == 4)
+					{
+						if (interrupt_enable.Bit(4)) { interrupt_src -= 16; }
+						else { int_src = 5; }
+					}
+
+					// if we lost the interrupt, find the next highest interrupt, if any
+					if (int_src == 5)
+					{
+						if (interrupt_src.Bit(0) && interrupt_enable.Bit(0)) { int_src = 0; interrupt_src -= 1; }
+						else if (interrupt_src.Bit(1) && interrupt_enable.Bit(1)) { int_src = 1; interrupt_src -= 2; }
+						else if (interrupt_src.Bit(2) && interrupt_enable.Bit(2)) { int_src = 2; interrupt_src -= 4; }
+						else if (interrupt_src.Bit(3) && interrupt_enable.Bit(3)) { int_src = 3; interrupt_src -= 8; }
+						else if (interrupt_src.Bit(4) && interrupt_enable.Bit(4)) { int_src = 4; interrupt_src -= 16; }
+						else { int_src = 5; }
+					}
+
+					if ((interrupt_src & interrupt_enable) == 0) { FlagI = false; }
+
+					Regs[W] = INT_vectors[int_src];
+
 					break;
 			}
 			totalExecutedCycles++;
@@ -443,6 +490,7 @@ namespace BizHawk.Emulation.Common.Components.LR35902
 			ser.Sync("Halted", ref halted);
 			ser.Sync("ExecutedCycles", ref totalExecutedCycles);
 			ser.Sync("EI_pending", ref EI_pending);
+			ser.Sync("int_src", ref int_src);
 
 			ser.Sync("instruction_pointer", ref instr_pntr);
 			ser.Sync("current instruction", ref cur_instr, false);