summaryrefslogtreecommitdiffstats
path: root/src/hbmame/bus/neogeo/prot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/hbmame/bus/neogeo/prot.cpp')
-rw-r--r--src/hbmame/bus/neogeo/prot.cpp3131
1 files changed, 3131 insertions, 0 deletions
diff --git a/src/hbmame/bus/neogeo/prot.cpp b/src/hbmame/bus/neogeo/prot.cpp
new file mode 100644
index 00000000000..27af99cca04
--- /dev/null
+++ b/src/hbmame/bus/neogeo/prot.cpp
@@ -0,0 +1,3131 @@
+// license:BSD-3-Clause
+// copyright-holders:S. Smith,David Haywood
+#include "neogeo.h"
+
+
+DEFINE_DEVICE_TYPE(NGBOOTLEG_PROT, ngbootleg_prot_device, "ngbootleg_prot", "NeoGeo Protection (Bootleg)")
+
+
+ngbootleg_prot_device::ngbootleg_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, NGBOOTLEG_PROT, tag, owner, clock)
+ , kof2k3_overlay(0)
+ , m_mainrom(nullptr)
+ , m_fixedrom(nullptr)
+ , m_bankdev(nullptr)
+ { }
+
+
+void ngbootleg_prot_device::device_start()
+{
+ memset(m_cartridge_ram, 0x00, 0x2000);
+
+ save_item(NAME(m_cartridge_ram));
+}
+
+void ngbootleg_prot_device::device_reset() { }
+
+
+/* General Bootleg Functions - used by more than 1 game */
+
+
+void ngbootleg_prot_device::neogeo_bootleg_cx_decrypt(uint8_t*sprrom, uint32_t sprrom_size)
+{
+ int i;
+ int cx_size = sprrom_size;
+ uint8_t *rom = sprrom;
+ std::vector<uint8_t> buf( cx_size );
+
+ memcpy( &buf[0], rom, cx_size );
+
+ for( i = 0; i < cx_size / 0x40; i++ )
+ memcpy( &rom[ i * 0x40 ], &buf[ (i ^ 1) * 0x40 ], 0x40 );
+}
+
+
+void ngbootleg_prot_device::neogeo_bootleg_sx_decrypt(uint8_t* fixed, uint32_t fixed_size, int value )
+{
+ int sx_size = fixed_size;
+ uint8_t *rom = fixed;
+ int i;
+
+ if (value == 1)
+ {
+ std::vector<uint8_t> buf( sx_size );
+ memcpy( &buf[0], rom, sx_size );
+
+ for( i = 0; i < sx_size; i += 0x10 )
+ {
+ memcpy( &rom[ i ], &buf[ i + 8 ], 8 );
+ memcpy( &rom[ i + 8 ], &buf[ i ], 8 );
+ }
+ }
+ else if (value == 2)
+ {
+ for( i = 0; i < sx_size; i++ )
+ rom[ i ] = bitswap<8>( rom[ i ], 7, 6, 0, 4, 3, 2, 1, 5 );
+ }
+}
+
+
+
+/* The King of Fighters '97 Oroshi Plus 2003 (bootleg) */
+
+void ngbootleg_prot_device::kof97oro_px_decode(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ int i;
+ std::vector<uint16_t> tmp( 0x500000 );
+ uint16_t *src = (uint16_t*)cpurom;
+
+ for (i = 0; i < 0x500000/2; i++)
+ tmp[i] = src[i ^ 0x7ffef];
+
+ memcpy (src, &tmp[0], 0x500000);
+}
+
+
+/* The King of Fighters 10th Anniversary (The King of Fighters 2002 bootleg) */
+
+
+/* this uses RAM based tiles for the text layer, however the implementation
+ is incomplete, at the moment the S data is copied from the program rom on
+ start-up instead */
+
+void ngbootleg_prot_device::kof10thBankswitch(address_space &space, uint16_t nBank)
+{
+ uint32_t bank = 0x100000 + ((nBank & 7) << 20);
+ if (bank >= 0x700000)
+ bank = 0x100000;
+ m_bankdev->neogeo_set_main_cpu_bank_address(bank);
+}
+
+READ16_MEMBER( ngbootleg_prot_device::kof10th_RAMB_r )
+{
+ return m_cartridge_ram[offset];
+}
+
+READ16_MEMBER(ngbootleg_prot_device::kof10th_RAM2_r)
+{
+// printf("kof10th_RAM2_r\n");
+ return m_cartridge_ram2[offset];
+}
+
+WRITE16_MEMBER( ngbootleg_prot_device::kof10th_custom_w )
+{
+ if (!m_cartridge_ram[0xFFE]) { // Write to RAM bank A
+ //uint16_t *prom = (uint16_t*)m_mainrom;
+ COMBINE_DATA(&m_cartridge_ram2[(0x00000/2) + (offset & 0xFFFF)]);
+ }
+ else
+ { // Write S data on-the-fly
+ m_fixedrom[offset] = bitswap<8>(data,7,6,0,4,3,2,1,5);
+ }
+}
+
+WRITE16_MEMBER( ngbootleg_prot_device::kof10th_bankswitch_w )
+{
+ if (offset >= 0x5F000) {
+ if (offset == 0x5FFF8)
+ { // Standard bankswitch
+ kof10thBankswitch(space, data);
+ }
+ else
+ if (offset == 0x5FFFC && m_cartridge_ram[0xFFC] != data)
+ { // Special bankswitch
+ uint8_t *src = m_mainrom;
+ memcpy (src + 0x10000, src + ((data & 1) ? 0x810000 : 0x710000), 0xcffff);
+ }
+ COMBINE_DATA(&m_cartridge_ram[offset & 0xFFF]);
+ }
+}
+
+void ngbootleg_prot_device::install_kof10th_protection (cpu_device* maincpu, neogeo_banked_cart_device* bankdev, uint8_t* cpurom, uint32_t cpurom_size, uint8_t* fixedrom, uint32_t fixedrom_size)
+{
+ m_mainrom = cpurom;
+ m_fixedrom = fixedrom;
+ m_bankdev = bankdev;
+
+ maincpu->space(AS_PROGRAM).install_read_handler(0x0e0000, 0x0fffff, read16_delegate(FUNC(ngbootleg_prot_device::kof10th_RAM2_r),this));
+
+ maincpu->space(AS_PROGRAM).install_read_handler(0x2fe000, 0x2fffff, read16_delegate(FUNC(ngbootleg_prot_device::kof10th_RAMB_r),this));
+ maincpu->space(AS_PROGRAM).install_write_handler(0x200000, 0x23ffff, write16_delegate(FUNC(ngbootleg_prot_device::kof10th_custom_w),this));
+ maincpu->space(AS_PROGRAM).install_write_handler(0x240000, 0x2fffff, write16_delegate(FUNC(ngbootleg_prot_device::kof10th_bankswitch_w),this));
+ memcpy(m_cartridge_ram2, cpurom + 0xe0000, 0x20000);
+
+ // HACK: only save this at device_start (not allowed later)
+ if (machine().phase() <= machine_phase::INIT)
+ save_pointer(NAME(m_fixedrom), 0x40000);
+}
+
+void ngbootleg_prot_device::decrypt_kof10th(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ int i, j;
+ std::vector<uint8_t> dst(0x900000);
+ uint8_t *src = cpurom;
+
+ memcpy(&dst[0x000000], src + 0x700000, 0x100000); // Correct (Verified in Uni-bios)
+ memcpy(&dst[0x100000], src + 0x000000, 0x800000);
+
+ for (i = 0; i < 0x900000; i++)
+ {
+ j = bitswap<24>(i,23,22,21,20,19,18,17,16,15,14,13,12,11,2,9,8,7,1,5,4,3,10,6,0);
+ src[j] = dst[i];
+ }
+
+ // Altera protection chip patches these over P ROM
+ ((uint16_t*)src)[0x0124/2] = 0x000d; // Enables XOR for RAM moves, forces SoftDIPs, and USA region
+ ((uint16_t*)src)[0x0126/2] = 0xf7a8;
+ ((uint16_t*)src)[0x8bf4/2] = 0x4ef9; // Run code to change "S" data
+ ((uint16_t*)src)[0x8bf6/2] = 0x000d;
+ ((uint16_t*)src)[0x8bf8/2] = 0xf980;
+}
+
+
+/* The King of Fighters 10th Anniversary Extra Plus (The King of Fighters 2002 bootleg) */
+
+
+void ngbootleg_prot_device::kf10thep_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ uint16_t *rom = (uint16_t*)cpurom;
+ std::vector<uint16_t> buf(0x100000/2);
+
+ memcpy(&buf[0x000000/2], &rom[0x060000/2], 0x20000);
+ memcpy(&buf[0x020000/2], &rom[0x100000/2], 0x20000);
+ memcpy(&buf[0x040000/2], &rom[0x0e0000/2], 0x20000);
+ memcpy(&buf[0x060000/2], &rom[0x180000/2], 0x20000);
+ memcpy(&buf[0x080000/2], &rom[0x020000/2], 0x20000);
+ memcpy(&buf[0x0a0000/2], &rom[0x140000/2], 0x20000);
+ memcpy(&buf[0x0c0000/2], &rom[0x0c0000/2], 0x20000);
+ memcpy(&buf[0x0e0000/2], &rom[0x1a0000/2], 0x20000);
+ memcpy(&buf[0x0002e0/2], &rom[0x0402e0/2], 0x6a); // copy banked code to a new memory region
+ memcpy(&buf[0x0f92bc/2], &rom[0x0492bc/2], 0xb9e); // copy banked code to a new memory region
+ memcpy(rom, &buf[0], 0x100000);
+
+ for (int i = 0xf92bc/2; i < 0xf9e58/2; i++)
+ {
+ if (rom[i+0] == 0x4eb9 && rom[i+1] == 0x0000) rom[i+1] = 0x000F; // correct JSR in moved code
+ if (rom[i+0] == 0x4ef9 && rom[i+1] == 0x0000) rom[i+1] = 0x000F; // correct JMP in moved code
+ }
+ rom[0x00342/2] = 0x000f;
+
+ memmove(&rom[0x100000/2], &rom[0x200000/2], 0x600000);
+}
+
+
+/* The King of Fighters 10th Anniversary 2005 Unique (The King of Fighters 2002 bootleg) */
+
+
+void ngbootleg_prot_device::kf2k5uni_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ int i, j, ofst;
+ uint8_t *src = cpurom;
+ uint8_t dst[0x80];
+
+ for (i = 0; i < 0x800000; i+=0x80)
+ {
+ for (j = 0; j < 0x80; j+=2)
+ {
+ ofst = bitswap<8>(j, 0, 3, 4, 5, 6, 1, 2, 7);
+ memcpy(&dst[j], src + i + ofst, 2);
+ }
+ memcpy(src + i, &dst[0], 0x80);
+ }
+
+ memcpy(src, src + 0x600000, 0x100000); // Seems to be the same as kof10th
+}
+
+void ngbootleg_prot_device::kf2k5uni_sx_decrypt(uint8_t* fixedrom, uint32_t fixedrom_size)
+{
+ int i;
+ uint8_t *srom = fixedrom;
+
+ for (i = 0; i < 0x20000; i++)
+ srom[i] = bitswap<8>(srom[i], 4, 5, 6, 7, 0, 1, 2, 3);
+}
+
+void ngbootleg_prot_device::kf2k5uni_mx_decrypt(uint8_t* audiorom, uint32_t audiorom_size)
+{
+ int i;
+ uint8_t *mrom = audiorom;
+
+ for (i = 0; i < 0x30000; i++)
+ mrom[i] = bitswap<8>(mrom[i], 4, 5, 6, 7, 0, 1, 2, 3);
+}
+
+void ngbootleg_prot_device::decrypt_kf2k5uni(uint8_t* cpurom, uint32_t cpurom_size, uint8_t* audiorom, uint32_t audiorom_size, uint8_t* fixedrom, uint32_t fixedrom_size)
+{
+ kf2k5uni_px_decrypt(cpurom, cpurom_size);
+ kf2k5uni_sx_decrypt(fixedrom, fixedrom_size);
+ kf2k5uni_mx_decrypt(audiorom, audiorom_size);
+}
+
+
+/* The King of Fighters 2002 (bootleg) */
+
+
+void ngbootleg_prot_device::kof2002b_gfx_decrypt(uint8_t *src, int size)
+{
+ int i, j;
+ static const uint8_t t[ 8 ][ 6 ] =
+ {
+ { 0, 8, 7, 6, 2, 1 },
+ { 1, 0, 8, 7, 6, 2 },
+ { 2, 1, 0, 8, 7, 6 },
+ { 6, 2, 1, 0, 8, 7 },
+ { 7, 6, 2, 1, 0, 8 },
+ { 0, 1, 2, 6, 7, 8 },
+ { 2, 1, 0, 6, 7, 8 },
+ { 8, 0, 7, 6, 2, 1 },
+ };
+
+ std::vector<uint8_t> dst( 0x10000 );
+
+ for ( i = 0; i < size; i+=0x10000 )
+ {
+ memcpy( &dst[0], src+i, 0x10000 );
+
+ for ( j = 0; j < 0x200; j++ )
+ {
+ int n = (j & 0x38) >> 3;
+ int ofst = bitswap<16>(j, 15, 14, 13, 12, 11, 10, 9, t[n][0], t[n][1], t[n][2], 5, 4, 3, t[n][3], t[n][4], t[n][5]);
+ memcpy( src+i+ofst*128, &dst[j*128], 128 );
+ }
+ }
+}
+
+
+/* The King of Fighters 2002 Magic Plus (bootleg) */
+
+
+void ngbootleg_prot_device::kf2k2mp_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ int i,j;
+
+ uint8_t *src = cpurom;
+ uint8_t dst[0x80];
+
+ memmove(src, src + 0x300000, 0x500000);
+
+ for (i = 0; i < 0x800000; i+=0x80)
+ {
+ for (j = 0; j < 0x80 / 2; j++)
+ {
+ int ofst = bitswap<8>( j, 6, 7, 2, 3, 4, 5, 0, 1 );
+ memcpy(dst + j * 2, src + i + ofst * 2, 2);
+ }
+ memcpy(src + i, dst, 0x80);
+ }
+}
+
+
+/* The King of Fighters 2002 Magic Plus II (bootleg) */
+
+
+void ngbootleg_prot_device::kf2k2mp2_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst(0x600000);
+
+ memcpy (&dst[0x000000], &src[0x1C0000], 0x040000);
+ memcpy (&dst[0x040000], &src[0x140000], 0x080000);
+ memcpy (&dst[0x0C0000], &src[0x100000], 0x040000);
+ memcpy (&dst[0x100000], &src[0x200000], 0x400000);
+ memcpy (&src[0x000000], &dst[0x000000], 0x600000);
+}
+
+
+/* Crouching Tiger Hidden Dragon 2003 (bootleg of King of Fighters 2001) */
+
+
+/* descrambling information from razoola */
+void ngbootleg_prot_device::cthd2003_neogeo_gfx_address_fix_do(uint8_t* sprrom, uint32_t sprrom_size, int start, int end, int bit3shift, int bit2shift, int bit1shift, int bit0shift)
+{
+ int i,j;
+ int tilesize=128;
+
+ std::vector<uint8_t> rom(16*tilesize); // 16 tiles buffer
+ uint8_t* realrom = sprrom + start*tilesize;
+
+ for (i = 0; i < (end-start)/16; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ int offset = (((j&1)>>0)<<bit0shift) +(((j&2)>>1)<<bit1shift) +(((j&4)>>2)<<bit2shift) +(((j&8)>>3)<<bit3shift);
+
+ memcpy(&rom[j*tilesize], realrom+offset*tilesize, tilesize);
+ }
+ memcpy(realrom,&rom[0],tilesize*16);
+ realrom += 16*tilesize;
+ }
+}
+
+void ngbootleg_prot_device::cthd2003_neogeo_gfx_address_fix(uint8_t* sprrom, uint32_t sprrom_size, int start, int end)
+{
+ cthd2003_neogeo_gfx_address_fix_do(sprrom, sprrom_size, start+512*0, end+512*0, 0,3,2,1);
+ cthd2003_neogeo_gfx_address_fix_do(sprrom, sprrom_size, start+512*1, end+512*1, 1,0,3,2);
+ cthd2003_neogeo_gfx_address_fix_do(sprrom, sprrom_size, start+512*2, end+512*2, 2,1,0,3);
+ // skip 3 & 4
+ cthd2003_neogeo_gfx_address_fix_do(sprrom, sprrom_size, start+512*5, end+512*5, 0,1,2,3);
+ cthd2003_neogeo_gfx_address_fix_do(sprrom, sprrom_size, start+512*6, end+512*6, 0,1,2,3);
+ cthd2003_neogeo_gfx_address_fix_do(sprrom, sprrom_size, start+512*7, end+512*7, 0,2,3,1);
+}
+
+void ngbootleg_prot_device::cthd2003_c(uint8_t* sprrom, uint32_t sprrom_size, int pow)
+{
+ int i;
+
+ for (i=0; i<=192; i+=8)
+ cthd2003_neogeo_gfx_address_fix(sprrom, sprrom_size, i*512,i*512+512);
+
+ for (i=200; i<=392; i+=8)
+ cthd2003_neogeo_gfx_address_fix(sprrom, sprrom_size, i*512,i*512+512);
+
+ for (i=400; i<=592; i+=8)
+ cthd2003_neogeo_gfx_address_fix(sprrom, sprrom_size, i*512,i*512+512);
+
+ for (i=600; i<=792; i+=8)
+ cthd2003_neogeo_gfx_address_fix(sprrom, sprrom_size, i*512,i*512+512);
+
+ for (i=800; i<=992; i+=8)
+ cthd2003_neogeo_gfx_address_fix(sprrom, sprrom_size, i*512,i*512+512);
+
+ for (i=1000; i<=1016; i+=8)
+ cthd2003_neogeo_gfx_address_fix(sprrom, sprrom_size, i*512,i*512+512);
+}
+
+void ngbootleg_prot_device::decrypt_cthd2003(uint8_t* sprrom, uint32_t sprrom_size, uint8_t* audiorom, uint32_t audiorom_size, uint8_t* fixedrom, uint32_t fixedrom_size)
+{
+ uint8_t *romdata = fixedrom;
+ std::vector<uint8_t> tmp(8*128*128);
+
+ memcpy(&tmp[8*0*128], romdata+8*0*128, 8*32*128);
+ memcpy(&tmp[8*32*128], romdata+8*64*128, 8*32*128);
+ memcpy(&tmp[8*64*128], romdata+8*32*128, 8*32*128);
+ memcpy(&tmp[8*96*128], romdata+8*96*128, 8*32*128);
+ memcpy(romdata, &tmp[0], 8*128*128);
+
+ romdata = audiorom+0x10000;
+ memcpy(&tmp[8*0*128], romdata+8*0*128, 8*32*128);
+ memcpy(&tmp[8*32*128], romdata+8*64*128, 8*32*128);
+ memcpy(&tmp[8*64*128], romdata+8*32*128, 8*32*128);
+ memcpy(&tmp[8*96*128], romdata+8*96*128, 8*32*128);
+ memcpy(romdata, &tmp[0], 8*128*128);
+
+ memcpy(romdata-0x10000,romdata,0x10000);
+
+ cthd2003_c(sprrom, sprrom_size, 0);
+}
+
+WRITE16_MEMBER( ngbootleg_prot_device::cthd2003_bankswitch_w )
+{
+ int bankaddress;
+ static const int cthd2003_banks[8] = { 1,0,1,0,1,0,3,2 };
+ if (offset == 0)
+ {
+ bankaddress = 0x100000 + cthd2003_banks[data&7] * 0x100000;
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress);
+ }
+}
+
+void ngbootleg_prot_device::patch_cthd2003(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, uint8_t* cpurom, uint32_t cpurom_size)
+{
+ /* patches thanks to razoola */
+ int i;
+ uint16_t *mem16 = (uint16_t *)cpurom;
+
+ /* special ROM banking handler */
+ maincpu->space(AS_PROGRAM).install_write_handler(0x2ffff0, 0x2fffff, write16_delegate(FUNC(ngbootleg_prot_device::cthd2003_bankswitch_w),this));
+ m_bankdev = bankdev;
+
+ // theres still a problem on the character select screen but it seems to be related to cpu core timing issues,
+ // overclocking the 68k prevents it.
+
+ // fix garbage on s1 layer over everything
+ mem16[0xf415a/2] = 0x4ef9;
+ mem16[0xf415c/2] = 0x000f;
+ mem16[0xf415e/2] = 0x4cf2;
+ // Fix corruption in attract mode before title screen
+ for (i=0x1ae290/2;i < 0x1ae8d0/2; i=i+1)
+ mem16[i] = 0x0000;
+
+ // Fix for title page
+ for (i=0x1f8ef0/2;i < 0x1fa1f0/2; i=i+2)
+ {
+ mem16[i] -= 0x7000;
+ mem16[i+1] -= 0x0010;
+ }
+
+ // Fix for green dots on title page
+ for (i=0xac500/2;i < 0xac520/2; i=i+1)
+ mem16[i] = 0xFFFF;
+
+ // Fix for blanks as screen change level end clear
+ mem16[0x991d0/2] = 0xdd03;
+ mem16[0x99306/2] = 0xdd03;
+ mem16[0x99354/2] = 0xdd03;
+ mem16[0x9943e/2] = 0xdd03;
+}
+
+
+/* Crouching Tiger Hidden Dragon 2003 Super Plus (bootleg of King of Fighters 2001) */
+
+
+void ngbootleg_prot_device::ct2k3sp_sx_decrypt( uint8_t* fixedrom, uint32_t fixedrom_size )
+{
+ int rom_size = fixedrom_size;
+ uint8_t *rom = fixedrom;
+ std::vector<uint8_t> buf( rom_size );
+ int i;
+ int ofst;
+
+ memcpy( &buf[0], rom, rom_size );
+
+ for( i = 0; i < rom_size; i++ ){
+ ofst = bitswap<24>( (i & 0x1ffff), 23, 22, 21, 20, 19, 18, 17, 3, 0, 1, 4, 2, 13, 14, 16, 15, 5, 6, 11, 10, 9, 8, 7, 12 );
+
+ ofst += (i >> 17) << 17;
+
+ rom[ i ] = buf[ ofst ];
+ }
+
+ memcpy( &buf[0], rom, rom_size );
+
+ memcpy( &rom[ 0x08000 ], &buf[ 0x10000 ], 0x8000 );
+ memcpy( &rom[ 0x10000 ], &buf[ 0x08000 ], 0x8000 );
+ memcpy( &rom[ 0x28000 ], &buf[ 0x30000 ], 0x8000 );
+ memcpy( &rom[ 0x30000 ], &buf[ 0x28000 ], 0x8000 );
+}
+
+void ngbootleg_prot_device::decrypt_ct2k3sp(uint8_t* sprrom, uint32_t sprrom_size, uint8_t* audiorom, uint32_t audiorom_size, uint8_t* fixedrom, uint32_t fixedrom_size)
+{
+ uint8_t *romdata = audiorom + 0x10000;
+ std::vector<uint8_t> tmp(8*128*128);
+ memcpy(&tmp[8*0*128], romdata+8*0*128, 8*32*128);
+ memcpy(&tmp[8*32*128], romdata+8*64*128, 8*32*128);
+ memcpy(&tmp[8*64*128], romdata+8*32*128, 8*32*128);
+ memcpy(&tmp[8*96*128], romdata+8*96*128, 8*32*128);
+ memcpy(romdata, &tmp[0], 8*128*128);
+ memcpy(romdata - 0x10000, romdata, 0x10000);
+ ct2k3sp_sx_decrypt(fixedrom, fixedrom_size);
+ cthd2003_c(sprrom, sprrom_size, 0);
+}
+
+
+/* Crouching Tiger Hidden Dragon 2003 Super Plus alternate (bootleg of King of Fighters 2001) */
+
+
+void ngbootleg_prot_device::decrypt_ct2k3sa(uint8_t* sprrom, uint32_t sprrom_size, uint8_t* audiorom, uint32_t audiorom_size )
+{
+ uint8_t *romdata = audiorom + 0x10000;
+ std::vector<uint8_t> tmp(8*128*128);
+ memcpy(&tmp[8*0*128], romdata+8*0*128, 8*32*128);
+ memcpy(&tmp[8*32*128], romdata+8*64*128, 8*32*128);
+ memcpy(&tmp[8*64*128], romdata+8*32*128, 8*32*128);
+ memcpy(&tmp[8*96*128], romdata+8*96*128, 8*32*128);
+ memcpy(romdata, &tmp[0], 8*128*128);
+
+ memcpy(romdata - 0x10000, romdata, 0x10000);
+ cthd2003_c(sprrom, sprrom_size, 0);
+}
+
+void ngbootleg_prot_device::patch_ct2k3sa(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ /* patches thanks to razoola - same as for cthd2003*/
+ int i;
+ uint16_t *mem16 = (uint16_t *)cpurom;
+
+ // theres still a problem on the character select screen but it seems to be related to cpu core timing issues,
+ // overclocking the 68k prevents it.
+
+ // fix garbage on s1 layer over everything
+ mem16[0xf415a/2] = 0x4ef9;
+ mem16[0xf415c/2] = 0x000f;
+ mem16[0xf415e/2] = 0x4cf2;
+
+ // Fix corruption in attract mode before title screen
+ for (i=0x1ae290/2;i < 0x1ae8d0/2; i=i+1)
+ mem16[i] = 0x0000;
+
+ // Fix for title page
+ for (i=0x1f8ef0/2;i < 0x1fa1f0/2; i=i+2)
+ {
+ mem16[i] -= 0x7000;
+ mem16[i+1] -= 0x0010;
+ }
+
+ // Fix for green dots on title page
+ for (i=0xac500/2;i < 0xac520/2; i=i+1)
+ mem16[i] = 0xFFFF;
+
+ // Fix for blanks as screen change level end clear
+ mem16[0x991d0/2] = 0xdd03;
+ mem16[0x99306/2] = 0xdd03;
+ mem16[0x99354/2] = 0xdd03;
+ mem16[0x9943e/2] = 0xdd03;
+}
+
+
+/* King of Fighters Special Edition 2004 (bootleg of King of Fighters 2002) */
+
+
+void ngbootleg_prot_device::decrypt_kof2k4se_68k(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ uint8_t *src = cpurom+0x100000;
+ std::vector<uint8_t> dst(0x400000);
+ static const int sec[] = {0x300000, 0x200000, 0x100000, 0x000000};
+ memcpy(&dst[0], src, 0x400000);
+
+ for(uint8_t i = 0; i < 4; ++i)
+ memcpy(src + i*0x100000, &dst[sec[i]], 0x100000);
+}
+
+
+/* Lansquenet 2004 (Shock Troopers - 2nd Squad bootleg) */
+
+
+void ngbootleg_prot_device::lans2004_vx_decrypt(uint8_t* ymsndrom, uint32_t ymsndrom_size)
+{
+ uint8_t *rom = ymsndrom;
+ for (uint8_t i = 0; i < 0xA00000; i++)
+ rom[i] = bitswap<8>(rom[i], 0, 1, 5, 4, 3, 2, 6, 7);
+}
+
+void ngbootleg_prot_device::lans2004_decrypt_68k(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ /* Descrambling P ROMs - Thanks to Razoola for the info */
+ int i;
+ uint8_t *src = cpurom;
+ uint16_t *rom = (uint16_t*)cpurom;
+
+ static const int sec[] = { 0x3, 0x8, 0x7, 0xC, 0x1, 0xA, 0x6, 0xD };
+ std::vector<uint8_t> dst(0x600000);
+
+ for (i = 0; i < 8; i++)
+ memcpy (&dst[i * 0x20000], src + sec[i] * 0x20000, 0x20000);
+
+ memcpy (&dst[0x0BBB00], src + 0x045B00, 0x001710);
+ memcpy (&dst[0x02FFF0], src + 0x1A92BE, 0x000010);
+ memcpy (&dst[0x100000], src + 0x200000, 0x400000);
+ memcpy (src, &dst[0], 0x600000);
+
+ for (i = 0xBBB00/2; i < 0xBE000/2; i++)
+ {
+ if ((((rom[i]&0xFFBF)==0x4EB9) || ((rom[i]&0xFFBF)==0x43B9)) && (rom[i+1]==0x0000))
+ {
+ rom[i + 1] = 0x000B;
+ rom[i + 2] += 0x6000;
+ }
+ }
+
+ /* Patched by protection chip (Altera) ? */
+ rom[0x2D15C/2] = 0x000B;
+ rom[0x2D15E/2] = 0xBB00;
+ rom[0x2D1E4/2] = 0x6002;
+ rom[0x2EA7E/2] = 0x6002;
+ rom[0xBBCD0/2] = 0x6002;
+ rom[0xBBDF2/2] = 0x6002;
+ rom[0xBBE42/2] = 0x6002;
+}
+
+
+/* Metal Slug 5 Plus (bootleg) */
+
+
+READ16_MEMBER( ngbootleg_prot_device::mslug5_prot_r )
+{
+ logerror("PC %06x: access protected\n",machine().describe_context());
+ return 0xa0;
+}
+
+WRITE16_MEMBER( ngbootleg_prot_device::ms5plus_bankswitch_w )
+{
+ int bankaddress;
+ logerror("offset: %06x PC %06x: set banking %04x\n",offset,machine().describe_context(),data);
+ if ((offset == 0)&&(data == 0xa0))
+ {
+ bankaddress=0xa0;
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress);
+ logerror("offset: %06x PC %06x: set banking %04x\n\n",offset,machine().describe_context(),bankaddress);
+ }
+ else if(offset == 2)
+ {
+ data=data>>4;
+ //data=data&7;
+ bankaddress=data*0x100000;
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress);
+ logerror("offset: %06x PC %06x: set banking %04x\n\n",offset,machine().describe_context(),bankaddress);
+ }
+}
+
+void ngbootleg_prot_device::install_ms5plus_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev)
+{
+ // special ROM banking handler / additional protection
+ maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2ffff0, 0x2fffff,
+ read16_delegate(FUNC(ngbootleg_prot_device::mslug5_prot_r),this),
+ write16_delegate(FUNC(ngbootleg_prot_device::ms5plus_bankswitch_w),this));
+ m_bankdev = bankdev;
+}
+
+
+/* SNK vs. CAPCOM SVC CHAOS (bootleg) */
+
+
+void ngbootleg_prot_device::svcboot_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ static const uint8_t sec[] = { 0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00 };
+ int i;
+ int size = cpurom_size;
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst( size );
+ int ofst;
+ for( i = 0; i < size / 0x100000; i++ )
+ memcpy( &dst[ i * 0x100000 ], &src[ sec[ i ] * 0x100000 ], 0x100000 );
+
+ for( i = 0; i < size / 2; i++ )
+ {
+ ofst = bitswap<8>( (i & 0x0000ff), 7, 6, 1, 0, 3, 2, 5, 4 );
+ ofst += (i & 0xffff00);
+ memcpy( &src[ i * 2 ], &dst[ ofst * 2 ], 0x02 );
+ }
+}
+
+void ngbootleg_prot_device::svcboot_cx_decrypt(uint8_t*sprrom, uint32_t sprrom_size)
+{
+ static const uint8_t idx_tbl[ 0x10 ] = { 0, 1, 0, 1, 2, 3, 2, 3, 3, 4, 3, 4, 4, 5, 4, 5 };
+ static const uint8_t bitswap4_tbl[ 6 ][ 4 ] = { { 3, 0, 1, 2 }, { 2, 3, 0, 1 }, { 1, 2, 3, 0 }, { 0, 1, 2, 3 }, { 3, 2, 1, 0 }, { 3, 0, 2, 1 } };
+ int i;
+ int size = sprrom_size;
+ uint8_t *src = sprrom;
+ std::vector<uint8_t> dst( size );
+ int ofst;
+ memcpy( &dst[0], src, size );
+ for( i = 0; i < size / 0x80; i++ )
+ {
+ int idx = idx_tbl[ (i & 0xf00) >> 8 ];
+ int bit0 = bitswap4_tbl[ idx ][ 0 ];
+ int bit1 = bitswap4_tbl[ idx ][ 1 ];
+ int bit2 = bitswap4_tbl[ idx ][ 2 ];
+ int bit3 = bitswap4_tbl[ idx ][ 3 ];
+ ofst = bitswap<8>( (i & 0x0000ff), 7, 6, 5, 4, bit3, bit2, bit1, bit0 );
+ ofst += (i & 0xfffff00);
+ memcpy( &src[ i * 0x80 ], &dst[ ofst * 0x80 ], 0x80 );
+ }
+}
+
+
+/* SNK vs. CAPCOM SVC CHAOS Plus (bootleg set 1) */
+
+
+void ngbootleg_prot_device::svcplus_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ static const int sec[] = { 0x00, 0x03, 0x02, 0x05, 0x04, 0x01 };
+ int i, ofst, size = cpurom_size;
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst( size );
+ memcpy( &dst[0], src, size );
+ for( i = 0; i < size / 2; i++ )
+ {
+ ofst = bitswap<24>( (i & 0xfffff), 0x17, 0x16, 0x15, 0x14, 0x13, 0x00, 0x01, 0x02, 0x0f, 0x0e, 0x0d, 0x0c,
+ 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x10, 0x11, 0x12 );
+ ofst ^= 0x0f0007;
+ ofst += (i & 0xff00000);
+ memcpy( &src[ i * 0x02 ], &dst[ ofst * 0x02 ], 0x02 );
+ }
+ memcpy( &dst[0], src, size );
+ for( i = 0; i < 6; i++ )
+ memcpy( &src[ i * 0x100000 ], &dst[ sec[ i ] * 0x100000 ], 0x100000 );
+}
+
+void ngbootleg_prot_device::svcplus_px_hack(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ /* patched by the protection chip? */
+ uint16_t *mem16 = (uint16_t *)cpurom;
+ mem16[0x0f8016/2] = 0x33c1;
+}
+
+
+/* SNK vs. CAPCOM SVC CHAOS Plus (bootleg set 2) */
+
+
+void ngbootleg_prot_device::svcplusa_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ int i;
+ static const int sec[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x00 };
+ int size = cpurom_size;
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst( size );
+ memcpy( &dst[0], src, size );
+ for( i = 0; i < 6; i++ )
+ memcpy( &src[ i * 0x100000 ], &dst[ sec[ i ] * 0x100000 ], 0x100000 );
+}
+
+
+/* SNK vs. CAPCOM SVC CHAOS Super Plus (bootleg) */
+
+
+void ngbootleg_prot_device::svcsplus_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ static const int sec[] = { 0x06, 0x07, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00 };
+ int i, ofst, size = cpurom_size;
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst( size );
+ memcpy( &dst[0], src, size );
+ for( i = 0; i < size / 2; i++ )
+ {
+ ofst = bitswap<16>( (i & 0x007fff), 0x0f, 0x00, 0x08, 0x09, 0x0b, 0x0a, 0x0c, 0x0d, 0x04, 0x03, 0x01, 0x07, 0x06, 0x02, 0x05, 0x0e );
+ ofst += (i & 0x078000);
+ ofst += sec[ (i & 0xf80000) >> 19 ] << 19;
+ memcpy( &src[ i * 2 ], &dst[ ofst * 2 ], 0x02 );
+ }
+}
+
+void ngbootleg_prot_device::svcsplus_px_hack(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ /* patched by the protection chip? */
+ uint16_t *mem16 = (uint16_t *)cpurom;
+ mem16[0x9e90/2] = 0x000f;
+ mem16[0x9e92/2] = 0xc9c0;
+ mem16[0xa10c/2] = 0x4eb9;
+ mem16[0xa10e/2] = 0x000e;
+ mem16[0xa110/2] = 0x9750;
+}
+
+
+/* The King of Fighters 2003 (bootleg set 1) */
+
+
+READ16_MEMBER( ngbootleg_prot_device::kof2003_r)
+{
+ return m_cartridge_ram[offset];
+}
+
+READ16_MEMBER(ngbootleg_prot_device::kof2003_overlay_r) // hack?
+{
+ return kof2k3_overlay;
+}
+
+WRITE16_MEMBER( ngbootleg_prot_device::kof2003_w )
+{
+ data = COMBINE_DATA(&m_cartridge_ram[offset]);
+ if (offset == 0x1ff0/2 || offset == 0x1ff2/2)
+ {
+ uint8_t* cr = (uint8_t *)m_cartridge_ram;
+ uint32_t address = (cr[BYTE_XOR_LE(0x1ff3)]<<16)|(cr[BYTE_XOR_LE(0x1ff2)]<<8)|cr[BYTE_XOR_LE(0x1ff1)];
+ uint8_t prt = cr[BYTE_XOR_LE(0x1ff2)];
+
+ cr[BYTE_XOR_LE(0x1ff0)] = 0xa0;
+ cr[BYTE_XOR_LE(0x1ff1)] &= 0xfe;
+ cr[BYTE_XOR_LE(0x1ff3)] &= 0x7f;
+ m_bankdev->neogeo_set_main_cpu_bank_address(address+0x100000);
+
+ kof2k3_overlay = (prt & 0x00ff) | (kof2k3_overlay & 0xff00);
+ }
+}
+
+WRITE16_MEMBER( ngbootleg_prot_device::kof2003p_w )
+{
+ data = COMBINE_DATA(&m_cartridge_ram[offset]);
+ if (offset == 0x1ff0/2 || offset == 0x1ff2/2)
+ {
+ uint8_t* cr = (uint8_t *)m_cartridge_ram;
+ uint32_t address = (cr[BYTE_XOR_LE(0x1ff3)]<<16)|(cr[BYTE_XOR_LE(0x1ff2)]<<8)|cr[BYTE_XOR_LE(0x1ff0)];
+ uint8_t prt = cr[BYTE_XOR_LE(0x1ff2)];
+
+ cr[BYTE_XOR_LE(0x1ff0)] &= 0xfe;
+ cr[BYTE_XOR_LE(0x1ff3)] &= 0x7f;
+ m_bankdev->neogeo_set_main_cpu_bank_address(address+0x100000);
+
+ kof2k3_overlay = (prt & 0x00ff) | (kof2k3_overlay & 0xff00);
+ }
+}
+
+void ngbootleg_prot_device::kf2k3bl_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ static const uint8_t sec[] = { 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
+
+ int rom_size = 0x800000;
+ uint8_t *rom = cpurom;
+ std::vector<uint8_t> buf( rom_size );
+ memcpy( &buf[0], rom, rom_size );
+
+ for( int i = 0; i < rom_size / 0x100000; i++ )
+ memcpy( &rom[ i * 0x100000 ], &buf[ sec[ i ] * 0x100000 ], 0x100000 );
+}
+
+void ngbootleg_prot_device::kf2k3bl_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, uint8_t* cpurom, uint32_t cpurom_size)
+{
+ m_mainrom = cpurom;
+
+ maincpu->space(AS_PROGRAM).install_read_handler(0x58196, 0x58197, read16_delegate(FUNC(ngbootleg_prot_device::kof2003_overlay_r),this) );
+
+ maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2fe000, 0x2fffff, read16_delegate(FUNC(ngbootleg_prot_device::kof2003_r),this), write16_delegate(FUNC(ngbootleg_prot_device::kof2003_w),this) );
+ m_bankdev = bankdev;
+}
+
+
+/* The King of Fighters 2004 Plus / Hero (The King of Fighters 2003 bootleg) */
+
+
+void ngbootleg_prot_device::kf2k3pl_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ std::vector<uint16_t> tmp(0x100000/2);
+ uint16_t*rom16 = (uint16_t*)cpurom;
+ int i, j;
+
+ for (i = 0;i < 0x700000/2;i+=0x100000/2)
+ {
+ memcpy(&tmp[0], &rom16[i], 0x100000);
+ for (j = 0; j < 0x100000/2; j++)
+ rom16[i+j] = tmp[bitswap<24>(j,23,22,21,20,19,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)];
+ }
+
+ /* patched by Altera protection chip on PCB */
+ rom16[0xf38ac/2] = 0x4e75;
+
+ kof2k3_overlay = rom16[0x58196 / 2];
+}
+
+void ngbootleg_prot_device::kf2k3pl_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev, uint8_t* cpurom, uint32_t cpurom_size)
+{
+ m_mainrom = cpurom;
+ maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2fe000, 0x2fffff,
+ read16_delegate(FUNC(ngbootleg_prot_device::kof2003_r),this),
+ write16_delegate(FUNC(ngbootleg_prot_device::kof2003p_w),this) );
+ m_bankdev = bankdev;
+}
+
+
+/* The King of Fighters 2004 Ultra Plus (The King of Fighters 2003 bootleg) */
+
+
+void ngbootleg_prot_device::kf2k3upl_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ {
+ uint8_t *src = cpurom;
+ memmove(src+0x100000, src, 0x600000);
+ memmove(src, src+0x700000, 0x100000);
+ }
+
+ {
+ int i, ofst;
+ uint8_t *rom = cpurom + 0xfe000;
+ uint8_t *buf = cpurom + 0xd0610;
+
+ for( i = 0; i < 0x2000 / 2; i++ )
+ {
+ ofst = (i & 0xff00) + bitswap<8>( (i & 0x00ff), 7, 6, 0, 4, 3, 2, 1, 5 );
+ memcpy( &rom[ i * 2 ], &buf[ ofst * 2 ], 2 );
+ }
+ }
+
+ uint16_t*rom16 = (uint16_t*)cpurom;
+ kof2k3_overlay = rom16[0x58196 / 2];
+}
+
+
+/* Samurai Shodown V / Samurai Spirits Zero (bootleg) */
+
+
+void ngbootleg_prot_device::samsho5b_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ int i, ofst, px_size = cpurom_size;
+ uint8_t *rom = cpurom;
+ std::vector<uint8_t> buf( px_size );
+
+ memcpy( &buf[0], rom, px_size );
+
+ for( i = 0; i < px_size / 2; i++ )
+ {
+ ofst = bitswap<8>( (i & 0x000ff), 7, 6, 5, 4, 3, 0, 1, 2 );
+ ofst += (i & 0xfffff00);
+ ofst ^= 0x060005;
+ memcpy( &rom[ i * 2 ], &buf[ ofst * 2 ], 0x02 );
+ }
+
+ memcpy( &buf[0], rom, px_size );
+
+ memcpy( &rom[ 0x000000 ], &buf[ 0x700000 ], 0x100000 );
+ memcpy( &rom[ 0x100000 ], &buf[ 0x000000 ], 0x700000 );
+}
+
+
+void ngbootleg_prot_device::samsho5b_vx_decrypt(uint8_t* ymsndrom, uint32_t ymsndrom_size)
+{
+ int vx_size = ymsndrom_size;
+ uint8_t *rom = ymsndrom;
+
+ for( int i = 0; i < vx_size; i++ )
+ rom[ i ] = bitswap<8>( rom[ i ], 0, 1, 5, 4, 3, 2, 6, 7 );
+}
+
+
+/* Matrimelee / Shin Gouketsuji Ichizoku Toukon (bootleg) */
+
+
+#define MATRIMBLZ80( i ) ( i^(bitswap<8>(i&0x3,4,3,1,2,0,7,6,5)<<8) )
+
+void ngbootleg_prot_device::matrimbl_decrypt(uint8_t* sprrom, uint32_t sprrom_size, uint8_t* audiorom, uint32_t audiorom_size)
+{
+ /* decrypt Z80 */
+ uint8_t *rom = audiorom+0x10000;
+ std::vector<uint8_t> buf( 0x20000 );
+ int i, j;
+ memcpy( &buf[0], rom, 0x20000 );
+ for( i=0x00000; i<0x20000; i++ )
+ {
+ if ( i&0x10000 )
+ {
+ if ( i&0x800 )
+ {
+ j=MATRIMBLZ80( i );
+ j=j^0x10000;
+ }
+ else
+ {
+ j=MATRIMBLZ80(( i^0x01 ));
+ }
+ }
+ else
+ {
+ if ( i&0x800 )
+ {
+ j=MATRIMBLZ80(( i^0x01 ));
+ j=j^0x10000;
+ }
+ else
+ {
+ j=MATRIMBLZ80( i );
+ }
+ }
+ rom[ j ]=buf[ i ];
+ }
+ memcpy( rom-0x10000, rom, 0x10000 );
+
+ /* decrypt gfx */
+ cthd2003_c(sprrom,sprrom_size, 0 );
+}
+
+/***********************************************************************************************************************************/
+
+DEFINE_DEVICE_TYPE(KOG_PROT, kog_prot_device, "kog_prot", "NeoGeo Protection (King of Gladiator)")
+
+
+kog_prot_device::kog_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, KOG_PROT, tag, owner, clock)
+ , m_jumper(*this, "JUMPER")
+ { }
+
+
+void kog_prot_device::device_start() { }
+void kog_prot_device::device_reset() { }
+
+READ16_MEMBER(kog_prot_device::read_jumper)
+{
+ return ioport("JUMPER")->read();
+}
+
+void kog_prot_device::kog_install_protection(cpu_device* maincpu)
+{
+ /* overlay cartridge ROM */
+ maincpu->space(AS_PROGRAM).install_read_handler(0x0ffffe, 0x0fffff, read16_delegate(FUNC(kog_prot_device::read_jumper), this));
+}
+
+
+void kog_prot_device::kog_px_decrypt(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst( 0x600000 );
+ uint16_t *rom = (uint16_t *)cpurom;
+ int i;
+ static const int sec[] = { 0x3, 0x8, 0x7, 0xC, 0x1, 0xA, 0x6, 0xD };
+
+ for (i = 0; i < 8; i++)
+ memcpy (&dst[i * 0x20000], src + sec[i] * 0x20000, 0x20000);
+
+ memcpy (&dst[0x0007A6], src + 0x0407A6, 0x000006);
+ memcpy (&dst[0x0007C6], src + 0x0407C6, 0x000006);
+ memcpy (&dst[0x0007E6], src + 0x0407E6, 0x000006);
+ memcpy (&dst[0x090000], src + 0x040000, 0x004000);
+ memcpy (&dst[0x100000], src + 0x200000, 0x400000);
+ memcpy (src, &dst[0], 0x600000);
+
+ for (i = 0x90000/2; i < 0x94000/2; i++)
+ {
+ if (((rom[i]&0xFFBF) == 0x4EB9 || rom[i] == 0x43F9) && !rom[i + 1])
+ rom[i + 1] = 0x0009;
+
+ if (rom[i] == 0x4EB8)
+ rom[i] = 0x6100;
+ }
+
+ rom[0x007A8/2] = 0x0009;
+ rom[0x007C8/2] = 0x0009;
+ rom[0x007E8/2] = 0x0009;
+ rom[0x93408/2] = 0xF168;
+ rom[0x9340C/2] = 0xFB7A;
+ rom[0x924AC/2] = 0x0009;
+ rom[0x9251C/2] = 0x0009;
+ rom[0x93966/2] = 0xFFDA;
+ rom[0x93974/2] = 0xFFCC;
+ rom[0x93982/2] = 0xFFBE;
+ rom[0x93990/2] = 0xFFB0;
+ rom[0x9399E/2] = 0xFFA2;
+ rom[0x939AC/2] = 0xFF94;
+ rom[0x939BA/2] = 0xFF86;
+ rom[0x939C8/2] = 0xFF78;
+ rom[0x939D4/2] = 0xFA5C;
+ rom[0x939E0/2] = 0xFA50;
+ rom[0x939EC/2] = 0xFA44;
+ rom[0x939F8/2] = 0xFA38;
+ rom[0x93A04/2] = 0xFA2C;
+ rom[0x93A10/2] = 0xFA20;
+ rom[0x93A1C/2] = 0xFA14;
+ rom[0x93A28/2] = 0xFA08;
+ rom[0x93A34/2] = 0xF9FC;
+ rom[0x93A40/2] = 0xF9F0;
+ rom[0x93A4C/2] = 0xFD14;
+ rom[0x93A58/2] = 0xFD08;
+ rom[0x93A66/2] = 0xF9CA;
+ rom[0x93A72/2] = 0xF9BE;
+}
+
+
+static INPUT_PORTS_START( kog )
+ /* a jumper on the pcb overlays a ROM address, very strange but that's how it works. */
+ PORT_START("JUMPER")
+ PORT_DIPNAME( 0x0001, 0x0001, "Title Language" ) PORT_DIPLOCATION("CART-JUMPER:1")
+ PORT_DIPSETTING( 0x0001, DEF_STR( English ) )
+ PORT_DIPSETTING( 0x0000, "Non-English" )
+ PORT_BIT( 0x00fe, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0xff00, IP_ACTIVE_LOW, IPT_UNUSED )
+INPUT_PORTS_END
+
+ioport_constructor kog_prot_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( kog );
+}
+
+/***********************************************************************************************************************************/
+
+
+DEFINE_DEVICE_TYPE(CMC_PROT, cmc_prot_device, "cmc_prot", "NeoGeo Protection (CMC)")
+
+
+cmc_prot_device::cmc_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, CMC_PROT, tag, owner, clock)
+ , type0_t03(nullptr)
+ , type0_t12(nullptr)
+ , type1_t03(nullptr)
+ , type1_t12(nullptr)
+ , address_8_15_xor1(nullptr)
+ , address_8_15_xor2(nullptr)
+ , address_16_23_xor1(nullptr)
+ , address_16_23_xor2(nullptr)
+ , address_0_7_xor(nullptr)
+ { }
+
+
+void cmc_prot_device::device_start() { }
+void cmc_prot_device::device_reset() { }
+
+static const uint8_t kof99_type0_t03[256] =
+{
+ 0xfb, 0x86, 0x9d, 0xf1, 0xbf, 0x80, 0xd5, 0x43, 0xab, 0xb3, 0x9f, 0x6a, 0x33, 0xd9, 0xdb, 0xb6,
+ 0x66, 0x08, 0x69, 0x88, 0xcc, 0xb7, 0xde, 0x49, 0x97, 0x64, 0x1f, 0xa6, 0xc0, 0x2f, 0x52, 0x42,
+ 0x44, 0x5a, 0xf2, 0x28, 0x98, 0x87, 0x96, 0x8a, 0x83, 0x0b, 0x03, 0x61, 0x71, 0x99, 0x6b, 0xb5,
+ 0x1a, 0x8e, 0xfe, 0x04, 0xe1, 0xf7, 0x7d, 0xdd, 0xed, 0xca, 0x37, 0xfc, 0xef, 0x39, 0x72, 0xda,
+ 0xb8, 0xbe, 0xee, 0x7f, 0xe5, 0x31, 0x78, 0xf3, 0x91, 0x9a, 0xd2, 0x11, 0x19, 0xb9, 0x09, 0x4c,
+ 0xfd, 0x6d, 0x2a, 0x4d, 0x65, 0xa1, 0x89, 0xc7, 0x75, 0x50, 0x21, 0xfa, 0x16, 0x00, 0xe9, 0x12,
+ 0x74, 0x2b, 0x1e, 0x4f, 0x14, 0x01, 0x70, 0x3a, 0x4e, 0x3f, 0xf5, 0xf4, 0x1d, 0x3d, 0x15, 0x27,
+ 0xa7, 0xff, 0x45, 0xe0, 0x6e, 0xf9, 0x54, 0xc8, 0x48, 0xad, 0xa5, 0x0a, 0xf6, 0x2d, 0x2c, 0xe2,
+ 0x68, 0x67, 0xd6, 0x85, 0xb4, 0xc3, 0x34, 0xbc, 0x62, 0xd3, 0x5f, 0x84, 0x06, 0x5b, 0x0d, 0x95,
+ 0xea, 0x5e, 0x9e, 0xd4, 0xeb, 0x90, 0x7a, 0x05, 0x81, 0x57, 0xe8, 0x60, 0x2e, 0x20, 0x25, 0x7c,
+ 0x46, 0x0c, 0x93, 0xcb, 0xbd, 0x17, 0x7e, 0xec, 0x79, 0xb2, 0xc2, 0x22, 0x41, 0xb1, 0x10, 0xac,
+ 0xa8, 0xbb, 0x9b, 0x82, 0x4b, 0x9c, 0x8b, 0x07, 0x47, 0x35, 0x24, 0x56, 0x8d, 0xaf, 0xe6, 0x26,
+ 0x40, 0x38, 0xc4, 0x5d, 0x1b, 0xc5, 0xd1, 0x0f, 0x6c, 0x7b, 0xb0, 0xe3, 0xa3, 0x23, 0x6f, 0x58,
+ 0xc1, 0xba, 0xcf, 0xd7, 0xa2, 0xe7, 0xd0, 0x63, 0x5c, 0xf8, 0x73, 0xa0, 0x13, 0xdc, 0x29, 0xcd,
+ 0xc9, 0x76, 0xae, 0x8f, 0xe4, 0x59, 0x30, 0xaa, 0x94, 0x1c, 0x3c, 0x0e, 0x55, 0x92, 0x77, 0x32,
+ 0xc6, 0xce, 0x18, 0x36, 0xdf, 0xa9, 0x8c, 0xd8, 0xa4, 0xf0, 0x3b, 0x51, 0x4a, 0x02, 0x3e, 0x53,
+};
+
+
+static const uint8_t kof99_type0_t12[256] =
+{
+ 0x1f, 0xac, 0x4d, 0xcd, 0xca, 0x70, 0x02, 0x6b, 0x18, 0x40, 0x62, 0xb2, 0x3f, 0x9b, 0x5b, 0xef,
+ 0x69, 0x68, 0x71, 0x3b, 0xcb, 0xd4, 0x30, 0xbc, 0x47, 0x72, 0x74, 0x5e, 0x84, 0x4c, 0x1b, 0xdb,
+ 0x6a, 0x35, 0x1d, 0xf5, 0xa1, 0xb3, 0x87, 0x5d, 0x57, 0x28, 0x2f, 0xc4, 0xfd, 0x24, 0x26, 0x36,
+ 0xad, 0xbe, 0x61, 0x63, 0x73, 0xaa, 0x82, 0xee, 0x29, 0xd0, 0xdf, 0x8c, 0x15, 0xb5, 0x96, 0xf3,
+ 0xdd, 0x7e, 0x3a, 0x37, 0x58, 0x7f, 0x0c, 0xfc, 0x0b, 0x07, 0xe8, 0xf7, 0xf4, 0x14, 0xb8, 0x81,
+ 0xb6, 0xd7, 0x1e, 0xc8, 0x85, 0xe6, 0x9d, 0x33, 0x60, 0xc5, 0x95, 0xd5, 0x55, 0x00, 0xa3, 0xb7,
+ 0x7d, 0x50, 0x0d, 0xd2, 0xc1, 0x12, 0xe5, 0xed, 0xd8, 0xa4, 0x9c, 0x8f, 0x2a, 0x4f, 0xa8, 0x01,
+ 0x52, 0x83, 0x65, 0xea, 0x9a, 0x6c, 0x44, 0x4a, 0xe2, 0xa5, 0x2b, 0x46, 0xe1, 0x34, 0x25, 0xf8,
+ 0xc3, 0xda, 0xc7, 0x6e, 0x48, 0x38, 0x7c, 0x78, 0x06, 0x53, 0x64, 0x16, 0x98, 0x3c, 0x91, 0x42,
+ 0x39, 0xcc, 0xb0, 0xf1, 0xeb, 0x13, 0xbb, 0x05, 0x32, 0x86, 0x0e, 0xa2, 0x0a, 0x9e, 0xfa, 0x66,
+ 0x54, 0x8e, 0xd3, 0xe7, 0x19, 0x20, 0x77, 0xec, 0xff, 0xbd, 0x6d, 0x43, 0x23, 0x03, 0xab, 0x75,
+ 0x3d, 0xcf, 0xd1, 0xde, 0x92, 0x31, 0xa7, 0x45, 0x4b, 0xc2, 0x97, 0xf9, 0x7a, 0x88, 0xd9, 0x1c,
+ 0xe9, 0xe4, 0x10, 0xc9, 0x22, 0x2d, 0x90, 0x76, 0x17, 0x79, 0x04, 0x51, 0x1a, 0x5a, 0x5f, 0x2c,
+ 0x21, 0x6f, 0x3e, 0xe0, 0xf0, 0xbf, 0xd6, 0x94, 0x0f, 0x80, 0x11, 0xa0, 0x5c, 0xa9, 0x49, 0x2e,
+ 0xce, 0xaf, 0xa6, 0x9f, 0x7b, 0x99, 0xb9, 0xb4, 0xe3, 0xfb, 0xf6, 0x27, 0xf2, 0x93, 0xfe, 0x08,
+ 0x67, 0xae, 0x09, 0x89, 0xdc, 0x4e, 0xc6, 0xc0, 0x8a, 0xb1, 0x59, 0x8b, 0x41, 0x56, 0x8d, 0xba,
+};
+
+
+static const uint8_t kof99_type1_t03[256] =
+{
+ 0xa9, 0x17, 0xaf, 0x0d, 0x34, 0x6e, 0x53, 0xb6, 0x7f, 0x58, 0xe9, 0x14, 0x5f, 0x55, 0xdb, 0xd4,
+ 0x42, 0x80, 0x99, 0x59, 0xa8, 0x3a, 0x57, 0x5d, 0xd5, 0x6f, 0x4c, 0x68, 0x35, 0x46, 0xa6, 0xe7,
+ 0x7b, 0x71, 0xe0, 0x93, 0xa2, 0x1f, 0x64, 0x21, 0xe3, 0xb1, 0x98, 0x26, 0xab, 0xad, 0xee, 0xe5,
+ 0xbb, 0xd9, 0x1e, 0x2e, 0x95, 0x36, 0xef, 0x23, 0x79, 0x45, 0x04, 0xed, 0x13, 0x1d, 0xf4, 0x85,
+ 0x96, 0xec, 0xc2, 0x32, 0xaa, 0x7c, 0x15, 0xd8, 0xda, 0x92, 0x90, 0x9d, 0xb7, 0x56, 0x6a, 0x66,
+ 0x41, 0xfc, 0x00, 0xf6, 0x50, 0x24, 0xcf, 0xfb, 0x11, 0xfe, 0x82, 0x48, 0x9b, 0x27, 0x1b, 0x67,
+ 0x4e, 0x84, 0x69, 0x97, 0x6d, 0x8c, 0xd2, 0xba, 0x74, 0xf9, 0x8f, 0xa5, 0x54, 0x5c, 0xcd, 0x73,
+ 0x07, 0xd1, 0x01, 0x09, 0xf1, 0x19, 0x3b, 0x5e, 0x87, 0x30, 0x76, 0xcc, 0xc0, 0x5a, 0xa7, 0x49,
+ 0x22, 0xfa, 0x16, 0x02, 0xdf, 0xa4, 0xff, 0xb3, 0x75, 0x33, 0xbd, 0x88, 0x2f, 0xcb, 0x2a, 0x44,
+ 0xb8, 0xbf, 0x1c, 0x0f, 0x81, 0x10, 0x43, 0xb4, 0xc8, 0x7e, 0x9a, 0x25, 0xea, 0x83, 0x4b, 0x38,
+ 0x7a, 0xd7, 0x3d, 0x1a, 0x4f, 0x62, 0x51, 0xc9, 0x47, 0x0e, 0xce, 0x3f, 0xc7, 0x4d, 0x2c, 0xa1,
+ 0x86, 0xb9, 0xc5, 0xca, 0xdd, 0x6b, 0x70, 0x6c, 0x91, 0x9c, 0xbe, 0x0a, 0x9f, 0xf5, 0x94, 0xbc,
+ 0x18, 0x2b, 0x60, 0x20, 0x29, 0xf7, 0xf2, 0x28, 0xc4, 0xa0, 0x0b, 0x65, 0xde, 0x8d, 0x78, 0x12,
+ 0x3e, 0xd0, 0x77, 0x08, 0x8b, 0xae, 0x05, 0x31, 0x3c, 0xd6, 0xa3, 0x89, 0x06, 0xdc, 0x52, 0x72,
+ 0xb0, 0xb5, 0x37, 0xd3, 0xc3, 0x8a, 0xc6, 0xf0, 0xc1, 0x61, 0xfd, 0x4a, 0x5b, 0x7d, 0x9e, 0xf3,
+ 0x63, 0x40, 0x2d, 0xe8, 0xb2, 0xe6, 0x39, 0x03, 0xeb, 0x8e, 0xe1, 0x0c, 0xe4, 0xe2, 0xf8, 0xac,
+};
+
+
+static const uint8_t kof99_type1_t12[256] =
+{
+ 0xea, 0xe6, 0x5e, 0xa7, 0x8e, 0xac, 0x34, 0x03, 0x30, 0x97, 0x52, 0x53, 0x76, 0xf2, 0x62, 0x0b,
+ 0x0a, 0xfc, 0x94, 0xb8, 0x67, 0x36, 0x11, 0xbc, 0xae, 0xca, 0xfa, 0x15, 0x04, 0x2b, 0x17, 0xc4,
+ 0x3e, 0x5b, 0x59, 0x01, 0x57, 0xe2, 0xba, 0xb7, 0xd1, 0x3f, 0xf0, 0x6a, 0x9c, 0x2a, 0xcb, 0xa9,
+ 0xe3, 0x2c, 0xc0, 0x0f, 0x46, 0x91, 0x8a, 0xd0, 0x98, 0xc5, 0xa6, 0x1b, 0x96, 0x29, 0x12, 0x09,
+ 0x63, 0xed, 0xe0, 0xa2, 0x86, 0x77, 0xbe, 0xe5, 0x65, 0xdb, 0xbd, 0x50, 0xb3, 0x9d, 0x1a, 0x4e,
+ 0x79, 0x0c, 0x00, 0x43, 0xdf, 0x3d, 0x54, 0x33, 0x8f, 0x89, 0xa8, 0x7b, 0xf9, 0xd5, 0x27, 0x82,
+ 0xbb, 0xc2, 0x8c, 0x47, 0x88, 0x6b, 0xb4, 0xc3, 0xf8, 0xaa, 0x06, 0x1e, 0x83, 0x7d, 0x05, 0x78,
+ 0x85, 0xf6, 0x6e, 0x2e, 0xec, 0x5a, 0x31, 0x45, 0x38, 0x14, 0x16, 0x8b, 0x02, 0xe4, 0x4f, 0xb0,
+ 0xbf, 0xab, 0xa4, 0x9e, 0x48, 0x60, 0x19, 0x35, 0x08, 0xde, 0xdd, 0x66, 0x90, 0x51, 0xcc, 0xa3,
+ 0xaf, 0x70, 0x9b, 0x75, 0x95, 0x49, 0x6c, 0x64, 0x72, 0x7e, 0x44, 0xa0, 0x73, 0x25, 0x68, 0x55,
+ 0x1f, 0x40, 0x7a, 0x74, 0x0e, 0x8d, 0xdc, 0x1c, 0x71, 0xc8, 0xcf, 0xd7, 0xe8, 0xce, 0xeb, 0x32,
+ 0x3a, 0xee, 0x07, 0x61, 0x4d, 0xfe, 0x5c, 0x7c, 0x56, 0x2f, 0x2d, 0x5f, 0x6f, 0x9f, 0x81, 0x22,
+ 0x58, 0x4b, 0xad, 0xda, 0xb9, 0x10, 0x18, 0x23, 0xe1, 0xf3, 0x6d, 0xe7, 0xe9, 0x28, 0xd6, 0xd8,
+ 0xf4, 0x4c, 0x39, 0x21, 0xb2, 0x84, 0xc1, 0x24, 0x26, 0xf1, 0x93, 0x37, 0xc6, 0x4a, 0xcd, 0x20,
+ 0xc9, 0xd9, 0xc7, 0xb1, 0xff, 0x99, 0xd4, 0x5d, 0xb5, 0xa1, 0x87, 0x0d, 0x69, 0x92, 0x13, 0x80,
+ 0xd2, 0xd3, 0xfd, 0x1d, 0xf5, 0x3b, 0xa5, 0x7f, 0xef, 0x9a, 0xb6, 0x42, 0xfb, 0x3c, 0xf7, 0x41,
+};
+
+
+/* underlined values are wrong (not enough evidence, FF fill in kof99 and garou) */
+/* they correspond to tiles 7d000-7efff */
+static const uint8_t kof99_address_8_15_xor1[256] =
+{
+ 0x00, 0xb1, 0x1e, 0xc5, 0x3d, 0x40, 0x45, 0x5e, 0xf2, 0xf8, 0x04, 0x63, 0x36, 0x87, 0x88, 0xbf,
+ 0xab, 0xcc, 0x78, 0x08, 0xdd, 0x20, 0xd4, 0x35, 0x09, 0x8e, 0x44, 0xae, 0x33, 0xa9, 0x9e, 0xcd,
+ 0xb3, 0xe5, 0xad, 0x41, 0xda, 0xbe, 0xf4, 0x16, 0x57, 0x2e, 0x53, 0x67, 0xaf, 0xdb, 0x8a, 0xd8,
+ 0x34, 0x17, 0x3c, 0x01, 0x55, 0x73, 0xcf, 0xe3, 0xe8, 0xc7, 0x0d, 0xe9, 0xa3, 0x13, 0x0c, 0xf6,
+ 0x90, 0x4e, 0xfb, 0x97, 0x6d, 0x5f, 0xa8, 0x71, 0x11, 0xfc, 0xd1, 0x95, 0x81, 0xba, 0x8c, 0x1b,
+ 0x39, 0xfe, 0xa2, 0x15, 0xa6, 0x52, 0x4d, 0x5b, 0x59, 0xa5, 0xe0, 0x96, 0xd9, 0x8f, 0x7b, 0xed,
+ 0x29, 0xd3, 0x1f, 0x0e, 0xec, 0x23, 0x0f, 0xb8, 0x6c, 0x6f, 0x7d, 0x18, 0x46, 0xd6, 0xe4, 0xb5,
+ 0x9a, 0x79, 0x02, 0xf5, 0x03, 0xc0, 0x60, 0x66, 0x5c, 0x2f, 0x76, 0x85, 0x9d, 0x54, 0x1a, 0x6a,
+ 0x28, 0xce, 0x7f, 0x7c, 0x91, 0x99, 0x4c, 0x83, 0x3e, 0xb4, 0x1d, 0x05, 0xc1, 0xc3, 0xd7, 0x47,
+ 0xde, 0xbc, 0x62, 0x6e, 0x86, 0x14, 0x80, 0x77, 0xeb, 0xf3, 0x07, 0x31, 0x56, 0xd2, 0xc2, 0xc6,
+ 0x6b, 0xdc, 0xfd, 0x22, 0x92, 0xf0, 0x06, 0x51, 0x2d, 0x38, 0xe6, 0xa0, 0x25, 0xdf, 0xd5, 0x2c,
+ 0x1c, 0x94, 0x12, 0x9c, 0xb0, 0x9b, 0xc4, 0x0b, 0xc8, 0xd0, 0xf7, 0x30, 0xcb, 0x27, 0xfa, 0x7a,
+ 0x10, 0x61, 0xaa, 0xa4, 0x70, 0xb7, 0x2a, 0x5a, 0xc9, 0xf1, 0x0a, 0x49, 0x65, 0xee, 0x69, 0x4b,
+ 0x3a, 0x8d, 0x32, 0x5d, 0x68, 0xb9, 0x9f, 0x75, 0x19, 0x3f, 0xac, 0x37, 0x4f, 0xe7, 0x93, 0x89,
+ 0x7e, 0x4a, 0x3b, 0xea, 0x74, 0x72, 0x43, 0xbd, 0x24, 0xef, 0xb6, 0xff, 0x64, 0x58, 0x84, 0x8b,
+ 0xa7, 0xbb, 0xb2, 0xe1, 0x26, 0x2b, 0x50, 0xca, 0x21, 0xf9, 0x98, 0xa1, 0xe2, 0x42, 0x82, 0x48,
+// ^^^^ ^^^^ ^^^^ ^^^^
+};
+
+
+static const uint8_t kof99_address_8_15_xor2[256] =
+{
+ 0x9b, 0x9d, 0xc1, 0x3d, 0xa9, 0xb8, 0xf4, 0x6f, 0xf6, 0x25, 0xc7, 0x47, 0xd5, 0x97, 0xdf, 0x6b,
+ 0xeb, 0x90, 0xa4, 0xb2, 0x5d, 0xf5, 0x66, 0xb0, 0xb9, 0x8b, 0x93, 0x64, 0xec, 0x7b, 0x65, 0x8c,
+ 0xf1, 0x43, 0x42, 0x6e, 0x45, 0x9f, 0xb3, 0x35, 0x06, 0x71, 0x96, 0xdb, 0xa0, 0xfb, 0x0b, 0x3a,
+ 0x1f, 0xf8, 0x8e, 0x69, 0xcd, 0x26, 0xab, 0x86, 0xa2, 0x0c, 0xbd, 0x63, 0xa5, 0x7a, 0xe7, 0x6a,
+ 0x5f, 0x18, 0x9e, 0xbf, 0xad, 0x55, 0xb1, 0x1c, 0x5c, 0x03, 0x30, 0xc6, 0x37, 0x20, 0xe3, 0xc9,
+ 0x52, 0xe8, 0xee, 0x4f, 0x01, 0x70, 0xc4, 0x77, 0x29, 0x2a, 0xba, 0x53, 0x12, 0x04, 0x7d, 0xaf,
+ 0x33, 0x8f, 0xa8, 0x4d, 0xaa, 0x5b, 0xb4, 0x0f, 0x92, 0xbb, 0xed, 0xe1, 0x2f, 0x50, 0x6c, 0xd2,
+ 0x2c, 0x95, 0xd9, 0xf9, 0x98, 0xc3, 0x76, 0x4c, 0xf2, 0xe4, 0xe5, 0x2b, 0xef, 0x9c, 0x49, 0xb6,
+ 0x31, 0x3b, 0xbc, 0xa1, 0xca, 0xde, 0x62, 0x74, 0xea, 0x81, 0x00, 0xdd, 0xa6, 0x46, 0x88, 0x3f,
+ 0x39, 0xd6, 0x23, 0x54, 0x24, 0x4a, 0xd8, 0xdc, 0xd7, 0xd1, 0xcc, 0xbe, 0x57, 0x7c, 0xda, 0x44,
+ 0x61, 0xce, 0xd3, 0xd4, 0xe9, 0x28, 0x80, 0xe0, 0x56, 0x8a, 0x09, 0x05, 0x9a, 0x89, 0x1b, 0xf7,
+ 0xf3, 0x99, 0x6d, 0x5e, 0x48, 0x91, 0xc0, 0xd0, 0xc5, 0x79, 0x78, 0x41, 0x59, 0x21, 0x2e, 0xff,
+ 0xc2, 0x4b, 0x38, 0x83, 0x32, 0xe6, 0xe2, 0x7f, 0x1e, 0x17, 0x58, 0x1d, 0x1a, 0xfa, 0x85, 0x82,
+ 0x94, 0xc8, 0x72, 0x7e, 0xb7, 0xac, 0x0e, 0xfc, 0xfd, 0x16, 0x27, 0x75, 0x8d, 0xcb, 0x08, 0xfe,
+ 0x0a, 0x02, 0x0d, 0x36, 0x11, 0x22, 0x84, 0x40, 0x34, 0x3e, 0x2d, 0x68, 0x5a, 0xa7, 0x67, 0xae,
+ 0x87, 0x07, 0x10, 0x60, 0x14, 0x73, 0x3c, 0x51, 0x19, 0xa3, 0xb5, 0xcf, 0x13, 0xf0, 0x15, 0x4e,
+};
+
+
+static const uint8_t kof99_address_16_23_xor1[256] =
+{
+ 0x00, 0x5f, 0x03, 0x52, 0xce, 0xe3, 0x7d, 0x8f, 0x6b, 0xf8, 0x20, 0xde, 0x7b, 0x7e, 0x39, 0xbe,
+ 0xf5, 0x94, 0x18, 0x78, 0x80, 0xc9, 0x7f, 0x7a, 0x3e, 0x63, 0xf2, 0xe0, 0x4e, 0xf7, 0x87, 0x27,
+ 0x69, 0x6c, 0xa4, 0x1d, 0x85, 0x5b, 0xe6, 0x44, 0x25, 0x0c, 0x98, 0xc7, 0x01, 0x02, 0xa3, 0x26,
+ 0x09, 0x38, 0xdb, 0xc3, 0x1e, 0xcf, 0x23, 0x45, 0x68, 0x76, 0xd6, 0x22, 0x5d, 0x5a, 0xae, 0x16,
+ 0x9f, 0xa2, 0xb5, 0xcd, 0x81, 0xea, 0x5e, 0xb8, 0xb9, 0x9d, 0x9c, 0x1a, 0x0f, 0xff, 0xe1, 0xe7,
+ 0x74, 0xaa, 0xd4, 0xaf, 0xfc, 0xc6, 0x33, 0x29, 0x5c, 0xab, 0x95, 0xf0, 0x19, 0x47, 0x59, 0x67,
+ 0xf3, 0x96, 0x60, 0x1f, 0x62, 0x92, 0xbd, 0x89, 0xee, 0x28, 0x13, 0x06, 0xfe, 0xfa, 0x32, 0x6d,
+ 0x57, 0x3c, 0x54, 0x50, 0x2c, 0x58, 0x49, 0xfb, 0x17, 0xcc, 0xef, 0xb2, 0xb4, 0xf9, 0x07, 0x70,
+ 0xc5, 0xa9, 0xdf, 0xd5, 0x3b, 0x86, 0x2b, 0x0d, 0x6e, 0x4d, 0x0a, 0x90, 0x43, 0x31, 0xc1, 0xf6,
+ 0x88, 0x0b, 0xda, 0x53, 0x14, 0xdc, 0x75, 0x8e, 0xb0, 0xeb, 0x99, 0x46, 0xa1, 0x15, 0x71, 0xc8,
+ 0xe9, 0x3f, 0x4a, 0xd9, 0x73, 0xe5, 0x7c, 0x30, 0x77, 0xd3, 0xb3, 0x4b, 0x37, 0x72, 0xc2, 0x04,
+ 0x97, 0x08, 0x36, 0xb1, 0x3a, 0x61, 0xec, 0xe2, 0x1c, 0x9a, 0x8b, 0xd1, 0x1b, 0x2e, 0x9e, 0x8a,
+ 0xd8, 0x41, 0xe4, 0xc4, 0x40, 0x2f, 0xad, 0xc0, 0xb6, 0x84, 0x51, 0x66, 0xbb, 0x12, 0xe8, 0xdd,
+ 0xcb, 0xbc, 0x6f, 0xd0, 0x11, 0x83, 0x56, 0x4c, 0xca, 0xbf, 0x05, 0x10, 0xd7, 0xba, 0xfd, 0xed,
+ 0x8c, 0x0e, 0x4f, 0x3d, 0x35, 0x91, 0xb7, 0xac, 0x34, 0x64, 0x2a, 0xf1, 0x79, 0x6a, 0x9b, 0x2d,
+ 0x65, 0xf4, 0x42, 0xa0, 0x8d, 0xa7, 0x48, 0x55, 0x21, 0x93, 0x24, 0xd2, 0xa6, 0xa5, 0xa8, 0x82,
+};
+
+
+static const uint8_t kof99_address_16_23_xor2[256] =
+{
+ 0x29, 0x97, 0x1a, 0x2c, 0x0b, 0x94, 0x3e, 0x75, 0x01, 0x0d, 0x1b, 0xe1, 0x4d, 0x38, 0x39, 0x8f,
+ 0xe7, 0xd0, 0x60, 0x90, 0xb2, 0x0f, 0xbb, 0x70, 0x1f, 0xe6, 0x5b, 0x87, 0xb4, 0x43, 0xfd, 0xf5,
+ 0xf6, 0xf9, 0xad, 0xc0, 0x98, 0x17, 0x9f, 0x91, 0x15, 0x51, 0x55, 0x64, 0x6c, 0x18, 0x61, 0x0e,
+ 0xd9, 0x93, 0xab, 0xd6, 0x24, 0x2f, 0x6a, 0x3a, 0x22, 0xb1, 0x4f, 0xaa, 0x23, 0x48, 0xed, 0xb9,
+ 0x88, 0x8b, 0xa3, 0x6b, 0x26, 0x4c, 0xe8, 0x2d, 0x1c, 0x99, 0xbd, 0x5c, 0x58, 0x08, 0x50, 0xf2,
+ 0x2a, 0x62, 0xc1, 0x72, 0x66, 0x04, 0x10, 0x37, 0x6e, 0xfc, 0x44, 0xa9, 0xdf, 0xd4, 0x20, 0xdd,
+ 0xee, 0x41, 0xdb, 0x73, 0xde, 0x54, 0xec, 0xc9, 0xf3, 0x4b, 0x2e, 0xae, 0x5a, 0x4a, 0x5e, 0x47,
+ 0x07, 0x2b, 0x76, 0xa4, 0xe3, 0x28, 0xfe, 0xb0, 0xf0, 0x02, 0x06, 0xd1, 0xaf, 0x42, 0xc2, 0xa5,
+ 0xe0, 0x67, 0xbf, 0x16, 0x8e, 0x35, 0xce, 0x8a, 0xe5, 0x3d, 0x7b, 0x96, 0xd7, 0x79, 0x52, 0x1e,
+ 0xa1, 0xfb, 0x9b, 0xbe, 0x21, 0x9c, 0xe9, 0x56, 0x14, 0x7f, 0xa0, 0xe4, 0xc3, 0xc4, 0x46, 0xea,
+ 0xf7, 0xd2, 0x1d, 0x31, 0x0a, 0x5f, 0xeb, 0xa2, 0x68, 0x8d, 0xb5, 0xc5, 0x74, 0x0c, 0xdc, 0x82,
+ 0x80, 0x09, 0x19, 0x95, 0x71, 0x9a, 0x11, 0x57, 0x77, 0x4e, 0xc6, 0xff, 0x12, 0x03, 0xa7, 0xc7,
+ 0xf4, 0xc8, 0xb6, 0x7a, 0x59, 0x36, 0x3c, 0x53, 0xe2, 0x69, 0x8c, 0x25, 0x05, 0x45, 0x63, 0xf8,
+ 0x34, 0x89, 0x33, 0x3f, 0x85, 0x27, 0xbc, 0x65, 0xfa, 0xa8, 0x6d, 0x84, 0x5d, 0xba, 0x40, 0x32,
+ 0x30, 0xef, 0x83, 0x13, 0xa6, 0x78, 0xcc, 0x81, 0x9e, 0xda, 0xca, 0xd3, 0x7e, 0x9d, 0x6f, 0xcd,
+ 0xb7, 0xb3, 0xd8, 0xcf, 0x3b, 0x00, 0x92, 0xb8, 0x86, 0xac, 0x49, 0x7c, 0xf1, 0xd5, 0xcb, 0x7d,
+};
+
+
+static const uint8_t kof99_address_0_7_xor[256] =
+{
+ 0x74, 0xad, 0x5d, 0x1d, 0x9e, 0xc3, 0xfa, 0x4e, 0xf7, 0xdb, 0xca, 0xa2, 0x64, 0x36, 0x56, 0x0c,
+ 0x4f, 0xcf, 0x43, 0x66, 0x1e, 0x91, 0xe3, 0xa5, 0x58, 0xc2, 0xc1, 0xd4, 0xb9, 0xdd, 0x76, 0x16,
+ 0xce, 0x61, 0x75, 0x01, 0x2b, 0x22, 0x38, 0x55, 0x50, 0xef, 0x6c, 0x99, 0x05, 0xe9, 0xe8, 0xe0,
+ 0x2d, 0xa4, 0x4b, 0x4a, 0x42, 0xae, 0xba, 0x8c, 0x6f, 0x93, 0x14, 0xbd, 0x71, 0x21, 0xb0, 0x02,
+ 0x15, 0xc4, 0xe6, 0x60, 0xd7, 0x44, 0xfd, 0x85, 0x7e, 0x78, 0x8f, 0x00, 0x81, 0xf1, 0xa7, 0x3b,
+ 0xa0, 0x10, 0xf4, 0x9f, 0x39, 0x88, 0x35, 0x62, 0xcb, 0x19, 0x31, 0x11, 0x51, 0xfb, 0x2a, 0x20,
+ 0x45, 0xd3, 0x7d, 0x92, 0x1b, 0xf2, 0x09, 0x0d, 0x97, 0xa9, 0xb5, 0x3c, 0xee, 0x5c, 0xaf, 0x7b,
+ 0xd2, 0x3a, 0x49, 0x8e, 0xb6, 0xcd, 0xd9, 0xde, 0x8a, 0x29, 0x6e, 0xd8, 0x0b, 0xe1, 0x69, 0x87,
+ 0x1a, 0x96, 0x18, 0xcc, 0xdf, 0xe7, 0xc5, 0xc7, 0xf8, 0x52, 0xc9, 0xf0, 0xb7, 0xe5, 0x33, 0xda,
+ 0x67, 0x9d, 0xa3, 0x03, 0x0e, 0x72, 0x26, 0x79, 0xe2, 0xb8, 0xfc, 0xaa, 0xfe, 0xb4, 0x86, 0xc8,
+ 0xd1, 0xbc, 0x12, 0x08, 0x77, 0xeb, 0x40, 0x8d, 0x04, 0x25, 0x4d, 0x5a, 0x6a, 0x7a, 0x2e, 0x41,
+ 0x65, 0x1c, 0x13, 0x94, 0xb2, 0x63, 0x28, 0x59, 0x5e, 0x9a, 0x30, 0x07, 0xc6, 0xbf, 0x17, 0xf5,
+ 0x0f, 0x89, 0xf3, 0x1f, 0xea, 0x6d, 0xb3, 0xc0, 0x70, 0x47, 0xf9, 0x53, 0xf6, 0xd6, 0x54, 0xed,
+ 0x6b, 0x4c, 0xe4, 0x8b, 0x83, 0x24, 0x90, 0xb1, 0x7c, 0xbb, 0x73, 0xab, 0xd5, 0x2f, 0x5f, 0xec,
+ 0x9c, 0x2c, 0xa8, 0x34, 0x46, 0x37, 0x27, 0xa1, 0x0a, 0x06, 0x80, 0x68, 0x82, 0x32, 0x84, 0xff,
+ 0x48, 0xac, 0x7f, 0x3f, 0x95, 0xdc, 0x98, 0x9b, 0xbe, 0x23, 0x57, 0x3e, 0x5b, 0xd0, 0x3d, 0xa6,
+};
+
+
+static const uint8_t kof2000_type0_t03[256] =
+{
+ 0x10, 0x61, 0xf1, 0x78, 0x85, 0x52, 0x68, 0xe3, 0x12, 0x0d, 0xfa, 0xf0, 0xc9, 0x36, 0x5e, 0x3d,
+ 0xf9, 0xa6, 0x01, 0x2e, 0xc7, 0x84, 0xea, 0x2b, 0x6d, 0x14, 0x38, 0x4f, 0x55, 0x1c, 0x9d, 0xa7,
+ 0x7a, 0xc6, 0xf8, 0x9a, 0xe6, 0x42, 0xb5, 0xed, 0x7d, 0x3a, 0xb1, 0x05, 0x43, 0x4a, 0x22, 0xfd,
+ 0xac, 0xa4, 0x31, 0xc3, 0x32, 0x76, 0x95, 0x9e, 0x7e, 0x88, 0x8e, 0xa2, 0x97, 0x18, 0xbe, 0x2a,
+ 0xf5, 0xd6, 0xca, 0xcc, 0x72, 0x3b, 0x87, 0x6c, 0xde, 0x75, 0xd7, 0x21, 0xcb, 0x0b, 0xdd, 0xe7,
+ 0xe1, 0x65, 0xaa, 0xb9, 0x44, 0xfb, 0x66, 0x15, 0x1a, 0x3c, 0x98, 0xcf, 0x8a, 0xdf, 0x37, 0xa5,
+ 0x2f, 0x67, 0xd2, 0x83, 0xb6, 0x6b, 0xfc, 0xe0, 0xb4, 0x7c, 0x08, 0xdc, 0x93, 0x30, 0xab, 0xe4,
+ 0x19, 0xc2, 0x8b, 0xeb, 0xa0, 0x0a, 0xc8, 0x03, 0xc0, 0x4b, 0x64, 0x71, 0x86, 0x9c, 0x9b, 0x16,
+ 0x79, 0xff, 0x70, 0x09, 0x8c, 0xd0, 0xf6, 0x53, 0x07, 0x73, 0xd4, 0x89, 0xb3, 0x00, 0xe9, 0xfe,
+ 0xec, 0x8f, 0xbc, 0xb2, 0x1e, 0x5d, 0x11, 0x35, 0xa9, 0x06, 0x59, 0x9f, 0xc1, 0xd3, 0x7b, 0xf2,
+ 0xc5, 0x77, 0x4e, 0x39, 0x20, 0xd5, 0x6a, 0x82, 0xda, 0x45, 0xf3, 0x33, 0x81, 0x23, 0xba, 0xe2,
+ 0x1d, 0x5f, 0x5c, 0x51, 0x49, 0xae, 0x8d, 0xc4, 0xa8, 0xf7, 0x1f, 0x0f, 0x34, 0x28, 0xa1, 0xd9,
+ 0x27, 0xd8, 0x4c, 0x2c, 0xbf, 0x91, 0x3e, 0x69, 0x57, 0x41, 0x25, 0x0c, 0x5a, 0x90, 0x92, 0xb0,
+ 0x63, 0x6f, 0x40, 0xaf, 0x74, 0xb8, 0x2d, 0x80, 0xbb, 0x46, 0x94, 0xe5, 0x29, 0xee, 0xb7, 0x1b,
+ 0x96, 0xad, 0x13, 0x0e, 0x58, 0x99, 0x60, 0x4d, 0x17, 0x26, 0xce, 0xe8, 0xdb, 0xef, 0x24, 0xa3,
+ 0x6e, 0x7f, 0x54, 0x3f, 0x02, 0xd1, 0x5b, 0x50, 0x56, 0x48, 0xf4, 0xbd, 0x62, 0x47, 0x04, 0xcd,
+};
+
+
+static const uint8_t kof2000_type0_t12[256] =
+{
+ 0xf4, 0x28, 0xb4, 0x8f, 0xfa, 0xeb, 0x8e, 0x54, 0x2b, 0x49, 0xd1, 0x76, 0x71, 0x47, 0x8b, 0x57,
+ 0x92, 0x85, 0x7c, 0xb8, 0x5c, 0x22, 0xf9, 0x26, 0xbc, 0x5b, 0x6d, 0x67, 0xae, 0x5f, 0x6f, 0xf5,
+ 0x9f, 0x48, 0x66, 0x40, 0x0d, 0x11, 0x4e, 0xb2, 0x6b, 0x35, 0x15, 0x0f, 0x18, 0x25, 0x1d, 0xba,
+ 0xd3, 0x69, 0x79, 0xec, 0xa8, 0x8c, 0xc9, 0x7f, 0x4b, 0xdb, 0x51, 0xaf, 0xca, 0xe2, 0xb3, 0x81,
+ 0x12, 0x5e, 0x7e, 0x38, 0xc8, 0x95, 0x01, 0xff, 0xfd, 0xfb, 0xf2, 0x74, 0x62, 0x14, 0xa5, 0x98,
+ 0xa6, 0xda, 0x80, 0x53, 0xe8, 0x56, 0xac, 0x1b, 0x52, 0xd0, 0xf1, 0x45, 0x42, 0xb6, 0x1a, 0x4a,
+ 0x3a, 0x99, 0xfc, 0xd2, 0x9c, 0xcf, 0x31, 0x2d, 0xdd, 0x86, 0x2f, 0x29, 0xe1, 0x03, 0x19, 0xa2,
+ 0x41, 0x33, 0x83, 0x90, 0xc1, 0xbf, 0x0b, 0x08, 0x3d, 0xd8, 0x8d, 0x6c, 0x39, 0xa0, 0xe3, 0x55,
+ 0x02, 0x50, 0x46, 0xe6, 0xc3, 0x82, 0x36, 0x13, 0x75, 0xab, 0x27, 0xd7, 0x1f, 0x0a, 0xd4, 0x89,
+ 0x59, 0x4f, 0xc0, 0x5d, 0xc6, 0xf7, 0x88, 0xbd, 0x3c, 0x00, 0xef, 0xcd, 0x05, 0x1c, 0xaa, 0x9b,
+ 0xed, 0x7a, 0x61, 0x17, 0x93, 0xfe, 0x23, 0xb9, 0xf3, 0x68, 0x78, 0xf6, 0x5a, 0x7b, 0xe0, 0xe4,
+ 0xa3, 0xee, 0x16, 0x72, 0xc7, 0x3b, 0x8a, 0x37, 0x2a, 0x70, 0xa9, 0x2c, 0x21, 0xf8, 0x24, 0x09,
+ 0xce, 0x20, 0x9e, 0x06, 0x87, 0xc5, 0x04, 0x64, 0x43, 0x7d, 0x4d, 0x10, 0xd6, 0xa4, 0x94, 0x4c,
+ 0x60, 0xde, 0xdf, 0x58, 0xb1, 0x44, 0x3f, 0xb0, 0xd9, 0xe5, 0xcb, 0xbb, 0xbe, 0xea, 0x07, 0x34,
+ 0x73, 0x6a, 0x77, 0xf0, 0x9d, 0x0c, 0x2e, 0x0e, 0x91, 0x9a, 0xcc, 0xc2, 0xb7, 0x63, 0x97, 0xd5,
+ 0xdc, 0xc4, 0x32, 0xe7, 0x84, 0x3e, 0x30, 0xa1, 0x1e, 0xb5, 0x6e, 0x65, 0xe9, 0xad, 0xa7, 0x96,
+};
+
+
+static const uint8_t kof2000_type1_t03[256] =
+{
+ 0x9a, 0x2f, 0xcc, 0x4e, 0x40, 0x69, 0xac, 0xca, 0xa5, 0x7b, 0x0a, 0x61, 0x91, 0x0d, 0x55, 0x74,
+ 0xcd, 0x8b, 0x0b, 0x80, 0x09, 0x5e, 0x38, 0xc7, 0xda, 0xbf, 0xf5, 0x37, 0x23, 0x31, 0x33, 0xe9,
+ 0xae, 0x87, 0xe5, 0xfa, 0x6e, 0x5c, 0xad, 0xf4, 0x76, 0x62, 0x9f, 0x2e, 0x01, 0xe2, 0xf6, 0x47,
+ 0x8c, 0x7c, 0xaa, 0x98, 0xb5, 0x92, 0x51, 0xec, 0x5f, 0x07, 0x5d, 0x6f, 0x16, 0xa1, 0x1d, 0xa9,
+ 0x48, 0x45, 0xf0, 0x6a, 0x9c, 0x1e, 0x11, 0xa0, 0x06, 0x46, 0xd5, 0xf1, 0x73, 0xed, 0x94, 0xf7,
+ 0xc3, 0x57, 0x1b, 0xe0, 0x97, 0xb1, 0xa4, 0xa7, 0x24, 0xe7, 0x2b, 0x05, 0x5b, 0x34, 0x0c, 0xb8,
+ 0x0f, 0x9b, 0xc8, 0x4d, 0x5a, 0xa6, 0x86, 0x3e, 0x14, 0x29, 0x84, 0x58, 0x90, 0xdb, 0x2d, 0x54,
+ 0x9d, 0x82, 0xd4, 0x7d, 0xc6, 0x67, 0x41, 0x89, 0xc1, 0x13, 0xb0, 0x9e, 0x81, 0x6d, 0xa8, 0x59,
+ 0xbd, 0x39, 0x8e, 0xe6, 0x25, 0x8f, 0xd9, 0xa2, 0xe4, 0x53, 0xc5, 0x72, 0x7e, 0x36, 0x4a, 0x4f,
+ 0x52, 0xc2, 0x22, 0x2a, 0xce, 0x3c, 0x21, 0x2c, 0x00, 0xd7, 0x75, 0x8a, 0x27, 0xee, 0x43, 0xfe,
+ 0xcb, 0x6b, 0xb9, 0xa3, 0x78, 0xb7, 0x85, 0x02, 0x20, 0xd0, 0x83, 0xc4, 0x12, 0xf9, 0xfd, 0xd8,
+ 0x79, 0x64, 0x3a, 0x49, 0x03, 0xb4, 0xc0, 0xf2, 0xdf, 0x15, 0x93, 0x08, 0x35, 0xff, 0x70, 0xdd,
+ 0x28, 0x6c, 0x0e, 0x04, 0xde, 0x7a, 0x65, 0xd2, 0xab, 0x42, 0x95, 0xe1, 0x3f, 0x3b, 0x7f, 0x66,
+ 0xd1, 0x8d, 0xe3, 0xbb, 0x1c, 0xfc, 0x77, 0x1a, 0x88, 0x18, 0x19, 0x68, 0x1f, 0x56, 0xd6, 0xe8,
+ 0xb6, 0xbc, 0xd3, 0xea, 0x3d, 0x26, 0xb3, 0xc9, 0x44, 0xdc, 0xf3, 0x32, 0x30, 0xef, 0x96, 0x4c,
+ 0xaf, 0x17, 0xf8, 0xfb, 0x60, 0x50, 0xeb, 0x4b, 0x99, 0x63, 0xba, 0xb2, 0x71, 0xcf, 0x10, 0xbe,
+};
+
+
+static const uint8_t kof2000_type1_t12[256] =
+{
+ 0xda, 0xa7, 0xd6, 0x6e, 0x2f, 0x5e, 0xf0, 0x3f, 0xa4, 0xce, 0xd3, 0xfd, 0x46, 0x2a, 0xac, 0xc9,
+ 0xbe, 0xeb, 0x9f, 0xd5, 0x3c, 0x61, 0x96, 0x11, 0xd0, 0x38, 0xca, 0x06, 0xed, 0x1b, 0x65, 0xe7,
+ 0x23, 0xdd, 0xd9, 0x05, 0xbf, 0x5b, 0x5d, 0xa5, 0x95, 0x00, 0xec, 0xf1, 0x01, 0xa9, 0xa6, 0xfc,
+ 0xbb, 0x54, 0xe3, 0x2e, 0x92, 0x58, 0x0a, 0x7b, 0xb6, 0xcc, 0xb1, 0x5f, 0x14, 0x35, 0x72, 0xff,
+ 0xe6, 0x52, 0xd7, 0x8c, 0xf3, 0x43, 0xaf, 0x9c, 0xc0, 0x4f, 0x0c, 0x42, 0x8e, 0xef, 0x80, 0xcd,
+ 0x1d, 0x7e, 0x88, 0x3b, 0x98, 0xa1, 0xad, 0xe4, 0x9d, 0x8d, 0x2b, 0x56, 0xb5, 0x50, 0xdf, 0x66,
+ 0x6d, 0xd4, 0x60, 0x09, 0xe1, 0xee, 0x4a, 0x47, 0xf9, 0xfe, 0x73, 0x07, 0x89, 0xa8, 0x39, 0xea,
+ 0x82, 0x9e, 0xcf, 0x26, 0xb2, 0x4e, 0xc3, 0x59, 0xf2, 0x3d, 0x9a, 0xb0, 0x69, 0xf7, 0xbc, 0x34,
+ 0xe5, 0x36, 0x22, 0xfb, 0x57, 0x71, 0x99, 0x6c, 0x83, 0x30, 0x55, 0xc2, 0xbd, 0xf4, 0x77, 0xe9,
+ 0x76, 0x97, 0xa0, 0xe0, 0xb9, 0x86, 0x6b, 0xa3, 0x84, 0x67, 0x1a, 0x70, 0x02, 0x5a, 0x41, 0x5c,
+ 0x25, 0x81, 0xaa, 0x28, 0x78, 0x4b, 0xc6, 0x64, 0x53, 0x16, 0x4d, 0x8b, 0x20, 0x93, 0xae, 0x0f,
+ 0x94, 0x2c, 0x3a, 0xc7, 0x62, 0xe8, 0xc4, 0xdb, 0x04, 0xc5, 0xfa, 0x29, 0x48, 0xd1, 0x08, 0x24,
+ 0x0d, 0xe2, 0xd8, 0x10, 0xb4, 0x91, 0x8a, 0x13, 0x0e, 0xdc, 0xd2, 0x79, 0xb8, 0xf8, 0xba, 0x2d,
+ 0xcb, 0xf5, 0x7d, 0x37, 0x51, 0x40, 0x31, 0xa2, 0x0b, 0x18, 0x63, 0x7f, 0xb3, 0xab, 0x9b, 0x87,
+ 0xf6, 0x90, 0xde, 0xc8, 0x27, 0x45, 0x7c, 0x1c, 0x85, 0x68, 0x33, 0x19, 0x03, 0x75, 0x15, 0x7a,
+ 0x1f, 0x49, 0x8f, 0x4c, 0xc1, 0x44, 0x17, 0x12, 0x6f, 0x32, 0xb7, 0x3e, 0x74, 0x1e, 0x21, 0x6a,
+};
+
+
+static const uint8_t kof2000_address_8_15_xor1[256] =
+{
+ 0xfc, 0x9b, 0x1c, 0x35, 0x72, 0x53, 0xd6, 0x7d, 0x84, 0xa4, 0xc5, 0x93, 0x7b, 0xe7, 0x47, 0xd5,
+ 0x24, 0xa2, 0xfa, 0x19, 0x0c, 0xb1, 0x8c, 0xb9, 0x9d, 0xd8, 0x59, 0x4f, 0x3c, 0xb2, 0x78, 0x4a,
+ 0x2a, 0x96, 0x9a, 0xf1, 0x1f, 0x22, 0xa8, 0x5b, 0x67, 0xa3, 0x0f, 0x00, 0xfb, 0xdf, 0xeb, 0x0a,
+ 0x57, 0xb8, 0x25, 0xd7, 0xf0, 0x6b, 0x0b, 0x31, 0x95, 0x23, 0x2d, 0x5c, 0x27, 0xc7, 0xf4, 0x55,
+ 0x1a, 0xf7, 0x74, 0xbe, 0xd3, 0xac, 0x3d, 0xc1, 0x7f, 0xbd, 0x28, 0x01, 0x10, 0xe5, 0x09, 0x37,
+ 0x1e, 0x58, 0xaf, 0x17, 0xf2, 0x16, 0x30, 0x92, 0x36, 0x68, 0xe6, 0xd4, 0xea, 0xb7, 0x75, 0x54,
+ 0x77, 0x41, 0xb4, 0x8d, 0xe0, 0xf3, 0x51, 0x03, 0xa9, 0xe8, 0x66, 0xab, 0x29, 0xa5, 0xed, 0xcb,
+ 0xd1, 0xaa, 0xf5, 0xdb, 0x4c, 0x42, 0x97, 0x8a, 0xae, 0xc9, 0x6e, 0x04, 0x33, 0x85, 0xdd, 0x2b,
+ 0x6f, 0xef, 0x12, 0x21, 0x7a, 0xa1, 0x5a, 0x91, 0xc8, 0xcc, 0xc0, 0xa7, 0x60, 0x3e, 0x56, 0x2f,
+ 0xe4, 0x71, 0x99, 0xc2, 0xa0, 0x45, 0x80, 0x65, 0xbb, 0x87, 0x69, 0x81, 0x73, 0xca, 0xf6, 0x46,
+ 0x43, 0xda, 0x26, 0x7e, 0x8f, 0xe1, 0x8b, 0xfd, 0x50, 0x79, 0xba, 0xc6, 0x63, 0x4b, 0xb3, 0x8e,
+ 0x34, 0xe2, 0x48, 0x14, 0xcd, 0xe3, 0xc4, 0x05, 0x13, 0x40, 0x06, 0x6c, 0x88, 0xb0, 0xe9, 0x1b,
+ 0x4d, 0xf8, 0x76, 0x02, 0x44, 0x94, 0xcf, 0x32, 0xfe, 0xce, 0x3b, 0x5d, 0x2c, 0x89, 0x5f, 0xdc,
+ 0xd2, 0x9c, 0x6a, 0xec, 0x18, 0x6d, 0x0e, 0x86, 0xff, 0x5e, 0x9e, 0xee, 0x11, 0xd0, 0x49, 0x52,
+ 0x4e, 0x61, 0x90, 0x0d, 0xc3, 0x39, 0x15, 0x83, 0xb5, 0x62, 0x3f, 0x70, 0x7c, 0xad, 0x20, 0xbf,
+ 0x2e, 0x08, 0x1d, 0xf9, 0xb6, 0xa6, 0x64, 0x07, 0x82, 0x38, 0x98, 0x3a, 0x9f, 0xde, 0xbc, 0xd9,
+};
+
+
+static const uint8_t kof2000_address_8_15_xor2[256] =
+{
+ 0x00, 0xbe, 0x06, 0x5a, 0xfa, 0x42, 0x15, 0xf2, 0x3f, 0x0a, 0x84, 0x93, 0x4e, 0x78, 0x3b, 0x89,
+ 0x32, 0x98, 0xa2, 0x87, 0x73, 0xdd, 0x26, 0xe5, 0x05, 0x71, 0x08, 0x6e, 0x9b, 0xe0, 0xdf, 0x9e,
+ 0xfc, 0x83, 0x81, 0xef, 0xb2, 0xc0, 0xc3, 0xbf, 0xa7, 0x6d, 0x1b, 0x95, 0xed, 0xb9, 0x3e, 0x13,
+ 0xb0, 0x47, 0x9c, 0x7a, 0x24, 0x41, 0x68, 0xd0, 0x36, 0x0b, 0xb5, 0xc2, 0x67, 0xf7, 0x54, 0x92,
+ 0x1e, 0x44, 0x86, 0x2b, 0x94, 0xcc, 0xba, 0x23, 0x0d, 0xca, 0x6b, 0x4c, 0x2a, 0x9a, 0x2d, 0x8b,
+ 0xe3, 0x52, 0x29, 0xf0, 0x21, 0xbd, 0xbb, 0x1f, 0xa3, 0xab, 0xf8, 0x46, 0xb7, 0x45, 0x82, 0x5e,
+ 0xdb, 0x07, 0x5d, 0xe9, 0x9d, 0x1a, 0x48, 0xce, 0x91, 0x12, 0xd4, 0xee, 0xa9, 0x39, 0xf1, 0x18,
+ 0x2c, 0x22, 0x8a, 0x7e, 0x34, 0x4a, 0x8c, 0xc1, 0x14, 0xf3, 0x20, 0x35, 0xd9, 0x96, 0x33, 0x77,
+ 0x9f, 0x76, 0x7c, 0x90, 0xc6, 0xd5, 0xa1, 0x5b, 0xac, 0x75, 0xc7, 0x0c, 0xb3, 0x17, 0xd6, 0x99,
+ 0x56, 0xa6, 0x3d, 0x1d, 0xb1, 0x2e, 0xd8, 0xbc, 0x2f, 0xde, 0x60, 0x55, 0x6c, 0x40, 0xcd, 0x43,
+ 0xff, 0xad, 0x38, 0x79, 0x51, 0xc8, 0x0e, 0x5f, 0xc4, 0x66, 0xcb, 0xa8, 0x7d, 0xa4, 0x3a, 0xea,
+ 0x27, 0x7b, 0x70, 0x8e, 0x5c, 0x19, 0x0f, 0x80, 0x6f, 0x8f, 0x10, 0xf9, 0x49, 0x85, 0x69, 0x7f,
+ 0xeb, 0x1c, 0x01, 0x65, 0x37, 0xa5, 0x28, 0xe4, 0x6a, 0x03, 0x04, 0xd1, 0x31, 0x11, 0x30, 0xfb,
+ 0x88, 0x97, 0xd3, 0xf6, 0xc5, 0x4d, 0xf5, 0x3c, 0xe8, 0x61, 0xdc, 0xd2, 0xb4, 0xb8, 0xa0, 0xae,
+ 0x16, 0x25, 0x02, 0x09, 0xfe, 0xcf, 0x53, 0x63, 0xaf, 0x59, 0xf4, 0xe1, 0xec, 0xd7, 0xe7, 0x50,
+ 0xe2, 0xc9, 0xaa, 0x4b, 0x8d, 0x4f, 0xe6, 0x64, 0xda, 0x74, 0xb6, 0x72, 0x57, 0x62, 0xfd, 0x58,
+};
+
+
+static const uint8_t kof2000_address_16_23_xor1[256] =
+{
+ 0x45, 0x9f, 0x6e, 0x2f, 0x28, 0xbc, 0x5e, 0x6d, 0xda, 0xb5, 0x0d, 0xb8, 0xc0, 0x8e, 0xa2, 0x32,
+ 0xee, 0xcd, 0x8d, 0x48, 0x8c, 0x27, 0x14, 0xeb, 0x65, 0xd7, 0xf2, 0x93, 0x99, 0x90, 0x91, 0xfc,
+ 0x5f, 0xcb, 0xfa, 0x75, 0x3f, 0x26, 0xde, 0x72, 0x33, 0x39, 0xc7, 0x1f, 0x88, 0x79, 0x73, 0xab,
+ 0x4e, 0x36, 0x5d, 0x44, 0xd2, 0x41, 0xa0, 0x7e, 0xa7, 0x8b, 0xa6, 0xbf, 0x03, 0xd8, 0x86, 0xdc,
+ 0x2c, 0xaa, 0x70, 0x3d, 0x46, 0x07, 0x80, 0x58, 0x0b, 0x2b, 0xe2, 0xf0, 0xb1, 0xfe, 0x42, 0xf3,
+ 0xe9, 0xa3, 0x85, 0x78, 0xc3, 0xd0, 0x5a, 0xdb, 0x1a, 0xfb, 0x9d, 0x8a, 0xa5, 0x12, 0x0e, 0x54,
+ 0x8f, 0xc5, 0x6c, 0xae, 0x25, 0x5b, 0x4b, 0x17, 0x02, 0x9c, 0x4a, 0x24, 0x40, 0xe5, 0x9e, 0x22,
+ 0xc6, 0x49, 0x62, 0xb6, 0x6b, 0xbb, 0xa8, 0xcc, 0xe8, 0x81, 0x50, 0x47, 0xc8, 0xbe, 0x5c, 0xa4,
+ 0xd6, 0x94, 0x4f, 0x7b, 0x9a, 0xcf, 0xe4, 0x59, 0x7a, 0xa1, 0xea, 0x31, 0x37, 0x13, 0x2d, 0xaf,
+ 0x21, 0x69, 0x19, 0x1d, 0x6f, 0x16, 0x98, 0x1e, 0x08, 0xe3, 0xb2, 0x4d, 0x9b, 0x7f, 0xa9, 0x77,
+ 0xed, 0xbd, 0xd4, 0xd9, 0x34, 0xd3, 0xca, 0x09, 0x18, 0x60, 0xc9, 0x6a, 0x01, 0xf4, 0xf6, 0x64,
+ 0xb4, 0x3a, 0x15, 0xac, 0x89, 0x52, 0x68, 0x71, 0xe7, 0x82, 0xc1, 0x0c, 0x92, 0xf7, 0x30, 0xe6,
+ 0x1c, 0x3e, 0x0f, 0x0a, 0x67, 0x35, 0xba, 0x61, 0xdd, 0x29, 0xc2, 0xf8, 0x97, 0x95, 0xb7, 0x3b,
+ 0xe0, 0xce, 0xf9, 0xd5, 0x06, 0x76, 0xb3, 0x05, 0x4c, 0x04, 0x84, 0x3c, 0x87, 0x23, 0x63, 0x7c,
+ 0x53, 0x56, 0xe1, 0x7d, 0x96, 0x1b, 0xd1, 0xec, 0x2a, 0x66, 0xf1, 0x11, 0x10, 0xff, 0x43, 0x2e,
+ 0xdf, 0x83, 0x74, 0xf5, 0x38, 0x20, 0xfd, 0xad, 0xc4, 0xb9, 0x55, 0x51, 0xb0, 0xef, 0x00, 0x57,
+};
+
+
+static const uint8_t kof2000_address_16_23_xor2[256] =
+{
+ 0x00, 0xb8, 0xf0, 0x34, 0xca, 0x21, 0x3c, 0xf9, 0x01, 0x8e, 0x75, 0x70, 0xec, 0x13, 0x27, 0x96,
+ 0xf4, 0x5b, 0x88, 0x1f, 0xeb, 0x4a, 0x7d, 0x9d, 0xbe, 0x02, 0x14, 0xaf, 0xa2, 0x06, 0xc6, 0xdb,
+ 0x35, 0x6b, 0x74, 0x45, 0x7b, 0x29, 0xd2, 0xfe, 0xb6, 0x15, 0xd0, 0x8a, 0xa9, 0x2d, 0x19, 0xf6,
+ 0x5e, 0x5a, 0x90, 0xe9, 0x11, 0x33, 0xc2, 0x47, 0x37, 0x4c, 0x4f, 0x59, 0xc3, 0x04, 0x57, 0x1d,
+ 0xf2, 0x63, 0x6d, 0x6e, 0x31, 0x95, 0xcb, 0x3e, 0x67, 0xb2, 0xe3, 0x98, 0xed, 0x8d, 0xe6, 0xfb,
+ 0xf8, 0xba, 0x5d, 0xd4, 0x2a, 0xf5, 0x3b, 0x82, 0x05, 0x16, 0x44, 0xef, 0x4d, 0xe7, 0x93, 0xda,
+ 0x9f, 0xbb, 0x61, 0xc9, 0x53, 0xbd, 0x76, 0x78, 0x52, 0x36, 0x0c, 0x66, 0xc1, 0x10, 0xdd, 0x7a,
+ 0x84, 0x69, 0xcd, 0xfd, 0x58, 0x0d, 0x6c, 0x89, 0x68, 0xad, 0x3a, 0xb0, 0x4b, 0x46, 0xc5, 0x03,
+ 0xb4, 0xf7, 0x30, 0x8c, 0x4e, 0x60, 0x73, 0xa1, 0x8b, 0xb1, 0x62, 0xcc, 0xd1, 0x08, 0xfc, 0x77,
+ 0x7e, 0xcf, 0x56, 0x51, 0x07, 0xa6, 0x80, 0x92, 0xdc, 0x0b, 0xa4, 0xc7, 0xe8, 0xe1, 0xb5, 0x71,
+ 0xea, 0xb3, 0x2f, 0x94, 0x18, 0xe2, 0x3d, 0x49, 0x65, 0xaa, 0xf1, 0x91, 0xc8, 0x99, 0x55, 0x79,
+ 0x86, 0xa7, 0x26, 0xa0, 0xac, 0x5f, 0xce, 0x6a, 0x5c, 0xf3, 0x87, 0x8f, 0x12, 0x1c, 0xd8, 0xe4,
+ 0x9b, 0x64, 0x2e, 0x1e, 0xd7, 0xc0, 0x17, 0xbc, 0xa3, 0xa8, 0x9a, 0x0e, 0x25, 0x40, 0x41, 0x50,
+ 0xb9, 0xbf, 0x28, 0xdf, 0x32, 0x54, 0x9e, 0x48, 0xd5, 0x2b, 0x42, 0xfa, 0x9c, 0x7f, 0xd3, 0x85,
+ 0x43, 0xde, 0x81, 0x0f, 0x24, 0xc4, 0x38, 0xae, 0x83, 0x1b, 0x6f, 0x7c, 0xe5, 0xff, 0x1a, 0xd9,
+ 0x3f, 0xb7, 0x22, 0x97, 0x09, 0xe0, 0xa5, 0x20, 0x23, 0x2c, 0x72, 0xd6, 0x39, 0xab, 0x0a, 0xee,
+};
+
+
+static const uint8_t kof2000_address_0_7_xor[256] =
+{
+ 0x26, 0x48, 0x06, 0x9b, 0x21, 0xa9, 0x1b, 0x76, 0xc9, 0xf8, 0xb4, 0x67, 0xe4, 0xff, 0x99, 0xf7,
+ 0x15, 0x9e, 0x62, 0x00, 0x72, 0x4d, 0xa0, 0x4f, 0x02, 0xf1, 0xea, 0xef, 0x0b, 0xf3, 0xeb, 0xa6,
+ 0x93, 0x78, 0x6f, 0x7c, 0xda, 0xd4, 0x7b, 0x05, 0xe9, 0xc6, 0xd6, 0xdb, 0x50, 0xce, 0xd2, 0x01,
+ 0xb5, 0xe8, 0xe0, 0x2a, 0x08, 0x1a, 0xb8, 0xe3, 0xf9, 0xb1, 0xf4, 0x8b, 0x39, 0x2d, 0x85, 0x9c,
+ 0x55, 0x73, 0x63, 0x40, 0x38, 0x96, 0xdc, 0xa3, 0xa2, 0xa1, 0x25, 0x66, 0x6d, 0x56, 0x8e, 0x10,
+ 0x0f, 0x31, 0x1c, 0xf5, 0x28, 0x77, 0x0a, 0xd1, 0x75, 0x34, 0xa4, 0xfe, 0x7d, 0x07, 0x51, 0x79,
+ 0x41, 0x90, 0x22, 0x35, 0x12, 0xbb, 0xc4, 0xca, 0xb2, 0x1f, 0xcb, 0xc8, 0xac, 0xdd, 0xd0, 0x0d,
+ 0xfc, 0xc5, 0x9d, 0x14, 0xbc, 0x83, 0xd9, 0x58, 0xc2, 0x30, 0x9a, 0x6a, 0xc0, 0x0c, 0xad, 0xf6,
+ 0x5d, 0x74, 0x7f, 0x2f, 0xbd, 0x1d, 0x47, 0xd5, 0xe6, 0x89, 0xcf, 0xb7, 0xd3, 0x59, 0x36, 0x98,
+ 0xf0, 0xfb, 0x3c, 0xf2, 0x3f, 0xa7, 0x18, 0x82, 0x42, 0x5c, 0xab, 0xba, 0xde, 0x52, 0x09, 0x91,
+ 0xaa, 0x61, 0xec, 0xd7, 0x95, 0x23, 0xcd, 0x80, 0xa5, 0x68, 0x60, 0x27, 0x71, 0xe1, 0x2c, 0x2e,
+ 0x8d, 0x2b, 0x57, 0x65, 0xbf, 0xc1, 0x19, 0xc7, 0x49, 0x64, 0x88, 0x4a, 0xcc, 0x20, 0x4e, 0xd8,
+ 0x3b, 0x4c, 0x13, 0x5f, 0x9f, 0xbe, 0x5e, 0x6e, 0xfd, 0xe2, 0xfa, 0x54, 0x37, 0x0e, 0x16, 0x7a,
+ 0x6c, 0x33, 0xb3, 0x70, 0x84, 0x7e, 0xc3, 0x04, 0xb0, 0xae, 0xb9, 0x81, 0x03, 0x29, 0xdf, 0x46,
+ 0xe5, 0x69, 0xe7, 0x24, 0x92, 0x5a, 0x4b, 0x5b, 0x94, 0x11, 0x3a, 0x3d, 0x87, 0xed, 0x97, 0xb6,
+ 0x32, 0x3e, 0x45, 0xaf, 0x1e, 0x43, 0x44, 0x8c, 0x53, 0x86, 0x6b, 0xee, 0xa8, 0x8a, 0x8f, 0x17,
+};
+
+
+
+void cmc_prot_device::decrypt(uint8_t *r0, uint8_t *r1, uint8_t c0, uint8_t c1, const uint8_t *table0hi, const uint8_t *table0lo, const uint8_t *table1, int base, int invert)
+{
+ uint8_t tmp,xor0,xor1;
+
+ tmp = table1[(base & 0xff) ^ address_0_7_xor[(base >> 8) & 0xff]];
+ xor0 = (table0hi[(base >> 8) & 0xff] & 0xfe) | (tmp & 0x01);
+ xor1 = (tmp & 0xfe) | (table0lo[(base >> 8) & 0xff] & 0x01);
+
+ if (invert)
+ {
+ *r0 = c1 ^ xor0;
+ *r1 = c0 ^ xor1;
+ }
+ else
+ {
+ *r0 = c0 ^ xor0;
+ *r1 = c1 ^ xor1;
+ }
+}
+
+
+void cmc_prot_device::neogeo_gfx_decrypt(uint8_t* rom, uint32_t rom_size, int extra_xor)
+{
+ int rpos;
+ std::vector<uint8_t> buf(rom_size);
+
+ // Data xor
+ for (rpos = 0;rpos < rom_size/4;rpos++)
+ {
+ decrypt(&buf[4*rpos+0], &buf[4*rpos+3], rom[4*rpos+0], rom[4*rpos+3], type0_t03, type0_t12, type1_t03, rpos, (rpos>>8) & 1);
+ decrypt(&buf[4*rpos+1], &buf[4*rpos+2], rom[4*rpos+1], rom[4*rpos+2], type0_t12, type0_t03, type1_t12, rpos, ((rpos>>16) ^ address_16_23_xor2[(rpos>>8) & 0xff]) & 1);
+ }
+
+ // Address xor
+ for (rpos = 0;rpos < rom_size/4;rpos++)
+ {
+ int baser = rpos ^ extra_xor;
+ baser ^= address_8_15_xor1[(baser >> 16) & 0xff] << 8;
+ baser ^= address_8_15_xor2[baser & 0xff] << 8;
+ baser ^= address_16_23_xor1[baser & 0xff] << 16;
+ baser ^= address_16_23_xor2[(baser >> 8) & 0xff] << 16;
+ baser ^= address_0_7_xor[(baser >> 8) & 0xff];
+
+ if (rom_size == 0x3000000) /* special handling for preisle2 */
+ {
+ if (rpos < 0x2000000/4)
+ baser &= (0x2000000/4)-1;
+ else
+ baser = 0x2000000/4 + (baser & ((0x1000000/4)-1));
+ }
+ else if (rom_size == 0x6000000) /* special handling for kf2k3pcb */
+ {
+ if (rpos < 0x4000000/4)
+ baser &= (0x4000000/4)-1;
+ else
+ baser = 0x4000000/4 + (baser & ((0x1000000/4)-1));
+ }
+ else /* Clamp to the real rom size */
+ baser &= (rom_size/4)-1;
+
+ rom[4*rpos+0] = buf[4*baser+0];
+ rom[4*rpos+1] = buf[4*baser+1];
+ rom[4*rpos+2] = buf[4*baser+2];
+ rom[4*rpos+3] = buf[4*baser+3];
+ }
+}
+
+
+/* the S data comes from the end of the C data */
+void cmc_prot_device::neogeo_sfix_decrypt(uint8_t* rom, uint32_t rom_size, uint8_t* fixed, uint32_t fixed_size)
+{
+ int i;
+ int tx_size = fixed_size;
+ uint8_t *src = rom+rom_size-tx_size;
+ uint8_t *dst = fixed;
+
+ for (i = 0;i < tx_size;i++)
+ dst[i] = src[(i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4)];
+}
+
+
+/* CMC42 protection chip */
+void cmc_prot_device::cmc42_neogeo_gfx_decrypt(uint8_t* rom, uint32_t rom_size, int extra_xor)
+{
+ type0_t03 = kof99_type0_t03;
+ type0_t12 = kof99_type0_t12;
+ type1_t03 = kof99_type1_t03;
+ type1_t12 = kof99_type1_t12;
+ address_8_15_xor1 = kof99_address_8_15_xor1;
+ address_8_15_xor2 = kof99_address_8_15_xor2;
+ address_16_23_xor1 = kof99_address_16_23_xor1;
+ address_16_23_xor2 = kof99_address_16_23_xor2;
+ address_0_7_xor = kof99_address_0_7_xor;
+ neogeo_gfx_decrypt(rom, rom_size, extra_xor);
+}
+
+
+/* CMC50 protection chip */
+void cmc_prot_device::cmc50_neogeo_gfx_decrypt(uint8_t* rom, uint32_t rom_size, int extra_xor)
+{
+ type0_t03 = kof2000_type0_t03;
+ type0_t12 = kof2000_type0_t12;
+ type1_t03 = kof2000_type1_t03;
+ type1_t12 = kof2000_type1_t12;
+ address_8_15_xor1 = kof2000_address_8_15_xor1;
+ address_8_15_xor2 = kof2000_address_8_15_xor2;
+ address_16_23_xor1 = kof2000_address_16_23_xor1;
+ address_16_23_xor2 = kof2000_address_16_23_xor2;
+ address_0_7_xor = kof2000_address_0_7_xor;
+ neogeo_gfx_decrypt(rom, rom_size, extra_xor);
+}
+
+
+
+/***************************************************************************
+
+NeoGeo 'M' ROM encryption
+ CMC50 protection chip
+
+***************************************************************************/
+
+
+static const uint8_t m1_address_8_15_xor[256] =
+{
+ 0x0a, 0x72, 0xb7, 0xaf, 0x67, 0xde, 0x1d, 0xb1, 0x78, 0xc4, 0x4f, 0xb5, 0x4b, 0x18, 0x76, 0xdd,
+ 0x11, 0xe2, 0x36, 0xa1, 0x82, 0x03, 0x98, 0xa0, 0x10, 0x5f, 0x3f, 0xd6, 0x1f, 0x90, 0x6a, 0x0b,
+ 0x70, 0xe0, 0x64, 0xcb, 0x9f, 0x38, 0x8b, 0x53, 0x04, 0xca, 0xf8, 0xd0, 0x07, 0x68, 0x56, 0x32,
+ 0xae, 0x1c, 0x2e, 0x48, 0x63, 0x92, 0x9a, 0x9c, 0x44, 0x85, 0x41, 0x40, 0x09, 0xc0, 0xc8, 0xbf,
+ 0xea, 0xbb, 0xf7, 0x2d, 0x99, 0x21, 0xf6, 0xba, 0x15, 0xce, 0xab, 0xb0, 0x2a, 0x60, 0xbc, 0xf1,
+ 0xf0, 0x9e, 0xd5, 0x97, 0xd8, 0x4e, 0x14, 0x9d, 0x42, 0x4d, 0x2c, 0x5c, 0x2b, 0xa6, 0xe1, 0xa7,
+ 0xef, 0x25, 0x33, 0x7a, 0xeb, 0xe7, 0x1b, 0x6d, 0x4c, 0x52, 0x26, 0x62, 0xb6, 0x35, 0xbe, 0x80,
+ 0x01, 0xbd, 0xfd, 0x37, 0xf9, 0x47, 0x55, 0x71, 0xb4, 0xf2, 0xff, 0x27, 0xfa, 0x23, 0xc9, 0x83,
+ 0x17, 0x39, 0x13, 0x0d, 0xc7, 0x86, 0x16, 0xec, 0x49, 0x6f, 0xfe, 0x34, 0x05, 0x8f, 0x00, 0xe6,
+ 0xa4, 0xda, 0x7b, 0xc1, 0xf3, 0xf4, 0xd9, 0x75, 0x28, 0x66, 0x87, 0xa8, 0x45, 0x6c, 0x20, 0xe9,
+ 0x77, 0x93, 0x7e, 0x3c, 0x1e, 0x74, 0xf5, 0x8c, 0x3e, 0x94, 0xd4, 0xc2, 0x5a, 0x06, 0x0e, 0xe8,
+ 0x3d, 0xa9, 0xb2, 0xe3, 0xe4, 0x22, 0xcf, 0x24, 0x8e, 0x6b, 0x8a, 0x8d, 0x84, 0x4a, 0xd2, 0x91,
+ 0x88, 0x79, 0x57, 0xa5, 0x0f, 0xcd, 0xb9, 0xac, 0x3b, 0xaa, 0xb3, 0xd1, 0xee, 0x31, 0x81, 0x7c,
+ 0xd7, 0x89, 0xd3, 0x96, 0x43, 0xc5, 0xc6, 0xc3, 0x69, 0x7f, 0x46, 0xdf, 0x30, 0x5b, 0x6e, 0xe5,
+ 0x08, 0x95, 0x9b, 0xfb, 0xb8, 0x58, 0x0c, 0x61, 0x50, 0x5d, 0x3a, 0xa2, 0x29, 0x12, 0xfc, 0x51,
+ 0x7d, 0x1a, 0x02, 0x65, 0x54, 0x5e, 0x19, 0xcc, 0xdc, 0xdb, 0x73, 0xed, 0xad, 0x59, 0x2f, 0xa3,
+};
+
+static const uint8_t m1_address_0_7_xor[256] =
+{
+ 0xf4, 0xbc, 0x02, 0xf7, 0x2c, 0x3d, 0xe8, 0xd9, 0x50, 0x62, 0xec, 0xbd, 0x53, 0x73, 0x79, 0x61,
+ 0x00, 0x34, 0xcf, 0xa2, 0x63, 0x28, 0x90, 0xaf, 0x44, 0x3b, 0xc5, 0x8d, 0x3a, 0x46, 0x07, 0x70,
+ 0x66, 0xbe, 0xd8, 0x8b, 0xe9, 0xa0, 0x4b, 0x98, 0xdc, 0xdf, 0xe2, 0x16, 0x74, 0xf1, 0x37, 0xf5,
+ 0xb7, 0x21, 0x81, 0x01, 0x1c, 0x1b, 0x94, 0x36, 0x09, 0xa1, 0x4a, 0x91, 0x30, 0x92, 0x9b, 0x9a,
+ 0x29, 0xb1, 0x38, 0x4d, 0x55, 0xf2, 0x56, 0x18, 0x24, 0x47, 0x9d, 0x3f, 0x80, 0x1f, 0x22, 0xa4,
+ 0x11, 0x54, 0x84, 0x0d, 0x25, 0x48, 0xee, 0xc6, 0x59, 0x15, 0x03, 0x7a, 0xfd, 0x6c, 0xc3, 0x33,
+ 0x5b, 0xc4, 0x7b, 0x5a, 0x05, 0x7f, 0xa6, 0x40, 0xa9, 0x5d, 0x41, 0x8a, 0x96, 0x52, 0xd3, 0xf0,
+ 0xab, 0x72, 0x10, 0x88, 0x6f, 0x95, 0x7c, 0xa8, 0xcd, 0x9c, 0x5f, 0x32, 0xae, 0x85, 0x39, 0xac,
+ 0xe5, 0xd7, 0xfb, 0xd4, 0x08, 0x23, 0x19, 0x65, 0x6b, 0xa7, 0x93, 0xbb, 0x2b, 0xbf, 0xb8, 0x35,
+ 0xd0, 0x06, 0x26, 0x68, 0x3e, 0xdd, 0xb9, 0x69, 0x2a, 0xb2, 0xde, 0x87, 0x45, 0x58, 0xff, 0x3c,
+ 0x9e, 0x7d, 0xda, 0xed, 0x49, 0x8c, 0x14, 0x8e, 0x75, 0x2f, 0xe0, 0x6e, 0x78, 0x6d, 0x20, 0xd2,
+ 0xfa, 0x2d, 0x51, 0xcc, 0xc7, 0xe7, 0x1d, 0x27, 0x97, 0xfc, 0x31, 0xdb, 0xf8, 0x42, 0xe3, 0x99,
+ 0x5e, 0x83, 0x0e, 0xb4, 0x2e, 0xf6, 0xc0, 0x0c, 0x4c, 0x57, 0xb6, 0x64, 0x0a, 0x17, 0xa3, 0xc1,
+ 0x77, 0x12, 0xfe, 0xe6, 0x8f, 0x13, 0x71, 0xe4, 0xf9, 0xad, 0x9f, 0xce, 0xd5, 0x89, 0x7e, 0x0f,
+ 0xc2, 0x86, 0xf3, 0x67, 0xba, 0x60, 0x43, 0xc9, 0x04, 0xb3, 0xb0, 0x1e, 0xb5, 0xc8, 0xeb, 0xa5,
+ 0x76, 0xea, 0x5c, 0x82, 0x1a, 0x4f, 0xaa, 0xca, 0xe1, 0x0b, 0x4e, 0xcb, 0x6a, 0xef, 0xd1, 0xd6,
+};
+
+
+/* The CMC50 hardware does a checksum of the first 64kb of the M1 rom,
+ ,and uses this checksum as the basis of the key with which to decrypt
+ the rom */
+
+uint16_t cmc_prot_device::generate_cs16(uint8_t *rom, int size)
+{
+ uint16_t cs16 = 0;
+ for (int i=0; i<size; i++ )
+ cs16 += rom[i];
+
+ return cs16;
+}
+
+
+int cmc_prot_device::m1_address_scramble(int address, uint16_t key)
+{
+ const int p1[8][16] = {
+ {15,14,10,7,1,2,3,8,0,12,11,13,6,9,5,4},
+ {7,1,8,11,15,9,2,3,5,13,4,14,10,0,6,12},
+ {8,6,14,3,10,7,15,1,4,0,2,5,13,11,12,9},
+ {2,8,15,9,3,4,11,7,13,6,0,10,1,12,14,5},
+ {1,13,6,15,14,3,8,10,9,4,7,12,5,2,0,11},
+ {11,15,3,4,7,0,9,2,6,14,12,1,8,5,10,13},
+ {10,5,13,8,6,15,1,14,11,9,3,0,12,7,4,2},
+ {9,3,7,0,2,12,4,11,14,10,5,8,15,13,1,6},
+ };
+
+ int block = (address>>16)&7;
+ int aux = address&0xffff;
+
+ aux ^= bitswap<16>(key,12,0,2,4,8,15,7,13,10,1,3,6,11,9,14,5);
+ aux = bitswap<16>(aux,
+ p1[block][15],p1[block][14],p1[block][13],p1[block][12],
+ p1[block][11],p1[block][10],p1[block][9],p1[block][8],
+ p1[block][7],p1[block][6],p1[block][5],p1[block][4],
+ p1[block][3],p1[block][2],p1[block][1],p1[block][0]);
+ aux ^= m1_address_0_7_xor[(aux>>8)&0xff];
+ aux ^= m1_address_8_15_xor[aux&0xff]<<8;
+ aux = bitswap<16>(aux, 7,15,14,6,5,13,12,4,11,3,10,2,9,1,8,0);
+
+ return (block<<16)|aux;
+}
+
+
+void cmc_prot_device::neogeo_cmc50_m1_decrypt(uint8_t* romcrypt, uint32_t romcrypt_size, uint8_t* romaudio, uint32_t romaudio_size)
+{
+ uint8_t* rom = romcrypt;
+ size_t rom_size = 0x80000;
+ uint8_t* rom2 = romaudio;
+
+ std::vector<uint8_t> buffer(rom_size);
+
+ uint32_t i;
+
+ uint16_t key=generate_cs16(rom,0x10000);
+
+ //printf("key %04x\n",key);
+
+ for (i=0; i<rom_size; i++)
+ buffer[i] = rom[m1_address_scramble(i, key)];
+
+ memcpy(rom,&buffer[0],rom_size);
+ memcpy(rom2,rom,0x10000);
+ memcpy(rom2+0x10000,rom,0x80000);
+
+#if 0
+ {
+ FILE *fp;
+ const char *gamename = machine().system().name;
+ char filename[256];
+ sprintf(filename, "%s_m1.dump", gamename);
+
+ fp=fopen(filename, "w+b");
+ if (fp)
+ {
+ fwrite(rom, rom_size, 1, fp);
+ fclose(fp);
+ }
+ }
+#endif
+
+
+#if 0
+ {
+ FILE *fp;
+ const char *gamename = machine().system().name;
+ char filename[256];
+ sprintf(filename, "%s_m1extra.dump", gamename);
+
+ fp=fopen(filename, "w+b");
+ if (fp)
+ {
+ fwrite(&rom[0xf800], 0x800, 1, fp);
+ fclose(fp);
+ }
+ }
+#endif
+}
+
+/***********************************************************************************************************************************/
+
+DEFINE_DEVICE_TYPE(FATFURY2_PROT, fatfury2_prot_device, "fatfury2_prot", "NeoGeo Protection (Fatal Fury 2)")
+
+
+fatfury2_prot_device::fatfury2_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, FATFURY2_PROT, tag, owner, clock)
+ , m_bankdev(nullptr)
+ , m_fatfury2_prot_data(0)
+ { }
+
+
+void fatfury2_prot_device::device_start()
+{
+ save_item(NAME(m_fatfury2_prot_data));
+}
+
+void fatfury2_prot_device::device_reset() { }
+
+
+
+/************************ Fatal Fury 2 *************************/
+
+READ16_MEMBER( fatfury2_prot_device::fatfury2_protection_16_r )
+{
+ uint16_t res = m_fatfury2_prot_data >> 24;
+
+ switch (offset)
+ {
+ case 0x55550/2:
+ case 0xffff0/2:
+ case 0x00000/2:
+ case 0xff000/2:
+ case 0x36000/2:
+ case 0x36008/2:
+ return res;
+
+ case 0x36004/2:
+ case 0x3600c/2:
+ return ((res & 0xf0) >> 4) | ((res & 0x0f) << 4);
+
+ default:
+ logerror("unknown protection read at pc %06x, offset %08x\n", machine().describe_context(), offset << 1);
+ return 0;
+ }
+}
+
+
+WRITE16_MEMBER( fatfury2_prot_device::fatfury2_protection_16_w )
+{
+ switch (offset)
+ {
+ case 0x11112/2: /* data == 0x1111; expects 0xff000000 back */
+ m_fatfury2_prot_data = 0xff000000;
+ break;
+
+ case 0x33332/2: /* data == 0x3333; expects 0x0000ffff back */
+ m_fatfury2_prot_data = 0x0000ffff;
+ break;
+
+ case 0x44442/2: /* data == 0x4444; expects 0x00ff0000 back */
+ m_fatfury2_prot_data = 0x00ff0000;
+ break;
+
+ case 0x55552/2: /* data == 0x5555; read back from 55550, ffff0, 00000, ff000 */
+ m_fatfury2_prot_data = 0xff00ff00;
+ break;
+
+ case 0x56782/2: /* data == 0x1234; read back from 36000 *or* 36004 */
+ m_fatfury2_prot_data = 0xf05a3601;
+ break;
+
+ case 0x42812/2: /* data == 0x1824; read back from 36008 *or* 3600c */
+ m_fatfury2_prot_data = 0x81422418;
+ break;
+
+ case 0x55550/2:
+ case 0xffff0/2:
+ case 0xff000/2:
+ case 0x36000/2:
+ case 0x36004/2:
+ case 0x36008/2:
+ case 0x3600c/2:
+ m_fatfury2_prot_data <<= 8;
+ break;
+
+ default:
+ logerror("unknown protection write at pc %06x, offset %08x, data %02x\n", machine().describe_context(), offset, data);
+ break;
+ }
+}
+
+
+void fatfury2_prot_device::fatfury2_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev)
+{
+ /* the protection involves reading and writing addresses in the */
+ /* 0x2xxxxx range. There are several checks all around the code. */
+ maincpu->space(AS_PROGRAM).install_readwrite_handler(0x200000, 0x2fffff,
+ read16_delegate(FUNC(fatfury2_prot_device::fatfury2_protection_16_r),this),
+ write16_delegate(FUNC(fatfury2_prot_device::fatfury2_protection_16_w),this));
+
+ m_bankdev = bankdev;
+ m_fatfury2_prot_data = 0;
+
+}
+
+/***********************************************************************************************************************************/
+
+
+DEFINE_DEVICE_TYPE(KOF2002_PROT, kof2002_prot_device, "kof2002_prot", "NeoGeo Protection (KOF2002)")
+
+
+kof2002_prot_device::kof2002_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, KOF2002_PROT, tag, owner, clock)
+ { }
+
+
+void kof2002_prot_device::device_start() { }
+
+void kof2002_prot_device::device_reset() { }
+
+
+/* kof2002, matrim, samsho5, samsh5sp have some simple block swapping */
+void kof2002_prot_device::kof2002_decrypt_68k(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ static const int sec[]={0x100000,0x280000,0x300000,0x180000,0x000000,0x380000,0x200000,0x080000};
+ uint8_t *src = cpurom+0x100000;
+ std::vector<uint8_t> dst(0x400000);
+ memcpy( &dst[0], src, 0x400000 );
+ for( uint8_t i=0; i<8; ++i )
+ memcpy( src+i*0x80000, &dst[sec[i]], 0x80000 );
+}
+
+
+void kof2002_prot_device::matrim_decrypt_68k(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ static const int sec[]={0x100000,0x280000,0x300000,0x180000,0x000000,0x380000,0x200000,0x080000};
+ uint8_t *src = cpurom+0x100000;
+ std::vector<uint8_t> dst(0x400000);
+ memcpy( &dst[0], src, 0x400000);
+ for( uint8_t i=0; i<8; ++i )
+ memcpy( src+i*0x80000, &dst[sec[i]], 0x80000 );
+}
+
+
+void kof2002_prot_device::samsho5_decrypt_68k(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ static const int sec[]={0x000000,0x080000,0x700000,0x680000,0x500000,0x180000,0x200000,0x480000,0x300000,0x780000,0x600000,0x280000,0x100000,0x580000,0x400000,0x380000};
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst(0x800000);
+ memcpy( &dst[0], src, 0x800000 );
+ for( uint8_t i=0; i<16; ++i )
+ memcpy( src+i*0x80000, &dst[sec[i]], 0x80000 );
+}
+
+
+void kof2002_prot_device::samsh5sp_decrypt_68k(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ static const int sec[]={0x000000,0x080000,0x500000,0x480000,0x600000,0x580000,0x700000,0x280000,0x100000,0x680000,0x400000,0x780000,0x200000,0x380000,0x300000,0x180000};
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst(0x800000);
+ memcpy( &dst[0], src, 0x800000 );
+ for( uint8_t i=0; i<16; ++i )
+ memcpy( src+i*0x80000, &dst[sec[i]], 0x80000 );
+}
+
+/***********************************************************************************************************************************/
+
+DEFINE_DEVICE_TYPE(KOF98_PROT, kof98_prot_device, "kof98_prot", "NeoGeo Protection (KOF98)")
+
+
+kof98_prot_device::kof98_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, KOF98_PROT, tag, owner, clock)
+ , kof98_prot_state(0)
+ { }
+
+
+void kof98_prot_device::device_start() { }
+
+void kof98_prot_device::device_reset()
+{
+ kof98_prot_state = 0;
+}
+
+
+/* Kof98 uses an early encryption, quite different from the others */
+void kof98_prot_device::kof98_decrypt_68k(uint8_t* cpurom, uint32_t cpurom_size)
+{
+ uint8_t *src = cpurom;
+ std::vector<uint8_t> dst(0x200000);
+ int i, j, k;
+ static const uint32_t sec[]={0x000000,0x100000,0x000004,0x100004,0x10000a,0x00000a,0x10000e,0x00000e};
+ static const uint32_t pos[]={0x000,0x004,0x00a,0x00e};
+
+ memcpy( &dst[0], src, 0x200000);
+ for( i=0x800; i<0x100000; i+=0x200 )
+ {
+ for( j=0; j<0x100; j+=0x10 )
+ {
+ for( k=0; k<16; k+=2)
+ {
+ memcpy( &src[i+j+k], &dst[ i+j+sec[k/2]+0x100 ], 2 );
+ memcpy( &src[i+j+k+0x100], &dst[ i+j+sec[k/2] ], 2 );
+ }
+ if( i >= 0x080000 && i < 0x0c0000)
+ {
+ for( k=0; k<4; k++ )
+ {
+ memcpy( &src[i+j+pos[k]], &dst[i+j+pos[k]], 2 );
+ memcpy( &src[i+j+pos[k]+0x100], &dst[i+j+pos[k]+0x100], 2 );
+ }
+ }
+ else if( i >= 0x0c0000 )
+ {
+ for( k=0; k<4; k++ )
+ {
+ memcpy( &src[i+j+pos[k]], &dst[i+j+pos[k]+0x100], 2 );
+ memcpy( &src[i+j+pos[k]+0x100], &dst[i+j+pos[k]], 2 );
+ }
+ }
+ }
+ memcpy( &src[i+0x000000], &dst[i+0x000000], 2 );
+ memcpy( &src[i+0x000002], &dst[i+0x100000], 2 );
+ memcpy( &src[i+0x000100], &dst[i+0x000100], 2 );
+ memcpy( &src[i+0x000102], &dst[i+0x100100], 2 );
+ }
+ memmove( &src[0x100000], &src[0x200000], 0x400000 );
+
+ uint16_t* mem16 = (uint16_t*)cpurom;
+ m_default_rom[0] = mem16[0x100 / 2];
+ m_default_rom[1] = mem16[0x102 / 2];
+}
+
+
+/************************ King of Fighters 98*******************
+ The encrypted set has a rom overlay feature, checked at
+ various points in the game.
+ Boards used: NEO-MVS PROGSF1 (1998.6.17) / NEO-MVS PROGSF1E (1998.6.18)
+ The boards have an ALTERA chip (EPM7128SQC100-15) which is tied to 242-P1
+***************************************************************/
+
+READ16_MEMBER(kof98_prot_device::kof98_prot_r)
+{
+ if (kof98_prot_state == 1)
+ {
+ if (!offset)
+ return 0x00c2;
+ else
+ return 0x00fd;
+ }
+
+ if (kof98_prot_state == 2)
+ {
+ if (!offset)
+ return 0x4e45;
+ else
+ return 0x4f2d;
+ }
+
+ if (!offset)
+ return m_default_rom[0];
+
+ return m_default_rom[1];
+}
+
+WRITE16_MEMBER( kof98_prot_device::kof98_prot_w )
+{
+ /* info from razoola */
+ switch (data)
+ {
+ case 0x0090:
+ logerror ("%06x kof98 - protection 0x0090x\n", machine().describe_context());
+ kof98_prot_state = 1;
+ break;
+
+ case 0x00f0:
+ logerror ("%06x kof98 - protection 0x00f0x\n", machine().describe_context());
+ kof98_prot_state = 2;
+ break;
+
+ default: // 00aa is written, but not needed?
+ logerror ("%06x kof98 - unknown protection write %04x\n", machine().describe_context(), data);
+ break;
+ }
+}
+
+
+void kof98_prot_device::install_kof98_protection(cpu_device* maincpu)
+{
+ /* when 0x20aaaa contains 0x0090 (word) then 0x100 (normally the neogeo header) should return 0x00c200fd worked out using real hw */
+ maincpu->space(AS_PROGRAM).install_read_handler(0x00100, 0x00103, read16_delegate(FUNC(kof98_prot_device::kof98_prot_r),this));
+ maincpu->space(AS_PROGRAM).install_write_handler(0x20aaaa, 0x20aaab, write16_delegate(FUNC(kof98_prot_device::kof98_prot_w),this));
+}
+
+/***********************************************************************************************************************************/
+
+
+DEFINE_DEVICE_TYPE(MSLUGX_PROT, mslugx_prot_device, "mslugx_prot", "NeoGeo Protection (Metal Slug X)")
+
+
+mslugx_prot_device::mslugx_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, MSLUGX_PROT, tag, owner, clock)
+ , m_mslugx_counter(0)
+ , m_mslugx_command(0)
+ { }
+
+
+void mslugx_prot_device::device_start()
+{
+ save_item(NAME(m_mslugx_command));
+ save_item(NAME(m_mslugx_counter));
+}
+
+void mslugx_prot_device::device_reset() { }
+
+
+
+
+/************************ Metal Slug X *************************
+ Board used: NEO-MVS PROGEOP (1999.2.2)
+ The board has an ALTERA chip (EPM7128SQC100-15) which is tied to 250-P1
+ Also found is a QFP144 chip labeled with 0103 - function unknown
+***************************************************************/
+
+WRITE16_MEMBER( mslugx_prot_device::mslugx_protection_16_w )
+{
+ switch (offset)
+ {
+ case 0x0/2: // start new read?
+ m_mslugx_command = 0;
+ break;
+
+ case 0x2/2: // command? These are pulsed with data and then 0
+ case 0x4/2:
+ m_mslugx_command |= data;
+ break;
+
+ case 0x6/2: // finished?
+ break;
+
+ case 0xa/2: // init?
+ m_mslugx_counter = 0;
+ m_mslugx_command = 0;
+ break;
+
+ default:
+ logerror("unknown protection write at pc %06x, offset %08x, data %02x\n", machine().describe_context(), offset << 1, data);
+ break;
+ }
+}
+
+
+READ16_MEMBER( mslugx_prot_device::mslugx_protection_16_r )
+{
+ uint16_t res = 0;
+
+ switch (m_mslugx_command)
+ {
+ case 0x0001: { // $3bdc(?) and $3c30 (Register D7)
+ res = (space.read_byte(0xdedd2 + ((m_mslugx_counter >> 3) & 0xfff)) >> (~m_mslugx_counter & 0x07)) & 1;
+ m_mslugx_counter++;
+ }
+ break;
+
+ case 0x0fff: { // All other accesses (Register D2)
+ int32_t select = space.read_word(0x10f00a) - 1; // How should this be calculated?
+ res = (space.read_byte(0xdedd2 + ((select >> 3) & 0x0fff)) >> (~select & 0x07)) & 1;
+ }
+ break;
+
+ default:
+ logerror("unknown protection read at pc %06x, offset %08x\n", machine().describe_context(), offset << 1);
+ break;
+ }
+
+ return res;
+}
+
+
+void mslugx_prot_device::mslugx_install_protection(cpu_device* maincpu)
+{
+ maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2fffe0, 0x2fffef,
+ read16_delegate(FUNC(mslugx_prot_device::mslugx_protection_16_r),this),
+ write16_delegate(FUNC(mslugx_prot_device::mslugx_protection_16_w),this));
+}
+
+/***********************************************************************************************************************************/
+
+
+DEFINE_DEVICE_TYPE(PCM2_PROT, pcm2_prot_device, "pcm2_prot", "NeoGeo Protection (NEOPCM2)")
+
+
+pcm2_prot_device::pcm2_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PCM2_PROT, tag, owner, clock)
+ { }
+
+
+void pcm2_prot_device::device_start() { }
+
+void pcm2_prot_device::device_reset() { }
+
+/***************************************************************************
+
+NeoGeo 'V' (PCM) ROM encryption
+ NEOPCM2 chip
+
+***************************************************************************/
+
+/* Neo-Pcm2 Drivers for Encrypted V Roms */
+void pcm2_prot_device::neo_pcm2_snk_1999(uint8_t* ymrom, uint32_t ymsize, int value)
+{ /* thanks to Elsemi for the NEO-PCM2 info */
+ uint16_t *rom = (uint16_t *)ymrom;
+ int size = ymsize;
+ int i, j;
+
+ if (rom)
+ { /* swap address lines on the whole ROMs */
+ std::vector<uint16_t> buffer(value / 2);
+
+ for( i = 0; i < size / 2; i += ( value / 2 ) )
+ {
+ memcpy( &buffer[0], &rom[ i ], value );
+ for( j = 0; j < (value / 2); j++ )
+ rom[ i + j ] = buffer[ j ^ (value/4) ];
+ }
+ }
+}
+
+
+/* the later PCM2 games have additional scrambling */
+void pcm2_prot_device::neo_pcm2_swap(uint8_t* ymrom, uint32_t ymsize, int value)
+{
+ static const uint32_t addrs[7][2]={
+ {0x000000,0xa5000},
+ {0xffce20,0x01000},
+ {0xfe2cf6,0x4e001},
+ {0xffac28,0xc2000},
+ {0xfeb2c0,0x0a000},
+ {0xff14ea,0xa7001},
+ {0xffb440,0x02000}};
+ static const uint8_t xordata[7][8]={
+ {0xf9,0xe0,0x5d,0xf3,0xea,0x92,0xbe,0xef},
+ {0xc4,0x83,0xa8,0x5f,0x21,0x27,0x64,0xaf},
+ {0xc3,0xfd,0x81,0xac,0x6d,0xe7,0xbf,0x9e},
+ {0xc3,0xfd,0x81,0xac,0x6d,0xe7,0xbf,0x9e},
+ {0xcb,0x29,0x7d,0x43,0xd2,0x3a,0xc2,0xb4},
+ {0x4b,0xa4,0x63,0x46,0xf0,0x91,0xea,0x62},
+ {0x4b,0xa4,0x63,0x46,0xf0,0x91,0xea,0x62}};
+
+ std::vector<uint8_t> buf(0x1000000);
+ int i, j, d;
+ uint8_t* src = ymrom;
+ memcpy(&buf[0], src, 0x1000000);
+ for (i=0; i<0x1000000; i++)
+ {
+ j = bitswap<24>(i,23,22,21,20,19,18,17,0,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,16);
+ j ^= addrs[value][1];
+ d=((i + addrs[value][0]) & 0xffffff);
+ src[j] = buf[d] ^ xordata[value][j & 0x7];
+ }
+}
+
+/***********************************************************************************************************************************/
+
+
+DEFINE_DEVICE_TYPE(PVC_PROT, pvc_prot_device, "pvc_prot", "NeoGeo Protection (PVC)")
+
+
+pvc_prot_device::pvc_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, PVC_PROT, tag, owner, clock)
+ , m_bankdev(nullptr)
+ { }
+
+
+void pvc_prot_device::device_start()
+{
+ save_item(NAME(m_cartridge_ram));
+}
+
+void pvc_prot_device::device_reset() { }
+
+
+
+
+/************************ PVC Protection ***********************
+ mslug5, svcchaos, kof2003
+***************************************************************/
+
+void pvc_prot_device::pvc_write_unpack_color()
+{
+ uint16_t pen = m_cartridge_ram[0xff0];
+
+ uint8_t b = ((pen & 0x000f) << 1) | ((pen & 0x1000) >> 12);
+ uint8_t g = ((pen & 0x00f0) >> 3) | ((pen & 0x2000) >> 13);
+ uint8_t r = ((pen & 0x0f00) >> 7) | ((pen & 0x4000) >> 14);
+ uint8_t s = (pen & 0x8000) >> 15;
+
+ m_cartridge_ram[0xff1] = (g << 8) | b;
+ m_cartridge_ram[0xff2] = (s << 8) | r;
+}
+
+
+void pvc_prot_device::pvc_write_pack_color()
+{
+ uint16_t gb = m_cartridge_ram[0xff4];
+ uint16_t sr = m_cartridge_ram[0xff5];
+
+ m_cartridge_ram[0xff6] = ((gb & 0x001e) >> 1) | ((gb & 0x1e00) >> 5) | ((sr & 0x001e) << 7) |
+ ((gb & 0x0001) << 12) | ((gb & 0x0100) << 5) | ((sr & 0x0001) << 14) | ((sr & 0x0100) << 7);
+}
+
+
+void pvc_prot_device::pvc_write_bankswitch( address_space &space )
+{
+ uint32_t bankaddress = ((m_cartridge_ram[0xff8] >> 8)|(m_cartridge_ram[0xff9] << 8));
+ m_cartridge_ram[0xff8] = (m_cartridge_ram[0xff8] & 0xfe00) | 0x00a0;
+ m_cartridge_ram[0xff9] &= 0x7fff;
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress + 0x100000);
+}
+
+
+READ16_MEMBER( pvc_prot_device::pvc_prot_r )
+{
+ return m_cartridge_ram[offset];
+}
+
+
+WRITE16_MEMBER( pvc_prot_device::pvc_prot_w )
+{
+ COMBINE_DATA(&m_cartridge_ram[offset] );
+ if (offset == 0xff0)
+ pvc_write_unpack_color();
+ else
+ if(offset >= 0xff4 && offset <= 0xff5)
+ pvc_write_pack_color();
+ else
+ if(offset >= 0xff8)
+ pvc_write_bankswitch(space);
+}
+
+
+void pvc_prot_device::install_pvc_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev)
+{
+ m_bankdev = bankdev;
+ maincpu->space(AS_PROGRAM).install_readwrite_handler(0x2fe000, 0x2fffff,
+ read16_delegate(FUNC(pvc_prot_device::pvc_prot_r),this),
+ write16_delegate(FUNC(pvc_prot_device::pvc_prot_w),this));
+}
+
+
+
+
+/* kf2k3pcb, kof2003, kof2003h, mslug5 and svc have updated P rom scramble */
+void pvc_prot_device::mslug5_decrypt_68k(uint8_t* rom, uint32_t size)
+{
+ static const uint8_t xor1[ 0x20 ] = { 0xc2, 0x4b, 0x74, 0xfd, 0x0b, 0x34, 0xeb, 0xd7, 0x10, 0x6d, 0xf9, 0xce, 0x5d, 0xd5, 0x61, 0x29, 0xf5, 0xbe, 0x0d, 0x82, 0x72, 0x45, 0x0f, 0x24, 0xb3, 0x34, 0x1b, 0x99, 0xea, 0x09, 0xf3, 0x03 };
+ static const uint8_t xor2[ 0x20 ] = { 0x36, 0x09, 0xb0, 0x64, 0x95, 0x0f, 0x90, 0x42, 0x6e, 0x0f, 0x30, 0xf6, 0xe5, 0x08, 0x30, 0x64, 0x08, 0x04, 0x00, 0x2f, 0x72, 0x09, 0xa0, 0x13, 0xc9, 0x0b, 0xa0, 0x3e, 0xc2, 0x00, 0x40, 0x2b };
+ int i, ofst, rom_size = 0x800000;
+ std::vector<uint8_t> buf( rom_size );
+
+ for( i = 0; i < 0x100000; i++ )
+ rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x800000; i++ )
+ rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x0800000; i += 4 )
+ {
+ uint16_t rom16;
+ rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8;
+ rom16 = bitswap<16>( rom16, 15, 14, 13, 12, 10, 11, 8, 9, 6, 7, 4, 5, 3, 2, 1, 0 );
+ rom[BYTE_XOR_LE(i+1)] = rom16&0xff;
+ rom[BYTE_XOR_LE(i+2)] = rom16>>8;
+ }
+
+ memcpy( &buf[0], rom, rom_size );
+
+ for( i = 0; i < 0x0100000 / 0x10000; i++ )
+ {
+ ofst = (i & 0xf0) + bitswap<8>( (i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2 );
+ memcpy( &rom[ i * 0x10000 ], &buf[ ofst * 0x10000 ], 0x10000 );
+ }
+
+ for( i = 0x100000; i < 0x800000; i += 0x100 )
+ {
+ ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00700) + (bitswap<8>( ((i & 0x0ff000) >> 12), 5, 4, 7, 6, 1, 0, 3, 2 ) << 12);
+ memcpy( &rom[ i ], &buf[ ofst ], 0x100 );
+ }
+
+ memcpy( &buf[0], rom, rom_size );
+ memcpy( &rom[ 0x100000 ], &buf[ 0x700000 ], 0x100000 );
+ memcpy( &rom[ 0x200000 ], &buf[ 0x100000 ], 0x600000 );
+}
+
+
+void pvc_prot_device::svc_px_decrypt(uint8_t* rom, uint32_t size)
+{
+ static const uint8_t xor1[ 0x20 ] = { 0x3b, 0x6a, 0xf7, 0xb7, 0xe8, 0xa9, 0x20, 0x99, 0x9f, 0x39, 0x34, 0x0c, 0xc3, 0x9a, 0xa5, 0xc8,
+ 0xb8, 0x18, 0xce, 0x56, 0x94, 0x44, 0xe3, 0x7a, 0xf7, 0xdd, 0x42, 0xf0, 0x18, 0x60, 0x92, 0x9f };
+ static const uint8_t xor2[ 0x20 ] = { 0x69, 0x0b, 0x60, 0xd6, 0x4f, 0x01, 0x40, 0x1a, 0x9f, 0x0b, 0xf0, 0x75, 0x58, 0x0e, 0x60, 0xb4,
+ 0x14, 0x04, 0x20, 0xe4, 0xb9, 0x0d, 0x10, 0x89, 0xeb, 0x07, 0x30, 0x90, 0x50, 0x0e, 0x20, 0x26 };
+ int i, ofst, rom_size = 0x800000;
+ std::vector<uint8_t> buf( rom_size );
+
+ for( i = 0; i < 0x100000; i++ )
+ rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x800000; i++ )
+ rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x0800000; i += 4 )
+ {
+ uint16_t rom16;
+ rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8;
+ rom16 = bitswap<16>( rom16, 15, 14, 13, 12, 10, 11, 8, 9, 6, 7, 4, 5, 3, 2, 1, 0 );
+ rom[BYTE_XOR_LE(i+1)] = rom16&0xff;
+ rom[BYTE_XOR_LE(i+2)] = rom16>>8;
+ }
+
+ memcpy( &buf[0], rom, rom_size );
+
+ for( i = 0; i < 0x0100000 / 0x10000; i++ )
+ {
+ ofst = (i & 0xf0) + bitswap<8>( (i & 0x0f), 7, 6, 5, 4, 2, 3, 0, 1 );
+ memcpy( &rom[ i * 0x10000 ], &buf[ ofst * 0x10000 ], 0x10000 );
+ }
+
+ for( i = 0x100000; i < 0x800000; i += 0x100 )
+ {
+ ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00a00) + (bitswap<8>( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12);
+ memcpy( &rom[ i ], &buf[ ofst ], 0x100 );
+ }
+
+ memcpy( &buf[0], rom, rom_size );
+ memcpy( &rom[ 0x100000 ], &buf[ 0x700000 ], 0x100000 );
+ memcpy( &rom[ 0x200000 ], &buf[ 0x100000 ], 0x600000 );
+}
+
+
+void pvc_prot_device::kf2k3pcb_decrypt_68k(uint8_t* rom, uint32_t size)
+{
+ static const uint8_t xor2[ 0x20 ] = { 0xb4, 0x0f, 0x40, 0x6c, 0x38, 0x07, 0xd0, 0x3f, 0x53, 0x08, 0x80, 0xaa, 0xbe, 0x07, 0xc0, 0xfa,
+ 0xd0, 0x08, 0x10, 0xd2, 0xf1, 0x03, 0x70, 0x7e, 0x87, 0x0b, 0x40, 0xf6, 0x2a, 0x0a, 0xe0, 0xf9 };
+ int i, ofst, rom_size = 0x900000;
+ std::vector<uint8_t> buf( rom_size );
+
+ for (i = 0; i < 0x100000; i++)
+ rom[ 0x800000 + i ] ^= rom[ 0x100002 | i ];
+
+ for( i = 0x100000; i < 0x800000; i++ )
+ rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x800000; i += 4 )
+ {
+ uint16_t rom16;
+ rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8;
+ rom16 = bitswap<16>( rom16, 15, 14, 13, 12, 4, 5, 6, 7, 8, 9, 10, 11, 3, 2, 1, 0 );
+ rom[BYTE_XOR_LE(i+1)] = rom16&0xff;
+ rom[BYTE_XOR_LE(i+2)] = rom16>>8;
+ }
+
+ for( i = 0; i < 0x0100000 / 0x10000; i++ )
+ {
+ ofst = (i & 0xf0) + bitswap<8>( (i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2 );
+ memcpy( &buf[ i * 0x10000 ], &rom[ ofst * 0x10000 ], 0x10000 );
+ }
+
+ for( i = 0x100000; i < 0x900000; i += 0x100 )
+ {
+ ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00300) + (bitswap<8>( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12);
+ memcpy( &buf[ i ], &rom[ ofst ], 0x100 );
+ }
+
+ memcpy (&rom[0x000000], &buf[0x000000], 0x100000);
+ memcpy (&rom[0x100000], &buf[0x800000], 0x100000);
+ memcpy (&rom[0x200000], &buf[0x100000], 0x700000);
+}
+
+
+void pvc_prot_device::kof2003_decrypt_68k(uint8_t* rom, uint32_t size)
+{
+ static const uint8_t xor1[0x20] = { 0x3b, 0x6a, 0xf7, 0xb7, 0xe8, 0xa9, 0x20, 0x99, 0x9f, 0x39, 0x34, 0x0c, 0xc3, 0x9a, 0xa5, 0xc8,
+ 0xb8, 0x18, 0xce, 0x56, 0x94, 0x44, 0xe3, 0x7a, 0xf7, 0xdd, 0x42, 0xf0, 0x18, 0x60, 0x92, 0x9f };
+ static const uint8_t xor2[0x20] = { 0x2f, 0x02, 0x60, 0xbb, 0x77, 0x01, 0x30, 0x08, 0xd8, 0x01, 0xa0, 0xdf, 0x37, 0x0a, 0xf0, 0x65,
+ 0x28, 0x03, 0xd0, 0x23, 0xd3, 0x03, 0x70, 0x42, 0xbb, 0x06, 0xf0, 0x28, 0xba, 0x0f, 0xf0, 0x7a };
+ int i, ofst, rom_size = 0x900000;
+ std::vector<uint8_t> buf( rom_size );
+
+ for (i = 0; i < 0x100000; i++)
+ rom[ 0x800000 + i ] ^= rom[ 0x100002 | i ];
+
+ for( i = 0; i < 0x100000; i++)
+ rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x800000; i++)
+ rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x800000; i += 4)
+ {
+ uint16_t rom16;
+ rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8;
+ rom16 = bitswap<16>( rom16, 15, 14, 13, 12, 5, 4, 7, 6, 9, 8, 11, 10, 3, 2, 1, 0 );
+ rom[BYTE_XOR_LE(i+1)] = rom16&0xff;
+ rom[BYTE_XOR_LE(i+2)] = rom16>>8;
+ }
+
+ for( i = 0; i < 0x0100000 / 0x10000; i++ )
+ {
+ ofst = (i & 0xf0) + bitswap<8>((i & 0x0f), 7, 6, 5, 4, 0, 1, 2, 3);
+ memcpy( &buf[ i * 0x10000 ], &rom[ ofst * 0x10000 ], 0x10000 );
+ }
+
+ for( i = 0x100000; i < 0x900000; i += 0x100)
+ {
+ ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00800) + (bitswap<8>( ((i & 0x0ff000) >> 12), 4, 5, 6, 7, 1, 0, 3, 2 ) << 12);
+ memcpy( &buf[ i ], &rom[ ofst ], 0x100 );
+ }
+
+ memcpy (&rom[0x000000], &buf[0x000000], 0x100000);
+ memcpy (&rom[0x100000], &buf[0x800000], 0x100000);
+ memcpy (&rom[0x200000], &buf[0x100000], 0x700000);
+}
+
+
+void pvc_prot_device::kof2003h_decrypt_68k(uint8_t* rom, uint32_t size)
+{
+ static const uint8_t xor1[0x20] = { 0xc2, 0x4b, 0x74, 0xfd, 0x0b, 0x34, 0xeb, 0xd7, 0x10, 0x6d, 0xf9, 0xce, 0x5d, 0xd5, 0x61, 0x29,
+ 0xf5, 0xbe, 0x0d, 0x82, 0x72, 0x45, 0x0f, 0x24, 0xb3, 0x34, 0x1b, 0x99, 0xea, 0x09, 0xf3, 0x03 };
+ static const uint8_t xor2[0x20] = { 0x2b, 0x09, 0xd0, 0x7f, 0x51, 0x0b, 0x10, 0x4c, 0x5b, 0x07, 0x70, 0x9d, 0x3e, 0x0b, 0xb0, 0xb6,
+ 0x54, 0x09, 0xe0, 0xcc, 0x3d, 0x0d, 0x80, 0x99, 0x87, 0x03, 0x90, 0x82, 0xfe, 0x04, 0x20, 0x18 };
+ int i, ofst, rom_size = 0x900000;
+ std::vector<uint8_t> buf( rom_size );
+
+ for (i = 0; i < 0x100000; i++)
+ rom[ 0x800000 + i ] ^= rom[ 0x100002 | i ];
+
+ for( i = 0; i < 0x100000; i++)
+ rom[ i ] ^= xor1[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x800000; i++)
+ rom[ i ] ^= xor2[ (BYTE_XOR_LE(i) % 0x20) ];
+
+ for( i = 0x100000; i < 0x800000; i += 4)
+ {
+ uint16_t rom16;
+ rom16 = rom[BYTE_XOR_LE(i+1)] | rom[BYTE_XOR_LE(i+2)]<<8;
+ rom16 = bitswap<16>( rom16, 15, 14, 13, 12, 10, 11, 8, 9, 6, 7, 4, 5, 3, 2, 1, 0 );
+ rom[BYTE_XOR_LE(i+1)] = rom16&0xff;
+ rom[BYTE_XOR_LE(i+2)] = rom16>>8;
+ }
+
+ for( i = 0; i < 0x0100000 / 0x10000; i++ )
+ {
+ ofst = (i & 0xf0) + bitswap<8>((i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2);
+ memcpy( &buf[ i * 0x10000 ], &rom[ ofst * 0x10000 ], 0x10000 );
+ }
+
+ for( i = 0x100000; i < 0x900000; i += 0x100)
+ {
+ ofst = (i & 0xf000ff) + ((i & 0x000f00) ^ 0x00400) + (bitswap<8>( ((i & 0x0ff000) >> 12), 6, 7, 4, 5, 0, 1, 2, 3 ) << 12);
+ memcpy( &buf[ i ], &rom[ ofst ], 0x100 );
+ }
+
+ memcpy (&rom[0x000000], &buf[0x000000], 0x100000);
+ memcpy (&rom[0x100000], &buf[0x800000], 0x100000);
+ memcpy (&rom[0x200000], &buf[0x100000], 0x700000);
+}
+
+/***********************************************************************************************************************************/
+
+
+DEFINE_DEVICE_TYPE(SBP_PROT, sbp_prot_device, "sbp_prot", "NeoGeo Protection (Super Bubble Pop)")
+
+
+sbp_prot_device::sbp_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SBP_PROT, tag, owner, clock)
+ , m_mainrom(nullptr)
+ { }
+
+void sbp_prot_device::device_start() { }
+void sbp_prot_device::device_reset() { }
+
+READ16_MEMBER( sbp_prot_device::sbp_lowerrom_r )
+{
+ uint16_t* rom = (uint16_t*)m_mainrom;
+ uint16_t origdata = rom[(offset+(0x200/2))];
+ uint16_t data = bitswap<16>(origdata, 11,10,9,8,15,14,13,12,3,2,1,0,7,6,5,4);
+ int realoffset = 0x200+(offset*2);
+ logerror("sbp_lowerrom_r offset %08x data %04x\n", realoffset, data );
+
+ // there is actually data in the rom here already, maybe we should just return it 'as is'
+ if (realoffset==0xd5e) return origdata;
+
+ return data;
+}
+
+WRITE16_MEMBER( sbp_prot_device::sbp_lowerrom_w )
+{
+ int realoffset = 0x200+(offset*2);
+
+ // the actual data written is just pulled from the end of the rom, and unused space
+ // maybe this is just some kind of watchdog for the protection device and it doesn't
+ // matter?
+ if (realoffset == 0x1080)
+ {
+ if (data==0x4e75)
+ return;
+ else
+ if (data==0xffff)
+ return;
+ }
+
+ printf("sbp_lowerrom_w offset %08x data %04x\n", realoffset, data );
+}
+
+
+void sbp_prot_device::sbp_install_protection(cpu_device* maincpu, uint8_t* cpurom, uint32_t cpurom_size)
+{
+ m_mainrom = cpurom;
+
+ // there seems to be a protection device living around here..
+ // if you nibble swap the data in the rom the game will boot
+ // there are also writes to 0x1080..
+ //
+ // other stuff going on as well tho, the main overlay is still missing, and p1 inputs don't work
+ maincpu->space(AS_PROGRAM).install_read_handler(0x00200, 0x001fff, read16_delegate(FUNC(sbp_prot_device::sbp_lowerrom_r), this));
+ maincpu->space(AS_PROGRAM).install_write_handler(0x00200, 0x001fff, write16_delegate(FUNC(sbp_prot_device::sbp_lowerrom_w), this));
+
+ /* the game code clears the text overlay used ingame immediately after writing it.. why? protection? sloppy code that the hw ignores? imperfect emulation? */
+ {
+ uint16_t* rom = (uint16_t*)cpurom;
+
+ rom[0x2a6f8 / 2] = 0x4e71;
+ rom[0x2a6fa / 2] = 0x4e71;
+ rom[0x2a6fc / 2] = 0x4e71;
+ }
+}
+
+/***********************************************************************************************************************************/
+
+
+DEFINE_DEVICE_TYPE(SMA_PROT, sma_prot_device, "sma_prot", "NeoGeo SMA Cartridge")
+
+
+sma_prot_device::sma_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, SMA_PROT, tag, owner, clock)
+ , m_bankdev(nullptr)
+ , m_sma_rng(0)
+ { }
+
+
+void sma_prot_device::device_start()
+{
+ save_item(NAME(m_sma_rng));
+}
+
+void sma_prot_device::device_reset()
+{
+ reset_sma_rng();
+}
+
+
+/************************ SMA Protection************************
+ thanks to Razoola
+***************************************************************/
+
+WRITE16_MEMBER( sma_prot_device::kof99_bankswitch_w )
+{
+ static const int bankoffset[64] =
+ {
+ 0x000000, 0x100000, 0x200000, 0x300000,
+ 0x3cc000, 0x4cc000, 0x3f2000, 0x4f2000,
+ 0x407800, 0x507800, 0x40d000, 0x50d000,
+ 0x417800, 0x517800, 0x420800, 0x520800,
+ 0x424800, 0x524800, 0x429000, 0x529000,
+ 0x42e800, 0x52e800, 0x431800, 0x531800,
+ 0x54d000, 0x551000, 0x567000, 0x592800,
+ 0x588800, 0x581800, 0x599800, 0x594800,
+ 0x598000, /* rest not used? */
+ };
+
+ /* unscramble bank number */
+ data = (((data>>14)&1)<<0) + (((data>> 6)&1)<<1) + (((data>> 8)&1)<<2) + (((data>>10)&1)<<3) + (((data>>12)&1)<<4) + (((data>> 5)&1)<<5);
+
+ int bankaddress = 0x100000 + bankoffset[data];
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress);
+}
+
+
+WRITE16_MEMBER( sma_prot_device::garou_bankswitch_w )
+{
+ /* thanks to Razoola and Mr K for the info */
+ static const int bankoffset[64] =
+ {
+ 0x000000, 0x100000, 0x200000, 0x300000, // 00
+ 0x280000, 0x380000, 0x2d0000, 0x3d0000, // 04
+ 0x2f0000, 0x3f0000, 0x400000, 0x500000, // 08
+ 0x420000, 0x520000, 0x440000, 0x540000, // 12
+ 0x498000, 0x598000, 0x4a0000, 0x5a0000, // 16
+ 0x4a8000, 0x5a8000, 0x4b0000, 0x5b0000, // 20
+ 0x4b8000, 0x5b8000, 0x4c0000, 0x5c0000, // 24
+ 0x4c8000, 0x5c8000, 0x4d0000, 0x5d0000, // 28
+ 0x458000, 0x558000, 0x460000, 0x560000, // 32
+ 0x468000, 0x568000, 0x470000, 0x570000, // 36
+ 0x478000, 0x578000, 0x480000, 0x580000, // 40
+ 0x488000, 0x588000, 0x490000, 0x590000, // 44
+ 0x5d0000, 0x5d8000, 0x5e0000, 0x5e8000, // 48
+ 0x5f0000, 0x5f8000, 0x600000, /* rest not used? */
+ };
+
+ /* unscramble bank number */
+ data = (((data>> 5)&1)<<0) + (((data>> 9)&1)<<1) + (((data>> 7)&1)<<2) + (((data>> 6)&1)<<3) + (((data>>14)&1)<<4) + (((data>>12)&1)<<5);
+
+ int bankaddress = 0x100000 + bankoffset[data];
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress);
+}
+
+
+WRITE16_MEMBER( sma_prot_device::garouh_bankswitch_w )
+{
+ /* thanks to Razoola and Mr K for the info */
+ static const int bankoffset[64] =
+ {
+ 0x000000, 0x100000, 0x200000, 0x300000, // 00
+ 0x280000, 0x380000, 0x2d0000, 0x3d0000, // 04
+ 0x2c8000, 0x3c8000, 0x400000, 0x500000, // 08
+ 0x420000, 0x520000, 0x440000, 0x540000, // 12
+ 0x598000, 0x698000, 0x5a0000, 0x6a0000, // 16
+ 0x5a8000, 0x6a8000, 0x5b0000, 0x6b0000, // 20
+ 0x5b8000, 0x6b8000, 0x5c0000, 0x6c0000, // 24
+ 0x5c8000, 0x6c8000, 0x5d0000, 0x6d0000, // 28
+ 0x458000, 0x558000, 0x460000, 0x560000, // 32
+ 0x468000, 0x568000, 0x470000, 0x570000, // 36
+ 0x478000, 0x578000, 0x480000, 0x580000, // 40
+ 0x488000, 0x588000, 0x490000, 0x590000, // 44
+ 0x5d8000, 0x6d8000, 0x5e0000, 0x6e0000, // 48
+ 0x5e8000, 0x6e8000, 0x6e8000, 0x000000, // 52
+ 0x000000, 0x000000, 0x000000, 0x000000, // 56
+ 0x000000, 0x000000, 0x000000, 0x000000, // 60
+ };
+
+ /* unscramble bank number */
+ data = (((data>> 4)&1)<<0) + (((data>> 8)&1)<<1) + (((data>>14)&1)<<2) + (((data>> 2)&1)<<3) + (((data>>11)&1)<<4) + (((data>>13)&1)<<5);
+
+ int bankaddress = 0x100000 + bankoffset[data];
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress);
+}
+
+
+WRITE16_MEMBER( sma_prot_device::mslug3_bankswitch_w )
+{
+ /* thanks to Razoola and Mr K for the info */
+ static const int bankoffset[64] =
+ {
+ 0x000000, 0x020000, 0x040000, 0x060000, // 00
+ 0x070000, 0x090000, 0x0b0000, 0x0d0000, // 04
+ 0x0e0000, 0x0f0000, 0x120000, 0x130000, // 08
+ 0x140000, 0x150000, 0x180000, 0x190000, // 12
+ 0x1a0000, 0x1b0000, 0x1e0000, 0x1f0000, // 16
+ 0x200000, 0x210000, 0x240000, 0x250000, // 20
+ 0x260000, 0x270000, 0x2a0000, 0x2b0000, // 24
+ 0x2c0000, 0x2d0000, 0x300000, 0x310000, // 28
+ 0x320000, 0x330000, 0x360000, 0x370000, // 32
+ 0x380000, 0x390000, 0x3c0000, 0x3d0000, // 36
+ 0x400000, 0x410000, 0x440000, 0x450000, // 40
+ 0x460000, 0x470000, 0x4a0000, 0x4b0000, // 44
+ 0x4c0000, /* rest not used? */
+ };
+
+ /* unscramble bank number */
+ data = (((data>>14)&1)<<0) + (((data>>12)&1)<<1) + (((data>>15)&1)<<2) + (((data>> 6)&1)<<3) + (((data>> 3)&1)<<4) + (((data>> 9)&1)<<5);
+
+ int bankaddress = 0x100000 + bankoffset[data];
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress);
+}
+
+
+WRITE16_MEMBER( sma_prot_device::kof2000_bankswitch_w )
+{
+ /* thanks to Razoola and Mr K for the info */
+ static const int bankoffset[64] =
+ {
+ 0x000000, 0x100000, 0x200000, 0x300000, // 00
+ 0x3f7800, 0x4f7800, 0x3ff800, 0x4ff800, // 04
+ 0x407800, 0x507800, 0x40f800, 0x50f800, // 08
+ 0x416800, 0x516800, 0x41d800, 0x51d800, // 12
+ 0x424000, 0x524000, 0x523800, 0x623800, // 16
+ 0x526000, 0x626000, 0x528000, 0x628000, // 20
+ 0x52a000, 0x62a000, 0x52b800, 0x62b800, // 24
+ 0x52d000, 0x62d000, 0x52e800, 0x62e800, // 28
+ 0x618000, 0x619000, 0x61a000, 0x61a800, // 32
+ };
+
+ /* unscramble bank number */
+ data = (((data>>15)&1)<<0) + (((data>>14)&1)<<1) + (((data>> 7)&1)<<2) + (((data>> 3)&1)<<3) + (((data>>10)&1)<<4) + (((data>> 5)&1)<<5);
+
+ int bankaddress = 0x100000 + bankoffset[data];
+ m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress);
+}
+
+
+READ16_MEMBER( sma_prot_device::prot_9a37_r )
+{
+ return 0x9a37;
+}
+
+
+/* information about the sma random number generator provided by razoola */
+/* this RNG is correct for KOF99, other games might be different */
+
+READ16_MEMBER( sma_prot_device::sma_random_r )
+{
+ uint16_t old = m_sma_rng;
+ uint16_t newbit = ((m_sma_rng >> 2) ^ (m_sma_rng >> 3) ^ (m_sma_rng >> 5) ^ (m_sma_rng >> 6) ^ (m_sma_rng >> 7) ^ (m_sma_rng >>11) ^ (m_sma_rng >>12) ^ (m_sma_rng >>15)) & 1;
+ m_sma_rng = (m_sma_rng << 1) | newbit;
+ return old;
+}
+
+
+void sma_prot_device::reset_sma_rng()
+{
+ m_sma_rng = 0x2345;
+}
+
+
+void sma_prot_device::sma_install_random_read_handler(cpu_device* maincpu, int addr1, int addr2 )
+{
+ maincpu->space(AS_PROGRAM).install_read_handler(addr1, addr1 + 1, read16_delegate(FUNC(sma_prot_device::sma_random_r),this));
+ maincpu->space(AS_PROGRAM).install_read_handler(addr2, addr2 + 1, read16_delegate(FUNC(sma_prot_device::sma_random_r),this));
+}
+
+
+void sma_prot_device::kof99_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev)
+{
+ maincpu->space(AS_PROGRAM).install_write_handler(0x2ffff0, 0x2ffff1, write16_delegate(FUNC(sma_prot_device::kof99_bankswitch_w),this));
+ maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this));
+ m_bankdev = bankdev;
+
+ sma_install_random_read_handler(maincpu, 0x2ffff8, 0x2ffffa);
+}
+
+
+void sma_prot_device::garou_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev)
+{
+ maincpu->space(AS_PROGRAM).install_write_handler(0x2fffc0, 0x2fffc1, write16_delegate(FUNC(sma_prot_device::garou_bankswitch_w),this));
+ maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this));
+ m_bankdev = bankdev;
+
+ sma_install_random_read_handler(maincpu, 0x2fffcc, 0x2ffff0);
+}
+
+
+void sma_prot_device::garouh_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev)
+{
+ maincpu->space(AS_PROGRAM).install_write_handler(0x2fffc0, 0x2fffc1, write16_delegate(FUNC(sma_prot_device::garouh_bankswitch_w),this));
+ maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this));
+ m_bankdev = bankdev;
+
+ sma_install_random_read_handler(maincpu, 0x2fffcc, 0x2ffff0);
+}
+
+
+void sma_prot_device::mslug3_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev)
+{
+ maincpu->space(AS_PROGRAM).install_write_handler(0x2fffe4, 0x2fffe5, write16_delegate(FUNC(sma_prot_device::mslug3_bankswitch_w),this));
+ maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this));
+ m_bankdev = bankdev;
+
+// sma_install_random_read_handler(maincpu, 0x2ffff8, 0x2ffffa);
+}
+
+
+void sma_prot_device::kof2000_install_protection(cpu_device* maincpu, neogeo_banked_cart_device* bankdev)
+{
+ maincpu->space(AS_PROGRAM).install_write_handler(0x2fffec, 0x2fffed, write16_delegate(FUNC(sma_prot_device::kof2000_bankswitch_w),this));
+ maincpu->space(AS_PROGRAM).install_read_handler(0x2fe446, 0x2fe447, read16_delegate(FUNC(sma_prot_device::prot_9a37_r),this));
+ m_bankdev = bankdev;
+
+ sma_install_random_read_handler(maincpu, 0x2fffd8, 0x2fffda);
+}
+
+
+
+/* kof99, garou, garouh, mslug3 and kof2000 have a SMA chip which contains program code and decrypts the 68k roms */
+void sma_prot_device::kof99_decrypt_68k(uint8_t* base)
+{
+ int i,j;
+ uint16_t *rom = (uint16_t *)(base + 0x100000);
+ /* swap data lines on the whole ROMs */
+ for (i = 0;i < 0x800000/2;i++)
+ rom[i] = bitswap<16>(rom[i],13,7,3,0,9,4,5,6,1,12,8,14,10,11,2,15);
+
+ /* swap address lines for the banked part */
+ for (i = 0;i < 0x600000/2;i+=0x800/2)
+ {
+ uint16_t buffer[0x800/2];
+ memcpy(buffer, &rom[i], 0x800);
+ for (j = 0; j < 0x800/2; j++)
+ rom[i+j] = buffer[bitswap<24>(j,23,22,21,20,19,18,17,16,15,14,13,12,11,10,6,2,4,9,8,3,1,7,0,5)];
+ }
+
+ /* swap address lines & relocate fixed part */
+ rom = (uint16_t *)base;
+ for (i = 0;i < 0x0c0000/2;i++)
+ rom[i] = rom[0x700000/2 + bitswap<24>(i,23,22,21,20,19,18,11,6,14,17,16,5,8,10,12,0,4,3,2,7,9,15,13,1)];
+}
+
+
+void sma_prot_device::garou_decrypt_68k(uint8_t* base)
+{
+ int i,j;
+
+ /* thanks to Razoola and Mr K for the info */
+ uint16_t *rom = (uint16_t *)(base + 0x100000);
+ /* swap data lines on the whole ROMs */
+ for (i = 0;i < 0x800000/2;i++)
+ rom[i] = bitswap<16>(rom[i],13,12,14,10,8,2,3,1,5,9,11,4,15,0,6,7);
+
+ /* swap address lines & relocate fixed part */
+ rom = (uint16_t *)base;
+ for (i = 0;i < 0x0c0000/2;i++)
+ rom[i] = rom[0x710000/2 + bitswap<24>(i,23,22,21,20,19,18,4,5,16,14,7,9,6,13,17,15,3,1,2,12,11,8,10,0)];
+
+ /* swap address lines for the banked part */
+ rom = (uint16_t *)(base + 0x100000);
+ for (i = 0;i < 0x800000/2;i+=0x8000/2)
+ {
+ uint16_t buffer[0x8000/2];
+ memcpy(buffer,&rom[i],0x8000);
+ for (j = 0;j < 0x8000/2;j++)
+ rom[i+j] = buffer[bitswap<24>(j,23,22,21,20,19,18,17,16,15,14,9,4,8,3,13,6,2,7,0,12,1,11,10,5)];
+ }
+}
+
+
+void sma_prot_device::garouh_decrypt_68k(uint8_t* base)
+{
+ int i,j;
+
+ /* thanks to Razoola and Mr K for the info */
+ uint16_t *rom = (uint16_t *)(base + 0x100000);
+ /* swap data lines on the whole ROMs */
+ for (i = 0;i < 0x800000/2;i++)
+ rom[i] = bitswap<16>(rom[i],14,5,1,11,7,4,10,15,3,12,8,13,0,2,9,6);
+
+ /* swap address lines & relocate fixed part */
+ rom = (uint16_t *)base;
+ for (i = 0;i < 0x0c0000/2;i++)
+ rom[i] = rom[0x7f8000/2 + bitswap<24>(i,23,22,21,20,19,18,5,16,11,2,6,7,17,3,12,8,14,4,0,9,1,10,15,13)];
+
+ /* swap address lines for the banked part */
+ rom = (uint16_t *)(base + 0x100000);
+ for (i = 0;i < 0x800000/2;i+=0x8000/2)
+ {
+ uint16_t buffer[0x8000/2];
+ memcpy(buffer,&rom[i],0x8000);
+ for (j = 0;j < 0x8000/2;j++)
+ rom[i+j] = buffer[bitswap<24>(j,23,22,21,20,19,18,17,16,15,14,12,8,1,7,11,3,13,10,6,9,5,4,0,2)];
+ }
+}
+
+
+void sma_prot_device::mslug3_decrypt_68k(uint8_t* base)
+{
+ int i,j;
+
+ /* thanks to Razoola and Mr K for the info */
+ uint16_t *rom = (uint16_t *)(base + 0x100000);
+ /* swap data lines on the whole ROMs */
+ for (i = 0;i < 0x800000/2;i++)
+ rom[i] = bitswap<16>(rom[i],4,11,14,3,1,13,0,7,2,8,12,15,10,9,5,6);
+
+ /* swap address lines & relocate fixed part */
+ rom = (uint16_t *)base;
+ for (i = 0;i < 0x0c0000/2;i++)
+ rom[i] = rom[0x5d0000/2 + bitswap<24>(i,23,22,21,20,19,18,15,2,1,13,3,0,9,6,16,4,11,5,7,12,17,14,10,8)];
+
+ /* swap address lines for the banked part */
+ rom = (uint16_t *)(base + 0x100000);
+ for (i = 0;i < 0x800000/2;i+=0x10000/2)
+ {
+ uint16_t buffer[0x10000/2];
+ memcpy(buffer,&rom[i],0x10000);
+ for (j = 0;j < 0x10000/2;j++)
+ rom[i+j] = buffer[bitswap<24>(j,23,22,21,20,19,18,17,16,15,2,11,0,14,6,4,13,8,9,3,10,7,5,12,1)];
+ }
+}
+
+
+void sma_prot_device::kof2000_decrypt_68k(uint8_t* base)
+{
+ int i,j;
+
+ /* thanks to Razoola and Mr K for the info */
+ uint16_t *rom = (uint16_t *)(base + 0x100000);
+ /* swap data lines on the whole ROMs */
+ for (i = 0;i < 0x800000/2;i++)
+ rom[i] = bitswap<16>(rom[i],12,8,11,3,15,14,7,0,10,13,6,5,9,2,1,4);
+
+ /* swap address lines for the banked part */
+ for (i = 0;i < 0x63a000/2;i+=0x800/2)
+ {
+ uint16_t buffer[0x800/2];
+ memcpy(buffer,&rom[i],0x800);
+ for (j = 0;j < 0x800/2;j++)
+ rom[i+j] = buffer[bitswap<24>(j,23,22,21,20,19,18,17,16,15,14,13,12,11,10,4,1,3,8,6,2,7,0,9,5)];
+ }
+
+ /* swap address lines & relocate fixed part */
+ rom = (uint16_t *)base;
+ for (i = 0;i < 0x0c0000/2;i++)
+ rom[i] = rom[0x73a000/2 + bitswap<24>(i,23,22,21,20,19,18,8,4,15,13,3,14,16,2,6,17,7,12,10,0,5,11,1,9)];
+}
+
+// From here are not sma decrypts, it's a convenient place to store them **************************************************
+
+
+/* ms5pcb and svcpcb have an additional scramble on top of the standard CMC scrambling */
+void sma_prot_device::svcpcb_gfx_decrypt(uint8_t* rom, uint32_t rom_size)
+{
+ static const uint8_t xorval[ 4 ] = { 0x34, 0x21, 0xc4, 0xe9 };
+ int i, ofst;
+ std::vector<uint8_t> buf( rom_size );
+
+ for( i = 0; i < rom_size; i++ )
+ rom[ i ] ^= xorval[ (i % 4) ];
+
+ for( i = 0; i < rom_size; i += 4 )
+ {
+ uint32_t rom32 = rom[i] | rom[i+1]<<8 | rom[i+2]<<16 | rom[i+3]<<24;
+ rom32 = bitswap<32>( rom32, 0x09, 0x0d, 0x13, 0x00, 0x17, 0x0f, 0x03, 0x05, 0x04, 0x0c, 0x11, 0x1e, 0x12,
+ 0x15, 0x0b, 0x06, 0x1b, 0x0a, 0x1a, 0x1c, 0x14, 0x02, 0x0e, 0x1d, 0x18, 0x08, 0x01, 0x10, 0x19, 0x1f, 0x07, 0x16 );
+ buf[i] = rom32 & 0xff;
+ buf[i+1] = (rom32>>8) & 0xff;
+ buf[i+2] = (rom32>>16) & 0xff;
+ buf[i+3] = (rom32>>24) & 0xff;
+ }
+
+ for( i = 0; i < rom_size / 4; i++ )
+ {
+ ofst = bitswap<24>( (i & 0x1fffff), 0x17, 0x16, 0x15, 0x04, 0x0b, 0x0e, 0x08, 0x0c, 0x10, 0x00, 0x0a, 0x13,
+ 0x03, 0x06, 0x02, 0x07, 0x0d, 0x01, 0x11, 0x09, 0x14, 0x0f, 0x12, 0x05 );
+ ofst ^= 0x0c8923;
+ ofst += (i & 0xffe00000);
+ memcpy( &rom[ i * 4 ], &buf[ ofst * 4 ], 0x04 );
+ }
+}
+
+
+/* and a further swap on the s1 data */
+void sma_prot_device::svcpcb_s1data_decrypt(uint8_t* rom, uint32_t rom_size)
+{
+ for( int i = 0; i < rom_size; i++ ) // Decrypt S
+ rom[ i ] = bitswap<8>( rom[ i ] ^ 0xd2, 4, 0, 7, 2, 5, 1, 6, 3 );
+}
+
+
+/* kf2k3pcb has an additional scramble on top of the standard CMC scrambling */
+/* Thanks to Razoola & Halrin for the info */
+void sma_prot_device::kf2k3pcb_gfx_decrypt(uint8_t* rom, uint32_t rom_size)
+{
+ const uint8_t xorval[ 4 ] = { 0x34, 0x21, 0xc4, 0xe9 };
+ int i, ofst;
+ std::vector<uint8_t> buf( rom_size );
+
+ for ( i = 0; i < rom_size; i++ )
+ rom[ i ] ^= xorval[ (i % 4) ];
+
+ for ( i = 0; i < rom_size; i +=4 )
+ {
+ uint32_t rom32 = rom[i] | rom[i+1]<<8 | rom[i+2]<<16 | rom[i+3]<<24;
+ rom32 = bitswap<32>( rom32, 0x09, 0x0d, 0x13, 0x00, 0x17, 0x0f, 0x03, 0x05, 0x04, 0x0c, 0x11, 0x1e, 0x12,
+ 0x15, 0x0b, 0x06, 0x1b, 0x0a, 0x1a, 0x1c, 0x14, 0x02, 0x0e, 0x1d, 0x18, 0x08, 0x01, 0x10, 0x19, 0x1f, 0x07, 0x16 );
+ buf[i] = rom32 & 0xff;
+ buf[i+1] = (rom32>>8) & 0xff;
+ buf[i+2] = (rom32>>16) & 0xff;
+ buf[i+3] = (rom32>>24) & 0xff;
+ }
+
+ for ( i = 0; i < rom_size; i+=4 )
+ {
+ ofst = bitswap<24>( (i & 0x7fffff), 0x17, 0x15, 0x0a, 0x14, 0x13, 0x16, 0x12, 0x11, 0x10, 0x0f, 0x0e, 0x0d,
+ 0x0c, 0x0b, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 );
+ ofst += (i & 0xff800000);
+ memcpy( &rom[ ofst ], &buf[ i ], 0x04 );
+ }
+}
+
+
+/* and a further swap on the s1 data */
+void sma_prot_device::kf2k3pcb_decrypt_s1data(uint8_t* rom, uint32_t rom_size, uint8_t* fixed, uint32_t fixed_size)
+{
+ uint8_t *src;
+ uint8_t *dst;
+ int i;
+
+ src = rom + rom_size - 0x1000000 - 0x80000; // Decrypt S
+
+ for( i = 0; i < fixed_size / 2; i++ )
+ fixed[ i ] = src[ (i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4) ];
+
+ src = rom + rom_size - 0x80000;
+ dst = fixed + 0x80000;
+
+ for( i = 0; i < fixed_size / 2; i++ )
+ dst[ i ] = src[ (i & ~0x1f) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4) ];
+
+ for( i = 0; i < fixed_size; i++ )
+ fixed[ i ] = bitswap<8>( fixed[ i ] ^ 0xd2, 4, 0, 7, 2, 5, 1, 6, 3 );
+}
+
+
+/***************************************************************************
+
+NeoGeo 'SP1' (BIOS) ROM encryption
+
+***************************************************************************/
+
+
+/* only found on kf2k3pcb */
+void sma_prot_device::kf2k3pcb_sp1_decrypt(uint16_t* rom)
+{
+ static const uint8_t address[0x40] = {
+ 0x04,0x0a,0x04,0x0a,0x04,0x0a,0x04,0x0a,
+ 0x0a,0x04,0x0a,0x04,0x0a,0x04,0x0a,0x04,
+ 0x09,0x07,0x09,0x07,0x09,0x07,0x09,0x07,
+ 0x09,0x09,0x04,0x04,0x09,0x09,0x04,0x04,
+ 0x0b,0x0d,0x0b,0x0d,0x03,0x05,0x03,0x05,
+ 0x0e,0x0e,0x03,0x03,0x0e,0x0e,0x03,0x03,
+ 0x03,0x05,0x0b,0x0d,0x03,0x05,0x0b,0x0d,
+ 0x04,0x00,0x04,0x00,0x0e,0x0a,0x0e,0x0a
+ };
+
+ std::vector<uint16_t> buf(0x80000/2);
+ int i, addr;
+
+ for (i = 0; i < 0x80000/2; i++)
+ {
+ // address xor
+ addr = i ^ 0x0020;
+ if ( i & 0x00020) addr ^= 0x0010;
+ if (~i & 0x00010) addr ^= 0x0040;
+ if (~i & 0x00004) addr ^= 0x0080;
+ if ( i & 0x00200) addr ^= 0x0100;
+ if (~i & 0x02000) addr ^= 0x0400;
+ if (~i & 0x10000) addr ^= 0x1000;
+ if ( i & 0x02000) addr ^= 0x8000;
+ addr ^= address[((i >> 1) & 0x38) | (i & 7)];
+ buf[i] = rom[addr];
+
+ // data xor
+ if (buf[i] & 0x0004) buf[i] ^= 0x0001;
+ if (buf[i] & 0x0010) buf[i] ^= 0x0002;
+ if (buf[i] & 0x0020) buf[i] ^= 0x0008;
+ }
+
+ memcpy(rom, &buf[0], 0x80000);
+}