From df49d8de1eac36f04a5cf84d7b0c03ffceec91ba Mon Sep 17 00:00:00 2001
From: taoenwen <67533945+taoenwen@users.noreply.github.com>
Date: Tue, 3 May 2022 20:59:41 +0800
Subject: [PATCH] neogeo update (#1015)

[1-1] NON-PCB CMC-encrypted games now allow Sprite-ROM to be longer than 0x4000000;
[1-2] The excess also applies to CMC encryption/decryption.
[2-1] In the case of ips, the reserved length of P-ROM/C-ROM/V-ROM is increased.
[2-2] ips extends the length of sprite-ROM, and in this mode, there is a judgment of the true length to ensure that CMC built-in TextRom can be correctly recognized.
[2-3] When synchronizing ips cmc decrypts the length of the temporary memory, it avoids overflows caused by inconsistencies in the length of the two temporary memory.
---
 src/burn/drv/neogeo/d_neogeo.cpp | 55 ++++++++++++++++----------------
 src/burn/drv/neogeo/neo_run.cpp  | 35 ++++++++++++++++++--
 src/burn/drv/neogeo/neogeo.cpp   | 25 ++++++++++++++-
 3 files changed, 85 insertions(+), 30 deletions(-)

diff --git a/src/burn/drv/neogeo/d_neogeo.cpp b/src/burn/drv/neogeo/d_neogeo.cpp
index fe803ea02b..2e57b6cf0d 100644
--- a/src/burn/drv/neogeo/d_neogeo.cpp
+++ b/src/burn/drv/neogeo/d_neogeo.cpp
@@ -18972,43 +18972,44 @@ struct BurnDriver BurnDrvkf2k2ps2 = {
 };
 
 // The King of Fighters 2002 (PlayStation 2, Hack)
-// Hack by Dream
+// Hacked by Dream
 
-static struct BurnRomInfo kf2k2ps2bRomDesc[] = {
+static struct BurnRomInfo kof2002ps2RomDesc[] = {
+	/* Encrypted */
 	{ "265-p1ps2.p1",		0x100000, 0x9da95b36, 1 | BRF_ESS | BRF_PRG }, //  0 68K code
-	{ "265-p2ps2.sp2",		0x500000, 0x9846db3a, 1 | BRF_ESS | BRF_PRG }, //  1
-
-	{ "265-s1ps2.s1",		0x020000, 0x714ade47, 2 | BRF_GRA },           //  2 Text layer tiles
+	{ "265-p2ps2.sp2",		0x500000, 0x11419517, 1 | BRF_ESS | BRF_PRG }, //  1
 
-	{ "265-c1ps2.c1",		0x800000, 0x7efa6ef7, 3 | BRF_GRA },           //  3 Sprite data
-	{ "265-c2ps2.c2",		0x800000, 0xaa82948b, 3 | BRF_GRA },           //  4
-	{ "265-c3ps2.c3",		0x800000, 0x959fad0b, 3 | BRF_GRA },           //  5
-	{ "265-c4ps2.c4",		0x800000, 0xefe6a468, 3 | BRF_GRA },           //  6
-	{ "265-c5ps2.c5",		0x800000, 0x74bba7c6, 3 | BRF_GRA },           //  7
-	{ "265-c6ps2.c6",		0x800000, 0xe20d2216, 3 | BRF_GRA },           //  8
-	{ "265-c7ps2.c7",		0x800000, 0xf0897b93, 3 | BRF_GRA },           //  9
-	{ "265-c8ps2.c8",		0x800000, 0x8d27a4a6, 3 | BRF_GRA },           // 10
-	{ "265-c9ps2.c9",		0x800000, 0x9939c08a, 3 | BRF_GRA },           // 11
-	{ "265-c10ps2.c10",		0x800000, 0xc724c069, 3 | BRF_GRA },           // 12
+	/* The Encrypted Boards do not have an s1 rom, data for it comes from the Cx ROMs */
+	/* Encrypted */
+	{ "265-c1ps2.c1",		0x800000, 0xa92b140e, 3 | BRF_GRA },           //  2 Sprite data
+	{ "265-c2ps2.c2",		0x800000, 0x365e3945, 3 | BRF_GRA },           //  3
+	{ "265-c3ps2.c3",		0x800000, 0xe88beb81, 3 | BRF_GRA },           //  4
+	{ "265-c4ps2.c4",		0x800000, 0x06c374e8, 3 | BRF_GRA },           //  5
+	{ "265-c5ps2.c5",		0x800000, 0x4ffb0fdf, 3 | BRF_GRA },           //  6
+	{ "265-c6ps2.c6",		0x800000, 0xa33c38b9, 3 | BRF_GRA },           //  7
+	{ "265-c7ps2.c7",		0x800000, 0x186cd736, 3 | BRF_GRA },           //  8
+	{ "265-c8ps2.c8",		0x800000, 0xaf60bcf9, 3 | BRF_GRA },           //  9
+	{ "265-c9ps2.c9",		0x800000, 0xbbbd99e5, 3 | BRF_GRA },           // 10
+	{ "265-c10ps2.c10",		0x800000, 0x5d820e2e, 3 | BRF_GRA },           // 11
 
-	{ "265-m1ps2.m1",		0x020000, 0xab9d360e, 4 | BRF_ESS | BRF_PRG }, // 13 Z80 code
+	/* Encrypted */
+	{ "265-m1ps2.m1",		0x020000, 0x23961378, 4 | BRF_ESS | BRF_PRG }, // 12 Z80 code
 
-	{ "265-v1sp2.v1",		0x400000, 0x13d98607, 5 | BRF_SND },           // 14 Sound data
-	{ "265-v2sp2.v2",		0x400000, 0x9cf74677, 5 | BRF_SND },           // 15
-	{ "265-v3sp2.v3",		0x400000, 0x8e9448b5, 5 | BRF_SND },           // 16
-	{ "265-v4sp2.v4",		0x400000, 0x067271b5, 5 | BRF_SND },           // 17
+	/* Encrypted */
+	{ "265-v1.v1",			0x800000, 0x15e8f3f5, 5 | BRF_SND },           // 11 Sound data
+	{ "265-v2.v2",			0x800000, 0xda41d6f9, 5 | BRF_SND },           // 12
 };
 
-STDROMPICKEXT(kf2k2ps2b, kf2k2ps2b, neogeo)
-STD_ROM_FN(kf2k2ps2b)
+STDROMPICKEXT(kof2002ps2, kof2002ps2, neogeo)
+STD_ROM_FN(kof2002ps2)
 
-struct BurnDriver BurnDrvkf2k2ps2b = {
-	"kf2k2ps2b", "kof2002", "neogeo", NULL, "2018",
+struct BurnDriver BurnDrvkof2002ps2 = {
+	"kof2002ps2", "kof2002", "neogeo", NULL, "2018",
 	"The King of Fighters 2002 (PlayStation 2, Hack)\0", "hack only enabled in AES mode", "Hack", "Neo Geo MVS",
 	NULL, NULL, NULL, NULL,
-	BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_SNK_NEOGEO, GBF_VSFIGHT, FBF_KOF,
-	NULL, kf2k2ps2bRomInfo, kf2k2ps2bRomName, NULL, NULL, NULL, NULL, neogeoInputInfo, neoaesjapanDIPInfo,
-	NeoInit, NeoExit, NeoFrame, NeoRender, NeoScan, &NeoRecalcPalette,
+	BDF_GAME_WORKING | BDF_CLONE | BDF_HACK, 2, HARDWARE_PREFIX_CARTRIDGE | HARDWARE_SNK_NEOGEO | HARDWARE_SNK_CMC50 | HARDWARE_SNK_ENCRYPTED_M1, GBF_VSFIGHT, FBF_KOF,
+	NULL, kof2002ps2RomInfo, kof2002ps2RomName, NULL, NULL, NULL, NULL, neogeoInputInfo, neoaesjapanDIPInfo,
+	kof2002Init, NeoExit, NeoFrame, NeoRender, NeoScan, &NeoRecalcPalette,
 	0x1000,	304, 224, 4, 3
 };
 
diff --git a/src/burn/drv/neogeo/neo_run.cpp b/src/burn/drv/neogeo/neo_run.cpp
index 1016ad00ae..05ad781b0c 100644
--- a/src/burn/drv/neogeo/neo_run.cpp
+++ b/src/burn/drv/neogeo/neo_run.cpp
@@ -569,6 +569,9 @@ static INT32 LoadRoms()
 		}
 		nCodeSize[nNeoActiveSlot] = (nCodeSize[nNeoActiveSlot] + 0x0FFFFF) & ~0x0FFFFF;
 
+		// Extend the length of[nCodeSize] to fit the ips of the hack games.
+		if (bDoIpsPatch) nCodeSize[nNeoActiveSlot] += (0x200000 << 1);
+
 		nSpriteSize[nNeoActiveSlot] = 0;
 
 		if (BurnDrvGetHardwareCode() & HARDWARE_SNK_SWAPC) {
@@ -605,6 +608,9 @@ static INT32 LoadRoms()
 			nSpriteSize[nNeoActiveSlot] += ri.nLen * 2;
 		}
 
+		// The [nSpriteSize] here corresponds to the setting of [nBuf1Len] in [neogeo.cpp].
+		if (bDoIpsPatch) nSpriteSize[nNeoActiveSlot] += (0x800000 << 2);
+
 		{
 			UINT32 nSize = nSpriteSize[nNeoActiveSlot];
 //			if (nSize > 0x4000000) {
@@ -633,12 +639,13 @@ static INT32 LoadRoms()
 				BurnDrvGetRomInfo(&ri, pInfo->nADPCMOffset + i);
 				if (ri.nLen > nMaxSize) nMaxSize = ri.nLen;
 			}
-			nYM2610ADPCMASize[nNeoActiveSlot] += nMaxSize * pInfo->nADPCMANum;
+			nYM2610ADPCMASize[nNeoActiveSlot] += bDoIpsPatch ? (nMaxSize << 1) * pInfo->nADPCMANum : nMaxSize * pInfo->nADPCMANum;
 
 			for (INT32 i = 0; i < pInfo->nADPCMBNum; i++) {
 				BurnDrvGetRomInfo(&ri, pInfo->nADPCMOffset + pInfo->nADPCMANum + i);
 				nYM2610ADPCMBSize[nNeoActiveSlot] += ri.nLen;
 			}
+			if (bDoIpsPatch) nYM2610ADPCMBSize[nNeoActiveSlot] *= 2;
 
 			bprintf(0, _T("ADPCM-A Size:\t%x\n"), nYM2610ADPCMASize[nNeoActiveSlot]);
 			bprintf(0, _T("ADPCM-B Size:\t%x\n"), nYM2610ADPCMBSize[nNeoActiveSlot]);
@@ -692,9 +699,33 @@ static INT32 LoadRoms()
 			// Load S ROM data
 			BurnLoadRom(NeoTextROM[nNeoActiveSlot], pInfo->nTextOffset, 1);
 		} else {
+			// With IPS, The true length of [nSpriteSize] will be obtained.
+			UINT32 nRealSpriteSize = nSpriteSize[nNeoActiveSlot];
+
+			if (bDoIpsPatch) {
+
+				// If the expansion bytes of 0x800000 << 2 are all empty data,
+				// then [SpriteSize] will subtract the expansion part to ensure that [NeoTextROM] is obtained correctly.
+				for (INT32 i = 0, nIndex = 0; i < ((0x800000 << 2) / nNeoTextROMSize[nNeoActiveSlot]); i++, nIndex++) {
+
+					// The last byte position segment to appear is the true Length of [nSpriteSize].
+					// First move the pointer to the last data segment of the length of [nNeoTextROMSize].
+					UINT8* pFind = NeoSpriteROM[nNeoActiveSlot] + nSpriteSize[nNeoActiveSlot] - ((i + 1) * nNeoTextROMSize[nNeoActiveSlot]);
+
+					for (INT32 j = 0; j < (nNeoTextROMSize[nNeoActiveSlot] / sizeof(UINT32)); j += sizeof(UINT32)) {
+						// Data has been found
+						if (0 != *(UINT32*)&pFind[j]) {
+							i = ((0x800000 << 2) / nNeoTextROMSize[nNeoActiveSlot]);
+							break;
+						}
+					}
+					if (i != ((0x800000 << 2) / nNeoTextROMSize[nNeoActiveSlot]))
+						nRealSpriteSize -= nNeoTextROMSize[nNeoActiveSlot];
+				}
+			}
 			// Extract data from the end of C ROMS
 			BurnUpdateProgress(0.0, _T("Decrypting text layer graphics...")/*, BST_DECRYPT_TXT*/, 0);
-			NeoCMCExtractSData(NeoSpriteROM[nNeoActiveSlot], NeoTextROM[nNeoActiveSlot], nSpriteSize[nNeoActiveSlot], nNeoTextROMSize[nNeoActiveSlot]);
+			NeoCMCExtractSData(NeoSpriteROM[nNeoActiveSlot], NeoTextROM[nNeoActiveSlot], nRealSpriteSize, nNeoTextROMSize[nNeoActiveSlot]);
 
 			if ((BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK) == HARDWARE_SNK_DEDICATED_PCB) {
 				for (INT32 i = 0; i < nNeoTextROMSize[nNeoActiveSlot]; i++) {
diff --git a/src/burn/drv/neogeo/neogeo.cpp b/src/burn/drv/neogeo/neogeo.cpp
index 360f5356b4..6a54c29d22 100644
--- a/src/burn/drv/neogeo/neogeo.cpp
+++ b/src/burn/drv/neogeo/neogeo.cpp
@@ -91,7 +91,12 @@ INT32 NeoLoadSprites(INT32 nOffset, INT32 nNum, UINT8* pDest, UINT32 nSpriteSize
 			}
 		}
 
-		pBuf1 = (UINT8*)BurnMalloc(nRomSize * 2);
+		// The length of the temporary memory corresponding to the CMC decryption.
+		// If the temporary memory length here is not set enough, a memory out-of-bounds error will occur during the [BurnExtLoadRom] process of [load.cpp].
+		// The temporary memory length here corresponds to the setting of [neo_run.cpp] in the ips environment.
+		UINT32 nBuf1Len = bDoIpsPatch ? (nRomSize << 1) + (0x800000 << 2) : nRomSize << 1;
+
+		pBuf1 = (UINT8*)BurnMalloc(nBuf1Len);
 		if (pBuf1 == NULL) {
 			return 1;
 		}
@@ -144,6 +149,13 @@ INT32 NeoLoadSprites(INT32 nOffset, INT32 nNum, UINT8* pDest, UINT32 nSpriteSize
 //					BurnUpdateProgress(dProgress, NULL/*, 0*/, 0);
 					NeoCMCDecrypt(nNeoProtectionXor, pDest, pBuf1 + j, i * (nRomSize * 2) + j, 0x400000, nSpriteSize);
 				}
+
+				// CMC decryption will not process data other than 0x4000000 in non PCB status.
+				// ips expansion data must be additionally loaded into reserved memory.
+				// In ips mode, the data segments that expand the capacity are not encrypted, otherwise CMC encryption will cause data redundancy.
+				if (bDoIpsPatch && i == (nNum >> 1) - 1) {
+					memcpy(pDest + (i + 1) * (nRomSize << 1), pBuf1 + (nRomSize << 1), nBuf1Len - (nRomSize << 1));
+				}
 			} else {
 				// The kof2k3 PCB has 96MB of graphics ROM, however the last 16MB are unused, and the protection/decryption hardware does not see them
 				if ((BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK) == HARDWARE_SNK_DEDICATED_PCB) {
@@ -154,6 +166,17 @@ INT32 NeoLoadSprites(INT32 nOffset, INT32 nNum, UINT8* pDest, UINT32 nSpriteSize
 						//					BurnUpdateProgress(dProgress, NULL, /*0,*/ 0);
 						NeoCMCDecrypt(nNeoProtectionXor, pDest + 0x4000000, pBuf1 + j, j, 0x400000, 0x1000000);
 					}
+				} else {
+					// Hack games that expands the capacity of Sprites.
+					// Additional processing of data after 0x4000000, loaded into memory.
+					// To prevent overflow, the data here should no longer be used to increase capacity ips.
+					memcpy(pDest + i * (nRomSize << 1), pBuf1, nRomSize << 1);
+
+					for (UINT32 j = 0; j < nRomSize * 2; j += 0x400000) {
+
+						// For CMC encryption in non-PCB state, the data after the 0x4000000 is also decrypted.
+						NeoCMCDecrypt(nNeoProtectionXor, pDest+ i * (nRomSize << 1), pBuf1 + j, j, 0x400000, nRomSize << 1);
+					}
 				}
 			}
 		}