From a81c455b02f42f69f7b610b7131316858bf181bf Mon Sep 17 00:00:00 2001 From: angelosa Date: Sat, 19 Mar 2022 19:41:57 +0100 Subject: [PATCH] vamphalf.cpp: improve misncrft protection handling --- src/mame/drivers/vamphalf.cpp | 228 +++++++++++++++++++++++----------- 1 file changed, 155 insertions(+), 73 deletions(-) diff --git a/src/mame/drivers/vamphalf.cpp b/src/mame/drivers/vamphalf.cpp index f8fba1ce6f3..8507cab2e12 100644 --- a/src/mame/drivers/vamphalf.cpp +++ b/src/mame/drivers/vamphalf.cpp @@ -180,11 +180,6 @@ protected: u32 finalgdr_prot_r(); void finalgdr_prot_w(u32 data); - u32 m_misncrft_prot_seed[2]; - u8 m_misncrft_prot_retval; - u16 misncrft_prot_r(offs_t offset); - void misncrft_prot_w(offs_t offset, u16 data); - private: required_device m_gfxdecode; @@ -258,19 +253,18 @@ public: { } - void misncrft(machine_config &config); void wyvernwg(machine_config &config); void yorijori(machine_config &config); - void init_misncrft(); void init_wyvernwg(); void init_yorijori(); +protected: + void install_qdsp(); + private: required_device m_qdsp_cpu; - u16 misncrft_speedup_r(); - u16 misncrfta_speedup_r(); u32 wivernwg_speedup_r(); u32 wyvernwg_speedup_r(); u32 wyvernwga_speedup_r(); @@ -282,12 +276,40 @@ private: void yorijori_eeprom_w(u32 data); - void misncrft_io(address_map &map); void wyvernwg_io(address_map &map); void yorijori_32bit_map(address_map &map); void yorijori_io(address_map &map); }; +class misncrft_state : public vamphalf_qdsp_state +{ +public: + misncrft_state(const machine_config &mconfig, device_type type, const char *tag) + : vamphalf_qdsp_state(mconfig, type, tag) + { + } + + void misncrft(machine_config &config); + void init_misncrft(); + void init_misncrfta(); + +private: + u8 prot_value_check(std::vector> &prot_table, int seed_size); + + u16 misncrft_speedup_r(); + u16 misncrfta_speedup_r(); + + u8 m_prot_seed[16]; + u8 m_prot_retval; + int m_prot_idx; + bool m_prot_armed; + + u16 misncrft_prot_r(offs_t offset); + template void misncrft_prot_w(offs_t offset, u16 data); + + void misncrft_io(address_map &map); +}; + class vamphalf_nvram_state : public vamphalf_state { public: @@ -547,68 +569,119 @@ void vamphalf_state::qs1000_p3_w(u8 data) /* * Mission Craft tests protection device on two places: * 1. at POST on $680 (PC=0xf81c) - * 2. If check one is successful it attempts two new checks after ~15 minutes, - * \- first tries 0x5fd8988e / 0x1f3f37ee at $680, - * \- then it tries 0xcfddfbbf / 0xeefff6e7 at $340 (PC=f9d6) - * If protection check fails then game intentionally add massive refresh hiccups - * after aforementioned 15 minutes. - * It doesn't seem to matter if game is being played or is left in attract during this time. + * 2. If check one is successful it attempts two new checks after about 15 minutes at $680 and $340, + * both seeds depends on number_of_credits % 3 inserted up to an arbitrary point in time + * (i.e. credit insertion is definitely disarmed after about 14 minutes) + * If protection check fails then game intentionally add massive refresh hiccups after aforementioned 15 minutes. + * It doesn't seem to matter if game(s) is being played, is left in attract or on title screen during this time. */ -u16 vamphalf_state::misncrft_prot_r(offs_t offset) +u16 misncrft_state::misncrft_prot_r(offs_t offset) { if (offset) { - u8 retval = (m_misncrft_prot_retval >> (7 - m_semicom_prot_idx)) & 1; + u8 retval = (m_prot_retval >> (7 - m_prot_idx)) & 1; if (!machine().side_effects_disabled()) - m_semicom_prot_idx ++; + m_prot_idx ++; return retval ? 0xffff : 0; } return 0; } -void vamphalf_state::misncrft_prot_w(offs_t offset, u16 data) +u8 misncrft_state::prot_value_check(std::vector> &prot_table, int seed_size) +{ + const int prot_size = prot_table.size(); + int i; + + for (i = 0; i < prot_size; i++) + { + bool result = true; + + for (int j = 0; j < seed_size; j ++) + { + if (prot_table[i][j] != m_prot_seed[j]) + { + result = false; + break; + } + } + + if (result == true) + return (u8)prot_table[i][seed_size]; + } + + std::ostringstream outbuffer; + util::stream_format(outbuffer, "%s: unhandled protection seed {", machine().describe_context()); + for (i = 0; i < seed_size; i++) + util::stream_format(outbuffer, "0x%02x, ", m_prot_seed[i]); + util::stream_format(outbuffer, "},\n"); + + logerror(outbuffer.str()); + //std::cout << outbuffer.str(); + // tested up to 3 hours, leave this in anyway for checking out if any inp testing triggers here. + machine().debug_break(); + return 0x00; +} + + +template void misncrft_state::misncrft_prot_w(offs_t offset, u16 data) { if (offset) { // Seed uploads with a 0xffff -> 1 byte x 8 times -> 0xffff // This should be used as a commit/reset chip mechanism, // likely in a flip-flop transition with any of the upper bits. + // Note: the $340 version actually checks for 16 times instead of 8 // Also note: return value is read 8 times but only first 4 bits are compared against, why? if (data == 0xffff) { - m_semicom_prot_idx = 0; - - if (m_misncrft_prot_seed[0] == 0x806b4bfb && m_misncrft_prot_seed[1] == 0xe3fb55f6) - m_misncrft_prot_retval = 0xf0; - else if (m_misncrft_prot_seed[0] == 0xdf7c1de1 && m_misncrft_prot_seed[1] == 0x8701be31) - m_misncrft_prot_retval = 0xe0; - else if (m_misncrft_prot_seed[0] == 0x57730e47 && m_misncrft_prot_seed[1] == 0x67678758) - m_misncrft_prot_retval = 0xa0; - else if (m_misncrft_prot_seed[0] == 0x893c59ea && m_misncrft_prot_seed[1] == 0x57127bd2) - m_misncrft_prot_retval = 0x00; - else if (m_misncrft_prot_seed[0] == 0xa1d83c54 && m_misncrft_prot_seed[1] == 0x542f36af) - m_misncrft_prot_retval = 0x80; - else if (m_misncrft_prot_seed[0] == 0x5fd8988e && m_misncrft_prot_seed[1] == 0x1f3f37ee) - m_misncrft_prot_retval = 0x20; - else if (m_misncrft_prot_seed[0] == 0xcfddfbbf && m_misncrft_prot_seed[1] == 0xeefff6e7) - m_misncrft_prot_retval = 0xa0; - else if (m_misncrft_prot_seed[0] != 0 && m_misncrft_prot_seed[1] != 0) + m_prot_idx = 0; + + if (m_prot_armed) { - logerror("%s: unhandled protection seed %08x %08x\n", machine().describe_context(), m_misncrft_prot_seed[0], m_misncrft_prot_seed[1]); - //printf("else if (m_misncrft_prot_seed[0] == 0x%08x && m_misncrft_prot_seed[1] == 0x%08x)\n",m_misncrft_prot_seed[0], m_misncrft_prot_seed[1]); - m_misncrft_prot_retval = 0x00; - // tested up to 3 hours, leave this in anyway for checking out if any inp testing triggers here. - machine().debug_break(); + if (seed_size == 8) + { + std::vector> prot_table_8 = { + { 0x80, 0x6b, 0x4b, 0xfb, 0xe3, 0xfb, 0x55, 0xf6, 0xf0 }, + { 0xdf, 0x7c, 0x1d, 0xe1, 0x87, 0x01, 0xbe, 0x31, 0xe0 }, + { 0x57, 0x73, 0x0e, 0x47, 0x67, 0x67, 0x87, 0x58, 0xa0 }, + { 0x89, 0x3c, 0x59, 0xea, 0x57, 0x12, 0x7b, 0xd2, 0x00 }, + { 0xa1, 0xd8, 0x3c, 0x54, 0x54, 0x2f, 0x36, 0xaf, 0x80 }, + // 15 minutes checks (PC=f81c): + // 0 credits + { 0x5f, 0xd8, 0x98, 0x8e, 0x1f, 0x3f, 0x37, 0xee, 0x20 }, + // 1 credit + { 0xda, 0x03, 0x78, 0x99, 0xcd, 0xe2, 0x1b, 0x77, 0x90 }, + }; + m_prot_retval = prot_value_check(prot_table_8, seed_size); + } + else + { + std::vector> prot_table_16 = { + { + 0x4d, 0x4d, 0xfa, 0xbe, 0xa6, 0x5a, 0xa4, 0x86, + 0x8e, 0xdc, 0x09, 0x2d, 0x4e, 0xef, 0x56, 0xe1, 0xa0 + }, + // 2 credits + { + 0xd9, 0xd9, 0x8f, 0x5f, 0x3f, 0xb6, 0xee, 0xc3, + 0xf8, 0x4d, 0x0d, 0xea, 0xbe, 0xa6, 0xda, 0x64, 0xc0 + }, + }; + m_prot_retval = prot_value_check(prot_table_16, seed_size); + } } - for (int i = 0; i < 2; i++) - m_misncrft_prot_seed[i] = 0; + // clear write latches + for (int i = 0; i < seed_size; i++) + m_prot_seed[i] = 0; + m_prot_armed = false; } else { - //printf("%02x %d\n", data & 0xff, m_semicom_prot_idx); - m_misncrft_prot_seed[(m_semicom_prot_idx & 4) >> 2] |= ((data & 0xff) << ((3 - (m_semicom_prot_idx & 3)) * 8)); - m_semicom_prot_idx ++; + //printf("%02x %d\n", data & 0xff, m_prot_idx); + m_prot_seed[m_prot_idx] = data & 0xff; + m_prot_armed = true; + m_prot_idx ++; } } } @@ -650,16 +723,16 @@ void vamphalf_state::vamphalf_io(address_map &map) map(0x608, 0x60b).w(FUNC(vamphalf_state::eeprom_w)); } -void vamphalf_qdsp_state::misncrft_io(address_map &map) +void misncrft_state::misncrft_io(address_map &map) { - map(0x100, 0x103).w(FUNC(vamphalf_state::flipscreen_w)); + map(0x100, 0x103).w(FUNC(misncrft_state::flipscreen_w)); map(0x200, 0x203).portr("P1_P2"); map(0x240, 0x243).portr("SYSTEM"); - map(0x340, 0x343).rw(FUNC(vamphalf_qdsp_state::misncrft_prot_r), FUNC(vamphalf_qdsp_state::misncrft_prot_w)); - map(0x3c0, 0x3c3).w(FUNC(vamphalf_state::eeprom_w)); + map(0x340, 0x343).rw(FUNC(misncrft_state::misncrft_prot_r), FUNC(misncrft_state::misncrft_prot_w<16>)); + map(0x3c0, 0x3c3).w(FUNC(misncrft_state::eeprom_w)); map(0x400, 0x403).w(m_soundlatch, FUNC(generic_latch_8_device::write)).umask16(0x00ff).cswidth(16); - map(0x580, 0x583).r(FUNC(vamphalf_state::eeprom_r)); - map(0x680, 0x683).rw(FUNC(vamphalf_qdsp_state::misncrft_prot_r), FUNC(vamphalf_qdsp_state::misncrft_prot_w)); + map(0x580, 0x583).r(FUNC(misncrft_state::eeprom_r)); + map(0x680, 0x683).rw(FUNC(misncrft_state::misncrft_prot_r), FUNC(misncrft_state::misncrft_prot_w<8>)); } void vamphalf_state::coolmini_io(address_map &map) @@ -1316,13 +1389,13 @@ void vamphalf_state::vamphalf(machine_config &config) sound_ym_oki(config); } -void vamphalf_qdsp_state::misncrft(machine_config &config) +void misncrft_state::misncrft(machine_config &config) { common(config); GMS30C2116(config.replace(), m_maincpu, XTAL(50'000'000)); /* 50 MHz */ - m_maincpu->set_addrmap(AS_PROGRAM, &vamphalf_qdsp_state::common_map); - m_maincpu->set_addrmap(AS_IO, &vamphalf_qdsp_state::misncrft_io); - m_maincpu->set_vblank_int("screen", FUNC(vamphalf_state::irq1_line_hold)); + m_maincpu->set_addrmap(AS_PROGRAM, &misncrft_state::common_map); + m_maincpu->set_addrmap(AS_IO, &misncrft_state::misncrft_io); + m_maincpu->set_vblank_int("screen", FUNC(misncrft_state::irq1_line_hold)); m_screen->set_raw(XTAL(28'000'000) / 4, 448, 31, 350, 264, 16, 251); // not measured, assume 59.18 Hz like others @@ -3101,7 +3174,7 @@ u16 vamphalf_state::vamphafk_speedup_r() return m_wram[0x4a648 / 2]; } -u16 vamphalf_qdsp_state::misncrft_speedup_r() +u16 misncrft_state::misncrft_speedup_r() { if (m_maincpu->pc() == 0xff5a) { @@ -3114,7 +3187,7 @@ u16 vamphalf_qdsp_state::misncrft_speedup_r() return m_wram[0x741e8 / 2]; } -u16 vamphalf_qdsp_state::misncrfta_speedup_r() +u16 misncrft_state::misncrfta_speedup_r() { if (m_maincpu->pc() == 0xecd6) { @@ -3473,18 +3546,31 @@ void vamphalf_state::init_vamphafk() m_flip_bit = 0x80; } -void vamphalf_qdsp_state::init_misncrft() +void vamphalf_qdsp_state::install_qdsp() { - m_maincpu->space(AS_PROGRAM).install_read_handler(0x000741e8, 0x000741e9, read16smo_delegate(*this, FUNC(vamphalf_qdsp_state::misncrft_speedup_r))); - m_maincpu->space(AS_PROGRAM).install_read_handler(0x00072e2c, 0x00072e2d, read16smo_delegate(*this, FUNC(vamphalf_qdsp_state::misncrfta_speedup_r))); - m_palshift = 0; - m_flip_bit = 1; - // Configure the QS1000 ROM banking. Care must be taken not to overlap the 256b internal RAM m_qdsp_cpu->space(AS_IO).install_read_bank(0x0100, 0xffff, m_qs1000_bank); m_qs1000_bank->configure_entries(0, 16, memregion("qs1000:cpu")->base() + 0x100, 0x8000-0x100); } +void misncrft_state::init_misncrft() +{ + m_maincpu->space(AS_PROGRAM).install_read_handler(0x000741e8, 0x000741e9, read16smo_delegate(*this, FUNC(misncrft_state::misncrft_speedup_r))); + m_palshift = 0; + m_flip_bit = 1; + + install_qdsp(); +} + +void misncrft_state::init_misncrfta() +{ + m_maincpu->space(AS_PROGRAM).install_read_handler(0x00072e2c, 0x00072e2d, read16smo_delegate(*this, FUNC(misncrft_state::misncrfta_speedup_r))); + m_palshift = 0; + m_flip_bit = 1; + + install_qdsp(); +} + void vamphalf_state::init_coolmini() { m_maincpu->space(AS_PROGRAM).install_read_handler(0x000d2df8, 0x000d2df9, read16smo_delegate(*this, FUNC(vamphalf_state::coolmini_speedup_r))); @@ -3563,9 +3649,7 @@ void vamphalf_qdsp_state::init_wyvernwg() m_semicom_prot_data[0] = 2; m_semicom_prot_data[1] = 1; - // Configure the QS1000 ROM banking. Care must be taken not to overlap the 256b internal RAM - m_qdsp_cpu->space(AS_IO).install_read_bank(0x0100, 0xffff, m_qs1000_bank); - m_qs1000_bank->configure_entries(0, 16, memregion("qs1000:cpu")->base() + 0x100, 0x8000-0x100); + install_qdsp(); save_item(NAME(m_semicom_prot_idx)); save_item(NAME(m_semicom_prot_which)); @@ -3587,9 +3671,7 @@ void vamphalf_qdsp_state::init_yorijori() romx[BYTE4_XOR_BE(0x8ff0)] = 3; romx[BYTE4_XOR_BE(0x8ff1)] = 0; - // Configure the QS1000 ROM banking. Care must be taken not to overlap the 256b internal RAM - m_qdsp_cpu->space(AS_IO).install_read_bank(0x0100, 0xffff, m_qs1000_bank); - m_qs1000_bank->configure_entries(0, 16, memregion("qs1000:cpu")->base() + 0x100, 0x8000-0x100); + install_qdsp(); } void vamphalf_nvram_state::init_finalgdr() @@ -3754,8 +3836,8 @@ GAME( 1999, vamphalfk, vamphalf, vamphalf, common, vamphalf_state, init GAME( 2000, dquizgo2, 0, coolmini, common, vamphalf_state, init_dquizgo2, ROT0, "SemiCom", "Date Quiz Go Go Episode 2" , MACHINE_SUPPORTS_SAVE ) -GAME( 2000, misncrft, 0, misncrft, common, vamphalf_qdsp_state, init_misncrft, ROT90, "Sun", "Mission Craft (version 2.7)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) // game starts to stall for several seconds at a time after it's been running for a certain amount of time (you can usually complete 1 loop) -GAME( 2000, misncrfta, misncrft, misncrft, common, vamphalf_qdsp_state, init_misncrft, ROT90, "Sun", "Mission Craft (version 2.4)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) +GAME( 2000, misncrft, 0, misncrft, common, misncrft_state, init_misncrft, ROT90, "Sun", "Mission Craft (version 2.7)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) // game starts to stall for several seconds at a time after it's been running for a certain amount of time (you can usually complete 1 loop) +GAME( 2000, misncrfta, misncrft, misncrft, common, misncrft_state, init_misncrfta, ROT90, "Sun", "Mission Craft (version 2.4)", MACHINE_SUPPORTS_SAVE | MACHINE_NOT_WORKING ) GAME( 2000, mrdig, 0, mrdig, common, vamphalf_state, init_mrdig, ROT0, "Sun", "Mr. Dig", MACHINE_SUPPORTS_SAVE )