pgm2.cpp: emulate kov3 ROM module communication, remove hack.

probably should be devicified later.
This commit is contained in:
MetalliC 2017-12-30 04:23:56 +02:00
parent 6cae274c80
commit 3b5154b1f7
3 changed files with 145 additions and 8 deletions

View File

@ -14,7 +14,7 @@ TODO:
can not be used in CV1K (/SEL pin is NC, internally pulled to VCC), probably not used in PGM2 too.
770:
- sequencer timers implemented but seems unused, presumably because of design flaws or bugs, likely due to lack of automatic adding of sequencer # to register offset.
in result sequences uses very long chains of 32-sample wait commands instead, wasting a lost of ROM space.
in result sequences uses very long chains of 32-sample wait commands instead, wasting a lot of ROM space.
- sequencer triggers not implemented, not sure how they works (Deathsmiles ending tune starts sequence with TGST = 01h, likely a bug and don't affect tune playback)
774:
- 4 channel output

View File

@ -348,7 +348,101 @@ WRITE16_MEMBER(pgm2_state::unk30120014_w)
}
}
/*
KOV3 ROM board uses special module intead of program ROM, tiny PCB with FPGA stamped "HW1" and BGA Flash ROM stamped "IG-L".
This module uses few pins for serial comms (wired to IGS036 GPIO), it can not be dumped as regular ROM until special unlock procedure (return weird data pattern while locked).
In case of KOV3 unlock sequence is:
1) send via serial 0x0d and 64bit xor_value, result must be A3A3A3A36D6D6D6D
2) send via serial 0x25 and 64bit xor_value, store result as 64bit key (after xor with xor_value)
3) read first 10h bytes from ROM area (at this point ROM area read as scrambled or random data)
4) write "key" to ROM area, using 2x 16bit writes, write offsets and data depends on 64bit key
5) write static sequence of words to ROM area, which probably enable ROM descrambling and normal access
6) read "expected sum" from ROM 10000002-10000009 (presumable at this point ROM area read as descrambled)
7) read first 10h bytes from ROM area and check they are not same as was at step 3
8) perform whole ROM summing, result must match 64bit key xor "expected sum" read at step 6
It is not clear if real address/data xor values derived from written "key",
or FPGA just waiting to be be written magic value at specific address in ROM area, and if this happen enable descrambling using hardcoded values.
*/
READ_LINE_MEMBER(pgm2_state::module_data_r)
{
return module_out_latch ? ASSERT_LINE : CLEAR_LINE;
}
WRITE_LINE_MEMBER(pgm2_state::module_data_w)
{
module_in_latch = (state == ASSERT_LINE) ? 1 : 0;
}
WRITE_LINE_MEMBER(pgm2_state::module_clk_w)
{
if (module_prev_state != state && state == CLEAR_LINE)
{
if (module_clk_cnt < 80)
{
int offs = module_clk_cnt / 8;
int bit = (module_clk_cnt & 7) ^ 7;
module_rcv_buf[offs] &= ~(1 << bit);
module_rcv_buf[offs] |= module_in_latch << bit;
++module_clk_cnt;
if (module_clk_cnt >= 80)
{
switch (module_rcv_buf[0])
{
case 0x0d: // init or status check
module_send_buf[0] = module_send_buf[1] = module_send_buf[2] = module_send_buf[3] = 0xa3;
module_send_buf[4] = module_send_buf[5] = module_send_buf[6] = module_send_buf[7] = 0x6d;
break;
case 0x25: // get key
for (int i = 0; i < 8; i++)
module_send_buf[i] = module_key[i] ^ module_rcv_buf[i + 1];
break;
default:
logerror("unknown FPGA command %02X!\n", module_rcv_buf[0]);
break;
}
module_send_buf[8] = 0;
for (int i = 0; i < 8; i++) // sum reply bytes
module_send_buf[8] += module_send_buf[i];
}
}
else
{
int offs = (module_clk_cnt - 80) / 8;
int bit = (module_clk_cnt & 7) ^ 7;
module_out_latch = (module_send_buf[offs] >> bit) & 1;
++module_clk_cnt;
if (module_clk_cnt >= 152)
module_clk_cnt = 0;
}
}
module_prev_state = state;
}
WRITE32_MEMBER(pgm2_state::module_scramble_w)
{
decrypt_kov3_module(module_addr_xor, module_data_xor);
}
// very primitive Atmel ARM PIO simulation, should be improved and devicified
WRITE32_MEMBER(pgm2_state::pio_sodr_w)
{
pio_out_data |= data & mem_mask;
module_data_w((pio_out_data & 0x100) ? ASSERT_LINE : CLEAR_LINE);
module_clk_w((pio_out_data & 0x200) ? ASSERT_LINE : CLEAR_LINE);
}
WRITE32_MEMBER(pgm2_state::pio_codr_w)
{
pio_out_data &= ~(data & mem_mask);
module_data_w((pio_out_data & 0x100) ? ASSERT_LINE : CLEAR_LINE);
module_clk_w((pio_out_data & 0x200) ? ASSERT_LINE : CLEAR_LINE);
}
READ32_MEMBER(pgm2_state::pio_pdsr_r)
{
return (module_data_r() == ASSERT_LINE ? 1 : 0) << 8; // fpga data read and status (bit 7, must be 0)
}
static ADDRESS_MAP_START( pgm2_map, AS_PROGRAM, 32, pgm2_state )
AM_RANGE(0x00000000, 0x00003fff) AM_ROM //AM_REGION("user1", 0x00000) // internal ROM
@ -423,6 +517,14 @@ static ADDRESS_MAP_START( pgm2_ram_rom_map, AS_PROGRAM, 32, pgm2_state )
AM_IMPORT_FROM(pgm2_map)
ADDRESS_MAP_END
static ADDRESS_MAP_START( pgm2_module_rom_map, AS_PROGRAM, 32, pgm2_state )
AM_RANGE(0x10014a40, 0x10014a43) AM_WRITE(module_scramble_w)
AM_RANGE(0xfffff430, 0xfffff433) AM_WRITE(pio_sodr_w)
AM_RANGE(0xfffff434, 0xfffff437) AM_WRITE(pio_codr_w)
AM_RANGE(0xfffff43c, 0xfffff43f) AM_READ(pio_pdsr_r)
AM_IMPORT_FROM(pgm2_rom_map)
ADDRESS_MAP_END
static INPUT_PORTS_START( pgm2 )
PORT_START("INPUTS0")
PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
@ -528,6 +630,13 @@ void pgm2_state::machine_start()
save_item(NAME(m_mcu_last_cmd));
save_item(NAME(m_shareram));
save_item(NAME(m_share_bank));
save_item(NAME(pio_out_data));
save_item(NAME(module_in_latch));
save_item(NAME(module_out_latch));
save_item(NAME(module_prev_state));
save_item(NAME(module_clk_cnt));
save_item(NAME(module_rcv_buf));
save_item(NAME(module_send_buf));
}
void pgm2_state::machine_reset()
@ -541,6 +650,10 @@ void pgm2_state::machine_reset()
memcpy(memregion("user1")->base(), &m_encrypted_copy[0], memregion("user1")->bytes());
m_has_decrypted = 0;
pio_out_data = 0;
module_prev_state = 0;
module_clk_cnt = 151; // this needed because of "false" clock pulse happen during gpio init
}
static const gfx_layout tiles8x8_layout =
@ -630,6 +743,8 @@ static MACHINE_CONFIG_DERIVED( pgm2_lores, pgm2 )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( pgm2_hires, pgm2 )
MCFG_CPU_MODIFY("maincpu")
MCFG_CPU_PROGRAM_MAP(pgm2_module_rom_map)
MCFG_SCREEN_MODIFY("screen")
MCFG_SCREEN_VISIBLE_AREA(0, 512-1, 0, 240-1)
MACHINE_CONFIG_END
@ -1168,13 +1283,13 @@ DRIVER_INIT_MEMBER(pgm2_state,ddpdojh)
machine().device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x20021e04, 0x20021e07, read32_delegate(FUNC(pgm2_state::ddpdojh_speedup2_r), this));
}
static const uint8_t kov3_100_key[] = { 0xde, 0x29, 0x52, 0x84, 0x71, 0x9e, 0xed, 0x66 };
static const uint8_t kov3_102_key[] = { 0x0e, 0x49, 0x9f, 0x1b, 0xca, 0x14, 0xec, 0x33 };
static const uint8_t kov3_104_key[] = { 0xaf, 0x35, 0x5f, 0xf9, 0x63, 0x78, 0xe8, 0xf9 };
DRIVER_INIT_MEMBER(pgm2_state,kov3)
{
common_encryption_init();
// patch FPGA check
uint32_t* rom = (uint32_t*)memregion("maincpu")->base();
rom[0x2a8c / 4] = 0xe320f000; // not endian safe ?
machine().device("maincpu")->memory().space(AS_PROGRAM).install_read_handler(0x200000b4, 0x200000b7, read32_delegate(FUNC(pgm2_state::kov3_speedup_r),this));
}
@ -1193,19 +1308,23 @@ void pgm2_state::decrypt_kov3_module(uint32_t addrxor, uint16_t dataxor)
DRIVER_INIT_MEMBER(pgm2_state, kov3_104)
{
decrypt_kov3_module(0x18ec71, 0xb89d);
// currently we don't know how to derive address/data xor values from real keys, so we need both
module_addr_xor = 0x18ec71; module_data_xor = 0xb89d;
module_key = kov3_104_key;
DRIVER_INIT_CALL(kov3);
}
DRIVER_INIT_MEMBER(pgm2_state, kov3_102)
{
decrypt_kov3_module(0x021d37, 0x81d0);
module_addr_xor = 0x021d37; module_data_xor = 0x81d0;
module_key = kov3_102_key;
DRIVER_INIT_CALL(kov3);
}
DRIVER_INIT_MEMBER(pgm2_state, kov3_100)
{
decrypt_kov3_module(0x3e8aa8, 0xc530);
module_addr_xor = 0x3e8aa8; module_data_xor = 0xc530;
module_key = kov3_100_key;
DRIVER_INIT_CALL(kov3);
}

View File

@ -59,6 +59,14 @@ public:
DECLARE_WRITE16_MEMBER(vbl_ack_w);
DECLARE_WRITE16_MEMBER(unk30120014_w);
DECLARE_WRITE32_MEMBER(pio_sodr_w);
DECLARE_WRITE32_MEMBER(pio_codr_w);
DECLARE_READ32_MEMBER(pio_pdsr_r);
DECLARE_WRITE32_MEMBER(module_scramble_w);
DECLARE_READ_LINE_MEMBER(module_data_r);
DECLARE_WRITE_LINE_MEMBER(module_data_w);
DECLARE_WRITE_LINE_MEMBER(module_clk_w);
DECLARE_READ32_MEMBER(orleg2_speedup_r);
DECLARE_READ32_MEMBER(kov2nl_speedup_r);
DECLARE_READ32_MEMBER(kof98umh_speedup_r);
@ -131,6 +139,16 @@ private:
std::vector<uint8_t> m_encrypted_copy;
uint32_t pio_out_data;
uint32_t module_addr_xor, module_data_xor;
const uint8_t *module_key;
uint32_t module_in_latch;
uint32_t module_out_latch;
int module_prev_state;
int module_clk_cnt;
uint8_t module_rcv_buf[10];
uint8_t module_send_buf[9];
// devices
required_device<cpu_device> m_maincpu;
required_device<screen_device> m_screen;