From e5628609f49e23552bee00d7a98a4ca0aa0a4fb6 Mon Sep 17 00:00:00 2001 From: andreasnaive Date: Sat, 1 Aug 2015 17:27:36 +0200 Subject: [PATCH] Preliminary decryption support for Namco System 10 [Andreas Naive] --- scripts/target/mame/arcade.lua | 1 + src/mame/drivers/namcos10.c | 107 +++++++++++------ src/mame/machine/ns10crypt.c | 214 +++++++++++++++++++++++++++++++++ src/mame/machine/ns10crypt.h | 62 ++++++++++ 4 files changed, 349 insertions(+), 35 deletions(-) create mode 100644 src/mame/machine/ns10crypt.c create mode 100644 src/mame/machine/ns10crypt.h diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua index b76800949af..2a275b53214 100644 --- a/scripts/target/mame/arcade.lua +++ b/scripts/target/mame/arcade.lua @@ -2085,6 +2085,7 @@ files { MAME_DIR .. "src/mame/machine/namcos1.c", MAME_DIR .. "src/mame/video/namcos1.c", MAME_DIR .. "src/mame/drivers/namcos10.c", + MAME_DIR .. "src/mame/machine/ns10crypt.c", MAME_DIR .. "src/mame/drivers/namcos11.c", MAME_DIR .. "src/mame/machine/ns11prot.c", MAME_DIR .. "src/mame/drivers/namcos12.c", diff --git a/src/mame/drivers/namcos10.c b/src/mame/drivers/namcos10.c index a101c02bf40..adbc50d5029 100644 --- a/src/mame/drivers/namcos10.c +++ b/src/mame/drivers/namcos10.c @@ -269,6 +269,7 @@ Kono Tako 10021 Ver.A KC034A 8E, 8D #include "emu.h" #include "cpu/psx/psx.h" #include "video/psx.h" +#include "machine/ns10crypt.h" class namcos10_state : public driver_device { @@ -283,7 +284,8 @@ public: DECLARE_WRITE16_MEMBER(bank_w); // memn variant interface - DECLARE_READ16_MEMBER (nand_status_r); + DECLARE_WRITE16_MEMBER(crypto_switch_w); + DECLARE_READ16_MEMBER(nand_status_r); DECLARE_WRITE8_MEMBER(nand_address1_w); DECLARE_WRITE8_MEMBER(nand_address2_w); DECLARE_WRITE8_MEMBER(nand_address3_w); @@ -301,6 +303,7 @@ private: UINT32 bank_base; UINT32 nand_address; UINT16 block[0x1ff]; + ns10_decrypter_device* decrypter; UINT16 nand_read( UINT32 address ); UINT16 nand_read2( UINT32 address ); @@ -401,6 +404,14 @@ ADDRESS_MAP_END // Block access to the nand. Something strange is going on with the // status port. Interaction with the decryption is unclear at best. +WRITE16_MEMBER(namcos10_state::crypto_switch_w) +{ + if (BIT(data, 15) != 0) + decrypter->activate(); + else + decrypter->deactivate(); +} + READ16_MEMBER(namcos10_state::nand_status_r ) { return 0; @@ -451,7 +462,10 @@ READ16_MEMBER( namcos10_state::nand_data_r ) /* printf( "data<-%08x (%08x)\n", data, nand_address ); */ nand_address++; - return data; + if (decrypter->is_active()) + return decrypter->decrypt(data); + else + return data; } void namcos10_state::nand_copy( UINT32 *dst, UINT32 address, int len ) @@ -475,8 +489,7 @@ READ16_MEMBER(namcos10_state::nand_block_r) } static ADDRESS_MAP_START( namcos10_memn_map, AS_PROGRAM, 32, namcos10_state ) - AM_RANGE(0x1f300000, 0x1f300003) AM_WRITE16(key_w, 0x0000ffff) - + AM_RANGE(0x1f300000, 0x1f300003) AM_WRITE16(crypto_switch_w, 0x0000ffff) AM_RANGE(0x1f400000, 0x1f400003) AM_READ16(nand_status_r, 0x0000ffff) AM_RANGE(0x1f410000, 0x1f410003) AM_WRITE8(nand_address1_w, 0x000000ff) AM_RANGE(0x1f420000, 0x1f420003) AM_WRITE8(nand_address2_w, 0x000000ff) @@ -492,17 +505,18 @@ void namcos10_state::memn_driver_init( ) { UINT8 *BIOS = (UINT8 *)memregion( "maincpu:rom" )->base(); nand_base = (UINT8 *)memregion( "user2" )->base(); + decrypter = static_cast(machine().root_device().subdevice("decrypter")); nand_copy( (UINT32 *)( BIOS + 0x0000000 ), 0x08000, 0x001c000 ); nand_copy( (UINT32 *)( BIOS + 0x0020000 ), 0x24000, 0x03e0000 ); } -static void decrypt_bios( running_machine &machine, const char *regionName, int start, int b15, int b14, int b13, int b12, int b11, int b10, int b9, int b8, +static void decrypt_bios( running_machine &machine, const char *regionName, int start, int end, int b15, int b14, int b13, int b12, int b11, int b10, int b9, int b8, int b7, int b6, int b5, int b4, int b3, int b2, int b1, int b0 ) { memory_region *region = machine.root_device().memregion( regionName ); UINT16 *BIOS = (UINT16 *)( region->base() + start ); - int len = (region->bytes()-start)/2; + int len = (end - start) / 2; for( int i = 0; i < len; i++ ) { @@ -513,66 +527,77 @@ static void decrypt_bios( running_machine &machine, const char *regionName, int DRIVER_INIT_MEMBER(namcos10_state,mrdrilr2) { - decrypt_bios( machine(), "maincpu:rom", 0, 0xc, 0xd, 0xf, 0xe, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x4, 0x1, 0x2, 0x5, 0x0, 0x3 ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "maincpu:rom", 0, regSize, 0xc, 0xd, 0xf, 0xe, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x4, 0x1, 0x2, 0x5, 0x0, 0x3); } DRIVER_INIT_MEMBER(namcos10_state,gjspace) { - decrypt_bios( machine(), "user2", 0x8400, 0x0, 0x2, 0xe, 0xd, 0xf, 0x6, 0xc, 0x7, 0x5, 0x1, 0x9, 0x8, 0xa, 0x3, 0x4, 0xb ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "user2", 0x8400, regSize, 0x0, 0x2, 0xe, 0xd, 0xf, 0x6, 0xc, 0x7, 0x5, 0x1, 0x9, 0x8, 0xa, 0x3, 0x4, 0xb); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,mrdrilrg) { - decrypt_bios( machine(), "user2", 0x8400, 0x6, 0x4, 0x7, 0x5, 0x2, 0x1, 0x0, 0x3, 0xc, 0xd, 0xe, 0xf, 0x8, 0x9, 0xb, 0xa ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "user2", 0x8400, regSize, 0x6, 0x4, 0x7, 0x5, 0x2, 0x1, 0x0, 0x3, 0xc, 0xd, 0xe, 0xf, 0x8, 0x9, 0xb, 0xa); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,knpuzzle) { - decrypt_bios( machine(), "user2", 0x8400, 0x6, 0x7, 0x4, 0x5, 0x2, 0x0, 0x3, 0x1, 0xc, 0xd, 0xe, 0xf, 0x9, 0xb, 0x8, 0xa ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "user2", 0x8400, regSize, 0x6, 0x7, 0x4, 0x5, 0x2, 0x0, 0x3, 0x1, 0xc, 0xd, 0xe, 0xf, 0x9, 0xb, 0x8, 0xa); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,startrgn) { - decrypt_bios( machine(), "user2", 0x8400, 0x6, 0x5, 0x4, 0x7, 0x1, 0x3, 0x0, 0x2, 0xc, 0xd, 0xe, 0xf, 0x8, 0xb, 0xa, 0x9 ); + decrypt_bios(machine(), "user2", 0x008400, 0x028000, 0x6, 0x5, 0x4, 0x7, 0x1, 0x3, 0x0, 0x2, 0xc, 0xd, 0xe, 0xf, 0x8, 0xb, 0xa, 0x9); + decrypt_bios(machine(), "user2", 0x0b4000, 0xfdc000, 0x6, 0x5, 0x4, 0x7, 0x1, 0x3, 0x0, 0x2, 0xc, 0xd, 0xe, 0xf, 0x8, 0xb, 0xa, 0x9); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,gamshara) { - decrypt_bios( machine(), "user2", 0x8400, 0x5, 0x4, 0x7, 0x6, 0x0, 0x1, 0x3, 0x2, 0xd, 0xf, 0xc, 0xe, 0x8, 0x9, 0xa, 0xb ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "user2", 0x8400, regSize, 0x5, 0x4, 0x7, 0x6, 0x0, 0x1, 0x3, 0x2, 0xd, 0xf, 0xc, 0xe, 0x8, 0x9, 0xa, 0xb); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,gunbalna) { - decrypt_bios( machine(), "user2", 0x8400, 0x5, 0x4, 0x7, 0x6, 0x0, 0x1, 0x3, 0x2, 0xd, 0xf, 0xc, 0xe, 0x9, 0x8, 0xa, 0xb ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "user2", 0x8400, regSize, 0x5, 0x4, 0x7, 0x6, 0x0, 0x1, 0x3, 0x2, 0xd, 0xf, 0xc, 0xe, 0x9, 0x8, 0xa, 0xb); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,chocovdr) { - decrypt_bios( machine(), "user2", 0x8400, 0x5, 0x4, 0x6, 0x7, 0x1, 0x0, 0x2, 0x3, 0xc, 0xf, 0xe, 0xd, 0x8, 0xb, 0xa, 0x9 ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "user2", 0x8400, regSize, 0x5, 0x4, 0x6, 0x7, 0x1, 0x0, 0x2, 0x3, 0xc, 0xf, 0xe, 0xd, 0x8, 0xb, 0xa, 0x9); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,panikuru) { - decrypt_bios( machine(), "user2", 0x8400, 0x6, 0x4, 0x7, 0x5, 0x0, 0x1, 0x2, 0x3, 0xc, 0xf, 0xe, 0xd, 0x9, 0x8, 0xb, 0xa ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "user2", 0x8400, regSize, 0x6, 0x4, 0x7, 0x5, 0x0, 0x1, 0x2, 0x3, 0xc, 0xf, 0xe, 0xd, 0x9, 0x8, 0xb, 0xa); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,nflclsfb) { - decrypt_bios( machine(), "user2", 0x8400, 0x6, 0x5, 0x4, 0x7, 0x1, 0x3, 0x0, 0x2, 0xc, 0xd, 0xe, 0xf, 0x8, 0xb, 0xa, 0x9 ); + int regSize = machine().root_device().memregion("user2")->bytes(); + decrypt_bios(machine(), "user2", 0x8400, regSize, 0x6, 0x5, 0x4, 0x7, 0x1, 0x3, 0x0, 0x2, 0xc, 0xd, 0xe, 0xf, 0x8, 0xb, 0xa, 0x9); memn_driver_init(); } DRIVER_INIT_MEMBER(namcos10_state,konotako) { - decrypt_bios( machine(), "user2", 0x8400, 0x6, 0x7, 0x4, 0x5, 0x0, 0x1, 0x3, 0x2, 0xd, 0xc, 0xf, 0xe, 0x8, 0x9, 0xb, 0xa ); + decrypt_bios(machine(), "user2", 0x008400, 0x028000, 0x6, 0x7, 0x4, 0x5, 0x0, 0x1, 0x3, 0x2, 0xd, 0xc, 0xf, 0xe, 0x8, 0x9, 0xb, 0xa); + decrypt_bios(machine(), "user2", 0x0b4000, 0xfdc000, 0x6, 0x7, 0x4, 0x5, 0x0, 0x1, 0x3, 0x2, 0xd, 0xc, 0xf, 0xe, 0x8, 0x9, 0xb, 0xa); memn_driver_init(); } @@ -615,6 +640,16 @@ static MACHINE_CONFIG_START( namcos10_memn, namcos10_state ) MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") MACHINE_CONFIG_END +static MACHINE_CONFIG_DERIVED(ns10_konotako, namcos10_memn) +/* decrypter device (CPLD in hardware?) */ +MCFG_DEVICE_ADD("decrypter", KONOTAKO_DECRYPTER, 0) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_DERIVED(ns10_startrgn, namcos10_memn) +/* decrypter device (CPLD in hardware?) */ +MCFG_DEVICE_ADD("decrypter", STARTRGN_DECRYPTER, 0) +MACHINE_CONFIG_END + static INPUT_PORTS_START( namcos10 ) /* IN 0 */ PORT_START("SYSTEM") @@ -750,8 +785,9 @@ ROM_START( ptblank3 ) ROM_FILL( 0x0000000, 0x400000, 0x55 ) ROM_REGION16_LE( 0x2100000, "user2", 0 ) /* main prg */ - ROM_LOAD( "gnn2a.8e", 0x0000000, 0x1080000, CRC(31b39221) SHA1(7fcb14aaa26c531928a6cd704e746d0e3ae3e031) ) - ROM_LOAD( "gnn2a.8d", 0x1080000, 0x1080000, CRC(82d2cfb5) SHA1(4b5e713a55e74a7b32b1b9b5811892df2df86256) ) + // protection issues preventing the last NAND block to be dumped + ROM_LOAD("gnn2a.8e", 0x0000000, 0x1080000, BAD_DUMP CRC(31b39221) SHA1(7fcb14aaa26c531928a6cd704e746d0e3ae3e031)) + ROM_LOAD( "gnn2a.8d", 0x1080000, 0x1080000, BAD_DUMP CRC(82d2cfb5) SHA1(4b5e713a55e74a7b32b1b9b5811892df2df86256) ) ROM_END ROM_START( gunbalina ) @@ -759,8 +795,9 @@ ROM_START( gunbalina ) ROM_FILL( 0x0000000, 0x400000, 0x55 ) ROM_REGION16_LE( 0x2100000, "user2", 0 ) /* main prg */ - ROM_LOAD( "gnn1a.8e", 0x0000000, 0x1080000, CRC(981b03d4) SHA1(1c55458f1b2964afe2cf4e9d84548c0699808e9f) ) - ROM_LOAD( "gnn1a.8d", 0x1080000, 0x1080000, CRC(6cd343e0) SHA1(dcec44abae1504025895f42fe574549e5010f7d5) ) + // protection issues preventing the last NAND block to be dumped + ROM_LOAD( "gnn1a.8e", 0x0000000, 0x1080000, BAD_DUMP CRC(981b03d4) SHA1(1c55458f1b2964afe2cf4e9d84548c0699808e9f) ) + ROM_LOAD( "gnn1a.8d", 0x1080000, 0x1080000, BAD_DUMP CRC(6cd343e0) SHA1(dcec44abae1504025895f42fe574549e5010f7d5) ) ROM_END ROM_START( chocovdr ) @@ -806,17 +843,17 @@ ROM_START( konotako ) ROM_END -GAME( 2000, mrdrilr2, 0, namcos10_memm, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Japan, DR21 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks -GAME( 2000, mrdrlr2a, mrdrilr2, namcos10_memm, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Asia, DR22 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks -GAME( 2000, ptblank3, 0, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Point Blank 3 (Asia, GNN2 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2000, gunbalina, ptblank3, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Gunbalina (Japan, GNN1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2001, gjspace, 0, namcos10_memn, namcos10, namcos10_state, gjspace, ROT0, "Namco / Metro", "Gekitoride-Jong Space (10011 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2001, mrdrilrg, 0, namcos10_memn, namcos10, namcos10_state, mrdrilrg, ROT0, "Namco", "Mr. Driller G (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks -GAME( 2001, mrdrilrga, mrdrilrg, namcos10_memn, namcos10, namcos10_state, mrdrilrg, ROT0, "Namco", "Mr. Driller G ALT (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks -GAME( 2001, knpuzzle, 0, namcos10_memn, namcos10, namcos10_state, knpuzzle, ROT0, "Namco", "Kotoba no Puzzle Mojipittan (Japan, KPM1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2002, chocovdr, 0, namcos10_memn, namcos10, namcos10_state, chocovdr, ROT0, "Namco", "Uchuu Daisakusen: Chocovader Contactee (Japan, CVC1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2002, startrgn, 0, namcos10_memn, namcos10, namcos10_state, startrgn, ROT0, "Namco", "Star Trigon (Japan, STT1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2002, panikuru, 0, namcos10_memn, namcos10, namcos10_state, panikuru, ROT0, "Namco", "Panicuru Panekuru (Japan, PPA1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2003, nflclsfb, 0, namcos10_memn, namcos10, namcos10_state, nflclsfb, ROT0, "Namco", "NFL Classic Football (US, NCF3 Ver.A.)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2003, gamshara, 0, namcos10_memn, namcos10, namcos10_state, gamshara, ROT0, "Mitchell", "Gamshara (10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -GAME( 2003, konotako, 0, namcos10_memn, namcos10, namcos10_state, konotako, ROT0, "Mitchell", "Kono Tako (10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2000, mrdrilr2, 0, namcos10_memm, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Japan, DR21 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks +GAME( 2000, mrdrlr2a, mrdrilr2, namcos10_memm, namcos10, namcos10_state, mrdrilr2, ROT0, "Namco", "Mr. Driller 2 (Asia, DR22 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks +GAME( 2000, ptblank3, 0, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Point Blank 3 (Asia, GNN2 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2000, gunbalina, ptblank3, namcos10_memn, namcos10, namcos10_state, gunbalna, ROT0, "Namco", "Gunbalina (Japan, GNN1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2001, gjspace, 0, namcos10_memn, namcos10, namcos10_state, gjspace, ROT0, "Namco / Metro", "Gekitoride-Jong Space (10011 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2001, mrdrilrg, 0, namcos10_memn, namcos10, namcos10_state, mrdrilrg, ROT0, "Namco", "Mr. Driller G (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks +GAME( 2001, mrdrilrga, mrdrilrg, namcos10_memn, namcos10, namcos10_state, mrdrilrg, ROT0, "Namco", "Mr. Driller G ALT (Japan, DRG1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // PORT_4WAY joysticks +GAME( 2001, knpuzzle, 0, namcos10_memn, namcos10, namcos10_state, knpuzzle, ROT0, "Namco", "Kotoba no Puzzle Mojipittan (Japan, KPM1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2002, chocovdr, 0, namcos10_memn, namcos10, namcos10_state, chocovdr, ROT0, "Namco", "Uchuu Daisakusen: Chocovader Contactee (Japan, CVC1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2002, startrgn, 0, ns10_startrgn, namcos10, namcos10_state, startrgn, ROT0, "Namco", "Star Trigon (Japan, STT1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +GAME( 2002, panikuru, 0, namcos10_memn, namcos10, namcos10_state, panikuru, ROT0, "Namco", "Panicuru Panekuru (Japan, PPA1 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2003, nflclsfb, 0, namcos10_memn, namcos10, namcos10_state, nflclsfb, ROT0, "Namco", "NFL Classic Football (US, NCF3 Ver.A.)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2003, gamshara, 0, namcos10_memn, namcos10, namcos10_state, gamshara, ROT0, "Mitchell", "Gamshara (10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +GAME( 2003, konotako, 0, ns10_konotako, namcos10, namcos10_state, konotako, ROT0, "Mitchell", "Kono Tako (10021 Ver.A)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) diff --git a/src/mame/machine/ns10crypt.c b/src/mame/machine/ns10crypt.c new file mode 100644 index 00000000000..6a72912c2e9 --- /dev/null +++ b/src/mame/machine/ns10crypt.c @@ -0,0 +1,214 @@ +// license:BSD-3 +// copyright-holders:Andreas Naive +/**************************************************************************** +Namco System 10 decryption emulation + +(As of 2015-08, this file is still pretty much a WIP; changes are expected as +out knowledge progress.) + +The decryption used by type-2 System10 PCBs (MEM-N) acts on 16-bit words and is +designed to operate in a serial way: once the decryption is triggered, every +word is XORed with a mask calculated over data taken from the previous words +(both encrypted and decrypted). Type-1 PCBs seem to use a similar +scheme, probably involving the word address too and a bitswap, but his relation +to what is described here needs further investigation. + +In type-2 PCBs, the encrypted data is always contained in the first ROM of the +game (8E), and it's always stored spanning an integer number of NAND blocks +(the K9F2808U0B is organized in blocks of 16 KiB, each containing 32 pages of +0x200 bytes). The first part of the encrypted data is stored at about the end +of the ROM, and apparently all the blocks in that area are processed in +reverse order (first the one nearest the end, then the second nearest, etc); +the second part goes inmediately after it from a logic perspective, but it's +physically located at the area starting at 0x28000 in the ROM. Games, after +some bootup code has been executed, will copy the encrypted content from +the ROM to RAM, moment at which the decryption is triggered. + +Most games do a single decryption run, so the process is only initialized once; +however, at least one game (gamshara) does write to the triggering registers +more than once, effectively resetting the internal state of the decrypter +several times. (gamshara do it every 5 NAND blocks). + +The calculation of the XOR masks seem to operate this way: most bits are +calculated by using linear equations over GF(2) taking as input data the bits from +previously processed words; however, one nonlinear calculation is performed +per word processed, and that calculation can affect several bits from the +mask (but, apparently, the same nonlinear terms affect all of them), +though in most cases only one bit is involved. Till now, most of the linear +relations seem to depend only on the previous 3 words, but there are some +bits from those showing nonlinear behaviour which seem to use farther words; +this is still being investigated, and the implementation is probable to +change to reflect new findings. + +The bits affected by the nonlinear calculations are given below: +chocovdr -> #10 +gamshara -> #2 +gjspace -> a subset of {#3, #4, #5, #10, #11}, maybe all of them +gunbalina -> #11 +knpuzzle -> #1 +konotako -> #15 +mrdrilrg -> #0 & #4 +nflclsfb -> #2 +panikuru -> #2 +ptblank3 -> #11 +startrgn -> #4 + + +TO-DO: +* Research the nonlinear calculations in most of the games. +* Determine how many previous words the hardware is really using, and change +the implementation accordingly. + +Observing the linear equations, there is a keen difference between bits using +just a bunch of previous bits, and others using much more bits from more words; +simplyfing the latter ones could be handy, and probably closer to what the +hardware is doing. Two possible simplyfications could be: +A) The linear relations are creating lots of identities involving the bits +from the sequence; they could be exploited to simplify the equations (but +only when the implementation be stable, to avoid duplicating work). +B) It's possible that some of those calculations are being stored and then +used as another input bits for subsequent masks. Determining that (supposed) +bits and factoring out them would simplify the expressions, in case they +really exist. +*****************************************************************************/ + +#include "emu.h" +#include "ns10crypt.h" + +const device_type KONOTAKO_DECRYPTER = &device_creator; +const device_type STARTRGN_DECRYPTER = &device_creator; + +ns10_decrypter_device::ns10_decrypter_device(device_type type, const ns10_crypto_logic &logic, const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, type, "Namco System 10 Decrypter", tag, owner, clock, "ns10_crypto", __FILE__) + , _active(false) + , _logic(logic) +{ +} + +void ns10_decrypter_device::activate() +{ + init(); + _active = true; +} + +void ns10_decrypter_device::deactivate() +{ + _active = false; +} + +bool ns10_decrypter_device::is_active()const +{ + return _active; +} + +UINT16 ns10_decrypter_device::decrypt(UINT16 cipherword) +{ + UINT16 plainword = cipherword ^ _mask; + + _previous_cipherwords <<= 16; + _previous_cipherwords ^= cipherword; + _previous_plainwords <<= 16; + _previous_plainwords ^= plainword; + + _mask = 0; + for (int j = 15; j >= 0; --j) + { + _mask <<= 1; + _mask ^= gf2_reduce(_logic.eMask[j] & _previous_cipherwords); + _mask ^= gf2_reduce(_logic.dMask[j] & _previous_plainwords); + } + _mask ^= _logic.xMask; + _mask ^= _logic.nonlinear_calculation(_previous_cipherwords, _previous_plainwords); + + return plainword; +} + +void ns10_decrypter_device::device_start() +{ + int reduction; + + // create a look-up table of GF2 reductions of 16-bits words + for (int i = 0; i < 0x10000; ++i) + { + reduction = 0; + for (int j = 0; j < 16; ++j) + reduction ^= BIT(i, j); + + _gf2Reduction[i] = reduction; + } +} + +void ns10_decrypter_device::init() +{ + _previous_cipherwords = 0; + _previous_plainwords = 0; + _mask = 0; +} + +int ns10_decrypter_device::gf2_reduce(UINT64 num) +{ + return + _gf2Reduction[num & 0xffff] ^ + _gf2Reduction[(num >> 16) & 0xffff] ^ + _gf2Reduction[(num >> 32) & 0xffff] ^ + _gf2Reduction[num >> 48]; +} + + +// game-specific logic + +static UINT16 konotako_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords) +{ + UINT64 previous_masks = previous_cipherwords ^ previous_plainwords; + return ((previous_masks >> 7) & (previous_masks >> 15) & 1) << 15; +} + +static const ns10_decrypter_device::ns10_crypto_logic konotako_crypto_logic = { + { + 0x000000000000004cull, 0x00000000d39e3d3dull, 0x0000000000001110ull, 0x0000000000002200ull, + 0x000000003680c008ull, 0x0000000000000281ull, 0x0000000000005002ull, 0x00002a7371895a47ull, + 0x0000000000000003ull, 0x00002a7371897a4eull, 0x00002a73aea17a41ull, 0x00002a73fd895a4full, + 0x000000005328200aull, 0x0000000000000010ull, 0x0000000000000040ull, 0x0000000000000200ull, + }, { + 0x000000000000008cull, 0x0000000053003d25ull, 0x0000000000001120ull, 0x0000000000002200ull, + 0x0000000037004008ull, 0x0000000000000282ull, 0x0000000000006002ull, 0x0000060035005a47ull, + 0x0000000000000003ull, 0x0000060035001a4eull, 0x0000060025007a41ull, 0x00000600b5005a2full, + 0x000000009000200bull, 0x0000000000000310ull, 0x0000000000001840ull, 0x0000000000000400ull, + }, + 0x0748, + konotako_nonlinear_calc +}; + +static UINT16 startrgn_nonlinear_calc(UINT64 previous_cipherwords, UINT64 previous_plainwords) +{ + UINT64 previous_masks = previous_cipherwords ^ previous_plainwords; + return ((previous_masks >> 12) & (previous_masks >> 14) & 1) << 4; +} + +static const ns10_decrypter_device::ns10_crypto_logic startrgn_crypto_logic = { + { + 0x00003e4bfe92c6a9ull, 0x000000000000010cull, 0x00003e4b7bd6c4aaull, 0x0000b1a904b8fab8ull, + 0x0000000000000080ull, 0x0000000000008c00ull, 0x0000b1a9b2f0b4cdull, 0x000000006c100828ull, + 0x000000006c100838ull, 0x0000b1a9d3913fcdull, 0x000000006161aa00ull, 0x0000000000006040ull, + 0x0000000000000420ull, 0x0000000000001801ull, 0x00003e4b7bd6deabull, 0x0000000000000105ull, + }, { + 0x000012021f00c6a8ull, 0x0000000000000008ull, 0x000012020b1046aaull, 0x000012001502fea8ull, + 0x0000000000002000ull, 0x0000000000008800ull, 0x000012001e02b4cdull, 0x000000002c0008aaull, + 0x000000002c00083aull, 0x000012003f027ecdull, 0x0000000021008a00ull, 0x0000000000002040ull, + 0x0000000000000428ull, 0x0000000000001001ull, 0x000012020b10ceabull, 0x0000000000000144ull, + }, + 0x8c46, + startrgn_nonlinear_calc +}; + +// game-specific devices + +konotako_decrypter_device::konotako_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ns10_decrypter_device(KONOTAKO_DECRYPTER, konotako_crypto_logic, mconfig, tag, owner, clock) +{ +} + +startrgn_decrypter_device::startrgn_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : ns10_decrypter_device(STARTRGN_DECRYPTER, startrgn_crypto_logic, mconfig, tag, owner, clock) +{ +} diff --git a/src/mame/machine/ns10crypt.h b/src/mame/machine/ns10crypt.h new file mode 100644 index 00000000000..698d4b69d0b --- /dev/null +++ b/src/mame/machine/ns10crypt.h @@ -0,0 +1,62 @@ +// license:BSD-3 +// copyright-holders:Andreas Naive + +#ifndef _NS10CRYPT_H_ +#define _NS10CRYPT_H_ + +class ns10_decrypter_device : public device_t +{ +public: + // this encodes the decryption logic, which varies per game + // and is probably hard-coded into the CPLD + struct ns10_crypto_logic + { + UINT64 eMask[16]; + UINT64 dMask[16]; + UINT16 xMask; + UINT16(*nonlinear_calculation)(UINT64, UINT64); // preliminary encoding; need research + }; + + void activate(); + void deactivate(); + bool is_active()const; + + UINT16 decrypt(UINT16 cipherword); + +protected: + ns10_decrypter_device( + device_type type, const ns10_decrypter_device::ns10_crypto_logic &logic, + const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +private: + UINT16 _mask; + UINT64 _previous_cipherwords; + UINT64 _previous_plainwords; + bool _active; + const ns10_crypto_logic& _logic; + int _gf2Reduction[0x10000]; + + void device_start(); + void init(); + int gf2_reduce(UINT64 num); +}; + +// game-specific devices + +class konotako_decrypter_device : public ns10_decrypter_device +{ +public: + konotako_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +class startrgn_decrypter_device : public ns10_decrypter_device +{ +public: + startrgn_decrypter_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + + +extern const device_type KONOTAKO_DECRYPTER; +extern const device_type STARTRGN_DECRYPTER; + +#endif