diff --git a/src/devices/sound/ymz770.cpp b/src/devices/sound/ymz770.cpp index 711bb3c1a91..b81e78a15f1 100644 --- a/src/devices/sound/ymz770.cpp +++ b/src/devices/sound/ymz770.cpp @@ -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 diff --git a/src/mame/drivers/pgm2.cpp b/src/mame/drivers/pgm2.cpp index 47bf8d4b3d8..f3f93471512 100644 --- a/src/mame/drivers/pgm2.cpp +++ b/src/mame/drivers/pgm2.cpp @@ -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); } diff --git a/src/mame/includes/pgm2.h b/src/mame/includes/pgm2.h index d685a97d042..6eab4f5a1a4 100644 --- a/src/mame/includes/pgm2.h +++ b/src/mame/includes/pgm2.h @@ -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 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 m_maincpu; required_device m_screen;