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:
etabeta78 2015-05-21 10:20:40 +02:00
parent 5ba57c6cde
commit 05ac233c0a
3 changed files with 224 additions and 38 deletions

View File

@ -23524,6 +23524,18 @@ These were produced between 2000 and 2001 by Rocket Games, run by Datel Design
</part>
</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">
<description>8 in 1 (Tw)</description>
<year>19??</year>

View File

@ -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_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_SACHEN1 = &device_creator<gb_rom_sachen1_device>;
const device_type GB_ROM_SACHEN2 = &device_creator<gb_rom_sachen1_device>; // Just a placeholder for the moment...
const device_type GB_ROM_SACHEN1 = &device_creator<gb_rom_sachen_mmc1_device>;
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_SINTAX = &device_creator<gb_rom_sintax_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_mbc1_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, const char *tag, device_t *owner, UINT32 clock)
: 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;
}
void gb_rom_sachen1_device::device_start()
void gb_rom_sachen_mmc1_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_sachen1_device::device_reset()
void gb_rom_sachen_mmc1_device::device_reset()
{
shared_reset();
m_base_bank = 0;
m_mask = 0;
m_base_bank = 0x00;
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()
@ -310,18 +342,18 @@ WRITE8_MEMBER(gb_rom_mbc_device::write_ram)
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;
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)
{
// the mapper only uses inputs A13-A15
// the mapper only uses inputs A15..A13
switch (offset & 0xe000)
{
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)
{
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
return 0xff;
}
@ -403,7 +435,7 @@ READ8_MEMBER(gb_rom_mbc2_device::read_ram)
WRITE8_MEMBER(gb_rom_mbc2_device::write_ram)
{
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
// 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)
{
@ -704,37 +744,140 @@ WRITE8_MEMBER(gb_rom_mmm01_device::write_bank)
}
}
// 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
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)];
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)
m_base_bank = data & 0x0f;
//logerror("write to base bank %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
case 0x0000: /* Base ROM Bank Register */
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));
break;
case 0x2000: /* ROM Bank Register */
m_latch_bank2 = data ? data : 0x01;
//logerror("write to latch %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
break;
case 0x4000: /* ROM Bank Mask Register */
if ((m_latch_bank2 & 0x30) == 0x30)
m_mask = data;
//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;
}
else if (offset < 0x4000) // ROM Bank Register
{
m_latch_bank2 = data ? data : 1;
//logerror("write to latch %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
}
// 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;
}
else if (offset < 0x6000) // ROM bank mask register
{
if ((m_latch_bank2 & 0x30) == 0x30)
m_mask = data;
//logerror("write to mask %X - %X\n", data, (m_base_bank & m_mask) | (m_latch_bank2 & ~m_mask));
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;
}
// nothing happens when writing to 0x6000-0x7fff, as verified by Tauwasser
//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;
}
}

View File

@ -191,14 +191,20 @@ public:
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:
enum {
MODE_LOCKED,
MODE_UNLOCKED
};
// 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
virtual void device_start();
@ -209,7 +215,32 @@ public:
virtual DECLARE_READ8_MEMBER(read_ram) { return 0xff; }
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