mirror of
https://github.com/holub/mame
synced 2025-06-06 12:53:46 +03:00
gameboy: more updates to the cart emulation [Tauwasser]
- fixed some MBC1, MBC2 details - added MMM01 notes on registers - fixed Sachen MMC1 implementation so that Sachen logo is properly displayed - started work on the emulation of Sachen MMC2 mapper
This commit is contained in:
parent
5ba57c6cde
commit
05ac233c0a
@ -23524,6 +23524,18 @@ These were produced between 2000 and 2001 by Rocket Games, run by Datel Design
|
|||||||
</part>
|
</part>
|
||||||
</software>
|
</software>
|
||||||
|
|
||||||
|
<software name="4in1_01c">
|
||||||
|
<description>4 in 1 (4B-001)</description>
|
||||||
|
<year>20??</year>
|
||||||
|
<publisher>Sachen</publisher>
|
||||||
|
<part name="cart" interface="gameboy_cart">
|
||||||
|
<feature name="slot" value="rom_sachen1" />
|
||||||
|
<dataarea name="rom" size="524288">
|
||||||
|
<rom name="4b-001.gbc" size="524288" crc="42a2fdf8" sha1="79a4faddfd1aca397e56d7895e45b1bc12900dab" offset="000000" />
|
||||||
|
</dataarea>
|
||||||
|
</part>
|
||||||
|
</software>
|
||||||
|
|
||||||
<software name="mc_8in1">
|
<software name="mc_8in1">
|
||||||
<description>8 in 1 (Tw)</description>
|
<description>8 in 1 (Tw)</description>
|
||||||
<year>19??</year>
|
<year>19??</year>
|
||||||
|
@ -26,8 +26,8 @@ const device_type GB_ROM_MBC6 = &device_creator<gb_rom_mbc6_device>;
|
|||||||
const device_type GB_ROM_MBC7 = &device_creator<gb_rom_mbc7_device>;
|
const device_type GB_ROM_MBC7 = &device_creator<gb_rom_mbc7_device>;
|
||||||
const device_type GB_ROM_M161_M12 = &device_creator<gb_rom_m161_device>;
|
const device_type GB_ROM_M161_M12 = &device_creator<gb_rom_m161_device>;
|
||||||
const device_type GB_ROM_MMM01 = &device_creator<gb_rom_mmm01_device>;
|
const device_type GB_ROM_MMM01 = &device_creator<gb_rom_mmm01_device>;
|
||||||
const device_type GB_ROM_SACHEN1 = &device_creator<gb_rom_sachen1_device>;
|
const device_type GB_ROM_SACHEN1 = &device_creator<gb_rom_sachen_mmc1_device>;
|
||||||
const device_type GB_ROM_SACHEN2 = &device_creator<gb_rom_sachen1_device>; // Just a placeholder for the moment...
|
const device_type GB_ROM_SACHEN2 = &device_creator<gb_rom_sachen_mmc2_device>;
|
||||||
const device_type GB_ROM_188IN1 = &device_creator<gb_rom_188in1_device>;
|
const device_type GB_ROM_188IN1 = &device_creator<gb_rom_188in1_device>;
|
||||||
const device_type GB_ROM_SINTAX = &device_creator<gb_rom_sintax_device>;
|
const device_type GB_ROM_SINTAX = &device_creator<gb_rom_sintax_device>;
|
||||||
const device_type GB_ROM_CHONGWU = &device_creator<gb_rom_chongwu_device>;
|
const device_type GB_ROM_CHONGWU = &device_creator<gb_rom_chongwu_device>;
|
||||||
@ -97,8 +97,18 @@ gb_rom_mmm01_device::gb_rom_mmm01_device(const machine_config &mconfig, const ch
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_rom_sachen1_device::gb_rom_sachen1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
gb_rom_sachen_mmc1_device::gb_rom_sachen_mmc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||||
: gb_rom_mbc1_device(mconfig, GB_ROM_SACHEN1, "GB Sachen MMC1 Carts", tag, owner, clock, "gb_rom_sachen1", __FILE__)
|
: gb_rom_mbc_device(mconfig, GB_ROM_SACHEN1, "GB Sachen MMC1 Carts", tag, owner, clock, "gb_rom_sachen1", __FILE__)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_rom_sachen_mmc1_device::gb_rom_sachen_mmc1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
|
||||||
|
: gb_rom_mbc_device(mconfig, type, name, tag, owner, clock, shortname, source)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_rom_sachen_mmc2_device::gb_rom_sachen_mmc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||||
|
: gb_rom_sachen_mmc1_device(mconfig, GB_ROM_SACHEN2, "GB Sachen MMC2 Carts", tag, owner, clock, "gb_rom_sachen2", __FILE__)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,18 +243,40 @@ void gb_rom_mmm01_device::device_reset()
|
|||||||
m_reg = 0;
|
m_reg = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gb_rom_sachen1_device::device_start()
|
void gb_rom_sachen_mmc1_device::device_start()
|
||||||
{
|
{
|
||||||
shared_start();
|
shared_start();
|
||||||
save_item(NAME(m_base_bank));
|
save_item(NAME(m_base_bank));
|
||||||
save_item(NAME(m_mask));
|
save_item(NAME(m_mask));
|
||||||
|
save_item(NAME(m_mode));
|
||||||
|
save_item(NAME(m_unlock_cnt));
|
||||||
}
|
}
|
||||||
|
|
||||||
void gb_rom_sachen1_device::device_reset()
|
void gb_rom_sachen_mmc1_device::device_reset()
|
||||||
{
|
{
|
||||||
shared_reset();
|
shared_reset();
|
||||||
m_base_bank = 0;
|
m_base_bank = 0x00;
|
||||||
m_mask = 0;
|
m_mask = 0x00;
|
||||||
|
m_mode = MODE_LOCKED;
|
||||||
|
m_unlock_cnt = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gb_rom_sachen_mmc2_device::device_start()
|
||||||
|
{
|
||||||
|
shared_start();
|
||||||
|
save_item(NAME(m_base_bank));
|
||||||
|
save_item(NAME(m_mask));
|
||||||
|
save_item(NAME(m_mode));
|
||||||
|
save_item(NAME(m_unlock_cnt));
|
||||||
|
}
|
||||||
|
|
||||||
|
void gb_rom_sachen_mmc2_device::device_reset()
|
||||||
|
{
|
||||||
|
shared_reset();
|
||||||
|
m_base_bank = 0x00;
|
||||||
|
m_mask = 0x00;
|
||||||
|
m_mode = MODE_LOCKED_DMG;
|
||||||
|
m_unlock_cnt = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gb_rom_sintax_device::device_start()
|
void gb_rom_sintax_device::device_start()
|
||||||
@ -310,18 +342,18 @@ WRITE8_MEMBER(gb_rom_mbc_device::write_ram)
|
|||||||
|
|
||||||
READ8_MEMBER(gb_rom_mbc1_device::read_rom)
|
READ8_MEMBER(gb_rom_mbc1_device::read_rom)
|
||||||
{
|
{
|
||||||
if (offset < 0x4000)
|
if (offset & 0x4000) /* RB1 */
|
||||||
{
|
return m_rom[rom_bank_map[(m_ram_bank << (5 + m_shift)) | m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
||||||
|
else
|
||||||
|
{ /* RB0 */
|
||||||
int bank = (m_mode == MODE_4M_256k) ? (m_ram_bank << (5 + m_shift)) : 0;
|
int bank = (m_mode == MODE_4M_256k) ? (m_ram_bank << (5 + m_shift)) : 0;
|
||||||
return m_rom[rom_bank_map[bank] * 0x4000 + (offset & 0x3fff)];
|
return m_rom[rom_bank_map[bank] * 0x4000 + (offset & 0x3fff)];
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return m_rom[rom_bank_map[(m_ram_bank << (5 + m_shift)) | m_latch_bank2] * 0x4000 + (offset & 0x3fff)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WRITE8_MEMBER(gb_rom_mbc1_device::write_bank)
|
WRITE8_MEMBER(gb_rom_mbc1_device::write_bank)
|
||||||
{
|
{
|
||||||
// the mapper only uses inputs A13-A15
|
// the mapper only uses inputs A15..A13
|
||||||
switch (offset & 0xe000)
|
switch (offset & 0xe000)
|
||||||
{
|
{
|
||||||
case 0x0000: // RAM Enable Register
|
case 0x0000: // RAM Enable Register
|
||||||
@ -395,7 +427,7 @@ WRITE8_MEMBER(gb_rom_mbc2_device::write_bank)
|
|||||||
READ8_MEMBER(gb_rom_mbc2_device::read_ram)
|
READ8_MEMBER(gb_rom_mbc2_device::read_ram)
|
||||||
{
|
{
|
||||||
if (!m_ram.empty() && m_ram_enable)
|
if (!m_ram.empty() && m_ram_enable)
|
||||||
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)];
|
return m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x01ff)] | 0xF0;
|
||||||
else
|
else
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
@ -403,7 +435,7 @@ READ8_MEMBER(gb_rom_mbc2_device::read_ram)
|
|||||||
WRITE8_MEMBER(gb_rom_mbc2_device::write_ram)
|
WRITE8_MEMBER(gb_rom_mbc2_device::write_ram)
|
||||||
{
|
{
|
||||||
if (!m_ram.empty() && m_ram_enable)
|
if (!m_ram.empty() && m_ram_enable)
|
||||||
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x1fff)] = data;
|
m_ram[ram_bank_map[m_ram_bank] * 0x2000 + (offset & 0x01ff)] = data & 0x0F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -661,6 +693,14 @@ WRITE8_MEMBER(gb_rom_m161_device::write_bank)
|
|||||||
|
|
||||||
// MMM01
|
// MMM01
|
||||||
// This mmm01 implementation is mostly guess work, no clue how correct it all is
|
// This mmm01 implementation is mostly guess work, no clue how correct it all is
|
||||||
|
/* TODO: This implementation is wrong. Tauwasser
|
||||||
|
*
|
||||||
|
* Register 0: Map Latch, AA Mask, RAM Enable
|
||||||
|
* Register 1: EA1..EA0, RA18..RA14
|
||||||
|
* Register 2: ??, AA18..AA15, AA14..AA13
|
||||||
|
* Register 3: AA Multiplex, RA Mask, ???, MBC1 Mode
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
READ8_MEMBER(gb_rom_mmm01_device::read_rom)
|
READ8_MEMBER(gb_rom_mmm01_device::read_rom)
|
||||||
{
|
{
|
||||||
@ -704,37 +744,140 @@ WRITE8_MEMBER(gb_rom_mmm01_device::write_bank)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Sachen MMC1
|
// Sachen MMC1
|
||||||
|
|
||||||
READ8_MEMBER(gb_rom_sachen1_device::read_rom)
|
READ8_MEMBER(gb_rom_sachen_mmc1_device::read_rom)
|
||||||
{
|
{
|
||||||
if (offset < 0x4000)
|
|
||||||
return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank & ~m_mask)] * 0x4000 + (offset & 0x3fff)];
|
UINT16 off_edit = offset;
|
||||||
|
|
||||||
|
/* Wait for 0x31 transitions of A15 (hi -> lo), i.e. ROM accesses; A15 = HI while in bootstrap */
|
||||||
|
/* This is 0x31 transitions, because we increment counter _after_ checking it */
|
||||||
|
if (m_unlock_cnt == 0x30)
|
||||||
|
m_mode = MODE_UNLOCKED;
|
||||||
else
|
else
|
||||||
|
m_unlock_cnt++;
|
||||||
|
|
||||||
|
/* Logo Switch */
|
||||||
|
if (m_mode == MODE_LOCKED)
|
||||||
|
off_edit |= 0x80;
|
||||||
|
|
||||||
|
/* Header Un-Scramble */
|
||||||
|
if ((off_edit & 0xFF00) == 0x0100) {
|
||||||
|
off_edit &= 0xFFAC;
|
||||||
|
off_edit |= ((offset >> 6) & 0x01) << 0;
|
||||||
|
off_edit |= ((offset >> 4) & 0x01) << 1;
|
||||||
|
off_edit |= ((offset >> 1) & 0x01) << 4;
|
||||||
|
off_edit |= ((offset >> 0) & 0x01) << 6;
|
||||||
|
}
|
||||||
|
//logerror("read from %04X (%04X)\n", offset, off_edit);
|
||||||
|
|
||||||
|
if (offset & 0x4000) /* RB1 */
|
||||||
return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask)] * 0x4000 + (offset & 0x3fff)];
|
return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask)] * 0x4000 + (offset & 0x3fff)];
|
||||||
|
else /* RB0 */
|
||||||
|
return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank & ~m_mask)] * 0x4000 + (off_edit & 0x3fff)];
|
||||||
}
|
}
|
||||||
|
|
||||||
WRITE8_MEMBER(gb_rom_sachen1_device::write_bank)
|
WRITE8_MEMBER(gb_rom_sachen_mmc1_device::write_bank)
|
||||||
{
|
{
|
||||||
if (offset < 0x2000) // Base ROM Bank register
|
|
||||||
|
/* Only A15..A6, A4, A1..A0 are connected */
|
||||||
|
/* We only decode upper three bits */
|
||||||
|
switch ((offset & 0xFFD3) & 0xE000)
|
||||||
{
|
{
|
||||||
if ((m_latch_bank2 & 0x30) == 0x30 && data)
|
case 0x0000: /* Base ROM Bank Register */
|
||||||
m_base_bank = data & 0x0f;
|
|
||||||
|
if ((m_latch_bank2 & 0x30) == 0x30)
|
||||||
|
m_base_bank = data;
|
||||||
//logerror("write to base bank %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
|
//logerror("write to base bank %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
|
||||||
}
|
break;
|
||||||
else if (offset < 0x4000) // ROM Bank Register
|
|
||||||
{
|
case 0x2000: /* ROM Bank Register */
|
||||||
m_latch_bank2 = data ? data : 1;
|
|
||||||
|
m_latch_bank2 = data ? data : 0x01;
|
||||||
//logerror("write to latch %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
|
//logerror("write to latch %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
|
||||||
}
|
break;
|
||||||
else if (offset < 0x6000) // ROM bank mask register
|
|
||||||
{
|
case 0x4000: /* ROM Bank Mask Register */
|
||||||
|
|
||||||
if ((m_latch_bank2 & 0x30) == 0x30)
|
if ((m_latch_bank2 & 0x30) == 0x30)
|
||||||
m_mask = data;
|
m_mask = data;
|
||||||
//logerror("write to mask %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
|
//logerror("write to mask %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x6000:
|
||||||
|
|
||||||
|
/* nothing happens when writing to 0x6000-0x7fff, as verified by Tauwasser */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
//logerror("write to unknown/unmapped area %04X <= %02X\n", offset, data);
|
||||||
|
/* did not extensively test other unlikely ranges */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// nothing happens when writing to 0x6000-0x7fff, as verified by Tauwasser
|
}
|
||||||
|
|
||||||
|
// Sachen MMC2
|
||||||
|
|
||||||
|
READ8_MEMBER(gb_rom_sachen_mmc2_device::read_rom)
|
||||||
|
{
|
||||||
|
|
||||||
|
UINT16 off_edit = offset;
|
||||||
|
|
||||||
|
/* Wait for 0x30 transitions of A15 (lo -> hi), i.e. ROM accesses; A15 = HI while in bootstrap */
|
||||||
|
/* This is 0x30 transitions, because we increment counter _after_ checking it, but A15 lo -> hi*/
|
||||||
|
/* transition means first read (hi -> lo transition) must not count */
|
||||||
|
|
||||||
|
if (m_unlock_cnt == 0x30 && m_mode == MODE_LOCKED_DMG) {
|
||||||
|
m_mode = MODE_LOCKED_CGB;
|
||||||
|
m_unlock_cnt = 0x00;
|
||||||
|
} else if (m_unlock_cnt == 0x30 && m_mode == MODE_LOCKED_CGB) {
|
||||||
|
m_mode = MODE_UNLOCKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_unlock_cnt != 0x30)
|
||||||
|
m_unlock_cnt++;
|
||||||
|
|
||||||
|
/* Logo Switch */
|
||||||
|
if (m_mode == MODE_LOCKED_CGB)
|
||||||
|
off_edit |= 0x80;
|
||||||
|
|
||||||
|
/* Header Un-Scramble */
|
||||||
|
if ((off_edit & 0xFF00) == 0x0100) {
|
||||||
|
off_edit &= 0xFFAC;
|
||||||
|
off_edit |= ((offset >> 6) & 0x01) << 0;
|
||||||
|
off_edit |= ((offset >> 4) & 0x01) << 1;
|
||||||
|
off_edit |= ((offset >> 1) & 0x01) << 4;
|
||||||
|
off_edit |= ((offset >> 0) & 0x01) << 6;
|
||||||
|
}
|
||||||
|
//logerror("read from %04X (%04X) cnt: %02X\n", offset, off_edit, m_unlock_cnt);
|
||||||
|
|
||||||
|
if (offset & 0x4000) /* RB1 */
|
||||||
|
return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask)] * 0x4000 + (offset & 0x3fff)];
|
||||||
|
else /* RB0 */
|
||||||
|
return m_rom[rom_bank_map[(m_base_bank & m_mask) | (m_latch_bank & ~m_mask)] * 0x4000 + (off_edit & 0x3fff)];
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8_MEMBER(gb_rom_sachen_mmc2_device::read_ram)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (m_mode == MODE_LOCKED_DMG) {
|
||||||
|
m_unlock_cnt = 0x00;
|
||||||
|
m_mode = MODE_LOCKED_CGB;
|
||||||
|
}
|
||||||
|
return 0xFF;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE8_MEMBER(gb_rom_sachen_mmc2_device::write_ram)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (m_mode == MODE_LOCKED_DMG) {
|
||||||
|
m_unlock_cnt = 0x00;
|
||||||
|
m_mode = MODE_LOCKED_CGB;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,14 +191,20 @@ public:
|
|||||||
UINT8 m_bank_mask, m_bank, m_reg;
|
UINT8 m_bank_mask, m_bank, m_reg;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ======================> gb_rom_sachen1_device
|
// ======================> gb_rom_sachen_mmc1_device
|
||||||
|
|
||||||
class gb_rom_sachen1_device : public gb_rom_mbc1_device
|
class gb_rom_sachen_mmc1_device : public gb_rom_mbc_device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MODE_LOCKED,
|
||||||
|
MODE_UNLOCKED
|
||||||
|
};
|
||||||
|
|
||||||
// construction/destruction
|
// construction/destruction
|
||||||
gb_rom_sachen1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
gb_rom_sachen_mmc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||||
|
gb_rom_sachen_mmc1_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
|
||||||
|
|
||||||
// device-level overrides
|
// device-level overrides
|
||||||
virtual void device_start();
|
virtual void device_start();
|
||||||
@ -209,7 +215,32 @@ public:
|
|||||||
virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; }
|
virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; }
|
||||||
virtual DECLARE_WRITE8_MEMBER(write_ram) { }
|
virtual DECLARE_WRITE8_MEMBER(write_ram) { }
|
||||||
|
|
||||||
UINT8 m_base_bank, m_mask;
|
UINT8 m_base_bank, m_mask, m_mode, m_unlock_cnt;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ======================> gb_rom_sachen_mmc2_device
|
||||||
|
|
||||||
|
class gb_rom_sachen_mmc2_device : public gb_rom_sachen_mmc1_device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MODE_LOCKED_DMG,
|
||||||
|
MODE_LOCKED_CGB,
|
||||||
|
MODE_UNLOCKED
|
||||||
|
};
|
||||||
|
|
||||||
|
// construction/destruction
|
||||||
|
gb_rom_sachen_mmc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||||
|
|
||||||
|
// device-level overrides
|
||||||
|
virtual void device_start();
|
||||||
|
virtual void device_reset();
|
||||||
|
|
||||||
|
virtual DECLARE_READ8_MEMBER(read_rom);
|
||||||
|
virtual DECLARE_READ8_MEMBER(read_ram);
|
||||||
|
virtual DECLARE_WRITE8_MEMBER(write_ram);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ======================> gb_rom_188in1_device
|
// ======================> gb_rom_188in1_device
|
||||||
|
Loading…
Reference in New Issue
Block a user