From 05ac233c0a94ba69aa3262b61a54bfddf7a9e21d Mon Sep 17 00:00:00 2001 From: etabeta78 Date: Thu, 21 May 2015 10:20:40 +0200 Subject: [PATCH] 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 --- hash/gbcolor.xml | 12 +++ src/emu/bus/gameboy/mbc.c | 211 ++++++++++++++++++++++++++++++++------ src/emu/bus/gameboy/mbc.h | 39 ++++++- 3 files changed, 224 insertions(+), 38 deletions(-) diff --git a/hash/gbcolor.xml b/hash/gbcolor.xml index f9656ba9299..83480c6d054 100644 --- a/hash/gbcolor.xml +++ b/hash/gbcolor.xml @@ -23524,6 +23524,18 @@ These were produced between 2000 and 2001 by Rocket Games, run by Datel Design + + 4 in 1 (4B-001) + 20?? + Sachen + + + + + + + + 8 in 1 (Tw) 19?? diff --git a/src/emu/bus/gameboy/mbc.c b/src/emu/bus/gameboy/mbc.c index ff58bff170e..f06f82fabeb 100644 --- a/src/emu/bus/gameboy/mbc.c +++ b/src/emu/bus/gameboy/mbc.c @@ -26,8 +26,8 @@ const device_type GB_ROM_MBC6 = &device_creator; const device_type GB_ROM_MBC7 = &device_creator; const device_type GB_ROM_M161_M12 = &device_creator; const device_type GB_ROM_MMM01 = &device_creator; -const device_type GB_ROM_SACHEN1 = &device_creator; -const device_type GB_ROM_SACHEN2 = &device_creator; // Just a placeholder for the moment... +const device_type GB_ROM_SACHEN1 = &device_creator; +const device_type GB_ROM_SACHEN2 = &device_creator; const device_type GB_ROM_188IN1 = &device_creator; const device_type GB_ROM_SINTAX = &device_creator; const device_type GB_ROM_CHONGWU = &device_creator; @@ -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; + } + } diff --git a/src/emu/bus/gameboy/mbc.h b/src/emu/bus/gameboy/mbc.h index d311bd1188f..e3485c6af09 100644 --- a/src/emu/bus/gameboy/mbc.h +++ b/src/emu/bus/gameboy/mbc.h @@ -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