summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes/somari.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes/somari.cpp')
-rw-r--r--src/devices/bus/nes/somari.cpp325
1 files changed, 100 insertions, 225 deletions
diff --git a/src/devices/bus/nes/somari.cpp b/src/devices/bus/nes/somari.cpp
index c517a4fae16..15382d01111 100644
--- a/src/devices/bus/nes/somari.cpp
+++ b/src/devices/bus/nes/somari.cpp
@@ -17,17 +17,15 @@
#ifdef NES_PCB_DEBUG
-#define VERBOSE 1
+#define VERBOSE (LOG_GENERAL)
#else
-#define VERBOSE 0
+#define VERBOSE (0)
#endif
-
-#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+#include "logmacro.h"
#define SOMARI_VRC2_MODE 0
#define SOMARI_MMC3_MODE 1
#define SOMARI_MMC1_MODE 2
-#define SOMARI_MMC1_MODE_AGAIN 3
//-------------------------------------------------
@@ -35,15 +33,21 @@
//-------------------------------------------------
DEFINE_DEVICE_TYPE(NES_SOMARI, nes_somari_device, "nes_somari", "NES Cart Team Somari PCB")
+DEFINE_DEVICE_TYPE(NES_HUANG2, nes_huang2_device, "nes_huang2", "NES Cart Huang-2 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, device_type type, const char *tag, device_t *owner, u32 clock, u8 mmc1_prg_shift)
+ : nes_txrom_device(mconfig, type, tag, owner, clock), m_board_mode(0), m_mmc1_count(0), m_mmc1_latch(0), m_mmc1_prg_shift(mmc1_prg_shift), m_vrc_mirror(0)
+{
+}
+
+nes_somari_device::nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_somari_device(mconfig, NES_SOMARI, tag, owner, clock, 0)
+{
+}
+
+nes_huang2_device::nes_huang2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : nes_somari_device(mconfig, NES_HUANG2, tag, owner, clock, 1)
{
}
@@ -51,67 +55,27 @@ 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_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;
+ m_board_mode = SOMARI_MMC3_MODE;
+ 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 +83,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
}
@@ -138,147 +99,87 @@ void nes_somari_device::pcb_reset()
SOMERI TEAM
+ Games: Somari, Kart Fighter, Garou Densetsu Special,
+ AV Bishoujo Senshi, AV Kyuukyoku Mahjong 2
+
+ Like Rex Soft's SL-1632 these boards use Huang chips
+ which simulate the behavior of MMC1, MMC3, and VRC2.
+ There is a second revision, Huang-2, that appears to
+ only have been used for AV Kyuukyoku Mahjong 2. Its
+ MMC1 mode has nonstandard PRG banking.
+
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[BIT(offset, 13, 2)] = 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 +187,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 (BIT(m_mmc1_reg[0], 2, 2))
{
- 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] >> m_mmc1_prg_shift);
+ break;
+ case 3:
+ prg16_89ab(m_mmc1_reg[3] >> m_mmc1_prg_shift);
+ prg16_cdef(0x0f >> m_mmc1_prg_shift);
+ break;
}
break;
}
@@ -332,27 +221,16 @@ 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);
chr4_4(m_mmc1_reg[2] & 0x1f, CHRROM);
}
else
- chr8((m_mmc1_reg[1] & 0x1f) >> 1, CHRROM);
+ chr8(BIT(m_mmc1_reg[1], 1, 4), CHRROM);
break;
}
}
@@ -362,13 +240,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 +257,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));
+ LOG("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));
+ LOG("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();
}
}