diff --git a/src/mame/drivers/pgm2.cpp b/src/mame/drivers/pgm2.cpp index 794de03f295..785b6953a2c 100644 --- a/src/mame/drivers/pgm2.cpp +++ b/src/mame/drivers/pgm2.cpp @@ -46,11 +46,7 @@ Identify which regions each game was released in and either dump alt. internal ROMs for each region, or create them until that can be done. properly implement RTC (integrated into the CPU) - Memory Card system (there's an MCU on the motherboard that will need simulating or dumping somehow) Verify Sprite Zoom (check exactly which pixels are doubled / missed on hardware for flipped , non-flipped cases etc.) - Simplify IGS036 encryption based on tables in internal roms - Fix ARM? bug that means Oriental Legend 2 needs a patch (might also be that it needs the card reader, and is running a - codepath that would not exist in a real environment at the moment) Fix Save States (is this a driver problem or an ARM core problem, they don't work unless you get through the startup tests) Debug features (require DIP SW1:8 On and SW1:1 Off): @@ -188,47 +184,86 @@ void pgm2_state::mcu_command(address_space &space, bool is_command) m_mcu_result1 = 0; } break; - // unknown / unimplemented, all C0-C9 commands is IC Card RW related - // (m_mcu_regs[0] >> 8) & 0xff - target RW unit (player) + // C0-C9 commands is IC Card RW comms case 0xc0: // insert card or/and check card presence. result: F7 - ok, F4 - no card if (m_memcard_device[arg1 & 3]->present() == -1) status = 0xf4; m_mcu_result0 = cmd; break; case 0xc1: // check ready/busy ? + if (m_memcard_device[arg1 & 3]->present() == -1) + status = 0xf4; m_mcu_result0 = cmd; break; - case 0xc2: // read data to shared ram, args - offset, len + case 0xc2: // read data to shared ram for (int i = 0; i < arg3; i++) { if (m_memcard_device[arg1 & 3]->present() != -1) m_shareram[i + (~m_share_bank & 1) * 128] = m_memcard_device[arg1 & 3]->read(space, arg2 + i); + else + status = 0xf4; } - m_mcu_result0 = cmd; break; - case 0xc3: // save data from shared ram, args - offset, len + case 0xc3: // save data from shared ram for (int i = 0; i < arg3; i++) { if (m_memcard_device[arg1 & 3]->present() != -1) m_memcard_device[arg1 & 3]->write(space, arg2 + i, m_shareram[i + (~m_share_bank & 1) * 128]); + else + status = 0xf4; } m_mcu_result0 = cmd; break; - case 0xc7: // get card ID?, no args, result1 expected to be fixed value for new card - m_mcu_result1 = 0xf81f0000; + case 0xc4: // presumable read security mem (password only?) + if (m_memcard_device[arg1 & 3]->present() != -1) + { + m_mcu_result1 = m_memcard_device[arg1 & 3]->read_sec(space, 1) | + (m_memcard_device[arg1 & 3]->read_sec(space, 2) << 8) | + (m_memcard_device[arg1 & 3]->read_sec(space, 3) << 16); + } + else + status = 0xf4; m_mcu_result0 = cmd; break; - case 0xc8: // write byte, args - offset, data byte + case 0xc5: // write security mem + if (m_memcard_device[arg1 & 3]->present() != -1) + m_memcard_device[arg1 & 3]->write_sec(space, arg2 & 3, arg3); + else + status = 0xf4; + m_mcu_result0 = cmd; + break; + case 0xc6: // presumable write protection mem + if (m_memcard_device[arg1 & 3]->present() != -1) + m_memcard_device[arg1 & 3]->write_prot(space, arg2 & 3, arg3); + else + status = 0xf4; + m_mcu_result0 = cmd; + break; + case 0xc7: // read protection mem + if (m_memcard_device[arg1 & 3]->present() != -1) + { + m_mcu_result1 = m_memcard_device[arg1 & 3]->read_prot(space, 0) | + (m_memcard_device[arg1 & 3]->read_prot(space, 1) << 8) | + (m_memcard_device[arg1 & 3]->read_prot(space, 2) << 16) | + (m_memcard_device[arg1 & 3]->read_prot(space, 3) << 24); + } + else + status = 0xf4; + m_mcu_result0 = cmd; + break; + case 0xc8: // write data mem if (m_memcard_device[arg1 & 3]->present() != -1) m_memcard_device[arg1 & 3]->write(space, arg2, arg3); - + else + status = 0xf4; m_mcu_result0 = cmd; break; - case 0xc4: // not used - case 0xc5: // set new password?, args - offset, data byte (offs 0 - always 7, 1-3 password) - case 0xc6: // not used - case 0xc9: // card authentication, args - 3 byte password, ('I','G','S' for new cards) + case 0xc9: // card authentication + if (m_memcard_device[arg1 & 3]->present() != -1) + m_memcard_device[arg1 & 3]->auth(arg2, arg3, m_mcu_regs[1] & 0xff); + else + status = 0xf4; m_mcu_result0 = cmd; break; default: @@ -585,8 +620,8 @@ MACHINE_CONFIG_END #define ORLEG2_INTERNAL_CHINA \ ROM_REGION( 0x04000, "maincpu", 0 ) \ ROM_LOAD( "xyj2_cn.igs036", 0x00000000, 0x0004000, CRC(bcce7641) SHA1(c3b5cf6e9f6eae09b6785314777a52b34c3c7657) ) \ - ROM_REGION( 0x100, "default_card", 0 ) \ - ROM_LOAD( "blank_orleg2_china_card.pg2", 0x000, 0x100, CRC(099156f0) SHA1(a621c9772a98719c657bba3a1bf235487eb78615) ) + ROM_REGION( 0x108, "default_card", 0 ) \ + ROM_LOAD( "blank_orleg2_china_card.pg2", 0x000, 0x108, CRC(dc29556f) SHA1(2335cc7af25d4dd9763c6944d3f0eb50276de80a) ) #define ORLEG2_INTERNAL_OVERSEAS \ ROM_REGION( 0x04000, "maincpu", 0 ) \ @@ -667,8 +702,8 @@ ROM_END #define KOV2NL_INTERNAL_CHINA \ ROM_REGION( 0x04000, "maincpu", 0 ) \ ROM_LOAD( "gsyx_igs036_china.rom", 0x00000000, 0x0004000, CRC(e09fe4ce) SHA1(c0cac64ef8727cbe79d503ec4df66ddb6f2c925e) ) \ - ROM_REGION( 0x100, "default_card", 0 ) \ - ROM_LOAD( "blank_kov2nl_china_card.pg2", 0x000, 0x100, CRC(91786244) SHA1(ac0ce11b46c19ffe21f6b94bc83ef061f547b591) ) + ROM_REGION( 0x108, "default_card", 0 ) \ + ROM_LOAD( "blank_kov2nl_china_card.pg2", 0x000, 0x108, CRC(02842ae8) SHA1(a6cda633b09a706039a79b73db2c258094826f85) ) ROM_START( kov2nl ) diff --git a/src/mame/machine/pgm2_memcard.cpp b/src/mame/machine/pgm2_memcard.cpp index 73755409294..549a8e5aa79 100644 --- a/src/mame/machine/pgm2_memcard.cpp +++ b/src/mame/machine/pgm2_memcard.cpp @@ -5,7 +5,7 @@ pgm2_memcard.cpp PGM2 Memory card functions. - (based on ng_memcard.cpp) + Presumable Siemens SLE 4442 or compatible. *********************************************************************/ @@ -45,25 +45,36 @@ void pgm2_memcard_device::device_start() image_init_result pgm2_memcard_device::call_load() { - if(length() != 0x100) + authenticated = false; + if(length() != 0x108) return image_init_result::FAIL; fseek(0, SEEK_SET); size_t ret = fread(m_memcard_data, 0x100); if(ret != 0x100) return image_init_result::FAIL; + ret = fread(m_protection_data, 4); + if (ret != 4) + return image_init_result::FAIL; + ret = fread(m_security_data, 4); + if (ret != 4) + return image_init_result::FAIL; return image_init_result::PASS; } void pgm2_memcard_device::call_unload() { + authenticated = false; fseek(0, SEEK_SET); fwrite(m_memcard_data, 0x100); + fwrite(m_protection_data, 4); + fwrite(m_security_data, 4); } image_init_result pgm2_memcard_device::call_create(int format_type, util::option_resolution *format_options) { + authenticated = false; // cards must contain valid defaults for each game / region or they don't work? memory_region *rgn = memregion("^default_card"); @@ -71,14 +82,28 @@ image_init_result pgm2_memcard_device::call_create(int format_type, util::option return image_init_result::FAIL; memcpy(m_memcard_data, rgn->base(), 0x100); + memcpy(m_protection_data, rgn->base() + 0x100, 4); + memcpy(m_security_data, rgn->base() + 0x104, 4); - size_t ret = fwrite(m_memcard_data, 0x100); - if(ret != 0x100) + size_t ret = fwrite(rgn->base(), 0x108); + if(ret != 0x108) return image_init_result::FAIL; return image_init_result::PASS; } +void pgm2_memcard_device::auth(uint8_t p1, uint8_t p2, uint8_t p3) +{ + if (m_security_data[0] & 3) + { + if (m_security_data[1] == p1 && m_security_data[2] == p2 && m_security_data[3] == p3) + authenticated = true; + else { + m_security_data[0] >>= 1; // hacky + logerror("Wrong IC Card password !!!"); + } + } +} READ8_MEMBER(pgm2_memcard_device::read) { @@ -87,5 +112,32 @@ READ8_MEMBER(pgm2_memcard_device::read) WRITE8_MEMBER(pgm2_memcard_device::write) { - m_memcard_data[offset] = data; + if (authenticated && (offset >= 0x20 || (m_protection_data[offset>>3] & (1 <<(offset & 7))))) + { + m_memcard_data[offset] = data; + } +} + +READ8_MEMBER(pgm2_memcard_device::read_prot) +{ + return m_protection_data[offset]; +} + +WRITE8_MEMBER(pgm2_memcard_device::write_prot) +{ + if (authenticated) + m_protection_data[offset] &= data; +} + +READ8_MEMBER(pgm2_memcard_device::read_sec) +{ + if (!authenticated) + return 0xff; // guess + return m_security_data[offset]; +} + +WRITE8_MEMBER(pgm2_memcard_device::write_sec) +{ + if (authenticated) + m_security_data[offset] = data; } diff --git a/src/mame/machine/pgm2_memcard.h b/src/mame/machine/pgm2_memcard.h index 0aa4d2adb04..175abe2d4fb 100644 --- a/src/mame/machine/pgm2_memcard.h +++ b/src/mame/machine/pgm2_memcard.h @@ -52,11 +52,19 @@ public: DECLARE_READ8_MEMBER(read); DECLARE_WRITE8_MEMBER(write); + DECLARE_READ8_MEMBER(read_prot); + DECLARE_WRITE8_MEMBER(write_prot); + DECLARE_READ8_MEMBER(read_sec); + DECLARE_WRITE8_MEMBER(write_sec); + void auth(uint8_t p1, uint8_t p2, uint8_t p3); /* returns the index of the current memory card, or -1 if none */ int present() { return is_loaded() ? 0 : -1; } private: uint8_t m_memcard_data[0x100]; + uint8_t m_protection_data[4]; + uint8_t m_security_data[4]; + bool authenticated; };