/*************************************************************************** Neo-Geo hardware Many of the NeoGeo bootlegs use their own form of encryption and protection, presumably to make them harder for other bootleggser to copy. This encryption often involves non-trivial scrambling of the program roms and the games are protected using an Altera chip which provides some kind of rom overlay, patching parts of the code. The graphics roms are usually scrambled in a different way to the official SNK cartridges too. ***************************************************************************/ #include "driver.h" #include "neogeo.h" /* General Bootleg Functions - used by more than 1 game */ void neogeo_bootleg_cx_decrypt( void ) { int i; int cx_size = memory_region_length( NEOGEO_REGION_SPRITES ); UINT8 *rom = memory_region( NEOGEO_REGION_SPRITES ); UINT8 *buf = malloc_or_die( cx_size ); memcpy( buf, rom, cx_size ); for( i = 0; i < cx_size / 0x40; i++ ){ memcpy( &rom[ i * 0x40 ], &buf[ (i ^ 1) * 0x40 ], 0x40 ); } free( buf ); } void neogeo_bootleg_sx_decrypt( int value ) { int sx_size = memory_region_length( NEOGEO_REGION_FIXED_LAYER_CARTRIDGE ); UINT8 *rom = memory_region( NEOGEO_REGION_FIXED_LAYER_CARTRIDGE ); int i; if (value == 1) { UINT8 *buf = malloc_or_die( sx_size ); memcpy( buf, 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 ); } free( buf ); } else if (value == 2) { for( i = 0; i < sx_size; i++ ) rom[ i ] = BITSWAP8( rom[ i ], 7, 6, 0, 4, 3, 2, 1, 5 ); } } /* The King of Gladiator (The King of Fighters '97 bootleg) */ /* the protection patching here may be incomplete */ // Thanks to Razoola for the info void kog_px_decrypt( void ) { /* the protection chip does some *very* strange things to the rom */ UINT8 *src = memory_region(NEOGEO_REGION_MAIN_CPU_CARTRIDGE); UINT8 *dst = malloc_or_die( 0x600000 ); UINT16 *rom = (UINT16 *)memory_region(NEOGEO_REGION_MAIN_CPU_CARTRIDGE); 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, 0x600000); free (dst); 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; } /* Kof 10th Anniversary (bootleg of King of Fighters 2002 */ /* 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 */ static UINT16 kof10thExtraRAMB[0x01000]; static void kof10thBankswitch(UINT16 nBank) { UINT32 bank = 0x100000 + ((nBank & 7) << 20); if (bank >= 0x700000) bank = 0x100000; neogeo_set_main_cpu_bank_address(bank); } READ16_HANDLER( kof10th_RAMB_r ) { return kof10thExtraRAMB[offset]; } WRITE16_HANDLER( kof10th_custom_w ) { if (!kof10thExtraRAMB[0xFFE]) { // Write to RAM bank A UINT16 *prom = (UINT16*)memory_region( NEOGEO_REGION_MAIN_CPU_CARTRIDGE ); COMBINE_DATA(&prom[(0xE0000/2) + (offset & 0xFFFF)]); } else { // Write S data on-the-fly UINT8 *srom = memory_region( NEOGEO_REGION_FIXED_LAYER_CARTRIDGE ); srom[offset] = BITSWAP8(data,7,6,0,4,3,2,1,5); } } static WRITE16_HANDLER( kof10th_bankswitch_w ) { if (offset >= 0x5F000) { if (offset == 0x5FFF8) { // Standard bankswitch kof10thBankswitch(data); } else if (offset == 0x5FFFC && kof10thExtraRAMB[0xFFC] != data) { // Special bankswitch UINT8 *src = memory_region( NEOGEO_REGION_MAIN_CPU_CARTRIDGE ); memcpy (src + 0x10000, src + ((data & 1) ? 0x810000 : 0x710000), 0xcffff); } COMBINE_DATA(&kof10thExtraRAMB[offset & 0xFFF]); } } void install_kof10th_protection ( void ) { memory_install_read16_handler(0, ADDRESS_SPACE_PROGRAM, 0x2fe000, 0x2fffff, 0, 0, kof10th_RAMB_r); memory_install_write16_handler(0, ADDRESS_SPACE_PROGRAM, 0x200000, 0x23ffff, 0, 0, kof10th_custom_w); memory_install_write16_handler(0, ADDRESS_SPACE_PROGRAM, 0x240000, 0x2fffff, 0, 0, kof10th_bankswitch_w); } void decrypt_kof10th( void ) { int i, j; UINT8 *dst = malloc_or_die(0x900000); UINT8 *src = memory_region( NEOGEO_REGION_MAIN_CPU_CARTRIDGE ); memcpy(dst + 0x000000, src + 0x700000, 0x100000); // Correct (Verified in Uni-bios) memcpy(dst + 0x100000, src + 0x000000, 0x800000); for (i = 0; i < 0x900000; i++) { j = BITSWAP24(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]; } free(dst); // Altera protection chip patches these over P ROM ((UINT16*)src)[0x0124/2] = 0x000d; // Enables XOR for RAM moves, forces SoftDIPs, and USA region ((UINT16*)src)[0x0126/2] = 0xf7a8; ((UINT16*)src)[0x8bf4/2] = 0x4ef9; // Run code to change "S" data ((UINT16*)src)[0x8bf6/2] = 0x000d; ((UINT16*)src)[0x8bf8/2] = 0xf980; } void decrypt_kf10thep(void) { int i; UINT16 *rom = (UINT16*)memory_region(NEOGEO_REGION_MAIN_CPU_CARTRIDGE); UINT8 *src = memory_region(NEOGEO_REGION_MAIN_CPU_CARTRIDGE); UINT16 *buf = (UINT16*)memory_region(NEOGEO_REGION_AUDIO_CPU_ENCRYPTED); UINT8 *srom = (UINT8*)memory_region(NEOGEO_REGION_FIXED_LAYER_CARTRIDGE); UINT8 *sbuf = malloc_or_die(0x20000); UINT8 *dst = malloc_or_die(0x200000); memcpy(dst,buf,0x200000); memcpy(src+0x000000,dst+0x060000,0x20000); memcpy(src+0x020000,dst+0x100000,0x20000); memcpy(src+0x040000,dst+0x0e0000,0x20000); memcpy(src+0x060000,dst+0x180000,0x20000); memcpy(src+0x080000,dst+0x020000,0x20000); memcpy(src+0x0a0000,dst+0x140000,0x20000); memcpy(src+0x0c0000,dst+0x0c0000,0x20000); memcpy(src+0x0e0000,dst+0x1a0000,0x20000); memcpy(src+0x0002e0,dst+0x0402e0,0x6a); // copy banked code to a new memory region memcpy(src+0x0f92bc,dst+0x0492bc,0xb9e); // copy banked code to a new memory region for (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; free(dst); for (i=0;i<0x20000;i++) sbuf[i]=srom[i^0x8]; memcpy(srom,sbuf,0x20000); free(sbuf); } static void kf2k5uni_px_decrypt( void ) { int i, j, ofst; UINT8 *src = memory_region( NEOGEO_REGION_MAIN_CPU_CARTRIDGE ); UINT8 *dst = malloc_or_die(0x80); for (i = 0; i < 0x800000; i+=0x80) { for (j = 0; j < 0x80; j+=2) { ofst = BITSWAP8(j, 0, 3, 4, 5, 6, 1, 2, 7); memcpy(dst + j, src + i + ofst, 2); } memcpy(src + i, dst, 0x80); } free(dst); memcpy(src, src + 0x600000, 0x100000); // Seems to be the same as kof10th } static void kf2k5uni_sx_decrypt( void ) { int i; UINT8 *srom = memory_region( NEOGEO_REGION_FIXED_LAYER_CARTRIDGE ); for (i = 0; i < 0x20000; i++) srom[i] = BITSWAP8(srom[i], 4, 5, 6, 7, 0, 1, 2, 3); } static void kf2k5uni_mx_decrypt( void ) { int i; UINT8 *mrom = memory_region( NEOGEO_REGION_AUDIO_CPU_CARTRIDGE ); for (i = 0; i < 0x30000; i++) mrom[i] = BITSWAP8(mrom[i], 4, 5, 6, 7, 0, 1, 2, 3); } void decrypt_kf2k5uni(void) { kf2k5uni_px_decrypt(); kf2k5uni_sx_decrypt(); kf2k5uni_mx_decrypt(); } /* Kof2002 Magic Plus */ void kf2k2mp_decrypt( void ) { int i,j; UINT8 *src = memory_region(NEOGEO_REGION_MAIN_CPU_CARTRIDGE); UINT8 *dst = malloc_or_die(0x80); memmove(src, src + 0x300000, 0x500000); for (i = 0; i < 0x800000; i+=0x80) { for (j = 0; j < 0x80 / 2; j++) { int ofst = BITSWAP8( j, 6, 7, 2, 3, 4, 5, 0, 1 ); memcpy(dst + j * 2, src + i + ofst * 2, 2); } memcpy(src + i, dst, 0x80); } free(dst); } /* Kof2002 Magic Plus 2 */ void kof2km2_px_decrypt( void ) { UINT8 *src = memory_region(NEOGEO_REGION_MAIN_CPU_CARTRIDGE); UINT8 *dst = malloc_or_die(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); free (dst); } /* Crouching Tiger Hidden Dragon 2003 (bootleg of King of Fighters 2001) */ /* descrambling information from razoola */ static void cthd2003_neogeo_gfx_address_fix_do(int start, int end, int bit3shift, int bit2shift, int bit1shift, int bit0shift) { int i,j; int tilesize=128; UINT8* rom = malloc_or_die(16*tilesize); // 16 tiles buffer UINT8* realrom = memory_region(NEOGEO_REGION_SPRITES) + start*tilesize; for (i = 0; i < (end-start)/16; i++) { for (j = 0; j < 16; j++) { int offset = (((j&1)>>0)<>1)<>2)<>3)<