mirror of
https://github.com/holub/mame
synced 2025-05-09 07:41:50 +03:00
pgm2.cpp: emulate kov3 ROM module communication, remove hack.
probably should be devicified later.
This commit is contained in:
parent
6cae274c80
commit
3b5154b1f7
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user