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