From 2463aae54588a726a2edbdaa14e147fc7c19fa5e Mon Sep 17 00:00:00 2001
From: tomcw <tomcw@users.noreply.github.com>
Date: Sat, 6 Apr 2019 15:17:18 +0100
Subject: [PATCH] Updates for DHGR MIX and detection (#633): . Support DHGR MIX
 mode and AN2 off to invert bit7 (undocumented) . Improve the video-mode
 precondition to check for 80COL access occurring before $C05F

---
 source/Memory.cpp     | 34 +++++++++++++++++++++-------------
 source/Memory.h       |  5 +++--
 source/NTSC.cpp       |  6 ++++++
 source/RGBMonitor.cpp | 21 ++++++++++++++++++---
 source/RGBMonitor.h   |  2 +-
 5 files changed, 49 insertions(+), 19 deletions(-)

diff --git a/source/Memory.cpp b/source/Memory.cpp
index 9b63b340..5c551104 100644
--- a/source/Memory.cpp
+++ b/source/Memory.cpp
@@ -2058,6 +2058,13 @@ LPVOID MemGetSlotParameters(UINT uSlot)
 
 //===========================================================================
 
+bool MemGetAnnunciator(UINT annunciator)
+{
+	return g_Annunciator[annunciator];
+}
+
+//===========================================================================
+
 // NB. Don't need to save 'modechanging', as this is just an optimisation to save calling UpdatePaging() twice.
 // . If we were to save the state when 'modechanging' is set, then on restoring the state, the 6502 code will immediately update the read memory mode.
 // . This will work correctly.
@@ -2078,7 +2085,8 @@ static const UINT kUNIT_AUXSLOT_VER = 2;
 
 // Unit version history:
 // 2: Added: RGB card state
-static const UINT kUNIT_VER = 2;
+// 3: Extended: RGB card state ('80COL changed')
+static const UINT kUNIT_CARD_VER = 3;
 
 #define SS_YAML_VALUE_CARD_80COL "80 Column"
 #define SS_YAML_VALUE_CARD_EXTENDED80COL "Extended 80 Column"
@@ -2156,14 +2164,14 @@ void MemSaveSnapshot(YamlSaveHelper& yamlSaveHelper)
 		MemSaveSnapshotMemory(yamlSaveHelper, true);
 }
 
-bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
+bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT unitVersion)
 {
 	if (!yamlLoadHelper.GetSubMap(MemGetSnapshotStructName()))
 		return false;
 
 	// Create default LC type for AppleII machine (do prior to loading saved LC state)
 	ResetDefaultMachineMemTypes();
-	if (version == 1)
+	if (unitVersion == 1)
 		g_MemTypeAppleII = CT_LanguageCard;	// version=1: original Apple II always has a LC
 	else
 		g_MemTypeAppleIIPlus = CT_Empty;	// version=2+: Apple II/II+ initially start with slot-0 empty
@@ -2178,7 +2186,7 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
 	g_eExpansionRomType = (eExpansionRomType) yamlLoadHelper.LoadUint(SS_YAML_KEY_EXPANSIONROMTYPE);
 	g_uPeripheralRomSlot = yamlLoadHelper.LoadUint(SS_YAML_KEY_PERIPHERALROMSLOT);
 
-	if (version == 1)
+	if (unitVersion == 1)
 	{
 		SetMemMode( yamlLoadHelper.LoadUint(SS_YAML_KEY_MEMORYMODE) ^ MF_INTCXROM );	// Convert from SLOTCXROM to INTCXROM
 		SetLastRamWrite( yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE );
@@ -2194,7 +2202,7 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
 			SetLastRamWrite( yamlLoadHelper.LoadUint(SS_YAML_KEY_LASTRAMWRITE) ? TRUE : FALSE );	// NB. This is set later for II,II+ by slot-0 LC or Saturn
 	}
 
-	if (version == 3)
+	if (unitVersion == 3)
 	{
 		for (UINT i=0; i<kNumAnnunciators; i++)
 		{
@@ -2213,7 +2221,7 @@ bool MemLoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
 	memset(memmain+0xC000, 0, LanguageCardSlot0::kMemBankSize);	// Clear it, as high 16K may not be in the save-state's "Main Memory" (eg. the case of II+ Saturn replacing //e LC)
 
 	yamlLoadHelper.LoadMemory(memmain, _6502_MEM_END+1);
-	if (version == 1 && IsApple2PlusOrClone(GetApple2Type()))
+	if (unitVersion == 1 && IsApple2PlusOrClone(GetApple2Type()))
 	{
 		// v1 for II/II+ doesn't have a dedicated slot-0 LC, instead the 16K is stored as the top 16K of memmain
 		memcpy(g_pMemMainLanguageCard, memmain+0xC000, LanguageCardSlot0::kMemBankSize);
@@ -2256,7 +2264,7 @@ void MemSaveSnapshotAux(YamlSaveHelper& yamlSaveHelper)
 													SS_YAML_VALUE_CARD_RAMWORKSIII;
 
 		yamlSaveHelper.SaveString(SS_YAML_KEY_CARD, card.c_str());
-		yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_VERSION, kUNIT_VER);
+		yamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_VERSION, kUNIT_CARD_VER);
 
 		// Card state
 		{
@@ -2348,7 +2356,7 @@ static void MemLoadSnapshotAuxVer1(YamlLoadHelper& yamlLoadHelper)
 	MemLoadSnapshotAuxCommon(yamlLoadHelper, card);
 }
 
-static void MemLoadSnapshotAuxVer2(YamlLoadHelper& yamlLoadHelper, UINT unitVersion)
+static void MemLoadSnapshotAuxVer2(YamlLoadHelper& yamlLoadHelper)
 {
 	std::string card = yamlLoadHelper.LoadString(SS_YAML_KEY_CARD);
 	UINT cardVersion = yamlLoadHelper.LoadUint(SS_YAML_KEY_VERSION);
@@ -2358,18 +2366,18 @@ static void MemLoadSnapshotAuxVer2(YamlLoadHelper& yamlLoadHelper, UINT unitVers
 
 	MemLoadSnapshotAuxCommon(yamlLoadHelper, card);
 
-	RGB_LoadSnapshot(yamlLoadHelper);
+	RGB_LoadSnapshot(yamlLoadHelper, cardVersion);
 }
 
-bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT version)
+bool MemLoadSnapshotAux(YamlLoadHelper& yamlLoadHelper, UINT unitVersion)
 {
-	if (version < 1 || version > kUNIT_AUXSLOT_VER)
+	if (unitVersion < 1 || unitVersion > kUNIT_AUXSLOT_VER)
 		throw std::string(SS_YAML_KEY_UNIT ": AuxSlot: Version mismatch");
 
-	if (version == 1)
+	if (unitVersion == 1)
 		MemLoadSnapshotAuxVer1(yamlLoadHelper);
 	else
-		MemLoadSnapshotAuxVer2(yamlLoadHelper, version);
+		MemLoadSnapshotAuxVer2(yamlLoadHelper);
 
 	return true;
 }
diff --git a/source/Memory.h b/source/Memory.h
index 6f4c440f..8e2a4a58 100644
--- a/source/Memory.h
+++ b/source/Memory.h
@@ -80,11 +80,12 @@ void    MemReset ();
 void    MemResetPaging ();
 void    MemUpdatePaging(BOOL initialize);
 LPVOID	MemGetSlotParameters (UINT uSlot);
+bool    MemGetAnnunciator(UINT annunciator);
 std::string MemGetSnapshotUnitAuxSlotName(void);
 void    MemSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
-bool    MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version);
+bool    MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT unitVersion);
 void    MemSaveSnapshotAux(class YamlSaveHelper& yamlSaveHelper);
-bool    MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT version);
+bool    MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT unitVersion);
 
 BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles);
 
diff --git a/source/NTSC.cpp b/source/NTSC.cpp
index 95e7c54f..186e3ba5 100644
--- a/source/NTSC.cpp
+++ b/source/NTSC.cpp
@@ -1378,6 +1378,12 @@ void updateScreenDoubleHires80Simplified (long cycles6502 ) // wsUpdateVideoDblH
 				uint8_t a = *MemGetAuxPtr(addr);
 				uint8_t m = *MemGetMainPtr(addr);
 
+				if (RGB_IsMixMode() && !MemGetAnnunciator(2))	// AN2 inverts high bit? (GH#633)
+				{
+					a ^= 0x80;
+					m ^= 0x80;
+				}
+
 				if (RGB_Is160Mode())
 				{
 					int width = UpdateDHiRes160Cell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
diff --git a/source/RGBMonitor.cpp b/source/RGBMonitor.cpp
index 81d41d34..93a8a0db 100644
--- a/source/RGBMonitor.cpp
+++ b/source/RGBMonitor.cpp
@@ -738,6 +738,7 @@ void VideoInitializeOriginal(baseColors_t pBaseNtscColors)
 static UINT g_rgbFlags = 0;
 static UINT g_rgbMode = 0;
 static WORD g_rgbPrevAN3Addr = 0;
+static bool g_rgbSet80COL = false;
 
 // Video7 RGB card:
 // . Clock in the !80COL state to define the 2 flags: F2, F1
@@ -745,7 +746,13 @@ static WORD g_rgbPrevAN3Addr = 0;
 // . NB. There's a final 5th AN3 transition to set DHGR mode
 void RGB_SetVideoMode(WORD address)
 {
-	if ((address&~1) != 0x5E)			// 0x5E or 0x5F?
+	if ((address&~1) == 0x0C)			// 0x0C or 0x0D? (80COL)
+	{
+		g_rgbSet80COL = true;
+		return;
+	}
+
+	if ((address&~1) != 0x5E)			// 0x5E or 0x5F? (DHIRES)
 		return;
 
 	// Precondition before toggling AN3:
@@ -754,10 +761,12 @@ void RGB_SetVideoMode(WORD address)
 	// . (*) "King's Quest 1" - see routine at 0x5FD7 (trigger by pressing TAB twice)
 	// . Apple II desktop sets DHGR B&W mode with HIRES off! (GH#631)
 	// Maybe there is no video-mode precondition?
-	if (g_uVideoMode & VF_MIXED)
+	// . After setting 80COL on/off then need a 0x5E->0x5F toggle. So if we see a 0x5F then reset (GH#633)
+	if ((g_uVideoMode & VF_MIXED) || (g_rgbSet80COL && address == 0x5F))
 	{
 		g_rgbMode = 0;
 		g_rgbPrevAN3Addr = 0;
+		g_rgbSet80COL = false;
 		return;
 	}
 
@@ -769,6 +778,7 @@ void RGB_SetVideoMode(WORD address)
 	}
 
 	g_rgbPrevAN3Addr = address;
+	g_rgbSet80COL = false;
 }
 
 bool RGB_Is140Mode(void)	// Extended 80-Column Text/AppleColor Card's Mode 2
@@ -806,6 +816,7 @@ void RGB_ResetState(void)
 #define SS_YAML_KEY_RGB_FLAGS "RGB mode flags"
 #define SS_YAML_KEY_RGB_MODE "RGB mode"
 #define SS_YAML_KEY_RGB_PREVIOUS_AN3 "Previous AN3"
+#define SS_YAML_KEY_RGB_80COL_CHANGED "80COL changed"
 
 void RGB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
 {
@@ -814,9 +825,10 @@ void RGB_SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
 	yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_RGB_FLAGS, g_rgbFlags);
 	yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_RGB_MODE, g_rgbMode);
 	yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_RGB_PREVIOUS_AN3, g_rgbPrevAN3Addr);
+	yamlSaveHelper.SaveBool(SS_YAML_KEY_RGB_80COL_CHANGED, g_rgbSet80COL);
 }
 
-void RGB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper)
+void RGB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT cardVersion)
 {
 	if (!yamlLoadHelper.GetSubMap(SS_YAML_KEY_RGB_CARD))
 		throw std::string("Card: Expected key: ") + std::string(SS_YAML_KEY_RGB_CARD);
@@ -825,5 +837,8 @@ void RGB_LoadSnapshot(YamlLoadHelper& yamlLoadHelper)
 	g_rgbMode = yamlLoadHelper.LoadUint(SS_YAML_KEY_RGB_MODE);
 	g_rgbPrevAN3Addr = yamlLoadHelper.LoadUint(SS_YAML_KEY_RGB_PREVIOUS_AN3);
 
+	if (cardVersion >= 3)
+		g_rgbSet80COL = yamlLoadHelper.LoadBool(SS_YAML_KEY_RGB_80COL_CHANGED);
+
 	yamlLoadHelper.PopMap();
 }
diff --git a/source/RGBMonitor.h b/source/RGBMonitor.h
index 0f7a16b8..b6b26ab7 100644
--- a/source/RGBMonitor.h
+++ b/source/RGBMonitor.h
@@ -16,4 +16,4 @@ bool RGB_Is560Mode(void);
 void RGB_ResetState(void);
 
 void RGB_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
-void RGB_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper);
+void RGB_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT cardVersion);