pgm2: memcard reader now uses image_device stuff, cards can be inserted / removed and get saved [Metallic, David Haywood]

promoted China set of Oriental Legend 2 to working
promoted Knights of Valour 2 New Legend to working

as each game/region requires a valid default card in order to save said cards are part of romset.

(there's probably a cleaner way to do the device finder stuff but I forgot and can't find reference)
This commit is contained in:
David Haywood 2017-12-11 15:11:26 +00:00
parent afcba799fc
commit caed83833c
5 changed files with 224 additions and 43 deletions

View File

@ -1950,6 +1950,8 @@ files {
MAME_DIR .. "src/mame/drivers/pgm2.cpp",
MAME_DIR .. "src/mame/video/pgm2.cpp",
MAME_DIR .. "src/mame/includes/pgm2.h",
MAME_DIR .. "src/mame/machine/pgm2_memcard.cpp",
MAME_DIR .. "src/mame/machine/pgm2_memcard.h",
MAME_DIR .. "src/mame/drivers/pgm3.cpp",
MAME_DIR .. "src/mame/drivers/spoker.cpp",
MAME_DIR .. "src/mame/machine/igs036crypt.cpp",

View File

@ -144,26 +144,14 @@ TIMER_DEVICE_CALLBACK_MEMBER(pgm2_state::igs_interrupt2)
m_arm_aic->set_irq(0x46);
}
static const uint8_t orleg2_china_card[32] = {
0xA2, 0x13, 0x10, 0x91, 0x05, 0x0C, 0x81, 0x15, 0x10, 0x00, 0x00, 0x03, 0x00, 0x49, 0x47, 0x53,
0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x76, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#ifdef UNUSED_DEFINITION
static const uint8_t kov2nl_china_card[32] = {
0xA2, 0x13, 0x10, 0x91, 0x05, 0x0C, 0x81, 0x15, 0x06, 0x00, 0x00, 0x04, 0x00, 0x49, 0x47, 0x53,
0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x76, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif
// "MPU" MCU HLE starts here
// TODO: make data cards using image_interface
// command delays is far not correct, might not work in other games
// command results probably either incorrect (except for explicit checked bytes)
void pgm2_state::mcu_command(bool is_command)
// command delays are far from correct, might not work in other games
// command results probably incorrect (except for explicit checked bytes)
void pgm2_state::mcu_command(address_space &space, bool is_command)
{
uint8_t cmd = m_mcu_regs[0] & 0xff;
// if (is_command && cmd != 0xf6)
// logerror("MCU command %08x %08x\n", m_mcu_regs[0], m_mcu_regs[1]);
// if (is_command && cmd != 0xf6)
// logerror("MCU command %08x %08x\n", m_mcu_regs[0], m_mcu_regs[1]);
if (is_command)
{
@ -199,11 +187,11 @@ void pgm2_state::mcu_command(bool is_command)
m_mcu_result0 = cmd;
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)
break;
// unknown / unimplemented, all C0-C9 commands is IC Card RW related
// (m_mcu_regs[0] >> 8) & 0xff - target RW unit (player)
case 0xc0: // insert card or/and check card presence. result: F7 - ok, F4 - no card
if (!m_have_card[arg1])
if (m_memcard_device[arg1 & 3]->present() == -1)
status = 0xf4;
m_mcu_result0 = cmd;
break;
@ -211,11 +199,20 @@ void pgm2_state::mcu_command(bool is_command)
m_mcu_result0 = cmd;
break;
case 0xc2: // read data to shared ram, args - offset, len
memcpy(&m_shareram[(~m_share_bank & 1) * 128], &m_card_data[arg1][arg2], arg3);
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);
}
m_mcu_result0 = cmd;
break;
case 0xc3: // save data from shared ram, args - offset, len
memcpy(&m_card_data[arg1][arg2], &m_shareram[(~m_share_bank & 1) * 128], arg3);
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]);
}
m_mcu_result0 = cmd;
break;
case 0xc7: // get card ID?, no args, result1 expected to be fixed value for new card
@ -223,7 +220,9 @@ void pgm2_state::mcu_command(bool is_command)
m_mcu_result0 = cmd;
break;
case 0xc8: // write byte, args - offset, data byte
m_card_data[arg1][arg2] = arg3;
if (m_memcard_device[arg1 & 3]->present() != -1)
m_memcard_device[arg1 & 3]->write(space, arg2, arg3);
m_mcu_result0 = cmd;
break;
case 0xc4: // not used
@ -262,9 +261,9 @@ WRITE32_MEMBER(pgm2_state::mcu_w)
COMBINE_DATA(&m_mcu_regs[reg]);
if (reg == 2 && m_mcu_regs[2]) // irq to mcu
mcu_command(true);
mcu_command(space, true);
if (reg == 5 && m_mcu_regs[5]) // ack to mcu (written at the end of irq handler routine)
mcu_command(false);
mcu_command(space, false);
}
static ADDRESS_MAP_START( pgm2_map, AS_PROGRAM, 32, pgm2_state )
@ -428,6 +427,11 @@ void pgm2_state::machine_start()
save_item(NAME(m_mcu_last_cmd));
save_item(NAME(m_shareram));
save_item(NAME(m_share_bank));
m_memcard_device[0] = m_memcard0;
m_memcard_device[1] = m_memcard1;
m_memcard_device[2] = m_memcard2;
m_memcard_device[3] = m_memcard3;
}
void pgm2_state::machine_reset()
@ -436,11 +440,6 @@ void pgm2_state::machine_reset()
m_realspritekey = 0;
m_mcu_last_cmd = 0;
m_share_bank = 0;
m_have_card[0] = true;
m_have_card[1] = m_have_card[2] = m_have_card[3] = false;
memcpy(m_card_data[0], orleg2_china_card, sizeof(orleg2_china_card));
// memcpy(m_card_data[0], kov2nl_china_card, sizeof(kov2nl_china_card));
}
static const gfx_layout tiles8x8_layout =
@ -516,6 +515,13 @@ static MACHINE_CONFIG_START( pgm2 )
MCFG_YMZ774_ADD("ymz774", 16384000) // is clock correct ?
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)
MCFG_SOUND_ROUTE(1, "rspeaker", 1.0)
MCFG_PGM2_MEMCARD_ADD("memcard_p1")
MCFG_PGM2_MEMCARD_ADD("memcard_p2")
MCFG_PGM2_MEMCARD_ADD("memcard_p3")
MCFG_PGM2_MEMCARD_ADD("memcard_p4")
MACHINE_CONFIG_END
/* using macros for the video / sound roms because the locations never change between sets, and
@ -578,7 +584,9 @@ MACHINE_CONFIG_END
#define ORLEG2_INTERNAL_CHINA \
ROM_REGION( 0x04000, "maincpu", 0 ) \
ROM_LOAD( "xyj2_cn.igs036", 0x00000000, 0x0004000, CRC(bcce7641) SHA1(c3b5cf6e9f6eae09b6785314777a52b34c3c7657) )
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) )
#define ORLEG2_INTERNAL_OVERSEAS \
ROM_REGION( 0x04000, "maincpu", 0 ) \
@ -658,7 +666,10 @@ ROM_END
#define KOV2NL_INTERNAL_CHINA \
ROM_REGION( 0x04000, "maincpu", 0 ) \
ROM_LOAD( "gsyx_igs036_china.rom", 0x00000000, 0x0004000, CRC(e09fe4ce) SHA1(c0cac64ef8727cbe79d503ec4df66ddb6f2c925e) )
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_START( kov2nl )
KOV2NL_INTERNAL_CHINA
@ -1024,14 +1035,14 @@ GAME( 2007, orleg2, 0, pgm2, pgm2, pgm2_state, orleg2,
GAME( 2007, orleg2_103, orleg2, pgm2, pgm2, pgm2_state, orleg2, ROT0, "IGS", "Oriental Legend 2 (V103, Oversea)", 0 )
GAME( 2007, orleg2_101, orleg2, pgm2, pgm2, pgm2_state, orleg2, ROT0, "IGS", "Oriental Legend 2 (V101, Oversea)", 0 )
GAME( 2007, orleg2_104cn, orleg2, pgm2, pgm2, pgm2_state, orleg2, ROT0, "IGS", "Oriental Legend 2 (V104, China)", MACHINE_NOT_WORKING )
GAME( 2007, orleg2_103cn, orleg2, pgm2, pgm2, pgm2_state, orleg2, ROT0, "IGS", "Oriental Legend 2 (V103, China)", MACHINE_NOT_WORKING )
GAME( 2007, orleg2_101cn, orleg2, pgm2, pgm2, pgm2_state, orleg2, ROT0, "IGS", "Oriental Legend 2 (V101, China)", MACHINE_NOT_WORKING )
GAME( 2007, orleg2_104cn, orleg2, pgm2, pgm2, pgm2_state, orleg2, ROT0, "IGS", "Oriental Legend 2 (V104, China)", 0 )
GAME( 2007, orleg2_103cn, orleg2, pgm2, pgm2, pgm2_state, orleg2, ROT0, "IGS", "Oriental Legend 2 (V103, China)", 0 )
GAME( 2007, orleg2_101cn, orleg2, pgm2, pgm2, pgm2_state, orleg2, ROT0, "IGS", "Oriental Legend 2 (V101, China)", 0 )
// Knights of Valour 2 New Legend
GAME( 2008, kov2nl, 0, pgm2, pgm2, pgm2_state, kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend (V302, China)", MACHINE_NOT_WORKING )
GAME( 2008, kov2nl_301, kov2nl, pgm2, pgm2, pgm2_state, kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend (V301, China)", MACHINE_NOT_WORKING )
GAME( 2008, kov2nl_300, kov2nl, pgm2, pgm2, pgm2_state, kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend (V300, China)", MACHINE_NOT_WORKING ) // was dumped from a Taiwan board tho
GAME( 2008, kov2nl, 0, pgm2, pgm2, pgm2_state, kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend (V302, China)", 0 )
GAME( 2008, kov2nl_301, kov2nl, pgm2, pgm2, pgm2_state, kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend (V301, China)", 0 )
GAME( 2008, kov2nl_300, kov2nl, pgm2, pgm2, pgm2_state, kov2nl, ROT0, "IGS", "Knights of Valour 2 New Legend (V300, China)", 0 ) // was dumped from a Taiwan board tho
// Dodonpachi Daioujou Tamashii - should be a V200 too
GAME( 2010, ddpdojh, 0, pgm2, pgm2, pgm2_state, ddpdojh, ROT270, "IGS", "Dodonpachi Daioujou Tamashii (V201, China)", MACHINE_NOT_WORKING )

View File

@ -16,6 +16,7 @@
#include "machine/nvram.h"
#include "machine/timer.h"
#include "machine/atmel_arm_aic.h"
#include "machine/pgm2_memcard.h"
class pgm2_state : public driver_device
{
@ -39,7 +40,11 @@ public:
m_sp_palette(*this, "sp_palette"),
m_bg_palette(*this, "bg_palette"),
m_tx_palette(*this, "tx_palette"),
m_mcu_timer(*this, "mcu_timer")
m_mcu_timer(*this, "mcu_timer"),
m_memcard0(*this, "memcard_p1"),
m_memcard1(*this, "memcard_p2"),
m_memcard2(*this, "memcard_p3"),
m_memcard3(*this, "memcard_p4")
{ }
DECLARE_READ32_MEMBER(unk_startup_r);
@ -116,9 +121,7 @@ private:
uint32_t m_mcu_result0;
uint32_t m_mcu_result1;
uint8_t m_mcu_last_cmd;
void mcu_command(bool is_command);
uint8_t m_card_data[4][0x100];
bool m_have_card[4];
void mcu_command(address_space &space, bool is_command);
// devices
required_device<cpu_device> m_maincpu;
@ -139,6 +142,13 @@ private:
required_device<palette_device> m_bg_palette;
required_device<palette_device> m_tx_palette;
required_device<timer_device> m_mcu_timer;
optional_device<pgm2_memcard_device> m_memcard0;
optional_device<pgm2_memcard_device> m_memcard1;
optional_device<pgm2_memcard_device> m_memcard2;
optional_device<pgm2_memcard_device> m_memcard3;
pgm2_memcard_device *m_memcard_device[4];
};
#endif

View File

@ -0,0 +1,91 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood, Miodrag Milanovic
/*********************************************************************
pgm2_memcard.cpp
PGM2 Memory card functions.
(based on ng_memcard.cpp)
*********************************************************************/
#include "emu.h"
#include "emuopts.h"
#include "pgm2_memcard.h"
// device type definition
DEFINE_DEVICE_TYPE(PGM2_MEMCARD, pgm2_memcard_device, "pgm2_memcard", "PGM2 Memory Card")
//-------------------------------------------------
// pgm2_memcard_device - constructor
//-------------------------------------------------
pgm2_memcard_device::pgm2_memcard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PGM2_MEMCARD, tag, owner, clock)
, device_image_interface(mconfig, *this)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void pgm2_memcard_device::device_start()
{
save_item(NAME(m_memcard_data));
}
/*-------------------------------------------------
memcard_insert - insert an existing memory card
with the given index
-------------------------------------------------*/
image_init_result pgm2_memcard_device::call_load()
{
if(length() != 0x100)
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;
return image_init_result::PASS;
}
void pgm2_memcard_device::call_unload()
{
fseek(0, SEEK_SET);
fwrite(m_memcard_data, 0x100);
}
image_init_result pgm2_memcard_device::call_create(int format_type, util::option_resolution *format_options)
{
// cards must contain valid defaults for each game / region or they don't work?
memory_region *rgn = memregion("^default_card");
if (!rgn)
return image_init_result::FAIL;
memcpy(m_memcard_data, rgn->base(), 0x100);
size_t ret = fwrite(m_memcard_data, 0x100);
if(ret != 0x100)
return image_init_result::FAIL;
return image_init_result::PASS;
}
READ8_MEMBER(pgm2_memcard_device::read)
{
return m_memcard_data[offset];
}
WRITE8_MEMBER(pgm2_memcard_device::write)
{
m_memcard_data[offset] = data;
}

View File

@ -0,0 +1,67 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood, Miodrag Milanovic
/*********************************************************************
pgm2_memcard.h
PGM2 Memory card functions.
(based on ng_memcard.h)
*********************************************************************/
#ifndef MAME_MACHINE_PGM2_MEMCARD_H
#define MAME_MACHINE_PGM2_MEMCARD_H
#pragma once
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_PGM2_MEMCARD_ADD(_tag) \
MCFG_DEVICE_ADD(_tag, PGM2_MEMCARD, 0)
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
// ======================> pgm2_memcard_device
class pgm2_memcard_device : public device_t,
public device_image_interface
{
public:
// construction/destruction
pgm2_memcard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual iodevice_t image_type() const override { return IO_MEMCARD; }
virtual bool is_readable() const override { return true; }
virtual bool is_writeable() const override { return true; }
virtual bool is_creatable() const override { return true; }
virtual bool must_be_loaded() const override { return false; }
virtual bool is_reset_on_load() const override { return false; }
virtual const char *file_extensions() const override { return "pg2,bin,mem"; }
virtual image_init_result call_load() override;
virtual void call_unload() override;
virtual image_init_result call_create(int format_type, util::option_resolution *format_options) override;
// device-level overrides
virtual void device_start() override;
DECLARE_READ8_MEMBER(read);
DECLARE_WRITE8_MEMBER(write);
/* 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];
};
// device type definition
DECLARE_DEVICE_TYPE(PGM2_MEMCARD, pgm2_memcard_device)
#endif // MAME_MACHINE_PGM2_MEMCARD_H