Preliminary decryption support for Namco System 10 [Andreas Naive]

This commit is contained in:
andreasnaive 2015-08-01 17:27:36 +02:00
parent 820c1f8a7b
commit e5628609f4
4 changed files with 349 additions and 35 deletions

View File

@ -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",

View File

@ -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<ns10_decrypter_device*>(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)

View File

@ -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<konotako_decrypter_device>;
const device_type STARTRGN_DECRYPTER = &device_creator<startrgn_decrypter_device>;
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)
{
}

View File

@ -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