// license:BSD-3-Clause // copyright-holders:S. Smith,David Haywood,Fabio Priuli #include "emu.h" #include "prot_pvc.h" DEFINE_DEVICE_TYPE(NG_PVC_PROT, pvc_prot_device, "ng_pvc_prot", "Neo Geo PVC Protection") pvc_prot_device::pvc_prot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, NG_PVC_PROT, tag, owner, clock) { } void pvc_prot_device::device_start() { save_item(NAME(m_cart_ram)); } void pvc_prot_device::device_reset() { } /************************ PVC Protection *********************** mslug5, svcchaos, kof2003 ***************************************************************/ void pvc_prot_device::pvc_write_unpack_color() { uint16_t pen = m_cart_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_cart_ram[0xff1] = (g << 8) | b; m_cart_ram[0xff2] = (s << 8) | r; } void pvc_prot_device::pvc_write_pack_color() { uint16_t gb = m_cart_ram[0xff4]; uint16_t sr = m_cart_ram[0xff5]; m_cart_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() { uint32_t bankaddress = ((m_cart_ram[0xff8] >> 8)|(m_cart_ram[0xff9] << 8)); m_cart_ram[0xff8] = (m_cart_ram[0xff8] & 0xfe00) | 0x00a0; m_cart_ram[0xff9] &= 0x7fff; m_bankdev->neogeo_set_main_cpu_bank_address(bankaddress + 0x100000); } */ uint32_t pvc_prot_device::get_bank_base() { uint32_t bankaddress = ((m_cart_ram[0xff8] >> 8)|(m_cart_ram[0xff9] << 8)); m_cart_ram[0xff8] = (m_cart_ram[0xff8] & 0xfe00) | 0x00a0; m_cart_ram[0xff9] &= 0x7fff; return bankaddress + 0x100000; } uint16_t pvc_prot_device::protection_r(offs_t offset) { return m_cart_ram[offset]; } void pvc_prot_device::protection_w(offs_t offset, uint16_t data, uint16_t mem_mask) { COMBINE_DATA(&m_cart_ram[offset]); if (offset == 0xff0) pvc_write_unpack_color(); else if (offset >= 0xff4 && offset <= 0xff5) pvc_write_pack_color(); // FIXME: temporarily moved to the driver, through get_bank_base() above // else if(offset >= 0xff8) // pvc_write_bankswitch(space); } /* 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 rom_size = 0x800000; std::vector buf(rom_size); for (int i = 0; i < 0x100000; i++) rom[i] ^= xor1[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x800000; i++) rom[i] ^= xor2[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x0800000; i += 4) { uint16_t 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 (int i = 0; i < 0x0100000 / 0x10000; i++) { int ofst = (i & 0xf0) + bitswap<8>((i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2); memcpy(&rom[i * 0x10000], &buf[ofst * 0x10000], 0x10000); } for (int i = 0x100000; i < 0x800000; i += 0x100) { int 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 rom_size = 0x800000; std::vector buf(rom_size); for (int i = 0; i < 0x100000; i++) rom[i] ^= xor1[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x800000; i++) rom[i] ^= xor2[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x0800000; i += 4) { uint16_t 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 (int i = 0; i < 0x0100000 / 0x10000; i++) { int ofst = (i & 0xf0) + bitswap<8>((i & 0x0f), 7, 6, 5, 4, 2, 3, 0, 1); memcpy(&rom[i * 0x10000], &buf[ofst * 0x10000], 0x10000); } for (int i = 0x100000; i < 0x800000; i += 0x100) { int 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 rom_size = 0x900000; std::vector buf(rom_size); for (int i = 0; i < 0x100000; i++) rom[0x800000 + i] ^= rom[0x100002 | i]; for (int i = 0x100000; i < 0x800000; i++) rom[i] ^= xor2[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x800000; i += 4) { uint16_t 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 (int i = 0; i < 0x0100000 / 0x10000; i++) { int ofst = (i & 0xf0) + bitswap<8>((i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2); memcpy(&buf[i * 0x10000], &rom[ofst * 0x10000], 0x10000); } for (int i = 0x100000; i < 0x900000; i += 0x100) { int 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 rom_size = 0x900000; std::vector buf(rom_size); for (int i = 0; i < 0x100000; i++) rom[0x800000 + i] ^= rom[0x100002 | i]; for (int i = 0; i < 0x100000; i++) rom[i] ^= xor1[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x800000; i++) rom[i] ^= xor2[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x800000; i += 4) { uint16_t 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 (int i = 0; i < 0x0100000 / 0x10000; i++) { int ofst = (i & 0xf0) + bitswap<8>((i & 0x0f), 7, 6, 5, 4, 0, 1, 2, 3); memcpy(&buf[i * 0x10000], &rom[ofst * 0x10000], 0x10000); } for (int i = 0x100000; i < 0x900000; i += 0x100) { int 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 rom_size = 0x900000; std::vector buf(rom_size); for (int i = 0; i < 0x100000; i++) rom[0x800000 + i] ^= rom[0x100002 | i]; for (int i = 0; i < 0x100000; i++) rom[i] ^= xor1[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x800000; i++) rom[i] ^= xor2[(BYTE_XOR_LE(i) % 0x20)]; for (int i = 0x100000; i < 0x800000; i += 4) { uint16_t 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 (int i = 0; i < 0x0100000 / 0x10000; i++) { int ofst = (i & 0xf0) + bitswap<8>((i & 0x0f), 7, 6, 5, 4, 1, 0, 3, 2); memcpy(&buf[i * 0x10000], &rom[ofst * 0x10000], 0x10000); } for (int i = 0x100000; i < 0x900000; i += 0x100) { int 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); }