From 9558a4d43443002102763eeae336306e0a3a7cf4 Mon Sep 17 00:00:00 2001 From: 0kmg <9137159+0kmg@users.noreply.github.com> Date: Tue, 19 Oct 2021 05:46:17 -0800 Subject: bus/nes: Overhauled SOMARI board emulation. (#8723) - Fixed non-booting games. - Garou Densetsu Special no longer crashes on black screen between rounds. - Fixed graphics corruption in AV Bishoujo Senshi. Yes, those graphics too. - Removed bad alt dump of AV Bishoujo Senshi. - Also save mirroring state in MMC3 (TxROM) base class as it's useful for subclasses. Software list items promoted to working (nes.xml) --------------------------------------- Kart Fighter (Asia, SOMARI-W) Somari (Asia, SOMARI-W) Somari (Asia, SOMARI-P) --- hash/nes.xml | 53 +++----- src/devices/bus/nes/batlab.h | 2 +- src/devices/bus/nes/mmc3.cpp | 7 +- src/devices/bus/nes/mmc3.h | 1 + src/devices/bus/nes/somari.cpp | 292 +++++++++++------------------------------ src/devices/bus/nes/somari.h | 33 +++-- 6 files changed, 117 insertions(+), 271 deletions(-) diff --git a/hash/nes.xml b/hash/nes.xml index ed456209ae2..bc5ee8c8bd5 100644 --- a/hash/nes.xml +++ b/hash/nes.xml @@ -62625,11 +62625,12 @@ preliminary proto for the PAL version, still running on NTSC systems) or the gfx - - AV Mei Shao Nv Zhan Shi (Asia, Alt) - 19?? - <unknown> - + + AV Měi Shàonǚ Zhànshì Girl Fighting (Asia) + 1994 + Ge De Industry + + @@ -62642,23 +62643,6 @@ preliminary proto for the PAL version, still running on NTSC systems) or the gfx - - AV Mei Shao Nv Zhan Shi (Asia) - 19?? - <unknown> - - - - - - - - - - - - - Bai-Bai Dino (Asia) 19?? @@ -66414,10 +66398,10 @@ All musics were removed in this game. - + Kart Fighter (Asia, SOMARI-W) - 19?? - <unknown> + 1994? + Ge De Industry @@ -67060,10 +67044,10 @@ All musics were removed in this game. - + Somari (Asia, SOMARI-W) - 19?? - <unknown> + 1994 + Ge De Industry @@ -67076,10 +67060,10 @@ All musics were removed in this game. - + Somari (Asia, SOMARI-P) - 19?? - <unknown> + 1994 + Ge De Industry @@ -76840,6 +76824,7 @@ be better to redump them properly. --> Garou Densetsu Special (Asia, Alt 2) 19?? <unknown> + @@ -76854,8 +76839,9 @@ be better to redump them properly. --> Garou Densetsu Special (Asia, SOMARI-W) - 19?? - <unknown> + 1995 + Ge De Industry + @@ -76872,6 +76858,7 @@ be better to redump them properly. --> Garou Densetsu Special (Asia, alt) 1995 Kasheng + diff --git a/src/devices/bus/nes/batlab.h b/src/devices/bus/nes/batlab.h index 6027108eb8d..a08fb8d6e51 100644 --- a/src/devices/bus/nes/batlab.h +++ b/src/devices/bus/nes/batlab.h @@ -48,7 +48,7 @@ private: u32 m_dpcm_addr; u8 m_dpcm_ctrl; - uint16_t m_irq_count, m_irq_count_latch; + u16 m_irq_count, m_irq_count_latch; int m_irq_enable; }; diff --git a/src/devices/bus/nes/mmc3.cpp b/src/devices/bus/nes/mmc3.cpp index 9e991603ec3..b2b8fc1fc34 100644 --- a/src/devices/bus/nes/mmc3.cpp +++ b/src/devices/bus/nes/mmc3.cpp @@ -54,7 +54,7 @@ DEFINE_DEVICE_TYPE(NES_ZZ_PCB, nes_zz_device, "nes_zz", "NES Cart PAL-ZZ nes_txrom_device::nes_txrom_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : nes_nrom_device(mconfig, type, tag, owner, clock), m_prg_base(0), m_prg_mask(0), m_chr_base(0), m_chr_mask(0) + : nes_nrom_device(mconfig, type, tag, owner, clock), m_mmc_mirror(0), m_prg_base(0), m_prg_mask(0), m_chr_base(0), m_chr_mask(0) , m_latch(0), m_wram_protect(0), m_alt_irq(0), m_irq_count(0), m_irq_count_latch(0), m_irq_clear(0), m_irq_enable(0) { } @@ -101,6 +101,7 @@ void nes_txrom_device::mmc3_start() common_start(); save_item(NAME(m_mmc_prg_bank)); save_item(NAME(m_mmc_vrom_bank)); + save_item(NAME(m_mmc_mirror)); save_item(NAME(m_latch)); save_item(NAME(m_wram_protect)); save_item(NAME(m_prg_base)); @@ -118,7 +119,8 @@ void nes_txrom_device::mmc3_common_initialize( int prg_mask, int chr_mask, int i { m_mmc_prg_bank[0] = m_mmc_prg_bank[2] = 0xffe; // m_mmc_prg_bank[2] & m_mmc_prg_bank[3] remain always the same in most MMC3 variants m_mmc_prg_bank[1] = m_mmc_prg_bank[3] = 0xfff; // but some pirate clone mappers change them after writing certain registers - memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank)); + std::fill(std::begin(m_mmc_vrom_bank), std::end(m_mmc_vrom_bank), 0x00); + m_mmc_mirror = 0; m_latch = 0; m_wram_protect = 0x80; @@ -288,6 +290,7 @@ void nes_txrom_device::txrom_write(offs_t offset, uint8_t data) break; case 0x2000: + m_mmc_mirror = data; if (m_mirroring != PPU_MIRROR_4SCREEN) set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); break; diff --git a/src/devices/bus/nes/mmc3.h b/src/devices/bus/nes/mmc3.h index 6b7ace77e53..c0c60d52375 100644 --- a/src/devices/bus/nes/mmc3.h +++ b/src/devices/bus/nes/mmc3.h @@ -40,6 +40,7 @@ protected: // are there MMC3 clones which need more regs? uint16_t m_mmc_prg_bank[4]; uint16_t m_mmc_vrom_bank[8]; // a few clones need more than the 6 banks used by base MMC3 (e.g. waixing_g) + uint8_t m_mmc_mirror; int m_prg_base, m_prg_mask; // MMC3 based multigame carts select a block of banks by using these (and then act like normal MMC3), int m_chr_base, m_chr_mask; // while MMC3 and clones (mapper 118 & 119) simply set them as 0 and 0xff resp. diff --git a/src/devices/bus/nes/somari.cpp b/src/devices/bus/nes/somari.cpp index c517a4fae16..cc0dc35f7c4 100644 --- a/src/devices/bus/nes/somari.cpp +++ b/src/devices/bus/nes/somari.cpp @@ -27,7 +27,6 @@ #define SOMARI_VRC2_MODE 0 #define SOMARI_MMC3_MODE 1 #define SOMARI_MMC1_MODE 2 -#define SOMARI_MMC1_MODE_AGAIN 3 //------------------------------------------------- @@ -37,13 +36,8 @@ DEFINE_DEVICE_TYPE(NES_SOMARI, nes_somari_device, "nes_somari", "NES Cart Team Somari PCB") -nes_somari_device::nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nes_txrom_device(mconfig, NES_SOMARI, tag, owner, clock) - , m_board_mode(0) - , m_mmc3_mirror_reg(0) - , m_count(0) - , m_mmc1_latch(0) - , m_vrc_mirror_reg(0) +nes_somari_device::nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : nes_txrom_device(mconfig, NES_SOMARI, tag, owner, clock), m_board_mode(0), m_mmc1_count(0), m_mmc1_latch(0), m_vrc_mirror(0) { } @@ -51,67 +45,29 @@ nes_somari_device::nes_somari_device(const machine_config &mconfig, const char * void nes_somari_device::device_start() { - common_start(); + mmc3_start(); save_item(NAME(m_board_mode)); - // MMC3 - save_item(NAME(m_mmc_prg_bank)); - save_item(NAME(m_mmc_vrom_bank)); - save_item(NAME(m_latch)); - save_item(NAME(m_prg_base)); - save_item(NAME(m_prg_mask)); - save_item(NAME(m_chr_base)); - save_item(NAME(m_chr_mask)); - save_item(NAME(m_mmc3_mirror_reg)); - - save_item(NAME(m_irq_enable)); - save_item(NAME(m_irq_count)); - save_item(NAME(m_irq_count_latch)); - save_item(NAME(m_irq_clear)); - // MMC1 - save_item(NAME(m_count)); + save_item(NAME(m_mmc1_count)); save_item(NAME(m_mmc1_latch)); save_item(NAME(m_mmc1_reg)); // VRC2 save_item(NAME(m_vrc_prg_bank)); save_item(NAME(m_vrc_vrom_bank)); - save_item(NAME(m_vrc_mirror_reg)); + save_item(NAME(m_vrc_mirror)); } void nes_somari_device::pcb_reset() { + m_board_mode = SOMARI_MMC3_MODE; + m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM; - prg32(0); - chr8(0, m_chr_source); - - m_board_mode = 2; // mode - - // MMC3 - m_prg_base = m_chr_base = 0; - m_prg_mask = 0xff; - m_chr_mask = 0xff; - m_latch = 0; - m_mmc_prg_bank[0] = 0x3c; - m_mmc_prg_bank[1] = 0x3d; - m_mmc_prg_bank[2] = 0x3e; - m_mmc_prg_bank[3] = 0x3f; - m_mmc_vrom_bank[0] = 0x00; - m_mmc_vrom_bank[1] = 0x01; - m_mmc_vrom_bank[2] = 0x04; - m_mmc_vrom_bank[3] = 0x05; - m_mmc_vrom_bank[4] = 0x06; - m_mmc_vrom_bank[5] = 0x07; - m_mmc3_mirror_reg = 0; - - m_alt_irq = 0; - m_irq_enable = 0; - m_irq_count = m_irq_count_latch = 0; - m_irq_clear = 0; + mmc3_common_initialize(0xff, 0xff, 0); // MMC1 regs - m_count = 0; + m_mmc1_count = 0; m_mmc1_latch = 0; m_mmc1_reg[0] = 0x0c; m_mmc1_reg[1] = 0x00; @@ -119,12 +75,9 @@ void nes_somari_device::pcb_reset() m_mmc1_reg[3] = 0x00; // VRC2 regs - m_vrc_prg_bank[0] = 0x00; - m_vrc_prg_bank[1] = 0x01; - for (int i = 0; i < 8; ++i) - m_vrc_vrom_bank[i] = i; - bank_update_switchmode(); - m_vrc_mirror_reg = 0; + m_vrc_prg_bank[0] = m_vrc_prg_bank[1] = 0; + m_vrc_mirror = 0; + std::fill(std::begin(m_vrc_vrom_bank), std::end(m_vrc_vrom_bank), 0xff); // Somari (original release) glitches on "Somari Team Presents" screen without this } @@ -141,144 +94,75 @@ void nes_somari_device::pcb_reset() iNES: mapper 116 - Emulation note about regs in MESS: currently, + Emulation note about regs in MAME: currently, - m_mmc_prg_bank[n] for n=0,...,3 represent the MMC3 PRG banks (inherited from base class) - m_mmc_vrom_bank[n] for n=0,...,5 represent the MMC3 CHR banks (inherited from base class) - m_mmc1_reg[n] for n=0,1,2,3 represent the MMC1 regs - - m_count and m_mmc1_latch are additional variables for MMC1 (notice that MMC3 uses a diff m_latch!) + - m_mmc1_count and m_mmc1_latch are additional variables for MMC1 (notice that MMC3 uses a diff m_latch!) - m_vrc_prg_bank[n] for n=0,1 represent the VRC2 PRG banks - m_vrc_vrom_bank[n] for n=0,...,7 represent the VRC2 CHR banks - In MESS: Preliminary support + In MAME: Supported. -------------------------------------------------*/ // MMC1 Mode emulation -void nes_somari_device::mmc1_w(offs_t offset, uint8_t data) +void nes_somari_device::mmc1_reset_latch() { - assert(m_board_mode == 2); - - if (data & 0x80) - { - m_count = 0; - m_mmc1_latch = 0; - - m_mmc1_reg[0] |= 0x0c; - update_prg(); - return; - } - - if (m_count < 5) - { - if (m_count == 0) m_mmc1_latch = 0; - m_mmc1_latch >>= 1; - m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00; - m_count++; - } - - if (m_count == 5) - { - m_mmc1_reg[(offset & 0x6000) >> 13] = m_mmc1_latch; - update_mirror(); - update_prg(); - update_chr(); - - m_count = 0; - } + m_mmc1_count = 0; + m_mmc1_reg[0] |= 0x0c; + update_prg(); } -// MMC3 Mode emulation -void nes_somari_device::mmc3_w(offs_t offset, uint8_t data) +void nes_somari_device::mmc1_w(offs_t offset, u8 data) { - uint8_t mmc_helper, cmd; - - assert(m_board_mode == 1); - - switch (offset & 0x6001) + if (BIT(data, 7)) + mmc1_reset_latch(); + else { - case 0x0000: - mmc_helper = m_latch ^ data; - m_latch = data; - - if (mmc_helper & 0x40) - update_prg(); - - if (mmc_helper & 0x80) - update_chr(); - break; - - case 0x0001: - cmd = m_latch & 0x07; - switch (cmd) - { - case 0: case 1: - case 2: case 3: case 4: case 5: - m_mmc_vrom_bank[cmd] = data; - update_chr(); - break; - case 6: - case 7: - m_mmc_prg_bank[cmd - 6] = data & 0x3f; - update_prg(); - break; - } - break; - - case 0x2000: - m_mmc3_mirror_reg = data & 1; - update_mirror(); - break; - case 0x2001: break; - case 0x4000: m_irq_count_latch = data; break; - case 0x4001: m_irq_count = 0; break; - case 0x6000: m_irq_enable = 0; set_irq_line(CLEAR_LINE); break; - case 0x6001: m_irq_enable = 1; break; + m_mmc1_latch = (data & 1) << 4 | m_mmc1_latch >> 1; + + m_mmc1_count = (m_mmc1_count + 1) % 5; + if (!m_mmc1_count) + { + m_mmc1_reg[(offset & 0x6000) >> 13] = m_mmc1_latch; + update_all_banks(); + } } } // VRC2 Mode emulation -void nes_somari_device::vrc2_w(offs_t offset, uint8_t data) +void nes_somari_device::vrc2_w(offs_t offset, u8 data) { - uint8_t bank, shift; - - assert(m_board_mode == 0); - switch (offset & 0x7000) { case 0x0000: - m_vrc_prg_bank[0] = data & 0x1f; + case 0x2000: + m_vrc_prg_bank[BIT(offset, 13)] = data & 0x1f; update_prg(); break; - case 0x1000: - m_vrc_mirror_reg = data & 1; + m_vrc_mirror = data; update_mirror(); break; - - case 0x2000: - m_vrc_prg_bank[1] = data & 0x1f; - update_prg(); - break; - case 0x3000: case 0x4000: case 0x5000: case 0x6000: - // this makes no sense for vrc2 and breaks somari, but it's ok for garousp!! - bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1); - shift = BIT(offset, 2) * 4; - data = (data & 0x0f) << shift; - m_vrc_vrom_bank[bank] = data; - + { + u8 bank = ((offset >> 12) - 3) * 2 + BIT(offset, 1); + u8 shift = (offset & 1) << 2; + u8 mask = 0x0f << shift; + m_vrc_vrom_bank[bank] = (m_vrc_vrom_bank[bank] & ~mask) | ((data << shift) & mask); update_chr(); break; + } } } - void nes_somari_device::update_prg() { switch (m_board_mode) @@ -286,38 +170,26 @@ void nes_somari_device::update_prg() case SOMARI_VRC2_MODE: prg8_89(m_vrc_prg_bank[0]); prg8_ab(m_vrc_prg_bank[1]); - prg8_cd(0x3e); - prg8_ef(0x3f); + prg16_cdef(m_prg_chunks - 1); break; case SOMARI_MMC3_MODE: - { - uint8_t prg_flip = (m_latch & 0x40) ? 2 : 0; - prg8_x(0, m_mmc_prg_bank[0 ^ prg_flip]); - prg8_x(1, m_mmc_prg_bank[1]); - prg8_x(2, m_mmc_prg_bank[2 ^ prg_flip]); - prg8_x(3, m_mmc_prg_bank[3]); - } + set_prg(m_prg_base, m_prg_mask); break; case SOMARI_MMC1_MODE: -// case SOMARI_MMC1_MODE_AGAIN: + switch ((m_mmc1_reg[0] >> 2) & 3) { - uint8_t prg_offset = m_mmc1_reg[1] & 0x10; - - switch (m_mmc1_reg[0] & 0x0c) - { - case 0x00: - case 0x04: - prg32((prg_offset + m_mmc1_reg[3]) >> 1); - break; - case 0x08: - prg16_89ab(prg_offset + 0); - prg16_cdef(prg_offset + m_mmc1_reg[3]); - break; - case 0x0c: - prg16_89ab(prg_offset + m_mmc1_reg[3]); - prg16_cdef(prg_offset + 0x0f); - break; - } + case 0: + case 1: + prg32(m_mmc1_reg[3] >> 1); + break; + case 2: + prg16_89ab(0); + prg16_cdef(m_mmc1_reg[3]); + break; + case 3: + prg16_89ab(m_mmc1_reg[3]); + prg16_cdef(0x0f); + break; } break; } @@ -332,20 +204,9 @@ void nes_somari_device::update_chr() chr1_x(i, m_chr_base | m_vrc_vrom_bank[i], CHRROM); break; case SOMARI_MMC3_MODE: - { - uint8_t chr_page = (m_latch & 0x80) >> 5; - chr1_x(chr_page ^ 0, m_chr_base | ((m_mmc_vrom_bank[0] & ~0x01)), CHRROM); - chr1_x(chr_page ^ 1, m_chr_base | ((m_mmc_vrom_bank[0] | 0x01)), CHRROM); - chr1_x(chr_page ^ 2, m_chr_base | ((m_mmc_vrom_bank[1] & ~0x01)), CHRROM); - chr1_x(chr_page ^ 3, m_chr_base | ((m_mmc_vrom_bank[1] | 0x01)), CHRROM); - chr1_x(chr_page ^ 4, m_chr_base | (m_mmc_vrom_bank[2]), CHRROM); - chr1_x(chr_page ^ 5, m_chr_base | (m_mmc_vrom_bank[3]), CHRROM); - chr1_x(chr_page ^ 6, m_chr_base | (m_mmc_vrom_bank[4]), CHRROM); - chr1_x(chr_page ^ 7, m_chr_base | (m_mmc_vrom_bank[5]), CHRROM); - } + set_chr(m_chr_source, m_chr_base, m_chr_mask); break; case SOMARI_MMC1_MODE: -// case SOMARI_MMC1_MODE_AGAIN: if (BIT(m_mmc1_reg[0], 4)) { chr4_0(m_mmc1_reg[1] & 0x1f, CHRROM); @@ -362,13 +223,12 @@ void nes_somari_device::update_mirror() switch (m_board_mode) { case SOMARI_VRC2_MODE: - set_nt_mirroring(m_vrc_mirror_reg ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + set_nt_mirroring(m_vrc_mirror & 1 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); break; case SOMARI_MMC3_MODE: - set_nt_mirroring(m_mmc3_mirror_reg ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); + set_nt_mirroring(m_mmc_mirror & 1 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT); break; case SOMARI_MMC1_MODE: -// case SOMARI_MMC1_MODE_AGAIN: switch (m_mmc1_reg[0] & 0x03) { case 0x00: set_nt_mirroring(PPU_MIRROR_LOW); break; @@ -380,45 +240,43 @@ void nes_somari_device::update_mirror() } } - -void nes_somari_device::write_h(offs_t offset, uint8_t data) +void nes_somari_device::write_h(offs_t offset, u8 data) { LOG_MMC(("somari write_h, mode %d, offset: %04x, data: %02x\n", m_board_mode, offset, data)); switch (m_board_mode) { case SOMARI_VRC2_MODE: vrc2_w(offset, data); break; - case SOMARI_MMC3_MODE: mmc3_w(offset, data); break; + case SOMARI_MMC3_MODE: txrom_write(offset, data); break; case SOMARI_MMC1_MODE: mmc1_w(offset, data); break; } } -void nes_somari_device::bank_update_switchmode() +void nes_somari_device::update_all_banks() { - switch (m_board_mode) - { - case SOMARI_VRC2_MODE: - break; - case SOMARI_MMC3_MODE: - break; - case SOMARI_MMC1_MODE: - break; - } update_mirror(); update_prg(); update_chr(); } -void nes_somari_device::write_m(offs_t offset, uint8_t data) +void nes_somari_device::write_m(offs_t offset, u8 data) { LOG_MMC(("somari write_m, offset: %04x, data: %02x\n", offset, data)); if (offset & 0x100) { - m_board_mode = data & 0x03; - m_chr_base = ((m_board_mode & 0x04) << 6); - if (m_board_mode != 1) + m_board_mode = std::min(data & 0x03, SOMARI_MMC1_MODE); + if (m_board_mode == SOMARI_MMC1_MODE) + mmc1_reset_latch(); // Garou crashes between fights without this + + m_chr_base = (data & 0x04) << 6; + + if (m_board_mode != SOMARI_MMC3_MODE) + { m_irq_enable = 0; - bank_update_switchmode(); + set_irq_line(CLEAR_LINE); + } + + update_all_banks(); } } diff --git a/src/devices/bus/nes/somari.h b/src/devices/bus/nes/somari.h index dda299b3a99..5976f83e5ef 100644 --- a/src/devices/bus/nes/somari.h +++ b/src/devices/bus/nes/somari.h @@ -14,14 +14,11 @@ class nes_somari_device : public nes_txrom_device { public: // construction/destruction - nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - virtual void write_l(offs_t offset, uint8_t data) override { write_m(offset + 0x100, data); } - virtual void write_m(offs_t offset, uint8_t data) override; - void mmc1_w(offs_t offset, uint8_t data); - void mmc3_w(offs_t offset, uint8_t data); - void vrc2_w(offs_t offset, uint8_t data); - virtual void write_h(offs_t offset, uint8_t data) override; + virtual void write_l(offs_t offset, u8 data) override { write_m(offset + 0x100, data); } + virtual void write_m(offs_t offset, u8 data) override; + virtual void write_h(offs_t offset, u8 data) override; virtual void pcb_reset() override; @@ -30,25 +27,25 @@ protected: virtual void device_start() override; private: + void mmc1_reset_latch(); + void mmc1_w(offs_t offset, u8 data); + void vrc2_w(offs_t offset, u8 data); void update_prg(); void update_chr(); void update_mirror(); - void bank_update_switchmode(); + void update_all_banks(); - uint8_t m_board_mode; - - // MMC3 - inherited from txrom - uint8_t m_mmc3_mirror_reg; + u8 m_board_mode; // MMC1 - uint8_t m_count; - uint8_t m_mmc1_latch; - uint8_t m_mmc1_reg[4]; + u8 m_mmc1_count; + u8 m_mmc1_latch; + u8 m_mmc1_reg[4]; // VRC2 - uint8_t m_vrc_prg_bank[2]; - uint8_t m_vrc_vrom_bank[8]; - uint8_t m_vrc_mirror_reg; + u8 m_vrc_prg_bank[2]; + u8 m_vrc_vrom_bank[8]; + u8 m_vrc_mirror; }; -- cgit v1.2.3