summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/machine
diff options
context:
space:
mode:
author Fabio Priuli <etabeta78@users.noreply.github.com>2013-04-21 19:27:29 +0000
committer Fabio Priuli <etabeta78@users.noreply.github.com>2013-04-21 19:27:29 +0000
commitc1540080a1f2262a86b0cce00d734ac49bafbc92 (patch)
tree6cfbab2077f5eaebb01bea115746b9470752db49 /src/mess/machine
parent335b6f828a3821a0dc84f86d55e6415a20f4160d (diff)
(MESS) nes.c: major refactoring and improvements of NES/FC cart emulation: [Fabio Priuli]
- converted carts, mappers and pcbs to use slot devices - fixed starting of Famicom, Famicom Twin and Dr. PCJr - fixed handling of "no disk" in FDS so that the system displays Mario and Luigi jumping around as expected - added AY8910 sound to Sunsoft-5B (Gimmick JPN sfx) - added YM2413 to VRC-7 (Lagrange Point OST) - added support for recorded samples to Jaleco sport titles and to Bandai Family Trainer Aerobics Studio, thanks to notes by hap and egoh, and recordings by Pongbashi (samples are needed because these games use a currently undumpable speech chip) - added support for NES-EVENT pcb used by Nintendo World Championship 1990, including dipswitches - added support for Galoob Game Genie real usage (in addition to the codes which Puggsy added to his cheat collections): when you load ggenie, a second cartslot becomes available to load another game attached to the cheat device (e.g. with "mess.exe nes -cart ggenie -cart2 smb") and you can enter the cheat codes as in a real NES - added support for Nantettatte!! Baseball lock-on mechanism, based on the tests performed by naruko on his carts: when you load nantbb, a second cartslot becomes available to load one of the two update minicarts (91 Hen or OB Hen) - improved emulation of Namcot 163, 175 and 340 boards, based on the tests performed by naruko, lidnariq and bootgod on the real hardware - moved Nantettatte!! Baseball minicarts to a separate list (nes_ntbrom.xml) because they cannot be loaded in the NES directly, but only through the nantbb subslot - emulated bus conflict (CPU/PRG) in PCBs documented as having it - partial emulation of open bus, enough to make working the games using it as a sort of protection - fixed crash when loading files using FFE mappers - fixed mirroring in some boards (Sunsoft DCS and UNL-CC-21) and in some games (e.g. Paris Dakar Rally Special and Escape from Atlantis) - fixed a few bugs in Tengen 800032 emulation (mapper 64), promoting Klax, Xybots and Road Runner to work state - fixed Tengen 800037 emulation (mapper 158), promoting US Alien Syndrome to work state - added working emulation of many bootleg pcbs used for pirate conversions from FDS (Ai Senshi Nicol, Doki Doki Panic, Fuuun Shaolin Kyo, Green Beret, Monty no Doki Doki Daidassou, Tobidase Daisakusen, Super Mario Bros Malee 2 / Genius Merio Bros...) - improved emulation of many pirate pcb (BMC-GOLDENCARD-6IN1, KS7013B, KS7012, BMC-GHOSTBUSTERS63IN1, UNL-MALISB, MAXI15 and more...) - improved RacerMate Challenge II emulation, but the game is still not working due to unemulated bicycle controller - added CPU-based IRQ mode in Tengen 800032 emulation (mapper 64), fixing Skulls & Crossbones gfx (but the game is still not working) - fixed many small inaccuracies in the old code, spot during the conversion - added support for most other known pcbs, even if in most cases emulation is only sketchy - reduced the need of fake alt pbcs for boards which only differed by mirroring handling (these are now recognized through the "mirroring" feature) - removed fake wram which was added to a lot of partially documented pcbs and re-added it only where actually present, so to more accurately document what was really in the carts Out of whatsnew: There's still a lot to do (e.g. to clean up the implementation of the pirate pcbs) but I hope that submitting this now I can get some wider testing help so to catch and fix regressions before next release :)
Diffstat (limited to 'src/mess/machine')
-rw-r--r--src/mess/machine/nes.c480
-rw-r--r--src/mess/machine/nes_ave.c207
-rw-r--r--src/mess/machine/nes_ave.h67
-rw-r--r--src/mess/machine/nes_bandai.c436
-rw-r--r--src/mess/machine/nes_bandai.h154
-rw-r--r--src/mess/machine/nes_benshieng.c106
-rw-r--r--src/mess/machine/nes_benshieng.h32
-rw-r--r--src/mess/machine/nes_bootleg.c1558
-rw-r--r--src/mess/machine/nes_bootleg.h434
-rw-r--r--src/mess/machine/nes_camerica.c220
-rw-r--r--src/mess/machine/nes_camerica.h71
-rw-r--r--src/mess/machine/nes_cne.c221
-rw-r--r--src/mess/machine/nes_cne.h64
-rw-r--r--src/mess/machine/nes_cony.c390
-rw-r--r--src/mess/machine/nes_cony.h70
-rw-r--r--src/mess/machine/nes_discrete.c201
-rw-r--r--src/mess/machine/nes_discrete.h78
-rw-r--r--src/mess/machine/nes_event.c239
-rw-r--r--src/mess/machine/nes_event.h40
-rw-r--r--src/mess/machine/nes_ggenie.c275
-rw-r--r--src/mess/machine/nes_ggenie.h55
-rw-r--r--src/mess/machine/nes_henggedianzi.c279
-rw-r--r--src/mess/machine/nes_henggedianzi.h76
-rw-r--r--src/mess/machine/nes_hes.c88
-rw-r--r--src/mess/machine/nes_hes.h26
-rw-r--r--src/mess/machine/nes_hosenkan.c156
-rw-r--r--src/mess/machine/nes_hosenkan.h37
-rw-r--r--src/mess/machine/nes_ines.c737
-rw-r--r--src/mess/machine/nes_irem.c333
-rw-r--r--src/mess/machine/nes_irem.h103
-rw-r--r--src/mess/machine/nes_jaleco.c910
-rw-r--r--src/mess/machine/nes_jaleco.h251
-rw-r--r--src/mess/machine/nes_jy.c581
-rw-r--r--src/mess/machine/nes_jy.h100
-rw-r--r--src/mess/machine/nes_kaiser.c501
-rw-r--r--src/mess/machine/nes_kaiser.h154
-rw-r--r--src/mess/machine/nes_konami.c680
-rw-r--r--src/mess/machine/nes_konami.h136
-rw-r--r--src/mess/machine/nes_legacy.c271
-rw-r--r--src/mess/machine/nes_legacy.h71
-rw-r--r--src/mess/machine/nes_mmc.c579
-rw-r--r--src/mess/machine/nes_mmc1.c371
-rw-r--r--src/mess/machine/nes_mmc1.h80
-rw-r--r--src/mess/machine/nes_mmc2.c199
-rw-r--r--src/mess/machine/nes_mmc2.h52
-rw-r--r--src/mess/machine/nes_mmc3.c554
-rw-r--r--src/mess/machine/nes_mmc3.h144
-rw-r--r--src/mess/machine/nes_mmc3_clones.c2598
-rw-r--r--src/mess/machine/nes_mmc3_clones.h695
-rw-r--r--src/mess/machine/nes_mmc5.c754
-rw-r--r--src/mess/machine/nes_mmc5.h74
-rw-r--r--src/mess/machine/nes_multigame.c2605
-rw-r--r--src/mess/machine/nes_multigame.h892
-rw-r--r--src/mess/machine/nes_namcot.c682
-rw-r--r--src/mess/machine/nes_namcot.h158
-rw-r--r--src/mess/machine/nes_nanjing.c176
-rw-r--r--src/mess/machine/nes_nanjing.h36
-rw-r--r--src/mess/machine/nes_ntdec.c185
-rw-r--r--src/mess/machine/nes_ntdec.h49
-rw-r--r--src/mess/machine/nes_nxrom.c494
-rw-r--r--src/mess/machine/nes_nxrom.h184
-rw-r--r--src/mess/machine/nes_pcb.c13477
-rw-r--r--src/mess/machine/nes_pirate.c1380
-rw-r--r--src/mess/machine/nes_pirate.h394
-rw-r--r--src/mess/machine/nes_pt554.c113
-rw-r--r--src/mess/machine/nes_pt554.h29
-rw-r--r--src/mess/machine/nes_racermate.c93
-rw-r--r--src/mess/machine/nes_racermate.h33
-rw-r--r--src/mess/machine/nes_rcm.c304
-rw-r--r--src/mess/machine/nes_rcm.h103
-rw-r--r--src/mess/machine/nes_rexsoft.c263
-rw-r--r--src/mess/machine/nes_rexsoft.h59
-rw-r--r--src/mess/machine/nes_sachen.c692
-rw-r--r--src/mess/machine/nes_sachen.h259
-rw-r--r--src/mess/machine/nes_slot.c1735
-rw-r--r--src/mess/machine/nes_slot.h398
-rw-r--r--src/mess/machine/nes_somari.c375
-rw-r--r--src/mess/machine/nes_somari.h48
-rw-r--r--src/mess/machine/nes_sunsoft.c635
-rw-r--r--src/mess/machine/nes_sunsoft.h140
-rw-r--r--src/mess/machine/nes_sunsoft_dcs.c302
-rw-r--r--src/mess/machine/nes_sunsoft_dcs.h136
-rw-r--r--src/mess/machine/nes_taito.c467
-rw-r--r--src/mess/machine/nes_taito.h102
-rw-r--r--src/mess/machine/nes_tengen.c382
-rw-r--r--src/mess/machine/nes_tengen.h85
-rw-r--r--src/mess/machine/nes_txc.c267
-rw-r--r--src/mess/machine/nes_txc.h97
-rw-r--r--src/mess/machine/nes_unif.c490
-rw-r--r--src/mess/machine/nes_waixing.c1245
-rw-r--r--src/mess/machine/nes_waixing.h394
91 files changed, 31762 insertions, 15184 deletions
diff --git a/src/mess/machine/nes.c b/src/mess/machine/nes.c
index d24979d3e23..03f33022bf4 100644
--- a/src/mess/machine/nes.c
+++ b/src/mess/machine/nes.c
@@ -9,9 +9,7 @@
#include "emu.h"
#include "crsshair.h"
#include "cpu/m6502/m6502.h"
-#include "video/ppu2c0x.h"
#include "includes/nes.h"
-//#include "includes/nes_mmc.h"
#include "imagedev/cartslot.h"
#include "imagedev/flopdrv.h"
#include "hashfile.h"
@@ -31,224 +29,6 @@
FUNCTIONS
***************************************************************************/
-void nes_state::init_nes_core()
-{
- address_space &space = machine().device("maincpu")->memory().space(AS_PROGRAM);
- static const char *const bank_names[] = { "bank1", "bank2", "bank3", "bank4" };
- int i;
- m_prg_chunks = 0;
- m_chr_chunks = 0;
- m_vram_chunks = 0;
- m_pcb_id = NO_BOARD;
-
- m_rom = memregion("maincpu")->base();
- m_ciram = memregion("ciram")->base();
-
- // other pointers got set in the loading routine
-
- /* Brutal hack put in as a consequence of the new memory system; we really need to fix the NES code */
- space.install_readwrite_bank(0x0000, 0x07ff, 0, 0x1800, "bank10");
-
- machine().device("ppu")->memory().space(AS_PROGRAM).install_readwrite_handler(0, 0x1fff, read8_delegate(FUNC(nes_state::nes_chr_r),this), write8_delegate(FUNC(nes_state::nes_chr_w),this));
- machine().device("ppu")->memory().space(AS_PROGRAM).install_readwrite_handler(0x2000, 0x3eff, read8_delegate(FUNC(nes_state::nes_nt_r),this), write8_delegate(FUNC(nes_state::nes_nt_w),this));
-
- membank("bank10")->set_base(m_rom);
-
- // get cart info from cartslot
- if (m_cartslot && m_cartslot->m_cart)
- {
- m_prg_chunks = m_cartslot->m_cart->get_prg_size() / 0x4000;
- m_chr_chunks = m_cartslot->m_cart->get_vrom_size() / 0x2000;
- m_vram_chunks = m_cartslot->m_cart->get_vram_size() / 0x2000;
-// printf("%d - %d - %d\n", m_prg_chunks, m_chr_chunks, m_vram_chunks);
- m_prg = m_cartslot->m_cart->get_prg_base();
- if (m_cartslot->m_cart->get_vrom_size())
- m_vrom = m_cartslot->m_cart->get_vrom_base();
- if (m_cartslot->m_cart->get_vram_size())
- m_vram = auto_alloc_array(machine(), UINT8, m_cartslot->m_cart->get_vram_size());
-
- m_pcb_id = m_cartslot->get_pcb_id();
- m_hard_mirroring = m_cartslot->m_cart->get_mirroring();
- m_four_screen_vram = m_cartslot->m_cart->get_four_screen_vram();
-
- // setup memory pointers and related variables
- m_prg_ram = m_cartslot->m_cart->get_battery_size() ? 1 : 0;
- m_wram_size = m_cartslot->m_cart->get_prgram_size();
- m_mapper_ram_size = m_cartslot->m_cart->get_mapper_ram_size();
- m_mapper_bram_size = m_cartslot->m_cart->get_mapper_bram_size();
- m_battery = m_cartslot->m_cart->get_battery_size() ? 1 : 0;
- m_battery_size = m_cartslot->m_cart->get_battery_size();
-
- if (m_prg_ram)
- m_wram = m_cartslot->m_cart->get_prgram_base();
- if (m_mapper_ram_size)
- m_mapper_ram = m_cartslot->m_cart->get_mapper_ram_base();
- if (m_battery)
- m_battery_ram = m_cartslot->m_cart->get_battery_base();
- if (m_mapper_bram_size)
- m_mapper_bram = m_cartslot->m_cart->get_mapper_bram_base();
-
- // setup the rest of the variables involved
- m_chr_open_bus = m_cartslot->get_chr_open_bus();
- m_ce_mask = m_cartslot->get_ce_mask();
- m_ce_state = m_cartslot->get_ce_state();
- m_vrc_ls_prg_a = m_cartslot->get_vrc_ls_prg_a();
- m_vrc_ls_prg_b = m_cartslot->get_vrc_ls_prg_b();
- m_vrc_ls_chr = m_cartslot->get_vrc_ls_chr();
- m_crc_hack = m_cartslot->get_crc_hack();
- }
-
- int prg_banks = (m_prg_chunks == 1) ? (2 * 2) : (m_prg_chunks * 2);
-
- /* If there is Disk Expansion and no cart has been loaded, setup memory accordingly */
- if (m_disk_expansion && m_pcb_id == NO_BOARD)
- {
- /* If we are loading a disk we have already filled m_fds_data and we don't want to overwrite it,
- if we are loading a cart image identified as mapper 20 (probably wrong mapper...) we need to alloc
- memory for use in nes_fds_r/nes_fds_w. Same goes for allocation of fds_ram (used for bank2) */
- if (m_fds_data == NULL)
- {
- UINT32 size = (m_prg_chunks == 1) ? 2 * 0x4000 : m_prg_chunks * 0x4000;
- m_fds_data = auto_alloc_array_clear(machine(), UINT8, size);
- memcpy(m_fds_data, m_prg, size); // copy in fds_data the cart PRG
- }
- if (m_fds_ram == NULL)
- m_fds_ram = auto_alloc_array(machine(), UINT8, 0x8000);
-
- space.install_read_handler(0x4030, 0x403f, read8_delegate(FUNC(nes_state::nes_fds_r),this));
- space.install_read_bank(0x6000, 0xdfff, "bank2");
- space.install_read_bank(0xe000, 0xffff, "bank1");
-
- space.install_write_handler(0x4020, 0x402f, write8_delegate(FUNC(nes_state::nes_fds_w),this));
- space.install_write_bank(0x6000, 0xdfff, "bank2");
-
- membank("bank1")->set_base(&m_rom[0xe000]);
- membank("bank2")->set_base(m_fds_ram);
- return;
- }
- else
- {
- /* Set up the mapper callbacks */
- pcb_handlers_setup();
-
- /* Set up the memory handlers for the mapper */
- space.install_read_bank(0x8000, 0x9fff, "bank1");
- space.install_read_bank(0xa000, 0xbfff, "bank2");
- space.install_read_bank(0xc000, 0xdfff, "bank3");
- space.install_read_bank(0xe000, 0xffff, "bank4");
- space.install_readwrite_bank(0x6000, 0x7fff, "bank5");
-
- /* configure banks 1-4 */
- for (i = 0; i < 4; i++)
- {
- membank(bank_names[i])->configure_entries(0, prg_banks, m_prg, 0x2000);
- // some mappers (e.g. MMC5) can map PRG RAM in 0x8000-0xffff as well
- if (m_prg_ram)
- membank(bank_names[i])->configure_entries(prg_banks, m_wram_size / 0x2000, m_wram, 0x2000);
- // however, at start we point to PRG ROM
- membank(bank_names[i])->set_entry(i);
- m_prg_bank[i] = i;
- }
-
- /* bank 5 configuration is more delicate, since it can have PRG RAM, PRG ROM or SRAM mapped to it */
- /* we first map PRG ROM banks, then the battery bank (if a battery is present), and finally PRG RAM (m_wram) */
- membank("bank5")->configure_entries(0, prg_banks, m_prg, 0x2000);
- m_battery_bank5_start = prg_banks;
- m_prgram_bank5_start = prg_banks;
- m_empty_bank5_start = prg_banks;
-
- /* add battery ram, but only if there's no trainer since they share overlapping memory. */
- if (m_battery && !m_trainer)
- {
- UINT32 bank_size = (m_battery_size > 0x2000) ? 0x2000 : m_battery_size;
- int bank_num = (m_battery_size > 0x2000) ? m_battery_size / 0x2000 : 1;
- membank("bank5")->configure_entries(prg_banks, bank_num, m_battery_ram, bank_size);
- m_prgram_bank5_start += bank_num;
- m_empty_bank5_start += bank_num;
- }
- /* add prg ram. */
- if (m_prg_ram)
- {
- membank("bank5")->configure_entries(m_prgram_bank5_start, m_wram_size / 0x2000, m_wram, 0x2000);
- m_empty_bank5_start += m_wram_size / 0x2000;
- }
-
- membank("bank5")->configure_entry(m_empty_bank5_start, m_rom + 0x6000);
-
- /* if we have any additional PRG RAM, point bank5 to its first bank */
- if (m_battery || m_prg_ram)
- m_prg_bank[4] = m_battery_bank5_start;
- else
- m_prg_bank[4] = m_empty_bank5_start; // or shall we point to "maincpu" region at 0x6000? point is that we should never access this region if no sram or wram is present!
-
- membank("bank5")->set_entry(m_prg_bank[4]);
-
- if (m_four_screen_vram)
- {
- m_extended_ntram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
- save_pointer(NAME(m_extended_ntram), 0x2000);
- }
-
- if (m_four_screen_vram)
- set_nt_mirroring(PPU_MIRROR_4SCREEN);
- else
- {
- switch (m_hard_mirroring)
- {
- case PPU_MIRROR_HORZ:
- case PPU_MIRROR_VERT:
- case PPU_MIRROR_HIGH:
- case PPU_MIRROR_LOW:
- set_nt_mirroring(m_hard_mirroring);
- break;
- default:
- set_nt_mirroring(PPU_MIRROR_NONE);
- break;
- }
- }
- }
-
- // there are still some quirk about writes to bank5... I hope to fix them soon. (mappers 34,45,52,246 have both mid_w and WRAM-->check)
- if (!m_mmc_write_low.isnull())
- space.install_write_handler(0x4100, 0x5fff, m_mmc_write_low);
- if (!m_mmc_write_mid.isnull())
- space.install_write_handler(0x6000, 0x7fff, m_mmc_write_mid);
- if (!m_mmc_write.isnull())
- space.install_write_handler(0x8000, 0xffff, m_mmc_write);
-
- // In fact, we also allow single pcbs to overwrite the bank read handlers defined above,
- // because some pcbs (mainly pirate ones) require protection values to be read instead of
- // the expected ROM banks: these handlers, though, must take care of the ROM access as well
- if (!m_mmc_read_low.isnull())
- space.install_read_handler(0x4100, 0x5fff, m_mmc_read_low);
- if (!m_mmc_read_mid.isnull())
- space.install_read_handler(0x6000, 0x7fff, m_mmc_read_mid);
- if (!m_mmc_read.isnull())
- space.install_read_handler(0x8000, 0xffff, m_mmc_read);
-
- // install additional handlers
- if (m_pcb_id == BTL_SMB2B || m_mapper == 50)
- {
- space.install_write_handler(0x4020, 0x403f, write8_delegate(FUNC(nes_state::smb2jb_extra_w),this));
- space.install_write_handler(0x40a0, 0x40bf, write8_delegate(FUNC(nes_state::smb2jb_extra_w),this));
- }
-
- if (m_pcb_id == KAISER_KS7017)
- {
- space.install_read_handler(0x4030, 0x4030, read8_delegate(FUNC(nes_state::ks7017_extra_r),this));
- space.install_write_handler(0x4020, 0x40ff, write8_delegate(FUNC(nes_state::ks7017_extra_w),this));
- }
-
- if (m_pcb_id == UNL_603_5052)
- {
- space.install_read_handler(0x4020, 0x40ff, read8_delegate(FUNC(nes_state::unl_6035052_extra_r),this));
- space.install_write_handler(0x4020, 0x40ff, write8_delegate(FUNC(nes_state::unl_6035052_extra_w),this));
- }
-
- if (m_pcb_id == WAIXING_SH2)
- machine().device("ppu")->memory().space(AS_PROGRAM).install_read_handler(0, 0x1fff, read8_delegate(FUNC(nes_state::waixing_sh2_chr_r),this));
-}
-
// to be probably removed (it does nothing since a long time)
int nes_state::nes_ppu_vidaccess( int address, int data )
{
@@ -258,10 +38,10 @@ int nes_state::nes_ppu_vidaccess( int address, int data )
void nes_state::machine_reset()
{
/* Reset the mapper variables. Will also mark the char-gen ram as dirty */
- if (m_disk_expansion && m_pcb_id == NO_BOARD)
+ if (m_disk_expansion && m_cartslot && !m_cartslot->m_cart)
m_ppu->set_hblank_callback(ppu2c0x_hblank_delegate(FUNC(nes_state::fds_irq),this));
- else
- nes_pcb_reset();
+ else if (m_cartslot)
+ m_cartslot->pcb_reset();
/* Reset the serial input ports */
m_in_0.shift = 0;
@@ -270,57 +50,12 @@ void nes_state::machine_reset()
m_maincpu->reset();
}
-TIMER_CALLBACK_MEMBER(nes_state::nes_irq_callback)
-{
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_irq_timer->adjust(attotime::never);
-}
-
-void nes_state::nes_banks_restore()
-{
- membank("bank1")->set_entry(m_prg_bank[0]);
- membank("bank2")->set_entry(m_prg_bank[1]);
- membank("bank3")->set_entry(m_prg_bank[2]);
- membank("bank4")->set_entry(m_prg_bank[3]);
- membank("bank5")->set_entry(m_prg_bank[4]);
-}
-
static void nes_state_register( running_machine &machine )
{
nes_state *state = machine.driver_data<nes_state>();
- state->save_item(NAME(state->m_prg_bank));
-
- state->save_item(NAME(state->m_MMC5_floodtile));
- state->save_item(NAME(state->m_MMC5_floodattr));
- state->save_item(NAME(state->m_mmc5_vram_control));
-
- state->save_item(NAME(state->m_nes_vram_sprite));
state->save_item(NAME(state->m_last_frame_flip));
- // shared mapper variables
- state->save_item(NAME(state->m_IRQ_enable));
- state->save_item(NAME(state->m_IRQ_enable_latch));
- state->save_item(NAME(state->m_IRQ_count));
- state->save_item(NAME(state->m_IRQ_count_latch));
- state->save_item(NAME(state->m_IRQ_toggle));
- state->save_item(NAME(state->m_IRQ_reset));
- state->save_item(NAME(state->m_IRQ_status));
- state->save_item(NAME(state->m_IRQ_mode));
- state->save_item(NAME(state->m_mult1));
- state->save_item(NAME(state->m_mult2));
- state->save_item(NAME(state->m_mmc_chr_source));
- state->save_item(NAME(state->m_mmc_cmd1));
- state->save_item(NAME(state->m_mmc_cmd2));
- state->save_item(NAME(state->m_mmc_count));
- state->save_item(NAME(state->m_mmc_prg_base));
- state->save_item(NAME(state->m_mmc_prg_mask));
- state->save_item(NAME(state->m_mmc_chr_base));
- state->save_item(NAME(state->m_mmc_chr_mask));
- state->save_item(NAME(state->m_mmc_prg_bank));
- state->save_item(NAME(state->m_mmc_vrom_bank));
- state->save_item(NAME(state->m_mmc_extra_bank));
-
state->save_item(NAME(state->m_fds_motor_on));
state->save_item(NAME(state->m_fds_door_closed));
state->save_item(NAME(state->m_fds_current_side));
@@ -330,12 +65,12 @@ static void nes_state_register( running_machine &machine )
state->save_item(NAME(state->m_fds_write_reg));
state->save_item(NAME(state->m_fds_last_side));
state->save_item(NAME(state->m_fds_count));
+ state->save_item(NAME(state->m_fds_mirroring));
- state->save_pointer(NAME(state->m_wram), state->m_wram_size);
- if (state->m_battery)
- state->save_pointer(NAME(state->m_battery_ram), state->m_battery_size);
+ state->save_pointer(NAME(state->m_ciram), 0x800);
- machine.save().register_postload(save_prepost_delegate(FUNC(nes_state::nes_banks_restore), state));
+ if (state->m_disk_expansion)
+ state->save_pointer(NAME(state->m_vram), 0x800);
}
@@ -345,11 +80,8 @@ static void nes_state_register( running_machine &machine )
void nes_state::machine_start()
{
- m_ppu = machine().device<ppu2c0x_device>("ppu");
-
- init_nes_core();
-
m_maincpu = machine().device<cpu_device>("maincpu");
+ m_ppu = machine().device<ppu2c0x_device>("ppu");
m_sound = machine().device("nessound");
m_io_ctrlsel = ioport("CTRLSEL");
m_io_fckey[0] = ioport("FCKEY0");
@@ -391,47 +123,90 @@ void nes_state::machine_start()
m_io_mahjong[1] = ioport("MAH1");
m_io_mahjong[2] = ioport("MAH2");
m_io_mahjong[3] = ioport("MAH3");
- m_prg_bank_mem[0] = membank("bank1");
- m_prg_bank_mem[1] = membank("bank2");
- m_prg_bank_mem[2] = membank("bank3");
- m_prg_bank_mem[3] = membank("bank4");
- m_prg_bank_mem[4] = membank("bank5");
-
- // If we're starting famicom with no disk inserted, we still haven't initialized the VRAM needed for
- // video emulation, so we need to take care of it now
- if (!m_vram)
+
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+
+ // CIRAM (Character Internal RAM)
+ // NES has 2KB of internal RAM which can be used to fill the 4x1KB banks of PPU RAM at $2000-$2fff
+ // Line A10 is exposed to the carts, so that games can change CIRAM mapping in PPU (we emulate this with the set_nt_mirroring
+ // function). CIRAM can also be disabled by the game (if e.g. VROM or cart RAM has to be used in PPU...
+ m_ciram = auto_alloc_array(machine(), UINT8, 0x800);
+ // other pointers got set in the loading routine, because they 'belong' to the cart itself
+
+ if (m_cartslot && m_cartslot->m_cart)
{
- m_vram = auto_alloc_array(machine(), UINT8, 0x4000);
- for (int i = 0; i < 8; i++)
+ // Set up memory handlers
+ space.install_read_handler(0x4100, 0x5fff, read8_delegate(FUNC(nes_cart_slot_device::read_l), (nes_cart_slot_device *)m_cartslot));
+ space.install_write_handler(0x4100, 0x5fff, write8_delegate(FUNC(nes_cart_slot_device::write_l), (nes_cart_slot_device *)m_cartslot));
+ space.install_read_handler(0x6000, 0x7fff, read8_delegate(FUNC(nes_cart_slot_device::read_m), (nes_cart_slot_device *)m_cartslot));
+ space.install_write_handler(0x6000, 0x7fff, write8_delegate(FUNC(nes_cart_slot_device::write_m), (nes_cart_slot_device *)m_cartslot));
+ space.install_read_bank(0x8000, 0x9fff, "prg0");
+ space.install_read_bank(0xa000, 0xbfff, "prg1");
+ space.install_read_bank(0xc000, 0xdfff, "prg2");
+ space.install_read_bank(0xe000, 0xffff, "prg3");
+ space.install_write_handler(0x8000, 0xffff, write8_delegate(FUNC(nes_cart_slot_device::write_h), (nes_cart_slot_device *)m_cartslot));
+
+ m_cartslot->pcb_start(m_ciram);
+ m_cartslot->m_cart->pcb_reg_postload(machine());
+ m_ppu->space(AS_PROGRAM).install_readwrite_handler(0, 0x1fff, read8_delegate(FUNC(device_nes_cart_interface::chr_r),m_cartslot->m_cart), write8_delegate(FUNC(device_nes_cart_interface::chr_w),m_cartslot->m_cart));
+ m_ppu->space(AS_PROGRAM).install_readwrite_handler(0x2000, 0x3eff, read8_delegate(FUNC(device_nes_cart_interface::nt_r),m_cartslot->m_cart), write8_delegate(FUNC(device_nes_cart_interface::nt_w),m_cartslot->m_cart));
+ m_ppu->set_scanline_callback(ppu2c0x_scanline_delegate(FUNC(device_nes_cart_interface::scanline_irq),m_cartslot->m_cart));
+ m_ppu->set_hblank_callback(ppu2c0x_hblank_delegate(FUNC(device_nes_cart_interface::hblank_irq),m_cartslot->m_cart));
+ m_ppu->set_latch(ppu2c0x_latch_delegate(FUNC(device_nes_cart_interface::ppu_latch),m_cartslot->m_cart));
+
+ // install additional handlers (read_h, read_ex, write_ex)
+ if (m_cartslot->get_pcb_id() == GG_NROM || m_cartslot->get_pcb_id() == SUNSOFT_DCS
+ || m_cartslot->get_pcb_id() == AVE_MAXI15 || m_cartslot->get_pcb_id() == KAISER_KS7022 || m_cartslot->get_pcb_id() == BMC_VT5201
+ || m_cartslot->get_pcb_id() == UNL_LH32 || m_cartslot->get_pcb_id() == UNL_LH10 || m_cartslot->get_pcb_id() == UNL_2708
+ || m_cartslot->get_pcb_id() == UNL_43272 || m_cartslot->get_pcb_id() == BMC_G63IN1 || m_cartslot->get_pcb_id() == BMC_8157
+ || m_cartslot->get_pcb_id() == BMC_GOLD150 || m_cartslot->get_pcb_id() == BMC_CH001
+ || m_cartslot->get_pcb_id() == BMC_70IN1 || m_cartslot->get_pcb_id() == BMC_800IN1)
{
- m_chr_map[i].source = CHRRAM;
- m_chr_map[i].origin = i * 0x400; // for save state uses!
- m_chr_map[i].access = &m_vram[m_chr_map[i].origin];
+ logerror("read_h installed!\n");
+ space.install_read_handler(0x8000, 0xffff, read8_delegate(FUNC(nes_cart_slot_device::read_h), (nes_cart_slot_device *)m_cartslot));
}
- }
- m_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(nes_state::nes_irq_callback),this));
- nes_state_register(machine());
-}
+ if (m_cartslot->get_pcb_id() == BTL_SMB2JB || m_cartslot->get_pcb_id() == UNL_AC08 || m_cartslot->get_pcb_id() == BTL_SMB2JC)
+ {
+ logerror("write_ex installed!\n");
+ space.install_write_handler(0x4020, 0x40ff, write8_delegate(FUNC(nes_cart_slot_device::write_ex), (nes_cart_slot_device *)m_cartslot));
+ }
+ if (m_cartslot->get_pcb_id() == KAISER_KS7017 || m_cartslot->get_pcb_id() == UNL_603_5052)
+ {
+ logerror("write_ex & read_ex installed!\n");
+ space.install_read_handler(0x4020, 0x40ff, read8_delegate(FUNC(nes_cart_slot_device::read_ex), (nes_cart_slot_device *)m_cartslot));
+ space.install_write_handler(0x4020, 0x40ff, write8_delegate(FUNC(nes_cart_slot_device::write_ex), (nes_cart_slot_device *)m_cartslot));
+ }
+ }
+ else if (m_disk_expansion) // if there is Disk Expansion and no cart has been loaded, setup memory accordingly
+ {
+ m_ppu->space(AS_PROGRAM).install_readwrite_handler(0, 0x1fff, read8_delegate(FUNC(nes_state::fds_chr_r),this), write8_delegate(FUNC(nes_state::fds_chr_w),this));
+ m_ppu->space(AS_PROGRAM).install_readwrite_handler(0x2000, 0x3eff, read8_delegate(FUNC(nes_state::fds_nt_r),this), write8_delegate(FUNC(nes_state::fds_nt_w),this));
-//-------------------------------------------------
-// update_prg_banks
-//-------------------------------------------------
+ if (!m_fds_ram)
+ m_fds_ram = auto_alloc_array(machine(), UINT8, 0x8000);
+ if (!m_vram)
+ m_vram = auto_alloc_array(machine(), UINT8, 0x2000);
-void nes_state::update_prg_banks(int prg_bank_start, int prg_bank_end)
-{
- for (int prg_bank = prg_bank_start; prg_bank <= prg_bank_end; prg_bank++)
- {
- assert(prg_bank >= 0);
- assert(prg_bank < ARRAY_LENGTH(m_prg_bank));
- assert(prg_bank < ARRAY_LENGTH(m_prg_bank_mem));
+ space.install_read_handler(0x4030, 0x403f, read8_delegate(FUNC(nes_state::nes_fds_r),this));
+ space.install_read_bank(0x6000, 0xdfff, "fdsram");
+ space.install_read_bank(0xe000, 0xffff, "bank1");
+
+ space.install_write_handler(0x4020, 0x402f, write8_delegate(FUNC(nes_state::nes_fds_w),this));
+ space.install_write_bank(0x6000, 0xdfff, "fdsram");
- m_prg_bank_mem[prg_bank]->set_entry(m_prg_bank[prg_bank]);
+ membank("bank1")->set_base(machine().root_device().memregion("maincpu")->base() + 0xe000);
+ membank("fdsram")->set_base(m_fds_ram);
}
+
+ nes_state_register(machine());
}
+//-------------------------------------------------
+// INPUTS
+//-------------------------------------------------
READ8_MEMBER(nes_state::nes_IN0_r)
{
@@ -716,15 +491,6 @@ WRITE8_MEMBER(nes_state::nes_IN1_w)
}
-
-void nes_partialhash(hash_collection &dest, const unsigned char *data,
- unsigned long length, const char *functions)
-{
- if (length <= 16)
- return;
- dest.compute(&data[16], length - 16, functions);
-}
-
/**************************
Disk System emulation
@@ -762,7 +528,7 @@ READ8_MEMBER(nes_state::nes_fds_r)
break;
case 0x01: /* $4031 - data latch */
/* don't read data if disk is unloaded */
- if (m_fds_data == NULL)
+ if (!m_fds_data)
ret = 0;
else if (m_fds_current_side)
{
@@ -777,7 +543,7 @@ READ8_MEMBER(nes_state::nes_fds_r)
break;
case 0x02: /* $4032 - disk status 1 */
/* return "no disk" status if disk is unloaded */
- if (m_fds_data == NULL)
+ if (!m_fds_data)
ret = 1;
else if (m_fds_last_side != m_fds_current_side)
{
@@ -832,7 +598,10 @@ WRITE8_MEMBER(nes_state::nes_fds_w)
m_fds_head_position = 0;
m_fds_read_mode = BIT(data, 2);
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ if (BIT(data, 3))
+ m_fds_mirroring = PPU_MIRROR_HORZ;
+ else
+ m_fds_mirroring = PPU_MIRROR_VERT;
if ((!(data & 0x40)) && (m_fds_write_reg & 0x40))
m_fds_head_position -= 2; // ???
@@ -843,6 +612,69 @@ WRITE8_MEMBER(nes_state::nes_fds_w)
}
}
+WRITE8_MEMBER(nes_state::fds_chr_w)
+{
+ m_vram[offset] = data;
+}
+
+READ8_MEMBER(nes_state::fds_chr_r)
+{
+ return m_vram[offset];
+}
+
+WRITE8_MEMBER(nes_state::fds_nt_w)
+{
+ int page = ((offset & 0xc00) >> 10);
+ int bank;
+
+ switch (page)
+ {
+ case 0:
+ bank = 0;
+ break;
+ case 1:
+ bank = (m_fds_mirroring == PPU_MIRROR_VERT) ? 1 : 0;
+ break;
+ case 2:
+ bank = (m_fds_mirroring == PPU_MIRROR_VERT) ? 0 : 1;
+ break;
+ case 3:
+ default:
+ bank = 1;
+ break;
+ }
+
+ m_ciram[(bank * 0x400) + (offset & 0x3ff)] = data;
+}
+
+READ8_MEMBER(nes_state::fds_nt_r)
+{
+ int page = ((offset & 0xc00) >> 10);
+ int bank;
+
+ switch (page)
+ {
+ case 0:
+ bank = 0;
+ break;
+ case 1:
+ bank = (m_fds_mirroring == PPU_MIRROR_VERT) ? 1 : 0;
+ break;
+ case 2:
+ bank = (m_fds_mirroring == PPU_MIRROR_VERT) ? 0 : 1;
+ break;
+ case 3:
+ default:
+ bank = 1;
+ break;
+ }
+
+ return m_ciram[(bank * 0x400) + (offset & 0x3ff)];
+}
+
+
+// Disk interface
+
static void nes_load_proc( device_image_interface &image )
{
nes_state *state = image.device().machine().driver_data<nes_state>();
@@ -854,7 +686,7 @@ static void nes_load_proc( device_image_interface &image )
state->m_fds_sides = (image.length() - header) / 65500;
- if (state->m_fds_data == NULL)
+ if (!state->m_fds_data)
state->m_fds_data = auto_alloc_array(image.device().machine(),UINT8,state->m_fds_sides * 65500); // I don't think we can arrive here ever, probably it can be removed...
/* if there is an header, skip it */
@@ -874,17 +706,8 @@ static void nes_unload_proc( device_image_interface &image )
DRIVER_INIT_MEMBER(nes_state,famicom)
{
- /* clear some of the variables we don't use */
- m_trainer = 0;
- m_battery = 0;
- m_prg_ram = 0;
- m_four_screen_vram = 0;
- m_hard_mirroring = 0;
- m_prg_chunks = m_chr_chunks = 0;
-
/* initialize the disk system */
m_disk_expansion = 1;
- m_pcb_id = NO_BOARD;
m_fds_sides = 0;
m_fds_last_side = 0;
@@ -896,7 +719,8 @@ DRIVER_INIT_MEMBER(nes_state,famicom)
m_fds_status0 = 0;
m_fds_read_mode = m_fds_write_reg = 0;
- m_fds_data = auto_alloc_array_clear(machine(), UINT8, 65500 * 2);
+ m_fds_mirroring = PPU_MIRROR_VERT; // correct?
+
m_fds_ram = auto_alloc_array_clear(machine(), UINT8, 0x8000);
save_pointer(NAME(m_fds_ram), 0x8000);
diff --git a/src/mess/machine/nes_ave.c b/src/mess/machine/nes_ave.c
new file mode 100644
index 00000000000..3dee1c0c06b
--- /dev/null
+++ b/src/mess/machine/nes_ave.c
@@ -0,0 +1,207 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for AVE PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * AVE Nina-001 [mapper 34]
+ * AVE Nina-006/Nina-003/MB-91 [mapper 79]
+ * AVE Maxi 15 [mapper 234]
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_ave.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_NINA001 = &device_creator<nes_nina001_device>;
+const device_type NES_NINA006 = &device_creator<nes_nina006_device>;
+const device_type NES_MAXI15 = &device_creator<nes_maxi15_device>;
+
+
+nes_nina001_device::nes_nina001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NINA001, "NES Cart AVE Nina-001 PCB", tag, owner, clock, "nes_nina001", __FILE__)
+{
+}
+
+nes_nina006_device::nes_nina006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NINA006, "NES Cart AVE Nina-006 PCB", tag, owner, clock, "nes_nina006", __FILE__)
+{
+}
+
+nes_maxi15_device::nes_maxi15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_MAXI15, "NES Cart AVE Maxi 15 PCB", tag, owner, clock, "nes_maxi15", __FILE__)
+{
+}
+
+
+
+
+void nes_nina001_device::device_start()
+{
+ common_start();
+}
+
+void nes_nina001_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_nina006_device::device_start()
+{
+ common_start();
+}
+
+void nes_nina006_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+}
+
+
+void nes_maxi15_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_bank));
+ save_item(NAME(m_reg));
+}
+
+void nes_maxi15_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+
+ m_reg = 0;
+ m_bank = 0;
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ AVE NINA-001 board emulation
+
+ iNES: mapper 34
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_nina001_device::write_m)
+{
+ LOG_MMC(("nina-001 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1ffd:
+ prg32(data);
+ break;
+ case 0x1ffe:
+ chr4_0(data, CHRROM);
+ break;
+ case 0x1fff:
+ chr4_4(data, CHRROM);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ AVE NINA-003, NINA-006 and MB-91 boards emulation
+
+ Games: Krazy Kreatures, Poke Block, Puzzle, Pyramid,
+ Solitaire, Ultimate League Soccer
+
+ iNES: mapper 79
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_nina006_device::write_l)
+{
+ LOG_MMC(("nina-006 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset & 0x0100))
+ {
+ prg32(data >> 3);
+ chr8(data, CHRROM);
+ }
+}
+
+/*-------------------------------------------------
+
+ AVE Maxi 15 boards emulation
+
+ Games: Maxi 15
+
+ iNES: mapper 234
+
+ In MESS: Partially Supported.
+
+ -------------------------------------------------*/
+
+void nes_maxi15_device::update_banks()
+{
+ if (m_bank & 0x40)
+ {
+ prg32((m_bank & 0x0e) | (m_reg & 1));
+ chr8(((m_bank & 0x0e) << 2) | ((m_reg >> 4) & 7), m_chr_source);
+ }
+ else
+ {
+ prg32(m_bank & 0x0f);
+ chr8(((m_bank & 0x0f) << 2) | ((m_reg >> 4) & 3), m_chr_source);
+ }
+}
+
+READ8_MEMBER(nes_maxi15_device::read_h)
+{
+ LOG_MMC(("Maxi 15 read_h, offset: %04x\n", offset));
+
+ if (offset >= 0x7f80 && offset < 0x7fa0)
+ {
+ m_bank = hi_access_rom(offset);
+ set_nt_mirroring(BIT(m_bank, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ update_banks();
+ return m_bank;
+ }
+ if (offset >= 0x7fe8 && offset < 0x7ff8)
+ {
+ m_reg = hi_access_rom(offset);
+ update_banks();
+ return m_reg;
+ }
+
+ return hi_access_rom(offset);
+}
diff --git a/src/mess/machine/nes_ave.h b/src/mess/machine/nes_ave.h
new file mode 100644
index 00000000000..3fa5e365a29
--- /dev/null
+++ b/src/mess/machine/nes_ave.h
@@ -0,0 +1,67 @@
+#ifndef __NES_AVE_H
+#define __NES_AVE_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_nina001_device
+
+class nes_nina001_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_nina001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_nina006_device
+
+class nes_nina006_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_nina006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_maxi15_device
+
+class nes_maxi15_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_maxi15_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+
+ virtual void pcb_reset();
+
+private:
+ void update_banks();
+ UINT8 m_reg, m_bank;
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_NINA001;
+extern const device_type NES_NINA006;
+extern const device_type NES_MAXI15;
+
+#endif
diff --git a/src/mess/machine/nes_bandai.c b/src/mess/machine/nes_bandai.c
new file mode 100644
index 00000000000..b70237a54cd
--- /dev/null
+++ b/src/mess/machine/nes_bandai.c
@@ -0,0 +1,436 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Bandai PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Bandai LZ93D50 [mapper 16]
+ * Bandai FCG (alt name of the LZ93D50 or something different?) [mapper 16]
+ * Bandai LZ93D50 + 24C01 EEPROM [mapper 159]
+ * Bandai LZ93D50 + 24C02 EEPROM [mapper 16]
+ * Bandai Famicom Jump 2 (aka LZ93D50 + SRAM) [mapper 153]
+ * Bandai LZ93D50 + Datach Barcode reader [mapper 34]
+ * Bandai Karaoke Studio [mapper 188]
+ * Bandai Oeka Kids [mapper 96]
+
+ TODO:
+ - investigate why EEPROM does not work
+ - try to implement some sort of Datach emulation
+ - try to implement some sort of Karaoke emulation
+ - add support to the PPU for the code necessary to Oeka Kids games (also needed by UNL-DANCE2000 PCB)
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_bandai.h"
+
+#include "cpu/m6502/m6502.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_KARAOKESTUDIO = &device_creator<nes_karaokestudio_device>;
+const device_type NES_OEKAKIDS = &device_creator<nes_oekakids_device>;
+const device_type NES_LZ93D50 = &device_creator<nes_lz93d50_device>;
+const device_type NES_LZ93D50_24C01 = &device_creator<nes_lz93d50_24c01_device>;
+const device_type NES_LZ93D50_24C02 = &device_creator<nes_lz93d50_24c02_device>;
+const device_type NES_FCG = &device_creator<nes_fcg_device>;
+const device_type NES_DATACH = &device_creator<nes_datach_device>;
+const device_type NES_FJUMP2 = &device_creator<nes_fjump2_device>;
+
+
+nes_karaokestudio_device::nes_karaokestudio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_KARAOKESTUDIO, "NES Cart Bandai Karaoke Studio PCB", tag, owner, clock, "nes_karaoke", __FILE__)
+{
+}
+
+nes_oekakids_device::nes_oekakids_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_OEKAKIDS, "NES Cart Bandai Oeka Kids PCB", tag, owner, clock, "nes_oeka", __FILE__)
+{
+}
+
+nes_lz93d50_device::nes_lz93d50_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_lz93d50_device::nes_lz93d50_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_LZ93D50, "NES Cart Bandai LZ93D50 PCB", tag, owner, clock, "nes_lz93d50", __FILE__)
+{
+}
+
+nes_lz93d50_24c01_device::nes_lz93d50_24c01_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)
+ : nes_lz93d50_device(mconfig, type, name, tag, owner, clock, shortname, source),
+ m_i2cmem(*this, "i2cmem")
+{
+}
+
+nes_lz93d50_24c01_device::nes_lz93d50_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_lz93d50_device(mconfig, NES_LZ93D50_24C01, "NES Cart Bandai LZ93D50 + 24C01 PCB", tag, owner, clock, "nes_lz93d50_ep1", __FILE__),
+ m_i2cmem(*this, "i2cmem")
+{
+}
+
+nes_lz93d50_24c02_device::nes_lz93d50_24c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_lz93d50_24c01_device(mconfig, NES_LZ93D50_24C02, "NES Cart Bandai LZ93D50 + 24C02 PCB", tag, owner, clock, "nes_lz93d50_ep2", __FILE__)
+{
+}
+
+nes_fcg_device::nes_fcg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_lz93d50_device(mconfig, NES_FCG, "NES Cart Bandai FCG PCB", tag, owner, clock, "nes_fcg", __FILE__)
+{
+}
+
+nes_datach_device::nes_datach_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_lz93d50_device(mconfig, NES_DATACH, "NES Cart Bandai Datach PCB", tag, owner, clock, "nes_datach", __FILE__)
+{
+}
+
+nes_fjump2_device::nes_fjump2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_lz93d50_device(mconfig, NES_FJUMP2, "NES Cart Bandai Famicom Jump II PCB", tag, owner, clock, "nes_fjump2", __FILE__)
+{
+}
+
+
+
+
+void nes_karaokestudio_device::device_start()
+{
+ common_start();
+}
+
+void nes_karaokestudio_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef((m_prg_chunks - 1) ^ 0x08);
+ chr8(0, m_chr_source);
+}
+
+void nes_oekakids_device::device_start()
+{
+ common_start();
+}
+
+void nes_oekakids_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_lz93d50_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+}
+
+void nes_lz93d50_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+void nes_lz93d50_24c01_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_i2c_mem));
+ save_item(NAME(m_i2c_clk));
+}
+
+void nes_lz93d50_24c01_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ m_i2c_mem = 0;
+ m_i2c_clk = 0;
+}
+
+void nes_fjump2_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_fjump2_device::pcb_reset()
+{
+ chr8(0, CHRRAM);
+ memset(m_reg, 0, sizeof(m_reg));
+ set_prg();
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bandai Karaoke Studio board emulation
+
+ Games: Karaoke Studio
+
+ Note: we currently do not emulate the mic
+
+ iNES: mapper 188
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_karaokestudio_device::write_h)
+{
+ LOG_MMC(("karaoke studio write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(data ^ 0x08);
+}
+
+/*-------------------------------------------------
+
+ Bandai Oeka Kids board emulation
+
+ Games: Oeka Kids - Anpanman no Hiragana Daisuki, Oeka
+ Kids - Anpanman to Oekaki Shiyou!!
+
+ This board can swap CHR whenever a PPU address line is
+ changed and we still do not emulate this.
+
+ iNES: mapper 96
+
+ In MESS: Preliminary Support.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_oekakids_device::write_h)
+{
+ LOG_MMC(("oeka kids write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(data);
+ chr4_0(0x00 | (data & 0x04), CHRRAM);
+ chr4_4(0x03 | (data & 0x04), CHRRAM);
+}
+
+/*-------------------------------------------------
+
+ Bandai LZ93D50 boards emulation
+
+ There are several variants: plain board with or without SRAM,
+ board + 24C01 EEPROM, board + 24C02 EEPROM, board + Barcode
+ Reader (DATACH).
+ We currently only emulate the base hardware.
+
+ Games: Crayon Shin-Chan - Ora to Poi Poi, Dragon Ball Z Gaiden,
+ Dragon Ball Z II & III, Rokudenashi Blues, SD Gundam
+ Gaiden - KGM2, Dragon Ball Z, Magical Taruruuto-kun, SD Gundam
+ Gaiden [with EEPROM], Dragon Ball, Dragon Ball 3, Famicom Jump,
+ Famicom Jump II [no EEPROM], Datach Games
+
+ At the moment, we don't support EEPROM I/O
+
+ iNES: mappers 16, 153 (see below), 157 & 159
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+void nes_lz93d50_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ /* 114 is the number of cycles per scanline */
+ /* TODO: change to reflect the actual number of cycles spent */
+ if (m_irq_enable)
+ {
+ if (m_irq_count <= 114)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_count = (0xffff - 114 + m_irq_count); // wrap around the 16 bits counter
+ }
+ m_irq_count -= 114;
+ }
+}
+
+WRITE8_MEMBER(nes_lz93d50_device::lz93d50_write)
+{
+ LOG_MMC(("lz93d50_write, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x0f)
+ {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ chr1_x(offset & 0x07, data, m_chr_source);
+ break;
+ case 8:
+ prg16_89ab(data);
+ break;
+ case 9:
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x0a:
+ m_irq_enable = data & 0x01;
+ break;
+ case 0x0b:
+ m_irq_count = (m_irq_count & 0xff00) | data;
+ break;
+ case 0x0c:
+ m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
+ break;
+ default:
+ logerror("lz93d50_write uncaught write, offset: %04x, data: %02x\n", offset, data);
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_lz93d50_device::write_m)
+{
+ LOG_MMC(("lz93d50 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (!m_battery && !m_prgram)
+ lz93d50_write(space, offset & 0x0f, data, mem_mask);
+ else if (m_battery)
+ m_battery[offset] = data;
+ else
+ m_prgram[offset] = data;
+}
+
+
+WRITE8_MEMBER(nes_lz93d50_24c01_device::write_h)
+{
+ LOG_MMC(("lz93d50_24c01 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x0f)
+ {
+ case 0x0d:
+ m_i2c_clk = BIT(data, 5);
+ m_i2c_mem = BIT(data, 6);
+ i2cmem_scl_write(m_i2cmem, m_i2c_clk);
+ i2cmem_sda_write(m_i2cmem, m_i2c_mem);
+ break;
+ default:
+ lz93d50_write(space, offset & 0x0f, data, mem_mask);
+ break;
+ }
+}
+
+READ8_MEMBER(nes_lz93d50_24c01_device::read_m)
+{
+ LOG_MMC(("lz93d50 EEPROM read, offset: %04x\n", offset));
+ return (i2cmem_sda_read(m_i2cmem) & 1) << 4;
+}
+
+//-------------------------------------------------
+// SERIAL I2C DEVICE
+//-------------------------------------------------
+
+static const i2cmem_interface bandai_24c01_i2cmem_interface =
+{
+ I2CMEM_SLAVE_ADDRESS, 4, 0x80
+};
+
+MACHINE_CONFIG_FRAGMENT( bandai_i2c_24c01 )
+ MCFG_I2CMEM_ADD("i2cmem", bandai_24c01_i2cmem_interface)
+MACHINE_CONFIG_END
+
+machine_config_constructor nes_lz93d50_24c01_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( bandai_i2c_24c01 );
+}
+
+
+
+static const i2cmem_interface bandai_24c02_i2cmem_interface =
+{
+ I2CMEM_SLAVE_ADDRESS, 4, 0x100
+};
+
+
+MACHINE_CONFIG_FRAGMENT( bandai_i2c_24c02 )
+ MCFG_I2CMEM_ADD("i2cmem", bandai_24c02_i2cmem_interface)
+MACHINE_CONFIG_END
+
+machine_config_constructor nes_lz93d50_24c02_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( bandai_i2c_24c02 );
+}
+
+
+/*-------------------------------------------------
+
+ Bandai BANDAI-JUMP2 boards emulation
+
+ This is a variant of LZ93D50, with SRAM and no EEPROM
+ The board is only used by Famicom Jump II, which
+ has no CHR and 512K of PRG, so it is not completely
+ clear if the CHR regs of LZ93D50 (i.e. offset & 0xf < 8)
+ would switch also CHR or if they are only used to select
+ upper 256K of PRG
+
+ iNES: mappers 153
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_fjump2_device::set_prg()
+{
+ UINT8 prg_base = 0;
+
+ for (int i = 0; i < 8; i++)
+ prg_base |= ((m_reg[i] & 0x01) << 4);
+
+ prg16_89ab(prg_base | m_reg[8]);
+ prg16_cdef(prg_base | 0x0f);
+}
+
+WRITE8_MEMBER(nes_fjump2_device::write_h)
+{
+ LOG_MMC(("fjump2 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x0f)
+ {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ case 8:
+ m_reg[offset & 0x0f] = data & 0x0f;
+ set_prg();
+ break;
+ default:
+ lz93d50_write(space, offset & 0x0f, data, mem_mask);
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_bandai.h b/src/mess/machine/nes_bandai.h
new file mode 100644
index 00000000000..09b426275b6
--- /dev/null
+++ b/src/mess/machine/nes_bandai.h
@@ -0,0 +1,154 @@
+#ifndef __NES_BANDAI_H
+#define __NES_BANDAI_H
+
+#include "machine/nes_nxrom.h"
+#include "machine/i2cmem.h"
+
+
+// ======================> nes_karaokestudio_device
+
+class nes_karaokestudio_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_karaokestudio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+ // TODO: add microphone I/O emulation
+};
+
+
+// ======================> nes_oekakids_device
+
+class nes_oekakids_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_oekakids_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+ // TODO: add oeka kids controller emulation
+};
+
+
+// ======================> nes_lz93d50_device
+
+class nes_lz93d50_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_lz93d50_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);
+ nes_lz93d50_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(lz93d50_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { lz93d50_write(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_lz93d50_24c01_device
+
+class nes_lz93d50_24c01_device : public nes_lz93d50_device
+{
+public:
+ // construction/destruction
+ nes_lz93d50_24c01_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);
+ nes_lz93d50_24c01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void device_start();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+ // TODO: fix EEPROM I/O emulation
+ required_device<i2cmem_device> m_i2cmem;
+ UINT8 m_i2c_mem, m_i2c_clk;
+};
+
+
+// ======================> nes_lz93d50_24c02_device
+
+class nes_lz93d50_24c02_device : public nes_lz93d50_24c01_device
+{
+public:
+ // construction/destruction
+ nes_lz93d50_24c02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+
+// ======================> nes_fcg_device
+
+class nes_fcg_device : public nes_lz93d50_device
+{
+public:
+ // construction/destruction
+ nes_fcg_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+
+// ======================> nes_datach_device
+
+class nes_datach_device : public nes_lz93d50_device
+{
+public:
+ // construction/destruction
+ nes_datach_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // TODO: add some kind of barcode reader emulation
+};
+
+
+// ======================> nes_fjump2_device
+
+class nes_fjump2_device : public nes_lz93d50_device
+{
+public:
+ // construction/destruction
+ nes_fjump2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+private:
+ void set_prg();
+ UINT8 m_reg[9];
+};
+
+
+
+// device type definition
+extern const device_type NES_KARAOKESTUDIO;
+extern const device_type NES_OEKAKIDS;
+extern const device_type NES_LZ93D50;
+extern const device_type NES_LZ93D50_24C01;
+extern const device_type NES_LZ93D50_24C02;
+extern const device_type NES_FCG;
+extern const device_type NES_DATACH;
+extern const device_type NES_FJUMP2;
+
+#endif
diff --git a/src/mess/machine/nes_benshieng.c b/src/mess/machine/nes_benshieng.c
new file mode 100644
index 00000000000..45bedc6da29
--- /dev/null
+++ b/src/mess/machine/nes_benshieng.c
@@ -0,0 +1,106 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Benshieng PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs used by Benshieng multigame carts series
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_benshieng.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_BENSHIENG = &device_creator<nes_benshieng_device>;
+
+
+nes_benshieng_device::nes_benshieng_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BENSHIENG, "NES Cart Benshieng PCB", tag, owner, clock, "nes_benshieng", __FILE__)
+{
+}
+
+
+
+
+void nes_benshieng_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_dipsetting));
+ save_item(NAME(m_mmc_prg_bank));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_benshieng_device::pcb_reset()
+{
+ m_dipsetting = 0;
+
+ m_mmc_prg_bank[0] = 0xff;
+ m_mmc_prg_bank[1] = 0xff;
+ m_mmc_prg_bank[2] = 0xff;
+ m_mmc_prg_bank[3] = 0xff;
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+ update_banks();
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ BMC-BS-5
+
+ Games: a few 4 in 1 multicarts
+
+ -------------------------------------------------*/
+
+void nes_benshieng_device::update_banks()
+{
+ prg8_89(m_mmc_prg_bank[0]);
+ prg8_ab(m_mmc_prg_bank[1]);
+ prg8_cd(m_mmc_prg_bank[2]);
+ prg8_ef(m_mmc_prg_bank[3]);
+ chr2_0(m_mmc_vrom_bank[0], CHRROM);
+ chr2_2(m_mmc_vrom_bank[1], CHRROM);
+ chr2_4(m_mmc_vrom_bank[2], CHRROM);
+ chr2_6(m_mmc_vrom_bank[3], CHRROM);
+}
+
+WRITE8_MEMBER(nes_benshieng_device::write_h)
+{
+ UINT8 helper = (offset & 0xc00) >> 10;
+ LOG_MMC(("benshieng write_h, offset: %04x, data: %02x\n", offset, data));
+// m_mmc_dipsetting = ioport("CARTDIPS")->read();
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ m_mmc_vrom_bank[helper] = offset & 0x1f;
+ break;
+ case 0x2000:
+ if (BIT(offset, m_dipsetting + 4)) // mmc_dipsetting is always zero atm, given we have no way to add cart-based DIPs
+ m_mmc_prg_bank[helper] = offset & 0x0f;
+ break;
+ }
+ update_banks();
+}
diff --git a/src/mess/machine/nes_benshieng.h b/src/mess/machine/nes_benshieng.h
new file mode 100644
index 00000000000..a3447ca65e1
--- /dev/null
+++ b/src/mess/machine/nes_benshieng.h
@@ -0,0 +1,32 @@
+#ifndef __NES_BENSHIENG_H
+#define __NES_BENSHIENG_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_benshieng_device
+
+class nes_benshieng_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_benshieng_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void update_banks();
+ UINT8 m_dipsetting;
+ UINT8 m_mmc_prg_bank[4];
+ UINT8 m_mmc_vrom_bank[4];
+};
+
+
+// device type definition
+extern const device_type NES_BENSHIENG;
+
+#endif
diff --git a/src/mess/machine/nes_bootleg.c b/src/mess/machine/nes_bootleg.c
new file mode 100644
index 00000000000..a7cddf9c380
--- /dev/null
+++ b/src/mess/machine/nes_bootleg.c
@@ -0,0 +1,1558 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Bootleg PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the PCBs used in FDS2NES conversions which are common in the Taiwanese & HK markets
+ Notice that many of these have unusual PRG sizes (32KB+8KB, 32KB+24KB) partially mapped in the WRAM
+ area, or WRAM overlapping the usual PRG area, so that we often skip the usual bankswitching mechanisms
+ in favor of direct handling of the PRG accesses
+
+ TODO:
+ - review all PCBs and fix the starting banks (which are often the main problem of not working games)
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_bootleg.h"
+
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_AX5705 = &device_creator<nes_ax5705_device>;
+const device_type NES_SC127 = &device_creator<nes_sc127_device>;
+const device_type NES_MARIOBABY = &device_creator<nes_mbaby_device>;
+const device_type NES_ASN = &device_creator<nes_asn_device>;
+const device_type NES_SMB3PIRATE = &device_creator<nes_smb3p_device>;
+const device_type NES_BTL_DNINJA = &device_creator<nes_btl_dn_device>;
+const device_type NES_WHIRLWIND_2706 = &device_creator<nes_whirl2706_device>;
+const device_type NES_SMB2J = &device_creator<nes_smb2j_device>;
+const device_type NES_SMB2JA = &device_creator<nes_smb2ja_device>;
+const device_type NES_SMB2JB = &device_creator<nes_smb2jb_device>;
+const device_type NES_SMB2JC = &device_creator<nes_smb2jc_device>;
+const device_type NES_TOBIDASE = &device_creator<nes_tobidase_device>;
+const device_type NES_LH32 = &device_creator<nes_lh32_device>;
+const device_type NES_LH10 = &device_creator<nes_lh10_device>;
+const device_type NES_2708 = &device_creator<nes_2708_device>;
+const device_type NES_AC08 = &device_creator<nes_ac08_device>;
+const device_type NES_UNL_BB = &device_creator<nes_unl_bb_device>;
+const device_type NES_MMALEE = &device_creator<nes_mmalee_device>;
+const device_type NES_SHUIGUAN = &device_creator<nes_shuiguan_device>;
+
+
+nes_ax5705_device::nes_ax5705_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_AX5705, "NES Cart AX5705 PCB", tag, owner, clock, "nes_ax5705", __FILE__)
+{
+}
+
+nes_sc127_device::nes_sc127_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SC127, "NES Cart SC-127 PCB", tag, owner, clock, "nes_sc127", __FILE__)
+{
+}
+
+nes_mbaby_device::nes_mbaby_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_MARIOBABY, "NES Cart Mario Baby Bootleg PCB", tag, owner, clock, "nes_mbaby", __FILE__)
+{
+}
+
+nes_asn_device::nes_asn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_ASN, "NES Cart Ai Senshi Nicol Bootleg PCB", tag, owner, clock, "nes_asn", __FILE__)
+{
+}
+
+nes_smb3p_device::nes_smb3p_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SMB3PIRATE, "NES Cart Super Mario Bros. 3 Pirate PCB", tag, owner, clock, "nes_smb3p", __FILE__)
+{
+}
+
+nes_btl_dn_device::nes_btl_dn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BTL_DNINJA, "NES Cart DragonNinja Pirate PCB", tag, owner, clock, "nes_btl_dn", __FILE__)
+{
+}
+
+nes_whirl2706_device::nes_whirl2706_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WHIRLWIND_2706, "NES Cart Whirlwind 2706 PCB", tag, owner, clock, "nes_whirl2706", __FILE__)
+{
+}
+
+nes_smb2j_device::nes_smb2j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SMB2J, "NES Cart Super Mario Bros. 2 Jpn PCB", tag, owner, clock, "nes_smb2j", __FILE__)
+{
+}
+
+nes_smb2ja_device::nes_smb2ja_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SMB2JA, "NES Cart Super Mario Bros. 2 Jpn (Alt) PCB", tag, owner, clock, "nes_smb2ja", __FILE__)
+{
+}
+
+nes_smb2jb_device::nes_smb2jb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SMB2JB, "NES Cart Super Mario Bros. 2 Jpn (Alt 2) PCB", tag, owner, clock, "nes_smb2jb", __FILE__)
+{
+}
+
+nes_smb2jc_device::nes_smb2jc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SMB2JC, "NES Cart Super Mario Bros. 2 Jpn (Alt 3) PCB", tag, owner, clock, "nes_smb2jc", __FILE__)
+{
+}
+
+nes_tobidase_device::nes_tobidase_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TOBIDASE, "NES Cart Tobidase Daisakusen Pirate PCB", tag, owner, clock, "nes_tobidase", __FILE__)
+{
+}
+
+nes_lh32_device::nes_lh32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_LH32, "NES Cart LH-32 Pirate PCB", tag, owner, clock, "nes_lh32", __FILE__)
+{
+}
+
+nes_lh10_device::nes_lh10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_LH10, "NES Cart LH-10 Pirate PCB", tag, owner, clock, "nes_lh10", __FILE__)
+{
+}
+
+nes_2708_device::nes_2708_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_2708, "NES Cart BTL-2708 Pirate PCB", tag, owner, clock, "nes_2708", __FILE__)
+{
+}
+
+nes_ac08_device::nes_ac08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_AC08, "NES Cart AC08 Pirate PCB", tag, owner, clock, "nes_ac08", __FILE__)
+{
+}
+
+nes_unl_bb_device::nes_unl_bb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_UNL_BB, "NES Cart FDS+CHR Pirate PCB", tag, owner, clock, "nes_unl_bb", __FILE__)
+{
+}
+
+nes_mmalee_device::nes_mmalee_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_MMALEE, "NES Cart Super Mario Bros. Malee 2 Pirate PCB", tag, owner, clock, "nes_mmalee", __FILE__)
+{
+}
+
+nes_shuiguan_device::nes_shuiguan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SHUIGUAN, "NES Cart Shui Guan Pipe Pirate PCB", tag, owner, clock, "nes_shuiguan", __FILE__)
+{
+}
+
+
+
+
+void nes_ax5705_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_mmc_prg_bank));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_ax5705_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ chr8(0, m_chr_source);
+
+ m_mmc_prg_bank[0] = 0;
+ m_mmc_prg_bank[1] = 1;
+ prg8_89(m_mmc_prg_bank[0]);
+ prg8_ab(m_mmc_prg_bank[1]);
+ prg8_cd(0xfe);
+ prg8_ef(0xff);
+
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+void nes_sc127_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+}
+
+void nes_sc127_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0xff);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+void nes_mbaby_device::device_start()
+{
+ common_start();
+ irq_timer = timer_alloc(TIMER_IRQ);
+ irq_timer->reset();
+
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_latch));
+}
+
+void nes_mbaby_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32((m_prg_chunks - 1) >> 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_latch = 0;
+}
+
+void nes_asn_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_asn_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32((m_prg_chunks - 1) >> 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_smb3p_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+}
+
+void nes_smb3p_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg8_89((m_prg_chunks << 1) - 1);
+ prg8_ab(0);
+ prg8_cd(0);
+ prg8_ef((m_prg_chunks << 1) - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+void nes_btl_dn_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_count));
+}
+
+void nes_btl_dn_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_count = 0;
+}
+
+void nes_whirl2706_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_whirl2706_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0xff);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_smb2j_device::device_start()
+{
+ common_start();
+}
+
+void nes_smb2j_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_smb2ja_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+}
+
+void nes_smb2ja_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg8_89(0xfc);
+ prg8_ab(0xfd);
+ prg8_cd(0xfe);
+ prg8_ef(0xff);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+void nes_smb2jb_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+}
+
+void nes_smb2jb_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg8_89(0x08);
+ prg8_ab(0x09);
+ prg8_cd(0);
+ prg8_ef(0x0b);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+void nes_smb2jc_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_prg_base));
+}
+
+void nes_smb2jc_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ chr8(0, m_chr_source);
+ prg8_89(1);
+ prg8_ab(0);
+ prg8_cd(0);
+ prg8_ef(9);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ m_prg_base = 1;
+}
+
+
+void nes_tobidase_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_tobidase_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(2);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_lh32_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_lh32_device::pcb_reset()
+{
+ chr8(0, CHRRAM);
+
+ prg32((m_prg_chunks - 1) >> 1);
+ // 0xc000-0xdfff reads/writes WRAM
+ m_latch = 0xf;
+}
+
+void nes_lh10_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_reg));
+}
+
+void nes_lh10_device::pcb_reset()
+{
+ chr8(0, CHRRAM);
+
+ prg8_89(0);
+ prg8_ab(0);
+ // 0xc000-0xdfff reads/writes WRAM
+ prg8_ef(0xff);
+ memset(m_reg, 0, sizeof(m_reg));
+ m_latch = 0;
+}
+
+void nes_2708_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_2708_device::pcb_reset()
+{
+ chr8(0, CHRRAM);
+
+ prg32(7);
+ // the upper PRG banks never change, but there are 8K of WRAM overlayed to the ROM area based on reg1
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+}
+
+void nes_ac08_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_ac08_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ chr8(0, m_chr_source);
+ prg32(0xff);
+ m_latch = 0xff;
+}
+
+void nes_unl_bb_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_unl_bb_device::pcb_reset()
+{
+ chr8(0, CHRROM);
+ prg32(0xff);
+ // the upper PRG banks never change, but there are 8K of WRAM overlayed to the ROM area based on reg1
+ m_reg[0] = 0xff;
+ m_reg[1] = 0;
+}
+
+void nes_mmalee_device::device_start()
+{
+ common_start();
+}
+
+void nes_mmalee_device::pcb_reset()
+{
+ chr8(0, CHRROM);
+ prg32(0);
+}
+
+void nes_shuiguan_device::device_start()
+{
+ common_start();
+ irq_timer = timer_alloc(TIMER_IRQ);
+ // always running and checking for IRQ every 114 cycles? or resetting every frame?
+ irq_timer->adjust(attotime::zero, 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(114));
+
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_shuiguan_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32((m_prg_chunks << 1) - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Board UNL-AX5705
+
+ Games: Super Mario Bros. Pocker Mali (Crayon Shin-chan pirate hack)
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_ax5705_device::set_prg()
+{
+ prg8_89(m_mmc_prg_bank[0]);
+ prg8_ab(m_mmc_prg_bank[1]);
+}
+
+WRITE8_MEMBER(nes_ax5705_device::write_h)
+{
+ UINT8 bank;
+ LOG_MMC(("ax5705 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x700f)
+ {
+ case 0x0000:
+ m_mmc_prg_bank[0] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2);
+ set_prg();
+ break;
+ case 0x0008:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ m_mmc_prg_bank[1] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2);
+ set_prg();
+ break;
+ /* CHR banks 0, 1, 4, 5 */
+ case 0x2008:
+ case 0x200a:
+ case 0x4008:
+ case 0x400a:
+ bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ case 0x2009:
+ case 0x200b:
+ case 0x4009:
+ case 0x400b:
+ bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4);
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ /* CHR banks 2, 3, 6, 7 */
+ case 0x4000:
+ case 0x4002:
+ case 0x6000:
+ case 0x6002:
+ bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ case 0x4001:
+ case 0x4003:
+ case 0x6001:
+ case 0x6003:
+ bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4);
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ SC-127 Board
+
+ Games: Wario World II (Kirby Hack)
+
+ iNES: mapper 35
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_sc127_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE && m_irq_enable)
+ {
+ m_irq_count--;
+
+ if (!blanked && (m_irq_count == 0))
+ {
+ LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
+ machine().primary_screen->vpos(), machine().primary_screen->hpos()));
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_enable = 0;
+ }
+ }
+}
+
+WRITE8_MEMBER(nes_sc127_device::write_h)
+{
+ LOG_MMC(("sc127 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x0001:
+ prg8_ab(data);
+ break;
+ case 0x0002:
+// m_mmc_prg_bank[offset & 0x02] = data;
+ prg8_cd(data);
+ break;
+ case 0x1000:
+ case 0x1001:
+ case 0x1002:
+ case 0x1003:
+ case 0x1004:
+ case 0x1005:
+ case 0x1006:
+ case 0x1007:
+// m_mmc_vrom_bank[offset & 0x07] = data;
+ chr1_x(offset & 0x07, data, CHRROM);
+ break;
+ case 0x4002:
+ m_irq_enable = 0;
+ break;
+ case 0x4003:
+ m_irq_enable = 1;
+ break;
+ case 0x4005:
+ m_irq_count = data;
+ break;
+ case 0x5001:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ BTL-MARIOBABY
+
+ Games: Mario Baby, Ai Senshi Nicol
+
+ iNES: mapper 42
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_mbaby_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_IRQ)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ irq_timer->adjust(attotime::never);
+ }
+}
+
+WRITE8_MEMBER(nes_mbaby_device::write_h)
+{
+ LOG_MMC(("Mario Baby write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x7000)
+ {
+ switch (offset & 0x03)
+ {
+ case 0x00:
+ m_latch = data;
+ break;
+ case 0x01:
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x02:
+ /* Check if IRQ is being enabled */
+ if (!m_irq_enable && (data & 0x02))
+ {
+ m_irq_enable = 1;
+ irq_timer->adjust(machine().device<cpu_device>("maincpu")->cycles_to_attotime(24576));
+ }
+ if (!(data & 0x02))
+ {
+ m_irq_enable = 0;
+ irq_timer->adjust(attotime::never);
+ }
+ break;
+ }
+ }
+}
+
+READ8_MEMBER(nes_mbaby_device::read_m)
+{
+ LOG_MMC(("Mario Baby read_m, offset: %04x\n", offset));
+ return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)];
+}
+
+/*-------------------------------------------------
+
+ BTL-AISENSHINICOL
+
+ Games: Ai Senshi Nicol
+
+ iNES: mapper 42 with no IRQ and no NT, but CHR switch
+
+ In MESS: Partially Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_asn_device::write_h)
+{
+ LOG_MMC(("Ai Senshi Nicol write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x0000)
+ chr8(data, CHRROM);
+
+ if (offset == 0x7000)
+ m_latch = data;
+}
+
+READ8_MEMBER(nes_asn_device::read_m)
+{
+ LOG_MMC(("Ai Senshi Nicol read_m, offset: %04x\n", offset));
+ return m_prg[((m_latch * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)];
+}
+
+
+/*-------------------------------------------------
+
+ BTL-SMB3
+
+ Games: Super Mario Bros. 3 Pirate
+
+ iNES: mapper 106
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_smb3p_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ if ((0xffff - m_irq_count) < 114)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_enable = 0;
+ }
+
+ m_irq_count = (m_irq_count + 114) & 0xffff;
+ }
+}
+
+WRITE8_MEMBER(nes_smb3p_device::write_h)
+{
+ LOG_MMC(("btl_smb3_w, offset: %04x, data: %02x\n", offset, data));
+ switch (offset & 0x0f)
+ {
+ case 0x00:
+ case 0x02:
+ chr1_x(offset & 0x07, data & 0xfe, CHRROM);
+ break;
+ case 0x01:
+ case 0x03:
+ chr1_x(offset & 0x07, data | 0x01, CHRROM);
+ break;
+ case 0x04: case 0x05:
+ case 0x06: case 0x07:
+ chr1_x(offset & 0x07, data, CHRROM);
+ break;
+ case 0x08:
+ prg8_89(data | 0x10);
+ break;
+ case 0x09:
+ prg8_ab(data);
+ break;
+ case 0x0a:
+ prg8_cd(data);
+ break;
+ case 0x0b:
+ prg8_ef(data | 0x10);
+ break;
+ case 0x0c:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x0d:
+ m_irq_count = 0;
+ m_irq_enable = 0;
+ break;
+ case 0x0e:
+ m_irq_count = (m_irq_count & 0xff00) | data;
+ break;
+ case 0x0f:
+ m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
+ m_irq_enable = 1;
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ BTL-DRAGONNINJA
+
+ Games: Dragon Ninja (Bootleg), Super Mario Bros. 8
+
+ iNES: mapper 222
+
+ In MESS: Unsupported.
+
+ -------------------------------------------------*/
+
+/* Scanline based IRQ ? */
+void nes_btl_dn_device::hblank_irq(int scanline, int vblank, int blanked )
+{
+ if (!m_irq_count || ++m_irq_count < 240)
+ return;
+
+ m_irq_count = 0;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+}
+
+WRITE8_MEMBER(nes_btl_dn_device::write_h)
+{
+ UINT8 bank;
+ LOG_MMC(("btl_dn write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x1000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ prg8_ab(data);
+ break;
+ case 0x3000:
+ case 0x3002:
+ case 0x4000:
+ case 0x4002:
+ case 0x5000:
+ case 0x5002:
+ case 0x6000:
+ case 0x6002:
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0002) >> 1);
+ chr1_x(bank, data, CHRROM);
+ break;
+ case 0x7000:
+ m_irq_count = data;
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ BOOTLEG FC VERSIONS OF FDS GAMES
+
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ WHIRLWIND-2706
+
+ Games: Meikyuu Jiin Dababa (FDS conversion) and a few
+ others
+
+ This PCB maps PRG in 0x6000-0x7fff
+
+ iNES: mapper 108
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_whirl2706_device::write_h)
+{
+ LOG_MMC(("whirl2706 write_h, offset: %04x, data: %02x\n", offset, data));
+ m_latch = data;
+}
+
+READ8_MEMBER(nes_whirl2706_device::read_m)
+{
+ LOG_MMC(("whirl2706 read_m, offset: %04x\n", offset));
+ return m_prg[(m_latch * 0x2000 + (offset & 0x1fff)) & (m_prg_size - 1)];
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board SMB2J
+
+ Games: Super Mario Bros. 2 Pirate (LF36)
+
+ iNES: mapper 43
+
+ This is actually strange. There is one variant of
+ mappers 43 games which maps the PRG linearly from
+ 0x5000 to 0xffff and then can switch the upper 32K
+ part (0x8000-0xffff). These are games with 80K of
+ PRG (SMB2 conversions only? also the Zanac FDS even
+ if has smaller PRG?).
+ Then there is a second variant (Volleyball FDS) with
+ only 32K of PRG which do not switches PRG (no 0x4200
+ writes) and probably mirrors lower 12K in 0x5000-0x7fff.
+ The Zanac FDS conversion might not belong to this
+ board...
+
+ In any case, for the moment we split the two variants
+ in smb2j and smb2jc!
+
+ In MESS: Unsupported? The only image I found is not working
+ (not even in NEStopia). Partially supported the
+ smb2jc variant (to be investigated...)
+
+ -------------------------------------------------*/
+
+/* This PCB can map PRG RAM to 0x8000-0xdfff like MMC5 */
+void nes_smb2j_device::prgram_bank8_x(int start, int bank)
+{
+ assert(start < 4);
+ assert(bank >= 0);
+
+ bank &= (m_prgram_size / 0x2000) - 1;
+
+ // PRG RAM is mapped after PRG ROM
+ m_prg_bank[start] = m_prg_chunks + bank;
+ m_prg_bank_mem[start]->set_entry(m_prg_bank[start]);
+}
+
+WRITE8_MEMBER(nes_smb2j_device::write_h)
+{
+ int bank = (((offset >> 8) & 0x03) * 0x20) + (offset & 0x1f);
+
+ LOG_MMC(("smb2j_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (offset & 0x0800)
+ {
+ if (offset & 0x1000)
+ {
+ if (bank * 2 >= m_prg_chunks)
+ {
+ prgram_bank8_x(2, 0);
+ prgram_bank8_x(3, 0);
+ }
+ else
+ {
+ LOG_MMC(("smb2j_w, selecting upper 16KB bank of #%02x\n", bank));
+ prg16_cdef(2 * bank + 1);
+ }
+ }
+ else
+ {
+ if (bank * 2 >= m_prg_chunks)
+ {
+ prgram_bank8_x(0, 0);
+ prgram_bank8_x(1, 0);
+ }
+ else
+ {
+ LOG_MMC(("smb2j_w, selecting lower 16KB bank of #%02x\n", bank));
+ prg16_89ab(2 * bank);
+ }
+ }
+ }
+ else
+ {
+ if (bank * 2 >= m_prg_chunks)
+ {
+ prgram_bank8_x(0, 0);
+ prgram_bank8_x(1, 0);
+ prgram_bank8_x(2, 0);
+ prgram_bank8_x(3, 0);
+ }
+ else
+ {
+ LOG_MMC(("smb2j_w, selecting 32KB bank #%02x\n", bank));
+ prg32(bank);
+ }
+ }
+}
+
+
+void nes_smb2jc_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ if ((0xfff - m_irq_count) <= 114)
+ {
+ m_irq_count = (m_irq_count + 1) & 0xfff;
+ m_irq_enable = 0;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ m_irq_count += 114;
+ }
+}
+WRITE8_MEMBER(nes_smb2jc_device::write_l)
+{
+ LOG_MMC(("smb2jc write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x122)
+ m_irq_enable = data & 3;
+}
+
+WRITE8_MEMBER(nes_smb2jc_device::write_ex)
+{
+ LOG_MMC(("smb2jc write_ex, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 2)
+ {
+ int temp = 0;
+
+ // According to hardware tests
+ if (data & 1)
+ temp = 3;
+ else
+ temp = 4 + ((data & 7) >> 1);
+
+ prg8_cd(temp);
+ }
+}
+
+READ8_MEMBER(nes_smb2jc_device::read_l)
+{
+ LOG_MMC(("smb2jc read_l, offset: %04x\n", offset));
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ return m_prg[0x10000 + (offset & 0x0fff)];
+
+ return ((offset + 0x4000) & 0xff00) >> 8;
+}
+
+READ8_MEMBER(nes_smb2jc_device::read_m)
+{
+ LOG_MMC(("smb2jc read_m, offset: %04x\n", offset));
+ return m_prg[0x4000 + offset];
+}
+
+/*-------------------------------------------------
+
+ BTL-SMB2A
+
+ Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2)
+
+ iNES: mapper 40
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_smb2ja_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ if ((0xfff - m_irq_count) <= 114)
+ {
+ m_irq_count = (m_irq_count + 1) & 0xfff;
+ m_irq_enable = 0;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ m_irq_count += 114;
+ }
+}
+
+WRITE8_MEMBER(nes_smb2ja_device::write_h)
+{
+ LOG_MMC(("smb2ja write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ break;
+ case 0x2000:
+ m_irq_enable = 1;
+ break;
+ case 0x6000:
+ prg8_cd(data);
+ break;
+ }
+}
+
+READ8_MEMBER(nes_smb2ja_device::read_m)
+{
+ LOG_MMC(("smb2ja read_m, offset: %04x\n", offset));
+ return m_prg[(0xfe * 0x2000 + (offset & 0x1fff)) & (m_prg_size - 1)];
+}
+
+/*-------------------------------------------------
+
+ BTL-SMB2B
+
+ Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2)
+
+ This was marked as Alt. Levels. is it true?
+
+ iNES: mapper 50
+
+ In MESS: Partially Supported.
+
+ -------------------------------------------------*/
+
+void nes_smb2jb_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ if (m_irq_count < 0x1000)
+ {
+ if ((0x1000 - m_irq_count) <= 114)
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ else
+ m_irq_count += 114;
+ }
+ else
+ m_irq_count += 114;
+
+ m_irq_count &= 0xffff; // according to docs is 16bit counter -> it wraps only after 0xffff?
+ }
+}
+
+WRITE8_MEMBER(nes_smb2jb_device::write_l)
+{
+ UINT8 prg;
+ LOG_MMC(("smb2jb write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ switch (offset & 0x160)
+ {
+ case 0x020:
+ case 0x0a0:
+ prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2);
+ prg8_cd(prg);
+ break;
+ case 0x120:
+ case 0x1a0:
+ m_irq_enable = data & 0x01;
+ break;
+ }
+}
+
+READ8_MEMBER(nes_smb2jb_device::read_m)
+{
+ LOG_MMC(("smb2jb read_m, offset: %04x\n", offset));
+ return m_prg[((0x0f * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)];
+}
+
+/* This goes to 0x4020-0x403f & 0x40a0-0x40bf */
+WRITE8_MEMBER(nes_smb2jb_device::write_ex)
+{
+ UINT8 prg;
+ LOG_MMC(("smb2jb write_ex, offset: %04x, data: %02x\n", offset, data));
+
+ if ((offset < 0x20) || (offset >= 0x80 && offset < 0xa0))
+ {
+ prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2);
+ prg8_cd(prg);
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board used for FDS conversion
+
+ Games: Tobidase Daisakusen (FDS conversion)
+
+ This PCB maps PRG in 0x6000-0x7fff
+
+ iNES: mapper 120
+
+ In MESS: Partially Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_tobidase_device::write_l)
+{
+ LOG_MMC(("tobidase write_h, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x4100;
+
+ if ((offset & 0x63c0) == 0x41c0)
+ m_latch = data & 0x0f;
+}
+
+READ8_MEMBER(nes_tobidase_device::read_m)
+{
+ LOG_MMC(("tobidase read_m, offset: %04x\n", offset));
+ if (m_latch >= 0x0c)
+ m_latch -= 4;
+ return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)];
+}
+
+/*-------------------------------------------------
+
+ UNL-LH32
+
+ Games: Monty no Doki Doki Daidassou (FDS conversion)
+
+ This PCB maps WRAM in 0xc000-0xdfff and PRG in 0x6000-0x7fff
+
+ iNES:
+
+ In MESS: Supported.
+
+-------------------------------------------------*/
+
+READ8_MEMBER(nes_lh32_device::read_m)
+{
+ LOG_MMC(("lh32 read_m, offset: %04x\n", offset));
+ return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)];
+}
+
+READ8_MEMBER(nes_lh32_device::read_h)
+{
+ LOG_MMC(("lh32 read_h, offset: %04x\n", offset));
+
+ if (offset >= 0x4000 && offset < 0x6000)
+ return m_prgram[offset & 0x1fff];
+
+ return hi_access_rom(offset);
+}
+
+WRITE8_MEMBER(nes_lh32_device::write_m)
+{
+ LOG_MMC(("lh32 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0) // 0x6000 only?
+ {
+// printf("write %x\n", data);
+ m_latch = data & 0xf;
+ }
+}
+
+WRITE8_MEMBER(nes_lh32_device::write_h)
+{
+ LOG_MMC(("lh32 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x4000 && offset < 0x6000)
+ m_prgram[offset & 0x1fff] = data;
+}
+
+/*-------------------------------------------------
+
+ UNL-LH10
+
+ Games: Fuuun Shaolin Kyo (FDS conversion)
+
+ This PCB maps WRAM in 0xc000-0xdfff and PRG in 0x6000-0x7fff
+ This is very similar to KS7037 (not sure which conversion
+ uses that one)
+
+ iNES:
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_lh10_device::update_prg()
+{
+ prg8_89(m_reg[6]);
+ prg8_ab(m_reg[7]);
+}
+
+READ8_MEMBER(nes_lh10_device::read_m)
+{
+ LOG_MMC(("lh10 read_m, offset: %04x\n", offset));
+ return m_prg[(0x0e * 0x2000) + (offset & 0x1fff)];
+}
+
+READ8_MEMBER(nes_lh10_device::read_h)
+{
+ LOG_MMC(("lh10 read_h, offset: %04x\n", offset));
+
+ if (offset >= 0x4000 && offset < 0x6000)
+ return m_prgram[offset & 0x1fff];
+
+ return hi_access_rom(offset);
+}
+
+WRITE8_MEMBER(nes_lh10_device::write_h)
+{
+ LOG_MMC(("lh10 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x4000 && offset < 0x6000)
+ m_prgram[offset & 0x1fff] = data;
+
+ else
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ m_latch = data & 7;
+ break;
+ case 0x0001:
+ m_reg[m_latch] = data;
+ update_prg();
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ BTL-2708
+
+ Games: Doki Doki Panic (FDS conversion)
+
+ iNES: mapper 103?
+
+ This board has a very unique setup, with 8KB of WRAM
+ in 0x6000-0x7fff and other 8KB of WRAM in 0xb800-0xd7ff
+ which can be switched in 2KB chunks (we attempt to
+ emulate this by intercepting reads in that area before
+ they get to the PRG banks...)
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(nes_2708_device::read_m)
+{
+ LOG_MMC(("btl-2708 read_m, offset: %04x\n", offset));
+ if (!m_reg[1])
+ return m_prgram[offset]; // lower 8K of WRAM
+ else
+ return m_prg[(m_reg[0] * 0x2000) + (offset & 0x1fff)];
+}
+
+WRITE8_MEMBER(nes_2708_device::write_m)
+{
+ LOG_MMC(("btl-2708 write_m, offset: %04x, data: %02x\n", offset, data));
+// if (!m_reg[1])
+ m_prgram[offset] = data; // lower 8K of WRAM
+}
+
+READ8_MEMBER(nes_2708_device::read_h)
+{
+ LOG_MMC(("btl-2708 read_h, offset: %04x\n", offset));
+
+ if (offset >= 0x3800 && offset < 0x5800 && !m_reg[1])
+ return m_prgram[0x2000 + ((offset - 0x3800) & 0x1fff)]; // higher 8K of WRAM
+
+ return hi_access_rom(offset);
+}
+
+WRITE8_MEMBER(nes_2708_device::write_h)
+{
+ LOG_MMC(("btl-2708 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x3800 && offset < 0x5800/* && !m_reg[1]*/)
+ m_prgram[0x2000 + ((offset - 0x3800) & 0x1fff)] = data; // higher 8K of WRAM
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ m_reg[0] = data & 0x0f; // PRG bank in 0x6000-0x7fff
+ break;
+ case 0x6000:
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x7000:
+ m_reg[1] = BIT(data, 4); // bit4 enables the two WRAM banks
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ UNL-AC08
+
+ Games: Green Beret (FDS conversions)
+
+ iNES:
+
+ This board has two PRG chips. The first (128K) is
+ connected to 0x6000-0x7fff and switches among the
+ 16x8K banks; the second (32K) is fixed in 0x8000-0xffff
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ac08_device::write_ex)
+{
+ LOG_MMC(("AC-08 write_ex, offset: %04x, data: %02x\n", offset, data));
+ if (offset == 5) // $4025
+ set_nt_mirroring(!BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+}
+
+READ8_MEMBER(nes_ac08_device::read_m)
+{
+ LOG_MMC(("AC-08 read_m, offset: %04x\n", offset));
+ return m_prg[(m_latch * 0x2000) + (offset & 0x1fff)];
+}
+
+WRITE8_MEMBER(nes_ac08_device::write_h)
+{
+ LOG_MMC(("AC-08 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 1)
+ m_latch = (data >> 1) & 0x0f;
+ else
+ m_latch = data & 0x0f; // apparently there also is a Castlevania FDS conversion using same board with different banking lines
+}
+
+/*-------------------------------------------------
+
+ UNL-BB
+
+ Games: Bubble Bobble and other FDS conversions with CHRROM!
+
+ iNES:
+
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(nes_unl_bb_device::read_m)
+{
+ LOG_MMC(("unl-bb read_m, offset: %04x\n", offset));
+ return m_prg[(((m_reg[0] & 3 & m_prg_mask) * 0x2000) + (offset & 0x1fff))];
+}
+
+WRITE8_MEMBER(nes_unl_bb_device::write_h)
+{
+ LOG_MMC(("unl-bb write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset & 0x1000))
+ {
+ m_reg[0] = data;
+ m_reg[1] = data;
+ }
+ else
+ m_reg[1] = data & 1; // Pro Wrestling uses this
+
+ chr8(m_reg[1] & 3, m_chr_source);
+}
+
+/*-------------------------------------------------
+
+ BTL-MARIO1-MALEE2 (aka Genius Merio Bros)
+
+ Games: Super Mario Bros Malee 2
+
+ iNES:
+
+ This PCB has two PRG chips (32K+2K) + one CHR chip (8K)
+ + 2KB of WRAM
+ The second PRG chip (2K) is connected at 0x6000-0x6800
+ while WRAM is at 0x7000-0x7800
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(nes_mmalee_device::read_m)
+{
+ LOG_MMC(("mmalee read_m, offset: %04x\n", offset));
+
+ if (offset < 0x0800)
+ return m_prg[0x8000 + offset];
+ else if (m_prgram && offset >= 0x1000 && offset < 0x1800) // WRAM only in these 2K
+ return m_prgram[offset];
+
+ return ((offset + 0x6000) & 0xff00) >> 8;
+}
+
+WRITE8_MEMBER(nes_mmalee_device::write_m)
+{
+ LOG_MMC(("mmalee write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_prgram && offset >= 0x1000 && offset < 0x1800) // WRAM only in these 2K
+ m_prgram[offset] = data;
+}
+
+/*-------------------------------------------------
+
+ BTL-SHUIGUANPIPE
+
+ Games: Shui Guan Pipe (Gimmick Pirate)
+
+ iNES:
+
+ In MESS: Supported, but there are glitches (PPU or IRQ?)
+
+ -------------------------------------------------*/
+
+// timer always running and checking IRQ every 114 CPU cycles?
+void nes_shuiguan_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_IRQ)
+ {
+ m_irq_count++;
+ m_irq_count &= 0xff;
+
+ if (m_irq_enable && !m_irq_count)
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+WRITE8_MEMBER(nes_shuiguan_device::write_h)
+{
+ int bank;
+ LOG_MMC(("shuiguan write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ if (offset & 0x800 && !(offset & 0x0c)) // 0x8800-0x8803 + N*0x10
+ prg8_89(data);
+ break;
+ case 0x1000:
+ if (offset & 0x800 && !(offset & 0x0c)) // 0x9800-0x9803 + N*0x10
+ {
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ }
+ break;
+ case 0x2000:
+ if (!(offset & 0x800) && !(offset & 0x0c)) // 0xa000-0xa003 + N*0x10
+ prg8_cd(data);
+ if (offset & 0x800 && !(offset & 0x0c)) // 0xa800-0xa803 + N*0x10
+ prg8_ab(data);
+ break;
+ case 0x3000:
+ case 0x4000:
+ case 0x5000:
+ case 0x6000:
+ bank = (((offset + 0x1000) >> 11) | (offset >> 3)) & 0x07;
+ if (offset & 4)
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
+ else
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
+ chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
+ break;
+ case 0x7000:
+ switch (offset & 0x0c)
+ {
+ case 0x00: m_irq_count = (m_irq_count & 0xf0) | ((data & 0x0f) << 0); break;
+ case 0x04: m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4); break;
+ case 0x08: m_irq_enable= data; break;
+ case 0x0c: break;
+ }
+ break;
+ }
+}
+
+READ8_MEMBER(nes_shuiguan_device::read_m)
+{
+ // always first bank??
+ LOG_MMC(("shuiguan read_m, offset: %04x\n", offset));
+ return m_prg[offset & 0x1fff];
+}
diff --git a/src/mess/machine/nes_bootleg.h b/src/mess/machine/nes_bootleg.h
new file mode 100644
index 00000000000..74c964635f2
--- /dev/null
+++ b/src/mess/machine/nes_bootleg.h
@@ -0,0 +1,434 @@
+#ifndef __NES_BTL_H
+#define __NES_BTL_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_ax5705_device
+
+class nes_ax5705_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ax5705_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void set_prg();
+ UINT8 m_mmc_prg_bank[2];
+ UINT8 m_mmc_vrom_bank[8];
+};
+
+
+// ======================> nes_sc127_device
+
+class nes_sc127_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sc127_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_mbaby_device
+
+class nes_mbaby_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_mbaby_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+ int m_irq_enable;
+
+ static const device_timer_id TIMER_IRQ = 0;
+ emu_timer *irq_timer;
+};
+
+
+// ======================> nes_asn_device
+
+class nes_asn_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_asn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_smb3p_device
+
+class nes_smb3p_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_smb3p_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_btl_dn_device
+
+class nes_btl_dn_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_btl_dn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count;
+};
+
+
+// ======================> nes_whirl2706_device
+
+class nes_whirl2706_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_whirl2706_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_smb2j_device
+
+class nes_smb2j_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_smb2j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void prgram_bank8_x(int start, int bank);
+};
+
+
+// ======================> nes_smb2ja_device
+
+class nes_smb2ja_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_smb2ja_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_smb2jb_device
+
+class nes_smb2jb_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_smb2jb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_ex);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_smb2jc_device
+
+class nes_smb2jc_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_smb2jc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_ex);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+ UINT8 m_prg_base;
+};
+
+
+// ======================> nes_tobidase_device
+
+class nes_tobidase_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_tobidase_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_lh32_device
+
+class nes_lh32_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_lh32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_lh10_device
+
+class nes_lh10_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_lh10_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void update_prg();
+ UINT8 m_latch;
+ UINT8 m_reg[8];
+};
+
+
+// ======================> nes_2708_device
+
+class nes_2708_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_2708_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[2];
+};
+
+// ======================> nes_ac08_device
+
+class nes_ac08_device : public nes_nrom_device
+{
+public:
+ // nes_ac08_device/destruction
+ nes_ac08_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_ex);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+// ======================> nes_unl_bb_device
+
+class nes_unl_bb_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_unl_bb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[2];
+};
+
+// ======================> nes_mmalee_device
+
+class nes_mmalee_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_mmalee_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+// ======================> nes_shuiguan_device
+
+class nes_shuiguan_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_shuiguan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+ UINT8 m_mmc_vrom_bank[8];
+
+ static const device_timer_id TIMER_IRQ = 0;
+ emu_timer *irq_timer;
+};
+
+
+
+// device type definition
+extern const device_type NES_AX5705;
+extern const device_type NES_SC127;
+extern const device_type NES_MARIOBABY;
+extern const device_type NES_ASN;
+extern const device_type NES_SMB3PIRATE;
+extern const device_type NES_BTL_DNINJA;
+extern const device_type NES_WHIRLWIND_2706;
+extern const device_type NES_SMB2J;
+extern const device_type NES_SMB2JA;
+extern const device_type NES_SMB2JB;
+extern const device_type NES_SMB2JC;
+extern const device_type NES_TOBIDASE;
+extern const device_type NES_LH32;
+extern const device_type NES_LH10;
+extern const device_type NES_2708;
+extern const device_type NES_AC08;
+extern const device_type NES_UNL_BB;
+extern const device_type NES_MMALEE;
+extern const device_type NES_SHUIGUAN;
+
+
+#endif
diff --git a/src/mess/machine/nes_camerica.c b/src/mess/machine/nes_camerica.c
new file mode 100644
index 00000000000..b47d246c837
--- /dev/null
+++ b/src/mess/machine/nes_camerica.c
@@ -0,0 +1,220 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Camerica/Codemasters PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Camerica BF9093, BF9097, BF909X & ALGNV11 [mapper 71, two variants]
+ * Camerica BF9096 & ALGQV11 Boards [mapper 232]
+ * Camerica Golden Five [mapper 104]
+
+
+ TODO:
+ - check what causes flickering from PPU
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_camerica.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_BF9093 = &device_creator<nes_bf9093_device>;
+const device_type NES_BF9096 = &device_creator<nes_bf9096_device>;
+const device_type NES_GOLDEN5 = &device_creator<nes_golden5_device>;
+
+
+nes_bf9093_device::nes_bf9093_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BF9093, "NES Cart Camerica BF9093 PCB", tag, owner, clock, "nes_bf9093", __FILE__)
+{
+}
+
+nes_bf9096_device::nes_bf9096_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BF9096, "NES Cart Camerica BF9096 PCB", tag, owner, clock, "nes_bf9096", __FILE__)
+{
+}
+
+nes_golden5_device::nes_golden5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_GOLDEN5, "NES Cart Camerica Golden 5 PCB", tag, owner, clock, "nes_golden5", __FILE__)
+{
+}
+
+
+
+
+void nes_bf9093_device::device_start()
+{
+ common_start();
+}
+
+void nes_bf9093_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0xff);
+ chr8(0, m_chr_source);
+}
+
+void nes_bf9096_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+}
+
+void nes_bf9096_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ chr8(0, m_chr_source);
+
+ m_latch1 = 0x18;
+ m_latch2 = 0x00;
+ set_prg();
+}
+
+void nes_golden5_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_golden5_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0x00);
+ prg16_cdef(0x0f);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Camerica Boards (BF9093, BF9097, BF909X, ALGNV11)
+
+ Games: Linus Spacehead's Cosmic Crusade, Micro Machines,
+ Mig-29, Stunt Kids
+
+ To emulate NT mirroring for BF9097 board (missing in BF9093)
+ we use crc_hack, however Fire Hawk is broken (but without
+ mirroring there would be no helicopter graphics).
+
+ iNES: mapper 71
+
+ In MESS: Partially Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bf9093_device::write_h)
+{
+ LOG_MMC(("bf9093 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ case 0x1000:
+ if (m_pcb_ctrl_mirror)
+ set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ break;
+ case 0x4000:
+ case 0x5000:
+ case 0x6000:
+ case 0x7000:
+ prg16_89ab(data);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Camerica BF9096 & ALGQV11 Boards
+
+ Games: Quattro Adventure, Quattro Arcade, Quattro Sports
+
+ Writes to 0x8000-0x9fff set prg block to (data&0x18)>>1,
+ writes to 0xa000-0xbfff set prg page to data&3. selected
+ prg are: prg16_89ab = block|page, prg_cdef = 3|page.
+ For more info on the hardware to bypass the NES lockout, see
+ Kevtris' Camerica Mappers documentation.
+
+ iNES: mapper 232
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_bf9096_device::set_prg()
+{
+ prg16_89ab((m_latch2 & 0x03) | ((m_latch1 & 0x18) >> 1));
+ prg16_cdef(0x03 | ((m_latch1 & 0x18) >> 1));
+}
+
+WRITE8_MEMBER(nes_bf9096_device::write_h)
+{
+ LOG_MMC(("bf9096 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x2000)
+ m_latch1 = data;
+ else
+ m_latch2 = data;
+
+ set_prg();
+}
+
+/*-------------------------------------------------
+
+ Camerica Golden Five board
+
+ Games: Pegasus 5 in 1
+
+ iNES: mapper 104
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_golden5_device::write_h)
+{
+ LOG_MMC(("golden5 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x4000)
+ {
+ if (data & 0x08)
+ {
+ m_latch = ((data & 0x07) << 4) | (m_latch & 0x0f);
+ prg16_89ab(m_latch);
+ prg16_cdef(((data & 0x07) << 4) | 0x0f);
+ }
+
+ }
+ else
+ {
+ m_latch = (m_latch & 0x70) | (data & 0x0f);
+ prg16_89ab(m_latch);
+ }
+}
diff --git a/src/mess/machine/nes_camerica.h b/src/mess/machine/nes_camerica.h
new file mode 100644
index 00000000000..b24411be908
--- /dev/null
+++ b/src/mess/machine/nes_camerica.h
@@ -0,0 +1,71 @@
+#ifndef __NES_CAMERICA_H
+#define __NES_CAMERICA_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_bf9093_device
+
+class nes_bf9093_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bf9093_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bf9096_device
+
+class nes_bf9096_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bf9096_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual DECLARE_WRITE8_MEMBER(write_m) { write_h(space, offset, data, mem_mask); }
+
+ virtual void pcb_reset();
+
+private:
+ void set_prg();
+ UINT8 m_latch1, m_latch2;
+};
+
+
+// ======================> nes_golden5_device
+
+class nes_golden5_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_golden5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_BF9093;
+extern const device_type NES_BF9096;
+extern const device_type NES_GOLDEN5;
+
+#endif
diff --git a/src/mess/machine/nes_cne.c b/src/mess/machine/nes_cne.c
new file mode 100644
index 00000000000..f02cc27470c
--- /dev/null
+++ b/src/mess/machine/nes_cne.c
@@ -0,0 +1,221 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for C&E PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * C&E Decathlon [mapper 244]
+ * C&E Feng Shen Bang [mapper 246]
+ * C&E Sheng Huo Lie Zhuan [mapper 240]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_cne.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_CNE_DECATHL = &device_creator<nes_cne_decathl_device>;
+const device_type NES_CNE_FSB = &device_creator<nes_cne_fsb_device>;
+const device_type NES_CNE_SHLZ = &device_creator<nes_cne_shlz_device>;
+
+
+nes_cne_decathl_device::nes_cne_decathl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_CNE_DECATHL, "NES Cart C&E Decathlon PCB", tag, owner, clock, "nes_cne_deca", __FILE__)
+{
+}
+
+nes_cne_fsb_device::nes_cne_fsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_CNE_FSB, "NES Cart C&E Feng Shen Bang PCB", tag, owner, clock, "nes_cne_fsb", __FILE__)
+{
+}
+
+nes_cne_shlz_device::nes_cne_shlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_CNE_SHLZ, "NES Cart C&E Sheng Huo Lie Zhuan PCB", tag, owner, clock, "nes_cne_shlz", __FILE__)
+{
+}
+
+
+
+void nes_cne_decathl_device::device_start()
+{
+ common_start();
+}
+
+void nes_cne_decathl_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_cne_fsb_device::device_start()
+{
+ common_start();
+}
+
+void nes_cne_fsb_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0xff);
+ chr8(0, m_chr_source);
+}
+
+void nes_cne_shlz_device::device_start()
+{
+ common_start();
+}
+
+void nes_cne_shlz_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ C & E Bootleg Board for Decathlon
+
+ Games: Decathlon
+
+ Pretty simple mapper: writes to 0x8065-0x80a4 set prg32 to
+ offset & 3; writes to 0x80a5-0x80e4 set chr8 to offset & 7
+
+ iNES: mapper 244
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_cne_decathl_device::write_h)
+{
+ LOG_MMC(("cne_decathl_w, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x0065)
+ return;
+ if (offset < 0x00a5)
+ {
+ prg32((offset - 0x0065) & 0x03);
+ return;
+ }
+ if (offset < 0x00e5)
+ {
+ chr8((offset - 0x00a5) & 0x07, CHRROM);
+ }
+}
+
+/*-------------------------------------------------
+
+ C & E Bootleg Board for Fong Shen Bang
+
+ Games: Fong Shen Bang - Zhu Lu Zhi Zhan
+
+ Simple mapper: writes to 0x6000-0x67ff set PRG and CHR banks.
+ Namely, 0x6000->0x6003 select resp. prg8_89, prg8_ab, prg8_cd
+ and prg8_ef. 0x6004->0x6007 select resp. crh2_0, chr2_2,
+ chr2_4 and chr2_6. In 0x6800-0x7fff lies WRAM. Battery backed?
+
+ iNES: mapper 246
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_cne_fsb_device::write_m)
+{
+ LOG_MMC(("cne_fsb write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x0800)
+ {
+ switch (offset & 0x0007)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x0001:
+ prg8_ab(data);
+ break;
+ case 0x0002:
+ prg8_cd(data);
+ break;
+ case 0x0003:
+ prg8_ef(data);
+ break;
+ case 0x0004:
+ chr2_0(data, CHRROM);
+ break;
+ case 0x0005:
+ chr2_2(data, CHRROM);
+ break;
+ case 0x0006:
+ chr2_4(data, CHRROM);
+ break;
+ case 0x0007:
+ chr2_6(data, CHRROM);
+ break;
+ }
+ }
+ else
+ m_battery[offset] = data;
+}
+
+READ8_MEMBER(nes_cne_fsb_device::read_m)
+{
+ LOG_MMC(("cne_fsb read_m, offset: %04x\n", offset));
+
+ if (offset >= 0x0800)
+ return m_battery[offset];
+
+ return 0xff;
+}
+
+/*-------------------------------------------------
+
+ C & E Bootleg Board for Sheng Huo Lie Zhuan
+
+ Games: Jing Ke Xin Zhuan, Sheng Huo Lie Zhuan
+
+ Simple Mapper: writes to 0x4020-0x5fff sets prg32 to
+ data>>4 and chr8 to data&f. We currently do not map
+ writes to 0x4020-0x40ff (to do: verify if this produces
+ issues)
+
+ iNES: mapper 240
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_cne_shlz_device::write_l)
+{
+ LOG_MMC(("cne_shlz write_l, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(data >> 4);
+ chr8(data & 0x0f, CHRROM);
+}
diff --git a/src/mess/machine/nes_cne.h b/src/mess/machine/nes_cne.h
new file mode 100644
index 00000000000..8756f414f3b
--- /dev/null
+++ b/src/mess/machine/nes_cne.h
@@ -0,0 +1,64 @@
+#ifndef __NES_CNE_H
+#define __NES_CNE_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_cne_decathl_device
+
+class nes_cne_decathl_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_cne_decathl_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_cne_fsb_device
+
+class nes_cne_fsb_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_cne_fsb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_cne_shlz_device
+
+class nes_cne_shlz_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_cne_shlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_CNE_DECATHL;
+extern const device_type NES_CNE_FSB;
+extern const device_type NES_CNE_SHLZ;
+
+#endif
diff --git a/src/mess/machine/nes_cony.c b/src/mess/machine/nes_cony.c
new file mode 100644
index 00000000000..f29a20f9d1e
--- /dev/null
+++ b/src/mess/machine/nes_cony.c
@@ -0,0 +1,390 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Cony/Yoko PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Bandai UNL-CONY [mapper 83]
+ * Bandai UNL-YOKO
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_cony.h"
+
+#include "cpu/m6502/m6502.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_CONY = &device_creator<nes_cony_device>;
+const device_type NES_YOKO = &device_creator<nes_yoko_device>;
+
+
+nes_cony_device::nes_cony_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_cony_device::nes_cony_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_CONY, "NES Cart Cony PCB", tag, owner, clock, "nes_cony", __FILE__)
+{
+}
+
+nes_yoko_device::nes_yoko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_cony_device(mconfig, NES_YOKO, "NES Cart Yoko PCB", tag, owner, clock, "nes_yoko", __FILE__)
+{
+}
+
+
+
+
+void nes_cony_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+
+ save_item(NAME(m_low_reg));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_extra1));
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+}
+
+void nes_cony_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg8_cd(0x1e);
+ prg8_ef(0x1f);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+
+ m_latch1 = 0;
+ m_latch2 = 0;
+ m_extra1 = 0;
+
+ memset(m_low_reg, 0, sizeof(m_low_reg));
+ memset(m_reg, 0, sizeof(m_reg));
+ m_reg[9] = 0x0f;
+}
+
+void nes_yoko_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+
+ save_item(NAME(m_low_reg));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_extra1));
+ save_item(NAME(m_extra2));
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+}
+
+void nes_yoko_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg8_cd(0x1e);
+ prg8_ef(0x1f);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+
+ m_latch1 = 0;
+ m_latch2 = 0;
+ m_extra1 = 0;
+ m_extra2 = 0;
+
+ memset(m_low_reg, 0, sizeof(m_low_reg));
+ memset(m_reg, 0, sizeof(m_reg));
+ m_reg[9] = 0x0f;
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Cony Bootleg Board
+
+ Games: Dragon Ball Party, Fatal Fury 2, Street Blaster II
+ Pro, World Heroes 2
+
+ iNES: mapper 83
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+void nes_cony_device::hblank_irq( int scanline, int vblank, int blanked )
+{
+ if (m_irq_enable)
+ {
+ if (m_irq_count <= 114)
+ {
+ m_irq_enable = 0;
+ m_irq_count = 0xffff;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ m_irq_count -= 114;
+ }
+}
+
+WRITE8_MEMBER(nes_cony_device::write_l)
+{
+ LOG_MMC(("cony write_l, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff
+ m_low_reg[offset & 0x03] = data;
+}
+
+READ8_MEMBER(nes_cony_device::read_l)
+{
+ LOG_MMC(("cony read_l, offset: %04x\n", offset));
+
+ if (offset == 0x0f00) // 0x5000
+ {
+ // read dipswitch bit! - currently unimplemented
+ }
+ if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff
+ return m_low_reg[offset & 0x03];
+ else
+ return 0x00;
+}
+
+void nes_cony_device::set_prg()
+{
+ prg16_89ab(m_reg[8] & 0x3f);
+ prg16_cdef((m_reg[8] & 0x30) | 0x0f);
+}
+
+void nes_cony_device::set_chr()
+{
+ // FIXME: here we emulate at least 3 different boards!!!
+ // one board switches 1k VROM banks only
+ // one writes to 0x8000 and then switches 2k VROM banks only
+ // one writes to 0x831n (n=2,3,4,5) and then switches 2k VROM banks only
+ // we should split them and possibly document the proper behavior of each variant
+ if (m_latch1 && !m_latch2)
+ {
+ chr2_0(m_reg[0], CHRROM);
+ chr2_2(m_reg[1], CHRROM);
+ chr2_4(m_reg[6], CHRROM);
+ chr2_6(m_reg[7], CHRROM);
+ }
+ else
+ {
+ chr1_0(m_reg[0] | ((m_reg[8] & 0x30) << 4), CHRROM);
+ chr1_1(m_reg[1] | ((m_reg[8] & 0x30) << 4), CHRROM);
+ chr1_2(m_reg[2] | ((m_reg[8] & 0x30) << 4), CHRROM);
+ chr1_3(m_reg[3] | ((m_reg[8] & 0x30) << 4), CHRROM);
+ chr1_4(m_reg[4] | ((m_reg[8] & 0x30) << 4), CHRROM);
+ chr1_5(m_reg[5] | ((m_reg[8] & 0x30) << 4), CHRROM);
+ chr1_6(m_reg[6] | ((m_reg[8] & 0x30) << 4), CHRROM);
+ chr1_7(m_reg[7] | ((m_reg[8] & 0x30) << 4), CHRROM);
+ }
+}
+
+WRITE8_MEMBER(nes_cony_device::write_h)
+{
+ LOG_MMC(("cony write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x0000:
+ m_latch1 = 1;
+ case 0x3000:
+ case 0x30ff:
+ case 0x31ff:
+ m_reg[8] = data;
+ set_prg();
+ set_chr();
+ break;
+ case 0x0100:
+ m_extra1 = data & 0x80;
+ switch (data & 0x03)
+ {
+ case 0:
+ set_nt_mirroring(PPU_MIRROR_VERT);
+ break;
+ case 1:
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ break;
+ case 2:
+ set_nt_mirroring(PPU_MIRROR_LOW);
+ break;
+ case 3:
+ set_nt_mirroring(PPU_MIRROR_HIGH);
+ break;
+ }
+ break;
+ case 0x0200:
+ m_irq_count = (m_irq_count & 0xff00) | data;
+ break;
+ case 0x0201:
+ m_irq_enable = m_extra1;
+ m_irq_count = (data << 8) | (m_irq_count & 0xff);
+ break;
+ case 0x0300:
+ prg8_89(data);
+ break;
+ case 0x0301:
+ prg8_ab(data);
+ break;
+ case 0x0302:
+ prg8_cd(data);
+ break;
+ case 0x0312:
+ case 0x0313:
+ case 0x0314:
+ case 0x0315:
+ m_latch2 = 1;
+ case 0x0310:
+ case 0x0311:
+ case 0x0316:
+ case 0x0317:
+ m_reg[offset - 0x0310] = data;
+ set_chr();
+ break;
+ case 0x0318:
+ m_reg[9] = data; // unused?
+ set_prg();
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Yoko Bootleg Board
+
+ Games: Mortal Kombat II, Master Figther VI'
+
+
+ Very similar to Cony board
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_yoko_device::write_l)
+{
+ LOG_MMC(("yoko write_l, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x1300) // from 0x5400
+ m_low_reg[offset & 0x03] = data;
+}
+
+READ8_MEMBER(nes_yoko_device::read_l)
+{
+ LOG_MMC(("yoko read_l, offset: %04x\n", offset));
+
+ if (offset >= 0x0f00 && offset < 0x1300) // 0x5000
+ {
+ // read dipswitch bit! - currently unimplemented
+ }
+ if (offset >= 0x1300) // from 0x5400
+ return m_low_reg[offset & 0x03];
+ else
+ return 0x00;
+}
+
+void nes_yoko_device::set_prg()
+{
+ if (m_extra1 & 0x10)
+ {
+ int base = (m_extra2 & 0x08) << 1;
+ prg8_89(base | (m_reg[0] & 0x0f));
+ prg8_ab(base | (m_reg[1] & 0x0f));
+ prg8_cd(base | (m_reg[2] & 0x0f));
+ prg8_ef(base | 0x0f);
+ }
+ else if (m_extra1 & 0x08)
+ prg32(m_extra2 >> 1);
+ else
+ {
+ prg16_89ab(m_extra2);
+ prg16_cdef(0xff);
+ }
+}
+
+void nes_yoko_device::set_chr()
+{
+ chr2_0(m_reg[4], CHRROM);
+ chr2_2(m_reg[5], CHRROM);
+ chr2_4(m_reg[6], CHRROM);
+ chr2_6(m_reg[7], CHRROM);
+}
+
+WRITE8_MEMBER(nes_yoko_device::write_h)
+{
+ LOG_MMC(("yoko write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x0c17)
+ {
+ case 0x0000:
+ m_extra2 = data;
+ set_prg();
+ break;
+ case 0x400:
+ m_extra1 = data;
+ if (data & 1)
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ else
+ set_nt_mirroring(PPU_MIRROR_VERT);
+ set_prg();
+ break;
+ case 0x0800:
+ m_irq_count = (m_irq_count & 0xff00) | data;
+ break;
+ case 0x0801:
+ m_irq_enable = m_extra1 & 0x80;
+ m_irq_count = (data << 8) | (m_irq_count & 0xff);
+ break;
+ case 0x0c00:
+ case 0x0c01:
+ case 0x0c02:
+ m_reg[offset & 3] = data;
+ set_prg();
+ break;
+ case 0x0c10:
+ case 0x0c11:
+ case 0x0c16:
+ case 0x0c17:
+ m_reg[4 + (offset & 3)] = data;
+ set_chr();
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_cony.h b/src/mess/machine/nes_cony.h
new file mode 100644
index 00000000000..5ccd852f4b9
--- /dev/null
+++ b/src/mess/machine/nes_cony.h
@@ -0,0 +1,70 @@
+#ifndef __NES_CONY_H
+#define __NES_CONY_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_cony_device
+
+class nes_cony_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_cony_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);
+ nes_cony_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ virtual void set_prg();
+ virtual void set_chr();
+
+ UINT16 m_irq_count;
+ int m_irq_enable;
+
+ UINT8 m_latch1, m_latch2;
+ UINT8 m_low_reg[4];
+ UINT8 m_reg[10];
+ UINT8 m_extra1;
+};
+
+
+// ======================> nes_yoko_device
+
+class nes_yoko_device : public nes_cony_device
+{
+public:
+ // construction/destruction
+ nes_yoko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ virtual void set_prg();
+ virtual void set_chr();
+
+ UINT8 m_extra2;
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_CONY;
+extern const device_type NES_YOKO;
+
+#endif
diff --git a/src/mess/machine/nes_discrete.c b/src/mess/machine/nes_discrete.c
new file mode 100644
index 00000000000..aa8bd3f197b
--- /dev/null
+++ b/src/mess/machine/nes_discrete.c
@@ -0,0 +1,201 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for PCBs mostly based on discrete components
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_discrete.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_74X161X161X32 = &device_creator<nes_74x161x161x32_device>;
+const device_type NES_74X139X74 = &device_creator<nes_74x139x74_device>;
+const device_type NES_74X377 = &device_creator<nes_74x377_device>;
+const device_type NES_74X161X138 = &device_creator<nes_74x161x138_device>;
+
+
+nes_74x161x161x32_device::nes_74x161x161x32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_74X161X161X32, "NES Cart Discrete Logic (74*161/161/32) PCB", tag, owner, clock, "nes_74x161", __FILE__)
+{
+}
+
+nes_74x139x74_device::nes_74x139x74_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_74X139X74, "NES Cart Discrete Logic (74*139/74) PCB", tag, owner, clock, "nes_74x139", __FILE__)
+{
+}
+
+nes_74x377_device::nes_74x377_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_74X377, "NES Cart Discrete Logic (74*377) PCB", tag, owner, clock, "nes_74x377", __FILE__)
+{
+}
+
+nes_74x161x138_device::nes_74x161x138_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_74X161X138, "NES Cart Discrete Logic (74*161/138) PCB", tag, owner, clock, "nes_bitcorp_dis", __FILE__)
+{
+}
+
+
+
+
+void nes_74x161x161x32_device::device_start()
+{
+ common_start();
+}
+
+void nes_74x161x161x32_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_74x139x74_device::device_start()
+{
+ common_start();
+}
+
+void nes_74x139x74_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_74x377_device::device_start()
+{
+ common_start();
+}
+
+void nes_74x377_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_74x161x138_device::device_start()
+{
+ common_start();
+}
+
+void nes_74x161x138_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Discrete Logic board IC 74x161x161x32
+
+ There are two variants (one with hardwired mirroring, the
+ other with a mirroring control), making necessary two distinct
+ mappers & pcb_id
+
+ iNES: mappers 70 & 152
+
+ -------------------------------------------------*/
+
+// there are two 'variants' depending on hardwired or mapper ctrl mirroring
+WRITE8_MEMBER(nes_74x161x161x32_device::write_h)
+{
+ LOG_MMC(("74x161x161x32 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ if (m_pcb_ctrl_mirror)
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ chr8(data, CHRROM);
+ prg16_89ab(data >> 4);
+}
+
+/*-------------------------------------------------
+
+ Discrete Logic board IC 74x139x74 by Konami & Jaleco
+
+ iNES: mapper 87
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_74x139x74_device::write_m)
+{
+ LOG_MMC(("74x139x74 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(((data & 0x02) >> 1) | ((data & 0x01) << 1), CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Discrete Logic board IC 74x377 by Color Dreams / Nina-007 emulation
+
+ Games: many Color Dreams and Wisdom Tree titles
+
+ iNES: mapper 11
+
+ In MESS: Supported
+
+ Note: bit2 & bit3 are actually related to CIC lockout
+ defeating, and real Color Dreams titles use only
+ bit0 & bit1 for PRG switching. Our usage allows for support
+ of extended PRG games (e.g. homebrew)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_74x377_device::write_h)
+{
+ LOG_MMC(("74x377 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict, but not the prototype of Secret Scout, which actually breaks in case of conflict...
+ data = account_bus_conflict(offset, data);
+
+ chr8(data >> 4, m_chr_source);
+ prg32(data & 0x0f);
+}
+
+/*-------------------------------------------------
+
+ Discrete Logic board IC 74x161x138
+
+ Games: Crime Busters
+
+ iNES: mapper 38
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_74x161x138_device::write_m)
+{
+ LOG_MMC(("74x161x138 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(data >> 2, CHRROM);
+ prg32(data);
+}
diff --git a/src/mess/machine/nes_discrete.h b/src/mess/machine/nes_discrete.h
new file mode 100644
index 00000000000..27ea57af211
--- /dev/null
+++ b/src/mess/machine/nes_discrete.h
@@ -0,0 +1,78 @@
+#ifndef __NES_DISCRETE_H
+#define __NES_DISCRETE_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_74x161x161x32_device
+
+class nes_74x161x161x32_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_74x161x161x32_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_74x139x74_device
+
+class nes_74x139x74_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_74x139x74_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_74x377_device
+
+class nes_74x377_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_74x377_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_74x161x138_device
+
+class nes_74x161x138_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_74x161x138_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+
+// device type definition
+extern const device_type NES_74X161X161X32;
+extern const device_type NES_74X139X74;
+extern const device_type NES_74X377;
+extern const device_type NES_74X161X138;
+
+#endif
diff --git a/src/mess/machine/nes_event.c b/src/mess/machine/nes_event.c
new file mode 100644
index 00000000000..d59fbf626f7
--- /dev/null
+++ b/src/mess/machine/nes_event.c
@@ -0,0 +1,239 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Nintendo NES-EVENT PCB
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Nintendo NES-EVENT [mapper 105]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_event.h"
+
+#include "cpu/m6502/m6502.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_EVENT = &device_creator<nes_event_device>;
+
+
+nes_event_device::nes_event_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sxrom_device(mconfig, NES_EVENT, "NES Cart Event PCB", tag, owner, clock, "nes_event", __FILE__),
+ m_dsw(*this, "DIPSW")
+{
+}
+
+
+void nes_event_device::device_start()
+{
+ common_start();
+ event_timer = timer_alloc(TIMER_EVENT);
+ event_timer->adjust(attotime::never);
+
+ save_item(NAME(m_latch));
+ save_item(NAME(m_count));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_reg_write_enable));
+ save_item(NAME(m_nwc_init));
+
+ save_item(NAME(m_timer_count));
+ save_item(NAME(m_timer_on));
+ save_item(NAME(m_timer_enabled));
+}
+
+void nes_event_device::pcb_reset()
+{
+ m_latch = 0;
+ m_count = 0;
+ m_reg[0] = 0x0f;
+ m_reg[1] = m_reg[2] = m_reg[3] = 0;
+ m_reg_write_enable = 1;
+ m_nwc_init = 2;
+
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ chr8(0, CHRRAM);
+ prg32(0);
+ m_timer_count = 0;
+ m_timer_enabled = 0;
+ m_timer_on = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Event PCB
+
+ Games: Nintento World Championships
+
+ MMC-1 variant with repurposed register at $a000 and a
+ lot of discrete components
+
+ iNES: mapper 105
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_event_device::set_chr()
+{
+ // no CHR switching, there are only 8KB VRAM from the cart
+}
+
+void nes_event_device::set_prg()
+{
+// printf("enter with %d and reg1 0x%x - reg3 0x%x\n", m_nwc_init, m_reg[1], m_reg[3]);
+ // reg[1] is different from base MMC-1!
+ // bit 0 is ignored, bit1/bit3 are used for PRG switch, bit4 is used for the timer
+ UINT8 temp = (m_reg[1] >> 1) & 7;
+
+ // initially PRG is fixed, until bit4 of reg1 is set to 1 and then to 0
+ switch (m_nwc_init)
+ {
+ case 2:
+ if (m_reg[1] & 0x10) m_nwc_init--;
+ return;
+ case 1:
+ if (~m_reg[1] & 0x10) m_nwc_init--;
+ return;
+ }
+
+ if (temp < 4)
+ prg32(temp);
+ else
+ {
+ // else PRG works similarly to base MMC-1, but only acts on the higher 128KB (2nd PRG ROM)
+ switch (m_reg[0] & 0x0c)
+ {
+ case 0x00:
+ case 0x04:
+ prg32(0x04 | ((m_reg[3] >> 1) & 0x03));
+ break;
+ case 0x08:
+ prg16_89ab(0x08 | 0x00);
+ prg16_cdef(0x08 | (m_reg[3] & 0x07));
+ break;
+ case 0x0c:
+ prg16_89ab(0x08 | (m_reg[3] & 0x07));
+ prg16_cdef(0x08 | 0x07);
+ break;
+ }
+ }
+
+ // after the init procedure above, bit4 of m_reg[1] is used to init IRQ, by setting and then clearing the bit
+ // however, there are (bankswitch related?) writes with bit4 cleared before the one 'enabling' the timer, so
+ // we need the additional m_timer_enabled variable, to avoid starting the timer before its time...
+ if (m_reg[1] & 0x10)
+ {
+ m_timer_enabled = 1;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
+ }
+ else
+ {
+ if (!m_timer_on && m_timer_enabled)
+ {
+ m_timer_count = 0x20000000 | ((m_dsw->read() & 0x0f) << 25);
+ event_timer->adjust(attotime::zero, 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(1));
+ m_timer_on = 1;
+ }
+ }
+}
+
+void nes_event_device::update_regs(int reg)
+{
+ switch (reg)
+ {
+ case 0:
+ switch (m_reg[0] & 0x03)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ }
+ set_prg();
+ break;
+ case 1:
+ set_prg();
+ break;
+ case 2:
+ set_chr();
+ break;
+ case 3:
+ set_prg();
+ break;
+ }
+}
+
+//-------------------------------------------------
+// Dipswicth
+//-------------------------------------------------
+
+static INPUT_PORTS_START( nwc_dsw )
+ PORT_START("DIPSW")
+ PORT_DIPNAME( 0x0f, 0x04, "Timer" ) PORT_DIPLOCATION("SW:!1,!2,!3,!4")
+ PORT_DIPSETTING( 0x00, "5:00.4" )
+ PORT_DIPSETTING( 0x01, "5:19.2" )
+ PORT_DIPSETTING( 0x02, "5:38.0" )
+ PORT_DIPSETTING( 0x03, "5:56.7" )
+ PORT_DIPSETTING( 0x04, "6:15.5" )
+ PORT_DIPSETTING( 0x05, "6:34.3" )
+ PORT_DIPSETTING( 0x06, "6:53.1" )
+ PORT_DIPSETTING( 0x07, "7:11.9" )
+ PORT_DIPSETTING( 0x08, "7:30.6" )
+ PORT_DIPSETTING( 0x09, "7:49.4" )
+ PORT_DIPSETTING( 0x0a, "8:08.2" )
+ PORT_DIPSETTING( 0x0b, "8:27.0" )
+ PORT_DIPSETTING( 0x0c, "8:45.8" )
+ PORT_DIPSETTING( 0x0d, "9:04.5" )
+ PORT_DIPSETTING( 0x0e, "9:23.3" )
+ PORT_DIPSETTING( 0x0f, "9:42.1" )
+INPUT_PORTS_END
+
+
+
+ioport_constructor nes_event_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( nwc_dsw );
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void nes_event_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_EVENT)
+ {
+ m_timer_count--;
+ if (!m_timer_count)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ event_timer->reset();
+ }
+ }
+}
diff --git a/src/mess/machine/nes_event.h b/src/mess/machine/nes_event.h
new file mode 100644
index 00000000000..100937c4890
--- /dev/null
+++ b/src/mess/machine/nes_event.h
@@ -0,0 +1,40 @@
+#ifndef __NES_EVENT_H
+#define __NES_EVENT_H
+
+#include "machine/nes_mmc1.h"
+
+
+// ======================> nes_event_device
+
+class nes_event_device : public nes_sxrom_device
+{
+public:
+ // construction/destruction
+ nes_event_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual ioport_constructor device_input_ports() const;
+ virtual void update_regs(int reg);
+
+ required_ioport m_dsw;
+
+ virtual void pcb_reset();
+
+protected:
+ virtual void set_prg();
+ virtual void set_chr();
+ int m_nwc_init;
+
+ static const device_timer_id TIMER_EVENT = 0;
+ emu_timer *event_timer;
+ UINT32 m_timer_count;
+ int m_timer_on, m_timer_enabled;
+};
+
+
+// device type definition
+extern const device_type NES_EVENT;
+
+#endif
diff --git a/src/mess/machine/nes_ggenie.c b/src/mess/machine/nes_ggenie.c
new file mode 100644
index 00000000000..1feac1d3e28
--- /dev/null
+++ b/src/mess/machine/nes_ggenie.c
@@ -0,0 +1,275 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Galoob Game Genie PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Galoob Game Genie, passthrough hacking cart
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_ggenie.h"
+#include "includes/nes.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_GGENIE = &device_creator<nes_ggenie_device>;
+
+
+nes_ggenie_device::nes_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_GGENIE, "NES Cart Game Genie PCB", tag, owner, clock, "nes_ggenie", __FILE__),
+ m_ggslot(*this, "gg_slot")
+{
+}
+
+
+void nes_ggenie_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_gg_bypass));
+}
+
+void nes_ggenie_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ set_nt_mirroring(PPU_MIRROR_LOW);
+ m_gg_bypass = 0;
+
+ if (m_ggslot->m_cart)
+ {
+ m_ggslot->pcb_start(m_ciram);
+ m_ggslot->m_cart->pcb_reset();
+ }
+}
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Game Genie board emulation
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ggenie_device::write_h)
+{
+// LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data));
+ if (!m_gg_bypass)
+ {
+ // From blargg: Codes are written to $8001-800C, starting at $800C and going down to $8001.
+ // Next, two values are written to $8000. The first specify the kind of codes which have
+ // been inserted, the second write to $8000 is always zero (all 8 bits).
+ // This probably disables the boot ROM (the code is executing from RAM at this point).
+ // Once done, the code jumps to ($FFFC) to begin the game.
+ // All 12 bytes from $8001-800C are written regardless of how many codes are inserted.
+ // The value written to $8000 is the only clue as to what codes are actually valid and which
+ // ones have compare values.
+ if (offset)
+ {
+ int code;
+ offset -= 1;
+ code = (offset & 0xc) >> 2;
+ if (code == 3)
+ return; // how did we end up here? the GG is not expected to write to $800d-800f!
+
+ switch (offset & 3)
+ {
+ case 0:
+ m_gg_addr[code] |= (data & 0x7f) << 8;
+ break;
+ case 1:
+ m_gg_addr[code] = data;
+ break;
+ case 2:
+ m_gg_comp[code] = data;
+ break;
+ case 3:
+ m_gg_repl[code] = data;
+ break;
+ }
+ return;
+ }
+
+ if (offset == 0 && data == 0)
+ {
+ m_gg_bypass = 1;
+ machine().device<cpu_device>("maincpu")->set_pc(0xfffc);
+ }
+ else
+ {
+ // bit 0 is always set (GG enable?)
+ m_gg_is_comp[0] = BIT(data, 1);
+ m_gg_is_comp[1] = BIT(data, 2);
+ m_gg_is_comp[2] = BIT(data, 3);
+ m_gg_disable[0] = BIT(data, 4);
+ m_gg_disable[1] = BIT(data, 5);
+ m_gg_disable[2] = BIT(data, 6);
+ // bit 7 is always clear
+ logerror("Game Genie Summary:\n");
+ for (int i = 0; i < 3; i++)
+ {
+ logerror("Code %d: %s\n", i, m_gg_disable[i] ? "No" : "Yes");
+ if (!m_gg_disable[i])
+ {
+ logerror("\tAddr: 0x%X\n", m_gg_addr[i]);
+ logerror("\tValue: 0x%X\n", m_gg_repl[i]);
+ if (m_gg_is_comp[i])
+ logerror("\t if equals: 0x%X\n", m_gg_comp[i]);
+
+ }
+ }
+ }
+ }
+ else
+ m_ggslot->write_h(space, offset, data, mem_mask);
+}
+
+WRITE8_MEMBER(nes_ggenie_device::write_m)
+{
+ if (m_gg_bypass && m_ggslot)
+ m_ggslot->write_m(space, offset, data, mem_mask);
+}
+
+WRITE8_MEMBER(nes_ggenie_device::write_l)
+{
+ if (m_gg_bypass && m_ggslot)
+ m_ggslot->write_l(space, offset, data, mem_mask);
+}
+
+READ8_MEMBER(nes_ggenie_device::read_h)
+{
+ if (m_gg_bypass && m_ggslot->m_cart)
+ {
+ UINT8 rom_value = m_ggslot->m_cart->hi_access_rom(offset);
+
+ // check if GG code has to act on this address
+ for (int i = 0; i < 3; i++)
+ {
+ if (!m_gg_disable[i] && offset == m_gg_addr[i])
+ {
+ if (!m_gg_is_comp[i] || (m_gg_is_comp[i] && m_gg_comp[i] == rom_value))
+ return m_gg_repl[i];
+ }
+ }
+
+ return rom_value;
+ }
+ return hi_access_rom(offset);
+}
+
+READ8_MEMBER(nes_ggenie_device::read_m)
+{
+ if (m_gg_bypass && m_ggslot->m_cart)
+ return m_ggslot->m_cart->read_m(space, offset, mem_mask);
+
+ return 0xff;
+}
+
+READ8_MEMBER(nes_ggenie_device::read_l)
+{
+ if (m_gg_bypass && m_ggslot->m_cart)
+ return m_ggslot->m_cart->read_l(space, offset, mem_mask);
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(nes_ggenie_device::chr_w)
+{
+ int bank = offset >> 10;
+
+ if (m_gg_bypass && m_ggslot->m_cart)
+ {
+ m_ggslot->m_cart->chr_w(space, offset, data, mem_mask);
+ return;
+ }
+
+ if (m_chr_src[bank] == CHRRAM)
+ m_chr_access[bank][offset & 0x3ff] = data;
+}
+
+READ8_MEMBER(nes_ggenie_device::chr_r)
+{
+ int bank = offset >> 10;
+
+ if (m_gg_bypass && m_ggslot->m_cart)
+ return m_ggslot->m_cart->chr_r(space, offset, mem_mask);
+
+ return m_chr_access[bank][offset & 0x3ff];
+}
+
+
+WRITE8_MEMBER(nes_ggenie_device::nt_w)
+{
+ int page = ((offset & 0xc00) >> 10);
+
+ if (m_gg_bypass && m_ggslot->m_cart)
+ {
+ m_ggslot->m_cart->nt_w(space, offset, data, mem_mask);
+ return;
+ }
+
+ if (!m_nt_writable[page])
+ return;
+
+ m_nt_access[page][offset & 0x3ff] = data;
+}
+
+READ8_MEMBER(nes_ggenie_device::nt_r)
+{
+ int page = ((offset & 0xc00) >> 10);
+
+ if (m_gg_bypass && m_ggslot->m_cart)
+ return m_ggslot->m_cart->nt_r(space, offset, mem_mask);
+
+ return m_nt_access[page][offset & 0x3ff];
+}
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( sub_slot )
+//-------------------------------------------------
+
+static const nes_cart_interface gg_crt_interface =
+{
+};
+
+static MACHINE_CONFIG_FRAGMENT( sub_slot )
+ MCFG_NES_CARTRIDGE_ADD("gg_slot", gg_crt_interface, nes_cart, NULL, NULL)
+ MCFG_NES_CARTRIDGE_NOT_MANDATORY
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nes_ggenie_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( sub_slot );
+}
diff --git a/src/mess/machine/nes_ggenie.h b/src/mess/machine/nes_ggenie.h
new file mode 100644
index 00000000000..c6851b10e8a
--- /dev/null
+++ b/src/mess/machine/nes_ggenie.h
@@ -0,0 +1,55 @@
+#ifndef __NES_GGENIE_H
+#define __NES_GGENIE_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_ggenie_device
+
+class nes_ggenie_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ggenie_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual DECLARE_READ8_MEMBER(chr_r);
+ virtual DECLARE_WRITE8_MEMBER(chr_w);
+ virtual DECLARE_READ8_MEMBER(nt_r);
+ virtual DECLARE_WRITE8_MEMBER(nt_w);
+
+ void hblank_irq(int scanline, int vblank, int blanked) { if (m_gg_bypass && m_ggslot->m_cart) m_ggslot->m_cart->hblank_irq(scanline, vblank, blanked); }
+ void scanline_irq(int scanline, int vblank, int blanked) { if (m_gg_bypass && m_ggslot->m_cart) m_ggslot->m_cart->scanline_irq(scanline, vblank, blanked); }
+ void ppu_latch(offs_t offset) { if (m_gg_bypass && m_ggslot->m_cart) m_ggslot->m_cart->ppu_latch(offset); }
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual void pcb_reset();
+
+private:
+ // emulate the Game Genie!
+ required_device<nes_cart_slot_device> m_ggslot;
+
+ int m_gg_bypass;
+ // GG codes
+ UINT16 m_gg_addr[3];
+ UINT8 m_gg_repl[3];
+ UINT8 m_gg_comp[3];
+ int m_gg_disable[3];
+ int m_gg_is_comp[3];
+};
+
+
+
+// device type definition
+extern const device_type NES_GGENIE;
+
+#endif
diff --git a/src/mess/machine/nes_henggedianzi.c b/src/mess/machine/nes_henggedianzi.c
new file mode 100644
index 00000000000..6b2b17f2ffe
--- /dev/null
+++ b/src/mess/machine/nes_henggedianzi.c
@@ -0,0 +1,279 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Henggedianzi PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Henggedianzi Super Rich [mapper 177]
+ * Henggedianzi Xing He Zhan Shi [mapper 179]
+ * Henggedianzi Shen Hua Jian Yun III
+
+
+ TODO:
+ - investigate relation with some TXC & Waixing boards
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_henggedianzi.h"
+
+#include "cpu/m6502/m6502.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_HENGG_SRICH = &device_creator<nes_hengg_srich_device>;
+const device_type NES_HENGG_XHZS = &device_creator<nes_hengg_xhzs_device>;
+const device_type NES_HENGG_SHJY3 = &device_creator<nes_hengg_shjy3_device>;
+
+
+nes_hengg_srich_device::nes_hengg_srich_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_HENGG_SRICH, "NES Cart Henggedianzi Super Rich PCB", tag, owner, clock, "nes_hengg_srich", __FILE__)
+{
+}
+
+nes_hengg_xhzs_device::nes_hengg_xhzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_HENGG_XHZS, "NES Cart Henggedianzi Xing He Zhan Shi PCB", tag, owner, clock, "nes_hengg_xhzs", __FILE__)
+{
+}
+
+nes_hengg_shjy3_device::nes_hengg_shjy3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_HENGG_SHJY3, "NES Cart Henggedianzi Shen Hua Jian Yun III PCB", tag, owner, clock, "nes_hengg_shjy3", __FILE__)
+{
+}
+
+
+
+
+void nes_hengg_srich_device::device_start()
+{
+ common_start();
+}
+
+void nes_hengg_srich_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_hengg_xhzs_device::device_start()
+{
+ common_start();
+}
+
+void nes_hengg_xhzs_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_hengg_shjy3_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_chr_mode));
+ save_item(NAME(m_mmc_prg_bank));
+ save_item(NAME(m_mmc_vrom_bank));
+ save_item(NAME(m_mmc_extra_bank));
+}
+
+void nes_hengg_shjy3_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = m_irq_count_latch = 0;
+
+ m_chr_mode = 0;
+ memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank));
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+ memset(m_mmc_extra_bank, 0, sizeof(m_mmc_extra_bank));
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bootleg Board by Henggedianzi
+
+ Games: Mei Guo Fu Hao, Shang Gu Shen Jian , Wang Zi Fu
+ Chou Ji
+
+ Writes to 0x8000-0xffff set prg32. Moreover, data&0x20 sets
+ NT mirroring.
+
+ iNES: mapper 177
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_hengg_srich_device::write_h)
+{
+ LOG_MMC(("hengg_srich write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(data);
+ set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by Henggedianzi
+
+ Games: Xing He Zhan Shi
+
+ Writes to 0x5000-0x5fff set prg32 banks, writes to 0x8000-
+ 0xffff set NT mirroring
+
+ Note: NEStopia marks this as Xjzb, but Xing Ji Zheng Ba
+ (Phantasy Star?) runs on the other Henggedianzi board
+ Is there an alt dump of Xing Ji Zheng Ba using this?
+
+ iNES: mapper 179
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_hengg_xhzs_device::write_l)
+{
+ LOG_MMC(("hengg_xhzs write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x4100;
+
+ if (offset & 0x5000)
+ prg32(data >> 1);
+}
+
+WRITE8_MEMBER(nes_hengg_xhzs_device::write_h)
+{
+ LOG_MMC(("hengg_xhzs write_h, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ UNL-SHJY3
+
+ -------------------------------------------------*/
+
+/* I think the IRQ should only get fired if enough CPU cycles have passed, but we don't implement (yet) this part */
+void nes_hengg_shjy3_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable & 0x02)
+ {
+ if (m_irq_count == 0xff)
+ {
+ m_irq_count = m_irq_count_latch;
+ m_irq_enable = m_irq_enable | ((m_irq_enable & 0x01) << 1);
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ m_irq_count++;
+ }
+}
+
+void nes_hengg_shjy3_device::update_banks()
+{
+ prg8_89(m_mmc_prg_bank[0]);
+ prg8_ab(m_mmc_prg_bank[1]);
+
+ for (int i = 0; i < 8; i++)
+ {
+ UINT8 chr_bank = m_mmc_vrom_bank[i] | (m_mmc_extra_bank[i] << 4);
+ if (m_mmc_vrom_bank[i] == 0xc8)
+ {
+ m_chr_mode = 0;
+ continue;
+ }
+ else if (m_mmc_vrom_bank[i] == 0x88)
+ {
+ m_chr_mode = 1;
+ continue;
+ }
+ if ((m_mmc_vrom_bank[i] == 4 || m_mmc_vrom_bank[i] == 5) && !m_chr_mode)
+ chr1_x(i, chr_bank & 1, CHRRAM);
+ else
+ chr1_x(i, chr_bank, CHRROM);
+ }
+}
+
+WRITE8_MEMBER(nes_hengg_shjy3_device::write_h)
+{
+ LOG_MMC(("shjy3 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x3000 && offset <= 0x600c)
+ {
+ UINT8 shift = offset & 4;
+ UINT8 mmc_helper = ((offset & 8) | (offset >> 8)) >> 3;
+ mmc_helper += 2;
+ mmc_helper &= 7;
+
+ m_mmc_vrom_bank[mmc_helper] = (m_mmc_vrom_bank[mmc_helper] & (0xf0 >> shift)) | ((data & 0x0f) << shift);
+ if (shift)
+ m_mmc_extra_bank[mmc_helper] = data >> 4;
+ }
+ else
+ {
+ switch (offset)
+ {
+ case 0x0010:
+ m_mmc_prg_bank[0] = data;
+ break;
+ case 0x2010:
+ m_mmc_prg_bank[1] = data;
+ break;
+ case 0x1400:
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x7000:
+ m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f);
+ break;
+ case 0x7004:
+ m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x7008:
+ m_irq_enable = data & 0x03;
+ if (m_irq_enable & 0x02)
+ m_irq_count = m_irq_count_latch;
+ break;
+ }
+ }
+ update_banks();
+}
diff --git a/src/mess/machine/nes_henggedianzi.h b/src/mess/machine/nes_henggedianzi.h
new file mode 100644
index 00000000000..ed07e71e32f
--- /dev/null
+++ b/src/mess/machine/nes_henggedianzi.h
@@ -0,0 +1,76 @@
+#ifndef __NES_HENGGEDIANZI_H
+#define __NES_HENGGEDIANZI_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_hengg_srich_device
+
+class nes_hengg_srich_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_hengg_srich_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_hengg_xhzs_device
+
+class nes_hengg_xhzs_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_hengg_xhzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_hengg_shjy3_device
+
+class nes_hengg_shjy3_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_hengg_shjy3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ void update_banks();
+
+ UINT16 m_irq_count, m_irq_count_latch;
+ int m_irq_enable;
+
+ int m_chr_mode;
+ UINT8 m_mmc_prg_bank[2];
+ UINT8 m_mmc_vrom_bank[8];
+ UINT8 m_mmc_extra_bank[8];
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_HENGG_SRICH;
+extern const device_type NES_HENGG_XHZS;
+extern const device_type NES_HENGG_SHJY3;
+
+#endif
diff --git a/src/mess/machine/nes_hes.c b/src/mess/machine/nes_hes.c
new file mode 100644
index 00000000000..c6eba7d51db
--- /dev/null
+++ b/src/mess/machine/nes_hes.c
@@ -0,0 +1,88 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for HES PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the HES PCBs (both the one with hardwired mirroring and the one with mapper-controlled
+ mirroring used by HES 6 in 1) [mapper 113]
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_hes.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_HES = &device_creator<nes_hes_device>;
+
+
+nes_hes_device::nes_hes_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_HES, "NES Cart HES PCB", tag, owner, clock, "nes_hes", __FILE__)
+{
+}
+
+
+void nes_hes_device::device_start()
+{
+ common_start();
+}
+
+void nes_hes_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bootleg Board by HES (also used by others)
+
+ Games: AV Hanafuda Club, AV Soccer, Papillon, Sidewinder,
+ Total Funpack
+
+ Actually, two variant: one for HES 6-in-1 with mirroring control
+ and one for AV Soccer and others with hardwired mirroring
+
+ iNES: mapper 113
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_hes_device::write_l)
+{
+ LOG_MMC(("hes write_l, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset & 0x100))
+ {
+ prg32((data & 0x38) >> 3);
+ chr8((data & 0x07) | ((data & 0x40) >> 3), CHRROM);
+ if (m_pcb_ctrl_mirror)
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ }
+}
diff --git a/src/mess/machine/nes_hes.h b/src/mess/machine/nes_hes.h
new file mode 100644
index 00000000000..4c1a27eae3b
--- /dev/null
+++ b/src/mess/machine/nes_hes.h
@@ -0,0 +1,26 @@
+#ifndef __NES_HES_H
+#define __NES_HES_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_hes_device
+
+class nes_hes_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_hes_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+};
+
+
+// device type definition
+extern const device_type NES_HES;
+
+#endif
diff --git a/src/mess/machine/nes_hosenkan.c b/src/mess/machine/nes_hosenkan.c
new file mode 100644
index 00000000000..cefc53b7b3f
--- /dev/null
+++ b/src/mess/machine/nes_hosenkan.c
@@ -0,0 +1,156 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Hosenkan PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_hosenkan.h"
+
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_HOSENKAN = &device_creator<nes_hosenkan_device>;
+
+
+nes_hosenkan_device::nes_hosenkan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_HOSENKAN, "NES Cart HOSENKAN PCB", tag, owner, clock, "nes_hosenkan", __FILE__)
+{
+}
+
+
+
+
+void nes_hosenkan_device::device_start()
+{
+ common_start();
+ 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));
+ save_item(NAME(m_latch));
+}
+
+void nes_hosenkan_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32((m_prg_chunks - 1) >> 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ m_irq_enable = 0;
+ m_irq_count = m_irq_count_latch = 0;
+ m_irq_clear = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bootleg Board by Hosenkan
+
+ Games: Pocahontas, Super Donkey Kong
+
+ iNES: mapper 182
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+// same as MMC3!
+void nes_hosenkan_device::hblank_irq( int scanline, int vblank, int blanked )
+{
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ int prior_count = m_irq_count;
+ if ((m_irq_count == 0) || m_irq_clear)
+ m_irq_count = m_irq_count_latch;
+ else
+ m_irq_count--;
+
+ if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear))
+ {
+ LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
+ machine().primary_screen->vpos(), machine().primary_screen->hpos()));
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+ m_irq_clear = 0;
+}
+
+WRITE8_MEMBER(nes_hosenkan_device::write_h)
+{
+ LOG_MMC(("hosenkan write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0001:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ m_latch = data;
+ break;
+ case 0x4000:
+ switch (m_latch)
+ {
+ case 0:
+ chr2_0(data >> 1, CHRROM);
+ break;
+ case 1:
+ chr1_5(data, CHRROM);
+ break;
+ case 2:
+ chr2_2(data >> 1, CHRROM);
+ break;
+ case 3:
+ chr1_7(data, CHRROM);
+ break;
+ case 4:
+ prg8_89(data);
+ break;
+ case 5:
+ prg8_ab(data);
+ break;
+ case 6:
+ chr1_4(data, CHRROM);
+ break;
+ case 7:
+ chr1_6(data, CHRROM);
+ break;
+ }
+ break;
+ case 0x6003:
+ if (data)
+ {
+ m_irq_count = data;
+ m_irq_enable = 1;
+ }
+ else
+ m_irq_enable = 0;
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_hosenkan.h b/src/mess/machine/nes_hosenkan.h
new file mode 100644
index 00000000000..a59567135ac
--- /dev/null
+++ b/src/mess/machine/nes_hosenkan.h
@@ -0,0 +1,37 @@
+#ifndef __NES_HOSENKAN_H
+#define __NES_HOSENKAN_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_hosenkan_device
+
+class nes_hosenkan_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_hosenkan_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count, m_irq_count_latch;
+ UINT8 m_irq_clear;
+ int m_irq_enable;
+
+ UINT8 m_latch;
+};
+
+
+
+// device type definition
+extern const device_type NES_HOSENKAN;
+
+
+#endif
diff --git a/src/mess/machine/nes_ines.c b/src/mess/machine/nes_ines.c
index 6f51bbadb70..4a68cab657a 100644
--- a/src/mess/machine/nes_ines.c
+++ b/src/mess/machine/nes_ines.c
@@ -6,175 +6,26 @@
****************************************************************************************/
-struct nes_mmc
-{
- int iNesMapper; /* iNES Mapper # */
- int pcb_id;
-};
-
-/*************************************************************
-
- Mapper 6
- Known Boards: FFE4 Copier Board
- Games: Hacked versions of games
+/* Set to generate prg & chr files when the cart is loaded */
+#define SPLIT_PRG 0
+#define SPLIT_CHR 0
- In MESS: Supported? Not sure if we could also have ExRAM or not...
- However, priority is pretty low for this mapper.
-
-*************************************************************/
-
-/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
-we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
-there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
-
-void nes_state::ffe_irq( int scanline, int vblank, int blanked )
-{
- // 114 is the number of cycles per scanline
- // TODO: change to reflect the actual number of cycles spent
- if (m_IRQ_enable)
- {
- if ((0xffff - m_IRQ_count) < 114)
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_count = 0xffff;
- m_IRQ_enable = 0;
- }
- m_IRQ_count -= 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::mapper6_l_w)
-{
- LOG_MMC(("mapper6_l_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x1fe:
- m_mmc_latch1 = data & 0x80;
- set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- break;
- case 0x1ff:
- set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- case 0x401:
- m_IRQ_enable = data & 0x01;
- break;
- case 0x402:
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
- break;
- case 0x403:
- m_IRQ_enable = 1;
- m_IRQ_count = (m_IRQ_count & 0x00ff) | (data << 8);
- break;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::mapper6_w)
-{
- LOG_MMC(("mapper6_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!m_mmc_latch1) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank?
- {
- prg16_89ab(data >> 2);
- // chr8(data & 0x03, ???);
- // due to lack of info on the exact behavior, we simply act as if mmc_latch1=1
- if (m_mmc_chr_source == CHRROM)
- chr8(data & 0x03, CHRROM);
- }
- else if (m_mmc_chr_source == CHRROM) // otherwise, we can use CHRROM (when present)
- chr8(data, CHRROM);
-}
-
-/*************************************************************
-
- Mapper 8
-
- Known Boards: FFE3 Copier Board
- Games: Hacked versions of games
-
- In MESS: Supported? (I have no games to test this)
-
-*************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::mapper8_w)
-{
- LOG_MMC(("mapper8_w, offset: %04x, data: %02x\n", offset, data));
-
- chr8(data & 0x07, CHRROM);
- prg16_89ab(data >> 3);
-}
/*************************************************************
- Mapper 17
+ mmc_list
- Known Boards: FFE8 Copier Board
- Games: Hacked versions of games
+ Supported mappers and corresponding pcb id
- In MESS: Supported?. IRQ support is just a guess (used to
- use MMC3 IRQ but it was wrong and it never enabled it)
+ *************************************************************/
-*************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::mapper17_l_w)
+struct nes_mmc
{
- LOG_MMC(("mapper17_l_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x1fe:
- set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- break;
- case 0x1ff:
- set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- case 0x401:
- m_IRQ_enable = data & 0x01;
- break;
- case 0x402:
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
- break;
- case 0x403:
- m_IRQ_enable = 1;
- m_IRQ_count = (m_IRQ_count & 0x00ff) | (data << 8);
- break;
-
- case 0x404:
- prg8_89(data);
- break;
- case 0x405:
- prg8_ab(data);
- break;
- case 0x406:
- prg8_cd(data);
- break;
- case 0x407:
- prg8_ef(data);
- break;
-
- case 0x410:
- case 0x411:
- case 0x412:
- case 0x413:
- case 0x414:
- case 0x415:
- case 0x416:
- case 0x417:
- chr1_x(offset & 7, data, CHRROM);
- break;
- }
-}
-
-/*************************************************************
-
- mmc_list
-
- Supported mappers and corresponding pcb id
+ int iNesMapper; /* iNES Mapper # */
+ int pcb_id;
+};
-*************************************************************/
static const nes_mmc mmc_list[] =
{
@@ -185,18 +36,18 @@ static const nes_mmc mmc_list[] =
{ 3, STD_CNROM },
{ 4, STD_TXROM },
{ 5, STD_EXROM },
- { 6, FFE_MAPPER6 },
+ { 6, FFE4_BOARD },
{ 7, STD_AXROM },
- { 8, FFE_MAPPER8 },
+ { 8, FFE3_BOARD },
{ 9, STD_PXROM },
{ 10, STD_FXROM },
{ 11, DIS_74X377 },
{ 12, REXSOFT_DBZ5 },
{ 13, STD_CPROM },
{ 14, REXSOFT_SL1632 },
- { 15, WAIXING_PS2 },
- { 16, BANDAI_LZ93EX }, // with 24c02
- { 17, FFE_MAPPER17 },
+ { 15, WAIXING_WXZS2 },
+ { 16, BANDAI_LZ93EX2 }, // with 24c02
+ { 17, FFE8_BOARD },
{ 18, JALECO_SS88006 },
{ 19, NAMCOT_163 },
{ 21, KONAMI_VRC4 },
@@ -205,6 +56,7 @@ static const nes_mmc mmc_list[] =
{ 24, KONAMI_VRC6 },
{ 25, KONAMI_VRC4 },
{ 26, KONAMI_VRC6 },
+ { 27, UNL_WORLDHERO },
// 27 World Hero board - Unsupported
// 28 Unused
// 29 Unused
@@ -214,13 +66,13 @@ static const nes_mmc mmc_list[] =
{ 33, TAITO_TC0190FMC },
{ 34, STD_BXROM },
{ 35, UNL_SC127 },
- { 36, TXC_STRIKEWOLF },
+ { 36, TXC_STRIKEW },
{ 37, PAL_ZZ },
{ 38, DIS_74X161X138 },
{ 39, UNL_STUDYNGAME },
- { 40, BTL_SMB2A },
+ { 40, BTL_SMB2JA },
{ 41, CALTRON_6IN1 },
- { 42, BTL_MARIOBABY }, // ai senshi nicol?
+ { 42, BTL_MARIOBABY }, // ai senshi nicole too, changed by crc_hack
{ 43, UNL_SMB2J },
{ 44, BMC_SUPERBIG_7IN1 },
{ 45, BMC_HIK8IN1 },
@@ -228,26 +80,26 @@ static const nes_mmc mmc_list[] =
{ 47, NES_QJ },
{ 48, TAITO_TC0190FMCP },
{ 49, BMC_SUPERHIK_4IN1 },
- { 50, BTL_SMB2B },
+ { 50, BTL_SMB2JB },
{ 51, BMC_BALLGAMES_11IN1 },
{ 52, BMC_GOLD_7IN1 },
- // 53 Supervision 16-in-1 - Unsupported
- { 54, BMC_NOVELDIAMOND },
+ { 53, SVISION16_BOARD },
+ { 54, BMC_NOVEL1 },
// 55 Genius SMB - No info (nor images) available
{ 56, KAISER_KS202 },
{ 57, BMC_GKA },
{ 58, BMC_GKB },
// 59 Unused
// 60 4-in-1, 35-in-1 Reset based
- { 61, RCM_TETRISFAMILY },
+ { 61, RCM_TF9IN1 },
{ 62, BMC_SUPER_700IN1 },
- // 63 CH001 X-in-1 - No info (nor images) available
+ { 63, BMC_CH001 }, // Powerful 255
{ 64, TENGEN_800032 },
{ 65, IREM_H3001 },
{ 66, STD_GXROM },
{ 67, SUNSOFT_3 },
- { 68, STD_NXROM },
- { 69, STD_JXROM },
+ { 68, SUNSOFT_DCS },
+ { 69, SUNSOFT_FME7 },
{ 70, DIS_74X161X161X32 },
{ 71, CAMERICA_BF9093 },
{ 72, JALECO_JF17 },
@@ -256,7 +108,7 @@ static const nes_mmc mmc_list[] =
{ 75, KONAMI_VRC1 },
{ 76, NAMCOT_3446 },
{ 77, IREM_LROG017 },
- { 78, IREM_HOLYDIV },
+ { 78, IREM_HOLYDIVR },
{ 79, AVE_NINA06 },
{ 80, TAITO_X1_005 },
// 81 Unused
@@ -268,7 +120,7 @@ static const nes_mmc mmc_list[] =
{ 87, DIS_74X139X74 },
{ 88, NAMCOT_34X3 },
{ 89, SUNSOFT_2 },
- // 90 JY Company Type A (Aladdin, Final Fight 3, Super Mario World, Tekken 2) - Unsupported
+ { 90, JYCOMPANY_A },
{ 91, UNL_MK2 },
{ 92, JALECO_JF19 },
{ 93, SUNSOFT_2 },
@@ -281,9 +133,10 @@ static const nes_mmc mmc_list[] =
// 100 images hacked to work with nesticle?
// 101 Unused (Urusei Yatsura had been assigned to this mapper, but it's Mapper 87)
// 102 Unused
+ { 103, UNL_2708 },
// 103 Bootleg cart 2708 (Doki Doki Panic - FDS Conversion) - Unsupported
{ 104, CAMERICA_GOLDENFIVE },
- // 105 Nintendo World Championship - Unsupported
+ { 105, STD_EVENT },
{ 106, BTL_SMB3 },
{ 107, MAGICSERIES_MD },
{ 108, WHIRLWIND_2706 },
@@ -294,12 +147,12 @@ static const nes_mmc mmc_list[] =
{ 113, HES_BOARD },
{ 114, SUPERGAME_LIONKING },
{ 115, KASING_BOARD },
- { 116, SOMERI_SL12 },
+ { 116, SOMARI_SL12 },
{ 117, FUTUREMEDIA_BOARD },
{ 118, STD_TXSROM },
{ 119, STD_TQROM },
{ 120, BTL_TOBIDASE },
- { 121, KAY_PANDAPRINCE },
+ { 121, KAY_BOARD },
// 122 Unused
{ 123, UNL_H2288 },
// 124 Unused
@@ -310,9 +163,9 @@ static const nes_mmc mmc_list[] =
// 129 Unused
// 130 Unused
// 131 Unused
- { 132, TXC_22211B },
+ { 132, TXC_22211 },
{ 133, SACHEN_SA72008 },
- { 134, BMC_FAMILY_4646B },
+ { 134, BMC_FAMILY_4646 },
// 135 Unused
{ 136, SACHEN_TCU02 },
{ 137, SACHEN_8259D },
@@ -332,12 +185,12 @@ static const nes_mmc mmc_list[] =
// 151 VS. system by Konami - Not going to be implemented (use MAME instead)
{ 152, DIS_74X161X161X32 },
{ 153, BANDAI_LZ93 },
- { 154, NAMCOT_3453 },
+ { 154, NAMCOT_34X3 },
{ 155, STD_SXROM_A }, // diff compared to MMC1 concern WRAM
{ 156, OPENCORP_DAOU306 },
{ 157, BANDAI_DATACH }, // no Datach Reader -> we fall back to mapper 16
{ 158, TENGEN_800037 },
- { 159, BANDAI_LZ93EX }, // with 24c01
+ { 159, BANDAI_LZ93EX1 }, // with 24c01
{ 160, SACHEN_SA009 },
// 161 Unused
// 162 Unused
@@ -350,18 +203,18 @@ static const nes_mmc mmc_list[] =
// 169 Unused
// 170 Fujiya
{ 171, KAISER_KS7058 },
- { 172, TXC_22211B },
- { 173, TXC_22211C },
+ { 172, TXC_DUMARACING },
+ { 173, TXC_MJBLOCK },
// 174 Unused
{ 175, KAISER_KS7022},
- { 176, UNL_XZY },
- { 177, HENGEDIANZI_BOARD },
+ { 176, UNL_XIAOZY },
+ { 177, HENGG_SRICH },
{ 178, WAIXING_SGZLZ },
- { 179, HENGEDIANZI_XJZB },
+ { 179, HENGG_XHZS },
{ 180, UXROM_CC },
// 181 Unused
{ 182, HOSENKAN_BOARD },
- // 183 FDS bootleg (Shui Guan Pipe) - Unsupported
+ { 183, BTL_SHUIGUAN },
{ 184, SUNSOFT_1 },
{ 185, STD_CNROM },
{ 186, FUKUTAKE_BOARD },
@@ -374,8 +227,8 @@ static const nes_mmc mmc_list[] =
{ 193, NTDEC_FIGHTINGHERO },
{ 194, WAIXING_TYPE_D },
{ 195, WAIXING_TYPE_E },
- { 196, BTL_SUPERBROS11 },
- { 197, UNL_SUPERFIGHTER3 },
+ { 196, BTL_SBROS11 },
+ { 197, UNL_SF3 },
{ 198, WAIXING_TYPE_F },
{ 199, WAIXING_TYPE_G },
{ 200, BMC_36IN1 },
@@ -384,20 +237,20 @@ static const nes_mmc mmc_list[] =
{ 203, BMC_35IN1 },
{ 204, BMC_64IN1 },
{ 205, BMC_15IN1 },
- { 206, STD_DXROM },
- { 207, TAITO_X1_005_A },
+ { 206, NAMCOT_34X3 },
+ { 207, TAITO_X1_005 },
{ 208, GOUDER_37017 },
- // 209 JY Company Type B (Power Rangers 3 & 4, Shin Samurai Spirits 2) - Unsupported
- // 210 Some emu uses this as Mapper 19 without some features
- // 211 JY Company Type C (Tiny Toon Adventures 6, Donkey Kong Country 4) - Unsupported
+ { 209, JYCOMPANY_C },
+ { 210, NAMCOT_175 },
+ { 211, JYCOMPANY_B },
{ 212, BMC_SUPERHIK_300IN1 },
- { 213, BMC_9999999IN1 },
+ { 213, BMC_NOVEL2 },
{ 214, BMC_SUPERGUN_20IN1 },
{ 215, SUPERGAME_BOOGERMAN },
{ 216, RCM_GS2015 },
{ 217, BMC_GOLDENCARD_6IN1 },
// 218 Unused
- // 219 Bootleg A9746 - Unsupported
+ { 216, UNL_A9746 },
// 220 Unused
{ 221, UNL_N625092 },
{ 222, BTL_DRAGONNINJA },
@@ -411,17 +264,18 @@ static const nes_mmc mmc_list[] =
{ 230, BMC_22GAMES },
{ 231, BMC_20IN1 },
{ 232, CAMERICA_BF9096 },
- // 233 Super 22 Games - Unsupported
- // 234 AVE Maxi 15 - Unsupported
+ { 233, BMC_SUPER22 },
+ { 234, AVE_MAXI15 },
+ { 235, BMC_GOLD150 },
// 235 Golden Game x-in-1 - Unsupported
// 236 Game 800-in-1 - Unsupported
// 237 Unused
{ 238, UNL_603_5052 },
// 239 Unused
{ 240, CNE_SHLZ },
- { 241, TXC_MXMDHTWO },
- { 242, WAIXING_ZS },
- { 243, SACHEN_74LS374_A },
+ { 241, TXC_COMMANDOS },
+ { 242, WAIXING_WXZS },
+ { 243, SACHEN_74LS374_ALT },
{ 244, CNE_DECATHLON },
{ 245, WAIXING_TYPE_H },
{ 246, CNE_FSB },
@@ -449,6 +303,7 @@ const nes_mmc *nes_mapper_lookup( int mapper )
return NULL;
}
+#if 0
int nes_get_mmc_id( running_machine &machine, int mapper )
{
const nes_mmc *mmc = nes_mapper_lookup(mapper);
@@ -458,3 +313,479 @@ int nes_get_mmc_id( running_machine &machine, int mapper )
return mmc->pcb_id;
}
+#endif
+
+/*************************************************************
+
+ ines_mapr_setup
+
+ setup the board specific pcb_id for a given mapper
+
+ *************************************************************/
+
+void ines_mapr_setup( int mapper, int *pcb_id )
+{
+ const nes_mmc *mmc = nes_mapper_lookup(mapper);
+ if (mmc == NULL)
+ fatalerror("Unimplemented Mapper %d\n", mapper);
+
+ *pcb_id = mmc->pcb_id;
+}
+
+/*************************************************************
+
+ call_load_ines
+
+ *************************************************************/
+
+void nes_cart_slot_device::call_load_ines()
+{
+ UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_sram_size = 0;
+ UINT32 prg_size, vrom_size;
+ UINT8 header[0x10];
+ UINT8 mapper, local_options;
+ bool ines20 = FALSE, prg16k;
+ const char *mapinfo = NULL;
+ int pcb_id = 0, mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0;
+ int crc_hack = 0;
+
+ // check if the image is recognized by nes.hsi
+ mapinfo = hashfile_extrainfo(*this);
+
+ // read out the header
+ fseek(0, SEEK_SET);
+ fread(&header, 0x10);
+
+ // SETUP step 1: getting PRG, VROM, VRAM sizes
+ prg16k = (header[4] == 1);
+ prg_size = prg16k ? 2 * 0x4000 : header[4] * 0x4000;
+ vrom_size = header[5] * 0x2000;
+ vram_size = 0x4000;
+
+ // SETUP step 2: getting PCB and other settings
+ mapper = (header[6] & 0xf0) >> 4;
+ local_options = header[6] & 0x0f;
+
+ switch (header[7] & 0xc)
+ {
+ case 0x4:
+ case 0xc:
+ // probably the header got corrupted: don't trust upper bits for mapper
+ break;
+
+ case 0x8: // it's iNES 2.0 format
+ ines20 = TRUE;
+ case 0x0:
+ default:
+ mapper |= header[7] & 0xf0;
+ break;
+ }
+
+ // use info from nes.hsi if available!
+ if (mapinfo)
+ {
+ if (4 == sscanf(mapinfo,"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4))
+ {
+ /* image is present in nes.hsi: overwrite the header settings with these */
+ mapper = mapint1;
+ local_options = mapint2 & 0x0f;
+ crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below)
+ prg16k = (mapint3 == 1);
+ prg_size = prg16k ? 2 * 0x4000 : mapint3 * 0x4000;
+ vrom_size = mapint4 * 0x2000;
+ logerror("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4);
+ }
+ else
+ {
+ logerror("NES: [%s], Invalid mapinfo found\n", mapinfo);
+ }
+ }
+ else
+ {
+ logerror("NES: No extrainfo found\n");
+ }
+
+ // use extended iNES2.0 info if available!
+ if (ines20)
+ {
+ mapper |= (header[8] & 0x0f) << 8;
+ // header[8] & 0xf0 is used for submappers, but I haven't found any specific image to implement this
+ prg_size += ((header[9] & 0x0f) << 8) * 0x4000;
+ vrom_size += ((header[9] & 0xf0) << 4) * 0x2000;
+ }
+ ines_mapr_setup(mapper, &pcb_id);
+
+ // SETUP step 3: storing the info needed for emulation
+ m_pcb_id = pcb_id;
+ m_cart->set_mirroring(BIT(local_options, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ if (BIT(local_options, 1))
+ battery_size = NES_BATTERY_SIZE; // with original iNES format we can only support 8K WRAM battery
+ m_cart->set_trainer(BIT(local_options, 2) ? TRUE : FALSE);
+ m_cart->set_four_screen_vram(BIT(local_options, 3) ? TRUE : FALSE);
+
+ if (ines20)
+ {
+ // PRGRAM/BWRAM (not fully supported, also due to lack of 2.0 files)
+ if ((header[10] & 0x0f) > 0)
+ prgram_size = 0x80 << ((header[10] & 0x0f) - 1);
+ if ((header[10] & 0xf0) > 0)
+ battery_size = 0x80 << ((header[10] & 0xf0) - 5);
+ // VRAM
+ vram_size = 0;
+ if ((header[11] & 0x0f) > 0)
+ vram_size = 0x80 << ((header[11] & 0x0f) - 1);
+ // header[11] & 0xf0 is the size of battery backed VRAM, found so far in Racermate II only and not supported yet
+ }
+ else
+ {
+ // PRGRAM size is 8k for most games, but pirate carts often use different sizes,
+ // so its size has been added recently to the iNES format spec, but almost no image uses it
+ prgram_size = header[8] ? header[8] * 0x2000 : 0x2000;
+ }
+
+ // a few mappers correspond to multiple PCBs, so we need a few additional checks and tweaks
+ switch (m_pcb_id)
+ {
+ case STD_CNROM:
+ if (mapper == 185)
+ {
+ switch (crc_hack)
+ {
+ case 0x0: // pin26: CE, pin27: CE (B-Wings, Bird Week)
+ m_cart->set_ce(0x03, 0x03);
+ break;
+ case 0x4: // pin26: CE, pin27: /CE (Mighty Bomb Jack, Spy Vs. Spy)
+ m_cart->set_ce(0x03, 0x01);
+ break;
+ case 0x8: // pin26: /CE, pin27: CE (Sansu 1, 2, 3 Nen)
+ m_cart->set_ce(0x03, 0x02);
+ break;
+ case 0xc: // pin26: /CE, pin27: /CE (Seicross v2.0)
+ m_cart->set_ce(0x03, 0x00);
+ break;
+ }
+ }
+ break;
+
+ case KONAMI_VRC2:
+ if (mapper == 22)
+ m_cart->set_vrc_lines(0, 1, 1);
+ if (mapper == 23 && !crc_hack)
+ m_cart->set_vrc_lines(1, 0, 0);
+ if (mapper == 23 && crc_hack)
+ {
+ // here there are also Akumajou Special, Crisis Force, Parodius da!, Tiny Toons which are VRC-4
+ m_cart->set_vrc_lines(3, 2, 0);
+ m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset
+ }
+ break;
+
+ case KONAMI_VRC4:
+ if (mapper == 21) // Wai Wai World 2 & Ganbare Goemon Gaiden 2 (the latter with crc_hack)
+ m_cart->set_vrc_lines(crc_hack ? 7 : 2, crc_hack ? 6 : 1, 0);
+ if (mapper == 25) // here there is also Ganbare Goemon Gaiden which is VRC-2
+ m_cart->set_vrc_lines(crc_hack ? 2 : 0, crc_hack ? 3 : 1, 0);
+ break;
+
+ case KONAMI_VRC6:
+ if (mapper == 24)
+ m_cart->set_vrc_lines(1, 0, 0);
+ if (mapper == 26)
+ m_cart->set_vrc_lines(0, 1, 0);
+ break;
+
+ case IREM_G101:
+ if (crc_hack)
+ m_cart->set_mirroring(PPU_MIRROR_HIGH); // Major League has hardwired mirroring
+ else
+ m_cart->set_pcb_ctrl_mirror(TRUE);
+ break;
+
+ case DIS_74X161X161X32:
+ if (mapper == 70)
+ m_cart->set_mirroring(PPU_MIRROR_VERT); // only hardwired mirroring makes different mappers 70 & 152
+ else
+ m_cart->set_pcb_ctrl_mirror(TRUE);
+ break;
+
+ case SUNSOFT_2:
+ if (mapper == 93)
+ m_cart->set_mirroring(PPU_MIRROR_VERT); // only hardwired mirroring makes different mappers 89 & 93
+ else
+ m_cart->set_pcb_ctrl_mirror(TRUE);
+ break;
+
+ case HES_BOARD:
+ if (crc_hack)
+ m_cart->set_pcb_ctrl_mirror(TRUE); // Mapper 113 is used for 2 diff boards
+ break;
+
+ case CAMERICA_BF9093:
+ if (crc_hack)
+ m_cart->set_pcb_ctrl_mirror(TRUE); // Mapper 71 is used for 2 diff boards
+ break;
+
+ case STD_BXROM:
+ if (crc_hack)
+ m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards
+ break;
+
+ case BANDAI_LZ93:
+ if (crc_hack)
+ m_pcb_id = BANDAI_FJUMP2; // Mapper 153 is used for 2 diff boards
+ break;
+
+ case IREM_HOLYDIVR:
+ if (crc_hack)
+ m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards
+ break;
+
+ case WAIXING_WXZS:
+ if (crc_hack)
+ m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards
+ break;
+
+ case BMC_GOLD_7IN1:
+ if (crc_hack)
+ m_pcb_id = BMC_MARIOPARTY_7IN1; // Mapper 52 is used for 2 diff boards
+ break;
+
+
+ case BTL_MARIOBABY:
+ if (crc_hack)
+ m_pcb_id = BTL_AISENSHINICOL; // Mapper 42 is used for 2 diff boards
+ break;
+
+ case TAITO_X1_017:
+ mapper_sram_size = m_cart->get_mapper_sram_size();
+ break;
+
+ case TAITO_X1_005:
+ if (mapper == 207)
+ m_cart->set_x1_005_alt(TRUE);
+ mapper_sram_size = m_cart->get_mapper_sram_size();
+ break;
+
+ case NAMCOT_163:
+ mapper_sram_size = m_cart->get_mapper_sram_size();
+ break;
+ //FIXME: we also have to fix Action 52 PRG loading somewhere...
+ }
+
+ // Finally turn off bus conflict emulation, because the pirate variants of the boards are bus conflict free and games would glitch
+ m_cart->set_bus_conflict(FALSE);
+
+ // SETUP step 4: logging what we have found
+ if (!ines20)
+ {
+ logerror("Loaded game in iNES format:\n");
+ logerror("-- Mapper %d\n", mapper);
+ logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000);
+ logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000);
+ logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000);
+ if (battery_size)
+ logerror("-- Battery found\n");
+ if (m_cart->get_trainer())
+ logerror("-- Trainer found\n");
+ if (m_cart->get_four_screen_vram())
+ logerror("-- 4-screen VRAM\n");
+ logerror("-- TV System: %s\n", ((header[10] & 3) == 0) ? "NTSC" : (header[10] & 1) ? "Both NTSC and PAL" : "PAL");
+ }
+ else
+ {
+ logerror("Loaded game in Extended iNES format:\n");
+ logerror("-- Mapper: %d\n", mapper);
+ logerror("-- Submapper: %d\n", (header[8] & 0xf0) >> 4);
+ logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000);
+ logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000);
+ logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000);
+ logerror("-- PRG NVWRAM: %d\n", header[10] & 0x0f);
+ logerror("-- PRG WRAM: %d\n", (header[10] & 0xf0) >> 4);
+ logerror("-- CHR NVWRAM: %d\n", header[11] & 0x0f);
+ logerror("-- CHR WRAM: %d\n", (header[11] & 0xf0) >> 4);
+ logerror("-- TV System: %s\n", (header[12] & 2) ? "Both NTSC and PAL" : (header[12] & 1) ? "PAL" : "NTSC");
+ }
+
+ // SETUP step 5: allocate pointers for PRG/VROM
+ if (prg_size)
+ m_cart->prg_alloc(machine(), prg_size);
+ if (vrom_size)
+ m_cart->vrom_alloc(machine(), vrom_size);
+
+ // if there is a trainer, skip it for the moment
+ if (m_cart->get_trainer())
+ fseek(0x210, SEEK_SET);
+
+ // SETUP step 6: at last load the data!
+ // Read in the program chunks
+ if (prg16k)
+ {
+ fread(m_cart->get_prg_base(), 0x4000);
+ memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000);
+ }
+ else
+ fread(m_cart->get_prg_base(), m_cart->get_prg_size());
+#if SPLIT_PRG
+ {
+ FILE *prgout;
+ char outname[255];
+
+ sprintf(outname, "%s.prg", filename());
+ prgout = fopen(outname, "wb");
+ if (prgout)
+ {
+ fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout);
+ mame_printf_error("Created PRG chunk\n");
+ }
+
+ fclose(prgout);
+ }
+#endif
+
+ // Read in any chr chunks
+ if (m_cart->get_vrom_size())
+ fread(m_cart->get_vrom_base(), m_cart->get_vrom_size());
+
+#if SPLIT_CHR
+ if (state->m_chr_chunks > 0)
+ {
+ FILE *chrout;
+ char outname[255];
+
+ sprintf(outname, "%s.chr", filename());
+ chrout= fopen(outname, "wb");
+ if (chrout)
+ {
+ fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout);
+ mame_printf_error("Created CHR chunk\n");
+ }
+ fclose(chrout);
+ }
+#endif
+
+ // SETUP steps 7: allocate the remaining pointer, when needed
+ if (vram_size)
+ m_cart->vram_alloc(machine(), vram_size);
+ if (prgram_size || m_cart->get_trainer())
+ {
+ if (prgram_size)
+ m_cart->prgram_alloc(machine(), prgram_size);
+ else
+ m_cart->prgram_alloc(machine(), 0x2000);
+ if (m_cart->get_trainer())
+ {
+ fseek(0x10, SEEK_SET);
+ fread(m_cart->get_prgram_base() + 0x1000, 0x200);
+ }
+ }
+
+
+ // Attempt to load a battery file for this ROM
+ // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.)
+ if (battery_size || mapper_sram_size)
+ {
+ UINT32 tot_size = battery_size + mapper_sram_size;
+ UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size);
+ battery_load(temp_nvram, tot_size, 0x00);
+ if (battery_size)
+ {
+ m_cart->battery_alloc(machine(), battery_size);
+ memcpy(m_cart->get_battery_base(), temp_nvram, battery_size);
+ }
+ if (mapper_sram_size)
+ memcpy(m_cart->get_mapper_sram_base(), temp_nvram + battery_size, m_cart->get_mapper_sram_size());
+
+ if (temp_nvram)
+ auto_free(machine(), temp_nvram);
+ }
+}
+
+const char * nes_cart_slot_device::get_default_card_ines(UINT8 *ROM, UINT32 len)
+{
+ UINT8 mapper;
+ bool ines20 = FALSE;
+ const char *mapinfo = NULL;
+ int pcb_id = 0, mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0;
+ int crc_hack = 0;
+
+ // check if the image is recognized by nes.hsi
+// mapinfo = hashfile_extrainfo(*this);
+
+ mapper = (ROM[6] & 0xf0) >> 4;
+
+ switch (ROM[7] & 0xc)
+ {
+ case 0x4:
+ case 0xc:
+ // probably the header got corrupted: don't trust upper bits for mapper
+ break;
+
+ case 0x8: // it's iNES 2.0 format
+ ines20 = TRUE;
+ case 0x0:
+ default:
+ mapper |= ROM[7] & 0xf0;
+ break;
+ }
+
+ // use info from nes.hsi if available!
+ if (mapinfo)
+ {
+ if (4 == sscanf(mapinfo,"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4))
+ {
+ /* image is present in nes.hsi: overwrite the header settings with these */
+ mapper = mapint1;
+ crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below)
+ }
+ }
+
+ // use extended iNES2.0 info if available!
+ if (ines20)
+ {
+ mapper |= (ROM[8] & 0x0f) << 8;
+ // ROM[8] & 0xf0 is used for submappers, but I haven't found any specific image to implement this
+ }
+
+ ines_mapr_setup(mapper, &pcb_id);
+
+ // solve mapper conflicts
+ switch (pcb_id)
+ {
+ case KONAMI_VRC2:
+ if (mapper == 23 && crc_hack)
+ m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset
+ break;
+
+ case STD_BXROM:
+ if (crc_hack)
+ m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards
+ break;
+
+ case BANDAI_LZ93:
+ if (crc_hack)
+ m_pcb_id = BANDAI_FJUMP2; // Mapper 153 is used for 2 diff boards
+ break;
+
+ case IREM_HOLYDIVR:
+ if (crc_hack)
+ m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards
+ break;
+
+ case WAIXING_WXZS:
+ if (crc_hack)
+ m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards
+ break;
+
+ case BMC_GOLD_7IN1:
+ if (crc_hack)
+ m_pcb_id = BMC_MARIOPARTY_7IN1; // Mapper 52 is used for 2 diff boards
+ break;
+
+ case BTL_MARIOBABY:
+ if (crc_hack)
+ m_pcb_id = BTL_AISENSHINICOL; // Mapper 42 is used for 2 diff boards
+ break;
+ }
+
+ return nes_get_slot(pcb_id);
+}
diff --git a/src/mess/machine/nes_irem.c b/src/mess/machine/nes_irem.c
new file mode 100644
index 00000000000..35bef9b856a
--- /dev/null
+++ b/src/mess/machine/nes_irem.c
@@ -0,0 +1,333 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for IREM PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * IREM LROG017 [mapper 77]
+ * IREM Holy Diver [mapper 78]
+ * IREM TAM-S1 [mapper 97]
+ * IREM G101 [mapper 32]
+ * IREM H3001 [mapper 65]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_irem.h"
+
+#include "cpu/m6502/m6502.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_LROG017 = &device_creator<nes_lrog017_device>;
+const device_type NES_HOLYDIVR = &device_creator<nes_holydivr_device>;
+const device_type NES_TAM_S1 = &device_creator<nes_tam_s1_device>;
+const device_type NES_G101 = &device_creator<nes_g101_device>;
+const device_type NES_H3001 = &device_creator<nes_h3001_device>;
+
+
+nes_lrog017_device::nes_lrog017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_LROG017, "NES Cart Irem Discrete 74*161/161/21/138 PCB", tag, owner, clock, "nes_lrog017", __FILE__)
+{
+}
+
+nes_holydivr_device::nes_holydivr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_HOLYDIVR, "NES Cart Irem Holy Diver PCB", tag, owner, clock, "nes_holydivr", __FILE__)
+{
+}
+
+nes_tam_s1_device::nes_tam_s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TAM_S1, "NES Cart Irem TAM-S1 PCB", tag, owner, clock, "nes_tam_s1", __FILE__)
+{
+}
+
+nes_g101_device::nes_g101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_G101, "NES Cart Irem G-101 PCB", tag, owner, clock, "nes_g101", __FILE__)
+{
+}
+
+nes_h3001_device::nes_h3001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_H3001, "NES Cart Irem H-3001 PCB", tag, owner, clock, "nes_h3001", __FILE__)
+{
+}
+
+
+
+
+void nes_lrog017_device::device_start()
+{
+ common_start();
+}
+
+void nes_lrog017_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr2_0(0, CHRROM);
+ chr2_2(0, CHRROM);
+ chr2_4(1, CHRROM);
+ chr2_6(2, CHRROM);
+}
+
+void nes_holydivr_device::device_start()
+{
+ common_start();
+}
+
+void nes_holydivr_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_tam_s1_device::device_start()
+{
+ common_start();
+}
+
+void nes_tam_s1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 1);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_g101_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_g101_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_h3001_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+}
+
+void nes_h3001_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0;
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Irem LROG017 - Discrete board emulation (74*161/161/21/138)
+
+ Games: Napoleon Senki
+
+ iNES: mapper 77
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_lrog017_device::write_h)
+{
+ LOG_MMC(("lrog017 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ prg32(data);
+ chr2_0((data >> 4), CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Irem Holy Diver board emulation
+
+ iNES: mapper 78 (shared with JF-16)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_holydivr_device::write_h)
+{
+ LOG_MMC(("holy diver write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ chr8(data >> 4, CHRROM);
+ prg16_89ab(data);
+}
+
+/*-------------------------------------------------
+
+ Irem TAM-S1 board emulation
+
+ Games: Kaiketsu Yanchamaru
+
+ iNES: mapper 97
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_tam_s1_device::write_h)
+{
+ LOG_MMC(("tam s1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x4000)
+ {
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ prg16_cdef(data);
+ }
+}
+
+/*-------------------------------------------------
+
+ Irem G-101 board emulation
+
+ Major League uses hardwired mirroring
+
+ iNES: mapper 32
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_g101_device::write_h)
+{
+ LOG_MMC(("g101 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ // NEStopia here differs a little bit
+ m_latch ? prg8_cd(data) : prg8_89(data);
+ break;
+ case 0x1000:
+ m_latch = BIT(data, 1);
+ if (m_pcb_ctrl_mirror)
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ prg8_ab(data);
+ break;
+ case 0x3000:
+ chr1_x(offset & 0x07, data, CHRROM);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Irem H-3001 board emulation
+
+ Games: Daiku no Gen San 2 - Akage no Dan no Gyakushuu,
+ Kaiketsu Yanchamaru 3, Spartan X 2
+
+ iNES: mapper 65
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+void nes_h3001_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ m_irq_count -= 114;
+
+ if (m_irq_count <= 114)
+ {
+ m_irq_enable = 0;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+}
+
+WRITE8_MEMBER(nes_h3001_device::write_h)
+{
+ LOG_MMC(("h3001 write_h, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7fff)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+
+ case 0x1001:
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x1003:
+ m_irq_enable = data & 0x80;
+ break;
+
+ case 0x1004:
+ m_irq_count = m_irq_count_latch;
+ break;
+
+ case 0x1005:
+ m_irq_count_latch = (m_irq_count_latch & 0x00ff) | (data << 8);
+ break;
+
+ case 0x1006:
+ m_irq_count_latch = (m_irq_count_latch & 0xff00) | data;
+ break;
+
+ case 0x2000:
+ prg8_ab(data);
+ break;
+
+ case 0x3000: case 0x3001: case 0x3002: case 0x3003:
+ case 0x3004: case 0x3005: case 0x3006: case 0x3007:
+ chr1_x(offset & 0x07, data, CHRROM);
+ break;
+
+ case 0x4000:
+ prg8_cd(data);
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_irem.h b/src/mess/machine/nes_irem.h
new file mode 100644
index 00000000000..9afdc29f076
--- /dev/null
+++ b/src/mess/machine/nes_irem.h
@@ -0,0 +1,103 @@
+#ifndef __NES_IREM_H
+#define __NES_IREM_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_lrog017_device
+
+class nes_lrog017_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_lrog017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_holydivr_device
+
+class nes_holydivr_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_holydivr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_tam_s1_device
+
+class nes_tam_s1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_tam_s1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_g101_device
+
+class nes_g101_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_g101_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_h3001_device
+
+class nes_h3001_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_h3001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ UINT16 m_irq_count, m_irq_count_latch;
+ int m_irq_enable;
+};
+
+
+
+// device type definition
+extern const device_type NES_LROG017;
+extern const device_type NES_HOLYDIVR;
+extern const device_type NES_TAM_S1;
+extern const device_type NES_G101;
+extern const device_type NES_H3001;
+
+#endif
diff --git a/src/mess/machine/nes_jaleco.c b/src/mess/machine/nes_jaleco.c
new file mode 100644
index 00000000000..ce66bc17ef7
--- /dev/null
+++ b/src/mess/machine/nes_jaleco.c
@@ -0,0 +1,910 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Jaleco PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Jaleco JF-11 [mapper 140]
+ * Jaleco JF-13 [mapper 86]
+ * Jaleco JF-16 [mapper 78]
+ * Jaleco JF-17 [mapper 72] + its variant with samples
+ * Jaleco JF-19 [mapper 92] + its variant with samples
+ * Jaleco SS88006 [mapper 18] + its variant(s) with samples
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_jaleco.h"
+
+#include "cpu/m6502/m6502.h"
+#include "sound/samples.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_JF11 = &device_creator<nes_jf11_device>;
+const device_type NES_JF16 = &device_creator<nes_jf16_device>;
+const device_type NES_JF17 = &device_creator<nes_jf17_device>;
+const device_type NES_JF19 = &device_creator<nes_jf19_device>;
+const device_type NES_SS88006 = &device_creator<nes_ss88006_device>;
+const device_type NES_JF13 = &device_creator<nes_jf13_device>;
+const device_type NES_JF17_ADPCM = &device_creator<nes_jf17_adpcm_device>;
+const device_type NES_JF19_ADPCM = &device_creator<nes_jf19_adpcm_device>;
+const device_type NES_JF23 = &device_creator<nes_jf23_device>;
+const device_type NES_JF24 = &device_creator<nes_jf24_device>;
+const device_type NES_JF29 = &device_creator<nes_jf29_device>;
+const device_type NES_JF33 = &device_creator<nes_jf33_device>;
+
+
+nes_jf11_device::nes_jf11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_JF11, "NES Cart Jaleco JF-11 PCB", tag, owner, clock, "nes_jf11", __FILE__)
+{
+}
+
+nes_jf13_device::nes_jf13_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_JF13, "NES Cart Jaleco JF-13 PCB", tag, owner, clock, "nes_jf13", __FILE__),
+ m_samples(*this, "samples")
+{
+}
+
+nes_jf16_device::nes_jf16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_JF16, "NES Cart Jaleco JF-16 PCB", tag, owner, clock, "nes_jf16", __FILE__)
+{
+}
+
+nes_jf17_device::nes_jf17_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_jf17_device::nes_jf17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_JF17, "NES Cart Jaleco JF-17 PCB", tag, owner, clock, "nes_jf17", __FILE__)
+{
+}
+
+nes_jf17_adpcm_device::nes_jf17_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_jf17_device(mconfig, NES_JF17_ADPCM, "NES Cart Jaleco JF-17 + ADPCM (Moero!! Pro Tennis) PCB", tag, owner, clock, "nes_jf17_pcm", __FILE__),
+ m_samples(*this, "samples")
+{
+}
+
+nes_jf19_device::nes_jf19_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_jf19_device::nes_jf19_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_JF19, "NES Cart Jaleco JF-19 (Moero!! Pro Soccer) PCB", tag, owner, clock, "nes_jf19", __FILE__)
+{
+}
+
+nes_jf19_adpcm_device::nes_jf19_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_jf19_device(mconfig, NES_JF19_ADPCM, "NES Cart Jaleco JF-19 + ADPCM (Moero!! Pro Yakyuu 88) PCB", tag, owner, clock, "nes_jf19_pcm", __FILE__),
+ m_samples(*this, "samples")
+{
+}
+
+nes_ss88006_device::nes_ss88006_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_ss88006_device::nes_ss88006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SS88006, "NES Cart Jaleco SS88006 PCB", tag, owner, clock, "nes_ss88006", __FILE__)
+{
+}
+
+nes_ss88006_adpcm_device::nes_ss88006_adpcm_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)
+ : nes_ss88006_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_jf23_device::nes_jf23_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_ss88006_adpcm_device(mconfig, NES_JF23, "NES Cart Jaleco Shin Moero Pro Yakyuu PCB", tag, owner, clock, "nes_jf23", __FILE__),
+ m_samples(*this, "samples")
+{
+}
+
+nes_jf24_device::nes_jf24_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_ss88006_adpcm_device(mconfig, NES_JF24, "NES Cart Jaleco Terao no Dosukoi Oozumou PCB", tag, owner, clock, "nes_jf24", __FILE__),
+ m_samples(*this, "samples")
+{
+}
+
+nes_jf29_device::nes_jf29_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_ss88006_adpcm_device(mconfig, NES_JF29, "NES Cart Jaleco Moe Pro! '90 PCB", tag, owner, clock, "nes_jf29", __FILE__),
+ m_samples(*this, "samples")
+{
+}
+
+nes_jf33_device::nes_jf33_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_ss88006_adpcm_device(mconfig, NES_JF33, "NES Cart Jaleco Moe Pro! Saikyou-hen PCB", tag, owner, clock, "nes_jf33", __FILE__),
+ m_samples(*this, "samples")
+{
+}
+
+
+
+void nes_jf11_device::device_start()
+{
+ common_start();
+}
+
+void nes_jf11_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_jf13_device::device_start()
+{
+ common_start();
+}
+
+void nes_jf13_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_jf16_device::device_start()
+{
+ common_start();
+}
+
+void nes_jf16_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_jf17_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_jf17_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ m_latch = 0;
+}
+
+void nes_jf19_device::device_start()
+{
+ common_start();
+}
+
+void nes_jf19_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_ss88006_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_mmc_prg_bank));
+ save_item(NAME(m_mmc_vrom_bank));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+ save_item(NAME(m_irq_mode));
+ save_item(NAME(m_latch));
+}
+
+void nes_ss88006_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank));
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+ m_irq_enable = 0;
+ m_irq_mode = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0;
+ m_latch = 0;
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Jaleco JF-11, JF-12 & JF-14 boards emulation
+
+ Games: Bio Senshi Dan, Mississippi Satsujin Jiken
+
+ iNES: mapper 140
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_jf11_device::write_m)
+{
+ LOG_MMC(("jf11 write_m, offset: %04x, data: %02x\n", offset, data));
+ chr8(data, CHRROM);
+ prg32(data >> 4);
+}
+
+/*-------------------------------------------------
+
+ Jaleco JF-13 board emulation
+
+ Games: Moero Pro Yakyuu
+
+ Note: we don't emulate the additional sound hardware.
+
+ iNES: mapper 86
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_jf13_device::write_m)
+{
+ LOG_MMC(("jf13 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x1000)
+ {
+ prg32((data >> 4) & 0x03);
+ chr8(((data >> 4) & 0x04) | (data & 0x03), CHRROM);
+ }
+ else
+ {
+// printf("sample write: offset: %04x, data: %02x\n", offset, data);
+ if (data & 0x20)
+ m_samples->start(data & 0x0f, data & 0x0f);
+ else
+ m_samples->stop_all();
+ }
+}
+
+/*-------------------------------------------------
+
+ Jaleco JF-16 board emulation
+
+ iNES: mapper 78 (shared with a diff Irem board)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_jf16_device::write_h)
+{
+ LOG_MMC(("jf16 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ chr8(data >> 4, CHRROM);
+ prg16_89ab(data);
+}
+
+
+/*-------------------------------------------------
+
+ Jaleco JF-17 boards emulation
+
+ Note: we don't emulate the additional sound hardware
+ for Moero!! Pro Tennis
+
+ Games: Moero!! Juudou Warriors, Moero!! Pro Tennis, Pinball
+ Quest Jpn
+
+ iNES: mapper 72
+
+ In MESS: Supported, see below for the Moero Pro Tennis
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_jf17_device::write_h)
+{
+ LOG_MMC(("jf17 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ if (BIT(m_latch, 7) && !BIT(data, 7))
+ prg16_89ab(m_latch & 0x07);
+ if (BIT(m_latch, 6) && !BIT(data, 6))
+ chr8(m_latch & 0x0f, CHRROM);
+
+ m_latch = data;
+}
+
+WRITE8_MEMBER(nes_jf17_adpcm_device::write_h)
+{
+ LOG_MMC(("jf17 + ADPCM write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ if (BIT(m_latch, 7) && !BIT(data, 7))
+ prg16_89ab(m_latch & 0x07);
+ if (BIT(m_latch, 6) && !BIT(data, 6))
+ chr8(m_latch & 0x0f, CHRROM);
+ if (BIT(data, 5) && !BIT(data,4))
+ {
+// printf("sample write: offset: %04x, data: %02x\n", offset, data);
+ m_samples->start(offset & 0x1f, offset & 0x1f);
+ }
+
+ m_latch = data;
+}
+
+/*-------------------------------------------------
+
+ Jaleco JF-19 boards emulation
+
+ Note: we don't emulate the additional sound hardware.
+
+ Games: Moero Pro Soccer, Moero Pro Yakyuu '88
+
+ iNES: mapper 92
+
+ In MESS: Supported, see below for the Moero Pro Yakyuu '88
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_jf19_device::write_h)
+{
+ LOG_MMC(("jf19 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ if (BIT(data, 7))
+ prg16_cdef(data & 0x0f);
+ if (BIT(data, 6))
+ chr8(data & 0x0f, CHRROM);
+}
+
+WRITE8_MEMBER(nes_jf19_adpcm_device::write_h)
+{
+ LOG_MMC(("jf19 + ADPCM write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ if (BIT(data, 7))
+ prg16_cdef(data & 0x0f);
+ if (BIT(data, 6))
+ chr8(data & 0x0f, CHRROM);
+ if (BIT(data, 5) && !BIT(data,4))
+ {
+// printf("sample write: offset: %04x, data: %02x\n", offset, data);
+ m_samples->start(offset & 0x1f, offset & 0x1f);
+ }
+}
+
+/*-------------------------------------------------
+
+ Jaleco SS88006 board emulation, aka JF-27, JF-29, JF-30, ...,
+ JF-38, JF-40, JF-41
+
+ Games: Lord of King, Magic John, Moe Pro '90, Ninja Jajamaru,
+ Pizza Pop, Plasma Ball
+
+ iNES: mapper 18
+
+ In MESS: Supported, see below for the games with samples
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+void nes_ss88006_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ /* Increment & check the IRQ scanline counter */
+ if (m_irq_enable)
+ {
+ LOG_MMC(("scanline: %d, irq count: %04x\n", scanline, m_irq_count));
+ if (m_irq_mode & 0x08)
+ {
+ if ((m_irq_count & 0x000f) < 114) // always true, but we only update the IRQ once per scanlines so we cannot be more precise :(
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_count = (m_irq_count & ~0x000f) | (0x0f - (114 & 0x0f) + (m_irq_count & 0x000f)); // sort of wrap around the counter
+ }
+ // decrements should not affect upper bits, so we don't do anything here (114 > 0x0f)
+ }
+ else if (m_irq_mode & 0x04)
+ {
+ if ((m_irq_count & 0x00ff) < 114)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_count = (m_irq_count & ~0x00ff) | (0xff - 114 + (m_irq_count & 0x00ff)); // wrap around the 8 bits counter
+ }
+ else
+ m_irq_count -= 114;
+ }
+ else if (m_irq_mode & 0x02)
+ {
+ if ((m_irq_count & 0x0fff) < 114)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_count = (m_irq_count & ~0x0fff) | (0xfff - 114 + (m_irq_count & 0x0fff)); // wrap around the 12 bits counter
+ }
+ else
+ m_irq_count -= 114;
+ }
+ else if (m_irq_count < 114)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_count = (0xffff - 114 + m_irq_count); // wrap around the 16 bits counter
+ }
+ else
+ m_irq_count -= 114;
+ }
+}
+
+WRITE8_MEMBER(nes_ss88006_device::ss88006_write)
+{
+ UINT8 bank;
+ LOG_MMC(("ss88006 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0xf0) | (data & 0x0f);
+ prg8_89(m_mmc_prg_bank[0]);
+ break;
+ case 0x0001:
+ m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0x0f) | (data << 4);
+ prg8_89(m_mmc_prg_bank[0]);
+ break;
+ case 0x0002:
+ m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0xf0) | (data & 0x0f);
+ prg8_ab(m_mmc_prg_bank[1]);
+ break;
+ case 0x0003:
+ m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0x0f) | (data << 4);
+ prg8_ab(m_mmc_prg_bank[1]);
+ break;
+ case 0x1000:
+ m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0xf0) | (data & 0x0f);
+ prg8_cd(m_mmc_prg_bank[2]);
+ break;
+ case 0x1001:
+ m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0x0f) | (data << 4);
+ prg8_cd(m_mmc_prg_bank[2]);
+ break;
+
+ /* $9002, 3 (1002, 3) uncaught = Jaleco Baseball writes 0 */
+ /* believe it's related to battery-backed ram enable/disable */
+
+ case 0x2000: case 0x2001: case 0x2002: case 0x2003:
+ case 0x3000: case 0x3001: case 0x3002: case 0x3003:
+ case 0x4000: case 0x4001: case 0x4002: case 0x4003:
+ case 0x5000: case 0x5001: case 0x5002: case 0x5003:
+ bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0002) >> 1);
+ if (offset & 0x0001)
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f)<< 4);
+ else
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+
+ case 0x6000:
+ m_irq_count_latch = (m_irq_count_latch & 0xfff0) | (data & 0x0f);
+ break;
+ case 0x6001:
+ m_irq_count_latch = (m_irq_count_latch & 0xff0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x6002:
+ m_irq_count_latch = (m_irq_count_latch & 0xf0ff) | ((data & 0x0f) << 8);
+ break;
+ case 0x6003:
+ m_irq_count_latch = (m_irq_count_latch & 0x0fff) | ((data & 0x0f) << 12);
+ break;
+
+ case 0x7000:
+ m_irq_count = m_irq_count_latch;
+ break;
+ case 0x7001:
+ m_irq_enable = data & 0x01;
+ m_irq_mode = data & 0x0e;
+ break;
+
+ case 0x7002:
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+
+ default:
+ logerror("Jaleco SS88006 uncaught write, addr: %04x, value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+
+// bits2-bits6 are sample number, bit1 is setup/enable/disable
+// program first write sample # + bit1 set to 'init' the sample
+// then it writes sample # + bit1 clear to 'start' the sample
+void nes_ss88006_adpcm_device::ss88006_adpcm_write(address_space &space, offs_t offset, UINT8 data, samples_device *dev)
+{
+ LOG_MMC(("ss88006 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x7003:
+ if ((m_latch & 0x7c) == (data & 0x7c))
+ {
+// printf("sample write: data: %02x\n", data);
+ if ((m_latch & 2) && !(data & 2))
+ dev->start((data >> 2) & 0x1f, (data >> 2) & 0x1f);
+ }
+ m_latch = data;
+ break;
+
+ default:
+ ss88006_write(space, offset, data);
+ break;
+ }
+}
+
+/**********************************************************
+
+ Boards with external samples
+ (due to undumpable UPD7755C/UPD7756C)
+
+ JF-13 (Moero!! Pro Yakyuu) / iNES mapper 86
+ JF-17 (Moero!! Pro Tennis) / iNES mapper 72 + ADPCM
+ JF-19 (Moero!! Pro Yakyuu '88 - Kettei Ban) / iNES mapper 92 + ADPCM
+ JF-23 (Shin Moero Pro Yakyuu) / iNES mapper 18 + ADPCM
+ JF-24 (Terao no Dosukoi Oozumou) / iNES mapper 18 + ADPCM
+ JF-29 (Moe Pro 90) / iNES mapper 18 + ADPCM
+ JF-33 (Moe Pro Saikyou-hen) / iNES mapper 18 + ADPCM
+
+
+***********************************************************/
+
+static const char *const jf13_sample_names[] =
+{
+ "*moepro",
+ "00", // strike
+ "01", // ball
+ "02", // time
+ "03", // out
+ "04", // safe
+ "05", // foul
+ "06", // (catcher obtains the ball)
+ "07", // you're out
+ "08", // play ball
+ "09", // ball four
+ "10", // home run
+ "11", // new pitcher
+ "12", // ouch (pitcher hits batter)
+ "13", // ??
+ "14", // (bat hits the ball)
+ "15", // (crowd)
+ 0
+};
+
+static const char *const jf17_sample_names[] =
+{
+ "*mptennis",
+ "00", // NOT EXISTING?
+ "01", // NOT EXISTING?
+ "02", // "love" (points)
+ "03", // 15 (points)
+ "04", // 30 (points)
+ "05", // 40 (points)
+ "06", // advantage
+ "07", // (advantage) server
+ "08", // (advantage) receiver
+ "09", // all (equal points)
+ "10", // deuce
+ "11", // game
+ "12", // (racket hits ball)
+ "13", // (crowd?)
+ "14", // fault
+ "15", // net
+ "16", // out
+ "17", // ??
+ "18", // (ball hits player)
+ "19", // NOT EXISTING?
+ 0
+};
+
+static const char *const jf19_sample_names[] =
+{
+ "*moepro88",
+ "00", // out
+ "01", // safe
+ "02", // foul
+ "03", // fair
+ "04", // strike
+ "05", // ball
+ "06", // time
+ "07", // batter out
+ "08", // ball four
+ "09", // home run
+ "10", // play ball
+ "11", // new pitcher
+ "12", // pinch-hit
+ "13", // (hit by pitch)
+ "14", // (bat hits the ball)
+ "15", // (bunt)
+ "16", // NOT EXISTING?
+ "17", // (catcher obtains the ball)
+ "18", // (pitcher obtains the ball)
+ "19", // (crowd)
+ 0
+};
+
+static const char *const jf23_sample_names[] =
+{
+ "*smoepro",
+ "00", // out
+ "01", // safe
+ "02", // foul
+ "03", // NOT EXISTING?
+ "04", // strike
+ "05", // ball
+ "06", // time
+ "07", // batter out
+ "08", // ball four
+ "09", // home run
+ "10", // play ball
+ "11", // new pitcher
+ "12", // pinch-hit
+ "13", // (hit by pitch)
+ "14", // (bat hits the ball)
+ "15", // (bunt)
+ "16", // (catcher obtains the ball)
+ "17", // fair
+ "18", // (catcher obtains the ball, alt)
+ "19", // (crowd)
+ 0
+};
+
+static const char *const jf24_sample_names[] =
+{
+ "*terao",
+ "00", // (tree beating sound)
+ "01", // Hakkyoyoi
+ "02", // Nokotta
+ "03", // Matta Nashi
+ "04", // Nokotta Nokotta
+ "05", // Matta Arimasen
+ 0
+};
+
+static const char *const jf29_sample_names[] =
+{
+ "*moepro90",
+ "00", // out
+ "01", // safe
+ "02", // foul
+ "03", // Not existing?
+ "04", // strike
+ "05", // ball
+ "06", // time
+ "07", // batter out
+ "08", // ball four
+ "09", // home run
+ "10", // play ball
+ "11", // new pitcher
+ "12", // pinch-hit
+ "13", // (hit by pitch)
+ "14", // (bat hits the ball)
+ "15", // (bunt)
+ "16", // (catcher obtains the ball, alt)
+ "17", // (catcher obtains the ball)
+ "18", // (catcher obtains the ball, alt 2)
+ "19", // (crowd)
+ 0
+};
+
+static const char *const jf33_sample_names[] =
+{
+ "*mpsaikyo",
+ "00", // out
+ "01", // safe
+ "02", // foul
+ "03", // ???
+ "04", // strike
+ "05", // ball
+ "06", // time
+ "07", // batter out
+ "08", // ball four
+ "09", // home run
+ "10", // play ball
+ "11", // new pitcher
+ "12", // pinch-hit
+ "13", // (hit by pitch)
+ "14", // (bat hits the ball)
+ "15", // (bunt)
+ "16", // (catcher obtains the ball)
+ "17", // (catcher obtains the ball, alt)
+ "18", // ??
+ "19", // (crowd)
+ 0
+};
+
+static const samples_interface jf13_samples_interface =
+{
+ 16, /* channels */
+ jf13_sample_names
+};
+
+static const samples_interface jf17_samples_interface =
+{
+ 20, /* channels */
+ jf17_sample_names
+};
+
+static const samples_interface jf19_samples_interface =
+{
+ 20, /* channels */
+ jf19_sample_names
+};
+
+static const samples_interface jf23_samples_interface =
+{
+ 20, /* channels */
+ jf23_sample_names
+};
+
+static const samples_interface jf24_samples_interface =
+{
+ 6, /* channels */
+ jf24_sample_names
+};
+
+static const samples_interface jf29_samples_interface =
+{
+ 20, /* channels */
+ jf29_sample_names
+};
+
+static const samples_interface jf33_samples_interface =
+{
+ 20, /* channels */
+ jf33_sample_names
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( jf13 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SAMPLES_ADD("samples", jf13_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( jf17 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SAMPLES_ADD("samples", jf17_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( jf19 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SAMPLES_ADD("samples", jf19_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( jf23 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SAMPLES_ADD("samples", jf23_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( jf24 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SAMPLES_ADD("samples", jf24_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( jf29 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SAMPLES_ADD("samples", jf29_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( jf33 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SAMPLES_ADD("samples", jf33_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions
+//-------------------------------------------------
+
+machine_config_constructor nes_jf13_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( jf13 );
+}
+
+machine_config_constructor nes_jf17_adpcm_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( jf17 );
+}
+
+machine_config_constructor nes_jf19_adpcm_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( jf19 );
+}
+
+machine_config_constructor nes_jf23_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( jf23 );
+}
+
+machine_config_constructor nes_jf24_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( jf24 );
+}
+
+machine_config_constructor nes_jf29_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( jf29 );
+}
+
+machine_config_constructor nes_jf33_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( jf33 );
+}
diff --git a/src/mess/machine/nes_jaleco.h b/src/mess/machine/nes_jaleco.h
new file mode 100644
index 00000000000..fc348f55dbf
--- /dev/null
+++ b/src/mess/machine/nes_jaleco.h
@@ -0,0 +1,251 @@
+#ifndef __NES_JALECO_H
+#define __NES_JALECO_H
+
+#include "machine/nes_nxrom.h"
+#include "sound/samples.h"
+
+
+// ======================> nes_jf11_device
+
+class nes_jf11_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_jf11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_jf13_device
+
+class nes_jf13_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_jf13_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ required_device<samples_device> m_samples;
+};
+
+
+// ======================> nes_jf16_device
+
+class nes_jf16_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_jf16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_jf17_device
+
+class nes_jf17_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_jf17_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);
+ nes_jf17_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_jf17_adpcm_device
+
+class nes_jf17_adpcm_device : public nes_jf17_device
+{
+public:
+ // construction/destruction
+ nes_jf17_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+private:
+ required_device<samples_device> m_samples;
+};
+
+
+// ======================> nes_jf19_device
+
+class nes_jf19_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_jf19_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);
+ nes_jf19_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_jf19_adpcm_device
+
+class nes_jf19_adpcm_device : public nes_jf19_device
+{
+public:
+ // construction/destruction
+ nes_jf19_adpcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+private:
+ required_device<samples_device> m_samples;
+};
+
+
+// ======================> nes_ss88006_device
+
+class nes_ss88006_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ss88006_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);
+ nes_ss88006_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(ss88006_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_write(space, offset, data, mem_mask); }
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ UINT16 m_irq_count, m_irq_count_latch;
+ UINT8 m_irq_mode;
+ int m_irq_enable;
+
+ UINT8 m_mmc_prg_bank[3];
+ UINT8 m_mmc_vrom_bank[8];
+
+ UINT8 m_latch; // used for samples, in derived classes
+};
+
+
+// ======================> nes_ss88006_adpcm_device
+
+class nes_ss88006_adpcm_device : public nes_ss88006_device
+{
+public:
+ // construction/destruction
+ nes_ss88006_adpcm_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
+ void ss88006_adpcm_write(address_space &space, offs_t offset, UINT8 data, samples_device *dev);
+};
+
+
+// ======================> nes_jf23_device
+
+class nes_jf23_device : public nes_ss88006_adpcm_device
+{
+public:
+ // construction/destruction
+ nes_jf23_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+ required_device<samples_device> m_samples;
+ virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_adpcm_write(space, offset, data, m_samples); }
+};
+
+
+// ======================> nes_jf24_device
+
+class nes_jf24_device : public nes_ss88006_adpcm_device
+{
+public:
+ // construction/destruction
+ nes_jf24_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+ required_device<samples_device> m_samples;
+ virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_adpcm_write(space, offset, data, m_samples); }
+};
+
+
+// ======================> nes_jf29_device
+
+class nes_jf29_device : public nes_ss88006_adpcm_device
+{
+public:
+ // construction/destruction
+ nes_jf29_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+ required_device<samples_device> m_samples;
+ virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_adpcm_write(space, offset, data, m_samples); }
+};
+
+
+// ======================> nes_jf33_device
+
+class nes_jf33_device : public nes_ss88006_adpcm_device
+{
+public:
+ // construction/destruction
+ nes_jf33_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+ required_device<samples_device> m_samples;
+ virtual DECLARE_WRITE8_MEMBER(write_h) { ss88006_adpcm_write(space, offset, data, m_samples); }
+};
+
+
+
+
+// device type definition
+extern const device_type NES_JF11;
+extern const device_type NES_JF13;
+extern const device_type NES_JF16;
+extern const device_type NES_JF17;
+extern const device_type NES_JF17_ADPCM;
+extern const device_type NES_JF19;
+extern const device_type NES_JF19_ADPCM;
+extern const device_type NES_SS88006;
+extern const device_type NES_JF23;
+extern const device_type NES_JF24;
+extern const device_type NES_JF29;
+extern const device_type NES_JF33;
+
+#endif
diff --git a/src/mess/machine/nes_jy.c b/src/mess/machine/nes_jy.c
new file mode 100644
index 00000000000..3568c650559
--- /dev/null
+++ b/src/mess/machine/nes_jy.c
@@ -0,0 +1,581 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for JY Company
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate multiple PCBs by JY Company with weird IRQ mechanisms [mappers 90, 209, 211]
+
+ TODO: long list...
+ - add dipswitches
+ - revamp IRQ system
+ * scanline/hblank irq should fire 8 times per line (currently not possible)
+ * implement CPU write IRQ (used by any games?)
+ * possibly implementing 'funky' IRQ mode (unused?)
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_jy.h"
+
+#include "cpu/m6502/m6502.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_JY_TYPEA = &device_creator<nes_jy_typea_device>;
+const device_type NES_JY_TYPEB = &device_creator<nes_jy_typeb_device>;
+const device_type NES_JY_TYPEC = &device_creator<nes_jy_typec_device>;
+
+
+nes_jy_typea_device::nes_jy_typea_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_jy_typea_device::nes_jy_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_JY_TYPEA, "NES Cart JY Company Type A PCB", tag, owner, clock, "nes_jya", __FILE__)
+{
+}
+
+nes_jy_typeb_device::nes_jy_typeb_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)
+ : nes_jy_typea_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_jy_typeb_device::nes_jy_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_jy_typea_device(mconfig, NES_JY_TYPEB, "NES Cart JY Company Type B PCB", tag, owner, clock, "nes_jyb", __FILE__)
+{
+}
+
+nes_jy_typec_device::nes_jy_typec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_jy_typeb_device(mconfig, NES_JY_TYPEC, "NES Cart JY Company Type C PCB", tag, owner, clock, "nes_jyc", __FILE__)
+{
+}
+
+
+
+
+void nes_jy_typea_device::device_start()
+{
+ common_start();
+ irq_timer = timer_alloc(TIMER_IRQ);
+ irq_timer->reset();
+
+ save_item(NAME(m_mul));
+ save_item(NAME(m_latch));
+ save_item(NAME(m_mmc_prg_bank));
+ save_item(NAME(m_mmc_nt_bank));
+ save_item(NAME(m_mmc_vrom_bank));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_chr_latch));
+ save_item(NAME(m_extra_chr_bank));
+ save_item(NAME(m_extra_chr_mask));
+ save_item(NAME(m_bank_6000));
+
+ save_item(NAME(m_irq_prescale));
+ save_item(NAME(m_irq_prescale_mask));
+ save_item(NAME(m_irq_mode));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_flip));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_up));
+ save_item(NAME(m_irq_down));
+}
+
+void nes_jy_typea_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ // 0x5000-0x5fff
+ m_mul[0] = 0;
+ m_mul[1] = 0;
+ m_latch = 0;
+
+ // 0x8000-0xffff
+ memset(m_mmc_prg_bank, 0xff, sizeof(m_mmc_prg_bank));
+ memset(m_mmc_nt_bank, 0, sizeof(m_mmc_nt_bank));
+ memset(m_mmc_vrom_bank, 0xffff, sizeof(m_mmc_vrom_bank));
+ memset(m_reg, 0, sizeof(m_reg));
+ m_chr_latch[0] = 0;
+ m_chr_latch[1] = 4;
+ m_extra_chr_bank = 0;
+ m_extra_chr_mask = 0;
+ m_bank_6000 = 0;
+
+ update_prg();
+ update_extra_chr();
+ update_chr();
+ update_mirror();
+
+ m_irq_mode = 0;
+ m_irq_count = 0;
+ m_irq_prescale = 0;
+ m_irq_prescale_mask = 0xff;
+ m_irq_flip = 0;
+ m_irq_enable = 0;
+ m_irq_up = 0;
+ m_irq_down = 0;
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ JY Company Type A board emulation
+
+ iNES: mapper 90
+
+ -------------------------------------------------*/
+
+void nes_jy_typea_device::update_chr_latches()
+{
+ update_extra_chr();
+ chr4_0((m_mmc_vrom_bank[m_chr_latch[0]] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr4_4((m_mmc_vrom_bank[m_chr_latch[1]] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+}
+
+READ8_MEMBER(nes_jy_typea_device::chr_r)
+{
+ int bank = offset >> 10;
+ UINT8 val = m_chr_access[bank][offset & 0x3ff]; // this would be usual return value
+
+ switch (offset & 0xff8)
+ {
+ case 0xfd0:
+ case 0xfe8:
+// m_chr_latch[BIT(offset, 12)] = ((bank & 0x4) | 0x2) & (offset >> 4);
+ break;
+ }
+
+ if ((m_reg[0] & 0x18) == 0x08) // 4KB mode is the only one using these latches!
+ update_chr_latches();
+
+ return val;
+}
+
+void nes_jy_typea_device::irq_clock(int mode, int blanked)
+{
+ bool clock = FALSE, fire = FALSE;
+
+ if (m_irq_mode != mode)
+ return;
+
+ // no counter changes if both Up/Down are set or clear
+ if ((m_irq_down && m_irq_up) || (!m_irq_down && !m_irq_down))
+ return;
+
+ // update prescaler
+ if (m_irq_down)
+ {
+ if ((m_irq_prescale & m_irq_prescale_mask) == 0)
+ {
+ clock = TRUE;
+ m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | 7) : 0xff;
+ }
+ else
+ m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | ((m_irq_prescale - 1) & m_irq_prescale_mask)) : (m_irq_prescale - 1);
+ }
+
+ if (m_irq_up)
+ {
+ if ((m_irq_prescale & m_irq_prescale_mask) == m_irq_prescale)
+ {
+ clock = TRUE;
+ m_irq_prescale = (m_irq_prescale_mask == 7) ? (m_irq_prescale & 0xf8) : 0;
+ }
+ else
+ m_irq_prescale = (m_irq_prescale_mask == 7) ? ((m_irq_prescale & 0xf8) | ((m_irq_prescale + 1) & m_irq_prescale_mask)) : (m_irq_prescale + 1);
+ }
+
+ // if prescaler wraps, update count
+ if (clock)
+ {
+ if (m_irq_down)
+ {
+ if (m_irq_count == 0)
+ {
+ fire = TRUE;
+ m_irq_count = 0xff;
+ }
+ else
+ m_irq_count--;
+ }
+
+ if (m_irq_up)
+ {
+ if (m_irq_count == 0xff)
+ {
+ fire = TRUE;
+ m_irq_count = 0;
+ }
+ else
+ m_irq_count++;
+ }
+
+
+ // if count wraps, check if IRQ is enabled
+ if (fire && m_irq_enable && !blanked)
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+
+ }
+}
+
+void nes_jy_typea_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_IRQ)
+ {
+ irq_clock(0, 0);
+ }
+}
+
+void nes_jy_typea_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ irq_clock(blanked, 2);
+}
+
+void nes_jy_typea_device::scanline_irq(int scanline, int vblank, int blanked)
+{
+ irq_clock(blanked, 1);
+}
+
+
+// 0x5000-0x5fff : sort of protection?
+READ8_MEMBER(nes_jy_typea_device::read_l)
+{
+ LOG_MMC(("JY Company write_m, offset: %04x\n", offset));
+ offset += 0x100;
+
+ if (offset >= 0x1000 && offset < 0x1800)
+ {
+ // DSW read
+ }
+ if (offset >= 0x1800)
+ {
+ if ((offset & 3) & 3 == 0)
+ return (m_mul[0] * m_mul[1]) & 0xff;
+ if ((offset & 3) & 3 == 1)
+ return ((m_mul[0] * m_mul[1]) >> 8) & 0xff;
+ if ((offset & 3) & 3 == 3)
+ return m_latch;
+ }
+ return ((offset + 0x4000) & 0xff00) >> 8; // open bus
+}
+
+WRITE8_MEMBER(nes_jy_typea_device::write_l)
+{
+ LOG_MMC(("JY Company write_m, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x1800)
+ {
+ if ((offset & 3) == 0)
+ m_mul[0] = data;
+ if ((offset & 3) & 3 == 1)
+ m_mul[1] = data;
+ if ((offset & 3) & 3 == 3)
+ m_latch = data;
+ }
+}
+
+// 0x6000-0x7fff : WRAM or open bus
+READ8_MEMBER(nes_jy_typea_device::read_m)
+{
+ LOG_MMC(("JY Company write_m, offset: %04x\n", offset));
+
+ if (m_reg[0] & 0x80)
+ return m_prg[(m_bank_6000 & m_prg_mask) * 0x2000 + (offset & 0x1fff)];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+
+inline UINT8 nes_jy_typea_device::unscramble(UINT8 bank)
+{
+ return BITSWAP8(bank & 0x7f,7,0,1,2,3,4,5,6);
+}
+
+void nes_jy_typea_device::update_prg()
+{
+ UINT8 exPrg = (m_reg[3] & 0x06) << 5;
+ UINT8 last = (m_reg[0] & 0x04) ? m_mmc_prg_bank[3] : 0x3f;
+
+ switch (m_reg[0] & 0x03)
+ {
+ case 0: // 32KB
+ prg32((last & 0xF) | (exPrg >> 2));
+ m_bank_6000 = (((m_mmc_prg_bank[3] * 4) + 3) & 0x3f) | (exPrg >> 2);
+ break;
+
+ case 1: // 16KB
+ prg16_89ab((m_mmc_prg_bank[1] & 0x1f) | (exPrg >> 1));
+ prg16_cdef((last & 0x1f) | (exPrg >> 1));
+ m_bank_6000 = (((m_mmc_prg_bank[3] * 2) + 1) & 0x3f) | (exPrg >> 1);
+ break;
+
+ case 2: // 8KB
+ prg8_89((m_mmc_prg_bank[0] & 0x3f) | exPrg);
+ prg8_ab((m_mmc_prg_bank[1] & 0x3f) | exPrg);
+ prg8_cd((m_mmc_prg_bank[2] & 0x3f) | exPrg);
+ prg8_ef((last & 0x3f) | exPrg);
+ m_bank_6000 = (m_mmc_prg_bank[3] & 0x3f) | exPrg;
+ break;
+
+ case 3: // 8KB Alt
+ prg8_89((unscramble(m_mmc_prg_bank[0]) & 0x3f) | exPrg);
+ prg8_ab((unscramble(m_mmc_prg_bank[1]) & 0x3f) | exPrg);
+ prg8_cd((unscramble(m_mmc_prg_bank[2]) & 0x3f) | exPrg);
+ prg8_ef((unscramble(last) & 0x3f) | exPrg);
+ m_bank_6000 = (unscramble(m_mmc_prg_bank[3]) & 0x3f) | exPrg;
+ break;
+ }
+}
+
+void nes_jy_typea_device::update_extra_chr()
+{
+ if (m_reg[3] & 0x20)
+ {
+ //Block mode disabled
+ m_extra_chr_mask = 0xffff;
+ m_extra_chr_bank = 0;
+ }
+ else
+ {
+ // Block mode enabled: in this case lower bits select a 256KB page inside CHRROM
+ // and the low bytes of m_mmc_vrom_bank select the banks inside such a page
+ int mode = (m_reg[0] & 0x18) >> 3;
+ m_extra_chr_mask = 0x00ff >> (mode ^ 0x3);
+ m_extra_chr_bank = ((m_reg[3] & 1) | ((m_reg[3] & 0x18) >> 2)) << (mode + 5);
+ }
+}
+
+void nes_jy_typea_device::update_chr()
+{
+ UINT8 chr_mirror_mode = BIT(m_reg[3], 7) << 1; // in 1KB & 2KB mode, PPU 0x800-0xfff always mirrors 0x000-0x7ff (0x1800-0x1fff not affected)
+
+ switch (m_reg[0] & 0x18)
+ {
+ case 0x00: // 8KB
+ chr8((m_mmc_vrom_bank[0] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ break;
+
+ case 0x08: // 4KB
+// chr4_0((m_mmc_vrom_bank[m_chr_latch[0]] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+// chr4_4((m_mmc_vrom_bank[m_chr_latch[1]] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ update_chr_latches();
+ break;
+
+ case 0x10: // 2KB
+ chr2_0((m_mmc_vrom_bank[0] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr2_2((m_mmc_vrom_bank[2 ^ chr_mirror_mode] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr2_4((m_mmc_vrom_bank[4] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr2_6((m_mmc_vrom_bank[6] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ break;
+
+ case 0x18: // 1KB
+ chr1_0((m_mmc_vrom_bank[0] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr1_0((m_mmc_vrom_bank[1] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr1_0((m_mmc_vrom_bank[2 ^ chr_mirror_mode] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr1_0((m_mmc_vrom_bank[3 ^ chr_mirror_mode] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr1_0((m_mmc_vrom_bank[4] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr1_0((m_mmc_vrom_bank[5] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr1_0((m_mmc_vrom_bank[6] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ chr1_0((m_mmc_vrom_bank[7] & m_extra_chr_mask) | m_extra_chr_bank, m_chr_source);
+ break;
+ }
+}
+
+void nes_jy_typea_device::update_mirror_typea()
+{
+ switch (m_reg[1] & 3)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+}
+
+void nes_jy_typea_device::update_banks(int reg)
+{
+ switch (reg & 3)
+ {
+ case 0:
+ update_prg();
+ update_extra_chr();
+ update_chr();
+ update_mirror();
+ break;
+ case 1:
+ update_mirror();
+ break;
+ case 2:
+ update_mirror();
+ break;
+ case 3:
+ update_prg();
+ update_extra_chr();
+ update_chr();
+ break;
+ }
+}
+
+
+WRITE8_MEMBER(nes_jy_typea_device::write_h)
+{
+ LOG_MMC(("JY Company write_m, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ offset &= 3;
+ data &= 0x3f;
+ if (m_mmc_prg_bank[offset] != data)
+ {
+ m_mmc_prg_bank[offset] = data;
+ update_prg();
+ }
+ break;
+ case 0x1000:
+ offset &= 7;
+ if ((m_mmc_vrom_bank[offset] & 0xff) != data)
+ {
+ m_mmc_vrom_bank[offset] = (m_mmc_vrom_bank[offset] & 0xff00) | data;
+ update_extra_chr();
+ update_chr();
+ }
+ break;
+ case 0x2000:
+ offset &= 7;
+ if ((m_mmc_vrom_bank[offset] & 0xff00) != (data << 8))
+ {
+ m_mmc_vrom_bank[offset] = (m_mmc_vrom_bank[offset] & 0x00ff) | (data << 8);
+ update_extra_chr();
+ update_chr();
+ }
+ break;
+ case 0x3000:
+ if ((offset & 7) < 4)
+ {
+ offset &= 3;
+ m_mmc_nt_bank[offset] = (m_mmc_nt_bank[offset] & 0xff00) | data;
+ update_mirror();
+ }
+ else
+ {
+ offset &= 3;
+ m_mmc_nt_bank[offset] = (m_mmc_nt_bank[offset] & 0x00ff) | data << 8;
+ update_mirror();
+ }
+ break;
+ case 0x4000:
+ switch (offset & 7)
+ {
+ case 0:
+ m_irq_enable = BIT(data, 0);
+ break;
+ case 1:
+ m_irq_mode = data & 3;
+ m_irq_prescale_mask = (data & 4) ? 0x07 : 0xff;
+ m_irq_down = data & 0x80;
+ m_irq_up = data & 0x40;
+ if (m_irq_mode == 0)
+ irq_timer->adjust(attotime::zero, 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(1));
+ else
+ irq_timer->adjust(attotime::never);
+ break;
+ case 2:
+ m_irq_enable = 0;
+ break;
+ case 3:
+ m_irq_enable = 1;
+ break;
+ case 4:
+ m_irq_prescale = data ^ m_irq_flip;
+ break;
+ case 5:
+ m_irq_count = data ^ m_irq_flip;
+ break;
+ case 6:
+ m_irq_flip = data;
+ break;
+ case 7:
+ // this is used for the 'funky' IRQ mode, not implemented yet
+ break;
+ }
+ break;
+ case 0x5000:
+ if (m_reg[offset & 3] != data)
+ {
+ m_reg[offset & 3] = data;
+ update_banks(offset & 3);
+ }
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ JY Company Type B board emulation
+
+ iNES: mapper 211
+
+ The mirroring system is a lot more complex in this
+ board
+
+ -------------------------------------------------*/
+
+void nes_jy_typeb_device::update_mirror_typeb()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ if (m_reg[0] & 0x40) // CHRROM
+ set_nt_page(i, VROM, m_mmc_nt_bank[i], 0);
+ else // might be either CHRROM or CIRAM
+ {
+ // CHRROM is only used if bit 7 of the NT Reg does not match bit7 of reg[2].
+ if ((m_mmc_nt_bank[i] ^ m_reg[2]) & 0x80)
+ set_nt_page(i, VROM, m_mmc_nt_bank[i], 0);
+ else
+ set_nt_page(i, CIRAM, m_mmc_nt_bank[i] & 1, 1);
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ JY Company Type C board emulation
+
+ iNES: mapper 209
+
+ These board can switch between the Type A and the
+ Type B mirroring
+
+ -------------------------------------------------*/
+
+void nes_jy_typec_device::update_mirror_typec()
+{
+ if (BIT(m_reg[0], 5))
+ update_mirror_typeb();
+ else
+ update_mirror_typea();
+}
diff --git a/src/mess/machine/nes_jy.h b/src/mess/machine/nes_jy.h
new file mode 100644
index 00000000000..6014723b1d5
--- /dev/null
+++ b/src/mess/machine/nes_jy.h
@@ -0,0 +1,100 @@
+#ifndef __NES_JY_H
+#define __NES_JY_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_jy_typea_device
+
+class nes_jy_typea_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_jy_typea_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);
+ nes_jy_typea_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual DECLARE_READ8_MEMBER(chr_r);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void scanline_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ void irq_clock(int blanked, int mode);
+ void update_banks(int reg);
+ void update_prg();
+ void update_chr();
+ void update_chr_latches(); // 4KB mode updates in a more complicate way...
+ void update_extra_chr();
+ void update_mirror_typea();
+ virtual void update_mirror() { update_mirror_typea(); }
+ inline UINT8 unscramble(UINT8 bank);
+
+ UINT8 m_mul[2];
+ UINT8 m_latch;
+ UINT8 m_reg[4];
+ UINT8 m_chr_latch[2];
+ UINT8 m_mmc_prg_bank[4];
+ UINT16 m_mmc_nt_bank[4];
+ UINT16 m_mmc_vrom_bank[8];
+ UINT16 m_extra_chr_bank;
+ UINT16 m_extra_chr_mask;
+ int m_bank_6000;
+
+ UINT8 m_irq_mode;
+ UINT8 m_irq_count;
+ UINT8 m_irq_prescale;
+ UINT8 m_irq_prescale_mask;
+ UINT8 m_irq_flip;
+ int m_irq_enable;
+ int m_irq_up, m_irq_down;
+
+ static const device_timer_id TIMER_IRQ = 0;
+ emu_timer *irq_timer;
+};
+
+
+// ======================> nes_jy_typeb_device
+
+class nes_jy_typeb_device : public nes_jy_typea_device
+{
+public:
+ // construction/destruction
+ nes_jy_typeb_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);
+ nes_jy_typeb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ void update_mirror_typeb();
+ virtual void update_mirror() { update_mirror_typeb(); }
+};
+
+// ======================> nes_jy_typec_device
+
+class nes_jy_typec_device : public nes_jy_typeb_device
+{
+public:
+ // construction/destruction
+ nes_jy_typec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ void update_mirror_typec();
+ virtual void update_mirror() { update_mirror_typeb(); }
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_JY_TYPEA;
+extern const device_type NES_JY_TYPEB;
+extern const device_type NES_JY_TYPEC;
+
+#endif
diff --git a/src/mess/machine/nes_kaiser.c b/src/mess/machine/nes_kaiser.c
new file mode 100644
index 00000000000..75c870749c7
--- /dev/null
+++ b/src/mess/machine/nes_kaiser.c
@@ -0,0 +1,501 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Kaiser PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following Kaiser bootleg PCBs
+
+ * Kaiser KS202
+ * Kaiser KS7012
+ * Kaiser KS7013B
+ * Kaiser KS7017
+ * Kaiser KS7022
+ * Kaiser KS7032
+ * Kaiser KS7058
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_kaiser.h"
+
+#include "cpu/m6502/m6502.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_KS7058 = &device_creator<nes_ks7058_device>;
+const device_type NES_KS7022 = &device_creator<nes_ks7022_device>;
+const device_type NES_KS7032 = &device_creator<nes_ks7032_device>;
+const device_type NES_KS202 = &device_creator<nes_ks202_device>;
+const device_type NES_KS7017 = &device_creator<nes_ks7017_device>;
+const device_type NES_KS7012 = &device_creator<nes_ks7012_device>;
+const device_type NES_KS7013B = &device_creator<nes_ks7013b_device>;
+
+
+nes_ks7058_device::nes_ks7058_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_KS7058, "NES Cart Kaiser KS-7058 PCB", tag, owner, clock, "nes_ks7058", __FILE__)
+{
+}
+
+nes_ks7022_device::nes_ks7022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_KS7022, "NES Cart Kaiser KS-7022 PCB", tag, owner, clock, "nes_ks7022", __FILE__)
+{
+}
+
+nes_ks7032_device::nes_ks7032_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_ks7032_device::nes_ks7032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_KS7032, "NES Cart Kaiser KS-7032 PCB", tag, owner, clock, "nes_ks7032", __FILE__)
+{
+}
+
+nes_ks202_device::nes_ks202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_ks7032_device(mconfig, NES_KS202, "NES Cart Kaiser KS-202 PCB", tag, owner, clock, "nes_ks202", __FILE__)
+{
+}
+
+nes_ks7017_device::nes_ks7017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_KS7017, "NES Cart Kaiser KS-7017 PCB", tag, owner, clock, "nes_ks7017", __FILE__)
+{
+}
+
+nes_ks7012_device::nes_ks7012_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_KS7012, "NES Cart Kaiser KS-7012 PCB", tag, owner, clock, "nes_ks7012", __FILE__)
+{
+}
+
+nes_ks7013b_device::nes_ks7013b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_KS7013B, "NES Cart Kaiser KS-7013B PCB", tag, owner, clock, "nes_ks7013b", __FILE__)
+{
+}
+
+
+
+
+void nes_ks7058_device::device_start()
+{
+ common_start();
+}
+
+void nes_ks7058_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_ks7022_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_ks7022_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_ks7032_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_reg));
+}
+
+void nes_ks7032_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ memset(m_reg, 0, sizeof(m_reg));
+ prg_update();
+}
+
+void nes_ks7017_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_status));
+}
+
+void nes_ks7017_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ m_irq_status = 0;
+}
+
+void nes_ks7012_device::device_start()
+{
+ common_start();
+}
+
+void nes_ks7012_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0xff);
+ chr8(0, m_chr_source);
+}
+
+void nes_ks7013b_device::device_start()
+{
+ common_start();
+}
+
+void nes_ks7013b_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Kaiser Board KS7058
+
+ Games: Tui Do Woo Ma Jeung
+
+ Writes to 0xf000-0xffff set 4k chr banks. Namely, if
+ offset&0x80 is 0 the lower 4k are set, if it is 1 the
+ upper 4k are set.
+
+ iNES: mapper 171
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ks7058_device::write_h)
+{
+ LOG_MMC(("ks7058 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7080)
+ {
+ case 0x7000:
+ chr4_0(data, CHRROM);
+ break;
+ case 0x7080:
+ chr4_4(data, CHRROM);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Kaiser Board KS7022
+
+ Games: 15 in 1
+
+ iNES: mapper 175
+
+ In MESS: Supported?
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ks7022_device::write_h)
+{
+ LOG_MMC(("ks7022 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0)
+ set_nt_mirroring(BIT(data, 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (offset == 0x2000)
+ m_latch = data & 0x0f;
+}
+
+READ8_MEMBER(nes_ks7022_device::read_h)
+{
+ LOG_MMC(("ks7022 read_h, offset: %04x\n", offset));
+
+ if (offset == 0x7ffc)
+ {
+ chr8(m_latch, CHRROM);
+ prg16_89ab(m_latch);
+ prg16_cdef(m_latch);
+ }
+
+ return hi_access_rom(offset);
+}
+
+/*-------------------------------------------------
+
+ Kaiser Board KS7032
+
+ Games: A few FDS conversions like Bubble Bobble
+ or SMB2
+
+ iNES:
+
+ TODO: available dumps do not seem to use WRAM...
+ yet m_reg[4] should switch WRAM bank... investigate!
+
+ In MESS: Supported?
+
+ -------------------------------------------------*/
+
+void nes_ks7032_device::prg_update()
+{
+ prg8_89(m_reg[1]);
+ prg8_ab(m_reg[2]);
+ prg8_cd(m_reg[3]);
+}
+
+void nes_ks7032_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ if (m_irq_count >= (0xffff - 114))
+ {
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ m_irq_count += 114;
+ }
+}
+
+WRITE8_MEMBER(nes_ks7032_device::ks7032_write)
+{
+ LOG_MMC(("ks7032_write, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ m_irq_count = (m_irq_count & 0xfff0) | (data & 0x0f);
+ break;
+ case 0x1000:
+ m_irq_count = (m_irq_count & 0xff0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x2000:
+ m_irq_count = (m_irq_count & 0xf0ff) | ((data & 0x0f) << 8);
+ break;
+ case 0x3000:
+ m_irq_count = (m_irq_count & 0x0fff) | ((data & 0x0f) << 12);
+ break;
+ case 0x4000:
+ m_irq_enable = 1;
+ break;
+ case 0x6000:
+ m_latch = data & 0x07;
+ break;
+ case 0x7000:
+ m_reg[m_latch] = data;
+ prg_update();
+ break;
+ }
+}
+
+READ8_MEMBER(nes_ks7032_device::read_m)
+{
+ LOG_MMC(("ks7032 read_m, offset: %04x\n", offset));
+ return m_prg[((m_reg[4] * 0x2000) + (offset & 0x1fff)) & (m_prg_size - 1)];
+}
+
+/*-------------------------------------------------
+
+ Kaiser Board KS202
+
+ Games: Super Mario Bros. 3 (Pirate, Alt)
+
+ iNES:
+
+ In MESS: Supported?
+
+ -------------------------------------------------*/
+
+
+WRITE8_MEMBER(nes_ks202_device::write_h)
+{
+ LOG_MMC(("ks202 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x7000:
+ m_reg[m_latch] = data;
+ prg_update();
+ switch (offset & 0xc00)
+ {
+ case 0x800:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ break;
+ case 0xc00:
+ chr1_x(offset & 0x07, data, CHRROM);
+ break;
+ }
+ break;
+ default:
+ ks7032_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+READ8_MEMBER(nes_ks202_device::read_m)
+{
+ LOG_MMC(("ks202 read_m, offset: %04x\n", offset));
+ return m_prgram[offset & 0x1fff];
+}
+
+/*-------------------------------------------------
+
+ Kaiser Board KS7017
+
+ Games: Almana no Kiseki FDS conversion
+
+ iNES:
+
+ In MESS: Not working
+
+ -------------------------------------------------*/
+
+void nes_ks7017_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ if (m_irq_count <= 114)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_enable = 0;
+ m_irq_status |= 0x01;
+ }
+ else
+ m_irq_count -= 114;
+ }
+}
+
+WRITE8_MEMBER(nes_ks7017_device::write_l)
+{
+ LOG_MMC(("ks7017 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ offset += 0x100;
+
+ if (offset >= 0xa00 && offset < 0xb00)
+ m_latch = ((offset >> 2) & 0x03) | ((offset >> 4) & 0x04);
+
+ if (offset >= 0x1000 && offset < 0x1100)
+ prg16_89ab(m_latch);
+}
+
+WRITE8_MEMBER(nes_ks7017_device::write_ex)
+{
+ LOG_MMC(("ks7017 write_ex, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x20;
+
+ if (offset == 0x0020) /* 0x4020 */
+ m_irq_count = (m_irq_count & 0xff00) | data;
+
+ if (offset == 0x0021) /* 0x4021 */
+ m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
+
+ if (offset == 0x0025) /* 0x4025 */
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+READ8_MEMBER(nes_ks7017_device::read_ex)
+{
+ LOG_MMC(("ks7017 read_ex, offset: %04x\n", offset));
+ offset += 0x20;
+
+ if (offset == 0x0030) /* 0x4030 */
+ {
+ m_irq_status &= ~0x01;
+ return m_irq_status;
+ }
+
+ return 0xff;
+}
+
+/*-------------------------------------------------
+
+ Kaiser Board KS7012
+
+ Games: Zanac FDS Conversion
+
+ iNES:
+
+ In MESS: Not working
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ks7012_device::write_h)
+{
+ LOG_MMC(("ks7012 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x60a0)
+ prg32(0);
+ if (offset == 0x6e36)
+ prg32(1);
+}
+
+
+/*-------------------------------------------------
+
+ Kaiser Board KS7013B
+
+ Games: Highway Star FDS Conversion
+
+ iNES:
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ks7013b_device::write_m)
+{
+ LOG_MMC(("ks7013b write_l, offset: %04x, data: %02x\n", offset, data));
+ prg16_89ab(data);
+}
+
+WRITE8_MEMBER(nes_ks7013b_device::write_h)
+{
+ LOG_MMC(("ks7013b write_h, offset: %04x, data: %02x\n", offset, data));
+ set_nt_mirroring((data & 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
diff --git a/src/mess/machine/nes_kaiser.h b/src/mess/machine/nes_kaiser.h
new file mode 100644
index 00000000000..bf712bcb464
--- /dev/null
+++ b/src/mess/machine/nes_kaiser.h
@@ -0,0 +1,154 @@
+#ifndef __NES_KAISER_H
+#define __NES_KAISER_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_ks7058_device
+
+class nes_ks7058_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ks7058_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_ks7022_device
+
+class nes_ks7022_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ks7022_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_ks7032_device
+
+class nes_ks7032_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ks7032_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);
+ nes_ks7032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(ks7032_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { ks7032_write(space, offset, data, mem_mask); }
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ void prg_update();
+
+ UINT8 m_latch;
+ UINT8 m_reg[8];
+
+ UINT16 m_irq_count;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_ks202_device
+
+class nes_ks202_device : public nes_ks7032_device
+{
+public:
+ // construction/destruction
+ nes_ks202_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+};
+
+
+// ======================> nes_ks7017_device
+
+class nes_ks7017_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ks7017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_ex);
+ virtual DECLARE_WRITE8_MEMBER(write_ex);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+
+ UINT16 m_irq_count;
+ UINT8 m_irq_status;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_ks7012_device
+
+class nes_ks7012_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ks7012_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+// ======================> nes_ks7013b_device
+
+class nes_ks7013b_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ks7013b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+
+// device type definition
+extern const device_type NES_KS7058;
+extern const device_type NES_KS7022;
+extern const device_type NES_KS7032;
+extern const device_type NES_KS202;
+extern const device_type NES_KS7017;
+extern const device_type NES_KS7012;
+extern const device_type NES_KS7013B;
+
+#endif
diff --git a/src/mess/machine/nes_konami.c b/src/mess/machine/nes_konami.c
new file mode 100644
index 00000000000..04991bceaff
--- /dev/null
+++ b/src/mess/machine/nes_konami.c
@@ -0,0 +1,680 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Konami PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs (multiple mappers needed due to different wirings in the pcbs
+ causing different addresses to be used for bankswitch & irq)
+
+ * Konami VRC-1 [mapper 75]
+ * Konami VRC-2 [mapper 22,23,25]
+ * Konami VRC-3 [mapper 73]
+ * Konami VRC-4 [mapper 21,23,25]
+ * Konami VRC-6 [mapper 24,26]
+ * Konami VRC-7 [mapper 85]
+
+
+ TODO:
+ - improve IRQ (CPU mode not currently emulated)
+ - add VRC-6 sound features
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_konami.h"
+
+#include "cpu/m6502/m6502.h"
+#include "sound/2413intf.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_VRC1 = &device_creator<nes_konami_vrc1_device>;
+const device_type NES_VRC2 = &device_creator<nes_konami_vrc2_device>;
+const device_type NES_VRC3 = &device_creator<nes_konami_vrc3_device>;
+const device_type NES_VRC4 = &device_creator<nes_konami_vrc4_device>;
+const device_type NES_VRC6 = &device_creator<nes_konami_vrc6_device>;
+const device_type NES_VRC7 = &device_creator<nes_konami_vrc7_device>;
+
+
+nes_konami_vrc1_device::nes_konami_vrc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_VRC1, "NES Cart Konami VRC-1 PCB", tag, owner, clock, "nes_vrc1", __FILE__)
+{
+}
+
+nes_konami_vrc2_device::nes_konami_vrc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_VRC2, "NES Cart Konami VRC-2 PCB", tag, owner, clock, "nes_vrc2", __FILE__)
+{
+}
+
+nes_konami_vrc3_device::nes_konami_vrc3_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_konami_vrc3_device::nes_konami_vrc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_VRC3, "NES Cart Konami VRC-3 PCB", tag, owner, clock, "nes_vrc3", __FILE__)
+{
+}
+
+nes_konami_vrc4_device::nes_konami_vrc4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_konami_vrc3_device(mconfig, NES_VRC4, "NES Cart Konami VRC-4 PCB", tag, owner, clock, "nes_vrc4", __FILE__)
+{
+}
+
+nes_konami_vrc6_device::nes_konami_vrc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_konami_vrc3_device(mconfig, NES_VRC6, "NES Cart Konami VRC-6 PCB", tag, owner, clock, "nes_vrc6", __FILE__)
+{
+}
+
+nes_konami_vrc7_device::nes_konami_vrc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_konami_vrc3_device(mconfig, NES_VRC7, "NES Cart Konami VRC-7 PCB", tag, owner, clock, "nes_vrc7", __FILE__)
+{
+}
+
+
+
+void nes_konami_vrc1_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_konami_vrc1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+void nes_konami_vrc2_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_mmc_vrom_bank));
+ save_item(NAME(m_latch));
+}
+
+void nes_konami_vrc2_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+void nes_konami_vrc3_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_enable_latch));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+}
+
+void nes_konami_vrc3_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_enable_latch = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0;
+}
+
+
+void nes_konami_vrc4_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_mode));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_enable_latch));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+ save_item(NAME(m_latch));
+ save_item(NAME(m_mmc_prg_bank));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_konami_vrc4_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_mode = 0;
+ m_irq_enable = 0;
+ m_irq_enable_latch = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0;
+
+ m_latch = 0;
+ m_mmc_prg_bank = 0;
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+void nes_konami_vrc7_device::device_start()
+{
+ m_ym2413 = device().subdevice("ym");
+
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_enable_latch));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+}
+
+void nes_konami_vrc7_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg8_89(0);
+ prg8_ab(0);
+ prg8_cd(0);
+ prg8_ef(0xff);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_enable_latch = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Konami VRC1 and Jaleco JF20, JF22
+
+ Games: Exciting Boxing, Ganbare Goemon!, Tetsuwan Atom
+
+ iNES: mapper 75
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_konami_vrc1_device::write_h)
+{
+ LOG_MMC(("VRC-1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x2000:
+ prg8_ab(data);
+ break;
+ case 0x4000:
+ prg8_cd(data);
+ break;
+ case 0x1000:
+ set_nt_mirroring((data & 0x01) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x0f) | ((data & 0x02) << 3);
+ m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x0f) | ((data & 0x04) << 2);
+ chr4_0(m_mmc_vrom_bank[0], CHRROM);
+ chr4_4(m_mmc_vrom_bank[1], CHRROM);
+ break;
+ case 0x6000:
+ m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x10) | (data & 0x0f);
+ chr4_0(m_mmc_vrom_bank[0], CHRROM);
+ break;
+ case 0x7000:
+ m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x10) | (data & 0x0f);
+ chr4_4(m_mmc_vrom_bank[1], CHRROM);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Konami VRC-2
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(nes_konami_vrc2_device::read_m)
+{
+ LOG_MMC(("VRC-2 read_m, offset: %04x\n", offset));
+
+ if (m_battery)
+ return m_battery[offset & (m_battery_size - 1)];
+ else if (m_prgram)
+ return m_prgram[offset & (m_prgram_size - 1)];
+ else // sort of protection? it returns open bus in $7000-$7fff and (open bus & 0xfe) | m_latch in $6000-$6fff
+ return (offset < 0x1000) ? ((((offset + 0x8000) & 0xfe00) >> 8) | (m_latch & 1)) : (((offset + 0x8000) & 0xff00) >> 8);
+}
+
+WRITE8_MEMBER(nes_konami_vrc2_device::write_m)
+{
+ LOG_MMC(("VRC-2 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_battery)
+ m_battery[offset & (m_battery_size - 1)] = data;
+ else if (m_prgram)
+ m_prgram[offset & (m_prgram_size - 1)] = data;
+ else if (offset < 0x1000)
+ m_latch = data;
+}
+
+WRITE8_MEMBER(nes_konami_vrc2_device::write_h)
+{
+ UINT8 bank, shift, mask;
+ UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100);
+ LOG_MMC(("VRC-2 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x2000:
+ prg8_ab(data);
+ break;
+ case 0x1000:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x3000:
+ case 0x4000:
+ case 0x5000:
+ case 0x6000:
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(add_lines, 9);
+ shift = BIT(add_lines, 8) * 4;
+ mask = (0xf0 >> shift);
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | (((data >> m_vrc_ls_chr) & 0x0f) << shift);
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ default:
+ logerror("VRC-2 write_h uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Konami VRC3
+
+ Games: Salamander
+
+ iNES: mapper 73
+
+ In MESS: Supported. It also uses konami_irq.
+
+ -------------------------------------------------*/
+
+void nes_konami_vrc3_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ /* Increment & check the IRQ scanline counter */
+ if (m_irq_enable && (++m_irq_count == 0x100))
+ {
+ m_irq_count = m_irq_count_latch;
+ m_irq_enable = m_irq_enable_latch;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+WRITE8_MEMBER(nes_konami_vrc3_device::write_h)
+{
+ LOG_MMC(("VRC-3 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ case 0x1000:
+ /* dunno which address controls these */
+ m_irq_count_latch = data;
+ m_irq_enable_latch = data;
+ break;
+ case 0x2000:
+ m_irq_enable = data;
+ break;
+ case 0x3000:
+ m_irq_count &= ~0x0f;
+ m_irq_count |= data & 0x0f;
+ break;
+ case 0x4000:
+ m_irq_count &= ~0xf0;
+ m_irq_count |= (data & 0x0f) << 4;
+ break;
+ case 0x7000:
+ prg16_89ab(data);
+ break;
+ default:
+ logerror("VRC-3 write_h uncaught write, offset %04x, data: %02x\n", offset, data);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Konami VRC-4
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_konami_vrc4_device::set_prg()
+{
+ if (m_latch & 0x02)
+ {
+ prg8_89(0xfe);
+ prg8_cd(m_mmc_prg_bank);
+ }
+ else
+ {
+ prg8_89(m_mmc_prg_bank);
+ prg8_cd(0xfe);
+ }
+}
+
+WRITE8_MEMBER(nes_konami_vrc4_device::write_h)
+{
+ UINT8 bank, shift, mask;
+ UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100);
+ LOG_MMC(("VRC-4 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ m_mmc_prg_bank = data;
+ set_prg();
+ break;
+ case 0x2000:
+ prg8_ab(data);
+ break;
+ case 0x1000:
+ if (add_lines & 0x200)
+ {
+ m_latch = data & 0x02;
+ set_prg();
+ }
+ else
+ {
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ }
+ break;
+ case 0x3000:
+ case 0x4000:
+ case 0x5000:
+ case 0x6000:
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(add_lines, 9);
+ shift = BIT(add_lines, 8) * 4;
+ mask = (0xf0 >> shift);
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | ((data & 0x0f) << shift);
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ case 0x7000:
+ switch (add_lines)
+ {
+ case 0x000:
+ m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f);
+ break;
+ case 0x100:
+ m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x200:
+ m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ m_irq_enable = data & 0x02;
+ m_irq_enable_latch = data & 0x01;
+ if (data & 0x02)
+ m_irq_count = m_irq_count_latch;
+ break;
+ case 0x300:
+ m_irq_enable = m_irq_enable_latch;
+ break;
+ }
+ break;
+ default:
+ logerror("VRC-4 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Konami VRC-6
+
+ In MESS: Supported. It also uses konami_irq (there are IRQ
+ issues though: see Akumajou Densetsu intro).
+
+ TODO: Add sound capabilities support!
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_konami_vrc6_device::write_h)
+{
+ UINT8 bank;
+ UINT16 add_lines = ((offset << (9 - m_vrc_ls_prg_a)) & 0x200) | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100);
+ LOG_MMC(("VRC-6 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ prg16_89ab(data);
+ break;
+ case 0x4000:
+ prg8_cd(data);
+ break;
+ case 0x1000:
+ case 0x2000:
+ LOG_MMC(("Konami VRC-6 Sound write, offset: %04x, data: %02x\n", (offset & 0x7000) | add_lines, data));
+ break;
+ case 0x3000:
+ if (add_lines == 0x300)
+ {
+ switch (data & 0x0c)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x04: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x08: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x0c: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ }
+ else
+ LOG_MMC(("Konami VRC-6 Sound write, offset: %04x, data: %02x\n", (offset & 0x7000) | add_lines, data));
+ break;
+ case 0x5000:
+ case 0x6000:
+ bank = ((offset & 0x7000) - 0x5000) / 0x0400 + ((add_lines & 0x0300) >> 8);
+ chr1_x(bank, data, CHRROM);
+ break;
+ case 0x7000:
+ switch (add_lines)
+ {
+ case 0x000:
+ m_irq_count_latch = data;
+ break;
+ case 0x100:
+ m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ m_irq_enable = data & 0x02;
+ m_irq_enable_latch = data & 0x01;
+ if (data & 0x02)
+ m_irq_count = m_irq_count_latch;
+ break;
+ case 0x200:
+ m_irq_enable = m_irq_enable_latch;
+ break;
+ default:
+ logerror("VRC-6 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data);
+ break;
+ }
+ break;
+ default:
+ logerror("VRC-6 write_h uncaught write, addr: %04x value: %02x\n", ((offset & 0x7000) | add_lines) + 0x8000, data);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Konami VRC7
+
+ Games: Lagrange Point, Tiny Toon Adventures 2
+
+ iNES: mapper 85
+
+ In MESS: Supported. It also uses konami_irq.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_konami_vrc7_device::write_h)
+{
+ UINT8 bank;
+ LOG_MMC(("VRC-7 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7038)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x0008:
+ case 0x0010:
+ case 0x0018:
+ prg8_ab(data);
+ break;
+
+ case 0x1000:
+ prg8_cd(data);
+ break;
+
+ case 0x1010:
+ case 0x1018:
+ ym2413_register_port_w(m_ym2413, space, 0, data);
+ break;
+ case 0x1030:
+ case 0x1038:
+ ym2413_data_port_w(m_ym2413, space, 0, data);
+ break;
+
+ case 0x2000:
+ case 0x2008:
+ case 0x2010:
+ case 0x2018:
+ case 0x3000:
+ case 0x3008:
+ case 0x3010:
+ case 0x3018:
+ case 0x4000:
+ case 0x4008:
+ case 0x4010:
+ case 0x4018:
+ case 0x5000:
+ case 0x5008:
+ case 0x5010:
+ case 0x5018:
+ bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0018) ? 1 : 0);
+ chr1_x(bank, data, m_chr_source);
+ break;
+
+ case 0x6000:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x6008: case 0x6010: case 0x6018:
+ m_irq_count_latch = data;
+ break;
+ case 0x7000:
+ m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ m_irq_enable = data & 0x02;
+ m_irq_enable_latch = data & 0x01;
+ if (data & 0x02)
+ m_irq_count = m_irq_count_latch;
+ break;
+ case 0x7008: case 0x7010: case 0x7018:
+ m_irq_enable = m_irq_enable_latch;
+ break;
+
+ default:
+ logerror("VRC-7 write_h uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( vrc7 )
+//-------------------------------------------------
+
+// From NESdev wiki: The VRC7, in addition to being a mapper chip, also produces 6 channels of
+// 2-operator FM Synthesis Audio. It is a derivative of the Yamaha YM2413 OPLL, implementing a
+// subset of its features and containing a custom fixed patch set.
+// The synthesis core is related to the Yamaha YM2413 OPLL:
+// - Register layout is the same.
+// - VRC7 has 6 channels, OPLL has 9.
+// - VRC7 has no rhythm channels, OPLL does (the last 3 channels are either FM or Rhythm on OPLL).
+// - VRC7 built-in instruments are not the same as OPLL instruments.
+// - VRC7 has no readily-accessible status register, under normal circumstances it is write-only;
+// OPLL has an undocumented, 2-bit 'internal state' register.
+// - VRC7 has an internal state output pin (may be serial version of the 2 bit internal state register)
+// and has one output pin for audio, multiplexed for all 6 channels; OPLL has two output pins, one for
+// FM and one for Rhythm, and has no special status pin.
+
+// FIXME: we currently emulate this as a base YM2413!
+
+
+#define VRC7_NTSC_CLOCK (21477272.724 / 12)
+
+static MACHINE_CONFIG_FRAGMENT( vrc7 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SOUND_ADD("ym", YM2413, VRC7_NTSC_CLOCK)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nes_konami_vrc7_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vrc7 );
+}
diff --git a/src/mess/machine/nes_konami.h b/src/mess/machine/nes_konami.h
new file mode 100644
index 00000000000..ef36d5d4eaf
--- /dev/null
+++ b/src/mess/machine/nes_konami.h
@@ -0,0 +1,136 @@
+#ifndef __NES_KONAMI_H
+#define __NES_KONAMI_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_konami_vrc1_device
+
+class nes_konami_vrc1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_konami_vrc1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_mmc_vrom_bank[2];
+};
+
+
+// ======================> nes_konami_vrc2_device
+
+class nes_konami_vrc2_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_konami_vrc2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_mmc_vrom_bank[8];
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_konami_vrc3_device
+
+class nes_konami_vrc3_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_konami_vrc3_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);
+ nes_konami_vrc3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ UINT16 m_irq_count, m_irq_count_latch;
+ int m_irq_enable, m_irq_enable_latch;
+ int m_irq_mode; // used by VRC-4, VRC-6 & VRC-7. currently not implemented: 0 = prescaler mode / 1 = CPU mode
+};
+
+
+// ======================> nes_konami_vrc4_device
+
+class nes_konami_vrc4_device : public nes_konami_vrc3_device
+{
+public:
+ // construction/destruction
+ nes_konami_vrc4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void set_prg();
+ UINT8 m_mmc_vrom_bank[8];
+ UINT8 m_latch, m_mmc_prg_bank;
+};
+
+
+// ======================> nes_konami_vrc6_device
+
+class nes_konami_vrc6_device : public nes_konami_vrc3_device
+{
+public:
+ // construction/destruction
+ nes_konami_vrc6_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ // TODO: emulate sound capabilities!
+};
+
+
+// ======================> nes_konami_vrc7_device
+
+class nes_konami_vrc7_device : public nes_konami_vrc3_device
+{
+public:
+ // construction/destruction
+ nes_konami_vrc7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ device_t *m_ym2413;
+};
+
+
+
+// device type definition
+extern const device_type NES_VRC1;
+extern const device_type NES_VRC2;
+extern const device_type NES_VRC3;
+extern const device_type NES_VRC4;
+extern const device_type NES_VRC6;
+extern const device_type NES_VRC7;
+
+#endif
diff --git a/src/mess/machine/nes_legacy.c b/src/mess/machine/nes_legacy.c
new file mode 100644
index 00000000000..d198b92ed8a
--- /dev/null
+++ b/src/mess/machine/nes_legacy.c
@@ -0,0 +1,271 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for FFE PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the mappers used by available Far Front East copier hacked games [mappers 6, 8, 17]
+
+ TODO:
+ - investigate IRQ mechanism (current code is broken)
+ - replace this with proper copier emulation, using disk images...
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_legacy.h"
+
+#include "cpu/m6502/m6502.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_FFE3 = &device_creator<nes_ffe3_device>;
+const device_type NES_FFE4 = &device_creator<nes_ffe4_device>;
+const device_type NES_FFE8 = &device_creator<nes_ffe8_device>;
+
+
+nes_ffe3_device::nes_ffe3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_FFE3, "NES Cart FFE-3 PCB", tag, owner, clock, "nes_ff3", __FILE__)
+{
+}
+
+nes_ffe4_device::nes_ffe4_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_ffe4_device::nes_ffe4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_FFE4, "NES Cart FFE-4 PCB", tag, owner, clock, "nes_ff4", __FILE__)
+{
+}
+
+nes_ffe8_device::nes_ffe8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_ffe4_device(mconfig, NES_FFE8, "NES Cart FFE-8 PCB", tag, owner, clock, "nes_ff8", __FILE__)
+{
+}
+
+
+
+void nes_ffe3_device::device_start()
+{
+ common_start();
+}
+
+void nes_ffe3_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+
+void nes_ffe4_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_latch));
+}
+
+void nes_ffe4_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(7);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+
+void nes_ffe8_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0xff);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Mapper 8
+
+ Known Boards: FFE3 Copier Board
+ Games: Hacked versions of games
+
+ In MESS: Supported? (I have no games to test this)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ffe3_device::write_h)
+{
+ LOG_MMC(("mapper8 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(data & 0x07, CHRROM);
+ prg16_89ab(data >> 3);
+}
+
+/*-------------------------------------------------
+
+ Mapper 6
+
+ Known Boards: FFE4 Copier Board
+ Games: Hacked versions of games
+
+ In MESS: Supported? Not sure if we could also have ExRAM or not...
+ However, priority is pretty low for this mapper.
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+
+void nes_ffe4_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ // 114 is the number of cycles per scanline
+ // TODO: change to reflect the actual number of cycles spent
+ if (m_irq_enable)
+ {
+ if ((0xffff - m_irq_count) < 114)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_count = 0xffff;
+ m_irq_enable = 0;
+ }
+ m_irq_count -= 114;
+ }
+}
+
+WRITE8_MEMBER(nes_ffe4_device::write_l)
+{
+ LOG_MMC(("mapper6 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1fe:
+ m_latch = data & 0x80;
+ set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ break;
+ case 0x1ff:
+ set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x401:
+ m_irq_enable = data & 0x01;
+ break;
+ case 0x402:
+ m_irq_count = (m_irq_count & 0xff00) | data;
+ break;
+ case 0x403:
+ m_irq_enable = 1;
+ m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_ffe4_device::write_h)
+{
+ LOG_MMC(("mapper6 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (!m_latch) // when in "FFE mode" we are forced to use CHRRAM/EXRAM bank?
+ {
+ prg16_89ab(data >> 2);
+ // chr8(data & 0x03, ???);
+ // due to lack of info on the exact behavior, we simply act as if m_latch=1
+ if (m_chr_source == CHRROM)
+ chr8(data & 0x03, CHRROM);
+ }
+ else if (m_chr_source == CHRROM) // otherwise, we can use CHRROM (when present)
+ chr8(data, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Mapper 17
+
+ Known Boards: FFE8 Copier Board
+ Games: Hacked versions of games
+
+ In MESS: Supported?. IRQ support is just a guess (used to
+ use MMC3 IRQ but it was wrong and it never enabled it)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ffe8_device::write_l)
+{
+ LOG_MMC(("mapper17 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1fe:
+ set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ break;
+ case 0x1ff:
+ set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x401:
+ m_irq_enable = data & 0x01;
+ break;
+ case 0x402:
+ m_irq_count = (m_irq_count & 0xff00) | data;
+ break;
+ case 0x403:
+ m_irq_enable = 1;
+ m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
+ break;
+
+ case 0x404:
+ prg8_89(data);
+ break;
+ case 0x405:
+ prg8_ab(data);
+ break;
+ case 0x406:
+ prg8_cd(data);
+ break;
+ case 0x407:
+ prg8_ef(data);
+ break;
+
+ case 0x410:
+ case 0x411:
+ case 0x412:
+ case 0x413:
+ case 0x414:
+ case 0x415:
+ case 0x416:
+ case 0x417:
+ chr1_x(offset & 7, data, CHRROM);
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_legacy.h b/src/mess/machine/nes_legacy.h
new file mode 100644
index 00000000000..df905ce1a89
--- /dev/null
+++ b/src/mess/machine/nes_legacy.h
@@ -0,0 +1,71 @@
+#ifndef __NES_LEGACY_H
+#define __NES_LEGACY_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_ffe3_device
+
+class nes_ffe3_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ffe3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_ffe4_device
+
+class nes_ffe4_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ffe4_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);
+ nes_ffe4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_ffe8_device
+
+class nes_ffe8_device : public nes_ffe4_device
+{
+public:
+ // construction/destruction
+ nes_ffe8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h) {}
+
+ virtual void pcb_reset();
+};
+
+
+
+// device type definition
+extern const device_type NES_FFE3;
+extern const device_type NES_FFE4;
+extern const device_type NES_FFE8;
+
+
+#endif
diff --git a/src/mess/machine/nes_mmc.c b/src/mess/machine/nes_mmc.c
deleted file mode 100644
index 4051c776af3..00000000000
--- a/src/mess/machine/nes_mmc.c
+++ /dev/null
@@ -1,579 +0,0 @@
-/*****************************************************************************************
-
- NES MMC Emulation
-
-
- MESS source file to handle various Multi-Memory Controllers (aka Mappers) used by NES carts.
-
- Many information about the mappers below come from the wonderful doc written by Disch.
- Current info (when used) are based on v0.6.1 of his docs.
- You can find the latest version of the doc at http://www.romhacking.net/docs/362/
-
-
- Missing components:
- * Currently, we are not emulating 4-screen mirroring (only 3 games use it)
- * We need a better way to implement CPU cycle based IRQ. Currently we update their counter once every scanline
- but, with this approach, every time 114 clocks have passed and for certain games it is too much!
- * We need to emulate additional sound hardware in mappers 019, 024, 026, 069, 085 (and possibly other ones)
- * We need to emulate EEPROM in mapper 016 and 159
- * Barcode World (mapper 069) and Datach games (mapper 157) need Barcode Reader emulation
- Notice that for mapper 157, the barcode reader enters in the irq, so glitches may be related to this!
- * Karaoke Studio (mapper 188) misses input devices
-
- Known issues on specific mappers:
-
- * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches.
- * 001 Yoshi flashes in-game. Back to the Future have heavily corrupted graphics (since forever).
- * 001 SOROM boards do not properly handle the two WRAM/Battery banks
- * 002, 003, 094, 097, 152 Bus conflict?
- * 003 Firehouse Rescue has flashing graphics
- * 004 Mendel Palace has never worked properly
- * 004 Ninja Gaiden 2 has flashing bg graphics in the second level
- * 005 has issues (see e.g. Just Breed or Metal Slader Glory), RAM banking needs hardware flags to determine size
- * 007 Marble Madness has small graphics corruptions
- * 014 in-game graphics is glitched
- * 015 Shanghai Tycoon has corrupted graphics
- * 033 has still some graphics problem (e.g. missing text in Akira)
- * 034 Impossible Mission II does not show graphics
- * 038 seems to miss inputs. separate reads?
- * 042 Ai Senshi Nicol has broken graphics (our Mapper 42 implementation does not handle CHR banks)
- * 048 Don Doko Don 2 freezes when you reach the first boss
- * 051 only half of the games work
- * 064 has many IRQ problems (due to the way we implement CPU based IRQ) - see Skull & Crossbones.
- Klax has problems as well (even if it uses scanline based IRQ, according to Disch's docs).
- * 067 some 1-line glitches that cannot be solved without a better implementation for cycle-based IRQs
- * 071 Fire Hawk is flashing all the times.
- * 072, 086, 092 lack samples support (maybe others as well)
- * 073 16 bit IRQ mode is not implemented
- * 077 Requires 4-screen mirroring. Currently, it is very glitchy
- * 083 has serious glitches
- * 088 Quinty has never worked properly
- * 096 is preliminary (no correct chr switch in connection to PPU)
- * 104 Not all the games work
- * 107 Are the scrolling glitches (check status bar) correct? NEStopia behaves similarly
- * 112 Master Shooter is not working and misses some graphics
- * 117 In-game glitches
- * 119 Pin Bot has glitches when the ball is in the upper half of the screen
- * 133 Qi Wang starts with corrupted graphics (ingame seems better)
- * 143 are Dancing Block borders (in the intro) correct?
- * 158 In addition to IRQ problems (same as 64), mirroring was just a guess (wrong?). info needed!
- * 164 preliminary - no sprites?
- * 176 has some graphics problem
- * 178 Fan Kong Jin Ying is not working (but not even in NEStopia)
- * 180 Crazy Climber controller?
- * 187, 198, 208, 215 have some PRG banking issues - preliminary!
- * 188 needs mic input (reads from 0x6000-0x7fff)
- * 197 Super Fighter 3 has some glitch in-game (maybe mirroring?)
- * 222 is only preliminar (wrong IRQ, mirroring or CHR banking?)
- * 225 115-in-1 has glitches in the menu (games seem fine)
- * 229 is preliminary
- * 230 not working yet (needs a value to flip at reset)
- * 232 has graphics glitches
- * 241 Commandos is not working (but not even in NEStopia)
- * 242 In Dragon Quest VIII graphics of the main character is not drawn (it seems similar to Shanghai Tycoon [map15]
- because in place of the missing graphics we get glitches in the left border)
- * 249 only half of the games work (and Du Bao Ying Hao seems to suffer the same problem as DQ8 and Shanghai Tycoon)
- * 255 does not really select game (same in NEStopia apparently)
-
- A few Mappers suffer of hardware conflict: original dumpers have used the same mapper number for more than
- a kind of boards. In these cases (and only in these cases) we exploit nes.hsi to set up accordingly
- emulation. Games which requires this hack are the following:
- * 032 - Major League needs hardwired mirroring (missing windows and glitched field in top view, otherwise)
- * 034 - Impossible Mission II is not like BxROM games (it writes to 0x7ffd-0x7fff, instead of 0x8000). It is still
- unplayable though (see above)
- * 071 - Fire Hawk is different from other Camerica games (no hardwired mirroring). Without crc_hack no helicopter graphics
- * 078 - Cosmo Carrier needs a different mirroring than Holy Diver
- * 113 - HES 6-in-1 requires mirroring (check Bookyman playfield), while other games break with this (check AV Soccer)
- * 153 - Famicom Jump II uses a different board (or the same in a very different way)
- * 242 - DQ8 has no mirroring (missing graphics is due to other reasons though)
-
- crc_hacks have been added also to handle a few wiring settings which would require submappers:
- * CHR protection pins for mapper 185
- * VRC-2, VRC-4 and VRC-6 line wiring
-
- Known issues on specific UNIF boards:
- * BMC-GS2004 is not working
- * BMC-GS2013 is not working
- * BMC-WS some games have corrupted graphics (e.g. Galaxian)
- * UNL-8237 is not working
- * UNL-KOF97 is not working
-
- Details to investigate:
- * 034 writes to 0x8000-0xffff should not be used for NINA-001 and BNROM, only unlicensed BxROM...
- * 144 we ignore writes to 0x8000 while NEStopia does not. is it a problem?
- * 240 we do not map writes to 0x4020-0x40ff. is this a problem?
- * some other emus uses mapper 210 for mapper 019 games without additional sound hardware and mirroring capabilities
- (in 210 mirroring is hardwired). However, simply initializing mirroring to Vertical in 019 seems to fix all glitches
- in 210 games, so there seems to be no reason to have this duplicate mapper
-
- Some mappers copy PRG rom in SRAM region. Below is a list of those which does it (in MESS) to further
- investigate if we are supporting them in the right way (e.g. do any of the following have conflicts with SRAM?):
- * 065 (Gimmick! breaks badly without it)
- * 040, 042, 050
-
- Remember that the MMC # does not equal the mapper #. In particular, Mapper 4 is
- in fact MMC3, Mapper 9 is MMC2 and Mapper 10 is MMC4. Makes perfect sense, right?
-
- TODO:
- - add more info
- - add missing mappers
-
-****************************************************************************************/
-
-#include "emu.h"
-#include "cpu/m6502/m6502.h"
-#include "video/ppu2c0x.h"
-#include "includes/nes.h"
-#include "includes/nes_mmc.h"
-#include "sound/nes_apu.h"
-
-#ifdef MAME_DEBUG
-#define VERBOSE 1
-#else
-#define VERBOSE 0
-#endif
-
-#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
-#define LOG_FDS(x) do { if (VERBOSE) logerror x; } while (0)
-
-/*************************************************************
-
- Base emulation (see drivers/nes.c):
- memory 0x0000-0x1fff RAM
- 0x2000-0x3fff PPU
- 0x4000-0x4017 APU
- 0x4018-0x5fff Expansion Area
- 0x6000-0x7fff PRG RAM
- 0x8000-0xffff PRG ROM
-
- nes_chr_r/w take care of RAM, nes_nt_r/w take care of PPU.
- for mapper specific emulation, we generically setup the
- following handlers:
- - nes_low_mapper_r/w take care of accesses to 0x4100-0x5fff
- (calling state->m_mmc_write_low/state->m_mmc_read_low)
- - state->m_mmc_write/read_mid take care of 0x6000-0x7fff
- - state->m_mmc_write/read take care of access to 0x8000-0xffff
- (most mappers only writes in this area)
- some mappers may access 0x4018-0x4100: this must be taken
- care separately in init_nes_core
-
-*************************************************************/
-
-WRITE8_MEMBER(nes_state::nes_chr_w)
-{
- int bank = offset >> 10;
-
- if (m_chr_map[bank].source == CHRRAM)
- {
- m_chr_map[bank].access[offset & 0x3ff] = data;
- }
-}
-
-READ8_MEMBER(nes_state::nes_chr_r)
-{
- int bank = offset >> 10;
-
- // a few CNROM boards contained copy protection schemes through
- // suitably configured diodes, so that subsequent CHR reads can
- // give actual VROM content or open bus values.
- // For most boards, chr_open_bus remains always zero.
- if (m_chr_open_bus)
- return 0xff;
-
- return m_chr_map[bank].access[offset & 0x3ff];
-}
-
-WRITE8_MEMBER(nes_state::nes_nt_w)
-{
- int page = ((offset & 0xc00) >> 10);
-
- if (m_nt_page[page].writable == 0)
- return;
-
- m_nt_page[page].access[offset & 0x3ff] = data;
-}
-
-READ8_MEMBER(nes_state::nes_nt_r)
-{
- int page = ((offset & 0xc00) >> 10);
-
- if (m_nt_page[page].source == MMC5FILL)
- {
- if ((offset & 0x3ff) >= 0x3c0)
- return m_MMC5_floodattr;
-
- return m_MMC5_floodtile;
- }
- return m_nt_page[page].access[offset & 0x3ff];
-}
-
-/*************************************************************
-
- Helpers to handle MMC
-
-*************************************************************/
-
-void nes_carts_state::wram_bank(int bank, int source)
-{
- nes_state *state = machine().driver_data<nes_state>();
-
- assert(m_battery || m_prg_ram);
- if (source == NES_BATTERY)
- {
- bank &= (m_battery_size / 0x2000) - 1;
- m_prg_bank[4] = m_battery_bank5_start + bank;
- }
- else
- {
- bank &= (m_wram_size / 0x2000) - 1;
- m_prg_bank[4] = m_prgram_bank5_start + bank;
- }
- state->update_prg_banks(4, 4);
-}
-
-INLINE void prg_bank_refresh( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->update_prg_banks(0, 3);
-}
-
-/* PRG ROM in 8K, 16K or 32K blocks */
-
-void nes_carts_state::prg32(int bank)
-{
- /* if there is only 16k PRG, return */
- if (!(m_prg_chunks >> 1))
- return;
-
- /* assumes that bank references a 32k chunk */
- bank &= ((m_prg_chunks >> 1) - 1);
-
- m_prg_bank[0] = bank * 4 + 0;
- m_prg_bank[1] = bank * 4 + 1;
- m_prg_bank[2] = bank * 4 + 2;
- m_prg_bank[3] = bank * 4 + 3;
- prg_bank_refresh(machine());
-}
-
-void nes_carts_state::prg16_89ab(int bank)
-{
- /* assumes that bank references a 16k chunk */
- bank &= (m_prg_chunks - 1);
-
- m_prg_bank[0] = bank * 2 + 0;
- m_prg_bank[1] = bank * 2 + 1;
- prg_bank_refresh(machine());
-}
-
-void nes_carts_state::prg16_cdef(int bank)
-{
- /* assumes that bank references a 16k chunk */
- bank &= (m_prg_chunks - 1);
-
- m_prg_bank[2] = bank * 2 + 0;
- m_prg_bank[3] = bank * 2 + 1;
- prg_bank_refresh(machine());
-}
-
-void nes_carts_state::prg8_89(int bank)
-{
- /* assumes that bank references an 8k chunk */
- bank &= ((m_prg_chunks << 1) - 1);
-
- m_prg_bank[0] = bank;
- prg_bank_refresh(machine());
-}
-
-void nes_carts_state::prg8_ab(int bank)
-{
- /* assumes that bank references an 8k chunk */
- bank &= ((m_prg_chunks << 1) - 1);
-
- m_prg_bank[1] = bank;
- prg_bank_refresh(machine());
-}
-
-void nes_carts_state::prg8_cd(int bank)
-{
- /* assumes that bank references an 8k chunk */
- bank &= ((m_prg_chunks << 1) - 1);
-
- m_prg_bank[2] = bank;
- prg_bank_refresh(machine());
-}
-
-void nes_carts_state::prg8_ef(int bank)
-{
- /* assumes that bank references an 8k chunk */
- bank &= ((m_prg_chunks << 1) - 1);
-
- m_prg_bank[3] = bank;
- prg_bank_refresh(machine());
-}
-
-/* We define an additional helper to map PRG-ROM to 0x6000-0x7000 */
-// TODO: are we implementing this correctly in the mappers which uses it? check!
-
-void nes_carts_state::prg8_67(int bank)
-{
- /* assumes that bank references an 8k chunk */
- bank &= ((m_prg_chunks << 1) - 1);
-
- m_prg_bank[4] = bank;
- membank("bank5")->set_entry(m_prg_bank[4]);
-}
-
-/* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */
-void nes_carts_state::prg8_x(int start, int bank)
-{
- assert(start < 4);
-
- /* assumes that bank references an 8k chunk */
- bank &= ((m_prg_chunks << 1) - 1);
-
- m_prg_bank[start] = bank;
- prg_bank_refresh(machine());
-}
-
-/* CHR ROM in 1K, 2K, 4K or 8K blocks */
-
-// this can be probably removed later, but it is useful while testing xml and unf handling with VRAM & VROM
-INLINE void chr_sanity_check( running_machine &machine, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (source == CHRRAM && state->m_vram == NULL)
- fatalerror("CHRRAM bankswitch with no VRAM\n");
-
- if (source == CHRROM && state->m_vrom == NULL)
- fatalerror("CHRROM bankswitch with no VROM\n");
-}
-
-void nes_carts_state::chr8(int bank, int source)
-{
- chr_sanity_check(machine(), source);
-
- if (source == CHRRAM)
- {
- bank &= (m_vram_chunks - 1);
- for (int i = 0; i < 8; i++)
- {
- m_chr_map[i].source = source;
- m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses!
- m_chr_map[i].access = &m_vram[m_chr_map[i].origin];
- }
- }
- else
- {
- bank &= (m_chr_chunks - 1);
- for (int i = 0; i < 8; i++)
- {
- m_chr_map[i].source = source;
- m_chr_map[i].origin = (bank * 0x2000) + (i * 0x400); // for save state uses!
- m_chr_map[i].access = &m_vrom[m_chr_map[i].origin];
- }
- }
-}
-
-void nes_carts_state::chr4_x(int start, int bank, int source)
-{
- chr_sanity_check(machine(), source);
-
- if (source == CHRRAM)
- {
- bank &= ((m_vram_chunks << 1) - 1);
- for (int i = 0; i < 4; i++)
- {
- m_chr_map[i + start].source = source;
- m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses!
- m_chr_map[i + start].access = &m_vram[m_chr_map[i + start].origin];
- }
- }
- else
- {
- bank &= ((m_chr_chunks << 1) - 1);
- for (int i = 0; i < 4; i++)
- {
- m_chr_map[i + start].source = source;
- m_chr_map[i + start].origin = (bank * 0x1000) + (i * 0x400); // for save state uses!
- m_chr_map[i + start].access = &m_vrom[m_chr_map[i + start].origin];
- }
- }
-}
-
-void nes_carts_state::chr2_x(int start, int bank, int source)
-{
- chr_sanity_check(machine(), source);
-
- if (source == CHRRAM)
- {
- bank &= ((m_vram_chunks << 2) - 1);
- for (int i = 0; i < 2; i++)
- {
- m_chr_map[i + start].source = source;
- m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses!
- m_chr_map[i + start].access = &m_vram[m_chr_map[i + start].origin];
- }
- }
- else
- {
- bank &= ((m_chr_chunks << 2) - 1);
- for (int i = 0; i < 2; i++)
- {
- m_chr_map[i + start].source = source;
- m_chr_map[i + start].origin = (bank * 0x800) + (i * 0x400); // for save state uses!
- m_chr_map[i + start].access = &m_vrom[m_chr_map[i + start].origin];
- }
- }
-}
-
-void nes_carts_state::chr1_x(int start, int bank, int source)
-{
- chr_sanity_check(machine(), source);
-
- if (source == CHRRAM)
- {
- bank &= ((m_vram_chunks << 3) - 1);
- m_chr_map[start].source = source;
- m_chr_map[start].origin = (bank * 0x400); // for save state uses!
- m_chr_map[start].access = &m_vram[m_chr_map[start].origin];
- }
- else
- {
- bank &= ((m_chr_chunks << 3) - 1);
- m_chr_map[start].source = source;
- m_chr_map[start].origin = (bank * 0x400); // for save state uses!
- m_chr_map[start].access = &m_vrom[m_chr_map[start].origin];
- }
-}
-
-
-/* NameTable paging and mirroring */
-
-void nes_carts_state::set_nt_page(int page, int source, int bank, int writable)
-{
- UINT8* base_ptr;
-
- switch (source)
- {
- case CART_NTRAM:
- base_ptr = m_extended_ntram;
- break;
- case MMC5FILL:
- base_ptr = NULL;
- break;
- case ROM:
- base_ptr = m_vrom;
- break;
- case EXRAM:
- base_ptr = m_mapper_ram;
- break;
- case CIRAM:
- default:
- base_ptr = m_ciram;
- break;
- }
-
- page &= 3; /* mask down to the 4 logical pages */
- m_nt_page[page].source = source;
-
- if (base_ptr != NULL)
- {
- m_nt_page[page].origin = bank * 0x400;
- m_nt_page[page].access = base_ptr + m_nt_page[page].origin;
- }
-
- m_nt_page[page].writable = writable;
-}
-
-void nes_carts_state::set_nt_mirroring(int mirroring)
-{
- /* setup our videomem handlers based on mirroring */
- switch (mirroring)
- {
- case PPU_MIRROR_VERT:
- set_nt_page(0, CIRAM, 0, 1);
- set_nt_page(1, CIRAM, 1, 1);
- set_nt_page(2, CIRAM, 0, 1);
- set_nt_page(3, CIRAM, 1, 1);
- break;
-
- case PPU_MIRROR_HORZ:
- set_nt_page(0, CIRAM, 0, 1);
- set_nt_page(1, CIRAM, 0, 1);
- set_nt_page(2, CIRAM, 1, 1);
- set_nt_page(3, CIRAM, 1, 1);
- break;
-
- case PPU_MIRROR_HIGH:
- set_nt_page(0, CIRAM, 1, 1);
- set_nt_page(1, CIRAM, 1, 1);
- set_nt_page(2, CIRAM, 1, 1);
- set_nt_page(3, CIRAM, 1, 1);
- break;
-
- case PPU_MIRROR_LOW:
- set_nt_page(0, CIRAM, 0, 1);
- set_nt_page(1, CIRAM, 0, 1);
- set_nt_page(2, CIRAM, 0, 1);
- set_nt_page(3, CIRAM, 0, 1);
- break;
-
- case PPU_MIRROR_NONE:
- case PPU_MIRROR_4SCREEN:
- default:
- /* external RAM needs to be used somehow. */
- /* but as a default, we'll arbitrarily set vertical so as not to crash*/
- /* mappers should use set_nt_page and assign which pages are which */
-
- logerror("Mapper set 4-screen mirroring without supplying external nametable memory!\n");
-
- set_nt_page(0, CIRAM, 0, 1);
- set_nt_page(1, CIRAM, 0, 1);
- set_nt_page(2, CIRAM, 1, 1);
- set_nt_page(3, CIRAM, 1, 1);
- break;
- }
-}
-
-/* Other custom mirroring helpers are defined below: Waixing games use waixing_set_mirror (which swaps
- MIRROR_HIGH and MIRROR_LOW compared to the above) and Sachen games use sachen_set_mirror (which has
- a slightly different MIRROR_HIGH, with page 0 set to 0) */
-
-#ifdef _MSC_VER
-#pragma optimize("", off)
-#endif
-
-
-/*************************************************************
-
- Support for xml list
-
- *************************************************************/
-
-/* Include emulation of NES PCBs for softlist */
-#include "machine/nes_pcb.c"
-
-
-/*************************************************************
-
- Support for .unf Files
-
-*************************************************************/
-
-/* Include emulation of UNIF Boards for .unf files */
-#include "machine/nes_unif.c"
-
-
-/*************************************************************
-
- Support for .nes Files
-
- *************************************************************/
-
-/* Include emulation of iNES Mappers for .nes files */
-#include "machine/nes_ines.c"
-
-#ifdef _MSC_VER
-#pragma optimize("", on)
-#endif
diff --git a/src/mess/machine/nes_mmc1.c b/src/mess/machine/nes_mmc1.c
new file mode 100644
index 00000000000..872b7e7370b
--- /dev/null
+++ b/src/mess/machine/nes_mmc1.c
@@ -0,0 +1,371 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Nintendo MMC-1 PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the Nintendo SxROM / MMC-1 PCBs + older variants without WRAM protect bit
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_mmc1.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_SXROM = &device_creator<nes_sxrom_device>;
+const device_type NES_SOROM = &device_creator<nes_sorom_device>;
+const device_type NES_SXROM_A = &device_creator<nes_sxrom_a_device>;
+const device_type NES_SOROM_A = &device_creator<nes_sorom_a_device>;
+
+
+
+nes_sxrom_device::nes_sxrom_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_sxrom_device::nes_sxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SXROM, "NES Cart SxROM (MMC-1) PCB", tag, owner, clock, "nes_sxrom", __FILE__)
+{
+}
+
+nes_sorom_device::nes_sorom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sxrom_device(mconfig, NES_SOROM, "NES Cart SOROM (MMC-1) PCB", tag, owner, clock, "nes_sorom", __FILE__)
+{
+}
+
+nes_sxrom_a_device::nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sxrom_device(mconfig, NES_SXROM_A, "NES Cart SxROM (MMC-1A) PCB", tag, owner, clock, "nes_sxrom_a", __FILE__)
+{
+}
+
+nes_sorom_a_device::nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sxrom_device(mconfig, NES_SOROM_A, "NES Cart SOROM (MMC-1A) PCB", tag, owner, clock, "nes_sorom_a", __FILE__)
+{
+}
+
+
+
+void nes_sxrom_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_count));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_reg_write_enable));
+}
+
+void nes_sxrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_latch = 0;
+ m_count = 0;
+ m_reg[0] = 0x0f;
+ m_reg[1] = m_reg[2] = m_reg[3] = 0;
+ m_reg_write_enable = 1;
+
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ set_chr();
+ set_prg();
+}
+
+void nes_sorom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_latch = 0;
+ m_count = 0;
+ m_reg[0] = 0x0f;
+ m_reg[1] = m_reg[2] = m_reg[3] = 0;
+ m_reg_write_enable = 1;
+
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ set_chr();
+ set_prg();
+}
+
+void nes_sorom_a_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_latch = 0;
+ m_count = 0;
+ m_reg[0] = 0x0f;
+ m_reg[1] = m_reg[2] = m_reg[3] = 0;
+ m_reg_write_enable = 1;
+
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ set_chr();
+ set_prg();
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+
+/*-------------------------------------------------
+
+ SxROM (MMC1 based) board emulation
+
+ iNES: mapper 1 (and 155 for the MMC1A variant which does not
+ have WRAM disable bit)
+
+ -------------------------------------------------*/
+
+TIMER_CALLBACK_MEMBER( nes_sxrom_device::resync_callback )
+{
+ m_reg_write_enable = 1;
+}
+
+
+void nes_sxrom_device::set_prg()
+{
+ UINT8 prg_mode, prg_offset;
+
+ prg_mode = m_reg[0] & 0x0c;
+ /* prg_mode&0x8 determines bank size: 32k (if 0) or 16k (if 1)? when in 16k mode,
+ prg_mode&0x4 determines which half of the PRG space we can swap: if it is 4,
+ m_reg[3] sets banks at 0x8000; if it is 0, m_reg[3] sets banks at 0xc000. */
+
+ prg_offset = m_reg[1] & 0x10;
+ /* In principle, m_reg[2]&0x10 might affect "extended" banks as well, when chr_mode=1.
+ However, quoting Disch's docs: When in 4k CHR mode, 0x10 in both $A000 and $C000 *must* be
+ set to the same value, or else pages will constantly be swapped as graphics render!
+ Hence, we use only m_reg[1]&0x10 for prg_offset */
+
+ switch (prg_mode)
+ {
+ case 0x00:
+ case 0x04:
+// printf("PRG 32 bank %d \n", (prg_offset + m_reg[3]) >> 1);
+ prg32((prg_offset + m_reg[3]) >> 1);
+ break;
+ case 0x08:
+// printf("PRG 16 bank %d (high) \n", prg_offset + m_reg[3]);
+ prg16_89ab(prg_offset + 0);
+ prg16_cdef(prg_offset + m_reg[3]);
+ break;
+ case 0x0c:
+// printf("PRG 16 bank %d (low) \n", prg_offset + m_reg[3]);
+ prg16_89ab(prg_offset + m_reg[3]);
+ prg16_cdef(prg_offset + 0x0f);
+ break;
+ }
+}
+
+void nes_sxrom_device::set_chr()
+{
+ UINT8 chr_mode = BIT(m_reg[0], 4);
+
+ if (chr_mode)
+ {
+ chr4_0(m_reg[1] & 0x1f, m_chr_source);
+ chr4_4(m_reg[2] & 0x1f, m_chr_source);
+ }
+ else
+ chr8((m_reg[1] & 0x1f) >> 1, m_chr_source);
+}
+
+// this allows for easier implementation of the NES-EVENT board used for Nintento World Championships
+void nes_sxrom_device::update_regs(int reg)
+{
+ switch (reg)
+ {
+ case 0:
+ switch (m_reg[0] & 0x03)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ }
+ set_chr();
+ set_prg();
+ break;
+ case 1:
+ set_chr();
+ set_prg();
+ break;
+ case 2:
+ set_chr();
+ break;
+ case 3:
+ set_prg();
+ break;
+ }
+}
+
+WRITE8_MEMBER( nes_sxrom_device::write_h )
+{
+ LOG_MMC(("sxrom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // There is only one latch and shift counter, shared amongst the 4 regs (testcase: Space Shuttle)
+
+ /* here we would need to add an if(cpu_cycles_passed>1) test, and
+ if requirement is not met simply return without writing anything.
+ Some games (AD&D Hillsfar, Bill & Ted Excellent Adventure, Cosmic
+ Wars, Rocket Ranger, Sesame Street 123 and Snow Brothers) rely on
+ this behavior!! */
+ if (!m_reg_write_enable)
+ return;
+ else
+ {
+ m_reg_write_enable = 0;
+ machine().scheduler().synchronize(timer_expired_delegate(FUNC(nes_sxrom_device::resync_callback),this));
+ }
+
+ if (data & 0x80)
+ {
+ m_count = 0;
+ m_latch = 0;
+
+ // Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars
+ m_reg[0] |= 0x0c;
+ set_prg();
+ return;
+ }
+
+ if (m_count < 5)
+ {
+ if (m_count == 0) m_latch = 0;
+ m_latch >>= 1;
+ m_latch |= (data & 0x01) ? 0x10 : 0x00;
+ m_count++;
+ }
+
+ if (m_count == 5)
+ {
+ m_reg[(offset & 0x6000) >> 13] = m_latch;
+ update_regs((offset & 0x6000) >> 13);
+ m_count = 0;
+ }
+}
+
+WRITE8_MEMBER(nes_sxrom_device::write_m)
+{
+ UINT8 bank = (m_reg[1] & 3) >> 2;
+ LOG_MMC(("sxrom write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (!BIT(m_reg[3], 4)) // WRAM enabled
+ {
+ if (m_battery)
+ m_battery[((bank * 0x2000) + offset) & (m_battery_size - 1)] = data;
+ if (m_prgram)
+ m_prgram[((bank * 0x2000) + offset) & (m_prgram_size - 1)] = data;
+ }
+}
+
+READ8_MEMBER(nes_sxrom_device::read_m)
+{
+ UINT8 bank = (m_reg[1] & 3) >> 2;
+ LOG_MMC(("sxrom read_m, offset: %04x\n", offset));
+
+ if (!BIT(m_reg[3], 4)) // WRAM enabled
+ {
+ if (m_battery)
+ return m_battery[((bank * 0x2000) + offset) & (m_battery_size - 1)];
+ if (m_prgram)
+ return m_prgram[((bank * 0x2000) + offset) & (m_prgram_size - 1)];
+ }
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+// SOROM has two RAM banks, the first is not battery backed up, the second is.
+WRITE8_MEMBER(nes_sorom_device::write_m)
+{
+ UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
+ LOG_MMC(("sorom write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (!BIT(m_reg[3], 4)) // WRAM enabled
+ {
+ if (type)
+ m_battery[offset & (m_battery_size - 1)] = data;
+ else
+ m_prgram[offset & (m_prgram_size - 1)] = data;
+ }
+}
+
+READ8_MEMBER(nes_sorom_device::read_m)
+{
+ UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
+ LOG_MMC(("sorom read_m, offset: %04x\n", offset));
+
+ if (!BIT(m_reg[3], 4)) // WRAM enabled
+ {
+ if (type)
+ return m_battery[offset & (m_battery_size - 1)];
+ else
+ return m_prgram[offset & (m_prgram_size - 1)];
+ }
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+// MMC1A boards have no wram enable/disable bit
+WRITE8_MEMBER(nes_sxrom_a_device::write_m)
+{
+ UINT8 bank = (m_reg[1] & 3) >> 2;
+ LOG_MMC(("sxrom_a write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_battery)
+ m_battery[((bank * 0x2000) + offset) & (m_battery_size - 1)] = data;
+ if (m_prgram)
+ m_prgram[((bank * 0x2000) + offset) & (m_prgram_size - 1)] = data;
+}
+
+READ8_MEMBER(nes_sxrom_a_device::read_m)
+{
+ UINT8 bank = (m_reg[1] & 3) >> 2;
+ LOG_MMC(("sxrom_a read_m, offset: %04x\n", offset));
+
+ if (m_battery)
+ return m_battery[((bank * 0x2000) + offset) & (m_battery_size - 1)];
+ if (m_prgram)
+ return m_prgram[((bank * 0x2000) + offset) & (m_prgram_size - 1)];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+WRITE8_MEMBER(nes_sorom_a_device::write_m)
+{
+ UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
+ LOG_MMC(("sorom_a write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (type)
+ m_battery[offset & (m_battery_size - 1)] = data;
+ else
+ m_prgram[offset & (m_prgram_size - 1)] = data;
+}
+
+READ8_MEMBER(nes_sorom_a_device::read_m)
+{
+ UINT8 type = BIT(m_reg[0], 4) ? BIT(m_reg[1], 4) : BIT(m_reg[1], 3);
+ LOG_MMC(("sorom_a read_m, offset: %04x\n", offset));
+
+ if (type)
+ return m_battery[offset & (m_battery_size - 1)];
+ else
+ return m_prgram[offset & (m_prgram_size - 1)];
+}
diff --git a/src/mess/machine/nes_mmc1.h b/src/mess/machine/nes_mmc1.h
new file mode 100644
index 00000000000..a13c4100b0a
--- /dev/null
+++ b/src/mess/machine/nes_mmc1.h
@@ -0,0 +1,80 @@
+#ifndef __NES_MMC1_H
+#define __NES_MMC1_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_sxrom_device
+
+class nes_sxrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sxrom_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);
+ nes_sxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void update_regs(int reg); // this is needed to simplify NES-EVENT pcb implementation, which handle differently some regs!
+
+ virtual void pcb_reset();
+
+protected:
+ TIMER_CALLBACK_MEMBER(resync_callback);
+ virtual void set_prg();
+ virtual void set_chr();
+
+ UINT8 m_reg[4];
+ int m_reg_write_enable;
+ int m_latch;
+ int m_count;
+};
+
+class nes_sorom_device : public nes_sxrom_device
+{
+public:
+ // construction/destruction
+ nes_sorom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+class nes_sxrom_a_device : public nes_sxrom_device
+{
+public:
+ // construction/destruction
+ nes_sxrom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+};
+
+class nes_sorom_a_device : public nes_sxrom_device
+{
+public:
+ // construction/destruction
+ nes_sorom_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+
+
+// device type definition
+extern const device_type NES_SXROM;
+extern const device_type NES_SOROM;
+extern const device_type NES_SXROM_A;
+extern const device_type NES_SOROM_A;
+
+
+#endif
diff --git a/src/mess/machine/nes_mmc2.c b/src/mess/machine/nes_mmc2.c
new file mode 100644
index 00000000000..87e69095bfb
--- /dev/null
+++ b/src/mess/machine/nes_mmc2.c
@@ -0,0 +1,199 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Nintendo MMC-2 & MMC-4 PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the Nintendo PxROM and FxROM PCBs [mapper 9 & 10]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_mmc2.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_PXROM = &device_creator<nes_pxrom_device>;
+const device_type NES_FXROM = &device_creator<nes_fxrom_device>;
+
+
+nes_pxrom_device::nes_pxrom_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_pxrom_device::nes_pxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_PXROM, "NES Cart PxROM (MMC-2) PCB", tag, owner, clock, "nes_pxrom", __FILE__)
+{
+}
+
+nes_fxrom_device::nes_fxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_pxrom_device(mconfig, NES_FXROM, "NES Cart FxROM (MMC-4) PCB", tag, owner, clock, "nes_fxrom", __FILE__)
+{
+}
+
+
+
+
+void nes_pxrom_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+ save_item(NAME(m_reg));
+}
+
+void nes_pxrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg8_89(0);
+ prg8_ab((m_prg_chunks << 1) - 3);
+ prg8_cd((m_prg_chunks << 1) - 2);
+ prg8_ef((m_prg_chunks << 1) - 1);
+ chr8(0, m_chr_source);
+
+ m_reg[0] = m_reg[2] = 0;
+ m_reg[1] = m_reg[3] = 0;
+ m_latch1 = m_latch2 = 0xfe;
+}
+
+void nes_fxrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_reg[0] = m_reg[2] = 0;
+ m_reg[1] = m_reg[3] = 0;
+ m_latch1 = m_latch2 = 0xfe;
+}
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ PxROM (MMC2 based) board emulation
+
+ Games: Punch Out!!, Mike Tyson's Punch Out!!
+
+ iNES: mapper 9
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_pxrom_device::ppu_latch(offs_t offset)
+{
+ if ((offset & 0x3ff0) == 0x0fd0)
+ {
+ LOG_MMC(("mmc2 vrom latch switch (bank 0 low): %02x\n", m_reg[0]));
+ m_latch1 = 0xfd;
+ chr4_0(m_reg[0], CHRROM);
+ }
+ else if ((offset & 0x3ff0) == 0x0fe0)
+ {
+ LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_reg[1]));
+ m_latch1 = 0xfe;
+ chr4_0(m_reg[1], CHRROM);
+ }
+ else if ((offset & 0x3ff0) == 0x1fd0)
+ {
+ LOG_MMC(("mmc2 vrom latch switch (bank 1 low): %02x\n", m_reg[2]));
+ m_latch2 = 0xfd;
+ chr4_4(m_reg[2], CHRROM);
+ }
+ else if ((offset & 0x3ff0) == 0x1fe0)
+ {
+ LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_reg[3]));
+ m_latch2 = 0xfe;
+ chr4_4(m_reg[3], CHRROM);
+ }
+}
+
+WRITE8_MEMBER( nes_pxrom_device::pxrom_write )
+{
+ LOG_MMC(("pxrom write_h, offset: %04x, data: %02x\n", offset, data));
+ switch (offset & 0x7000)
+ {
+ case 0x2000:
+ prg8_89(data);
+ break;
+ case 0x3000:
+ m_reg[0] = data;
+ if (m_latch1 == 0xfd)
+ chr4_0(m_reg[0], CHRROM);
+ break;
+ case 0x4000:
+ m_reg[1] = data;
+ if (m_latch1 == 0xfe)
+ chr4_0(m_reg[1], CHRROM);
+ break;
+ case 0x5000:
+ m_reg[2] = data;
+ if (m_latch2 == 0xfd)
+ chr4_4(m_reg[2], CHRROM);
+ break;
+ case 0x6000:
+ m_reg[3] = data;
+ if (m_latch2 == 0xfe)
+ chr4_4(m_reg[3], CHRROM);
+ break;
+ case 0x7000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ default:
+ LOG_MMC(("MMC2 uncaught w: %04x:%02x\n", offset, data));
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ FxROM (MMC4 based) board emulation
+
+ Games: Famicom Wars, Fire Emblem, Fire Emblem Gaiden
+
+ This is a small hardware variants of MMC2 (additional
+ prg bankswitch line)
+
+ iNES: mapper 10
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER( nes_fxrom_device::write_h )
+{
+ LOG_MMC(("fxrom write_h, offset: %04x, data: %02x\n", offset, data));
+ switch (offset & 0x7000)
+ {
+ case 0x2000:
+ prg16_89ab(data);
+ break;
+ default:
+ pxrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_mmc2.h b/src/mess/machine/nes_mmc2.h
new file mode 100644
index 00000000000..580ac31302b
--- /dev/null
+++ b/src/mess/machine/nes_mmc2.h
@@ -0,0 +1,52 @@
+#ifndef __NES_MMC2_H
+#define __NES_MMC2_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_pxrom_device
+
+class nes_pxrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_pxrom_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);
+ nes_pxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(pxrom_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { pxrom_write(space, offset, data, mem_mask); }
+
+ virtual void ppu_latch(offs_t offset);
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_reg[4];
+ int m_latch1, m_latch2;
+};
+
+
+// ======================> nes_fxrom_device
+
+class nes_fxrom_device : public nes_pxrom_device
+{
+public:
+ // construction/destruction
+ nes_fxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_PXROM;
+extern const device_type NES_FXROM;
+
+#endif
diff --git a/src/mess/machine/nes_mmc3.c b/src/mess/machine/nes_mmc3.c
new file mode 100644
index 00000000000..6dd75778594
--- /dev/null
+++ b/src/mess/machine/nes_mmc3.c
@@ -0,0 +1,554 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Nintendo MMC-3 & MMC-6 PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Nintendo TxROM, aka MMC-3 [mapper 4]
+ * Nintendo HKROM, aka MMC-6 [mapper 4]
+ * Nintendo TxSROM [mapper 118]
+ * Nintendo TQROM [mapper 119]
+ * Nintendo NES-QJ [mapper 47]
+ * Nintendo PAL-ZZ [mapper 37]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_mmc3.h"
+
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_TXROM = &device_creator<nes_txrom_device>;
+const device_type NES_HKROM = &device_creator<nes_hkrom_device>;
+const device_type NES_TXSROM = &device_creator<nes_txsrom_device>;
+const device_type NES_TQROM = &device_creator<nes_tqrom_device>;
+const device_type NES_QJ_PCB = &device_creator<nes_qj_device>;
+const device_type NES_ZZ_PCB = &device_creator<nes_zz_device>;
+
+
+nes_txrom_device::nes_txrom_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_txrom_device::nes_txrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TXROM, "NES Cart TxROM (MMC-3) PCB", tag, owner, clock, "nes_txrom", __FILE__)
+{
+}
+
+nes_hkrom_device::nes_hkrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_HKROM, "NES Cart HKROM (MMC-6) PCB", tag, owner, clock, "nes_hkrom", __FILE__)
+{
+}
+
+nes_txsrom_device::nes_txsrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_TXSROM, "NES Cart TxSROM PCB", tag, owner, clock, "nes_txsrom", __FILE__)
+{
+}
+
+nes_tqrom_device::nes_tqrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_TQROM, "NES Cart TQROM PCB", tag, owner, clock, "nes_tqrom", __FILE__)
+{
+}
+
+nes_qj_device::nes_qj_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_QJ_PCB, "NES Cart NES-QJ PCB", tag, owner, clock, "nes_qj", __FILE__)
+{
+}
+
+nes_zz_device::nes_zz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_ZZ_PCB, "NES Cart PAL-ZZ PCB", tag, owner, clock, "nes_zz", __FILE__)
+{
+}
+
+
+
+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_latch));
+ save_item(NAME(m_wram_protect));
+ 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_alt_irq));
+ 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));
+}
+
+void nes_txrom_device::mmc3_common_initialize( int prg_mask, int chr_mask, int irq_type )
+{
+ 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));
+
+ m_latch = 0;
+ m_wram_protect = 0x80;
+
+ m_prg_base = m_chr_base = 0;
+ m_prg_mask = prg_mask;
+ m_chr_mask = chr_mask;
+
+ m_alt_irq = irq_type; // later MMC3 boards seem to use MMC6-type IRQ... more investigations are in progress at NESDev...
+ m_irq_enable = 0;
+ m_irq_count = m_irq_count_latch = 0;
+ m_irq_clear = 0;
+
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+}
+
+
+void nes_txrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ // 4-screen mirroring is taken care in pcb_start, if needed...
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+
+void nes_hkrom_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_mmc6_reg));
+ save_item(NAME(m_wram_enable));
+
+ m_mmc6_ram = auto_alloc_array_clear(machine(), UINT8, 0x400);
+ save_pointer(NAME(m_mmc6_ram), 0x400);
+
+ m_mapper_sram_size = 0x400;
+ m_mapper_sram = m_mmc6_ram;
+}
+
+void nes_hkrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0xff, 0xff, 1);
+ m_mmc6_reg = 0xf0;
+ m_wram_enable = 0;
+}
+
+
+void nes_qj_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0x0f, 0x7f, 0);
+}
+
+
+void nes_zz_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0x07, 0x7f, 0);
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ TxROM (MMC3 based) board emulation
+
+ iNES: mapper 4
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every scanline. */
+void nes_txrom_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ int prior_count = m_irq_count;
+ if ((m_irq_count == 0) || m_irq_clear)
+ m_irq_count = m_irq_count_latch;
+ else
+ m_irq_count--;
+
+ if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear /*|| !m_mmc3_alt_irq*/)) // according to blargg the latter should be present as well, but it breaks Rampart and Joe & Mac US: they probably use the alt irq!
+ {
+ LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
+ machine().primary_screen->vpos(), machine().primary_screen->hpos()));
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+ m_irq_clear = 0;
+}
+
+// base MMC3 simply calls prg8_x
+void nes_txrom_device::prg_cb( int start, int bank )
+{
+ prg8_x(start, bank);
+}
+
+// base MMC3 simply calls chr1_x
+void nes_txrom_device::chr_cb( int start, int bank, int source )
+{
+ chr1_x(start, bank, source);
+}
+
+
+void nes_txrom_device::set_prg( int prg_base, int prg_mask )
+{
+ UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0;
+
+ prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask));
+ prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask));
+ prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask));
+ prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask));
+}
+
+void nes_txrom_device::set_chr( UINT8 chr, int chr_base, int chr_mask )
+{
+ UINT8 chr_page = (m_latch & 0x80) >> 5;
+
+ chr_cb(chr_page ^ 0, chr_base | ((m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr);
+ chr_cb(chr_page ^ 1, chr_base | ((m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr);
+ chr_cb(chr_page ^ 2, chr_base | ((m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr);
+ chr_cb(chr_page ^ 3, chr_base | ((m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr);
+ chr_cb(chr_page ^ 4, chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr);
+ chr_cb(chr_page ^ 5, chr_base | (m_mmc_vrom_bank[3] & chr_mask), chr);
+ chr_cb(chr_page ^ 6, chr_base | (m_mmc_vrom_bank[4] & chr_mask), chr);
+ chr_cb(chr_page ^ 7, chr_base | (m_mmc_vrom_bank[5] & chr_mask), chr);
+}
+
+WRITE8_MEMBER(nes_txrom_device::txrom_write)
+{
+ UINT8 mmc_helper, cmd;
+
+ LOG_MMC(("txrom_write, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc_helper = m_latch ^ data;
+ m_latch = data;
+
+ // Has PRG Mode changed?
+ if (mmc_helper & 0x40)
+ set_prg(m_prg_base, m_prg_mask);
+
+ // Has CHR Mode changed?
+ if (mmc_helper & 0x80)
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+
+ case 0x0001:
+ cmd = m_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
+ case 2: case 3: case 4: case 5:
+ m_mmc_vrom_bank[cmd] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ m_mmc_prg_bank[cmd - 6] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ }
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x2001:
+ m_wram_protect = data;
+ break;
+
+ case 0x4000:
+ m_irq_count_latch = data;
+ break;
+
+ case 0x4001:
+ m_irq_count = 0;
+ break;
+
+ case 0x6000:
+ m_irq_enable = 0;
+ break;
+
+ case 0x6001:
+ m_irq_enable = 1;
+ break;
+
+ default:
+ logerror("txrom_write uncaught: %04x value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_txrom_device::write_m)
+{
+ LOG_MMC(("txrom write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (BIT(m_wram_protect, 7) && !BIT(m_wram_protect, 6))
+ {
+ if (m_battery)
+ m_battery[offset & (m_battery_size - 1)] = data;
+ if (m_prgram)
+ m_prgram[offset & (m_prgram_size - 1)] = data;
+ }
+}
+
+READ8_MEMBER(nes_txrom_device::read_m)
+{
+ LOG_MMC(("txrom read_m, offset: %04x\n", offset));
+
+ if (BIT(m_wram_protect, 7))
+ {
+ if (m_battery)
+ return m_battery[offset & (m_battery_size - 1)];
+ if (m_prgram)
+ return m_prgram[offset & (m_prgram_size - 1)];
+ }
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+
+/*-------------------------------------------------
+
+ HKROM (MMC6 based) board emulation
+
+ iNES: mapper 4
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_hkrom_device::write_m)
+{
+ UINT8 write_hi, write_lo;
+ LOG_MMC(("hkrom write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x1000)
+ return;
+
+ // banks can be written only if both read & write is enabled!
+ write_hi = ((m_mmc6_reg & 0xc0) == 0xc0);
+ write_lo = ((m_mmc6_reg & 0x30) == 0x30);
+
+ if (BIT(offset, 9) && write_hi) // access to upper half of 1k
+ m_mmc6_ram[offset & 0x3ff] = data;
+
+ if (!BIT(offset, 9) && write_lo) // access to lower half of 1k
+ m_mmc6_ram[offset & 0x3ff] = data;
+}
+
+READ8_MEMBER(nes_hkrom_device::read_m)
+{
+ LOG_MMC(("hkrom read_m, offset: %04x\n", offset));
+
+ if (offset < 0x1000)
+ return 0xff; // here it should be open bus
+
+ if (!(m_mmc6_reg & 0xa0))
+ return 0xff; // here it should be open bus
+
+ if (BIT(offset, 9) && BIT(m_mmc6_reg, 7)) // access to upper half of 1k when upper read is enabled
+ return m_mmc6_ram[offset & 0x3ff];
+
+ if (!BIT(offset, 9) && BIT(m_mmc6_reg, 5)) // access to lower half of 1k when lower read is enabled
+ return m_mmc6_ram[offset & 0x3ff];
+
+ // If only one bank is enabled for reading, the other reads back as zero
+ return 0x00;
+}
+
+WRITE8_MEMBER(nes_hkrom_device::write_h)
+{
+ UINT8 mmc6_helper;
+ LOG_MMC(("hkrom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc6_helper = m_latch ^ data;
+ m_latch = data;
+
+ if (!m_wram_enable && BIT(data, 5)) // if WRAM is disabled and has to be enabled, write
+ m_wram_enable = BIT(data, 5); // (once WRAM has been enabled, it cannot be disabled without resetting the game)
+
+ // Has PRG Mode changed?
+ if (BIT(mmc6_helper, 6))
+ set_prg(m_prg_base, m_prg_mask);
+
+ // Has CHR Mode changed?
+ if (BIT(mmc6_helper, 7))
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+
+ case 0x2001:
+ if (m_wram_enable)
+ m_mmc6_reg = data;
+ break;
+
+ case 0x4001:
+ m_irq_count = 0;
+ m_irq_clear = 1;
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ TxSROM (MMC3 based) board emulation
+
+ Games: Armadillo, Play Action Football, Pro Hockey, RPG
+ Jinsei Game, Y's 3
+
+ iNES: mapper 118
+
+ In MESS: Supported. It also uses mmc3_irq.
+
+ -------------------------------------------------*/
+
+void nes_txsrom_device::set_mirror()
+{
+ if (m_latch & 0x80)
+ {
+ set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1);
+ set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1);
+ set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1);
+ set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1);
+ }
+ else
+ {
+ set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1);
+ set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1);
+ set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1);
+ set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1);
+ }
+}
+
+void nes_txsrom_device::chr_cb( int start, int bank, int source )
+{
+ set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code
+ chr1_x(start, bank, source);
+}
+
+WRITE8_MEMBER(nes_txsrom_device::write_h)
+{
+ LOG_MMC(("txsrom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x2000:
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ TQROM (MMC3 based) board emulation
+
+ Games: Pin Bot, High Speed
+
+ iNES: mapper 119
+
+ In MESS: Supported. It also uses mmc3_irq.
+
+ -------------------------------------------------*/
+
+void nes_tqrom_device::set_chr( UINT8 chr, int chr_base, int chr_mask )
+{
+ UINT8 chr_page = (m_latch & 0x80) >> 5;
+ UINT8 src[6], mask[6];
+
+ // TQROM ignores the source, base and mask set by the MMC3 and determines them based on vrom bank bits
+ for (int i = 0; i < 6; i++)
+ {
+ src[i] = (m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM;
+ mask[i] = (m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f;
+ }
+
+ chr1_x(chr_page ^ 0, ((m_mmc_vrom_bank[0] & ~0x01) & mask[0]), src[0]);
+ chr1_x(chr_page ^ 1, ((m_mmc_vrom_bank[0] | 0x01) & mask[0]), src[0]);
+ chr1_x(chr_page ^ 2, ((m_mmc_vrom_bank[1] & ~0x01) & mask[1]), src[1]);
+ chr1_x(chr_page ^ 3, ((m_mmc_vrom_bank[1] | 0x01) & mask[1]), src[1]);
+ chr1_x(chr_page ^ 4, (m_mmc_vrom_bank[2] & mask[2]), src[2]);
+ chr1_x(chr_page ^ 5, (m_mmc_vrom_bank[3] & mask[3]), src[3]);
+ chr1_x(chr_page ^ 6, (m_mmc_vrom_bank[4] & mask[4]), src[4]);
+ chr1_x(chr_page ^ 7, (m_mmc_vrom_bank[5] & mask[5]), src[5]);
+}
+
+
+/*-------------------------------------------------
+
+ NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart
+ Super Spike V'Ball + Nintendo World Cup)
+
+ iNES: mapper 47
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_qj_device::write_m)
+{
+ LOG_MMC(("qj write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_prg_base = BIT(data, 0) << 4;
+ m_prg_mask = 0x0f;
+ m_chr_base = BIT(data, 0) << 7;
+ m_chr_mask = 0x7f;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+}
+
+
+/*-------------------------------------------------
+
+ PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart
+ Super Mario Bros. + Tetris + Nintendo World Cup)
+
+ iNES: mapper 37
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_zz_device::write_m)
+{
+ UINT8 mmc_helper = data & 0x07;
+ LOG_MMC(("zz write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0);
+ m_prg_mask = (mmc_helper << 1) | 0x07;
+ m_chr_base = BIT(mmc_helper, 2) << 7;
+ m_chr_mask = 0x7f;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+}
diff --git a/src/mess/machine/nes_mmc3.h b/src/mess/machine/nes_mmc3.h
new file mode 100644
index 00000000000..7c2e607e5ec
--- /dev/null
+++ b/src/mess/machine/nes_mmc3.h
@@ -0,0 +1,144 @@
+#ifndef __NES_MMC3_H
+#define __NES_MMC3_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_txrom_device
+
+class nes_txrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_txrom_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);
+ nes_txrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start() { mmc3_start(); }
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(txrom_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { txrom_write(space, offset, data, mem_mask); }
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ virtual void set_prg(int prg_base, int prg_mask);
+ virtual void set_chr(UINT8 chr, int chr_base, int chr_mask);
+ void mmc3_start();
+ void mmc3_common_initialize(int prg_mask, int chr_mask, int IRQ_type);
+
+ // are there MMC3 clones which need more regs?
+ UINT16 m_mmc_prg_bank[4];
+ UINT16 m_mmc_vrom_bank[8]; // a few clones need more than the 6 banks used by base MMC3 (e.g. waixing_g)
+
+ 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.
+
+ int m_latch;
+ int m_wram_protect;
+ int m_alt_irq;
+
+ UINT16 m_irq_count, m_irq_count_latch;
+ UINT8 m_irq_clear;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_hkrom_device
+
+class nes_hkrom_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_hkrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+protected:
+ int m_wram_enable;
+ UINT8 m_mmc6_reg;
+
+ // MMC-6 contains 1K of internal ram, battery backed up
+ UINT8 *m_mmc6_ram;
+};
+
+
+// ======================> nes_txsrom_device
+
+class nes_txsrom_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_txsrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void chr_cb(int start, int bank, int source);
+
+protected:
+ void set_mirror();
+};
+
+
+// ======================> nes_tqrom_device
+
+class nes_tqrom_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_tqrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual void set_chr( UINT8 chr, int chr_base, int chr_mask );
+};
+
+
+// ======================> nes_qj_device
+
+class nes_qj_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_qj_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_zz_device
+
+class nes_zz_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_zz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual void pcb_reset();
+};
+
+
+
+
+// device type definition
+extern const device_type NES_TXROM;
+extern const device_type NES_HKROM;
+extern const device_type NES_TXSROM;
+extern const device_type NES_TQROM;
+extern const device_type NES_QJ_PCB;
+extern const device_type NES_ZZ_PCB;
+
+#endif
diff --git a/src/mess/machine/nes_mmc3_clones.c b/src/mess/machine/nes_mmc3_clones.c
new file mode 100644
index 00000000000..705f559035c
--- /dev/null
+++ b/src/mess/machine/nes_mmc3_clones.c
@@ -0,0 +1,2598 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for MMC-3 clone PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate several pirate PCBs based on MMC-3 boards
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_mmc3_clones.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_NITRA = &device_creator<nes_nitra_device>;
+const device_type NES_KS7057 = &device_creator<nes_ks7057_device>;
+const device_type NES_SBROS11 = &device_creator<nes_sbros11_device>;
+const device_type NES_MALISB = &device_creator<nes_malisb_device>;
+const device_type NES_FAMILY4646 = &device_creator<nes_family4646_device>;
+const device_type NES_PIKAY2K = &device_creator<nes_pikay2k_device>;
+const device_type NES_8237 = &device_creator<nes_8237_device>;
+const device_type NES_SG_LIONK = &device_creator<nes_sglionk_device>;
+const device_type NES_SG_BOOG = &device_creator<nes_sgboog_device>;
+const device_type NES_KASING = &device_creator<nes_kasing_device>;
+const device_type NES_KAY = &device_creator<nes_kay_device>;
+const device_type NES_H2288 = &device_creator<nes_h2288_device>;
+const device_type NES_6035052 = &device_creator<nes_6035052_device>;
+const device_type NES_TXC_TW = &device_creator<nes_txc_tw_device>;
+const device_type NES_KOF97 = &device_creator<nes_kof97_device>;
+const device_type NES_KOF96 = &device_creator<nes_kof96_device>;
+const device_type NES_SF3 = &device_creator<nes_sf3_device>;
+const device_type NES_GOUDER = &device_creator<nes_gouder_device>;
+const device_type NES_SA9602B = &device_creator<nes_sa9602b_device>;
+const device_type NES_SACHEN_SHERO = &device_creator<nes_sachen_shero_device>;
+const device_type NES_A9746 = &device_creator<nes_a9746_device>;
+
+const device_type NES_FK23C = &device_creator<nes_fk23c_device>;
+const device_type NES_FK23CA = &device_creator<nes_fk23ca_device>;
+const device_type NES_S24IN1SC03 = &device_creator<nes_s24in1sc03_device>;
+const device_type NES_BMC_15IN1 = &device_creator<nes_bmc_15in1_device>;
+const device_type NES_BMC_SBIG7 = &device_creator<nes_bmc_sbig7_device>;
+const device_type NES_BMC_HIK8 = &device_creator<nes_bmc_hik8_device>;
+const device_type NES_BMC_HIK4 = &device_creator<nes_bmc_hik4_device>;
+const device_type NES_BMC_MARIO7IN1 = &device_creator<nes_bmc_mario7in1_device>;
+const device_type NES_BMC_GOLD7IN1 = &device_creator<nes_bmc_gold7in1_device>;
+const device_type NES_BMC_GC6IN1 = &device_creator<nes_bmc_gc6in1_device>;
+const device_type NES_BMC_411120C = &device_creator<nes_bmc_411120c_device>;
+const device_type NES_BMC_830118C = &device_creator<nes_bmc_830118c_device>;
+const device_type NES_PJOY84 = &device_creator<nes_pjoy84_device>;
+
+
+nes_nitra_device::nes_nitra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_NITRA, "NES Cart Nitra PCB", tag, owner, clock, "nes_nitra", __FILE__)
+{
+}
+
+nes_ks7057_device::nes_ks7057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_KS7057, "NES Cart KS-7057 PCB", tag, owner, clock, "nes_ks7057", __FILE__)
+{
+}
+
+nes_sbros11_device::nes_sbros11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_SBROS11, "NES Cart SMB 11 PCB", tag, owner, clock, "nes_smb11", __FILE__)
+{
+}
+
+nes_malisb_device::nes_malisb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_MALISB, "NES Cart Mali Spash Bomb PCB", tag, owner, clock, "nes_malisb", __FILE__)
+{
+}
+
+nes_family4646_device::nes_family4646_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_FAMILY4646, "NES Cart BMC-FAMILY-4646 PCB", tag, owner, clock, "nes_family4646", __FILE__)
+{
+}
+
+nes_pikay2k_device::nes_pikay2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_PIKAY2K, "NES Cart PIKACHU Y2K PCB", tag, owner, clock, "nes_pikay2k", __FILE__)
+{
+}
+
+nes_8237_device::nes_8237_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_8237, "NES Cart UNL-8237 PCB", tag, owner, clock, "nes_8237", __FILE__)
+{
+}
+
+nes_sglionk_device::nes_sglionk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_SG_LIONK, "NES Cart SuperGame Lion King PCB", tag, owner, clock, "nes_sglionk", __FILE__)
+{
+}
+
+nes_sgboog_device::nes_sgboog_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_SG_BOOG, "NES Cart SuperGame BoogerMan PCB", tag, owner, clock, "nes_sgbooger", __FILE__)
+{
+}
+
+nes_kasing_device::nes_kasing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_KASING, "NES Cart Kasing PCB", tag, owner, clock, "nes_kasing", __FILE__)
+{
+}
+
+nes_kay_device::nes_kay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_KAY, "NES Cart KAY PCB", tag, owner, clock, "nes_kay", __FILE__)
+{
+}
+
+nes_h2288_device::nes_h2288_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_H2288, "NES Cart H-2288 PCB", tag, owner, clock, "nes_h2288", __FILE__)
+{
+}
+
+nes_6035052_device::nes_6035052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_6035052, "NES Cart UNL-603-5052 PCB", tag, owner, clock, "nes_6035052", __FILE__)
+{
+}
+
+nes_txc_tw_device::nes_txc_tw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_TXC_TW, "NES Cart TXC Thunder Warrior PCB", tag, owner, clock, "nes_txc_tw", __FILE__)
+{
+}
+
+nes_kof97_device::nes_kof97_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_KOF97, "NES Cart KOF 97 PCB", tag, owner, clock, "nes_kof97", __FILE__)
+{
+}
+
+nes_kof96_device::nes_kof96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_KOF96, "NES Cart KOF 96 PCB", tag, owner, clock, "nes_kof96", __FILE__)
+{
+}
+
+nes_sf3_device::nes_sf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_SF3, "NES Cart Super Fighter III PCB", tag, owner, clock, "nes_sf3", __FILE__)
+{
+}
+
+nes_gouder_device::nes_gouder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_GOUDER, "NES Cart Gouder PCB", tag, owner, clock, "nes_gouder", __FILE__)
+{
+}
+
+nes_sa9602b_device::nes_sa9602b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_SA9602B, "NES Cart SA-9602B PCB", tag, owner, clock, "nes_sa9602b", __FILE__)
+{
+}
+
+nes_sachen_shero_device::nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_SACHEN_SHERO, "NES Cart Street Hero PCB", tag, owner, clock, "nes_shero", __FILE__)
+{
+}
+
+nes_a9746_device::nes_a9746_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_A9746, "NES Cart A-9746 PCB", tag, owner, clock, "nes_bmc_a9746", __FILE__)
+{
+}
+
+nes_fk23c_device::nes_fk23c_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)
+ : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_fk23c_device::nes_fk23c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_FK23C, "NES Cart FK23C PCB", tag, owner, clock, "nes_fk23c", __FILE__)
+{
+}
+
+nes_fk23ca_device::nes_fk23ca_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_fk23c_device(mconfig, NES_FK23CA, "NES Cart FK23CA PCB", tag, owner, clock, "nes_fk23ca", __FILE__)
+{
+}
+
+nes_s24in1sc03_device::nes_s24in1sc03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_S24IN1SC03, "NES Cart Super 24 in 1 SC-03 PCB", tag, owner, clock, "nes_s24in1c03", __FILE__)
+{
+}
+
+nes_bmc_15in1_device::nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_15IN1, "NES Cart BMC 15 in 1 PCB", tag, owner, clock, "nes_bmc_15in1", __FILE__)
+{
+}
+
+nes_bmc_sbig7_device::nes_bmc_sbig7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_SBIG7, "NES Cart BMC Super BIG 7 in 1 PCB", tag, owner, clock, "nes_bmc_sbit7", __FILE__)
+{
+}
+
+nes_bmc_hik8_device::nes_bmc_hik8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_HIK8, "NES Cart BMC Super HIK 8 in 1 PCB", tag, owner, clock, "nes_bmc_hik8", __FILE__)
+{
+}
+
+nes_bmc_hik4_device::nes_bmc_hik4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_HIK4, "NES Cart BMC Super HIK 4 in 1 PCB", tag, owner, clock, "nes_bmc_hik4", __FILE__)
+{
+}
+
+nes_bmc_mario7in1_device::nes_bmc_mario7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_MARIO7IN1, "NES Cart BMC Mario 7 in 1 PCB", tag, owner, clock, "nes_bmc_mario7in1", __FILE__)
+{
+}
+
+nes_bmc_gold7in1_device::nes_bmc_gold7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_GOLD7IN1, "NES Cart BMC Golden 7 in 1 PCB", tag, owner, clock, "nes_bmc_gold7in1", __FILE__)
+{
+}
+
+nes_bmc_gc6in1_device::nes_bmc_gc6in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_GC6IN1, "NES Cart BMC Golden Card 6 in 1 PCB", tag, owner, clock, "nes_bmc_gc6in1", __FILE__)
+{
+}
+
+nes_bmc_411120c_device::nes_bmc_411120c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_411120C, "NES Cart BMC 411120C PCB", tag, owner, clock, "nes_bmc_411120c", __FILE__)
+{
+}
+
+nes_bmc_830118c_device::nes_bmc_830118c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_BMC_830118C, "NES Cart BMC 830118C PCB", tag, owner, clock, "nes_bmc_830118c", __FILE__)
+{
+}
+
+nes_pjoy84_device::nes_pjoy84_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_PJOY84, "NES Cart Powerjoy 84 PCB", tag, owner, clock, "nes_pjoy84", __FILE__)
+{
+}
+
+
+
+void nes_family4646_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0x1f, 0xff, 0);
+}
+
+void nes_pikay2k_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_pikay2k_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg[0] = 0xff;
+ m_reg[1] = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_8237_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_cd_enable));
+}
+
+void nes_8237_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ m_reg[2] = 0;
+ m_cd_enable = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_sglionk_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_reg_enabled));
+}
+
+void nes_sglionk_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg = m_reg_enabled = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_sgboog_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_mode));
+}
+
+void nes_sgboog_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_mode = 0x04;
+ m_reg[0] = 0x00;
+ m_reg[1] = 0xff;
+ m_reg[2] = 0;
+ mmc3_common_initialize(0x1f, 0xff, 0);
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+}
+
+void nes_kasing_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_kasing_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+
+void nes_kay_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_low_reg));
+ save_item(NAME(m_reg));
+}
+
+void nes_kay_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ memset(m_reg, 0, sizeof(m_reg));
+ m_low_reg = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+
+void nes_h2288_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_h2288_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_6035052_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_prot));
+}
+
+void nes_6035052_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0xff, 0xff, 0);
+
+ m_prot = 0;
+}
+
+void nes_kof96_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_kof96_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ memset(m_reg, 0, sizeof(m_reg));
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_gouder_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_gouder_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ memset(m_reg, 0, sizeof(m_reg));
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_sa9602b_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_use_prgram));
+}
+
+void nes_sa9602b_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg = 0;
+ m_use_prgram = 0;
+ mmc3_common_initialize(0x1ff, 0, 0); // 1.5MB of PRG-ROM, no CHR-ROM
+}
+
+void nes_sachen_shero_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_sachen_shero_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg = 0;
+ mmc3_common_initialize(0xff, 0x1ff, 0);
+}
+
+void nes_a9746_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_a9746_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ mmc3_common_initialize(0x7f, 0xff, 0);
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ m_reg[2] = 0;
+}
+
+void nes_fk23c_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_mmc_cmd1));
+}
+
+void nes_fk23c_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_mmc_cmd1 = 0;
+ m_reg[0] = 4;
+ m_reg[1] = 0xff;
+ m_reg[2] = m_reg[3] = 0;
+ m_reg[4] = m_reg[5] = m_reg[6] = m_reg[7] = 0xff;
+ mmc3_common_initialize(0xff, 0xff, 0);
+ fk23c_set_prg();
+ fk23c_set_chr();
+
+}
+
+void nes_fk23ca_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_mmc_cmd1 = 0;
+ m_reg[0] = m_reg[1] = m_reg[2] = m_reg[3] = 0;
+ m_reg[4] = m_reg[5] = m_reg[6] = m_reg[7] = 0xff;
+ mmc3_common_initialize(0xff, 0xff, 0);
+ fk23c_set_prg();
+ fk23c_set_chr();
+}
+
+void nes_s24in1sc03_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_s24in1sc03_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg[0] = 0x24;
+ m_reg[1] = 0x9f;
+ m_reg[2] = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_bmc_15in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ mmc3_common_initialize(0x1f, 0xff, 0);
+ m_prg_base = 0x10; // this board has a diff prg_base
+ set_prg(m_prg_base, m_prg_mask);
+}
+
+void nes_bmc_sbig7_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0x0f, 0x7f, 0);
+}
+
+void nes_bmc_hik8_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_count));
+}
+
+void nes_bmc_hik8_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_count = 0;
+ memset(m_reg, 0, sizeof(m_reg));
+ mmc3_common_initialize(0x3f, 0xff, 0);
+}
+
+void nes_bmc_hik4_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0x0f, 0x7f, 0);
+}
+
+void nes_bmc_mario7in1_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg_written));
+}
+
+void nes_bmc_mario7in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg_written = 0;
+ mmc3_common_initialize(0x1f, 0xff, 0);
+}
+
+void nes_bmc_gold7in1_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg_written));
+}
+
+void nes_bmc_gold7in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg_written = 0;
+ mmc3_common_initialize(0x1f, 0xff, 0);
+}
+
+void nes_bmc_gc6in1_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_bmc_gc6in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ mmc3_common_initialize(0xff, 0xff, 0);
+ m_reg[0] = 0x00;
+ m_reg[1] = 0xff;
+ m_reg[2] = 0x03;
+ m_reg[3] = 0;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+}
+
+void nes_bmc_411120c_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_bmc_411120c_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg = 0;
+ mmc3_common_initialize(0x7f, 0x7f, 0);
+}
+
+void nes_bmc_830118c_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_bmc_830118c_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg = 0;
+ mmc3_common_initialize(0x7f, 0x7f, 0);
+}
+
+void nes_pjoy84_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_pjoy84_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ memset(m_reg, 0, sizeof(m_reg));
+ set_base_mask();
+ mmc3_common_initialize(m_prg_mask, m_chr_mask, 0);
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bootleg Board by Nitra
+
+ Games: Time Diver Avenger
+
+ This acts basically like a MMC3 with different use of write
+ address.
+
+ iNES: mapper 250
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_nitra_device::write_h)
+{
+ LOG_MMC(("nitra write_h, offset: %04x, data: %02x\n", offset, data));
+
+ txrom_write(space, (offset & 0x6000) | ((offset & 0x400) >> 10), offset & 0xff, mem_mask);
+}
+
+/*-------------------------------------------------
+
+ Board UNL-KS7057
+
+ Games: Street Fighter VI / Fight Street VI
+
+ MMC3 clone (identical, but for switched address lines)
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ks7057_device::write_h)
+{
+ LOG_MMC(("ks7057 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ offset = (BIT(offset, 0) << 1) | BIT(offset, 1) | (offset & ~0x03);
+ txrom_write(space, offset, data, mem_mask);
+}
+
+/*-------------------------------------------------
+
+ BTL-SUPERBROS11
+
+ Games: Super Mario Bros. 11, Super Mario Bros. 17
+
+ This acts basically like a MMC3 with different use of write
+ address.
+
+ iNES: mapper 196
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sbros11_device::write_h)
+{
+ LOG_MMC(("smb11 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ txrom_write(space, (offset & 0x6000) | ((offset & 0x04) >> 2), data, mem_mask);
+}
+
+/*-------------------------------------------------
+
+ UNL-MALISB
+
+ Games: Super Mali Bros Splash Bomb
+
+ This is very similar to mapper 196, but with additional
+ data bit swap.
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_malisb_device::prg_cb(int start, int bank)
+{
+ bank = (bank & 3) | ((bank & 8) >> 1) | ((bank & 4) << 1);
+ prg8_x(start, bank);
+}
+
+void nes_malisb_device::chr_cb(int start, int bank, int source)
+{
+ bank = (bank & 0xdd) | ((bank & 0x20) >> 4) | ((bank & 2) << 4);
+ chr1_x(start, bank, source);
+}
+
+WRITE8_MEMBER(nes_malisb_device::write_h)
+{
+ LOG_MMC(("malisb write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset > 0x4000)
+ txrom_write(space, (offset & 0xfffe) | ((offset & 0x04) >> 2) | ((offset & 0x08) >> 3), data, mem_mask);
+ else
+ txrom_write(space, (offset & 0xfffe) | ((offset & 0x08) >> 3), data, mem_mask);
+}
+
+/*-------------------------------------------------
+
+ BMC-FAMILY-4646B
+
+ Known Boards: Unknown Multigame Bootleg Board (4646B)
+ Games: 2 in 1 - Family Kid & Aladdin 4
+
+ MMC3 clone
+
+ iNES: mapper 134
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_family4646_device::write_m)
+{
+ LOG_MMC(("family4646 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x01)
+ {
+ m_prg_base = (data & 0x02) << 4;
+ m_prg_mask = 0x1f;
+ m_chr_base = (data & 0x20) << 3;
+ m_chr_mask = 0xff;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+/*-------------------------------------------------
+
+ BTL-PIKACHUY2K
+
+ Games: Pikachu Y2k
+
+ iNES: mapper 254
+
+ In MESS:
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_pikay2k_device::write_h)
+{
+ LOG_MMC(("pikay2k write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x2001:
+ m_reg[1] = data;
+ break;
+
+ case 0x2000:
+ m_reg[0] = 0;
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+// strange WRAM usage: it is protected at start, and gets unprotected after the first write to 0xa000
+WRITE8_MEMBER(nes_pikay2k_device::write_m)
+{
+ LOG_MMC(("pikay2k write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_prgram[offset & 0x1fff] = data;
+}
+
+READ8_MEMBER(nes_pikay2k_device::read_m)
+{
+ LOG_MMC(("pikay2k read_m, offset: %04x\n", offset));
+
+ return m_prgram[offset & 0x1fff] ^ (m_reg[0] & m_reg[1]);
+}
+
+/*-------------------------------------------------
+
+ Board UNL-8237
+
+ Games: Pocahontas 2
+
+ MMC3 clone
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_8237_device::prg_cb(int start, int bank)
+{
+ if (!(m_reg[0] & 0x80))
+ prg8_x(start, bank);
+}
+
+void nes_8237_device::chr_cb(int start, int bank, int source)
+{
+ bank |= ((m_reg[1] << 6) & 0x100);
+ chr1_x(start, bank, source);
+}
+
+WRITE8_MEMBER(nes_8237_device::write_l)
+{
+ LOG_MMC(("unl_8237 write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ m_reg[0] = data;
+ if (m_reg[0] & 0x80)
+ {
+ if (m_reg[0] & 0x20)
+ prg32((m_reg[0] & 0x0f) >> 1);
+ else
+ {
+ prg16_89ab(m_reg[0] & 0x1f);
+ prg16_cdef(m_reg[0] & 0x1f);
+ }
+ }
+ else
+ set_prg(m_prg_base, m_prg_mask);
+ }
+
+ if (offset == 0x1001)
+ {
+ m_reg[1] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+
+ if (offset == 0x1007)
+ {
+ m_reg[2] = data & 0x07; // this selects different permutations for addresses and regs (to be implemented)
+ }
+}
+
+WRITE8_MEMBER(nes_8237_device::write_h)
+{
+ static const UINT8 conv_table[8] = {0, 2, 6, 1, 7, 3, 4, 5};
+ LOG_MMC(("unl_8237 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ case 0x1000:
+ set_nt_mirroring((data | (data >> 7)) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x2000:
+ case 0x3000:
+ m_cd_enable = 1;
+ data = (data & 0xc0) | conv_table[data & 0x07];
+ txrom_write(space, 0x0000, data, mem_mask);
+ break;
+
+ case 0x4000:
+ case 0x5000:
+ if (m_cd_enable)
+ {
+ m_cd_enable = 0;
+ txrom_write(space, 0x0001, data, mem_mask);
+ }
+ break;
+
+ case 0x6000:
+ break;
+
+ case 0x7000:
+ txrom_write(space, 0x6001, data, mem_mask);
+ txrom_write(space, 0x4000, data, mem_mask);
+ txrom_write(space, 0x4001, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by Super Game
+
+ Games: The Lion King
+
+ MMC3 clone.
+
+ iNES: mapper 114
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sglionk_device::write_m)
+{
+ LOG_MMC(("sglionk write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_reg = data;
+
+ if (m_reg & 0x80)
+ {
+ prg16_89ab(data & 0x1f);
+ prg16_cdef(data & 0x1f);
+ }
+ else
+ set_prg(m_prg_base, m_prg_mask);
+
+}
+
+WRITE8_MEMBER(nes_sglionk_device::write_h)
+{
+ static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4};
+ LOG_MMC(("sglionk write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x6000)
+ {
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x2000:
+ m_reg_enabled = 1;
+ data = (data & 0xc0) | conv_table[data & 0x07];
+ txrom_write(space, 0x0000, data, mem_mask);
+ break;
+ case 0x4000:
+ if (m_reg_enabled && (m_reg & 0x80) == 0)
+ {
+ m_reg_enabled = 0;
+ txrom_write(space, 0x0001, data, mem_mask);
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (offset & 0x03)
+ {
+ case 0x02:
+ txrom_write(space, 0x6000, data, mem_mask);
+ break;
+ case 0x03:
+ txrom_write(space, 0x6001, data, mem_mask);
+ txrom_write(space, 0x4000, data, mem_mask);
+ txrom_write(space, 0x4001, data, mem_mask);
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by Super Game
+
+ Games: Boogerman, Mortal Kombat III
+
+ MMC3 clone. Also, it probably needs a hack to support both
+ variants (Boogerman & MK3).
+
+ iNES: mapper 215
+
+ In MESS: Preliminary support.
+
+ -------------------------------------------------*/
+
+void nes_sgboog_device::prg_cb(int start, int bank)
+{
+ if (!(m_reg[0] & 0x80)) // if this is != 0 we should never even arrive here
+ {
+ if (m_reg[1] & 0x08)
+ bank = (bank & 0x1f) | 0x20;
+ else
+ bank = (bank & 0x0f) | (m_reg[1] & 0x10);
+
+ prg8_x(start, bank);
+ }
+}
+
+void nes_sgboog_device::chr_cb(int start, int bank, int source)
+{
+ if ((m_reg[1] & 0x04))
+ bank |= 0x100;
+ else
+ bank = (bank & 0x7f) | ((m_reg[1] & 0x10) << 3);
+
+ chr1_x(start, bank, source);
+}
+
+void nes_sgboog_device::set_prg(int prg_base, int prg_mask)
+{
+ if (m_reg[0] & 0x80)
+ {
+ prg16_89ab((m_reg[0] & 0xf0) | (m_reg[1] & 0x10));
+ prg16_cdef((m_reg[0] & 0xf0) | (m_reg[1] & 0x10));
+ }
+ else
+ {
+ // here standard MMC3 bankswitch
+ UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0;
+
+ prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask));
+ prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask));
+ prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask));
+ prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask));
+ }
+}
+
+WRITE8_MEMBER(nes_sgboog_device::write_l)
+{
+ LOG_MMC(("sgboog write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ m_reg[0] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ }
+ else if (offset == 0x1001)
+ {
+ m_reg[1] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+ else if (offset == 0x1007)
+ {
+ m_latch = 0;
+ m_mode = data;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+WRITE8_MEMBER(nes_sgboog_device::write_m)
+{
+ LOG_MMC(("sgboog write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x0000)
+ {
+ m_reg[0] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ }
+ else if (offset == 0x0001)
+ {
+ m_reg[1] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+ else if (offset == 0x0007)
+ {
+ m_latch = 0;
+ m_mode = data;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+WRITE8_MEMBER(nes_sgboog_device::write_h)
+{
+ static const UINT8 conv_table[8] = {0,2,5,3,6,1,7,4};
+ LOG_MMC(("sgboog write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_mode)
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ break;
+
+ case 0x0001:
+ if (m_reg[2] && ((m_reg[0] & 0x80) == 0 || (m_latch & 0x07) < 6)) // if we use the prg16 banks and cmd=6,7 DON'T enter!
+ {
+ m_reg[2] = 0;
+ txrom_write(space, 0x0001, data, mem_mask);
+ }
+ break;
+
+ case 0x2000:
+ data = (data & 0xc0) | conv_table[data & 0x07];
+ m_reg[2] = 1;
+ txrom_write(space, 0x0000, data, mem_mask);
+ break;
+
+ case 0x4000:
+ set_nt_mirroring(((data >> 7) | data) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x4001:
+ txrom_write(space, 0x6001, data, mem_mask);
+ break;
+
+ case 0x6001:
+ txrom_write(space, 0x4000, data, mem_mask);
+ txrom_write(space, 0x4001, data, mem_mask);
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+ }
+ else
+ txrom_write(space, offset, data, mem_mask);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by Kasing
+
+ Games: AV Jiu Ji Mahjong, Bao Qing Tian, Thunderbolt 2,
+ Shisen Mahjong 2
+
+ MMC3 clone
+
+ iNES: mapper 115
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_kasing_device::prg_cb(int start, int bank)
+{
+ if (BIT(m_reg, 7))
+ prg32(m_reg >> 1);
+ else
+ prg8_x(start, bank);
+}
+
+WRITE8_MEMBER(nes_kasing_device::write_m)
+{
+ LOG_MMC(("kasing write_m, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x01)
+ {
+ case 0x00:
+ m_reg = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ case 0x01:
+ m_chr_base = (data & 0x01) ? 0x100 : 0x000;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by Kay (for Panda Prince)
+
+ Games: The Panda Prince, Sonic 3d Blast 6, SFZ2 '97, YuYu '97
+ (and its title hack MK6), UMK3, Super Lion King 2
+
+ MMC3 clone. This is basically KOF96 board + protection
+
+ iNES: mapper 121
+
+ In MESS: Most game works, with some graphical issues.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_kay_device::write_l)
+{
+ LOG_MMC(("kay write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ {
+ switch (data & 0x03)
+ {
+ case 0x00:
+ case 0x01:
+ m_low_reg = 0x83;
+ break;
+ case 0x02:
+ m_low_reg = 0x42;
+ break;
+ case 0x03:
+ m_low_reg = 0x00;
+ break;
+ }
+ }
+}
+
+READ8_MEMBER(nes_kay_device::read_l)
+{
+ LOG_MMC(("kay read_l, offset: %04x\n", offset));
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ return m_low_reg;
+ else
+ return 0xff;
+}
+
+void nes_kay_device::update_regs()
+{
+ switch (m_reg[5] & 0x3f)
+ {
+ case 0x20:
+ case 0x29:
+ case 0x2b:
+ case 0x3f:
+ m_reg[7] = 1;
+ m_reg[1] = m_reg[6];
+ break;
+ case 0x26:
+ m_reg[7] = 0;
+ m_reg[1] = m_reg[6];
+ break;
+ case 0x2c:
+ m_reg[7] = 1;
+ if (m_reg[6])
+ m_reg[1] = m_reg[6];
+ break;
+
+ case 0x28:
+ m_reg[7] = 0;
+ m_reg[2] = m_reg[6];
+ break;
+
+ case 0x2a:
+ m_reg[7] = 0;
+ m_reg[3] = m_reg[6];
+ break;
+
+ case 0x2f:
+ break;
+
+ default:
+ m_reg[5] = 0;
+ break;
+ }
+}
+
+void nes_kay_device::prg_cb(int start, int bank)
+{
+ if (m_reg[5] & 0x3f)
+ {
+ prg8_x(start, bank & 0x3f);
+ prg8_ef(m_reg[1]);
+ prg8_cd(m_reg[2]);
+ prg8_ab(m_reg[3]);
+ }
+ else
+ prg8_x(start, bank & 0x3f);
+}
+
+void nes_kay_device::chr_cb(int start, int bank, int source)
+{
+ UINT8 chr_page = (m_latch & 0x80) >> 5;
+
+ if ((start & 0x04) == chr_page)
+ bank |= 0x100;
+
+ chr1_x(start, bank, source);
+}
+
+WRITE8_MEMBER(nes_kay_device::write_h)
+{
+ LOG_MMC(("kay write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6003)
+ {
+ case 0x0000:
+ txrom_write(space, offset, data, mem_mask);
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+
+ case 0x0001:
+ m_reg[6] = (BIT(data, 0) << 5) | (BIT(data, 1) << 4) | (BIT(data, 2) << 3)
+ | (BIT(data, 3) << 2) | (BIT(data, 4) << 1) | BIT(data, 5);
+ if (!m_reg[7])
+ update_regs();
+ txrom_write(space, offset, data, mem_mask);
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+
+ case 0x0003:
+ m_reg[5] = data;
+ update_regs();
+ txrom_write(space, 0x0000, data, mem_mask);
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ UNL-H2288
+
+ -------------------------------------------------*/
+
+void nes_h2288_device::prg_cb(int start, int bank)
+{
+ if (!(m_reg[0] & 0x40))
+ prg8_x(start, bank);
+}
+
+WRITE8_MEMBER(nes_h2288_device::write_l)
+{
+ LOG_MMC(("h2288 write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x1800)
+ {
+ m_reg[offset & 1] = data;
+ if (m_reg[0] & 0x40)
+ {
+ UINT8 helper1 = (m_reg[0] & 0x05) | ((m_reg[0] >> 2) & 0x0a);
+ UINT8 helper2 = BIT(m_reg[0], 1);
+ prg16_89ab(helper1 & ~helper2);
+ prg16_cdef(helper1 | helper2);
+ }
+ else
+ set_prg(m_prg_base, m_prg_mask);
+ }
+}
+
+READ8_MEMBER(nes_h2288_device::read_l)
+{
+ LOG_MMC(("h2288 read_l, offset: %04x\n", offset));
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ {
+ int helper = offset >> 8;
+ if (offset & 1)
+ return helper | 0x01;
+ else
+ return helper ^ 0x01;
+ }
+
+ return 0;
+}
+
+WRITE8_MEMBER(nes_h2288_device::write_h)
+{
+ static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4};
+ LOG_MMC(("h2288 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ txrom_write(space, 0x0000, (data & 0xc0) | conv_table[data & 0x07], mem_mask);
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ UNL-603-5052
+
+ MMC3 + protection access in 0x4020 - 0x7fff
+
+ in MESS: Partial support
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_6035052_device::write_ex)
+{
+ LOG_MMC(("6035052 write_ex, offset: %04x, data: %02x\n", offset, data));
+ m_prot = data & 0x03;
+ if (m_prot == 1)
+ m_prot = 2;
+}
+
+READ8_MEMBER(nes_6035052_device::read_ex)
+{
+ LOG_MMC(("6035052 read_ex, offset: %04x\n", offset));
+ return m_prot;
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board 'Thunder Warrior' by TXC
+
+ Games: Master Fighter II, Master Fighter 3, Thunder Warrior
+
+ MMC3 clone
+
+ iNES: mapper 189
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_txc_tw_device::write_l)
+{
+ LOG_MMC(("txc_tw write_l, offset: %04x, data: %02x\n", offset, data));
+
+ prg32((data >> 4) | data);
+}
+
+/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */
+void nes_txc_tw_device::prg_cb(int start, int bank)
+{
+ return;
+}
+
+/*-------------------------------------------------
+
+ Board UNL-KOF97
+
+ Games: King of Fighters 97 (Rex Soft)
+
+ MMC3 clone
+
+ In MESS: Not working
+
+ -------------------------------------------------*/
+
+inline UINT8 kof97_unscramble( UINT8 data )
+{
+ return ((data >> 1) & 0x01) | ((data >> 4) & 0x02) | ((data << 2) & 0x04) | ((data >> 0) & 0xd8) | ((data << 3) & 0x20);
+}
+
+WRITE8_MEMBER(nes_kof97_device::write_h)
+{
+ LOG_MMC(("kof97 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ /* Addresses 0x9000, 0xa000, 0xd000 & 0xf000 behaves differently than MMC3 */
+ if (offset == 0x1000)
+ txrom_write(space, 0x0001, kof97_unscramble(data), mem_mask);
+ else if (offset == 0x2000)
+ txrom_write(space, 0x0000, kof97_unscramble(data), mem_mask);
+ else if (offset == 0x5000)
+ txrom_write(space, 0x4001, kof97_unscramble(data), mem_mask);
+ else if (offset == 0x7000)
+ txrom_write(space, 0x6001, kof97_unscramble(data), mem_mask);
+ /* Other addresses behaves like MMC3, up to unscrambling data */
+ else
+ txrom_write(space, offset, kof97_unscramble(data), mem_mask);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board for KOF96
+
+ Games: The King of Fighters 96, Sonic 3D Blast 6, Street
+ Fighter Zero 2
+
+ MMC3 clone
+
+ iNES: mapper 187
+
+ In MESS: Preliminary Support.
+
+ -------------------------------------------------*/
+
+void nes_kof96_device::prg_cb(int start, int bank)
+{
+ if (!(m_reg[0] & 0x80))
+ prg8_x(start, bank);
+}
+
+void nes_kof96_device::chr_cb(int start, int bank, int source)
+{
+ UINT8 chr_page = (m_latch & 0x80) >> 5;
+
+ if ((start & 0x04) == chr_page)
+ bank |= 0x100;
+
+ chr1_x(start, bank, source);
+}
+
+WRITE8_MEMBER(nes_kof96_device::write_l)
+{
+ UINT8 new_bank;
+ LOG_MMC(("kof96 write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ m_reg[0] = data;
+
+ if (m_reg[0] & 0x80)
+ {
+ new_bank = (m_reg[0] & 0x1f);
+
+ if (m_reg[0] & 0x20)
+ prg32(new_bank >> 2);
+ else
+ {
+ prg16_89ab(new_bank);
+ prg16_cdef(new_bank);
+ }
+ }
+ else
+ set_prg(m_prg_base, m_prg_mask);
+ }
+
+ if (offset >= 0x1000)
+ {
+ switch (data & 0x03)
+ {
+ case 0x00:
+ case 0x01:
+ m_reg[1] = 0x83;
+ break;
+ case 0x02:
+ m_reg[1] = 0x42;
+ break;
+ case 0x03:
+ m_reg[1] = 0x00;
+ break;
+ }
+
+ }
+
+ if (!m_reg[3] && offset > 0x1000)
+ {
+ m_reg[3] = 1;
+ space.write_byte(0x4017, 0x40);
+ }
+}
+
+READ8_MEMBER(nes_kof96_device::read_l)
+{
+ LOG_MMC(("kof96 read_l, offset: %04x\n", offset));
+ offset += 0x100;
+
+ if (!(offset < 0x1000))
+ return m_reg[1];
+ else
+ return 0;
+}
+
+WRITE8_MEMBER(nes_kof96_device::write_h)
+{
+ LOG_MMC(("kof96 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6003)
+ {
+ case 0x0000:
+ m_reg[2] = 1;
+ txrom_write(space, 0x0000, data, mem_mask);
+ break;
+
+ case 0x0001:
+ if (m_reg[2])
+ txrom_write(space, 0x0001, data, mem_mask);
+ break;
+
+ case 0x0002:
+ break;
+
+ case 0x0003:
+ m_reg[2] = 0;
+
+ if (data == 0x28)
+ prg8_cd(0x17);
+ else if (data == 0x2a)
+ prg8_ab(0x0f);
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board for Super Fighter III
+
+ MMC3 clone
+
+ iNES: mapper 197
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_sf3_device::set_chr(UINT8 chr_source, int chr_base, int chr_mask)
+{
+ chr4_0(chr_base | ((m_mmc_vrom_bank[0] >> 1) & chr_mask), chr_source);
+ chr2_4(chr_base | (m_mmc_vrom_bank[1] & chr_mask), chr_source);
+ chr2_6(chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr_source);
+}
+
+WRITE8_MEMBER(nes_sf3_device::write_h)
+{
+ UINT8 cmd;
+ LOG_MMC(("sf3 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ cmd = m_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: case 2: case 4:
+ m_mmc_vrom_bank[cmd >> 1] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ m_mmc_prg_bank[cmd - 6] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ }
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board 37017 (?) by Gouder
+
+ Games: Street Fighter IV
+
+ MMC3 clone. It also requires reads from 0x5000-0x7fff.
+
+ iNES: mapper 208
+
+ In MESS: Preliminary Support.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_gouder_device::write_l)
+{
+ static const UINT8 conv_table[256] =
+ {
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09,
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01,
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09,
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01,
+ 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08,
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00,
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08,
+ 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00,
+ 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+ };
+
+ LOG_MMC(("gouder write_l, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset < 0x1700))
+ m_reg[offset & 0x03] = data ^ conv_table[m_reg[4]];
+ else if (!(offset < 0xf00))
+ m_reg[4] = data;
+ else if (!(offset < 0x700))
+ prg32(((data >> 3) & 0x02) | (data & 0x01));
+}
+
+READ8_MEMBER(nes_gouder_device::read_l)
+{
+ LOG_MMC(("gouder read_l, offset: %04x\n", offset));
+
+ if (!(offset < 0x1700))
+ return m_reg[offset & 0x03];
+
+ return 0x00;
+}
+
+/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */
+void nes_gouder_device::prg_cb(int start, int bank)
+{
+ return;
+}
+
+
+/*-------------------------------------------------
+
+ UNL-SA-9602B
+
+ Sachen boards used for a chinese port of Princess Maker (?)
+
+ in MESS: Very Preliminary support
+
+ -------------------------------------------------*/
+
+/* This PCB can map PRG RAM to 0x8000-0xdfff like MMC5 */
+void nes_sa9602b_device::prgram_bank8_x(int start, int bank)
+{
+ assert(start < 4);
+ assert(bank >= 0);
+
+ bank &= (m_prgram_size / 0x2000) - 1;
+
+ // PRG RAM is mapped after PRG ROM
+ m_prg_bank[start] = m_prg_chunks + bank;
+ m_prg_bank_mem[start]->set_entry(m_prg_bank[start]);
+}
+
+void nes_sa9602b_device::prg_cb(int start, int bank)
+{
+ if (m_use_prgram)
+ prgram_bank8_x(start, bank);
+ else
+ prg8_x(start, bank);
+
+ if (m_latch & 0x40)
+ prg8_89(m_prg_chunks-2);
+ else
+ prg8_cd(m_prg_chunks-2);
+
+ prg8_ef(m_prg_chunks-1);
+// printf("start %d, bank %d\n", start, bank);
+}
+
+
+WRITE8_MEMBER( nes_sa9602b_device::write_h )
+{
+ LOG_MMC(("sa9602b write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ m_reg = data;
+ break;
+ case 0x0001:
+ if ((m_reg & 7) < 6)
+ m_use_prgram = (data & 0xc0);
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ default:
+ txrom_write(space, offset, data);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ UNL-SHERO
+
+ Sachen boards used for Street Heroes
+
+ in MESS: Very Preliminary support
+
+ -------------------------------------------------*/
+
+
+void nes_sachen_shero_device::chr_cb( int start, int bank, int source )
+{
+ int shift = start < 2 ? 5 :
+ start < 4 ? 6 :
+ start < 6 ? 8 : 7;
+ if (!BIT(m_reg, 6))
+ chr1_x(start, ((m_reg << shift) & 0x100) | bank, source);
+}
+
+
+WRITE8_MEMBER( nes_sachen_shero_device::write_l )
+{
+ LOG_MMC(("shero write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x4100;
+
+ if (offset == 0x4100)
+ {
+ m_reg = data;
+ if (BIT(m_reg, 6))
+ chr8(0, CHRRAM);
+ else
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+READ8_MEMBER( nes_sachen_shero_device::read_l )
+{
+ LOG_MMC(("shero read_l, offset: %04x\n", offset));
+ offset += 0x4100;
+
+ if (offset == 0x4100)
+ {
+ // DSW read!
+ }
+ return (offset & 0xff00) >> 8; // open bus
+}
+
+
+/*-------------------------------------------------
+
+ UNL-A9746
+
+
+ MMC3 clone
+
+
+ In MESS: Very Preliminary Support
+
+ -------------------------------------------------*/
+
+void nes_a9746_device::update_banks(UINT8 value)
+{
+ UINT8 bank = BITSWAP8(value & 0x3c,7,6,0,1,2,3,4,5);
+
+ switch (m_reg[0])
+ {
+ case 0x26: prg8_89(bank); break;
+ case 0x25: prg8_ab(bank); break;
+ case 0x24: prg8_cd(bank); break;
+ case 0x23: prg8_ef(bank); break;
+ }
+
+ switch (m_reg[1])
+ {
+ case 0x08: case 0x0a: case 0x0c: case 0x0e:
+ case 0x10: case 0x12: case 0x14: case 0x16:
+ case 0x18: case 0x1a: case 0x1c: case 0x1e:
+ m_reg[2] = (value << 4);
+ break;
+ case 0x09: chr1_0(m_reg[2] | (value >> 1), m_chr_source); break;
+ case 0x0b: chr1_1(m_reg[2] | (value >> 1) | 1, m_chr_source); break;
+ case 0x0d: chr1_2(m_reg[2] | (value >> 1), m_chr_source); break;
+ case 0x0f: chr1_3(m_reg[2] | (value >> 1) | 1, m_chr_source); break;
+ case 0x11: chr1_4(m_reg[2] | (value >> 1), m_chr_source); break;
+ case 0x15: chr1_5(m_reg[2] | (value >> 1), m_chr_source); break;
+ case 0x19: chr1_6(m_reg[2] | (value >> 1), m_chr_source); break;
+ case 0x1d: chr1_7(m_reg[2] | (value >> 1), m_chr_source); break;
+ }
+}
+
+WRITE8_MEMBER(nes_a9746_device::write_h)
+{
+ LOG_MMC(("unl_a9746 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6003)
+ {
+ case 0x0000:
+ m_reg[1] = data;
+ m_reg[0] = 0;
+ break;
+ case 0x0001:
+ update_banks(data);
+ break;
+ case 0x0002:
+ m_reg[0] = data;
+ m_reg[1] = 0;
+ break;
+
+ case 0x0003:
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+
+ MULTIGAME CARTS BASED ON MMC3
+
+ -------------------------------------------------*/
+
+ /*-------------------------------------------------
+
+ Board BMC-FK23C
+
+ MMC3 clone
+
+ In MESS: partially supported (still to sort initial banking
+ for many games)
+
+ -------------------------------------------------*/
+
+#if 0
+// alt version...
+void nes_fk23c_device::prg_cb(int start, int bank)
+{
+ if (((m_reg[0] & 0x07) - 3) > 1 && (!(m_reg[3] & 0x02) || start < 2))
+ {
+ if (m_reg[0] & 0x03)
+ bank = (bank & (0x3f >> (m_reg[0] & 0x03))) | (m_reg[1] << 1);
+
+ prg8_x(start, bank);
+ }
+}
+
+void nes_fk23c_device::chr_cb(int start, int bank, int source)
+{
+ if (!(m_reg[0] & 0x40) && (!(m_reg[3] & 0x02) || (start != 1 && start != 3)))
+ chr1_x(start, ((m_reg[2] & 0x7f) << 3) | bank, source);
+}
+
+#endif
+
+void nes_fk23c_device::prg_cb(int start, int bank)
+{
+ UINT8 mask = (0x3f >> (m_reg[0] & 0x03));
+
+ if ((m_reg[0] & 0x07) < 3)
+ {
+ if (!(m_reg[0] & 0x03))
+ bank = (bank & mask) | ((m_reg[1] & (0x7f ^ mask)) << 1);
+
+ prg8_x(start, bank);
+ }
+}
+
+void nes_fk23c_device::chr_cb(int start, int bank, int source)
+{
+ if (!(m_reg[0] & 0x40) && (!(m_reg[3] & 0x02) || (start != 1 && start != 3)))
+ chr1_x(start, ((m_reg[2] & 0x7f) << 3) | bank, source);
+}
+
+void nes_fk23c_device::fk23c_set_prg()
+{
+ if ((m_reg[0] & 0x07) == 4)
+ prg32((m_reg[1] & 0x7f) >> 1);
+ else if ((m_reg[0] & 0x07) == 3)
+ {
+ prg16_89ab(m_reg[1] & 0x7f);
+ prg16_cdef(m_reg[1] & 0x7f);
+ }
+ else
+ {
+ if (m_reg[3] & 0x02)
+ {
+ prg8_cd(m_reg[4]);
+ prg8_ef(m_reg[5]);
+ }
+ else
+ set_prg(m_prg_base, m_prg_mask);
+ }
+}
+
+void nes_fk23c_device::fk23c_set_chr()
+{
+ if (m_reg[0] & 0x40)
+ chr8(m_reg[2] | m_mmc_cmd1, m_chr_source);
+ else
+ {
+ if (m_reg[3] & 0x02)
+ {
+ int base = (m_reg[2] & 0x7f) << 3;
+ chr1_x(1, base | m_reg[6], m_chr_source);
+ chr1_x(3, base | m_reg[7], m_chr_source);
+ }
+ else
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+WRITE8_MEMBER(nes_fk23c_device::write_l)
+{
+ LOG_MMC(("fk23c write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ {
+ if (offset & (1 << 4)) // here it should be (4 + m_mmc_dipsetting)
+ {
+ m_reg[offset & 0x03] = data;
+
+ fk23c_set_prg();
+ fk23c_set_chr();
+ }
+ }
+}
+
+WRITE8_MEMBER(nes_fk23c_device::write_h)
+{
+ LOG_MMC(("fk23c write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_reg[0] & 0x40)
+ {
+ if (m_reg[0] & 0x30)
+ m_mmc_cmd1 = 0;
+ else
+ {
+ m_mmc_cmd1 = data & 0x03;
+ fk23c_set_chr();
+ }
+ }
+ else
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ if ((m_reg[3] & 0x02) && (m_latch & 0x08))
+ {
+ m_reg[4 | (m_latch & 0x03)] = data;
+ fk23c_set_prg();
+ fk23c_set_chr();
+ }
+ else
+ txrom_write(space, offset, data, mem_mask);
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ Board BMC-SUPER24IN1SC03
+
+ Games: Super 24-in-1
+
+ In MESS: Partially Supported
+
+ -------------------------------------------------*/
+
+void nes_s24in1sc03_device::prg_cb(int start, int bank)
+{
+ static const UINT8 masks[8] = {0x3f, 0x1f, 0x0f, 0x01, 0x03, 0x00, 0x00, 0x00};
+ int prg_base = m_reg[1] << 1;
+ int prg_mask = masks[m_reg[0] & 0x07];
+
+ bank = prg_base | (bank & prg_mask);
+ prg8_x(start, bank);
+}
+
+void nes_s24in1sc03_device::chr_cb(int start, int bank, int source)
+{
+ UINT8 chr = BIT(m_reg[0], 5) ? CHRRAM : CHRROM;
+ int chr_base = (m_reg[2] << 3) & 0xf00;
+
+ chr1_x(start, chr_base | bank, chr);
+}
+
+WRITE8_MEMBER(nes_s24in1sc03_device::write_l)
+{
+ LOG_MMC(("s24in1sc03 write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1ff0)
+ {
+ m_reg[0] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ set_prg(m_prg_base, m_prg_mask);
+ }
+
+ if (offset == 0x1ff1)
+ {
+ m_reg[1] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ }
+
+ if (offset == 0x1ff2)
+ {
+ m_reg[2] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-15IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 3 in 1, 15 in 1
+
+ iNES: mapper 205, MMC3 clone
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_15in1_device::write_m)
+{
+ LOG_MMC(("bmc_15in1 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x0800)
+ {
+ m_prg_base = (data & 0x03) << 4;
+ m_prg_mask = (data & 0x02) ? 0x0f : 0x1f;
+ m_chr_base = (data & 0x03) << 7;
+ m_chr_mask = (data & 0x02) ? 0x7f : 0xff;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-SUPERBIG-7IN1
+
+ Known Boards: Unknown Multigame Bootleg Board
+ Games: Kunio 8 in 1, Super Big 7 in 1
+
+ iNES: mapper 44
+
+ In MESS: Supported. It also uses mmc3_irq.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_sbig7_device::write_h)
+{
+ UINT8 page;
+ LOG_MMC(("bmc_sbig7 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x2001: /* $a001 - Select 128K ROM/VROM base (0..5) or last 256K ROM/VRAM base (6) */
+ page = (data & 0x07);
+ if (page > 6)
+ page = 6;
+
+ m_prg_base = page << 4;
+ m_prg_mask = (page > 5) ? 0x1f : 0x0f;
+ m_chr_base = page << 7;
+ m_chr_mask = (page > 5) ? 0xff : 0x7f;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-HIK8IN1
+
+ Known Boards: Unknown Multigame Bootleg Board
+ Games: Street Fighter V, various multigame carts
+
+ iNES: mapper 45
+
+ In MESS: Supported. It also uses mmc3_irq.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_hik8_device::write_m)
+{
+ LOG_MMC(("bmc_hik8 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ /* This bit is the "register lock". Once register are locked, writes go to WRAM
+ and there is no way to unlock them (except by resetting the machine) */
+ if ((m_reg[3] & 0x40) && m_prgram)
+ m_prgram[offset] = data;
+ else
+ {
+ m_reg[m_count] = data;
+ m_count = (m_count + 1) & 0x03;
+
+ if (!m_count)
+ {
+ LOG_MMC(("bmc_hik8 write_m, command completed %02x %02x %02x %02x\n", m_reg[3],
+ m_reg[2], m_reg[1], m_reg[0]));
+
+ m_prg_base = m_reg[1];
+ m_prg_mask = 0x3f ^ (m_reg[3] & 0x3f);
+ m_chr_base = ((m_reg[2] & 0xf0) << 4) | m_reg[0];
+ if (BIT(m_reg[2], 3))
+ m_chr_mask = (1 << ((m_reg[2] & 7) + 1)) - 1;
+ else if (m_reg[2])
+ m_chr_mask = 0;
+ else
+ m_chr_mask = 0xff; // i.e. we use the vrom_bank with no masking
+
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-SUPERHIK-4IN1
+
+ Known Boards: Unknown Multigame Bootleg Board
+ Games: Super HIK 4 in 1
+
+ iNES: mapper 49
+
+ In MESS: Supported. It also uses mmc3_irq.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_hik4_device::write_m)
+{
+ LOG_MMC(("bmc_hik4 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ /* mid writes only work when WRAM is enabled. not sure if I should
+ change the condition to m_mmc_latch2==0x80 (i.e. what is the effect of
+ the read-only bit?) */
+ if (m_wram_protect & 0x80)
+ {
+ if (data & 0x01) /* if this is 0, then we have 32k PRG blocks */
+ {
+ m_prg_base = (data & 0xc0) >> 2;
+ m_prg_mask = 0x0f;
+ set_prg(m_prg_base, m_prg_mask);
+ }
+ else
+ prg32((data & 0x30) >> 4);
+
+ m_chr_base = (data & 0xc0) << 1;
+ m_chr_mask = 0x7f;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-MARIOPARTY-7IN1
+
+ Known Boards: Unknown Multigame Bootleg Board
+ Games: Mario 7 in 1
+
+ MMC3 clone
+
+ iNES: mapper 52
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_mario7in1_device::write_m)
+{
+ UINT8 helper1, helper2;
+ LOG_MMC(("bmc_mario7in1 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ /* mid writes only work when WRAM is enabled. not sure if I should
+ change the condition to m_map52_reg_written == 0x80 (i.e. what is the effect of
+ the read-only bit?) and it only can happen once! */
+ if ((m_wram_protect & 0x80) && !m_reg_written)
+ {
+ helper1 = (data & 0x08);
+ helper2 = (data & 0x40);
+
+ m_prg_base = helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4);
+ m_prg_mask = helper1 ? 0x0f : 0x1f;
+ m_chr_base = ((data & 0x20) << 4) | ((data & 0x04) << 6) | (helper2 ? ((data & 0x10) << 3) : 0);
+ m_chr_mask = helper2 ? 0x7f : 0xff;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+
+ m_reg_written = 1;
+ }
+ else
+ m_prgram[offset] = data;
+}
+
+/*-------------------------------------------------
+
+ BMC-GOLD-7IN1
+
+ Known Boards: Unknown Multigame Bootleg Board
+ Games: Super HIK Gold 7 in 1, Golden 7 in 1 and many more
+
+ MMC3 clone, same as BMC-MARIOPARTY-7IN1 but with switched CHR
+ bank lines
+
+ iNES: mapper 52
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_gold7in1_device::write_m)
+{
+ UINT8 helper1, helper2;
+ LOG_MMC(("bmc_gold7in1 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if ((m_wram_protect & 0x80) && !m_reg_written)
+ {
+ helper1 = (data & 0x08);
+ helper2 = (data & 0x40);
+
+ m_prg_base = helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4);
+ m_prg_mask = helper1 ? 0x0f : 0x1f;
+ m_chr_base = ((data & 0x20) << 3) | ((data & 0x04) << 7) | (helper2 ? ((data & 0x10) << 3) : 0);
+ m_chr_mask = helper2 ? 0x7f : 0xff;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+
+ m_reg_written = BIT(data, 7); // mc_2hikg & mc_s3nt3 write here multiple time
+ }
+ else
+ m_prgram[offset] = data;
+}
+
+/*-------------------------------------------------
+
+ BMC-GOLDENCARD-6IN1
+
+ Known Boards: Unknown Bootleg Multigame Board
+ Games: Golden Card 6 in 1
+
+ MMC3 clone
+
+ iNES: mapper 217
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_bmc_gc6in1_device::prg_cb(int start, int bank)
+{
+ if (m_reg[1] & 0x08)
+ bank &= 0x1f;
+ else
+ {
+ bank &= 0x0f;
+ bank |= m_reg[1] & 0x10;
+ }
+
+ prg8_x(start, bank | ((m_reg[1] & 0x03) << 5));
+}
+
+void nes_bmc_gc6in1_device::chr_cb(int start, int bank, int source)
+{
+ if (!(m_reg[1] & 0x08))
+ bank = ((m_reg[1] & 0x10) << 3) | (bank & 0x7f);
+
+
+ bank |= ((m_reg[1] << 6) & 0x100);
+ chr1_x(start, ((m_reg[1] & 0x03) << 8) | bank, source);
+}
+
+WRITE8_MEMBER(nes_bmc_gc6in1_device::write_l)
+{
+ UINT8 bank;
+ LOG_MMC(("bmc_gc6in1 write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ m_reg[0] = data;
+ if (data & 0x80)
+ {
+ bank = (data & 0x0f) | ((m_reg[1] & 0x03) << 4);
+ prg16_89ab(bank);
+ prg16_cdef(bank);
+ }
+ else
+ set_prg(m_prg_base, m_prg_mask);
+ }
+ else if (offset == 0x1001)
+ {
+ m_reg[1] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ }
+ else if (offset == 0x1007)
+ {
+ m_reg[2] = data;
+ }
+}
+
+WRITE8_MEMBER(nes_bmc_gc6in1_device::write_h)
+{
+ UINT8 cmd;
+ static const UINT8 conv_table[8] = {0, 6, 3, 7, 5, 2, 4, 1};
+ LOG_MMC(("bmc_gc6in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (!m_reg[2])
+ {
+ // in this case we act like MMC3, only with alt prg/chr handlers
+ txrom_write(space, offset, data, mem_mask);
+ }
+ else
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ txrom_write(space, 0x4000, data, mem_mask);
+ break;
+
+ case 0x0001:
+ data = (data & 0xc0) | conv_table[data & 0x07];
+ m_reg[3] = 1;
+ txrom_write(space, 0x0000, data, mem_mask);
+ break;
+
+ case 0x2000:
+ cmd = m_latch & 0x07;
+ if (m_reg[3])
+ {
+ m_reg[3] = 0;
+ switch (cmd)
+ {
+ case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
+ case 2: case 3: case 4: case 5:
+ m_mmc_vrom_bank[cmd] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ m_mmc_prg_bank[cmd - 6] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ }
+ }
+ break;
+
+
+ case 0x2001:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-411120C
+
+
+ MMC3 clone
+
+
+ In MESS: Very Preliminary Support
+
+ -------------------------------------------------*/
+
+void nes_bmc_411120c_device::prg_cb(int start, int bank)
+{
+ if (m_reg & 8) // & 0xc when DSW change (diff menu?)
+ prg32(((m_reg >> 4) & 3) | 0x0c);
+ else
+ prg8_x(start, (bank & 0x0f) | ((m_reg & 0x03) << 4));
+}
+
+void nes_bmc_411120c_device::chr_cb(int start, int bank, int source)
+{
+ chr1_x(start, bank | ((m_reg & 3) << 7), source);
+}
+
+WRITE8_MEMBER(nes_bmc_411120c_device::write_m)
+{
+ LOG_MMC(("bmc_411120c write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_reg = data;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+}
+
+/*-------------------------------------------------
+
+ BMC-830118C
+
+
+ MMC3 clone
+
+
+ In MESS: Very Preliminary Support
+
+ -------------------------------------------------*/
+
+void nes_bmc_830118c_device::prg_cb(int start, int bank)
+{
+ if (m_reg & 0x0c != 0x0c)
+ prg8_x(start, (bank & 0x0f) | ((m_reg & 0x0c) << 2));
+ else
+ {
+ if (start == 0)
+ {
+ prg8_89((bank & 0x0f) | ((m_reg & 0x0c) << 2));
+ prg8_ab((bank & 0x0f) | 0x20);
+ }
+ else if (start == 2)
+ {
+ prg8_cd((bank & 0x0f) | ((m_reg & 0x0c) << 2));
+ prg8_ef((bank & 0x0f) | 0x20);
+ }
+ }
+}
+
+void nes_bmc_830118c_device::chr_cb(int start, int bank, int source)
+{
+ chr1_x(start, (bank & 0x7f) | ((m_reg & 0x0c) << 5), source);
+}
+
+WRITE8_MEMBER(nes_bmc_830118c_device::write_m)
+{
+ LOG_MMC(("bmc_830118c write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset >= 0x800 && offset < 0x900)
+ {
+ m_reg = data;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-POWERJOY
+
+ -------------------------------------------------*/
+
+void nes_pjoy84_device::prg_cb(int start, int bank)
+{
+ UINT8 flip = (m_latch & 0x40) ? 2 : 0;
+
+ if (!(m_reg[3] & 0x03))
+ prg8_x(start, bank);
+ else if (start == flip)
+ {
+ if ((m_reg[3] & 0x03) == 0x03)
+ prg32(bank >> 2);
+ else
+ {
+ prg16_89ab(bank >> 1);
+ prg16_cdef(bank >> 1);
+ }
+ }
+}
+
+void nes_pjoy84_device::chr_cb(int start, int bank, int source)
+{
+ if (!(m_reg[3] & 0x10))
+ chr1_x(start, bank, source);
+}
+
+inline void nes_pjoy84_device::set_base_mask()
+{
+ m_prg_base = ((m_reg[0] & (0x06 | BIT(m_reg[0], 6))) << 4) |
+ (BIT(m_reg[0], 4) << 7);
+
+ m_chr_base = ((~m_reg[0] << 0) & 0x080 & m_reg[2]) |
+ ((m_reg[0] << 4) & 0x080 & m_reg[0]) |
+ ((m_reg[0] << 3) & 0x100) |
+ ((m_reg[0] << 5) & 0x200);
+
+ m_prg_mask = BIT(m_reg[0], 6) ? 0x0f : 0x1f;
+ m_chr_mask = BIT(m_reg[0], 7) ? 0x7f : 0xff;
+}
+
+WRITE8_MEMBER(nes_pjoy84_device::write_m)
+{
+ LOG_MMC(("pjoy84 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x03)
+ {
+ case 0x00:
+ case 0x03:
+ if (m_reg[3] & 0x80)
+ return; // else we act as if offset & 3 = 1,2
+ case 0x01:
+ case 0x02:
+ m_reg[offset & 0x03] = data;
+ set_base_mask();
+ if (m_reg[3] & 0x10)
+ chr8((m_chr_base >> 3) | (m_reg[2] & 0x0f), m_chr_source);
+ else
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_mmc3_clones.h b/src/mess/machine/nes_mmc3_clones.h
new file mode 100644
index 00000000000..4f70bc03e67
--- /dev/null
+++ b/src/mess/machine/nes_mmc3_clones.h
@@ -0,0 +1,695 @@
+#ifndef __NES_MMC3_CLONES_H
+#define __NES_MMC3_CLONES_H
+
+#include "machine/nes_mmc3.h"
+
+
+// ======================> nes_nitra_device
+
+class nes_nitra_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_nitra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+};
+
+
+// ======================> nes_ks7057_device
+
+class nes_ks7057_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_ks7057_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+};
+
+
+// ======================> nes_sbros11_device
+
+class nes_sbros11_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_sbros11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+};
+
+
+// ======================> nes_malisb_device
+
+class nes_malisb_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_malisb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+};
+
+
+// ======================> nes_family4646_device
+
+class nes_family4646_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_family4646_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_pikay2k_device
+
+class nes_pikay2k_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_pikay2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[2];
+};
+
+
+// ======================> nes_8237_device
+
+class nes_8237_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_8237_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[3];
+ int m_cd_enable;
+};
+
+
+// ======================> nes_sglionk_device
+
+class nes_sglionk_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_sglionk_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg;
+ int m_reg_enabled;
+};
+
+
+// ======================> nes_sgboog_device
+
+class nes_sgboog_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_sgboog_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ virtual void set_prg(int prg_base, int prg_mask);
+ UINT8 m_reg[3];
+ UINT8 m_mode;
+};
+
+
+// ======================> nes_kasing_device
+
+class nes_kasing_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_kasing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual void prg_cb(int start, int bank);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg;
+};
+
+
+// ======================> nes_kay_device
+
+class nes_kay_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_kay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ void update_regs();
+ UINT8 m_reg[8];
+ UINT8 m_low_reg;
+};
+
+
+// ======================> nes_h2288_device
+
+class nes_h2288_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_h2288_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[2]; // reg 1 is unused?
+};
+
+
+// ======================> nes_6035052_device
+
+class nes_6035052_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_6035052_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_ex);
+ virtual DECLARE_WRITE8_MEMBER(write_ex);
+ virtual DECLARE_READ8_MEMBER(read_l) { return read_ex(space, offset, mem_mask); }
+ virtual DECLARE_READ8_MEMBER(read_m) { return read_ex(space, offset, mem_mask); }
+ virtual DECLARE_WRITE8_MEMBER(write_l) { write_ex(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE8_MEMBER(write_m) { write_ex(space, offset, data, mem_mask); }
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_prot;
+};
+
+
+// ======================> nes_txc_tw_device
+
+class nes_txc_tw_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_txc_tw_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m) { write_l(space, offset & 0xff, data, mem_mask); } // offset does not really count for this mapper }
+ virtual void prg_cb(int start, int bank);
+};
+
+
+// ======================> nes_kof97_device
+
+class nes_kof97_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_kof97_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+};
+
+
+// ======================> nes_kof96_device
+
+class nes_kof96_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_kof96_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h); // offset does not really count for this mapper
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[3];
+};
+
+
+// ======================> nes_sf3_device
+
+class nes_sf3_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_sf3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+protected:
+ virtual void set_chr(UINT8 chr, int chr_base, int chr_mask);
+};
+
+
+// ======================> nes_gouder_device
+
+class nes_gouder_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_gouder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual void prg_cb(int start, int bank);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[5];
+};
+
+
+// ======================> nes_sa9602b_device
+
+class nes_sa9602b_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_sa9602b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+
+ virtual void pcb_reset();
+
+private:
+ void prgram_bank8_x(int start, int bank);
+ UINT8 m_reg;
+ int m_use_prgram;
+};
+
+
+// ======================> nes_sachen_shero_device
+
+class nes_sachen_shero_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_shero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg;
+};
+
+
+// ======================> nes_a9746_device
+
+class nes_a9746_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_a9746_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void update_banks(UINT8 value);
+ UINT8 m_reg[3];
+};
+
+
+// ======================> nes_fk23c_device
+
+class nes_fk23c_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_fk23c_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);
+ nes_fk23c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+protected:
+ void fk23c_set_prg();
+ void fk23c_set_chr();
+ UINT8 m_reg[8];
+ UINT8 m_mmc_cmd1;
+};
+
+
+// ======================> nes_fk23ca_device
+
+class nes_fk23ca_device : public nes_fk23c_device
+{
+public:
+ // construction/destruction
+ nes_fk23ca_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_s24in1sc03_device
+
+class nes_s24in1sc03_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_s24in1sc03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[3];
+};
+
+
+// ======================> nes_bmc_15in1_device
+
+class nes_bmc_15in1_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_15in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_sbig7_device
+
+class nes_bmc_sbig7_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_sbig7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_hik8_device
+
+class nes_bmc_hik8_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_hik8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[4];
+ UINT8 m_count;
+};
+
+
+// ======================> nes_bmc_hik4_device
+
+class nes_bmc_hik4_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_hik4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_mario7in1_device
+
+class nes_bmc_mario7in1_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_mario7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg_written;
+};
+
+
+// ======================> nes_bmc_gold7in1_device
+
+class nes_bmc_gold7in1_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_gold7in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg_written;
+};
+
+
+// ======================> nes_bmc_gc6in1_device
+
+class nes_bmc_gc6in1_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_gc6in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[3];
+};
+
+
+// ======================> nes_bmc_411120c_device
+
+class nes_bmc_411120c_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_411120c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg;
+};
+
+
+// ======================> nes_bmc_830118c_device
+
+class nes_bmc_830118c_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_830118c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg;
+};
+
+
+// ======================> nes_pjoy84_device
+
+class nes_pjoy84_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_pjoy84_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+private:
+ inline void set_base_mask();
+ UINT8 m_reg[4];
+};
+
+
+
+
+// device type definition
+extern const device_type NES_NITRA;
+extern const device_type NES_KS7057;
+extern const device_type NES_SBROS11;
+extern const device_type NES_MALISB;
+extern const device_type NES_FAMILY4646;
+extern const device_type NES_PIKAY2K;
+extern const device_type NES_8237;
+extern const device_type NES_SG_LIONK;
+extern const device_type NES_SG_BOOG;
+extern const device_type NES_KASING;
+extern const device_type NES_KAY;
+extern const device_type NES_H2288;
+extern const device_type NES_6035052;
+extern const device_type NES_TXC_TW;
+extern const device_type NES_KOF97;
+extern const device_type NES_KOF96;
+extern const device_type NES_SF3;
+extern const device_type NES_GOUDER;
+extern const device_type NES_SA9602B;
+extern const device_type NES_SACHEN_SHERO;
+extern const device_type NES_A9746;
+
+extern const device_type NES_FK23C;
+extern const device_type NES_FK23CA;
+extern const device_type NES_S24IN1SC03;
+extern const device_type NES_BMC_15IN1;
+extern const device_type NES_BMC_SBIG7;
+extern const device_type NES_BMC_HIK8;
+extern const device_type NES_BMC_HIK4;
+extern const device_type NES_BMC_MARIO7IN1;
+extern const device_type NES_BMC_GOLD7IN1;
+extern const device_type NES_BMC_GC6IN1;
+extern const device_type NES_BMC_411120C;
+extern const device_type NES_BMC_830118C;
+extern const device_type NES_PJOY84;
+
+#endif
diff --git a/src/mess/machine/nes_mmc5.c b/src/mess/machine/nes_mmc5.c
new file mode 100644
index 00000000000..2bf25a0fc4e
--- /dev/null
+++ b/src/mess/machine/nes_mmc5.c
@@ -0,0 +1,754 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Nintendo MMC-5 / ExROM
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the Nintendo MMC-5 / ExROM PCBs [mapper 5]
+
+
+ TODO:
+ - improve PPU code in order to support the two sets of registers used by MMC5
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_mmc5.h"
+
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE
+#include "sound/nes_apu.h" // temp hack to pass the additional sound regs to APU...
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_EXROM = &device_creator<nes_exrom_device>;
+
+
+nes_exrom_device::nes_exrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_EXROM, "NES Cart ExROM (MMC-5) PCB", tag, owner, clock, "nes_exrom", __FILE__)
+{
+}
+
+
+
+
+void nes_exrom_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_status));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_mult1));
+ save_item(NAME(m_mult2));
+ save_item(NAME(m_mmc5_scanline));
+ save_item(NAME(m_vrom_page_a));
+ save_item(NAME(m_vrom_page_b));
+ save_item(NAME(m_floodtile));
+ save_item(NAME(m_floodattr));
+ save_item(NAME(m_prg_mode));
+ save_item(NAME(m_chr_mode));
+ save_item(NAME(m_wram_base));
+ save_item(NAME(m_wram_protect_1));
+ save_item(NAME(m_wram_protect_2));
+ save_item(NAME(m_mmc5_last_chr_a)); // basically unused in current code
+ save_item(NAME(m_high_chr));
+ save_item(NAME(m_split_scr));
+ save_item(NAME(m_split_ctrl));
+ save_item(NAME(m_split_yst));
+ save_item(NAME(m_split_bank));
+ save_item(NAME(m_prg_regs));
+ save_item(NAME(m_vrom_bank));
+
+ m_exram = auto_alloc_array_clear(machine(), UINT8, 0x400);
+ save_pointer(NAME(m_exram), 0x400);
+
+ m_mapper_sram_size = 0x400;
+ m_mapper_sram = m_exram;
+}
+
+void nes_exrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 2);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_count = 0;
+ m_irq_status = 0;
+ m_irq_enable = 0;
+
+ m_mult1 = m_mult2 = 0;
+ m_mmc5_scanline = 0;
+ m_vrom_page_a = m_vrom_page_b = 0;
+
+ m_floodtile = m_floodattr = 0;
+
+ m_prg_mode = 3;
+ m_chr_mode = 0;
+ m_wram_base = 0;
+ m_wram_protect_1 = 0;
+ m_wram_protect_2 = 0;
+ m_mmc5_last_chr_a = 1;
+ m_high_chr = 0;
+ m_split_scr = 0;
+ m_split_ctrl = 0;
+ m_split_yst = 0;
+ m_split_bank = 0;
+
+ memset(m_vrom_bank, 0x3ff, ARRAY_LENGTH(m_vrom_bank));
+ m_prg_regs[0] = 0xfc;
+ m_prg_regs[1] = 0xfd;
+ m_prg_regs[2] = 0xfe;
+ m_prg_regs[3] = 0xff;
+}
+
+
+READ8_MEMBER(nes_exrom_device::nt_r)
+{
+ int page = ((offset & 0xc00) >> 10);
+
+ if (m_nt_src[page] == MMC5FILL)
+ {
+ if ((offset & 0x3ff) >= 0x3c0)
+ return m_floodattr;
+
+ return m_floodtile;
+ }
+ return m_nt_access[page][offset & 0x3ff];
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ ExROM (MMC5 based) board emulation
+
+ Games: Castlevania III, Just Breed, many Koei titles
+
+ iNES: mapper 5
+
+ MESS status: Mostly Unsupported
+
+ -------------------------------------------------*/
+
+/* MMC5 can map PRG RAM to 0x8000-0xdfff */
+void nes_exrom_device::prgram_bank8_x(int start, int bank)
+{
+ assert(start < 4);
+ assert(bank >= 0);
+
+ bank &= (m_prgram_size / 0x2000) - 1;
+
+ // PRG RAM is mapped after PRG ROM
+ m_prg_bank[start] = m_prg_chunks + bank;
+ m_prg_bank_mem[start]->set_entry(m_prg_bank[start]);
+}
+
+
+void nes_exrom_device::update_prg()
+{
+ int bank0, bank1, bank2, bank3;
+
+ switch (m_prg_mode)
+ {
+ case 0: // 32k banks
+ bank3 = m_prg_regs[3];
+ prg32(bank3 >> 2);
+ break;
+
+ case 1: // 16k banks
+ bank1 = m_prg_regs[1];
+ bank3 = m_prg_regs[3];
+
+ if (!BIT(bank1, 7)) // PRG RAM
+ {
+ prgram_bank8_x(0, (bank1 & 0x06));
+ prgram_bank8_x(1, (bank1 & 0x06) + 1);
+ }
+ else
+ prg16_89ab(bank1 >> 1);
+
+ prg16_cdef(bank3);
+ break;
+
+ case 2: // 16k-8k banks
+ bank1 = m_prg_regs[1];
+ bank2 = m_prg_regs[2];
+ bank3 = m_prg_regs[3];
+
+ if (!BIT(bank1, 7))
+ {
+ prgram_bank8_x(0, (bank1 & 0x06));
+ prgram_bank8_x(1, (bank1 & 0x06) + 1);
+ }
+ else
+ prg16_89ab((bank1 & 0x7f) >> 1);
+
+ if (!BIT(bank2, 7))
+ prgram_bank8_x(2, bank2 & 0x07);
+ else
+ prg8_cd(bank2 & 0x7f);
+
+ prg8_ef(bank3);
+ break;
+
+ case 3: // 8k banks
+ bank0 = m_prg_regs[0];
+ bank1 = m_prg_regs[1];
+ bank2 = m_prg_regs[2];
+ bank3 = m_prg_regs[3];
+
+ if (!BIT(bank0, 7))
+ prgram_bank8_x(0, bank0 & 0x07);
+ else
+ prg8_89(bank0 & 0x7f);
+
+ if (!BIT(bank1, 7))
+ prgram_bank8_x(1, bank1 & 0x07);
+ else
+ prg8_ab(bank1 & 0x7f);
+
+ if (!BIT(bank2, 7))
+ prgram_bank8_x(2, bank2 & 0x07);
+ else
+ prg8_cd(bank2 & 0x7f);
+
+ prg8_ef(bank3);
+ break;
+ }
+}
+
+void nes_exrom_device::update_render_mode()
+{
+ // if m_exram_control is 0 or 1, m_exram must be used for NT
+}
+
+void nes_exrom_device::hblank_irq(int scanline, int vblank, int blanked )
+{
+#if 1
+ if (scanline == 0)
+ m_irq_status |= 0x40;
+ else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE)
+ m_irq_status &= ~0x40;
+#endif
+
+ if (scanline == m_irq_count)
+ {
+ if (m_irq_enable)
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+
+ m_irq_status = 0xff;
+ }
+
+ /* FIXME: this is ok, but then we would need to update them again when we have the BG Hblank
+ I leave it commented out until the PPU is updated for this */
+// if (ppu2c0x_is_sprite_8x16(m_ppu) || m_mmc5_last_chr_a)
+// update_chr_a();
+// else
+// update_chr_b();
+}
+
+void nes_exrom_device::set_mirror(int page, int src)
+{
+ switch (src)
+ {
+ case 0: /* CIRAM0 */
+ set_nt_page(page, CIRAM, 0, 1);
+ break;
+ case 1: /* CIRAM1 */
+ set_nt_page(page, CIRAM, 1, 1);
+ break;
+ case 2: /* ExRAM */
+ set_nt_page(page, EXRAM, 0, 1); // actually only works during rendering.
+ break;
+ case 3: /* Fill Registers */
+ set_nt_page(page, MMC5FILL, 0, 0);
+ break;
+ default:
+ fatalerror("This should never happen\n");
+ break;
+ }
+}
+
+READ8_MEMBER(nes_exrom_device::read_l)
+{
+ int value;
+
+ /* $5c00 - $5fff: extended videoram attributes */
+ if ((offset >= 0x1b00) && (offset <= 0x1eff))
+ {
+ return m_exram[offset - 0x1b00];
+ }
+
+ switch (offset)
+ {
+ case 0x1104: /* $5204 */
+#if 0
+ if (current_scanline == m_mmc5_scanline)
+ return 0x80;
+ else
+ return 0x00;
+#else
+ value = m_irq_status;
+ m_irq_status &= ~0x80;
+ return value;
+#endif
+
+ case 0x1105: /* $5205 */
+ return (m_mult1 * m_mult2) & 0xff;
+ case 0x1106: /* $5206 */
+ return ((m_mult1 * m_mult2) & 0xff00) >> 8;
+
+ default:
+ logerror("** MMC5 uncaught read, offset: %04x\n", offset + 0x4100);
+ return 0x00;
+ }
+}
+
+
+WRITE8_MEMBER(nes_exrom_device::write_l)
+{
+ // LOG_MMC(("Mapper 5 write, offset: %04x, data: %02x\n", offset + 0x4100, data));
+ /* Send $5000-$5015 to the sound chip */
+ if ((offset >= 0xf00) && (offset <= 0xf15))
+ {
+ device_t *m_sound = machine().device("nessound");
+ nes_psg_w(m_sound, space, offset & 0x1f, data);
+ return;
+ }
+
+ /* $5c00 - $5fff: extended videoram attributes */
+ if ((offset >= 0x1b00) && (offset <= 0x1eff))
+ {
+ if (m_exram_control != 0x03)
+ m_exram[offset - 0x1b00] = data;
+ return;
+ }
+
+ switch (offset)
+ {
+ case 0x1000: /* $5100 */
+ m_prg_mode = data & 0x03;
+ // update_prg();
+ LOG_MMC(("MMC5 rom bank mode: %02x\n", data));
+ break;
+
+ case 0x1001: /* $5101 */
+ m_chr_mode = data & 0x03;
+ // update chr
+ LOG_MMC(("MMC5 vrom bank mode: %02x\n", data));
+ break;
+
+ case 0x1002: /* $5102 */
+ m_wram_protect_1 = data & 0x03;
+ LOG_MMC(("MMC5 vram protect 1: %02x\n", data));
+ break;
+ case 0x1003: /* 5103 */
+ m_wram_protect_2 = data & 0x03;
+ LOG_MMC(("MMC5 vram protect 2: %02x\n", data));
+ break;
+
+ case 0x1004: /* $5104 - Extra VRAM (EXRAM) control */
+ m_exram_control = data & 0x03;
+ // update render
+ update_render_mode();
+ LOG_MMC(("MMC5 exram control: %02x\n", data));
+ break;
+
+ case 0x1005: /* $5105 */
+ set_mirror(0, (data & 0x03) >> 0);
+ set_mirror(1, (data & 0x0c) >> 2);
+ set_mirror(2, (data & 0x30) >> 4);
+ set_mirror(3, (data & 0xc0) >> 6);
+ // update render
+ update_render_mode();
+ break;
+
+ /* tile data for MMC5 flood-fill NT mode */
+ case 0x1006:
+ m_floodtile = data;
+ break;
+
+ /* attr data for MMC5 flood-fill NT mode */
+ case 0x1007:
+ switch (data & 3)
+ {
+ default:
+ case 0: m_floodattr = 0x00; break;
+ case 1: m_floodattr = 0x55; break;
+ case 2: m_floodattr = 0xaa; break;
+ case 3: m_floodattr = 0xff; break;
+ }
+ break;
+
+ case 0x1013: /* $5113 */
+ LOG_MMC(("MMC5 mid RAM bank select: %02x\n", data & 0x07));
+ m_wram_base = data & 0x07;
+ break;
+
+
+ case 0x1014: /* $5114 */
+ case 0x1015: /* $5115 */
+ case 0x1016: /* $5116 */
+ case 0x1017: /* $5117 */
+ m_prg_regs[offset & 3] = data;
+ update_prg();
+ break;
+
+ case 0x1020: /* $5120 */
+ LOG_MMC(("MMC5 $5120 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[0] = data | (m_high_chr << 8);
+// mapper5_sync_vrom(0);
+ chr1_0(m_vrom_bank[0], CHRROM);
+// m_nes_vram_sprite[0] = m_vrom_bank[0] * 64;
+// vrom_next[0] = 4;
+// vrom_page_a = 1;
+// vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1021: /* $5121 */
+ LOG_MMC(("MMC5 $5121 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x02:
+ /* 2k switch */
+ chr2_0(data | (m_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[1] = data | (m_high_chr << 8);
+// mapper5_sync_vrom(0);
+ chr1_1(m_vrom_bank[1], CHRROM);
+// m_nes_vram_sprite[1] = m_vrom_bank[0] * 64;
+// vrom_next[1] = 5;
+// vrom_page_a = 1;
+// vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1022: /* $5122 */
+ LOG_MMC(("MMC5 $5122 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[2] = data | (m_high_chr << 8);
+// mapper5_sync_vrom(0);
+ chr1_2(m_vrom_bank[2], CHRROM);
+// m_nes_vram_sprite[2] = m_vrom_bank[0] * 64;
+// vrom_next[2] = 6;
+// vrom_page_a = 1;
+// vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1023: /* $5123 */
+ LOG_MMC(("MMC5 $5123 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x01:
+ chr4_0(data, CHRROM);
+ break;
+ case 0x02:
+ /* 2k switch */
+ chr2_2(data | (m_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[3] = data | (m_high_chr << 8);
+// mapper5_sync_vrom(0);
+ chr1_3(m_vrom_bank[3], CHRROM);
+// m_nes_vram_sprite[3] = m_vrom_bank[0] * 64;
+// vrom_next[3] = 7;
+// vrom_page_a = 1;
+// vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1024: /* $5124 */
+ LOG_MMC(("MMC5 $5124 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[4] = data | (m_high_chr << 8);
+// mapper5_sync_vrom(0);
+ chr1_4(m_vrom_bank[4], CHRROM);
+// m_nes_vram_sprite[4] = m_vrom_bank[0] * 64;
+// vrom_next[0] = 0;
+// vrom_page_a = 0;
+// vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1025: /* $5125 */
+ LOG_MMC(("MMC5 $5125 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x02:
+ /* 2k switch */
+ chr2_4(data | (m_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[5] = data | (m_high_chr << 8);
+// mapper5_sync_vrom(0);
+ chr1_5(m_vrom_bank[5], CHRROM);
+// m_nes_vram_sprite[5] = m_vrom_bank[0] * 64;
+// vrom_next[1] = 1;
+// vrom_page_a = 0;
+// vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1026: /* $5126 */
+ LOG_MMC(("MMC5 $5126 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[6] = data | (m_high_chr << 8);
+// mapper5_sync_vrom(0);
+ chr1_6(m_vrom_bank[6], CHRROM);
+// m_nes_vram_sprite[6] = m_vrom_bank[0] * 64;
+// vrom_next[2] = 2;
+// vrom_page_a = 0;
+// vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1027: /* $5127 */
+ LOG_MMC(("MMC5 $5127 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x00:
+ /* 8k switch */
+ chr8(data, CHRROM);
+ break;
+ case 0x01:
+ /* 4k switch */
+ chr4_4(data, CHRROM);
+ break;
+ case 0x02:
+ /* 2k switch */
+ chr2_6(data | (m_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[7] = data | (m_high_chr << 8);
+// mapper5_sync_vrom(0);
+ chr1_7(m_vrom_bank[7], CHRROM);
+// m_nes_vram_sprite[7] = m_vrom_bank[0] * 64;
+// vrom_next[3] = 3;
+// vrom_page_a = 0;
+// vrom_page_b = 0;
+ break;
+ }
+ break;
+ case 0x1028: /* $5128 */
+ LOG_MMC(("MMC5 $5128 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[8] = data | (m_high_chr << 8);
+// nes_vram[vrom_next[0]] = data * 64;
+// nes_vram[0 + (vrom_page_a*4)] = data * 64;
+// nes_vram[0] = data * 64;
+ chr1_4(m_vrom_bank[8], CHRROM);
+// mapper5_sync_vrom(1);
+ if (!m_vrom_page_b)
+ {
+ m_vrom_page_a ^= 0x01;
+ m_vrom_page_b = 1;
+ }
+ break;
+ }
+ break;
+ case 0x1029: /* $5129 */
+ LOG_MMC(("MMC5 $5129 vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x02:
+ /* 2k switch */
+ chr2_0(data | (m_high_chr << 8), CHRROM);
+ chr2_4(data | (m_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[9] = data | (m_high_chr << 8);
+// nes_vram[vrom_next[1]] = data * 64;
+// nes_vram[1 + (vrom_page_a*4)] = data * 64;
+// nes_vram[1] = data * 64;
+ chr1_5(m_vrom_bank[9], CHRROM);
+// mapper5_sync_vrom(1);
+ if (!m_vrom_page_b)
+ {
+ m_vrom_page_a ^= 0x01;
+ m_vrom_page_b = 1;
+ }
+ break;
+ }
+ break;
+ case 0x102a: /* $512a */
+ LOG_MMC(("MMC5 $512a vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[10] = data | (m_high_chr << 8);
+// nes_vram[vrom_next[2]] = data * 64;
+// nes_vram[2 + (vrom_page_a*4)] = data * 64;
+// nes_vram[2] = data * 64;
+ chr1_6(m_vrom_bank[10], CHRROM);
+// mapper5_sync_vrom(1);
+ if (!m_vrom_page_b)
+ {
+ m_vrom_page_a ^= 0x01;
+ m_vrom_page_b = 1;
+ }
+ break;
+ }
+ break;
+ case 0x102b: /* $512b */
+ LOG_MMC(("MMC5 $512b vrom select: %02x (mode: %d)\n", data, m_chr_mode));
+ switch (m_chr_mode)
+ {
+ case 0x00:
+ /* 8k switch */
+ /* switches in first half of an 8K bank!) */
+ chr4_0(data << 1, CHRROM);
+ chr4_4(data << 1, CHRROM);
+ break;
+ case 0x01:
+ /* 4k switch */
+ chr4_0(data, CHRROM);
+ chr4_4(data, CHRROM);
+ break;
+ case 0x02:
+ /* 2k switch */
+ chr2_2(data | (m_high_chr << 8), CHRROM);
+ chr2_6(data | (m_high_chr << 8), CHRROM);
+ break;
+ case 0x03:
+ /* 1k switch */
+ m_vrom_bank[11] = data | (m_high_chr << 8);
+// nes_vram[vrom_next[3]] = data * 64;
+// nes_vram[3 + (vrom_page_a*4)] = data * 64;
+// nes_vram[3] = data * 64;
+ chr1_7(m_vrom_bank[11], CHRROM);
+// mapper5_sync_vrom(1);
+ if (!m_vrom_page_b)
+ {
+ m_vrom_page_a ^= 0x01;
+ m_vrom_page_b = 1;
+ }
+ break;
+ }
+ break;
+
+ case 0x1030: /* $5130 */
+ m_high_chr = data & 0x03;
+ if (m_exram_control == 1)
+ {
+// in this case m_high_chr selects which 256KB of CHR ROM
+// is to be used for all background tiles on the screen.
+ }
+ break;
+
+
+ case 0x1100: /* $5200 */
+ m_split_scr = data;
+ // in EX2 and EX3 modes, no split screen
+ if (m_exram_control & 0x02)
+ m_split_scr &= 0x7f;
+ m_split_ctrl = data;
+ break;
+
+ case 0x1101: /* $5201 */
+ m_split_yst = (data >= 240) ? data - 16 : data;
+ break;
+
+ case 0x1102: /* $5202 */
+ m_split_bank = data;
+ break;
+
+ case 0x1103: /* $5203 */
+ m_irq_count = data;
+ m_mmc5_scanline = data;
+ LOG_MMC(("MMC5 irq scanline: %d\n", m_irq_count));
+ break;
+ case 0x1104: /* $5204 */
+ m_irq_enable = data & 0x80;
+ LOG_MMC(("MMC5 irq enable: %02x\n", data));
+ break;
+ case 0x1105: /* $5205 */
+ m_mult1 = data;
+ break;
+ case 0x1106: /* $5206 */
+ m_mult2 = data;
+ break;
+
+ default:
+ logerror("** MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data);
+ break;
+ }
+}
+
+// 3bits are used to access the "WRAM" banks
+// bit3 select the chip (2 of them can be accessed, each up to 32KB)
+// bit1 & bit2 select the 8KB banks inside the chip
+// same mechanism is used also when "WRAM" is mapped in higher banks, but there we setup the bank map in a smart
+// way so to access the correct bank as if the 3 bits were directly selecting the bank in a 64KB RAM area
+READ8_MEMBER(nes_exrom_device::read_m)
+{
+ if (m_battery && m_prgram) // 2 chips present: first is BWRAM, second is WRAM
+ {
+ if (m_wram_base & 0x04)
+ return m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram_size - 1)];
+ else
+ return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery_size - 1)];
+ }
+ else if (m_prgram) // 1 chip, WRAM
+ return m_prgram[(offset + (m_wram_base & 0x03) * 0x2000) & (m_prgram_size - 1)];
+ else if (m_battery) // 1 chip, BWRAM
+ return m_battery[(offset + (m_wram_base & 0x03) * 0x2000) & (m_battery_size - 1)];
+ else
+ return ((offset + 0x6000) & 0xff00) >> 8;
+}
+
+WRITE8_MEMBER(nes_exrom_device::write_m)
+{
+ if (m_wram_protect_1 != 0x02 || m_wram_protect_2 != 0x01)
+ return;
+
+ if (m_battery)
+ m_battery[offset & (m_battery_size - 1)] = data;
+ if (m_prgram)
+ m_prgram[offset & (m_prgram_size - 1)] = data;
+}
diff --git a/src/mess/machine/nes_mmc5.h b/src/mess/machine/nes_mmc5.h
new file mode 100644
index 00000000000..1bf97b9e349
--- /dev/null
+++ b/src/mess/machine/nes_mmc5.h
@@ -0,0 +1,74 @@
+#ifndef __NES_MMC5_H
+#define __NES_MMC5_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_exrom_device
+
+class nes_exrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_exrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_READ8_MEMBER(nt_r);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ void set_mirror(int page, int src);
+ void prgram_bank8_x(int start, int bank);
+ void update_render_mode();
+ void update_prg();
+
+ UINT16 m_irq_count;
+ UINT8 m_irq_status;
+ int m_irq_enable;
+
+ int m_mult1, m_mult2;
+
+ int m_mmc5_scanline;
+ int m_vrom_page_a;
+ int m_vrom_page_b;
+ UINT16 m_vrom_bank[12]; // MMC5 has 10bit wide VROM regs!
+
+ int m_floodtile;
+ int m_floodattr;
+
+ int m_prg_mode; // $5100
+ int m_chr_mode; // $5101
+ int m_wram_protect_1; // $5102
+ int m_wram_protect_2; // $5103
+ int m_exram_control; // $5104
+ int m_wram_base; // $5113
+
+ UINT8 m_mmc5_last_chr_a;
+ UINT8 m_prg_regs[4];
+
+ UINT8 m_high_chr; // $5130
+
+ UINT8 m_split_scr; // $5200
+ UINT8 m_split_ctrl; // $5200
+ UINT8 m_split_yst; // $5201
+ UINT8 m_split_bank; // $5202
+
+ // MMC-5 contains 1K of internal ram
+ UINT8 *m_exram;
+
+// int m_nes_vram_sprite[8];
+};
+
+
+
+// device type definition
+extern const device_type NES_EXROM;
+
+#endif
diff --git a/src/mess/machine/nes_multigame.c b/src/mess/machine/nes_multigame.c
new file mode 100644
index 00000000000..345636a3524
--- /dev/null
+++ b/src/mess/machine/nes_multigame.c
@@ -0,0 +1,2605 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Multigame Carts PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate several PCBs used in multigame pirate carts (not MMC-3 based)
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_multigame.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_ACTION52 = &device_creator<nes_action52_device>;
+const device_type NES_CALTRON6IN1 = &device_creator<nes_caltron_device>;
+const device_type NES_RUMBLESTATION = &device_creator<nes_rumblestat_device>;
+const device_type NES_SVISION16 = &device_creator<nes_svision16_device>;
+const device_type NES_N625092 = &device_creator<nes_n625092_device>;
+const device_type NES_A65AS = &device_creator<nes_a65as_device>;
+const device_type NES_T262 = &device_creator<nes_t262_device>;
+const device_type NES_NOVEL1 = &device_creator<nes_novel1_device>;
+const device_type NES_NOVEL2 = &device_creator<nes_novel2_device>;
+const device_type NES_STUDYNGAME = &device_creator<nes_studyngame_device>;
+const device_type NES_SUPERGUN20IN1 = &device_creator<nes_sgun20in1_device>;
+const device_type NES_VT5201 = &device_creator<nes_vt5201_device>;
+const device_type NES_810544C = &device_creator<nes_810544c_device>;
+const device_type NES_NTD03 = &device_creator<nes_ntd03_device>;
+const device_type NES_BMC_GB63 = &device_creator<nes_bmc_gb63_device>;
+const device_type NES_BMC_GKA = &device_creator<nes_bmc_gka_device>;
+const device_type NES_BMC_GKB = &device_creator<nes_bmc_gkb_device>;
+const device_type NES_BMC_WS = &device_creator<nes_bmc_ws_device>;
+const device_type NES_BMC_11160 = &device_creator<nes_bmc_11160_device>;
+const device_type NES_BMC_G146 = &device_creator<nes_bmc_g146_device>;
+const device_type NES_BMC_8157 = &device_creator<nes_bmc_8157_device>;
+const device_type NES_BMC_HIK300 = &device_creator<nes_bmc_hik300_device>;
+const device_type NES_BMC_S700 = &device_creator<nes_bmc_s700_device>;
+const device_type NES_BMC_BALL11 = &device_creator<nes_bmc_ball11_device>;
+const device_type NES_BMC_22GAMES = &device_creator<nes_bmc_22games_device>;
+const device_type NES_BMC_64Y2K = &device_creator<nes_bmc_64y2k_device>;
+const device_type NES_BMC_12IN1 = &device_creator<nes_bmc_12in1_device>;
+const device_type NES_BMC_20IN1 = &device_creator<nes_bmc_20in1_device>;
+const device_type NES_BMC_21IN1 = &device_creator<nes_bmc_21in1_device>;
+const device_type NES_BMC_31IN1 = &device_creator<nes_bmc_31in1_device>;
+const device_type NES_BMC_35IN1 = &device_creator<nes_bmc_35in1_device>;
+const device_type NES_BMC_36IN1 = &device_creator<nes_bmc_36in1_device>;
+const device_type NES_BMC_64IN1 = &device_creator<nes_bmc_64in1_device>;
+const device_type NES_BMC_70IN1 = &device_creator<nes_bmc_70in1_device>;
+const device_type NES_BMC_72IN1 = &device_creator<nes_bmc_72in1_device>;
+const device_type NES_BMC_76IN1 = &device_creator<nes_bmc_76in1_device>;
+const device_type NES_BMC_110IN1 = &device_creator<nes_bmc_110in1_device>;
+const device_type NES_BMC_150IN1 = &device_creator<nes_bmc_150in1_device>;
+const device_type NES_BMC_190IN1 = &device_creator<nes_bmc_190in1_device>;
+const device_type NES_BMC_800IN1 = &device_creator<nes_bmc_800in1_device>;
+const device_type NES_BMC_1200IN1 = &device_creator<nes_bmc_1200in1_device>;
+const device_type NES_BMC_GOLD150 = &device_creator<nes_bmc_gold150_device>;
+const device_type NES_BMC_GOLD260 = &device_creator<nes_bmc_gold260_device>;
+const device_type NES_BMC_CH001 = &device_creator<nes_bmc_ch001_device>;
+const device_type NES_BMC_SUPER22 = &device_creator<nes_bmc_super22_device>;
+const device_type NES_BMC_4IN1RESET = &device_creator<nes_bmc_4in1reset_device>;
+const device_type NES_BMC_42IN1RESET = &device_creator<nes_bmc_42in1reset_device>;
+
+
+nes_action52_device::nes_action52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_ACTION52, "NES Cart Action 52 PCB", tag, owner, clock, "nes_action52", __FILE__)
+{
+}
+
+nes_caltron_device::nes_caltron_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_CALTRON6IN1, "NES Cart Caltron 6 in 1 PCB", tag, owner, clock, "nes_caltron", __FILE__)
+{
+}
+
+nes_rumblestat_device::nes_rumblestat_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_RUMBLESTATION, "NES Cart Rumblestation PCB", tag, owner, clock, "nes_rumblestat", __FILE__)
+{
+}
+
+nes_svision16_device::nes_svision16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SVISION16, "NES Cart Supervision 16 in 1 PCB", tag, owner, clock, "nes_svision16", __FILE__)
+{
+}
+
+nes_n625092_device::nes_n625092_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_N625092, "NES Cart N625092 PCB", tag, owner, clock, "nes_n625092", __FILE__)
+{
+}
+
+nes_a65as_device::nes_a65as_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_A65AS, "NES Cart A65AS PCB", tag, owner, clock, "nes_a65as", __FILE__)
+{
+}
+
+nes_t262_device::nes_t262_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_T262, "NES Cart T-262 PCB", tag, owner, clock, "nes_t262", __FILE__)
+{
+}
+
+nes_novel1_device::nes_novel1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NOVEL1, "NES Cart Novel Diamond Type 1 PCB", tag, owner, clock, "nes_novel1", __FILE__)
+{
+}
+
+nes_novel2_device::nes_novel2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NOVEL2, "NES Cart Novel Diamond Type 2 PCB", tag, owner, clock, "nes_novel2", __FILE__)
+{
+}
+
+nes_studyngame_device::nes_studyngame_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_STUDYNGAME, "NES Cart Study n Game PCB", tag, owner, clock, "nes_studyngame", __FILE__)
+{
+}
+
+nes_sgun20in1_device::nes_sgun20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SUPERGUN20IN1, "NES Cart Supergun 20 in 1 PCB", tag, owner, clock, "nes_sgun20in1", __FILE__)
+{
+}
+
+nes_vt5201_device::nes_vt5201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_VT5201, "NES Cart VT5201 PCB", tag, owner, clock, "nes_vt5201", __FILE__)
+{
+}
+
+nes_810544c_device::nes_810544c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_810544C, "NES Cart 810544-C-A1 PCB", tag, owner, clock, "nes_810544c", __FILE__)
+{
+}
+
+nes_ntd03_device::nes_ntd03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NTD03, "NES Cart NTD-03 PCB", tag, owner, clock, "nes_ntd03", __FILE__)
+{
+}
+
+nes_bmc_gb63_device::nes_bmc_gb63_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_GB63, "NES Cart BMC Ghostbusters 63 in 1 PCB", tag, owner, clock, "nes_bmc_gb63", __FILE__)
+{
+}
+
+nes_bmc_gka_device::nes_bmc_gka_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_GKA, "NES Cart BMC GK-A PCB", tag, owner, clock, "nes_bmc_gka", __FILE__)
+{
+}
+
+nes_bmc_gkb_device::nes_bmc_gkb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_GKB, "NES Cart BMC GK-B PCB", tag, owner, clock, "nes_bmc_gkb", __FILE__)
+{
+}
+
+nes_bmc_ws_device::nes_bmc_ws_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_WS, "NES Cart BMC WS PCB", tag, owner, clock, "nes_bmc_ws", __FILE__)
+{
+}
+
+nes_bmc_11160_device::nes_bmc_11160_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_11160, "NES Cart BMC-11160 PCB", tag, owner, clock, "nes_bmc_11160", __FILE__)
+{
+}
+
+nes_bmc_g146_device::nes_bmc_g146_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_G146, "NES Cart BMC-G-146 PCB", tag, owner, clock, "nes_bmc_g146", __FILE__)
+{
+}
+
+nes_bmc_8157_device::nes_bmc_8157_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_8157, "NES Cart BMC-8157 PCB", tag, owner, clock, "nes_bmc_8157", __FILE__)
+{
+}
+
+nes_bmc_hik300_device::nes_bmc_hik300_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_HIK300, "NES Cart BMC HIK 300 in 1 PCB", tag, owner, clock, "nes_bmc_hik300", __FILE__)
+{
+}
+
+nes_bmc_s700_device::nes_bmc_s700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_S700, "NES Cart BMC Super 700 in 1 PCB", tag, owner, clock, "nes_bmc_s700", __FILE__)
+{
+}
+
+nes_bmc_ball11_device::nes_bmc_ball11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_BALL11, "NES Cart BMC Ball 11 in 1 PCB", tag, owner, clock, "nes_bmc_ball11", __FILE__)
+{
+}
+
+nes_bmc_22games_device::nes_bmc_22games_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_22GAMES, "NES Cart BMC 22 Games PCB", tag, owner, clock, "nes_bmc_22games", __FILE__)
+{
+}
+
+nes_bmc_64y2k_device::nes_bmc_64y2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_64Y2K, "NES Cart BMC 64 in 1 Y2K PCB", tag, owner, clock, "nes_bmc_64y2k", __FILE__)
+{
+}
+
+nes_bmc_12in1_device::nes_bmc_12in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_12IN1, "NES Cart BMC 12 in 1 PCB", tag, owner, clock, "nes_bmc_12in1", __FILE__)
+{
+}
+
+nes_bmc_20in1_device::nes_bmc_20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_20IN1, "NES Cart BMC 20 in 1 PCB", tag, owner, clock, "nes_bmc_20in1", __FILE__)
+{
+}
+
+nes_bmc_21in1_device::nes_bmc_21in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_21IN1, "NES Cart BMC 21 in 1 PCB", tag, owner, clock, "nes_bmc_21in1", __FILE__)
+{
+}
+
+nes_bmc_31in1_device::nes_bmc_31in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_31IN1, "NES Cart BMC 31 in 1 PCB", tag, owner, clock, "nes_bmc_31in1", __FILE__)
+{
+}
+
+nes_bmc_35in1_device::nes_bmc_35in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_35IN1, "NES Cart BMC 35 in 1 PCB", tag, owner, clock, "nes_bmc_35in1", __FILE__)
+{
+}
+
+nes_bmc_36in1_device::nes_bmc_36in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_36IN1, "NES Cart BMC 36 in 1 PCB", tag, owner, clock, "nes_bmc_36in1", __FILE__)
+{
+}
+
+nes_bmc_64in1_device::nes_bmc_64in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_64IN1, "NES Cart BMC 64 in 1 PCB", tag, owner, clock, "nes_bmc_64in1", __FILE__)
+{
+}
+
+nes_bmc_70in1_device::nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_70IN1, "NES Cart BMC 70 in 1 PCB", tag, owner, clock, "nes_bmc_70in1", __FILE__)
+{
+}
+
+nes_bmc_72in1_device::nes_bmc_72in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_72IN1, "NES Cart BMC 72 in 1 PCB", tag, owner, clock, "nes_bmc_72in1", __FILE__)
+{
+}
+
+nes_bmc_76in1_device::nes_bmc_76in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_76IN1, "NES Cart BMC 76 in 1 PCB", tag, owner, clock, "nes_bmc_76in1", __FILE__)
+{
+}
+
+nes_bmc_110in1_device::nes_bmc_110in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_110IN1, "NES Cart BMC 110 in 1 PCB", tag, owner, clock, "nes_bmc_110in1", __FILE__)
+{
+}
+
+nes_bmc_150in1_device::nes_bmc_150in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_150IN1, "NES Cart BMC 150 in 1 PCB", tag, owner, clock, "nes_bmc_150in1", __FILE__)
+{
+}
+
+nes_bmc_190in1_device::nes_bmc_190in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_190IN1, "NES Cart BMC 190 in 1 PCB", tag, owner, clock, "nes_bmc_190in1", __FILE__)
+{
+}
+
+nes_bmc_800in1_device::nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_800IN1, "NES Cart BMC 800 in 1 PCB", tag, owner, clock, "nes_bmc_800in1", __FILE__)
+{
+}
+
+nes_bmc_1200in1_device::nes_bmc_1200in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_1200IN1, "NES Cart BMC 1200 in 1 PCB", tag, owner, clock, "nes_bmc_1200in1", __FILE__)
+{
+}
+
+nes_bmc_gold150_device::nes_bmc_gold150_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_GOLD150, "NES Cart BMC Golden 150 in 1 PCB", tag, owner, clock, "nes_bmc_gold150", __FILE__)
+{
+}
+
+nes_bmc_gold260_device::nes_bmc_gold260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_GOLD260, "NES Cart BMC Golden 260 in 1 PCB", tag, owner, clock, "nes_bmc_gold260", __FILE__)
+{
+}
+
+nes_bmc_ch001_device::nes_bmc_ch001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_CH001, "NES Cart BMC CH-001 PCB", tag, owner, clock, "nes_bmc_ch001", __FILE__)
+{
+}
+
+nes_bmc_super22_device::nes_bmc_super22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_SUPER22, "NES Cart BMC Super 22 Games PCB", tag, owner, clock, "nes_bmc_super22", __FILE__)
+{
+}
+
+nes_bmc_4in1reset_device::nes_bmc_4in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_4IN1RESET, "NES Cart BMC 4 in 1 (Reset Based) PCB", tag, owner, clock, "nes_bmc_4in1reset", __FILE__)
+{
+}
+
+nes_bmc_42in1reset_device::nes_bmc_42in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BMC_42IN1RESET, "NES Cart BMC 42 in 1 (Reset Based) PCB", tag, owner, clock, "nes_bmc_42in1reset", __FILE__)
+{
+}
+
+
+
+
+void nes_action52_device::device_start()
+{
+ common_start();
+}
+
+void nes_action52_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_caltron_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_caltron_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_rumblestat_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_prg));
+ save_item(NAME(m_chr));
+}
+
+void nes_rumblestat_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_prg = 0;
+ m_chr = 0;
+}
+
+void nes_svision16_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+}
+
+void nes_svision16_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch1 = 0;
+ m_latch2 = 0;
+}
+
+void nes_n625092_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+}
+
+void nes_n625092_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+
+ m_latch1 = 0;
+ m_latch2 = 0;
+}
+
+void nes_a65as_device::device_start()
+{
+ common_start();
+}
+
+void nes_a65as_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(7);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+ chr8(0, m_chr_source);
+}
+
+void nes_t262_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+}
+
+void nes_t262_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(7);
+ chr8(0, m_chr_source);
+
+ m_latch1 = 0;
+ m_latch2 = 0;
+}
+
+void nes_novel1_device::device_start()
+{
+ common_start();
+}
+
+void nes_novel1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+}
+
+void nes_novel2_device::device_start()
+{
+ common_start();
+}
+
+void nes_novel2_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_studyngame_device::device_start()
+{
+ common_start();
+}
+
+void nes_studyngame_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_sgun20in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_sgun20in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_vt5201_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_dipsetting));
+}
+
+void nes_vt5201_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ m_dipsetting = 0;
+}
+
+void nes_810544c_device::device_start()
+{
+ common_start();
+}
+
+void nes_810544c_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+}
+
+void nes_ntd03_device::device_start()
+{
+ common_start();
+}
+
+void nes_ntd03_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_gb63_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_dipsetting));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_vram_disable));
+}
+
+void nes_bmc_gb63_device::pcb_reset()
+{
+ prg16_89ab(0);
+ prg16_cdef(0xfff);
+ chr8(0, CHRRAM);
+
+ m_latch = 0;
+ m_dipsetting = 0;
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ update_banks();
+ m_vram_disable = 0;
+}
+
+void nes_bmc_gka_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+}
+
+void nes_bmc_gka_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+
+ m_latch1 = 0;
+ m_latch2 = 0;
+}
+
+void nes_bmc_gkb_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_gkb_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_ws_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_bmc_ws_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_bmc_11160_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_11160_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_g146_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_g146_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_8157_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_8157_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_hik300_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_hik300_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0xff);
+ chr8(0xff, CHRROM);
+}
+
+void nes_bmc_s700_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_s700_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_ball11_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_bmc_ball11_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_reg[0] = 1;
+ m_reg[1] = 0;
+ set_banks();
+}
+
+void nes_bmc_22games_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_22games_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(7);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_64y2k_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_bmc_64y2k_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ chr8(0, m_chr_source);
+
+ m_reg[0] = 0x80;
+ m_reg[1] = 0x43;
+ m_reg[2] = m_reg[3] = 0;
+ set_prg();
+ set_nt_mirroring(PPU_MIRROR_VERT);
+}
+
+void nes_bmc_12in1_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_bmc_12in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ m_reg[2] = 0;
+ m_reg[3] = 0;
+ update_banks();
+}
+
+void nes_bmc_20in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_20in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+}
+
+void nes_bmc_21in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_21in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_31in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_31in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(1);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_35in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_35in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_36in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_36in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 1);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_64in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_64in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_70in1_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_mode));
+}
+
+void nes_bmc_70in1_device::pcb_reset()
+{
+ prg16_89ab(m_prg_chunks - 1);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, CHRROM);
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ m_mode = 0;
+}
+
+void nes_bmc_72in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_72in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_76in1_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+}
+
+void nes_bmc_76in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch1 = 0;
+ m_latch2 = 0;
+}
+
+void nes_bmc_110in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_110in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(1);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+}
+
+void nes_bmc_150in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_150in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_190in1_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_190in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_800in1_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_mode));
+}
+
+void nes_bmc_800in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 1);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ m_mode = 0;
+}
+
+void nes_bmc_1200in1_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_vram_protect));
+}
+
+void nes_bmc_1200in1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+ m_vram_protect = 0;
+}
+
+void nes_bmc_gold150_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_bmc_gold150_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_bmc_gold260_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_gold260_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_bmc_ch001_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_bmc_ch001_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_bmc_super22_device::device_start()
+{
+ common_start();
+}
+
+void nes_bmc_super22_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+
+// This PCB is fully emulated here :)
+void nes_bmc_4in1reset_device::device_start()
+{
+ common_start();
+ m_latch = -1;
+ save_item(NAME(m_latch));
+}
+
+void nes_bmc_4in1reset_device::pcb_reset()
+{
+ m_latch++;
+ m_latch &= 3;
+ chr8(m_latch, CHRROM);
+ prg16_89ab(m_latch);
+ prg16_cdef(m_latch);
+}
+
+
+void nes_bmc_42in1reset_device::device_start()
+{
+ common_start();
+ m_latch = -1;
+ save_item(NAME(m_reg));
+}
+
+void nes_bmc_42in1reset_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ m_latch++;
+ m_latch &= 1;
+ chr8(0, m_chr_source);
+ prg32(m_latch << 4);
+
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+}
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Active Entertainment Action 52 board emulation
+
+ iNES: mapper 228
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_action52_device::write_h)
+{
+ UINT8 pmode = offset & 0x20;
+ int pbank = (offset & 0x1fc0) >> 6;
+ int cbank = (data & 0x03) | ((offset & 0x0f) << 2);
+ LOG_MMC(("ae_act52_w, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ chr8(cbank, CHRROM);
+
+ if (pmode)
+ {
+ prg16_89ab(pbank);
+ prg16_cdef(pbank);
+ }
+ else
+ prg32(pbank >> 1);
+}
+
+/*-------------------------------------------------
+
+ Caltron 6 in 1 Board
+
+ Games: 6 in 1 by Caltron
+
+ iNES: mapper 41
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_caltron_device::write_m)
+{
+ LOG_MMC(("caltron write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_latch = offset & 0xff;
+ set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ prg32(offset & 0x07);
+}
+
+WRITE8_MEMBER(nes_caltron_device::write_h)
+{
+ LOG_MMC(("caltron write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_latch & 0x04)
+ chr8(((m_latch & 0x18) >> 1) | (data & 0x03), CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Rumblestation Board
+
+ Games: Rumblestation 15 in 1
+
+ iNES: mapper 46
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_rumblestat_device::write_m)
+{
+ LOG_MMC(("rumblestation write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_prg = (m_prg & 0x01) | ((data & 0x0f) << 1);
+ m_chr = (m_chr & 0x07) | ((data & 0xf0) >> 1);
+ prg32(m_prg);
+ chr8(m_chr, CHRROM);
+}
+
+WRITE8_MEMBER(nes_rumblestat_device::write_h)
+{
+ LOG_MMC(("rumblestation write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ m_prg = (m_prg & ~0x01) | (data & 0x01);
+ m_chr = (m_chr & ~0x07) | ((data & 0x70) >> 4);
+ prg32(m_prg);
+ chr8(m_chr, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Supervision 16 in 1 Board
+
+ Games: Supervision 16 in 1
+
+ iNES: mapper 53
+
+ In MESS: Partially Supported. (the dump contains 32KB of
+ EEPROM which is not currently handled well)
+
+ -------------------------------------------------*/
+
+void nes_svision16_device::update_prg()
+{
+ int base = (m_latch1 & 0x0f) << 3;
+ if (m_latch1 & 0x10)
+ {
+ prg16_89ab((base | (m_latch2 & 7)) + 2); // +2 due to the eeprom
+ prg16_cdef((base | 0x07) + 2); // +2 due to the eeprom
+ }
+ else
+ {
+ prg16_89ab(0);
+ prg16_cdef(1);
+ }
+
+}
+
+READ8_MEMBER(nes_svision16_device::read_m)
+{
+ int bank = (((m_latch1 & 0x0f) << 4) | 0x0f) + 4 ; // +4 due to the eeprom
+ LOG_MMC(("svision16 read_m, offset: %04x\n", offset));
+ return m_prg[((bank * 0x2000) + (offset & 0x1fff)) & m_prg_mask];
+}
+
+WRITE8_MEMBER(nes_svision16_device::write_m)
+{
+ LOG_MMC(("svision16 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_latch1 = data;
+ update_prg();
+ set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+WRITE8_MEMBER(nes_svision16_device::write_h)
+{
+ LOG_MMC(("svision16 write_h, offset: %04x, data: %02x\n", offset, data));
+ m_latch2 = data;
+ update_prg();
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board N625092
+
+ Games: 400 in 1, 700 in 1, 1000 in 1
+
+ iNES: mapper 221
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_n625092_device::set_prg(UINT8 reg1, UINT8 reg2)
+{
+ UINT8 helper1, helper2;
+
+ helper1 = !(reg1 & 0x01) ? reg2 : (reg1 & 0x80) ? reg2 : (reg2 & 0x06) | 0x00;
+ helper2 = !(reg1 & 0x01) ? reg2 : (reg1 & 0x80) ? 0x07 : (reg2 & 0x06) | 0x01;
+
+ prg16_89ab(helper1 | ((reg1 & 0x70) >> 1));
+ prg16_cdef(helper2 | ((reg1 & 0x70) >> 1));
+}
+
+WRITE8_MEMBER(nes_n625092_device::write_h)
+{
+ LOG_MMC(("n625092 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x4000)
+ {
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ offset = (offset >> 1) & 0xff;
+
+ if (m_latch1 != offset)
+ {
+ m_latch1 = offset;
+ set_prg(m_latch1, m_latch2);
+ }
+ }
+ else
+ {
+ offset &= 0x07;
+
+ if (m_latch2 != offset)
+ {
+ m_latch2 = offset;
+ set_prg(m_latch1, m_latch2);
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+
+ Board BMC-A65AS
+
+ Games: 3-in-1 (N068)
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_a65as_device::write_h)
+{
+ UINT8 helper = (data & 0x30) >> 1;
+ LOG_MMC(("a65as write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (data & 0x80)
+ set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ else
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (data & 0x40)
+ prg32(data >> 1);
+ else
+ {
+ prg16_89ab(helper | (data & 0x07));
+ prg16_cdef(helper | 0x07);
+ }
+}
+
+/*-------------------------------------------------
+
+ Board BMC-T-262
+
+ Games: 4-in-1 (D-010), 8-in-1 (A-020)
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_t262_device::write_h)
+{
+ UINT8 mmc_helper;
+ LOG_MMC(("t262 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_latch2 || offset == 0)
+ {
+ m_latch1 = (m_latch1 & 0x38) | (data & 0x07);
+ prg16_89ab(m_latch1);
+ }
+ else
+ {
+ m_latch2 = 1;
+ set_nt_mirroring(BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ mmc_helper = ((offset >> 3) & 0x20) | ((offset >> 2) & 0x18);
+ m_latch1 = mmc_helper | (m_latch1 & 0x07);
+ prg16_89ab(m_latch1);
+ prg16_cdef(mmc_helper | 0x07);
+ }
+}
+
+
+/*-------------------------------------------------
+
+ BMC-NOVELDIAMOND and BMC-999999in1
+
+ Unknown Bootleg Multigame Board
+ Games: I only found 'Novel Diamond 999999-in-1.unf' using
+ this mapper (hence the code is used for BMC_NOVELDIAMOND
+ board). The code is included here in case a mapper 54
+ dump arises.
+
+ iNES: mappers 54 and 213
+
+ In MESS: Partial Support.
+
+ -------------------------------------------------*/
+
+// Are this correct or should they work the same?
+WRITE8_MEMBER(nes_novel1_device::write_h)
+{
+ LOG_MMC(("novel1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(offset & 0x03);
+ chr8(offset & 0x07, CHRROM);
+}
+
+WRITE8_MEMBER(nes_novel2_device::write_h)
+{
+ LOG_MMC(("novel2 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(offset >> 1);
+ chr8(offset >> 3, CHRROM);
+}
+
+
+/*-------------------------------------------------
+
+ Board UNL-STUDYNGAME
+
+ Games: Study n Game 32 in 1
+
+ iNES: mapper 39
+
+ In MESS: Partially Supported (problems with PRG bankswitch,
+ only keyboard exercise work).
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_studyngame_device::write_h)
+{
+ LOG_MMC(("studyngame write_h, offset: %04x, data: %02x\n", offset, data));
+ prg32(data);
+}
+
+/*-------------------------------------------------
+
+ BMC-SUPERGUN-20IN1
+
+ Unknown Bootleg Multigame Board
+ Games: Super Gun 20 in 1
+
+ iNES: mapper 214
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sgun20in1_device::write_h)
+{
+ LOG_MMC(("supergun20in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(offset >> 2);
+ prg16_cdef(offset >> 2);
+ chr8(offset, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ BMC-VT5201
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_vt5201_device::write_h)
+{
+ LOG_MMC(("vt5201 wirte_h, offset: %04x, data: %02x\n", offset, data));
+
+ m_latch = BIT(offset, 8);
+
+ // not sure about this mirroring bit!!
+ // without it TN 95 in 1 has glitches in Lunar Ball; with it TN 95 in 1 has glitches in Galaxian!
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ if (BIT(offset, 7))
+ {
+ prg16_89ab((offset >> 4) & 0x07);
+ prg16_cdef((offset >> 4) & 0x07);
+ }
+ else
+ prg32((offset >> 5) & 0x03);
+ chr8(offset, CHRROM);
+}
+
+READ8_MEMBER(nes_vt5201_device::read_h)
+{
+ LOG_MMC(("bmc_vt5201 read_h, offset: %04x\n", offset));
+ // m_dipsetting = ioport("CARTDIPS")->read();
+
+ if (m_latch)
+ return m_dipsetting; // cart mode, depending on the Dip Switches (always zero atm, given we have no way to add cart-based DIPs)
+ else
+ return hi_access_rom(offset);
+}
+
+/*-------------------------------------------------
+
+ BMC-810544-C-A1
+
+ Games: 200-in-1 Elfland
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_810544c_device::write_h)
+{
+ UINT8 bank = (offset >> 7);
+ LOG_MMC(("810544 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (!BIT(offset, 6))
+ {
+ prg16_89ab((bank << 1) | BIT(offset, 5));
+ prg16_cdef((bank << 1) | BIT(offset, 5));
+ }
+ else
+ prg32(bank);
+
+ set_nt_mirroring(BIT(offset, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ chr8(offset & 0x0f, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ BMC-NTD-03
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ntd03_device::write_h)
+{
+ UINT8 pbank = (offset >> 10) & 0x1e;
+ UINT8 cbank = ((offset & 0x300) >> 5) | (offset & 0x07);
+ LOG_MMC(("ntd03 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (BIT(offset, 7))
+ {
+ prg16_89ab(pbank | BIT(offset, 6));
+ prg16_cdef(pbank | BIT(offset, 6));
+ }
+ else
+ prg32(pbank >> 1);
+
+ set_nt_mirroring(BIT(offset, 10) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ chr8(cbank, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ BMC-GHOSTBUSTERS63IN1
+
+ in MESS: only preliminar support
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_gb63_device::chr_w)
+{
+ int bank = offset >> 10;
+
+ if (!m_vram_disable)
+ m_chr_access[bank][offset & 0x3ff] = data;
+}
+
+void nes_bmc_gb63_device::update_banks()
+{
+ set_nt_mirroring(BIT(m_reg[0], 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+
+ if (BIT(m_reg[0], 5))
+ {
+ prg16_89ab(m_reg[0] & 0x1f);
+ prg16_cdef(m_reg[0] & 0x1f);
+ }
+ else
+ prg32((m_reg[0] & 0x1f) >> 1);
+
+// according to FCEUMM source, the game should be able to disable the VRAM, but this stops the game from working
+// maybe the VRAM disable does not work at start?
+// m_vram_disable = BIT(m_reg[1], 1) ? 0 : 1;
+}
+
+WRITE8_MEMBER(nes_bmc_gb63_device::write_h)
+{
+ LOG_MMC(("bmc_gb63 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ m_reg[offset & 1] = data;
+ m_latch = BIT(m_reg[0], 7) | (BIT(m_reg[1], 0) << 1);
+ update_banks();
+}
+
+READ8_MEMBER(nes_bmc_gb63_device::read_h)
+{
+ LOG_MMC(("bmc_gb63 read_h, offset: %04x\n", offset));
+ // m_dipsetting = ioport("CARTDIPS")->read();
+
+ if (m_latch == 1)
+ return (offset & 0xff00) >> 8; // open bus
+ else
+ return hi_access_rom(offset);
+}
+
+
+/*-------------------------------------------------
+
+ Board BMC-GKA
+
+ Unknown Bootleg Multigame Board
+ Games: 6 in 1, 54 in 1, 106 in 1
+
+ iNES: mapper 57
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_gka_device::write_h)
+{
+ LOG_MMC(("bmc_gka write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x0800)
+ m_latch2 = data;
+ else
+ m_latch1 = data;
+
+ if (m_latch2 & 0x80)
+ prg32(2 | (m_latch2 >> 6));
+ else
+ {
+ prg16_89ab((m_latch2 >> 5) & 0x03);
+ prg16_cdef((m_latch2 >> 5) & 0x03);
+ }
+
+ set_nt_mirroring((m_latch2 & 0x08) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ chr8((m_latch1 & 0x03) | (m_latch2 & 0x07) | ((m_latch2 & 0x10) >> 1), CHRROM);
+}
+
+
+/*-------------------------------------------------
+
+ Board BMC-GKB
+
+ Unknown Bootleg Multigame Board
+ Games: 68 in 1, 73 in 1, 98 in 1
+
+ iNES: mapper 58
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_gkb_device::write_h)
+{
+ UINT8 bank = (offset & 0x40) ? 0 : 1;
+ LOG_MMC(("bmc_gkb write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(offset & ~bank);
+ prg16_cdef(offset | bank);
+ chr8(offset >> 3, m_chr_source);
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ Board BMC-WS
+
+ Games: Super 40-in-1
+
+ In MESS: Partially Supported (some games, like Galaxian, have
+ issues)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_ws_device::write_m)
+{
+ UINT8 mmc_helper;
+ LOG_MMC(("bmc_ws write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x1000)
+ {
+ switch (offset & 0x01)
+ {
+ case 0:
+ if (!m_latch)
+ {
+ m_latch = data & 0x20;
+ set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ mmc_helper = (~data & 0x08) >> 3;
+ prg16_89ab(data & ~mmc_helper);
+ prg16_cdef(data | mmc_helper);
+ }
+ break;
+ case 1:
+ if (!m_latch)
+ chr8(data, CHRROM);
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ Board BMC-11160 (by TXC?)
+
+ Games: 6 in 1 (MGC-023)
+
+ In MESS: Partially Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_11160_device::write_h)
+{
+ LOG_MMC(("bmc_11160 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32((data & 0x70) >> 4);
+ chr8(((data & 0x70) >> 2) | (data & 3), m_chr_source);
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ Board BMC-G-146
+
+ Games: 1994 Super HIK 14 in 1 (G-136)
+
+ In MESS: Partially Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_g146_device::write_h)
+{
+ LOG_MMC(("bmc_g146 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x800)
+ {
+ // UNROM mode
+ int helper = offset & BIT(offset, 6);
+ prg16_89ab((offset & 0x1f) | helper);
+ prg16_cdef((offset & 0x18) | 7);
+ }
+ else if (offset & 0x40)
+ {
+ // 16KB mode
+ prg16_89ab(offset & 0x1f);
+ prg16_cdef(offset & 0x1f);
+ }
+ else
+ prg32((offset & 0x1f) >> 4);
+
+ set_nt_mirroring(!BIT(offset, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ Board BMC-8157
+
+ Games: 4 in 1 1993 (CK-001)
+
+ In MESS: Partially Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_8157_device::write_h)
+{
+ LOG_MMC(("bmc_8157 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab((offset >> 2) & 0x1f);
+ if (offset & 0x200)
+ prg16_cdef(offset & 0x1f);
+ else
+ prg16_cdef((offset & 0x18) | 7);
+
+ set_nt_mirroring(!BIT(offset, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+READ8_MEMBER(nes_bmc_8157_device::read_h)
+{
+ LOG_MMC(("bmc_8157 read_h, offset: %04x\n", offset));
+ // m_dipsetting = ioport("CARTDIPS")->read();
+
+// UINT8 val = hi_access_rom(offset);
+// return val | m_noise; // the first write_h sets m_noise=0xff or 0 depending on dsw
+
+ return hi_access_rom(offset);
+}
+
+
+/*-------------------------------------------------
+
+ BMC-SUPERHIK_300IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 100000 in 1, Super HIK 300 in 1, 1997 in 1
+
+ iNES: mapper 212
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_hik300_device::write_h)
+{
+ LOG_MMC(("bmc_hik300 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ chr8(offset, CHRROM);
+
+ if (offset < 0x4000)
+ {
+ prg16_89ab(offset);
+ prg16_cdef(offset);
+ }
+ else
+ prg32(offset >> 1);
+}
+
+/*-------------------------------------------------
+
+ BMC-SUPER-700IN1
+
+ Unknown Bootleg Multigame Board
+ Games: Super 700 in 1
+
+ iNES: mapper 62
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_s700_device::write_h)
+{
+ LOG_MMC(("bmc_s700 write_h, offset :%04x, data: %02x\n", offset, data));
+
+ chr8(((offset & 0x1f) << 2) | (data & 0x03), CHRROM);
+
+ if (offset & 0x20)
+ {
+ prg16_89ab((offset & 0x40) | ((offset >> 8) & 0x3f));
+ prg16_cdef((offset & 0x40) | ((offset >> 8) & 0x3f));
+ }
+ else
+ {
+ prg32(((offset & 0x40) | ((offset >> 8) & 0x3f)) >> 1);
+ }
+
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ BMC-BALLGAMES-11IN1
+
+ Known Boards: Unknown Multigame Bootleg Board
+ Games: 11 in 1 Ball Games
+
+ iNES: mapper 51
+
+ In MESS: Partially Supported.
+
+ -------------------------------------------------*/
+
+void nes_bmc_ball11_device::set_banks()
+{
+ set_nt_mirroring((m_reg[0] == 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (m_reg[0] & 0x01)
+ {
+ prg32(m_reg[1]);
+ }
+ else
+ {
+ prg16_89ab((m_reg[1] << 1) | (m_reg[0] >> 1));
+ prg16_cdef((m_reg[1] << 1) | 0x07);
+ }
+}
+
+WRITE8_MEMBER(nes_bmc_ball11_device::write_m)
+{
+ LOG_MMC(("bmc_ball11 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ m_reg[0] = ((data >> 1) & 0x01) | ((data >> 3) & 0x02);
+ set_banks();
+}
+
+WRITE8_MEMBER(nes_bmc_ball11_device::write_h)
+{
+ LOG_MMC(("bmc_ball11 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6000)
+ {
+ case 0x4000: // here we also update reg[0] upper bit
+ m_reg[0] = (m_reg[0] & 0x01) | ((data >> 3) & 0x02);
+ case 0x0000:
+ case 0x2000:
+ case 0x6000:
+ m_reg[1] = data & 0x0f;
+ set_banks();
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-22GAMES
+
+ Unknown Bootleg Multigame Board
+ Games: 22 in 1
+
+ iNES: mapper 230
+
+ In MESS: Partially Supported. It would need a reset
+ to work (not possible yet)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_22games_device::write_h)
+{
+ LOG_MMC(("bmc_22games write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (1) // this should flip at reset
+ {
+ prg16_89ab(data & 0x07);
+ }
+ else
+ {
+ if (data & 0x20)
+ {
+ prg16_89ab((data & 0x1f) + 8);
+ prg16_cdef((data & 0x1f) + 8);
+ }
+ else
+ {
+ prg16_89ab((data & 0x1f) + 8);
+ prg16_cdef((data & 0x1f) + 9);
+ }
+ set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ }
+}
+
+/*-------------------------------------------------
+
+ Board BMC-64IN1NOREPEAT
+
+ Games: 64-in-1 Y2K
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_bmc_64y2k_device::set_prg()
+{
+ UINT8 helper1 = (m_reg[1] & 0x1f);
+ UINT8 helper2 = (helper1 << 1) | ((m_reg[1] & 0x40) >> 6);
+
+ if (m_reg[0] & 0x80)
+ {
+ if (m_reg[1] & 0x80)
+ prg32(helper1);
+ else
+ {
+ prg16_89ab(helper2);
+ prg16_cdef(helper2);
+ }
+ }
+ else
+ prg16_cdef(helper2);
+}
+
+WRITE8_MEMBER(nes_bmc_64y2k_device::write_l)
+{
+ LOG_MMC(("bmc64y2k write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ switch (offset)
+ {
+ case 0x1000:
+ case 0x1001:
+ case 0x1002:
+ case 0x1003:
+ m_reg[offset & 0x03] = data;
+ set_prg();
+ chr8(((m_reg[0] >> 1) & 0x03) | (m_reg[2] << 2), CHRROM);
+ break;
+ }
+ if (offset == 0x1000) /* write to reg[0] also sets mirroring */
+ set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+WRITE8_MEMBER(nes_bmc_64y2k_device::write_h)
+{
+ LOG_MMC(("bmc64y2k write_h, offset: %04x, data: %02x\n", offset, data));
+
+ m_reg[3] = data; // reg[3] is currently unused?!?
+}
+
+/*-------------------------------------------------
+
+ BMC-12IN1
+
+ Unknown Bootleg Multigame Board
+ Games:
+
+ iNES:
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+void nes_bmc_12in1_device::update_banks()
+{
+ int bank = (m_reg[3] & 3) << 3;
+
+ chr4_0((m_reg[1] >> 3) | (bank << 2), m_chr_source);
+ chr4_4((m_reg[2] >> 3) | (bank << 2), m_chr_source);
+
+ if (m_reg[3] & 8)
+ prg32(((m_reg[2] & 7) >> 1) | bank);
+ else
+ {
+ prg16_89ab((m_reg[1] & 7) | bank);
+ prg16_cdef(7 | bank);
+ }
+
+ set_nt_mirroring(!BIT(m_reg[3], 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+WRITE8_MEMBER(nes_bmc_12in1_device::write_h)
+{
+ LOG_MMC(("bmc_12in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0xafff: m_reg[0] = data; break;
+ case 0xbfff: m_reg[1] = data; break;
+ case 0xdfff: m_reg[2] = data; break;
+ case 0xefff: m_reg[3] = data; break;
+ }
+ update_banks();
+}
+
+/*-------------------------------------------------
+
+ BMC-20IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 20 in 1
+
+ iNES: mapper 231
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_20in1_device::write_h)
+{
+ LOG_MMC(("bmc_20in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ prg16_89ab((offset & 0x1e));
+ prg16_cdef((offset & 0x1e) | ((offset & 0x20) ? 1 : 0));
+}
+
+/*-------------------------------------------------
+
+ BMC-21IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 8 in 1, 21 in 1
+
+ iNES: mapper 201
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_21in1_device::write_h)
+{
+ LOG_MMC(("bmc_21in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(offset & 0x03);
+ chr8(offset & 0x03, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ BMC-31IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 31 in 1
+
+ iNES: mapper 229
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_31in1_device::write_h)
+{
+ LOG_MMC(("bmc_31in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ chr8(offset, CHRROM);
+
+ if ((offset & 0x1e) == 0)
+ {
+ prg16_89ab(0);
+ prg16_89ab(1);
+ }
+ else
+ {
+ prg16_89ab(offset & 0x1f);
+ prg16_89ab(offset & 0x1f);
+ }
+}
+
+/*-------------------------------------------------
+
+ BMC-35IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 35 in 1
+
+ iNES: mapper 203
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_35in1_device::write_h)
+{
+ LOG_MMC(("bmc_35in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab((data >> 2) & 0x03);
+ prg16_cdef((data >> 2) & 0x03);
+ chr8(data & 0x03, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ BMC-36IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 36 in 1, 1200 in 1
+
+ iNES: mapper 200
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_36in1_device::write_h)
+{
+ LOG_MMC(("bmc_36in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(offset & 0x07);
+ prg16_cdef(offset & 0x07);
+ chr8(offset & 0x07, CHRROM);
+
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ BMC-64IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 64 in 1
+
+ iNES: mapper 204
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_64in1_device::write_h)
+{
+ int bank = (offset >> 1) & (offset >> 2) & 0x01;
+
+ LOG_MMC(("bmc_64in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(offset & ~bank);
+ prg16_cdef(offset | bank);
+ chr8(offset & ~bank, CHRROM);
+
+ set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ BMC-70IN1
+
+ Unknown Bootleg Multigame Board
+ Games:
+
+ iNES: mapper
+
+ This is same hardware as BMC-800IN1 below, but this
+ cart has CHR and slightly diff bankswitch.
+ DSW not emulated yet.
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_70in1_device::write_h)
+{
+ LOG_MMC(("bmc70in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x4000)
+ {
+ set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT);
+ chr8(offset & 7, CHRROM);
+ }
+ else
+ {
+ switch (offset & 0x30)
+ {
+ case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break;
+ case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break;
+ case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break;
+ case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break;
+ }
+ prg16_89ab(m_reg[0]);
+ prg16_cdef(m_reg[1]);
+ }
+}
+
+READ8_MEMBER(nes_bmc_70in1_device::read_h)
+{
+ LOG_MMC(("bmc70in1 read_h, offset: %04x\n", offset));
+
+ if (m_mode)
+ offset = (offset & 0x7ff0) | m_mode;
+
+ return hi_access_rom(offset);
+}
+
+/*-------------------------------------------------
+
+ BMC-72IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 72 in 1, 115 in 1 and other multigame carts
+
+ iNES: mapper 225
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_72in1_device::write_h)
+{
+ int hi_bank = offset & 0x40;
+ int size_16 = offset & 0x1000;
+ int bank = (offset & 0xf80) >> 7;
+
+ LOG_MMC(("bmc_72in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(offset, CHRROM);
+ set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ if (size_16)
+ {
+ bank <<= 1;
+ if (hi_bank)
+ bank ++;
+
+ prg16_89ab(bank);
+ prg16_cdef(bank);
+ }
+ else
+ prg32(bank);
+}
+
+/*-------------------------------------------------
+
+ BMC-76IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 76 in 1, Super 42 in 1
+
+ iNES: mapper 226
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+// does this work for super42in1 as well?!?
+WRITE8_MEMBER(nes_bmc_76in1_device::write_h)
+{
+ int hi_bank;
+ int size_16;
+ int bank;
+
+ LOG_MMC(("bmc_76in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x01)
+ m_latch2 = data;
+ else
+ m_latch1 = data;
+
+ set_nt_mirroring(BIT(m_latch1, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ hi_bank = m_latch1 & 0x01;
+ size_16 = m_latch1 & 0x20;
+ bank = ((m_latch1 & 0x1e) >> 1) | ((m_latch1 & 0x80) >> 3) | ((m_latch2 & 0x01) << 5);
+
+ if (size_16)
+ {
+ bank <<= 1;
+ if (hi_bank)
+ bank ++;
+
+ prg16_89ab(bank);
+ prg16_cdef(bank);
+ }
+ else
+ prg32(bank);
+}
+
+/*-------------------------------------------------
+
+ BMC-110IN1
+
+ Known Boards: Unknown Bootleg Board
+ Games: 110 in 1
+
+ iNES: mapper 255
+
+ In MESS: Preliminary support.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_110in1_device::write_h)
+{
+ UINT8 helper1 = (offset >> 12) ? 0 : 1;
+ UINT8 helper2 = ((offset >> 8) & 0x40) | ((offset >> 6) & 0x3f);
+
+ LOG_MMC(("bmc_110in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ prg16_89ab(helper1 & ~helper2);
+ prg16_cdef(helper1 | helper2);
+ chr8(((offset >> 8) & 0x40) | (offset & 0x3f), CHRROM);
+}
+
+
+/*-------------------------------------------------
+
+ BMC-150IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 150 in 1
+
+ iNES: mapper 202
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_150in1_device::write_h)
+{
+ int bank = (offset >> 1) & 0x07;
+
+ LOG_MMC(("bmc_150in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_89ab(bank);
+ prg16_cdef(bank + (((bank & 0x06) == 0x06) ? 1 : 0));
+ chr8(bank, CHRROM);
+
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT);
+}
+
+
+/*-------------------------------------------------
+
+ Board BMC-190IN1
+
+ Games: 190-in-1
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_190in1_device::write_h)
+{
+ LOG_MMC(("bmc190in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ offset >>= 2;
+ prg16_89ab(offset);
+ prg16_cdef(offset);
+ chr8(offset, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ BMC-800IN1
+
+ Unknown Bootleg Multigame Board
+ Games:
+
+ iNES: mapper
+
+ DSW not emulated yet.
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_800in1_device::write_h)
+{
+ LOG_MMC(("bmc800in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 0x4000)
+ {
+ set_nt_mirroring(BIT(offset, 5) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT);
+
+ m_reg[0] = (m_reg[0]) | ((offset << 3) & 0x38);
+ m_reg[1] = (m_reg[1]) | ((offset << 3) & 0x38);
+ }
+ else
+ {
+ switch (offset & 0x30)
+ {
+ case 0x00: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break;
+ case 0x10: m_mode = 0x1; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x7; break;
+ case 0x20: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x6); m_reg[1] = m_reg[0] | 0x1; break;
+ case 0x30: m_mode = 0x0; m_reg[0] = (m_reg[0] & 0x38) | (offset & 0x7); m_reg[1] = m_reg[0] | 0x0; break;
+ }
+ }
+ prg16_89ab(m_reg[0]);
+ prg16_cdef(m_reg[1]);
+}
+
+READ8_MEMBER(nes_bmc_800in1_device::read_h)
+{
+ LOG_MMC(("bmc800in1 read_h, offset: %04x\n", offset));
+
+ if (m_mode)
+ offset = (offset & 0x7ff0) | m_mode;
+
+ return hi_access_rom(offset);
+}
+
+/*-------------------------------------------------
+
+ BMC-1200IN1
+
+ Unknown Bootleg Multigame Board
+ Games: 1200 in 1, 295 in 1, 76 in 1
+
+ iNES: mapper 227
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_1200in1_device::chr_w)
+{
+ int bank = offset >> 10;
+
+ if (!m_vram_protect)
+ m_chr_access[bank][offset & 0x3ff] = data;
+}
+
+
+WRITE8_MEMBER(nes_bmc_1200in1_device::write_h)
+{
+ int bank = ((offset >> 2) & 0x1f) | ((offset & 0x0100) >> 3);
+
+ LOG_MMC(("bmc_1200in1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x80)
+ {
+// m_vram_protect = 1;
+ prg16_89ab(bank);
+ prg16_cdef(bank + (offset & 1));
+ }
+ else
+ {
+ int low_mask = (offset & 1) ? 0x3e : 0xff;
+
+// m_vram_protect = 0;
+ if (!BIT(offset, 9))
+ {
+ prg16_89ab(bank & low_mask);
+ prg16_cdef(bank & 0x38);
+ }
+ else
+ {
+ prg16_89ab(bank & low_mask);
+ prg16_cdef(bank | 0x07);
+ }
+ }
+
+ set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+
+/*-------------------------------------------------
+
+ BMC-GOLDEN260IN1
+
+ Unknown Bootleg Multigame Board
+ Games:
+
+ iNES: mapper 235
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_gold260_device::write_h)
+{
+ int bank = (offset & 0x1f) | ((offset & 0x0300) >> 3);
+ LOG_MMC(("bmc_gold260 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset & 0x400)
+ set_nt_mirroring(PPU_MIRROR_LOW);
+ else
+ set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (offset & 0x800)
+ {
+ bank = (bank << 1) | BIT(offset, 12);
+ prg16_89ab(bank);
+ prg16_cdef(bank);
+ }
+ else
+ prg32(bank);
+}
+
+
+/*-------------------------------------------------
+
+ BMC-GOLDEN150IN1
+
+ Unknown Bootleg Multigame Board
+ Games:
+
+ iNES: mapper 235
+
+ Same as the above + open bus in 0x8000-0xffff when
+ enabled
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+
+WRITE8_MEMBER(nes_bmc_gold150_device::write_h)
+{
+ int bank = (offset & 0x1f) | ((offset & 0x0200) >> 4);
+ LOG_MMC(("bmc_gold150 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ m_latch = (offset & 0x0100);
+
+ if (offset & 0x400)
+ set_nt_mirroring(PPU_MIRROR_LOW);
+ else
+ set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (offset & 0x800)
+ {
+ bank = (bank << 1) | BIT(offset, 12);
+ prg16_89ab(bank);
+ prg16_cdef(bank);
+ }
+ else
+ prg32(bank);
+}
+
+READ8_MEMBER(nes_bmc_gold150_device::read_h)
+{
+ LOG_MMC(("bmc_gold150 read_h, offset: %04x\n", offset));
+
+ if (m_latch) // open bus
+ return (offset & 0xff00) >> 8;
+ else
+ return hi_access_rom(offset);
+}
+
+
+/*-------------------------------------------------
+
+ BMC-POWERFUL-255
+
+ Unknown Bootleg Multigame Board
+ Games:
+
+ iNES: mapper 63
+
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_ch001_device::write_h)
+{
+ int bank = ((offset >> 1) & 0x1fc);
+ LOG_MMC(("bmc_ch001 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ m_latch = ((offset & 0x300) == 0x300);
+ set_nt_mirroring(BIT(offset, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ if (offset & 2)
+ {
+ prg8_89(bank + 0);
+ prg8_ab(bank + 1);
+ prg8_cd(bank + 2);
+ prg8_ef(bank + 3);
+ }
+ else
+ {
+ bank |= (offset & 4) >> 1;
+ prg8_89(bank + 0);
+ prg8_ab(bank + 1);
+ prg8_cd(bank + 0);
+ prg8_ef(bank + 1);
+ }
+
+ if (offset & 0x800) // in this case, the last 8KB bank is switched differently...
+ prg8_ef((offset & 0x07c ) | ((offset & 0x6) ? 0x3 : 0x1));
+}
+
+READ8_MEMBER(nes_bmc_ch001_device::read_h)
+{
+ LOG_MMC(("bmc_ch001 read_h, offset: %04x\n", offset));
+
+ if (m_latch && offset < 0x4000) // open bus
+ return (offset & 0xff00) >> 8;
+ else
+ return hi_access_rom(offset);
+}
+
+/*-------------------------------------------------
+
+ BMC-SUPER22GAMES
+
+ Unknown Bootleg Multigame Board
+ Games:
+
+ iNES:
+
+ is there a dsw to access the higher banks above 0x20?
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_super22_device::write_h)
+{
+ LOG_MMC(("bmc_super22 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (data & 0x20)
+ {
+ prg16_89ab(data & 0x1f);
+ prg16_cdef(data & 0x1f);
+ }
+ else
+ prg32((data & 0x1f) >> 1);
+
+ switch (data & 0xc0)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x40: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x80: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0xc0: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+}
+
+
+/*-------------------------------------------------
+
+ BMC-RESETBASED4IN1
+
+ Unknown Bootleg Multigame Board
+
+ Games:
+
+ iNES:
+
+ No need to use handlers. At reset the banks change
+ and so does the game.
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ BMC-42IN1RESETBASED
+
+ Unknown Bootleg Multigame Board
+
+ Games:
+
+ iNES:
+
+ In MESS: Preliminary Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bmc_42in1reset_device::write_h)
+{
+ int bank;
+ LOG_MMC(("bmc_42in1reset write_h, offset: %04x, data: %02x\n", offset, data));
+
+ m_reg[offset & 1] = data;
+ bank = (m_reg[0] & 0x1f) | (m_latch << 5) | ((m_reg[1] & 1) << 6);
+
+ if (!(m_reg[0] & 0x20))
+ prg32(bank >> 1);
+ else
+ {
+ prg16_89ab(bank);
+ prg16_cdef(bank);
+ }
+
+ set_nt_mirroring(BIT(offset, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+}
diff --git a/src/mess/machine/nes_multigame.h b/src/mess/machine/nes_multigame.h
new file mode 100644
index 00000000000..93b87908177
--- /dev/null
+++ b/src/mess/machine/nes_multigame.h
@@ -0,0 +1,892 @@
+#ifndef __NES_MULTIGAME_H
+#define __NES_MULTIGAME_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_action52_device
+
+class nes_action52_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_action52_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_caltron_device
+
+class nes_caltron_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_caltron_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_rumblestat_device
+
+class nes_rumblestat_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_rumblestat_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_prg, m_chr;
+};
+
+
+// ======================> nes_svision16_device
+
+class nes_svision16_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_svision16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void update_prg();
+ UINT8 m_latch1, m_latch2;
+};
+
+
+// ======================> nes_n625092_device
+
+class nes_n625092_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_n625092_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void set_prg(UINT8 reg1, UINT8 reg2);
+ UINT8 m_latch1, m_latch2;
+};
+
+
+// ======================> nes_a65as_device
+
+class nes_a65as_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_a65as_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_t262_device
+
+class nes_t262_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_t262_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch1, m_latch2;
+};
+
+
+// ======================> nes_novel1_device
+
+class nes_novel1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_novel1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_novel2_device
+
+class nes_novel2_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_novel2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_studyngame_device
+
+class nes_studyngame_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_studyngame_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sgun20in1_device
+
+class nes_sgun20in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sgun20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_vt5201_device
+
+class nes_vt5201_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_vt5201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch, m_dipsetting;
+};
+
+
+// ======================> nes_810544c_device
+
+class nes_810544c_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_810544c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_ntd03_device
+
+class nes_ntd03_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ntd03_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_gb63_device
+
+class nes_bmc_gb63_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_gb63_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual DECLARE_WRITE8_MEMBER(chr_w);
+
+ virtual void pcb_reset();
+
+private:
+ void update_banks();
+ UINT8 m_latch, m_dipsetting;
+ UINT8 m_reg[2];
+ int m_vram_disable;
+};
+
+// ======================> nes_bmc_gka_device
+
+class nes_bmc_gka_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_gka_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch1, m_latch2;
+};
+
+
+// ======================> nes_bmc_gkb_device
+
+class nes_bmc_gkb_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_gkb_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_ws_device
+
+class nes_bmc_ws_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_ws_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_bmc_11160_device
+
+class nes_bmc_11160_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_11160_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_g146_device
+
+class nes_bmc_g146_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_g146_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_8157_device
+
+class nes_bmc_8157_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_8157_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_hik300_device
+
+class nes_bmc_hik300_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_hik300_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_s700_device
+
+class nes_bmc_s700_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_s700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_ball11_device
+
+class nes_bmc_ball11_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_ball11_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void set_banks();
+ UINT8 m_reg[2];
+};
+
+
+// ======================> nes_bmc_22games_device
+
+class nes_bmc_22games_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_22games_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_64y2k_device
+
+class nes_bmc_64y2k_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_64y2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void set_prg();
+ UINT8 m_reg[4];
+};
+
+
+// ======================> nes_bmc_12in1_device
+
+class nes_bmc_12in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_12in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void update_banks();
+ UINT8 m_reg[4];
+};
+
+
+// ======================> nes_bmc_20in1_device
+
+class nes_bmc_20in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_20in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_21in1_device
+
+class nes_bmc_21in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_21in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_31in1_device
+
+class nes_bmc_31in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_31in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_35in1_device
+
+class nes_bmc_35in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_35in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_36in1_device
+
+class nes_bmc_36in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_36in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_64in1_device
+
+class nes_bmc_64in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_64in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_70in1_device
+
+class nes_bmc_70in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_70in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_mode;
+ UINT8 m_reg[2];
+};
+
+
+// ======================> nes_bmc_72in1_device
+
+class nes_bmc_72in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_72in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_76in1_device
+
+class nes_bmc_76in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_76in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch1, m_latch2;
+};
+
+
+// ======================> nes_bmc_110in1_device
+
+class nes_bmc_110in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_110in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_150in1_device
+
+class nes_bmc_150in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_150in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_190in1_device
+
+class nes_bmc_190in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_190in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_800in1_device
+
+class nes_bmc_800in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_800in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_mode;
+ UINT8 m_reg[2];
+};
+
+
+// ======================> nes_bmc_1200in1_device
+
+class nes_bmc_1200in1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_1200in1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual DECLARE_WRITE8_MEMBER(chr_w);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_vram_protect;
+};
+
+
+// ======================> nes_bmc_gold150_device
+
+class nes_bmc_gold150_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_gold150_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_bmc_gold260_device
+
+class nes_bmc_gold260_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_gold260_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_ch001_device
+
+class nes_bmc_ch001_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_ch001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_bmc_super22_device
+
+class nes_bmc_super22_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_super22_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bmc_4in1reset_device
+
+class nes_bmc_4in1reset_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_4in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void pcb_reset();
+
+private:
+ int m_latch;
+};
+
+// ======================> nes_bmc_42in1reset_device
+
+class nes_bmc_42in1reset_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bmc_42in1reset_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ int m_latch;
+ UINT8 m_reg[2];
+};
+
+
+
+// device type definition
+extern const device_type NES_ACTION52;
+extern const device_type NES_CALTRON6IN1;
+extern const device_type NES_RUMBLESTATION;
+extern const device_type NES_SVISION16;
+extern const device_type NES_N625092;
+extern const device_type NES_A65AS;
+extern const device_type NES_T262;
+extern const device_type NES_NOVEL1;
+extern const device_type NES_NOVEL2;
+extern const device_type NES_STUDYNGAME;
+extern const device_type NES_SUPERGUN20IN1;
+extern const device_type NES_VT5201;
+extern const device_type NES_810544C;
+extern const device_type NES_NTD03;
+extern const device_type NES_BMC_GB63;
+extern const device_type NES_BMC_GKA;
+extern const device_type NES_BMC_GKB;
+extern const device_type NES_BMC_WS;
+extern const device_type NES_BMC_11160;
+extern const device_type NES_BMC_G146;
+extern const device_type NES_BMC_8157;
+extern const device_type NES_BMC_HIK300;
+extern const device_type NES_BMC_S700;
+extern const device_type NES_BMC_BALL11;
+extern const device_type NES_BMC_22GAMES;
+extern const device_type NES_BMC_64Y2K;
+extern const device_type NES_BMC_12IN1;
+extern const device_type NES_BMC_20IN1;
+extern const device_type NES_BMC_21IN1;
+extern const device_type NES_BMC_31IN1;
+extern const device_type NES_BMC_35IN1;
+extern const device_type NES_BMC_36IN1;
+extern const device_type NES_BMC_64IN1;
+extern const device_type NES_BMC_70IN1;
+extern const device_type NES_BMC_72IN1;
+extern const device_type NES_BMC_76IN1;
+extern const device_type NES_BMC_110IN1;
+extern const device_type NES_BMC_150IN1;
+extern const device_type NES_BMC_190IN1;
+extern const device_type NES_BMC_800IN1;
+extern const device_type NES_BMC_1200IN1;
+extern const device_type NES_BMC_GOLD150;
+extern const device_type NES_BMC_GOLD260;
+extern const device_type NES_BMC_CH001;
+extern const device_type NES_BMC_SUPER22;
+extern const device_type NES_BMC_4IN1RESET;
+extern const device_type NES_BMC_42IN1RESET;
+
+
+#endif
diff --git a/src/mess/machine/nes_namcot.c b/src/mess/machine/nes_namcot.c
new file mode 100644
index 00000000000..0547492e574
--- /dev/null
+++ b/src/mess/machine/nes_namcot.c
@@ -0,0 +1,682 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Namcot PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Namcot 3433 & 3443 (aka DxROM) [mapper 88, 204, 154]
+ * Namcot 3446 [mapper 76]
+ * Namcot 3425 [mapper 95]
+ * Namcot 163 [mapper 19]
+ * Namcot 175 [mapper 210]
+ * Namcot 340 [mapper 210]
+
+ TODO:
+ - add sound feature of Namcot-163
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_namcot.h"
+#include "ui.h"
+
+#include "cpu/m6502/m6502.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_NAMCOT3433 = &device_creator<nes_namcot3433_device>;
+const device_type NES_NAMCOT3446 = &device_creator<nes_namcot3446_device>;
+const device_type NES_NAMCOT3425 = &device_creator<nes_namcot3425_device>;
+const device_type NES_NAMCOT175 = &device_creator<nes_namcot175_device>;
+const device_type NES_NAMCOT340 = &device_creator<nes_namcot340_device>;
+const device_type NES_NAMCOT163 = &device_creator<nes_namcot163_device>;
+
+
+nes_namcot3433_device::nes_namcot3433_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_namcot3433_device::nes_namcot3433_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NAMCOT3433, "NES Cart Namcot 3433 & 3443 / DxROM PCB", tag, owner, clock, "nes_namcot3433", __FILE__)
+{
+}
+
+nes_namcot3446_device::nes_namcot3446_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NAMCOT3446, "NES Cart Namcot 3446 PCB", tag, owner, clock, "nes_namcot3446", __FILE__)
+{
+}
+
+nes_namcot3425_device::nes_namcot3425_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NAMCOT3425, "NES Cart Namcot 3425 PCB", tag, owner, clock, "nes_namcot3425", __FILE__)
+{
+}
+
+nes_namcot340_device::nes_namcot340_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_namcot340_device::nes_namcot340_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NAMCOT175, "NES Cart Namcot 340 PCB", tag, owner, clock, "nes_namcot340", __FILE__)
+{
+}
+
+nes_namcot175_device::nes_namcot175_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_namcot340_device(mconfig, NES_NAMCOT340, "NES Cart Namcot 175 PCB", tag, owner, clock, "nes_namcot175", __FILE__)
+{
+}
+
+nes_namcot163_device::nes_namcot163_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_namcot340_device(mconfig, NES_NAMCOT163, "NES Cart Namcot 163 PCB", tag, owner, clock, "nes_namcot163", __FILE__)
+{
+}
+
+
+
+void nes_namcot3433_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_namcot3433_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 2);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_namcot3446_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_namcot3446_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_namcot3425_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_reg));
+}
+
+void nes_namcot3425_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ memset(m_reg, 0, sizeof(m_reg));
+}
+
+void nes_namcot340_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+
+ m_n163_ram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
+ save_pointer(NAME(m_n163_ram), 0x2000);
+
+ m_mapper_sram_size = 0x2000;
+ m_mapper_sram = m_n163_ram;
+}
+
+void nes_namcot340_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+void nes_namcot175_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_wram_enable));
+
+ m_n163_ram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
+ save_pointer(NAME(m_n163_ram), 0x2000);
+
+ m_mapper_sram_size = 0x2000;
+ m_mapper_sram = m_n163_ram;
+}
+
+void nes_namcot175_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ m_wram_enable = 0;
+}
+
+void nes_namcot163_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_wram_protect));
+ save_item(NAME(m_latch));
+ save_item(NAME(m_chr_bank));
+
+ m_n163_ram = auto_alloc_array_clear(machine(), UINT8, 0x2000);
+ save_pointer(NAME(m_n163_ram), 0x2000);
+
+ m_mapper_sram_size = 0x2000;
+ m_mapper_sram = m_n163_ram;
+}
+
+void nes_namcot163_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ m_wram_protect = 0;
+ m_latch = 0;
+ m_chr_bank = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ DxROM & Namcot 3433 - 3443 - 3453 board emulation
+
+ Games: Dragon Spirit - Aratanaru Densetsu, Namcot Mahjong, Quinty,
+ Devilman
+
+ These are the same board, but DRROM (and Tengen 800004) have
+ 4-screen mirroring
+
+ iNES: mappers 88, 206 (same as 88 but possibly 4-screen mirroring),
+ and 154 (same as 88 but with additional mirroring control)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_namcot3433_device::dxrom_write)
+{
+ LOG_MMC(("dxrom_write, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(offset & 1) && m_pcb_ctrl_mirror)
+ set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+
+ if (offset >= 0x2000)
+ return;
+
+ switch (offset & 1)
+ {
+ case 1:
+ switch (m_latch & 0x07)
+ {
+ case 0: chr2_0(data >> 1, CHRROM); break;
+ case 1: chr2_2(data >> 1, CHRROM); break;
+ case 2: chr1_4(data | 0x40, CHRROM); break;
+ case 3: chr1_5(data | 0x40, CHRROM); break;
+ case 4: chr1_6(data | 0x40, CHRROM); break;
+ case 5: chr1_7(data | 0x40, CHRROM); break;
+ case 6: prg8_89(data); break;
+ case 7: prg8_ab(data); break;
+ }
+ break;
+ case 0:
+ m_latch = data;
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+
+ Namcot 3446 board emulation
+
+ Games: Digital Devil Monogatari - Megami Tensei
+
+ These are similar Namcot 34x3, but different bankswitch capabilities
+
+ iNES: mapper 76
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_namcot3446_device::write_h)
+{
+ LOG_MMC(("namcot3446 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // NEStopia does not have this!
+ if (offset >= 0x2000)
+ {
+ if (!(offset & 1))
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ return;
+ }
+
+ switch (offset & 1)
+ {
+ case 1:
+ switch (m_latch & 0x07)
+ {
+ case 2: chr2_0(data, CHRROM); break;
+ case 3: chr2_2(data, CHRROM); break;
+ case 4: chr2_4(data, CHRROM); break;
+ case 5: chr2_6(data, CHRROM); break;
+ case 6: BIT(m_latch, 6) ? prg8_cd(data) : prg8_89(data); break;
+ case 7: prg8_ab(data); break;
+ }
+ break;
+ case 0:
+ m_latch = data;
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Namcot 3425 board emulation
+
+ Games: Dragon Buster
+
+ These are similar Namcot 34x3, but with NT mirroring (two
+ different modes)
+
+ iNES: mapper 95
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_namcot3425_device::write_h)
+{
+ UINT8 mode;
+ LOG_MMC(("namcot3425 write_h, offset: %04x, data: %02x\n", offset, data));
+ if (offset >= 0x2000)
+ return;
+
+ switch (offset & 1)
+ {
+ case 1:
+ mode = m_latch & 0x07;
+ switch (mode)
+ {
+ case 0: chr2_0(data >> 1, CHRROM); break;
+ case 1: chr2_2(data >> 1, CHRROM); break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ chr1_x(2 + mode, data, CHRROM);
+ m_reg[mode - 2] = BIT(data, 5);
+ if (!BIT(m_latch, 7))
+ {
+ set_nt_page(0, CIRAM, m_reg[0], 1);
+ set_nt_page(1, CIRAM, m_reg[1], 1);
+ set_nt_page(2, CIRAM, m_reg[2], 1);
+ set_nt_page(3, CIRAM, m_reg[3], 1);
+ }
+ else
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ break;
+ case 6: prg8_89(data); break;
+ case 7: prg8_ab(data); break;
+ }
+ break;
+ case 0:
+ m_latch = data;
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Namcot-340 board emulation
+
+ Games: Famista '92, '93 & '94, Top Striker,
+ Wagyan Land 2 & 3
+
+ This (and Namcot-175 below) is a cut-down version
+ of the Namcot-163 chip, without the sound capabilities.
+ They also cannot use NTRAM as VRAM and differ for
+ the mirroring handling
+
+ iNES: mapper 210
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+void nes_namcot340_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ if (m_irq_count >= (0x7fff - 114))
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ m_irq_count = 0;
+ }
+ else
+ m_irq_count += 114;
+ }
+}
+
+WRITE8_MEMBER(nes_namcot340_device::n340_lowrite)
+{
+ LOG_MMC(("n340_lowrite, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ switch (offset & 0x1800)
+ {
+ case 0x1000: /* low byte of IRQ */
+ m_irq_count = (m_irq_count & 0x7f00) | data;
+ break;
+ case 0x1800: /* high byte of IRQ, IRQ enable in high bit */
+ m_irq_count = (m_irq_count & 0xff) | ((data & 0x7f) << 8);
+ m_irq_enable = data & 0x80;
+ break;
+ }
+}
+
+READ8_MEMBER(nes_namcot340_device::n340_loread)
+{
+ LOG_MMC(("n340_loread, offset: %04x\n", offset));
+ offset += 0x100;
+
+ switch (offset & 0x1800)
+ {
+ case 0x1000:
+ return m_irq_count & 0xff;
+ case 0x1800:
+ return (m_irq_count >> 8) & 0xff;
+ default:
+ return 0x00;
+ }
+}
+
+WRITE8_MEMBER(nes_namcot340_device::n340_hiwrite)
+{
+ LOG_MMC(("n340_hiwrite, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7800)
+ {
+ case 0x0000: case 0x0800:
+ case 0x1000: case 0x1800:
+ case 0x2000: case 0x2800:
+ case 0x3000: case 0x3800:
+ chr1_x(offset / 0x800, data, CHRROM);
+ break;
+ case 0x4000:
+ // no cart found with wram, so it is not clear if this could work as in Namcot-175...
+ break;
+ case 0x6000:
+ switch (data & 0xc0)
+ {
+ case 0x00:
+ set_nt_mirroring(PPU_MIRROR_LOW);
+ break;
+ case 0x40:
+ set_nt_mirroring(PPU_MIRROR_VERT);
+ break;
+ case 0x80:
+ set_nt_mirroring(PPU_MIRROR_HIGH);
+ break;
+ case 0xc0:
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ break;
+ }
+ prg8_89(data & 0x3f);
+ break;
+ case 0x6800:
+ prg8_ab(data & 0x3f);
+ break;
+ case 0x7000:
+ prg8_cd(data & 0x3f);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+
+ Namcot-175 board emulation
+
+ Games: Chibi Maruko-chan, Family Circuit '91,
+ Famista '91
+
+ This (and Namcot-340 above) is a cut-down version
+ of the Namcot-163 chip, without the sound capabilities.
+ They also cannot use NTRAM as VRAM and differ for
+ the mirroring handling
+
+ iNES: mapper 210
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(nes_namcot175_device::read_m)
+{
+ // the only game supporting this is Family Circuit '91, and it has 2KB of battery
+ if (m_battery && offset < m_battery_size && m_wram_enable)
+ return m_battery[offset & (m_battery_size - 1)];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+WRITE8_MEMBER(nes_namcot175_device::write_m)
+{
+ // the only game supporting this is Family Circuit '91, and it has 2KB of battery
+ if (m_battery && offset < m_battery_size && m_wram_enable)
+ m_battery[offset & (m_battery_size - 1)] = data;
+}
+
+WRITE8_MEMBER(nes_namcot175_device::write_h)
+{
+ LOG_MMC(("namcot175 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7800)
+ {
+ case 0x4000:
+ m_wram_enable = data & 1;
+ break;
+ case 0x6000:
+ prg8_89(data & 0x3f);
+ break;
+ default:
+ n340_hiwrite(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Namcot-163 board emulation
+
+ Games: Battle Fleet, Famista '90, Megami Tensei II,
+ Juvei Quest, etc.
+
+ Compared to Namcot-175 here we have mapper controlled
+ mirroring, NTRAM mapping to VRAM and additional
+ sound hw inside the chip (currently unemulated) and
+ some internal RAM.
+
+ iNES: mapper 19
+
+ In MESS: Supported (with no emulation of the
+ sound component)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_namcot163_device::chr_w)
+{
+ int bank = offset >> 10;
+
+ if (!(m_latch) & 0x40 && m_chr_bank >= 0xe0)
+ {
+ // CIRAM!!!
+ ui_popup_time(10, "CIRAM mapped to VRAM. Please contact MAMEDevs.");
+
+ if (!m_nt_writable[bank & 0x03])
+ return;
+ m_nt_access[bank & 0x03][offset & 0x3ff] = data;
+ }
+ // or ROM, so no write
+}
+
+READ8_MEMBER(nes_namcot163_device::chr_r)
+{
+ int bank = offset >> 10;
+ if (!(m_latch) & 0x40 && m_chr_bank >= 0xe0)
+ {
+ // CIRAM!!!
+ ui_popup_time(10, "CIRAM mapped to VRAM. Please contact MAMEDevs.");
+ return m_nt_access[bank & 0x03][offset & 0x3ff];
+ }
+ // or ROM, accessed as usual
+ return m_chr_access[bank][offset & 0x3ff];
+}
+
+
+READ8_MEMBER(nes_namcot163_device::read_m)
+{
+ if (m_battery && offset < m_battery_size)
+ return m_battery[offset & (m_battery_size - 1)];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+WRITE8_MEMBER(nes_namcot163_device::write_m)
+{
+ // the pcb can separately protect each 2KB chunk of the external wram from writes
+ int bank = (offset & 0x1800) >> 11;
+ if (m_battery && !BIT(m_wram_protect, bank))
+ m_battery[offset & (m_battery_size - 1)] = data;
+}
+
+WRITE8_MEMBER(nes_namcot163_device::write_l)
+{
+ LOG_MMC(("namcot163 write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ switch (offset & 0x1800)
+ {
+ case 0x0800:
+ LOG_MMC(("Namcot-163 sound reg write, data: %02x\n", data));
+ break;
+ default:
+ n340_lowrite(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+READ8_MEMBER(nes_namcot163_device::read_l)
+{
+ LOG_MMC(("namcot163 read_l, offset: %04x\n", offset));
+ offset += 0x100;
+
+ switch (offset & 0x1800)
+ {
+ case 0x0800:
+ LOG_MMC(("Namcot-163 sound reg read\n"));
+ return 0;
+ default:
+ return n340_loread(space, offset, mem_mask);
+ }
+}
+
+void nes_namcot163_device::set_mirror(UINT8 page, UINT8 data)
+{
+ if (data < 0xe0)
+ set_nt_page(page, VROM, data, 0);
+ else
+ set_nt_page(page, CIRAM, data & 0x01, 1);
+}
+
+WRITE8_MEMBER(nes_namcot163_device::write_h)
+{
+ int page;
+ LOG_MMC(("namcot163 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7800)
+ {
+ case 0x0000: case 0x0800:
+ case 0x1000: case 0x1800:
+ case 0x2000: case 0x2800:
+ case 0x3000: case 0x3800:
+ m_chr_bank = data;
+ chr1_x(offset / 0x800, m_chr_bank, CHRROM);
+ break;
+ case 0x4000:
+ case 0x4800:
+ case 0x5000:
+ case 0x5800:
+ page = (offset & 0x1800) >> 11;
+ set_mirror(page, data);
+ break;
+ case 0x6000:
+ // TODO: data & 40 (or data & c0) disable sound if set
+ prg8_89(data & 0x3f);
+ break;
+ case 0x6800:
+ m_latch = data & 0xc0;
+ prg8_ab(data & 0x3f);
+ break;
+ case 0x7800:
+ // the lower 4 bits work *BOTH* as WRAM write protect *AND* as sound address!
+ m_wram_protect = data & 0x0f;
+ LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data));
+ break;
+ default:
+ n340_hiwrite(space, offset, data, mem_mask);
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_namcot.h b/src/mess/machine/nes_namcot.h
new file mode 100644
index 00000000000..2ef881a1824
--- /dev/null
+++ b/src/mess/machine/nes_namcot.h
@@ -0,0 +1,158 @@
+#ifndef __NES_NAMCOT_H
+#define __NES_NAMCOT_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_namcot3433_device
+
+class nes_namcot3433_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_namcot3433_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);
+ nes_namcot3433_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(dxrom_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { dxrom_write(space, offset, data, mem_mask); }
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_namcot3446_device
+
+class nes_namcot3446_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_namcot3446_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_namcot3425_device
+
+class nes_namcot3425_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_namcot3425_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+ UINT8 m_reg[4];
+};
+
+
+// ======================> nes_namcot340_device
+
+class nes_namcot340_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_namcot340_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);
+ nes_namcot340_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(n340_loread);
+ virtual DECLARE_WRITE8_MEMBER(n340_lowrite);
+ virtual DECLARE_WRITE8_MEMBER(n340_hiwrite);
+ virtual DECLARE_READ8_MEMBER(read_l) { return n340_loread(space, offset, mem_mask); }
+ virtual DECLARE_WRITE8_MEMBER(write_l) { n340_lowrite(space, offset, data, mem_mask); }
+ virtual DECLARE_WRITE8_MEMBER(write_h) { n340_hiwrite(space, offset, data, mem_mask); }
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ UINT16 m_irq_count;
+ int m_irq_enable;
+
+ // Namcot-163 chip contains 8K of internal ram, possibly battery backed up (not emulated yet)
+ // was it also present in 175 & 340 chips?
+ UINT8 *m_n163_ram;
+};
+
+
+// ======================> nes_namcot175_device
+
+class nes_namcot175_device : public nes_namcot340_device
+{
+public:
+ // construction/destruction
+ nes_namcot175_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_wram_enable;
+};
+
+
+// ======================> nes_namcot163_device
+
+class nes_namcot163_device : public nes_namcot340_device
+{
+public:
+ // construction/destruction
+ nes_namcot163_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ // we have to overwrite these to allow CIRAM to be used for VRAM, even if it's not clear which game(s) use this
+ virtual DECLARE_READ8_MEMBER(chr_r);
+ virtual DECLARE_WRITE8_MEMBER(chr_w);
+
+ virtual void pcb_reset();
+
+private:
+ void set_mirror(UINT8 page, UINT8 data);
+
+ UINT8 m_wram_protect, m_latch, m_chr_bank;
+ // TODO: add emulation of the sound part of the chip
+};
+
+
+
+// device type definition
+extern const device_type NES_NAMCOT3433;
+extern const device_type NES_NAMCOT3446;
+extern const device_type NES_NAMCOT3425;
+extern const device_type NES_NAMCOT175;
+extern const device_type NES_NAMCOT340;
+extern const device_type NES_NAMCOT163;
+
+#endif
diff --git a/src/mess/machine/nes_nanjing.c b/src/mess/machine/nes_nanjing.c
new file mode 100644
index 00000000000..469371b2e29
--- /dev/null
+++ b/src/mess/machine/nes_nanjing.c
@@ -0,0 +1,176 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Nanjing PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+ TODO:
+ - Emulate the variants often assigned to mapper 162/164 (and investigate connection with Waixing FS-304)!
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_nanjing.h"
+
+#include "video/ppu2c0x.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_NANJING = &device_creator<nes_nanjing_device>;
+
+
+nes_nanjing_device::nes_nanjing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NANJING, "NES Cart Nanjing PCB", tag, owner, clock, "nes_nanjing", __FILE__)
+{
+}
+
+
+
+
+void nes_nanjing_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_count));
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+ save_item(NAME(m_reg));
+}
+
+void nes_nanjing_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 2);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_count = 0xff;
+ m_latch1 = 0;
+ m_latch2 = 0;
+ m_reg[0] = 0xff;
+ m_reg[1] = 0;
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bootleg Board by Nanjing
+
+ Games: A lot of pirate originals
+
+ iNES: mapper 163
+
+ In MESS: Unsupported.
+
+ -------------------------------------------------*/
+
+void nes_nanjing_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (BIT(m_reg[0], 7))
+ {
+ if (scanline == 127)
+ {
+ chr4_0(1, CHRRAM);
+ chr4_4(1, CHRRAM);
+ }
+
+ if (scanline == 239)
+ {
+ chr4_0(0, CHRRAM);
+ chr4_4(0, CHRRAM);
+ }
+ }
+
+}
+
+WRITE8_MEMBER(nes_nanjing_device::write_l)
+{
+ LOG_MMC(("nanjing write_l, offset: %04x, data: %02x\n", offset, data));
+
+ offset += 0x100;
+
+ if (offset < 0x1000)
+ return;
+
+ if (offset == 0x1100) // 0x5100
+ {
+ if (data == 6)
+ prg32(3);
+ return;
+ }
+
+ if (offset == 0x1101) // 0x5101
+ {
+ UINT8 temp = m_count;
+ m_count = data;
+
+ if (temp & !data)
+ m_latch2 ^= 0xff;
+ }
+
+ switch (offset & 0x300)
+ {
+ case 0x000:
+ case 0x200:
+ m_reg[BIT(offset, 9)] = data;
+ if (!BIT(m_reg[0], 7) && machine().device<ppu2c0x_device>("ppu")->get_current_scanline() <= 127)
+ chr8(0, CHRRAM);
+ break;
+ case 0x300:
+ m_latch1 = data;
+ break;
+ }
+
+ prg32((m_reg[0] & 0x0f) | ((m_reg[1] & 0x0f) << 4));
+}
+
+READ8_MEMBER(nes_nanjing_device::read_l)
+{
+ UINT8 value = 0;
+ LOG_MMC(("nanjing read_l, offset: %04x\n", offset));
+
+ offset += 0x100;
+
+ if (offset < 0x1000)
+ return 0;
+
+ switch (offset & 0x700)
+ {
+ case 0x100:
+ value = m_latch1;
+ break;
+ case 0x500:
+ value = m_latch2 & m_latch1;
+ break;
+ case 0x000:
+ case 0x200:
+ case 0x300:
+ case 0x400:
+ case 0x600:
+ case 0x700:
+ value = 4;
+ break;
+ }
+ return value;
+}
diff --git a/src/mess/machine/nes_nanjing.h b/src/mess/machine/nes_nanjing.h
new file mode 100644
index 00000000000..71a93d11ee0
--- /dev/null
+++ b/src/mess/machine/nes_nanjing.h
@@ -0,0 +1,36 @@
+#ifndef __NES_NANJING_H
+#define __NES_NANJING_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_nanjing_device
+
+class nes_nanjing_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_nanjing_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_count;
+ UINT8 m_reg[2];
+ UINT8 m_latch1, m_latch2;
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_NANJING;
+
+#endif
diff --git a/src/mess/machine/nes_ntdec.c b/src/mess/machine/nes_ntdec.c
new file mode 100644
index 00000000000..dc9379ac6cd
--- /dev/null
+++ b/src/mess/machine/nes_ntdec.c
@@ -0,0 +1,185 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for NTDEC PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * NTDEC ASDER [mapper 112]
+ * NTDEC Fighting Hero [mapper 193]
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_ntdec.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_NTDEC_ASDER = &device_creator<nes_ntdec_asder_device>;
+const device_type NES_NTDEC_FH = &device_creator<nes_ntdec_fh_device>;
+
+
+nes_ntdec_asder_device::nes_ntdec_asder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NTDEC_ASDER, "NES Cart NTDEC Asder PCB", tag, owner, clock, "nes_ntdec_asder", __FILE__)
+{
+}
+
+nes_ntdec_fh_device::nes_ntdec_fh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_NTDEC_FH, "NES Cart NTDEC Fighting Hero PCB", tag, owner, clock, "nes_ntdec_fh", __FILE__)
+{
+}
+
+
+
+
+void nes_ntdec_asder_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_ntdec_asder_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_ntdec_fh_device::device_start()
+{
+ common_start();
+}
+
+void nes_ntdec_fh_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32((m_prg_chunks - 1) >> 1);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ NTDEC ASDER Bootleg Board
+
+ Games: Cobra Mission, Fighting Hero III, Huang Di, Master
+ Shooter
+
+ iNES: mapper 112
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ntdec_asder_device::write_h)
+{
+ LOG_MMC(("ntdec_asder write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x0000:
+ m_latch = data & 0x07;
+ break;
+ case 0x2000:
+ switch (m_latch)
+ {
+ case 0:
+ prg8_89(data);
+ break;
+ case 1:
+ prg8_ab(data);
+ break;
+ case 2:
+ data &= 0xfe;
+ chr1_0(data, CHRROM);
+ chr1_1(data + 1, CHRROM);
+ break;
+ case 3:
+ data &= 0xfe;
+ chr1_2(data, CHRROM);
+ chr1_3(data + 1, CHRROM);
+ break;
+ case 4:
+ chr1_4(data, CHRROM);
+ break;
+ case 5:
+ chr1_5(data, CHRROM);
+ break;
+ case 6:
+ chr1_6(data, CHRROM);
+ break;
+ case 7:
+ chr1_7(data, CHRROM);
+ break;
+ }
+ break;
+ case 0x6000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by NTDEC for Fighting Hero
+
+ Games: Fighting Hero
+
+ Very simple mapper: writes to 0x6000-0x7fff swap PRG and
+ CHR banks.
+
+ iNES: mapper 193
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_ntdec_fh_device::write_m)
+{
+ LOG_MMC(("ntdec_fh write_m, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x03)
+ {
+ case 0:
+ chr4_0(data >> 2, CHRROM);
+ break;
+ case 1:
+ chr2_4(data >> 1, CHRROM);
+ break;
+ case 2:
+ chr2_6(data >> 1 , CHRROM);
+ break;
+ case 3:
+ prg8_89(data);
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_ntdec.h b/src/mess/machine/nes_ntdec.h
new file mode 100644
index 00000000000..df2b9cf2bc4
--- /dev/null
+++ b/src/mess/machine/nes_ntdec.h
@@ -0,0 +1,49 @@
+#ifndef __NES_NTDEC_H
+#define __NES_NTDEC_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_ntdec_asder_device
+
+class nes_ntdec_asder_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ntdec_asder_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_ntdec_fh_device
+
+class nes_ntdec_fh_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_ntdec_fh_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_NTDEC_ASDER;
+extern const device_type NES_NTDEC_FH;
+
+#endif
diff --git a/src/mess/machine/nes_nxrom.c b/src/mess/machine/nes_nxrom.c
new file mode 100644
index 00000000000..55ff5f07a39
--- /dev/null
+++ b/src/mess/machine/nes_nxrom.c
@@ -0,0 +1,494 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Nintendo xxROM PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Nintendo NROM [mapper 0]
+ * Nintendo AxROM [mapper 7]
+ * Nintendo BxROM [mapper 34]
+ * Nintendo CNROM [mapper 3 & 185]
+ * Nintendo CPROM [mapper 13]
+ * Nintendo GxROM/MxROM [mapper 66]
+ * Nintendo UxROM [mapper 2] + Crazy Climbers variant [mapper 180]
+ * Nintendo UN1ROM [mapper 94]
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_nxrom.h"
+
+#include "sound/samples.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_NROM = &device_creator<nes_nrom_device>;
+const device_type NES_FCBASIC = &device_creator<nes_fcbasic_device>;
+const device_type NES_AXROM = &device_creator<nes_axrom_device>;
+const device_type NES_BXROM = &device_creator<nes_bxrom_device>;
+const device_type NES_CNROM = &device_creator<nes_cnrom_device>;
+const device_type NES_CPROM = &device_creator<nes_cprom_device>;
+const device_type NES_GXROM = &device_creator<nes_gxrom_device>;
+const device_type NES_UXROM = &device_creator<nes_uxrom_device>;
+const device_type NES_UXROM_CC = &device_creator<nes_uxrom_cc_device>;
+const device_type NES_UN1ROM = &device_creator<nes_un1rom_device>;
+
+
+nes_nrom_device::nes_nrom_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_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_nes_cart_interface( mconfig, *this )
+{
+}
+
+nes_nrom_device::nes_nrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, NES_NROM, "NES Cart NROM PCB", tag, owner, clock, "nes_nrom", __FILE__),
+ device_nes_cart_interface( mconfig, *this )
+{
+}
+
+nes_fcbasic_device::nes_fcbasic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_FCBASIC, "NES Cart Famicom BASIC PCB", tag, owner, clock, "nes_fcbasic", __FILE__)
+{
+}
+
+nes_axrom_device::nes_axrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_AXROM, "NES Cart AxROM PCB", tag, owner, clock, "nes_axrom", __FILE__)
+{
+}
+
+nes_bxrom_device::nes_bxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_BXROM, "NES Cart BxROM PCB", tag, owner, clock, "nes_bxrom", __FILE__)
+{
+}
+
+nes_cnrom_device::nes_cnrom_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_cnrom_device::nes_cnrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_CNROM, "NES Cart CNROM PCB", tag, owner, clock, "nes_cnrom", __FILE__)
+{
+}
+
+nes_cprom_device::nes_cprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_CPROM, "NES Cart CPROM PCB", tag, owner, clock, "nes_cprom", __FILE__)
+{
+}
+
+nes_gxrom_device::nes_gxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_GXROM, "NES Cart GxROM PCB", tag, owner, clock, "nes_gxrom", __FILE__)
+{
+}
+
+nes_uxrom_device::nes_uxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_UXROM, "NES Cart UxROM PCB", tag, owner, clock, "nes_uxrom", __FILE__)
+{
+}
+
+nes_uxrom_cc_device::nes_uxrom_cc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_UXROM_CC, "NES Cart UNROM M5 PCB (Crazy Climber)", tag, owner, clock, "nes_uxrom_cc", __FILE__)
+{
+}
+
+nes_un1rom_device::nes_un1rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_UN1ROM, "NES Cart UN1ROM PCB", tag, owner, clock, "nes_un1rom", __FILE__)
+{
+}
+
+
+void nes_nrom_device::common_start()
+{
+ // PRG
+ save_item(NAME(m_prg_bank));
+
+ // CHR
+ save_item(NAME(m_chr_source));
+ save_item(NAME(m_chr_src));
+ save_item(NAME(m_chr_orig));
+
+ // NT
+ save_item(NAME(m_mirroring));
+ save_item(NAME(m_nt_src));
+ save_item(NAME(m_nt_orig));
+ save_item(NAME(m_nt_writable));
+}
+
+void nes_nrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_axrom_device::device_start()
+{
+ common_start();
+}
+
+void nes_axrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ set_nt_mirroring(PPU_MIRROR_LOW);
+}
+
+void nes_bxrom_device::device_start()
+{
+ common_start();
+}
+
+void nes_bxrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_cnrom_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_chr_open_bus));
+}
+
+void nes_cnrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_chr_open_bus = 0;
+}
+
+void nes_cprom_device::device_start()
+{
+ common_start();
+}
+
+void nes_cprom_device::pcb_reset()
+{
+ m_chr_source = CHRRAM;
+ prg32(0);
+ chr4_0(0, m_chr_source);
+ chr4_4(0, m_chr_source);
+}
+
+void nes_gxrom_device::device_start()
+{
+ common_start();
+}
+
+void nes_gxrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_uxrom_device::device_start()
+{
+ common_start();
+}
+
+void nes_uxrom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_uxrom_cc_device::device_start()
+{
+ common_start();
+}
+
+void nes_uxrom_cc_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_un1rom_device::device_start()
+{
+ common_start();
+}
+
+void nes_un1rom_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ NROM board emulation
+
+ Games: Mario Bros., Super Mario Bros., Tennis and most of
+ the first generation games
+
+ iNES: mapper 0
+
+ In MESS: Supported, no need of specific handlers or IRQ
+
+ -------------------------------------------------*/
+
+
+/*-------------------------------------------------
+
+ AxROM board emulation
+
+ Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice
+
+ writes to 0x8000-0xffff change PRG banks + sets mirroring
+
+ AMROM has bus conflict
+ AOROM has generally bus conflict too, but some later pcbs
+ added some discrete component to disable ROM and avoid
+ conflicts. No AOROM games is known to glitch due to lack of
+ bus conflict, so it seems safe to emulate AOROM
+ without bus conflict.
+
+ iNES: mapper 7
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_axrom_device::write_h)
+{
+ LOG_MMC(("axrom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ prg32(data);
+}
+
+/*-------------------------------------------------
+
+ BxROM board emulation
+
+ writes to 0x8000-0xffff change PRG banks
+
+ iNES: mapper 34
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bxrom_device::write_h)
+{
+ /* This portion of the mapper is nearly identical to Mapper 7, except no one-screen mirroring */
+ /* Deadly Towers is really a BxROM game - the demo screens look wrong using mapper 7. */
+ LOG_MMC(("bxrom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict, but the same is not true for some pirate variants
+ data = account_bus_conflict(offset, data);
+
+ prg32(data);
+}
+
+/*-------------------------------------------------
+
+ CNROM board emulation
+
+ Games: B-Wings, Mighty Bomb Jack, Seicross, Spy vs. Spy,
+ Adventure Island, Flipull, Friday 13th, GeGeGe no
+ Kitarou, Ghostbusters, Gradius, Hokuto no Ken, Milon's
+ Secret Castle
+
+ writes to 0x8000-0xffff change CHR 8K banks
+
+ missing BC?
+
+ iNES: mappers 3 & 185 (the latter for games using Pins as
+ protection)
+
+ Notice that BANDAI_PT554 board (Aerobics Studio) uses very
+ similar hardware but with an additional sound chip which
+ gets writes to 0x6000 (currently unemulated in MESS)
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_cnrom_device::write_h)
+{
+ LOG_MMC(("cxrom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict, but the same is not true for some pirate variants
+ data = account_bus_conflict(offset, data);
+
+ if (m_ce_mask)
+ {
+ chr8(data & ~m_ce_mask, CHRROM);
+
+ if ((data & m_ce_mask) == m_ce_state)
+ m_chr_open_bus = 0;
+ else
+ m_chr_open_bus = 1;
+ }
+ else
+ chr8(data, CHRROM);
+}
+
+READ8_MEMBER(nes_cnrom_device::chr_r)
+{
+ int bank = offset >> 10;
+
+ // a few CNROM boards contained copy protection schemes through
+ // suitably configured diodes, so that subsequent CHR reads can
+ // give actual VROM content or open bus values.
+ // For most boards, chr_open_bus remains always zero.
+ if (m_chr_open_bus)
+ return 0xff;
+
+ return m_chr_access[bank][offset & 0x3ff];
+}
+
+
+/*-------------------------------------------------
+
+ CPROM board emulation
+
+ Games: Videomation
+
+ writes to 0x8000-0xffff change CHR 4K lower banks
+
+ iNES: mapper 13
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_cprom_device::write_h)
+{
+ LOG_MMC(("cprom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ chr4_4(data, CHRRAM);
+}
+
+
+/*-------------------------------------------------
+
+ GxROM/MxROM board emulation
+
+ writes to 0x8000-0xffff change PRG and CHR banks
+
+ iNES: mapper 66
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_gxrom_device::write_h)
+{
+ LOG_MMC(("gxrom write_h, offset %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ prg32((data & 0xf0) >> 4);
+ chr8(data & 0x0f, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ UxROM board emulation
+
+ Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan,
+ Metal Gear
+
+ writes to 0x8000-0xffff change PRG 16K lower banks
+
+ iNES: mapper 2
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_uxrom_device::write_h)
+{
+ LOG_MMC(("uxrom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ prg16_89ab(data);
+}
+
+/*-------------------------------------------------
+
+ Nihon Bussan UNROM M5
+
+ Games: Crazy Climber Jpn
+
+ Very simple mapper: prg16_89ab is always set to bank 0,
+ while prg16_cdef is set by writes to 0x8000-0xffff. The game
+ uses a custom controller.
+
+ iNES: mapper 180
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_uxrom_cc_device::write_h)
+{
+ LOG_MMC(("uxrom_cc write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg16_cdef(data);
+}
+
+/*-------------------------------------------------
+
+ UN1ROM board emulation
+
+ Games: Senjou no Okami
+
+ writes to 0x8000-0xffff change PRG 16K lower banks
+
+ iNES: mapper 94
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_un1rom_device::write_h)
+{
+ LOG_MMC(("un1rom write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ prg16_89ab(data >> 2);
+}
diff --git a/src/mess/machine/nes_nxrom.h b/src/mess/machine/nes_nxrom.h
new file mode 100644
index 00000000000..89fbee933e7
--- /dev/null
+++ b/src/mess/machine/nes_nxrom.h
@@ -0,0 +1,184 @@
+#ifndef __NES_MMCX_H
+#define __NES_MMCX_H
+
+#include "machine/nes_slot.h"
+#include "sound/samples.h"
+
+
+// ======================> nes_nrom_device
+
+class nes_nrom_device : public device_t,
+ public device_nes_cart_interface
+{
+public:
+ // construction/destruction
+ nes_nrom_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);
+ nes_nrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void device_start() { common_start(); }
+
+ virtual void pcb_reset();
+
+ void common_start();
+};
+
+
+// ======================> nes_fcbasic_device
+
+class nes_fcbasic_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_fcbasic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // emulate the additional WRAM
+};
+
+
+// ======================> nes_axrom_device
+
+class nes_axrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_axrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_bxrom_device
+
+class nes_bxrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_bxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_cnrom_device
+
+class nes_cnrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_cnrom_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);
+ nes_cnrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(chr_r);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_chr_open_bus;
+};
+
+
+// ======================> nes_cprom_device
+
+class nes_cprom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_cprom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_gxrom_device
+
+class nes_gxrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_gxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_uxrom_device
+
+class nes_uxrom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_uxrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_uxrom_cc_device
+
+class nes_uxrom_cc_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_uxrom_cc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_un1rom_device
+
+class nes_un1rom_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_un1rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+
+// device type definition
+extern const device_type NES_NROM;
+extern const device_type NES_FCBASIC;
+extern const device_type NES_AXROM;
+extern const device_type NES_BXROM;
+extern const device_type NES_CNROM;
+extern const device_type NES_CPROM;
+extern const device_type NES_GXROM;
+extern const device_type NES_UXROM;
+extern const device_type NES_UXROM_CC;
+extern const device_type NES_UN1ROM;
+
+#endif
diff --git a/src/mess/machine/nes_pcb.c b/src/mess/machine/nes_pcb.c
index 53d12e35339..bbe76a7eb90 100644
--- a/src/mess/machine/nes_pcb.c
+++ b/src/mess/machine/nes_pcb.c
@@ -6,13114 +6,593 @@
struct nes_pcb
{
- const char *pcb_name;
+ const char *slot_opt;
int pcb_id;
};
// Here, we take the feature attribute from .xml (i.e. the PCB name) and we assign a unique ID to it
static const nes_pcb pcb_list[] =
{
- /* Nintendo HROM, NROM, RROM, SROM & STROM */
- { "HVC-HROM", STD_NROM },
- { "HVC-NROM", STD_NROM },
- { "HVC-NROM-128", STD_NROM },
- { "HVC-NROM-256", STD_NROM },
- { "HVC-RROM", STD_NROM },
- { "HVC-RROM-128", STD_NROM },
- { "HVC-RTROM", STD_NROM },
- { "HVC-SROM", STD_NROM },
- { "HVC-STROM", STD_NROM },
- { "NES-HROM", STD_NROM },
- { "NES-NROM", STD_NROM },
- { "NES-NROM-128", STD_NROM },
- { "NES-NROM-256", STD_NROM },
- { "NES-RROM", STD_NROM },
- { "NES-RROM-128", STD_NROM },
- { "NES-SROM", STD_NROM },
- { "NES-STROM", STD_NROM },
- /* "No mapper" boards by other manufacturer */
- { "IREM-NROM-128", STD_NROM },
- { "IREM-NROM-256", STD_NROM },
- { "BANDAI-NROM-128", STD_NROM },
- { "BANDAI-NROM-256", STD_NROM },
- { "KONAMI-NROM-128", STD_NROM },
- { "SETA-NROM-128", STD_NROM },
- { "SUNSOFT-NROM-128", STD_NROM },
- { "SUNSOFT-NROM-256", STD_NROM },
- { "TAITO-NROM-128", STD_NROM },
- { "TAITO-NROM-256", STD_NROM },
- { "NAMCOT-3301", STD_NROM },
- { "NAMCOT-3302", STD_NROM },
- { "NAMCOT-3303", STD_NROM },
- { "NAMCOT-3304", STD_NROM },
- { "NAMCOT-3305", STD_NROM },
- { "NAMCOT-3311", STD_NROM },
- { "NAMCOT-3312", STD_NROM },
- { "NAMCOT-3411", STD_NROM },
- { "JALECO-JF-01", STD_NROM },
- { "JALECO-JF-02", STD_NROM },
- { "JALECO-JF-03", STD_NROM },
- { "JALECO-JF-04", STD_NROM },
- { "TENGEN-800003", STD_NROM },
- { "SACHEN-NROM", STD_NROM },
- /* Nintendo Family BASIC pcb (NROM + 2K or 4K WRAM) */
- { "HVC-FAMILYBASIC", HVC_FAMBASIC },
- /* Game Genie */
- { "CAMERICA-GAMEGENIE", GG_NROM },
-//
- /* Nintendo UNROM/UOROM */
- { "HVC-UNROM", STD_UXROM },
- { "HVC-UNEPROM", STD_UXROM },
- { "HVC-UOROM", STD_UXROM },
- { "NES-UNROM", STD_UXROM },
- { "NES-UNEPROM", STD_UXROM },
- { "NES-UOROM", STD_UXROM },
- { "HVC-UNROM+74HC08", UXROM_CC },
- /* UxROM boards by other manufacturer */
- { "IREM-UNROM", STD_UXROM },
- { "KONAMI-UNROM", STD_UXROM },
- { "TAITO-UNROM", STD_UXROM },
- { "JALECO-JF-15", STD_UXROM },
- { "JALECO-JF-18", STD_UXROM },
- { "JALECO-JF-39", STD_UXROM },
-//
- /* Nintendo CNROM */
- { "HVC-CNROM", STD_CNROM },
- { "NES-CNROM", STD_CNROM },
- /* CxROM boards by other manufacturer */
- { "BANDAI-CNROM", STD_CNROM },
- { "BANDAI-74*161/32", STD_CNROM },
- { "KONAMI-CNROM", STD_CNROM },
- { "NAMCOT-CNROM+WRAM", STD_CNROM },
- { "TAITO-CNROM", STD_CNROM },
- { "AVE-74*161", STD_CNROM },
- { "NTDEC-N715061", STD_CNROM },
- { "NTDEC-N715062", STD_CNROM },
- { "SACHEN-CNROM", STD_CNROM },
- /* Bandai Aerobics Studio (CNROM boards + special audio chip) */
- { "BANDAI-PT-554", BANDAI_PT554 },
- /* FIXME: Is this the same as mapper 3? */
- { "TENGEN-800008", TENGEN_800008 },
-//
- /* Nintendo AxROM */
- { "HVC-AMROM", STD_AXROM },
- { "HVC-AN1ROM", STD_AXROM },
- { "HVC-ANROM", STD_AXROM },
- { "HVC-AOROM", STD_AXROM },
- { "NES-AMROM", STD_AXROM },
- { "NES-AN1ROM", STD_AXROM },
- { "NES-ANROM", STD_AXROM },
- { "NES-AOROM", STD_AXROM },
- /* AxROM boards by other manufacturer */
- { "ACCLAIM-AOROM", STD_AXROM },
-//
- /* Nintendo PxROM */
- { "HVC-PEEOROM", STD_PXROM },
- { "HVC-PNROM", STD_PXROM },
- { "NES-PEEOROM", STD_PXROM },
- { "NES-PNROM", STD_PXROM },
-//
- /* Nintendo FxROM */
- { "HVC-FJROM", STD_FXROM },
- { "HVC-FKROM", STD_FXROM },
- { "NES-FJROM", STD_FXROM },
- { "NES-FKROM", STD_FXROM },
-//
- /* Nintendo BXROM */
- { "HVC-BNROM", STD_BXROM },
- { "NES-BNROM", STD_BXROM },
- /* BxROM boards by other manufacturer */
- { "IREM-BNROM", STD_BXROM },
-//
- /* Nintendo CPROM */
- { "HVC-CPROM", STD_CPROM },
- { "NES-CPROM", STD_CPROM },
-//
- /* Nintendo GNROM & MHROM */
- { "HVC-GNROM", STD_GXROM },
- { "NES-GNROM", STD_GXROM },
- { "HVC-MHROM", STD_MXROM },
- { "NES-MHROM", STD_MXROM },
- { "PAL-MH", STD_MXROM },
- /* GxROM boards by other manufacturer */
- { "BANDAI-GNROM", STD_GXROM },
-//
- /* Nintendo NxROM */
- { "HVC-NTBROM", STD_NXROM },
- { "NES-NTBROM", STD_NXROM },
- /* NxROM boards by other manufacturer (this board was mainly used by Sunsoft?) */
- { "SUNSOFT-4", STD_NXROM },
- { "SUNSOFT-DCS", SUNSOFT_DCS },
- { "TENGEN-800042", STD_NXROM },
-//
- /* Nintendo JxROM */
- { "HVC-JLROM", STD_JXROM },
- { "HVC-JSROM", STD_JXROM },
- { "NES-JLROM", STD_JXROM },
- { "NES-JSROM", STD_JXROM },
- { "NES-BTR", STD_JXROM },
- /* JxROM boards by other manufacturer (this board was mainly used by Sunsoft?) */
- { "SUNSOFT-5A", STD_JXROM },
- { "SUNSOFT-5B", STD_JXROM },
- { "SUNSOFT-FME-7", STD_JXROM },
-//
- /* Nintendo UN1ROM */
- { "HVC-UN1ROM", STD_UN1ROM },
- { "NES-UN1ROM", STD_UN1ROM },
-//
- /* Nintendo SxROM */
- { "HVC-SAROM", STD_SXROM },
- { "HVC-SBROM", STD_SXROM },
- { "HVC-SC1ROM", STD_SXROM },
- { "HVC-SCROM", STD_SXROM },
- { "HVC-SEROM", STD_SXROM },
- { "HVC-SF1ROM", STD_SXROM },
- { "HVC-SFROM", STD_SXROM },
- { "HVC-SGROM", STD_SXROM },
- { "HVC-SH1ROM", STD_SXROM },
- { "HVC-SHROM", STD_SXROM },
- { "HVC-SIROM", STD_SXROM },
- { "HVC-SJROM", STD_SXROM },
- { "HVC-SKROM", STD_SXROM },
- { "HVC-SKEPROM", STD_SXROM },
- { "HVC-SL1ROM", STD_SXROM },
- { "HVC-SL2ROM", STD_SXROM },
- { "HVC-SL3ROM", STD_SXROM },
- { "HVC-SLROM", STD_SXROM },
- { "HVC-SLRROM", STD_SXROM },
- { "HVC-SMROM", STD_SXROM },
- { "HVC-SNROM", STD_SXROM },
- { "HVC-SUROM", STD_SXROM },
- { "HVC-SXROM", STD_SXROM },
- { "NES-SAROM", STD_SXROM },
- { "NES-SBROM", STD_SXROM },
- { "NES-SC1ROM", STD_SXROM },
- { "NES-SCROM", STD_SXROM },
- { "NES-SEROM", STD_SXROM },
- { "NES-SF1ROM", STD_SXROM },
- { "NES-SFROM", STD_SXROM },
- { "NES-SGROM", STD_SXROM },
- { "NES-SH1ROM", STD_SXROM },
- { "NES-SHROM", STD_SXROM },
- { "NES-SIROM", STD_SXROM },
- { "NES-SIEPROM", STD_SXROM },
- { "NES-SJROM", STD_SXROM },
- { "NES-SKROM", STD_SXROM },
- { "NES-SKEPROM", STD_SXROM },
- { "NES-SL1ROM", STD_SXROM },
- { "NES-SL2ROM", STD_SXROM },
- { "NES-SL3ROM", STD_SXROM },
- { "NES-SLROM", STD_SXROM },
- { "NES-SLRROM", STD_SXROM },
- { "NES-SMROM", STD_SXROM },
- { "NES-SNROM", STD_SXROM },
- { "NES-SNWEPROM", STD_SXROM },
- { "NES-SUROM", STD_SXROM },
- { "NES-SXROM", STD_SXROM },
- { "NES-WH", STD_SXROM },
- { "NES-SOROM", STD_SOROM },
- { "HVC-SOROM", STD_SOROM },
- /* SxROM boards by other manufacturer */
- { "KONAMI-SLROM", STD_SXROM },
- { "VIRGIN-SNROM", STD_SXROM },
-//
- /* Nintendo TxROM */
- { "HVC-TBROM", STD_TXROM },
- { "HVC-TEROM", STD_TXROM },
- { "HVC-TFROM", STD_TXROM },
- { "HVC-TGROM", STD_TXROM },
- { "HVC-TKROM", STD_TXROM },
- { "HVC-TKEPROM", STD_TXROM },
- { "HVC-TL1ROM", STD_TXROM },
- { "HVC-TL2ROM", STD_TXROM },
- { "HVC-TLROM", STD_TXROM },
- { "HVC-TNROM", STD_TXROM },
- { "HVC-TR1ROM", STD_TVROM },
- { "HVC-TSROM", STD_TXROM },
- { "HVC-TVROM", STD_TVROM },
- { "NES-B4", STD_TXROM },
- { "NES-TBROM", STD_TXROM },
- { "NES-TEROM", STD_TXROM },
- { "NES-TFROM", STD_TXROM },
- { "NES-TGROM", STD_TXROM },
- { "NES-TKROM", STD_TXROM },
- { "NES-TKEPROM", STD_TXROM },
- { "NES-TL1ROM", STD_TXROM },
- { "NES-TL2ROM", STD_TXROM },
- { "NES-TLROM", STD_TXROM },
- { "NES-TNROM", STD_TXROM },
- { "NES-TR1ROM", STD_TVROM },
- { "NES-TSROM", STD_TXROM },
- { "NES-TVROM", STD_TVROM },
- /* TxROM boards by other manufacturer */
- { "ACCLAIM-MC-ACC", STD_TXROM },
- { "ACCLAIM-TLROM", STD_TXROM },
- { "KONAMI-TLROM", STD_TXROM },
-//
- /* Nintendo DxROM */
- { "HVC-DE1ROM", STD_DXROM },
- { "HVC-DEROM", STD_DXROM },
- { "HVC-DRROM", STD_DRROM },
- { "NES-DE1ROM", STD_DXROM },
- { "NES-DEROM", STD_DXROM },
- { "NES-DRROM", STD_DRROM },
- /* DxROM boards by other manufacturer */
- { "NAMCOT-3401", STD_DXROM },
- { "NAMCOT-3405", STD_DXROM },
- { "NAMCOT-3406", STD_DXROM },
- { "NAMCOT-3407", STD_DXROM },
- { "NAMCOT-3413", STD_DXROM },
- { "NAMCOT-3414", STD_DXROM },
- { "NAMCOT-3415", STD_DXROM },
- { "NAMCOT-3416", STD_DXROM },
- { "NAMCOT-3417", STD_DXROM },
- { "NAMCOT-3451", STD_DXROM },
- { "TENGEN-800002", STD_DXROM },
- { "TENGEN-800004", STD_DRROM },
- { "TENGEN-800030", STD_DXROM },
-//
- /* Nintendo HKROM */
- { "HVC-HKROM", STD_HKROM },
- { "NES-HKROM", STD_HKROM },
-//
- /* Nintendo BNROM */
- { "HVC-TQROM", STD_TQROM },
- { "NES-TQROM", STD_TQROM },
-//
- /* Nintendo TxSROM */
- { "HVC-TKSROM", STD_TXSROM },
- { "HVC-TLSROM", STD_TXSROM },
- { "NES-TKSROM", STD_TXSROM },
- { "NES-TLSROM", STD_TXSROM },
-//
- /* Nintendo ExROM */
- { "HVC-EKROM", STD_EXROM },
- { "HVC-ELROM", STD_EXROM },
- { "HVC-ETROM", STD_EXROM },
- { "HVC-EWROM", STD_EXROM },
- { "NES-EKROM", STD_EXROM },
- { "NES-ELROM", STD_EXROM },
- { "NES-ETROM", STD_EXROM },
- { "NES-EWROM", STD_EXROM },
-//
- /* Nintendo Custom boards */
- { "PAL-ZZ", PAL_ZZ },
- { "NES-QJ", NES_QJ },
- { "NES-EVENT", UNSUPPORTED_BOARD },
-//
- /* Discrete board IC_74x139x74 */
- { "JALECO-JF-05", DIS_74X139X74 },
- { "JALECO-JF-06", DIS_74X139X74 },
- { "JALECO-JF-07", DIS_74X139X74 },
- { "JALECO-JF-08", DIS_74X139X74 },
- { "JALECO-JF-09", DIS_74X139X74 },
- { "JALECO-JF-10", DIS_74X139X74 },
- { "KONAMI-74*139/74", DIS_74X139X74 },
- { "TAITO-74*139/74", DIS_74X139X74 },
- /* Discrete board IC_74x377 */
- { "AGCI-47516", DIS_74X377 },
- { "AVE-NINA-07", DIS_74X377 },
- { "COLORDREAMS-74*377", DIS_74X377 },
- /* Discrete board IC_74x161x161x32 */
- { "BANDAI-74*161/161/32", DIS_74X161X161X32 },
- { "TAITO-74*161/161/32", DIS_74X161X161X32 },
- /* Discrete board IC_74x161x138 */
- { "BIT-CORP-74*161/138", DIS_74X161X138 },
-//
- { "BANDAI-LZ93D50", BANDAI_LZ93 },
- { "BANDAI-LZ93D50+24C01", BANDAI_LZ93EX },
- { "BANDAI-LZ93D50+24C02", BANDAI_LZ93EX },
- { "BANDAI-FCG-1", BANDAI_FCG },
- { "BANDAI-FCG-2", BANDAI_FCG },
- { "BANDAI-JUMP2", BANDAI_JUMP2 },
- { "BANDAI-DATACH", BANDAI_DATACH },
- { "BANDAI-KARAOKE", BANDAI_KARAOKE },
- { "BANDAI-OEKAKIDS", BANDAI_OEKAKIDS },
- { "IREM-FCG-1", BANDAI_FCG },
-//
- { "IREM-G101", IREM_G101 },
- { "IREM-74*161/161/21/138", IREM_LROG017 },
- { "IREM-H-3001", IREM_H3001 },
- { "IREM-H3001", IREM_H3001 },
- { "IREM-HOLYDIVER", IREM_HOLYDIV },
- { "IREM-TAM-S1", IREM_TAM_S1 },
-//
- { "JALECO-JF-23", JALECO_SS88006 },
- { "JALECO-JF-24", JALECO_SS88006 },
- { "JALECO-JF-25", JALECO_SS88006 },
- { "JALECO-JF-27", JALECO_SS88006 },
- { "JALECO-JF-29", JALECO_SS88006 },
- { "JALECO-JF-30", JALECO_SS88006 },
- { "JALECO-JF-31", JALECO_SS88006 },
- { "JALECO-JF-32", JALECO_SS88006 },
- { "JALECO-JF-33", JALECO_SS88006 },
- { "JALECO-JF-34", JALECO_SS88006 },
- { "JALECO-JF-35", JALECO_SS88006 },
- { "JALECO-JF-36", JALECO_SS88006 },
- { "JALECO-JF-37", JALECO_SS88006 },
- { "JALECO-JF-38", JALECO_SS88006 },
- { "JALECO-JF-40", JALECO_SS88006 },
- { "JALECO-JF-41", JALECO_SS88006 },
- { "JALECO-JF-11", JALECO_JF11 },
- { "JALECO-JF-12", JALECO_JF11 },
- { "JALECO-JF-14", JALECO_JF11 },
- { "JALECO-JF-13", JALECO_JF13 },
- { "JALECO-JF-16", JALECO_JF16 },
- { "JALECO-JF-17", JALECO_JF17 },
- { "JALECO-JF-26", JALECO_JF17 },
- { "JALECO-JF-28", JALECO_JF17 },
- { "JALECO-JF-19", JALECO_JF19 },
- { "JALECO-JF-21", JALECO_JF19 },
-//
- { "KONAMI-VRC-1", KONAMI_VRC1 },
- { "JALECO-JF-20", KONAMI_VRC1 },
- { "JALECO-JF-22", KONAMI_VRC1 },
- { "KONAMI-VRC-2", KONAMI_VRC2 },
- { "KONAMI-VRC-3", KONAMI_VRC3 },
- { "KONAMI-VRC-4", KONAMI_VRC4 },
- { "KONAMI-VRC-6", KONAMI_VRC6 },
- { "KONAMI-VRC-7", KONAMI_VRC7 },
- { "UNL-VRC7", KONAMI_VRC7 },
-//
- { "NAMCOT-163", NAMCOT_163 },
- { "NAMCOT-175", NAMCOT_163 },
- { "NAMCOT-340", NAMCOT_163 },
- { "NAMCOT-3425", NAMCOT_3425 },
- { "NAMCOT-3433", NAMCOT_34X3 },
- { "NAMCOT-3443", NAMCOT_34X3 },
- { "NAMCOT-3446", NAMCOT_3446 },
- { "NAMCOT-3453", NAMCOT_3453 },
-//
- { "SUNSOFT-1", SUNSOFT_1 },
- { "SUNSOFT-2", SUNSOFT_2 },
- { "SUNSOFT-3", SUNSOFT_3 },
- //
- { "TAITO-TC0190FMC", TAITO_TC0190FMC },
- { "TAITO-TC0190FMC+PAL16R4", TAITO_TC0190FMCP },
- { "TAITO-TC0350FMR", TAITO_TC0190FMC },
- { "TAITO-X1-005", TAITO_X1_005 }, // two variants exist, depending on pin17 & pin31 connections
- { "TAITO-X1-017", TAITO_X1_017 },
-//
- { "AGCI-50282", AGCI_50282 },
- { "AVE-NINA-01", AVE_NINA01 },
- { "AVE-NINA-02", AVE_NINA01 },
- { "AVE-NINA-03", AVE_NINA06 },
- { "AVE-NINA-06", AVE_NINA06 },
- { "AVE-MB-91", AVE_NINA06 },
- { "TXC-74*138/175", AVE_NINA06 },
- { "UNL-SA-016-1M", AVE_NINA06 },
- { "CAMERICA-ALGN", CAMERICA_BF9093 },
- { "CAMERICA-BF9093", CAMERICA_BF9093 },
- { "CODEMASTERS-NR8N", CAMERICA_BF9093 },
- { "NR8NV1-1", CAMERICA_BF9093 },
- { "CAMERICA-BF9097", CAMERICA_BF9097 },
- { "CAMERICA-ALGQ", CAMERICA_BF9096 },
- { "CAMERICA-BF9096", CAMERICA_BF9096 },
- { "CAMERICA-GOLDENFIVE", CAMERICA_GOLDENFIVE },
- { "CNE-DECATHLON", CNE_DECATHLON },
- { "CNE-PSB", CNE_FSB },
- { "CNE-SHLZ", CNE_SHLZ },
- { "JYCOMPANY-A", UNSUPPORTED_BOARD }, // mapper 90
- { "JYCOMPANY-B", UNSUPPORTED_BOARD }, // mapper 209
- { "JYCOMPANY-C", UNSUPPORTED_BOARD }, // mapper 211
- { "NTDEC-112", NTDEC_ASDER }, // mapper 112 (better rename this board tag, to avoid confusion with TC-112!!
- { "NTDEC-TC-112", NTDEC_FIGHTINGHERO },
- { "NTDEC-193", NTDEC_FIGHTINGHERO }, // mapper 193
- { "UNL-TEK90", UNSUPPORTED_BOARD }, // related to JY Company? (i.e. mappers 90, 209, 211?)
- { "UNL-SA-002", SACHEN_TCU02 },
- { "UNL-SA-009", SACHEN_SA009 },
- { "UNL-SA-0036", SACHEN_SA0036 },
- { "UNL-SA-0037", SACHEN_SA0037 },
- { "UNL-SA-72007", SACHEN_SA72007 },
- { "UNL-SA-72008", SACHEN_SA72008 },
- { "UNL-SA-NROM", SACHEN_TCA01 },
- { "UNL-SACHEN-TCA01", SACHEN_TCA01 },
- { "SACHEN-8259A", SACHEN_8259A },
- { "UNL-SACHEN-8259A", SACHEN_8259A },
- { "SACHEN-8259B", SACHEN_8259B },
- { "UNL-SACHEN-8259B", SACHEN_8259B },
- { "SACHEN-8259C", SACHEN_8259C },
- { "UNL-SACHEN-8259C", SACHEN_8259C },
- { "SACHEN-8259D", SACHEN_8259D },
- { "UNL-SACHEN-8259D", SACHEN_8259D },
- { "UNL-SACHEN-74LS374N", SACHEN_74LS374 },
- { "UNL-SACHEN-74LS374N-A", SACHEN_74LS374_A }, /* FIXME: Made up boards the different mirroring handling */
- { "UNL-TC-U01-1.5M", SACHEN_TCU01 },
- { "UNL-SA-9602B", UNSUPPORTED_BOARD },
- { "TENGEN-800032", TENGEN_800032 },
- { "TENGEN-800037", TENGEN_800037 },
- { "WAIXING-A", WAIXING_TYPE_A },
- { "WAIXING-A-1", WAIXING_TYPE_A_1 }, /* FIXME: Made up boards the different CHRRAM banks (see Ji Jia Zhan Shi) */
- { "WAIXING-B", WAIXING_TYPE_B },
- { "WAIXING-C", WAIXING_TYPE_C },
- { "WAIXING-D", WAIXING_TYPE_D },
- { "WAIXING-E", WAIXING_TYPE_E },
- { "WAIXING-F", WAIXING_TYPE_F },
- { "WAIXING-G", WAIXING_TYPE_G },
- { "WAIXING-H", WAIXING_TYPE_H },
- { "WAIXING-I", WAIXING_TYPE_I },
- { "WAIXING-J", WAIXING_TYPE_J },
- { "WAIXING-SGZLZ", WAIXING_SGZLZ },
- { "WAIXING-SEC", WAIXING_SECURITY },
- { "WAIXING-SGZ", WAIXING_SGZ },
- { "WAIXING-PS2", WAIXING_PS2 },
- { "WAIXING-FFV", WAIXING_FFV },
- { "WAIXING-ZS", WAIXING_ZS },
- { "WAIXING-DQ8", WAIXING_DQ8 },
- { "WAIXING-SH2", WAIXING_SH2 },
-//
- { "TXC-TW", TXC_TW },
- { "TXC-STRIKEWOLF", TXC_STRIKEWOLF },
- { "TXC-MXMDHTWO", TXC_MXMDHTWO },
- { "UNL-22211", TXC_22211A },
- /* FIXME: Made up boards the different mirroring handling */
- { "UNL-22211-A", TXC_22211A },
- { "UNL-22211-B", TXC_22211B },
- { "UNL-22211-C", TXC_22211C },
- { "UNL-REXSOFT-DBZ5", REXSOFT_DBZ5 },
- { "UNL-SL1632", REXSOFT_SL1632 },
- { "SUBOR-BOARD-0", SUBOR_TYPE0 },
- { "SUBOR-BOARD-1", SUBOR_TYPE1 },
- { "SOMERITEAM-SL-12", SOMERI_SL12 }, // mapper 116
- { "UNL-CONY", CONY_BOARD },
- { "UNL-YOKO", YOKO_BOARD },
- { "UNL-GOUDER", GOUDER_37017 },
- { "UNL-NITRA", NITRA_TDA },
- { "UNL-HOSENKAN", HOSENKAN_BOARD },
- { "UNL-SUPERGAME", SUPERGAME_LIONKING },
- { "UNL-PANDAPRINCE", KAY_PANDAPRINCE },
- { "DREAMTECH01", DREAMTECH_BOARD },
- { "DAOU-306", OPENCORP_DAOU306 },
- { "HES", HES_BOARD },
- /* FIXME: Made up boards the different mirroring handling? */
- { "HES-6IN1", HES6IN1_BOARD },
- { "SUPERGAME-BOOGERMAN", SUPERGAME_BOOGERMAN },
- { "FUTUREMEDIA", FUTUREMEDIA_BOARD },
- { "FUKUTAKE", FUKUTAKE_BOARD },
- { "MAGICSERIES", MAGICSERIES_MD },
- { "KASING", KASING_BOARD },
- { "HENGGEDIANZI", HENGEDIANZI_BOARD },
- { "HENGGEDIANZI-XJZB", HENGEDIANZI_XJZB },
- { "KAISER-KS7058", KAISER_KS7058 },
- { "KAISER-KS202", KAISER_KS202 },// mapper 56
- { "KAISER-KS7022", KAISER_KS7022 },// mapper 175
- { "UNL-KS7012", UNSUPPORTED_BOARD /*KAISER_KS7012*/ }, // used in Zanac (FDS Conversion) (support missing atm)
- { "UNL-KS7013B", UNSUPPORTED_BOARD }, // used in Highway Star (FDS Conversion) (support missing atm)
- { "UNL-KS7017", KAISER_KS7017 },
- { "UNL-KS7032", KAISER_KS7032 }, // mapper 142
- { "RCM-GS2015", RCM_GS2015 },
- { "RCM-TETRISFAMILY", RCM_TETRISFAMILY },
- { "UNL-NINJARYU", UNSUPPORTED_BOARD },// mapper 111
- { "UNL-NANJING", NANJING_BOARD },// mapper 163
- { "WHIRLWIND-2706", WHIRLWIND_2706 },
- { "UNL-H2288", UNL_H2288 },
- { "UNL-DANCE", UNSUPPORTED_BOARD },
- { "UNL-EDU2000", UNL_EDU2K },
- { "UNL-SHERO", UNSUPPORTED_BOARD /*SACHEN_SHERO*/ },
- { "UNL-TF1201", UNSUPPORTED_BOARD /*UNL_TF1201*/ },
- { "RUMBLESTATION", RUMBLESTATION_BOARD }, // mapper 46
- { "UNL-WORLDHERO", UNSUPPORTED_BOARD },// mapper 27
- { "UNL-A9746", UNSUPPORTED_BOARD },// mapper 219
- { "UNL-603-5052", UNL_603_5052 },// mapper 238?
- { "UNL-SHJY3", UNL_SHJY3 },// mapper 253
- { "UNL-RACERMATE", UNL_RACERMATE },// mapper 168
- { "UNL-N625092", UNL_N625092 },
- { "BMC-N625092", UNL_N625092 },
- { "UNL-SC-127", UNL_SC127 },
- { "UNL-SMB2J", UNL_SMB2J },
- { "BTL-SMB2C", UNL_SMB2J },
- { "UNL-MK2", UNL_MK2 },
- { "UNL-XZY", UNL_XZY },
- { "UNL-KOF96", UNL_KOF96 },
- { "UNL-SUPERFIGHTER3", UNL_SUPERFIGHTER3 },
- { "UNL-8237", UNL_8237 },
- { "UNL-8237A", UNSUPPORTED_BOARD },
- { "UNL-AX5705", UNL_AX5705 },
- { "UNL-CC-21", UNL_CC21 },
- { "UNL-KOF97", UNL_KOF97 },
- { "UNL-KS7057", UNL_KS7057 }, // mapper 196 alt (for Street Fighter VI / Fight Street VI)
- { "UNL-T-230", UNL_T230 },
- { "UNL-STUDYNGAME", UNL_STUDYNGAME }, // mapper 39
- { "UNL-OneBus", UNSUPPORTED_BOARD },
- { "UNL-FS304", UNL_FS304 }, // used in Zelda 3 by Waixing
- { "UNL-43272", UNSUPPORTED_BOARD }, // used in Gaau Hok Gwong Cheung (support missing atm)
- { "UNL-LH10", UNSUPPORTED_BOARD }, // used in Fuuun Shaolin Kyo (FDS Conversion) (support missing atm)
-//
- { "BTL-SMB2A", BTL_SMB2A },
- { "BTL-MARIOBABY", BTL_MARIOBABY },
- { "BTL-AISENSHINICOL", BTL_AISENSHINICOL },
- { "BTL-SMB2B", BTL_SMB2B },
- { "BTL-SMB3", BTL_SMB3 },
- { "BTL-SUPERBROS11", BTL_SUPERBROS11 },
- { "BTL-DRAGONNINJA", BTL_DRAGONNINJA },
- { "BTL-MARIO1-MALEE2", UNSUPPORTED_BOARD }, // mapper 55?
- { "BTL-2708", UNSUPPORTED_BOARD },// mapper 103
- { "BTL-TOBIDASEDAISAKUSEN", BTL_TOBIDASE },// mapper 120
- { "BTL-SHUIGUANPIPE", UNSUPPORTED_BOARD },// mapper 183
- { "BTL-PIKACHUY2K", BTL_PIKACHUY2K },// mapper 254
-//
- { "BMC-190IN1", BMC_190IN1 },
- { "BMC-64IN1NOREPEAT", BMC_64IN1NR },
- { "BMC-A65AS", BMC_A65AS },
- { "BMC-GS-2004", BMC_GS2004 },
- { "BMC-GS-2013", BMC_GS2013 },
- { "BMC-NOVELDIAMOND9999999IN1", BMC_NOVELDIAMOND },
- { "BMC-9999999IN1", BMC_9999999IN1 }, // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 ??
- { "BMC-SUPER24IN1SC03", BMC_S24IN1SC03 },
- { "BMC-SUPERHIK8IN1", BMC_HIK8IN1 },
- { "BMC-T-262", BMC_T262 },
- { "BMC-WS", BMC_WS },
- { "MLT-ACTION52", ACTENT_ACT52 },
- { "MLT-CALTRON6IN1", CALTRON_6IN1 },
- { "MLT-MAXI15", UNSUPPORTED_BOARD}, // mapper 234
- { "BMC-SUPERBIG-7IN1", BMC_SUPERBIG_7IN1 },
- { "BMC-SUPERHIK-4IN1", BMC_SUPERHIK_4IN1 },
- { "BMC-BALLGAMES-11IN1", BMC_BALLGAMES_11IN1 },
- { "BMC-MARIOPARTY-7IN1", BMC_MARIOPARTY_7IN1 },
- { "BMC-GOLD-7IN1", BMC_GOLD_7IN1 },
- { "BMC-GKA", BMC_GKA },
- { "BMC-GKB", BMC_GKB },
- { "BMC-SUPER700IN1", BMC_SUPER_700IN1 },
- { "BMC-FAMILY-4646B", BMC_FAMILY_4646B },
- { "BMC-36IN1", BMC_36IN1 },
- { "BMC-21IN1", BMC_21IN1 },
- { "BMC-150IN1", BMC_150IN1 },
- { "BMC-35IN1", BMC_35IN1 },
- { "BMC-64IN1", BMC_64IN1 },
- { "BMC-15IN1", BMC_15IN1 },
- { "BMC-SUPERHIK-300IN1", BMC_SUPERHIK_300IN1 },
- { "BMC-SUPERGUN-20IN1", BMC_SUPERGUN_20IN1 },
- { "BMC-GOLDENCARD-6IN1", BMC_GOLDENCARD_6IN1 },
- { "BMC-72IN1", BMC_72IN1 },
- { "BMC-76IN1", BMC_76IN1 },
- { "BMC-SUPER42IN1", BMC_SUPER_42IN1 },
- { "BMC-1200IN1", BMC_1200IN1 },
- { "BMC-31IN1", BMC_31IN1 },
- { "BMC-22GAMES", BMC_22GAMES },
- { "BMC-20IN1", BMC_20IN1 },
- { "BMC-110IN1", BMC_110IN1 },
- { "BMC-810544-C-A1", BMC_810544 },
- { "BMC-411120-C", UNSUPPORTED_BOARD },
- { "BMC-830118C", UNSUPPORTED_BOARD },
- { "BMC-12-IN-1", UNSUPPORTED_BOARD },
- { "BMC-NTD-03", BMC_NTD_03 },
- { "BMC-8157", UNSUPPORTED_BOARD /*BMC_8157*/ },
- { "BMC-BS-5", BMC_BENSHENG_BS5 },
- { "BMC-FK23C", BMC_FK23C },
- { "BMC-FK23CA", BMC_FK23CA },
- { "BMC-GHOSTBUSTERS63IN1", BMC_G63IN1 },
- { "BMC-SUPERVISION16IN1", UNSUPPORTED_BOARD }, // mapper 53
- { "BMC-RESETBASED-4IN1", UNSUPPORTED_BOARD },// mapper 60 with 64k prg and 32k chr
- { "BMC-VT5201", BMC_VT5201 },// mapper 60 otherwise
- { "BMC-D1038", BMC_VT5201 }, // mapper 60?
- { "BMC-42IN1RESETSWITCH", UNSUPPORTED_BOARD }, // mapper 60?
- { "BMC-SUPER22GAMES", UNSUPPORTED_BOARD },// mapper 233
- { "BMC-GOLDENGAME-150IN1", UNSUPPORTED_BOARD },// mapper 235 with 2M PRG
- { "BMC-GOLDENGAME-260IN1", UNSUPPORTED_BOARD },// mapper 235 with 4M PRG
- { "BMC-70IN1", UNSUPPORTED_BOARD }, // mapper 236?
- { "BMC-70IN1B", UNSUPPORTED_BOARD }, // mapper 236?
- { "BMC-SUPERHIK-KOF", UNSUPPORTED_BOARD },// mapper 251
- { "BMC-POWERJOY", BMC_PJOY84 },
- { "BMC-POWERFUL-255", UNSUPPORTED_BOARD }, // mapper 63?
- { "UNL-AC08", UNSUPPORTED_BOARD }, // used by Green Beret FDS conversions
- { "UNL-BB", UNSUPPORTED_BOARD }, // used by a few FDS conversions
- { "UNL-LH32", UNSUPPORTED_BOARD }, // used by Monty no Doki Doki Daidassou FDS conversion
- { "UNL-CITYFIGHT", UNSUPPORTED_BOARD }, // used by City Fighter IV
- { "UNL-MALISB", UNSUPPORTED_BOARD }, // used by Super Mali Splash Bomb
- { "BMC-G-146", UNSUPPORTED_BOARD }, // multigame mapper
- { "BMC-11160", UNSUPPORTED_BOARD }, // multigame mapper
-// are there dumps of games with these boards?
- { "BMC-13IN1JY110", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
- { "BMC-GK-192", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
- { "KONAMI-QTAI", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
- { "UNL-3D-BLOCK", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
- { "UNL-C-N22M", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
- { "UNL-PEC-586", UNSUPPORTED_BOARD }, // [mentioned in FCEUMM source - we need more info]
-//
- { "UNKNOWN", UNKNOWN_BOARD } // a few pirate dumps uses the wrong mapper...
+ { "nrom", STD_NROM },
+ { "hvc_basic", HVC_FAMBASIC },
+ { "nrom_gg", GG_NROM },
+ { "uxrom", STD_UXROM },
+ { "unrom_cc", UXROM_CC },
+ { "cnrom", STD_CNROM },
+ { "bandai_pt554", BANDAI_PT554 },
+ { "cprom", STD_CPROM },
+ { "axrom", STD_AXROM },
+ { "pxrom", STD_PXROM },
+ { "fxrom", STD_FXROM },
+ { "bnrom", STD_BXROM },
+ { "gxrom", STD_GXROM },
+ { "un1rom", STD_UN1ROM },
+ { "sxrom", STD_SXROM },
+ { "sorom", STD_SOROM },
+ { "sxrom_a", STD_SXROM_A },
+ { "sorom_a", STD_SOROM_A },
+ { "txrom", STD_TXROM },
+ { "hkrom", STD_HKROM },
+ { "tqrom", STD_TQROM },
+ { "txsrom", STD_TXSROM },
+ { "exrom", STD_EXROM },
+ { "pal_zz", PAL_ZZ },
+ { "nes_qj", NES_QJ },
+ { "nes_event", STD_EVENT },
+ { "discrete_74x139", DIS_74X139X74 },
+ { "discrete_74x377", DIS_74X377 },
+ { "discrete_74x161", DIS_74X161X161X32 },
+ { "bitcorp_dis", DIS_74X161X138 },
+ { "lz93d50", BANDAI_LZ93 },
+ { "lz93d50_ep1", BANDAI_LZ93EX1 },
+ { "lz93d50_ep2", BANDAI_LZ93EX2 },
+ { "fcg", BANDAI_FCG },
+ { "fjump2", BANDAI_FJUMP2 },
+ { "datach", BANDAI_DATACH },
+ { "karastudio", BANDAI_KARAOKE },
+ { "oekakids", BANDAI_OEKAKIDS },
+ { "g101", IREM_G101 },
+ { "lrog017", IREM_LROG017 },
+ { "h3001", IREM_H3001 },
+ { "holydivr", IREM_HOLYDIVR },
+ { "tam_s1", IREM_TAM_S1 },
+ { "jf11", JALECO_JF11 },
+ { "jf13", JALECO_JF13 },
+ { "jf16", JALECO_JF16 },
+ { "jf17", JALECO_JF17 },
+ { "jf17pcm", JALECO_JF17_ADPCM },
+ { "jf19", JALECO_JF19 },
+ { "jf19pcm", JALECO_JF19_ADPCM },
+ { "ss88006", JALECO_SS88006 },
+ { "jf23", JALECO_JF23 },
+ { "jf24", JALECO_JF24 },
+ { "jf29", JALECO_JF29 },
+ { "jf33", JALECO_JF33 },
+ { "vrc1", KONAMI_VRC1 },
+ { "vrc2", KONAMI_VRC2 },
+ { "vrc3", KONAMI_VRC3 },
+ { "vrc4", KONAMI_VRC4 },
+ { "vrc6", KONAMI_VRC6 },
+ { "vrc7", KONAMI_VRC7 },
+ { "namcot_163", NAMCOT_163 },
+ { "namcot_175", NAMCOT_175 },
+ { "namcot_340", NAMCOT_340 },
+ { "namcot_3433", NAMCOT_34X3 }, // DxROM is a Nintendo board for US versions of the 3433/3443 games
+ { "namcot_3425", NAMCOT_3425 },
+ { "namcot_3446", NAMCOT_3446 },
+ { "sunsoft1", SUNSOFT_1 },
+ { "sunsoft2", SUNSOFT_2 },
+ { "sunsoft3", SUNSOFT_3 },
+ { "sunsoft4", SUNSOFT_4 },
+ { "sunsoft_dcs", SUNSOFT_DCS },
+ { "sunsoft_fme7", SUNSOFT_FME7 }, // JxROM is a Nintendo board for US versions of the Sunsoft FME7 games
+ { "sunsoft5a", SUNSOFT_FME7 },
+ { "sunsoft5b", SUNSOFT_5 },
+ { "tc0190fmc", TAITO_TC0190FMC },
+ { "tc0190fmcp", TAITO_TC0190FMCP },
+ { "tc0350fmr", TAITO_TC0190FMC },
+ { "x1_005", TAITO_X1_005 }, // two variants exist, depending on pin17 & pin31 connections
+ { "x1_017", TAITO_X1_017 },
+ { "nina001", AVE_NINA01 },
+ { "nina006", AVE_NINA06 },
+ { "maxi15", AVE_MAXI15 },
+ { "bf9093", CAMERICA_BF9093 },
+ { "bf9096", CAMERICA_BF9096 },
+ { "goldenfive", CAMERICA_GOLDENFIVE },
+ { "cne_decathl", CNE_DECATHLON },
+ { "cne_fsb", CNE_FSB },
+ { "cne_shlz", CNE_SHLZ },
+ { "nanjing", NANJING_BOARD }, // mapper 163
+ { "ntdec_asder", NTDEC_ASDER }, // mapper 112
+ { "ntdec_fh", NTDEC_FIGHTINGHERO }, // mapper 193
+ { "sa009", SACHEN_SA009 },
+ { "sa0036", SACHEN_SA0036 },
+ { "sa0037", SACHEN_SA0037 },
+ { "sa72007", SACHEN_SA72007 },
+ { "sa72008", SACHEN_SA72008 },
+ { "tca01", SACHEN_TCA01 },
+ { "s8259a", SACHEN_8259A },
+ { "s8259b", SACHEN_8259B },
+ { "s8259c", SACHEN_8259C },
+ { "s8259d", SACHEN_8259D },
+ { "s74x374", SACHEN_74LS374 },
+ { "s74x374a", SACHEN_74LS374_ALT }, /* FIXME: Made up boards some different handling */
+ { "tcu01", SACHEN_TCU01 },
+ { "tcu02", SACHEN_TCU02 },
+ { "sa9602b", SACHEN_SA9602B },
+ { "tengen_800008", TENGEN_800008 }, /* FIXME: Is this the same as mapper 3? */
+ { "tengen_800032", TENGEN_800032 },
+ { "tengen_800037", TENGEN_800037 },
+ { "txc_22211", TXC_22211 },
+ { "txc_dumarc", TXC_DUMARACING },
+ { "txc_mjblock", TXC_MJBLOCK },
+ { "txc_strikew", TXC_STRIKEW },
+ { "txc_commandos", TXC_COMMANDOS },
+ { "waixing_a", WAIXING_TYPE_A },
+ { "waixing_a1", WAIXING_TYPE_A1 }, /* FIXME: Made up boards the different CHRRAM banks (see Ji Jia Zhan Shi }, */
+ { "waixing_b", WAIXING_TYPE_B },
+ { "waixing_c", WAIXING_TYPE_C },
+ { "waixing_d", WAIXING_TYPE_D },
+ { "waixing_e", WAIXING_TYPE_E },
+ { "waixing_f", WAIXING_TYPE_F },
+ { "waixing_g", WAIXING_TYPE_G },
+ { "waixing_h", WAIXING_TYPE_H },
+ { "waixing_h1", WAIXING_TYPE_H1 },
+ { "waixing_i", WAIXING_TYPE_I },
+ { "waixing_j", WAIXING_TYPE_J },
+ { "waixing_sgz", WAIXING_SGZ },
+ { "waixing_sgzlz", WAIXING_SGZLZ },
+ { "waixing_sec", WAIXING_SECURITY },
+ { "waixing_ffv", WAIXING_FFV },
+ { "waixing_wxzs", WAIXING_WXZS },
+ { "waixing_wxzs2", WAIXING_WXZS2 },
+ { "waixing_dq8", WAIXING_DQ8 },
+ { "waixing_sh2", WAIXING_SH2 },
+ { "fs304", WAIXING_FS304 }, // used in Zelda 3 by Waixing
+ { "cony", CONY_BOARD },
+ { "yoko", YOKO_BOARD },
+ { "hengg_srich", HENGG_SRICH },
+ { "hengg_xhzs", HENGG_XHZS },
+ { "hengg_shjy3", HENGG_SHJY3 }, // mapper 253
+ { "hes", HES_BOARD },
+ { "hosenkan", HOSENKAN_BOARD },
+ { "ks7058", KAISER_KS7058 },
+ { "ks202", KAISER_KS202 }, // mapper 56
+ { "ks7022", KAISER_KS7022 }, // mapper 175
+ { "ks7017", KAISER_KS7017 },
+ { "ks7032", KAISER_KS7032 }, // mapper 142
+ { "ks7012", STD_NROM /*KAISER_KS7012*/ }, // used in Zanac (FDS Conversion }, - UNSUPPORTED
+ { "ks7013b", STD_NROM /*KAISER_KS7013B*/ }, // used in Highway Star (FDS Conversion }, - UNSUPPORTED
+ { "gs2015", RCM_GS2015 },
+ { "gs2004", RCM_GS2004 },
+ { "gs2013", RCM_GS2013 },
+ { "tf9in1", RCM_TF9IN1 },
+ { "3dblock", RCM_3DBLOCK }, // NROM + IRQ?
+ { "racermate", UNL_RACERMATE }, // mapper 168
+ { "agci_50282", AGCI_50282 },
+ { "dreamtech01", DREAMTECH_BOARD },
+ { "fukutake", FUKUTAKE_BOARD },
+ { "futuremedia", FUTUREMEDIA_BOARD },
+ { "magicseries", MAGICSERIES_MD },
+ { "daou_306", OPENCORP_DAOU306 },
+ { "subor0", SUBOR_TYPE0 },
+ { "subor1", SUBOR_TYPE1 },
+ { "cc21", UNL_CC21 },
+ { "xiaozy", UNL_XIAOZY },
+ { "edu2k", UNL_EDU2K },
+ { "t230", UNL_T230 },
+ { "mk2", UNL_MK2 },
+ // misc bootleg boards
+ { "ax5705", UNL_AX5705 },
+ { "sc127", UNL_SC127 },
+ { "mariobaby", BTL_MARIOBABY },
+ { "asnicol", BTL_AISENSHINICOL },
+ { "smb3pirate", BTL_SMB3 },
+ { "btl_dninja", BTL_DRAGONNINJA },
+ { "whirl2706", WHIRLWIND_2706 },
+ { "smb2j", UNL_SMB2J },
+ { "smb2ja", BTL_SMB2JA },
+ { "smb2jb", BTL_SMB2JB },
+ { "smb2jc", BTL_SMB2JC }, // really?
+ { "tobidase", BTL_TOBIDASE }, // mapper 120
+ { "dbz5", REXSOFT_DBZ5 },
+ { "sl1632", REXSOFT_SL1632 },
+ { "somari", SOMARI_SL12 }, // mapper 116
+ { "nitra", NITRA_TDA },
+ { "ks7057", UNL_KS7057 }, // mapper 196 alt (for Street Fighter VI / Fight Street VI },
+ { "sbros11", BTL_SBROS11 },
+ { "family4646", BMC_FAMILY_4646 },
+ { "pikay2k", BTL_PIKACHUY2K }, // mapper 254
+ { "8237", UNL_8237 },
+ { "sg_lionk", SUPERGAME_LIONKING },
+ { "sg_boog", SUPERGAME_BOOGERMAN },
+ { "kasing", KASING_BOARD },
+ { "kay", KAY_BOARD },
+ { "h2288", UNL_H2288 },
+ { "unl_6035052", UNL_603_5052 }, // mapper 238?
+ { "txc_tw", TXC_TW },
+ { "kof97", UNL_KOF97 },
+ { "kof96", UNL_KOF96 },
+ { "sfight3", UNL_SF3 },
+ { "gouder", GOUDER_37017 },
+ { "benshieng", BMC_BENSHIENG },
+ { "action52", ACTENT_ACT52 },
+ { "caltron6in1", CALTRON_6IN1 },
+ { "rumblestation", RUMBLESTATION_BOARD }, // mapper 46
+ { "svision16", SVISION16_BOARD },
+ { "n625092", UNL_N625092 },
+ { "a65as", BMC_A65AS },
+ { "t262", BMC_T262 },
+ { "novel1", BMC_NOVEL1 },
+ { "novel2", BMC_NOVEL2 }, // mapper 213... same as BMC-NOVELDIAMOND9999999IN1 board?
+ { "studyngame", UNL_STUDYNGAME }, // mapper 39
+ { "sgun20in1", BMC_SUPERGUN_20IN1 },
+ { "bmc_vt5201", BMC_VT5201 }, // mapper 60 otherwise
+ { "bmc_d1038", BMC_VT5201 }, // mapper 60?
+ { "810544c", BMC_810544 },
+ { "ntd03", BMC_NTD_03 },
+ { "bmc_gb63", BMC_G63IN1 },
+ { "bmc_gka", BMC_GKA },
+ { "bmc_gkb", BMC_GKB },
+ { "bmc_ws", BMC_WS },
+ { "bmc_hik300", BMC_SUPERHIK_300IN1 },
+ { "bmc_s700", BMC_SUPER_700IN1 },
+ { "bmc_ball11", BMC_BALLGAMES_11IN1 },
+ { "bmc_22games", BMC_22GAMES },
+ { "bmc_64y2k", BMC_64IN1NR },
+ { "bmc_12in1", BMC_12IN1 },
+ { "bmc_20in1", BMC_20IN1 },
+ { "bmc_21in1", BMC_21IN1 },
+ { "bmc_31in1", BMC_31IN1 },
+ { "bmc_35in1", BMC_35IN1 },
+ { "bmc_36in1", BMC_36IN1 },
+ { "bmc_64in1", BMC_64IN1 },
+ { "bmc_70in1", BMC_70IN1 },
+ { "bmc_72in1", BMC_72IN1 },
+ { "bmc_76in1", BMC_76IN1 },
+ { "bmc_s42in1", BMC_76IN1 },
+ { "bmc_110in1", BMC_110IN1 },
+ { "bmc_150in1", BMC_150IN1 },
+ { "bmc_190in1", BMC_190IN1 },
+ { "bmc_800in1", BMC_800IN1 },
+ { "bmc_1200in1", BMC_1200IN1 },
+ { "bmc_8157", BMC_8157 },
+ { "bmc_g146", BMC_G146 },
+ { "bmc_11160", BMC_11160 },
+ { "fk23c", BMC_FK23C },
+ { "fk23ca", BMC_FK23CA },
+ { "s24in1c03", BMC_S24IN1SC03 },
+ { "bmc_15in1", BMC_15IN1 },
+ { "bmc_sbig7in1", BMC_SUPERBIG_7IN1 },
+ { "bmc_hik8in1", BMC_HIK8IN1 },
+ { "bmc_hik4in1", BMC_SUPERHIK_4IN1 },
+ { "bmc_mario7in1", BMC_MARIOPARTY_7IN1 },
+ { "bmc_gold7in1", BMC_GOLD_7IN1 },
+ { "bmc_gc6in1", BMC_GOLDENCARD_6IN1 },
+ { "bmc_411120c", BMC_411120C },
+ { "bmc_830118c", BMC_830118C },
+ { "pjoy84", BMC_PJOY84 },
+ { "bmc_gold150", BMC_GOLD150 },
+ { "bmc_gold260", BMC_GOLD260 },
+ { "bmc_power255", BMC_CH001 },
+ { "bmc_s22games", BMC_SUPER22 },
+ { "bmc_reset4", BMC_4IN1RESET },
+ { "bmc_reset42", BMC_42IN1RESET },
+ { "jyc_a", JYCOMPANY_A },
+ { "jyc_b", JYCOMPANY_B },
+ { "jyc_c", JYCOMPANY_C },
+ { "tek90", JYCOMPANY_A },
+ { "sa9602b", SACHEN_SA9602B },
+ { "unl_shero", SACHEN_SHERO },
+ { "ks7012", KAISER_KS7012 },
+ { "ks7013b", KAISER_KS7013B },
+ { "mmalee2", UNL_MMALEE },
+ { "unl_2708", UNL_2708 },
+ { "a9746", UNL_A9746 },
+ { "unl_lh10", UNL_LH10 },
+ { "unl_lh32", UNL_LH32 },
+ { "unl_ac08", UNL_AC08 },
+ { "unl_bb", UNL_BB },
+ { "unl_malisb", UNL_MALISB },
+ { "sgpipe", BTL_SHUIGUAN },
+ { "unl_whero", UNL_WORLDHERO },
+ { "unl_43272", UNL_43272 },
+ { "tf1201", UNL_TF1201 },
+ { "unl_cfight", UNL_CITYFIGHT },
+ { "ffe3", FFE3_BOARD },
+ { "ffe4", FFE4_BOARD },
+ { "ffe8", FFE8_BOARD },
+ { "8237a", UNSUPPORTED_BOARD },
+ { "ninjaryu", UNSUPPORTED_BOARD },
+ { "unl_dance", UNSUPPORTED_BOARD },
+ { "bmc_hik_kof", UNSUPPORTED_BOARD },
+ { "onebus", UNSUPPORTED_BOARD },
+ { "unknown", UNKNOWN_BOARD } // a few pirate dumps uses the wrong mapper...
};
-const nes_pcb *nes_pcb_lookup( const char *board )
+static const nes_pcb *nes_pcb_lookup( const char *slot )
{
- int i;
- for (i = 0; i < ARRAY_LENGTH(pcb_list); i++)
+ for (int i = 0; i < ARRAY_LENGTH(pcb_list); i++)
{
- if (!mame_stricmp(pcb_list[i].pcb_name, board))
+ if (!mame_stricmp(pcb_list[i].slot_opt, slot))
return &pcb_list[i];
}
return NULL;
}
-int nes_get_pcb_id( running_machine &machine, const char *feature )
+static const nes_pcb *nes_id_lookup( int id )
{
- const nes_pcb *pcb = nes_pcb_lookup(feature);
-
- if (pcb == NULL)
- fatalerror("Unimplemented PCB type %s\n", feature);
-
- return pcb->pcb_id;
-}
-
-/************************************************
-
- PCB Emulation (to be moved to MAME later)
-
- In the end, iNES, UNIF and xml should be
- simply handled through a look-up table
- which associates the mapper/board/feature
- to the correct pcb_id and then the core
- function pcb_handlers_setup should be called
- to set-up the expected handlers and callbacks
-
- Similarly, PC-10, VSNES and NES-based
- multigame boards, should simply call
- pcb_handlers_setup with the proper pcb_id
- at the beginning, rather than use ad hoc
- implementations.
-
-************************************************/
-
-// helper function for the few mappers reading from 0x8000-0xffff for protection
-INLINE UINT8 mmc_hi_access_rom( running_machine &machine, UINT32 offset )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- // usual ROM access
- switch (offset & 0x6000)
- {
- case 0x0000:
- return state->m_prg[state->m_prg_bank[0] * 0x2000 + (offset & 0x1fff)];
- case 0x2000:
- return state->m_prg[state->m_prg_bank[1] * 0x2000 + (offset & 0x1fff)];
- case 0x4000:
- return state->m_prg[state->m_prg_bank[2] * 0x2000 + (offset & 0x1fff)];
- case 0x6000:
- return state->m_prg[state->m_prg_bank[3] * 0x2000 + (offset & 0x1fff)];
- }
- return 0;
-}
-
-/*************************************************************
-
- NROM board emulation
-
- Games: Mario Bros., Super Mario Bros., Tennis and most of
- the first generation games
-
- iNES: mapper 0
-
- In MESS: Supported, no need of specific handlers or IRQ
-
- *************************************************************/
-
-/*************************************************************
-
- UxROM board emulation
-
- Games: Castlevania, Dragon Quest II, Duck Tales, MegaMan,
- Metal Gear
-
- writes to 0x8000-0xffff change PRG 16K lower banks
-
- missing BC?
-
- iNES: mapper 2
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::uxrom_w)
-{
- LOG_MMC(("uxrom_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab(data);
-}
-
-/*************************************************************
-
- Nihon Bussan UNROM M5
-
- Games: Crazy Climber Jpn
-
- Very simple mapper: prg16_89ab is always set to bank 0,
- while prg16_cdef is set by writes to 0x8000-0xffff. The game
- uses a custom controller.
-
- iNES: mapper 180
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::uxrom_cc_w)
-{
- LOG_MMC(("uxrom_cc_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_cdef(data);
-}
-
-/*************************************************************
-
- UN1ROM board emulation
-
- Games: Senjou no Okami
-
- writes to 0x8000-0xffff change PRG 16K lower banks
-
- missing BC?
-
- iNES: mapper 94
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::un1rom_w)
-{
- LOG_MMC(("un1rom_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab(data >> 2);
-}
-
-/*************************************************************
-
- CNROM board emulation
-
- Games: B-Wings, Mighty Bomb Jack, Seicross, Spy vs. Spy,
- Adventure Island, Flipull, Friday 13th, GeGeGe no
- Kitarou, Ghostbusters, Gradius, Hokuto no Ken, Milon's
- Secret Castle
-
- writes to 0x8000-0xffff change CHR 8K banks
-
- missing BC?
-
- iNES: mappers 3 & 185 (the latter for games using Pins as
- protection)
-
- Notice that BANDAI_PT554 board (Aerobics Studio) uses very
- similar hardware but with an additional sound chip which
- gets writes to 0x6000 (currently unemulated in MESS)
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::cnrom_w)
-{
- LOG_MMC(("cnrom_w, offset: %04x, data: %02x\n", offset, data));
-
- if (m_ce_mask)
- {
- chr8(data & ~m_ce_mask, CHRROM);
-
- if ((data & m_ce_mask) == m_ce_state)
- m_chr_open_bus = 0;
- else
- m_chr_open_bus = 1;
- }
- else
- chr8(data, CHRROM);
-}
-
-/*************************************************************
-
- Bandai PT-554 board emulation
-
- This is used by Aerobics Studio. It is basically a CNROM board
- with an additional sound chip which is not currently emulated by
- MESS
-
- iNES: mapper 3?
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bandai_pt554_m_w)
-{
- LOG_MMC(("Bandai PT-554 Sound write, data: %02x\n", data));
-
- // according to NEStopia, this is the effect
- if (!BIT(data, 6))
- {
- // send command (data & 0x07) to sound chip
- }
-}
-
-/*************************************************************
-
- CPROM board emulation
-
- Games: Videomation
-
- writes to 0x8000-0xffff change CHR 4K lower banks
-
- iNES: mapper 13
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::cprom_w)
-{
- LOG_MMC(("cprom_w, offset: %04x, data: %02x\n", offset, data));
- chr4_4(data, CHRRAM);
-}
-
-/*************************************************************
-
- AxROM board emulation
-
- Games: Arch Rivals, Battletoads, Cabal, Commando, Solstice
-
- writes to 0x8000-0xffff change PRG banks + sets mirroring
-
- missing BC for AMROM?
-
- iNES: mapper 7
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::axrom_w)
-{
- LOG_MMC(("axrom_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- prg32(data);
-}
-
-/*************************************************************
-
- BxROM board emulation
-
- writes to 0x8000-0xffff change PRG banks
-
- missing BC?
-
- iNES: mapper 34
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bxrom_w)
-{
- /* This portion of the mapper is nearly identical to Mapper 7, except no one-screen mirroring */
- /* Deadly Towers is really a BxROM game - the demo screens look wrong using mapper 7. */
- LOG_MMC(("bxrom_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data);
-}
-
-/*************************************************************
-
- GxROM/MxROM board emulation
-
- writes to 0x8000-0xffff change PRG and CHR banks
-
- missing BC?
-
- iNES: mapper 66
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::gxrom_w)
-{
- LOG_MMC(("gxrom_w, offset %04x, data: %02x\n", offset, data));
-
- prg32((data & 0xf0) >> 4);
- chr8(data & 0x0f, CHRROM);
-}
-
-/*************************************************************
-
- SxROM (MMC1 based) board emulation
-
- iNES: mapper 1 (and 155 for the MMC1A variant which does not
- have WRAM disable bit)
-
- *************************************************************/
-
-static TIMER_CALLBACK( mmc1_resync_callback )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->m_mmc1_reg_write_enable = 1;
-}
-
-
-static void mmc1_set_wram( address_space &space, int board )
-{
- running_machine &machine = space.machine();
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 bank = BIT(state->m_mmc_reg[0], 4) ? BIT(state->m_mmc_reg[1], 4) : BIT(state->m_mmc_reg[1], 3);
-
- switch (board)
- {
- case STD_SXROM: // here also reads are disabled!
- if (!BIT(state->m_mmc_reg[3], 4))
- space.install_readwrite_bank(0x6000, 0x7fff, "bank5");
- else
- {
- space.unmap_readwrite(0x6000, 0x7fff);
- break;
- }
- case STD_SXROM_A: // ignore WRAM enable bit
- if (state->m_battery_size > 0x2000)
- state->wram_bank(((state->m_mmc_reg[1] & 3) >> 2), NES_BATTERY);
- else if (state->m_battery_size)
- state->wram_bank(0, NES_BATTERY);
- break;
- case STD_SOROM: // there are 2 WRAM banks only and battery is bank 2 for the cart (hence, we invert bank, because we have battery first)
- if (!BIT(state->m_mmc_reg[3], 4))
- space.install_readwrite_bank(0x6000, 0x7fff, "bank5");
- else
- {
- space.unmap_readwrite(0x6000, 0x7fff);
- break;
- }
- case STD_SOROM_A: // ignore WRAM enable bit
- state->wram_bank(0, bank ? NES_BATTERY : NES_WRAM);
- break;
- }
-}
-
-static void mmc1_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 prg_mode, prg_offset;
-
- prg_mode = state->m_mmc_reg[0] & 0x0c;
- /* prg_mode&0x8 determines bank size: 32k (if 0) or 16k (if 1)? when in 16k mode,
- prg_mode&0x4 determines which half of the PRG space we can swap: if it is 4,
- mmc_reg[3] sets banks at 0x8000; if it is 0, mmc_reg[3] sets banks at 0xc000. */
-
- prg_offset = state->m_mmc_reg[1] & 0x10;
- /* In principle, mmc_reg[2]&0x10 might affect "extended" banks as well, when chr_mode=1.
- However, quoting Disch's docs: When in 4k CHR mode, 0x10 in both $A000 and $C000 *must* be
- set to the same value, or else pages will constantly be swapped as graphics render!
- Hence, we use only mmc_reg[1]&0x10 for prg_offset */
-
- switch (prg_mode)
- {
- case 0x00:
- case 0x04:
-// printf("PRG 32 bank %d \n", (prg_offset + state->m_mmc_reg[3]) >> 1);
- state->prg32((prg_offset + state->m_mmc_reg[3]) >> 1);
- break;
- case 0x08:
-// printf("PRG 16 bank %d (high) \n", prg_offset + state->m_mmc_reg[3]);
- state->prg16_89ab(prg_offset + 0);
- state->prg16_cdef(prg_offset + state->m_mmc_reg[3]);
- break;
- case 0x0c:
-// printf("PRG 16 bank %d (low) \n", prg_offset + state->m_mmc_reg[3]);
- state->prg16_89ab(prg_offset + state->m_mmc_reg[3]);
- state->prg16_cdef(prg_offset + 0x0f);
- break;
- }
-}
-
-static void mmc1_set_prg_wram( address_space &space, int board )
-{
- mmc1_set_prg(space.machine());
- mmc1_set_wram(space, board);
-}
-
-static void mmc1_set_chr( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_mode = BIT(state->m_mmc_reg[0], 4);
-
- if (chr_mode)
- {
- state->chr4_0(state->m_mmc_reg[1] & 0x1f, state->m_mmc_chr_source);
- state->chr4_4(state->m_mmc_reg[2] & 0x1f, state->m_mmc_chr_source);
- }
- else
- state->chr8((state->m_mmc_reg[1] & 0x1f) >> 1, state->m_mmc_chr_source);
-}
-
-static void common_sxrom_write_handler( address_space &space, offs_t offset, UINT8 data, int board )
-{
- running_machine &machine = space.machine();
- nes_state *state = machine.driver_data<nes_state>();
- /* Note that there is only one latch and shift counter, shared amongst the 4 regs */
- /* Space Shuttle will not work if they have independent variables. */
-
- /* here we would need to add an if(cpu_cycles_passed>1) test, and
- if requirement is not met simply return without writing anything.
- Some games (AD&D Hillsfar, Bill & Ted Excellent Adventure, Cosmic
- Wars, Rocket Ranger, Sesame Street 123 and Snow Brothers) rely on
- this behavior!! */
- if (state->m_mmc1_reg_write_enable == 0)
- {
- return;
- }
- else
- {
- state->m_mmc1_reg_write_enable = 0;
- machine.scheduler().synchronize(FUNC(mmc1_resync_callback));
- }
-
- if (data & 0x80)
- {
- state->m_mmc1_count = 0;
- state->m_mmc1_latch = 0;
-
- /* Set reg at 0x8000 to size 16k and lower half swap - needed for Robocop 3, Dynowars */
- state->m_mmc_reg[0] |= 0x0c;
- mmc1_set_prg_wram(space, board);
- return;
- }
-
- if (state->m_mmc1_count < 5)
- {
- if (state->m_mmc1_count == 0) state->m_mmc1_latch = 0;
- state->m_mmc1_latch >>= 1;
- state->m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00;
- state->m_mmc1_count++;
- }
-
- if (state->m_mmc1_count == 5)
- {
- switch (offset & 0x6000) /* Which reg shall we write to? */
- {
- case 0x0000:
- state->m_mmc_reg[0] = state->m_mmc1_latch;
-
- switch (state->m_mmc_reg[0] & 0x03)
- {
- case 0: state->set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 1: state->set_nt_mirroring(PPU_MIRROR_HIGH); break;
- case 2: state->set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 3: state->set_nt_mirroring(PPU_MIRROR_HORZ); break;
- }
- mmc1_set_chr(machine);
- mmc1_set_prg_wram(space, board);
- break;
- case 0x2000:
- state->m_mmc_reg[1] = state->m_mmc1_latch;
- mmc1_set_chr(machine);
- mmc1_set_prg_wram(space, board);
- break;
- case 0x4000:
- state->m_mmc_reg[2] = state->m_mmc1_latch;
- mmc1_set_chr(machine);
- break;
- case 0x6000:
- state->m_mmc_reg[3] = state->m_mmc1_latch;
- mmc1_set_prg_wram(space, board);
- break;
- }
- state->m_mmc1_count = 0;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::sxrom_w)
-{
- LOG_MMC(("sxrom_w, offset: %04x, data: %02x\n", offset, data));
- common_sxrom_write_handler(space, offset, data, m_pcb_id);
-}
-
-/*************************************************************
-
- PxROM (MMC2 based) board emulation
-
- Games: Punch Out!!, Mike Tyson's Punch Out!!
-
- iNES: mapper 9
-
- In MESS: Supported
-
- *************************************************************/
-
-void nes_state::mmc2_latch(offs_t offset )
-{
- if ((offset & 0x3ff0) == 0x0fd0)
- {
- LOG_MMC(("mmc2 vrom latch switch (bank 0 low): %02x\n", m_mmc_reg[0]));
- m_mmc_latch1 = 0xfd;
- chr4_0(m_mmc_reg[0], CHRROM);
- }
- else if ((offset & 0x3ff0) == 0x0fe0)
- {
- LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_mmc_reg[1]));
- m_mmc_latch1 = 0xfe;
- chr4_0(m_mmc_reg[1], CHRROM);
- }
- else if ((offset & 0x3ff0) == 0x1fd0)
- {
- LOG_MMC(("mmc2 vrom latch switch (bank 1 low): %02x\n", m_mmc_reg[2]));
- m_mmc_latch2 = 0xfd;
- chr4_4(m_mmc_reg[2], CHRROM);
- }
- else if ((offset & 0x3ff0) == 0x1fe0)
- {
- LOG_MMC(("mmc2 vrom latch switch (bank 0 high): %02x\n", m_mmc_reg[3]));
- m_mmc_latch2 = 0xfe;
- chr4_4(m_mmc_reg[3], CHRROM);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::pxrom_w)
-{
- LOG_MMC(("pxrom_w, offset: %04x, data: %02x\n", offset, data));
- switch (offset & 0x7000)
- {
- case 0x2000:
- prg8_89(data);
- break;
- case 0x3000:
- m_mmc_reg[0] = data;
- if (m_mmc_latch1 == 0xfd)
- chr4_0(m_mmc_reg[0], CHRROM);
- break;
- case 0x4000:
- m_mmc_reg[1] = data;
- if (m_mmc_latch1 == 0xfe)
- chr4_0(m_mmc_reg[1], CHRROM);
- break;
- case 0x5000:
- m_mmc_reg[2] = data;
- if (m_mmc_latch2 == 0xfd)
- chr4_4(m_mmc_reg[2], CHRROM);
- break;
- case 0x6000:
- m_mmc_reg[3] = data;
- if (m_mmc_latch2 == 0xfe)
- chr4_4(m_mmc_reg[3], CHRROM);
- break;
- case 0x7000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- default:
- LOG_MMC(("MMC2 uncaught w: %04x:%02x\n", offset, data));
- break;
- }
-}
-
-/*************************************************************
-
- FxROM (MMC4 based) board emulation
-
- Games: Famicom Wars, Fire Emblem, Fire Emblem Gaiden
-
- iNES: mapper 10
-
- In MESS: Supported
-
-*************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::fxrom_w)
-{
- LOG_MMC(("fxrom_w, offset: %04x, data: %02x\n", offset, data));
- switch (offset & 0x7000)
- {
- case 0x2000:
- prg16_89ab(data);
- break;
- default:
- pxrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- TxROM (MMC3 based) board emulation
-
- iNES: mapper 4
-
- *************************************************************/
-
-static void mmc3_set_wram( address_space &space )
-{
- running_machine &machine = space.machine();
- nes_state *state = machine.driver_data<nes_state>();
-
- // skip this function if we are emulating a MMC3 clone with mid writes
- if (!state->m_mmc_write_mid.isnull())
- return;
-
- if (BIT(state->m_mmc3_wram_protect, 7))
- space.install_readwrite_bank(0x6000, 0x7fff, "bank5");
- else
- {
- space.unmap_readwrite(0x6000, 0x7fff);
- return;
- }
-
- if (!BIT(state->m_mmc3_wram_protect, 6))
- space.install_write_bank(0x6000, 0x7fff, "bank5");
- else
- {
- space.unmap_write(0x6000, 0x7fff);
- return;
- }
-}
-
-// base MMC3 simply calls prg8_x
-static void mmc3_base_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->prg8_x(start, bank);
-}
-
-// base MMC3 simply calls chr1_x
-static void mmc3_base_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->chr1_x(start, bank, source);
-}
-
-
-static void mmc3_set_prg( running_machine &machine, int prg_base, int prg_mask )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 prg_flip = (state->m_mmc3_latch & 0x40) ? 2 : 0;
-
- state->m_mmc3_prg_cb(machine, 0, prg_base | (state->m_mmc_prg_bank[0 ^ prg_flip] & prg_mask));
- state->m_mmc3_prg_cb(machine, 1, prg_base | (state->m_mmc_prg_bank[1] & prg_mask));
- state->m_mmc3_prg_cb(machine, 2, prg_base | (state->m_mmc_prg_bank[2 ^ prg_flip] & prg_mask));
- state->m_mmc3_prg_cb(machine, 3, prg_base | (state->m_mmc_prg_bank[3] & prg_mask));
-}
-
-static void mmc3_set_chr( running_machine &machine, UINT8 chr, int chr_base, int chr_mask )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5;
-
- state->m_mmc3_chr_cb(machine, chr_page ^ 0, chr_base | ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr);
- state->m_mmc3_chr_cb(machine, chr_page ^ 1, chr_base | ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr);
- state->m_mmc3_chr_cb(machine, chr_page ^ 2, chr_base | ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr);
- state->m_mmc3_chr_cb(machine, chr_page ^ 3, chr_base | ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr);
- state->m_mmc3_chr_cb(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr);
- state->m_mmc3_chr_cb(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), chr);
- state->m_mmc3_chr_cb(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), chr);
- state->m_mmc3_chr_cb(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), chr);
-}
-
-/* Here, IRQ counter decrements every scanline. */
-void nes_state::mmc3_irq(int scanline, int vblank, int blanked )
-{
- if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
- {
- int priorCount = m_IRQ_count;
- if ((m_IRQ_count == 0) || m_IRQ_clear)
- m_IRQ_count = m_IRQ_count_latch;
- else
- m_IRQ_count--;
-
- if (m_IRQ_enable && !blanked && (m_IRQ_count == 0) && (priorCount || m_IRQ_clear /*|| !m_mmc3_alt_irq*/)) // according to blargg the latter should be present as well, but it breaks Rampart and Joe & Mac US: they probably use the alt irq!
- {
- LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
- machine().primary_screen->vpos(), machine().primary_screen->hpos()));
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- }
- m_IRQ_clear = 0;
-}
-
-WRITE8_MEMBER(nes_carts_state::txrom_w)
-{
- UINT8 mmc_helper, cmd;
-
- LOG_MMC(("txrom_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- mmc_helper = m_mmc3_latch ^ data;
- m_mmc3_latch = data;
-
- /* Has PRG Mode changed? */
- if (mmc_helper & 0x40)
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- /* Has CHR Mode changed? */
- if (mmc_helper & 0x80)
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
-
- case 0x0001:
- cmd = m_mmc3_latch & 0x07;
- switch (cmd)
- {
- case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
- case 2: case 3: case 4: case 5:
- m_mmc_vrom_bank[cmd] = data;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
- case 6:
- case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- }
- break;
-
- case 0x2000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- case 0x2001:
- m_mmc3_wram_protect = data;
- mmc3_set_wram(space);
- break;
-
- case 0x4000:
- m_IRQ_count_latch = data;
- break;
-
- case 0x4001:
- m_IRQ_count = 0;
- break;
-
- case 0x6000:
- m_IRQ_enable = 0;
- break;
-
- case 0x6001:
- m_IRQ_enable = 1;
- break;
-
- default:
- logerror("txrom_w uncaught: %04x value: %02x\n", offset + 0x8000, data);
- break;
- }
-}
-
-/*************************************************************
-
- HKROM (MMC6 based) board emulation
-
- iNES: mapper 4
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::hkrom_m_w)
-{
- UINT8 write_hi, write_lo;
- LOG_MMC(("hkrom_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x1000)
- return;
-
- // banks can be written only if both read & write is enabled!
- write_hi = ((m_mmc6_reg & 0xc0) == 0xc0);
- write_lo = ((m_mmc6_reg & 0x30) == 0x30);
-
- if (BIT(offset, 9) && write_hi) // access to upper 1k
- m_mapper_bram[offset & (m_mapper_bram_size - 1)] = data;
-
- if (!BIT(offset, 9) && write_lo) // access to lower 1k
- m_mapper_bram[offset & (m_mapper_bram_size - 1)] = data;
-}
-
-READ8_MEMBER(nes_carts_state::hkrom_m_r)
-{
- LOG_MMC(("hkrom_m_r, offset: %04x\n", offset));
-
- if (offset < 0x1000)
- return 0xff; // here it should be open bus
-
- if (!(m_mmc6_reg & 0xa0))
- return 0xff; // here it should be open bus
-
- if (BIT(offset, 9) && BIT(m_mmc6_reg, 7)) // access to upper 1k when upper read is enabled
- return m_mapper_bram[offset & (m_mapper_bram_size - 1)];
-
- if (!BIT(offset, 9) && BIT(m_mmc6_reg, 5)) // access to lower 1k when lower read is enabled
- return m_mapper_bram[offset & (m_mapper_bram_size - 1)];
-
- // If only one bank is enabled for reading, the other reads back as zero
- return 0x00;
-}
-
-WRITE8_MEMBER(nes_carts_state::hkrom_w)
-{
- UINT8 mmc6_helper;
- LOG_MMC(("hkrom_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- mmc6_helper = m_mmc3_latch ^ data;
- m_mmc3_latch = data;
-
- if (!m_mmc_latch2 && BIT(data, 5)) // if WRAM is disabled and has to be enabled, write
- m_mmc_latch2 = BIT(data, 5); // (once WRAM has been enabled, it cannot be disabled without resetting the game)
-
- /* Has PRG Mode changed? */
- if (BIT(mmc6_helper, 6))
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- /* Has CHR Mode changed? */
- if (BIT(mmc6_helper, 7))
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
-
- case 0x2001:
- if (m_mmc_latch2)
- m_mmc6_reg = data;
- break;
-
- case 0x4001:
- m_IRQ_count = 0;
- m_IRQ_clear = 1;
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- TxSROM (MMC3 based) board emulation
-
- Games: Armadillo, Play Action Football, Pro Hockey, RPG
- Jinsei Game, Y's 3
-
- iNES: mapper 118
-
- In MESS: Supported. It also uses mmc3_irq.
-
- *************************************************************/
-
-static void txsrom_set_mirror( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (state->m_mmc3_latch & 0x80)
- {
- state->set_nt_page(0, CIRAM, (state->m_mmc_vrom_bank[2] & 0x80) >> 7, 1);
- state->set_nt_page(1, CIRAM, (state->m_mmc_vrom_bank[3] & 0x80) >> 7, 1);
- state->set_nt_page(2, CIRAM, (state->m_mmc_vrom_bank[4] & 0x80) >> 7, 1);
- state->set_nt_page(3, CIRAM, (state->m_mmc_vrom_bank[5] & 0x80) >> 7, 1);
- }
- else
- {
- state->set_nt_page(0, CIRAM, (state->m_mmc_vrom_bank[0] & 0x80) >> 7, 1);
- state->set_nt_page(1, CIRAM, (state->m_mmc_vrom_bank[0] & 0x80) >> 7, 1);
- state->set_nt_page(2, CIRAM, (state->m_mmc_vrom_bank[1] & 0x80) >> 7, 1);
- state->set_nt_page(3, CIRAM, (state->m_mmc_vrom_bank[1] & 0x80) >> 7, 1);
- }
-}
-
-static void txsrom_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- txsrom_set_mirror(machine); // we could probably update only for one (e.g. the first) call, to slightly optimize the code
- state->chr1_x(start, bank, source);
-}
-
-WRITE8_MEMBER(nes_carts_state::txsrom_w)
-{
- LOG_MMC(("txsrom_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x2000:
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- TQROM (MMC3 based) board emulation
-
- Games: Pin Bot, High Speed
-
- iNES: mapper 119
-
- In MESS: Supported. It also uses mmc3_irq.
-
- *************************************************************/
-
-static void tqrom_set_chr( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5;
- UINT8 chr_src[6], chr_mask[6];
- int i;
-
- for (i = 0; i < 6; i++)
- {
- chr_src[i] = (state->m_mmc_vrom_bank[i] & 0x40) ? CHRRAM : CHRROM;
- chr_mask[i] = (state->m_mmc_vrom_bank[i] & 0x40) ? 0x07 : 0x3f;
- }
-
- state->chr1_x(chr_page ^ 0, ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask[0]), chr_src[0]);
- state->chr1_x(chr_page ^ 1, ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask[0]), chr_src[0]);
- state->chr1_x(chr_page ^ 2, ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask[1]), chr_src[1]);
- state->chr1_x(chr_page ^ 3, ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask[1]), chr_src[1]);
- state->chr1_x(chr_page ^ 4, (state->m_mmc_vrom_bank[2] & chr_mask[2]), chr_src[2]);
- state->chr1_x(chr_page ^ 5, (state->m_mmc_vrom_bank[3] & chr_mask[3]), chr_src[3]);
- state->chr1_x(chr_page ^ 6, (state->m_mmc_vrom_bank[4] & chr_mask[4]), chr_src[4]);
- state->chr1_x(chr_page ^ 7, (state->m_mmc_vrom_bank[5] & chr_mask[5]), chr_src[5]);
-}
-
-WRITE8_MEMBER(nes_carts_state::tqrom_w)
-{
- UINT8 mmc_helper, cmd;
- LOG_MMC(("tqrom_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- mmc_helper = m_mmc3_latch ^ data;
- m_mmc3_latch = data;
-
- /* Has PRG Mode changed? */
- if (mmc_helper & 0x40)
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- /* Has CHR Mode changed? */
- if (mmc_helper & 0x80)
- tqrom_set_chr(machine());
- break;
- case 0x0001: /* $8001 */
- cmd = m_mmc3_latch & 0x07;
- switch (cmd)
- {
- case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
- case 2: case 3: case 4: case 5:
- m_mmc_vrom_bank[cmd] = data;
- tqrom_set_chr(machine());
- break;
- case 6:
- case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- }
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- PAL-ZZ board (MMC3 variant for European 3-in-1 Nintendo cart
- Super Mario Bros. + Tetris + Nintendo World Cup)
-
- iNES: mapper 37
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::zz_m_w)
-{
- UINT8 mmc_helper = data & 0x07;
- LOG_MMC(("zz_m_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_prg_base = (BIT(mmc_helper, 2) << 4) | (((mmc_helper & 0x03) == 0x03) ? 0x08 : 0);
- m_mmc_prg_mask = (mmc_helper << 1) | 0x07;
- m_mmc_chr_base = BIT(mmc_helper, 2) << 7;
- m_mmc_chr_mask = 0x7f;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
-}
-
-/*************************************************************
-
- NES-QJ board (MMC3 variant for US 2-in-1 Nintendo cart
- Super Spike V'Ball + Nintendo World Cup)
-
- iNES: mapper 47
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::qj_m_w)
-{
- LOG_MMC(("qj_m_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_prg_base = BIT(data, 0) << 4;
- m_mmc_prg_mask = 0x0f;
- m_mmc_chr_base = BIT(data, 0) << 7;
- m_mmc_chr_mask = 0x7f;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
-}
-
-/*************************************************************
-
- ExROM (MMC5 based) board emulation
-
- Games: Castlevania III, Just Breed, many Koei titles
-
- iNES: mapper 5
-
- MESS status: Mostly Unsupported
-
- *************************************************************/
-
-#if 0
-static void mmc5_update_chr_a( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- switch (state->m_mmc5_chr_mode)
- {
- case 0: // 8k banks
- state->chr8(state->m_mmc5_vrom_regA[7] & 0xff, CHRROM);
- break;
-
- case 1: // 4k banks
- state->chr4_0(state->m_mmc5_vrom_regA[3] & 0xff, CHRROM);
- state->chr4_4(state->m_mmc5_vrom_regA[7] & 0xff, CHRROM);
- break;
-
- case 2: // 2k banks
- state->chr2_0(state->m_mmc5_vrom_regA[1], CHRROM);
- state->chr2_2(state->m_mmc5_vrom_regA[3], CHRROM);
- state->chr2_4(state->m_mmc5_vrom_regA[5], CHRROM);
- state->chr2_6(state->m_mmc5_vrom_regA[7], CHRROM);
- break;
-
- case 3: // 1k banks
- state->chr1_0(state->m_mmc5_vrom_regA[0], CHRROM);
- state->chr1_1(state->m_mmc5_vrom_regA[1], CHRROM);
- state->chr1_2(state->m_mmc5_vrom_regA[2], CHRROM);
- state->chr1_3(state->m_mmc5_vrom_regA[3], CHRROM);
- state->chr1_4(state->m_mmc5_vrom_regA[4], CHRROM);
- state->chr1_5(state->m_mmc5_vrom_regA[5], CHRROM);
- state->chr1_6(state->m_mmc5_vrom_regA[6], CHRROM);
- state->chr1_7(state->m_mmc5_vrom_regA[7], CHRROM);
- break;
- }
-}
-
-static void mmc5_update_chr_b( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- switch (state->m_mmc5_chr_mode)
- {
- case 0: // 8k banks
- state->chr8(state->m_mmc5_vrom_regB[3] & 0xff, CHRROM);
- break;
-
- case 1: // 4k banks
- state->chr4_0(state->m_mmc5_vrom_regB[3] & 0xff, CHRROM);
- state->chr4_4(state->m_mmc5_vrom_regB[3] & 0xff, CHRROM);
- break;
-
- case 2: // 2k banks
- state->chr2_0(state->m_mmc5_vrom_regB[1], CHRROM);
- state->chr2_2(state->m_mmc5_vrom_regB[3], CHRROM);
- state->chr2_4(state->m_mmc5_vrom_regB[1], CHRROM);
- state->chr2_6(state->m_mmc5_vrom_regB[3], CHRROM);
- break;
-
- case 3: // 1k banks
- state->chr1_0(state->m_mmc5_vrom_regB[0], CHRROM);
- state->chr1_1(state->m_mmc5_vrom_regB[1], CHRROM);
- state->chr1_2(state->m_mmc5_vrom_regB[2], CHRROM);
- state->chr1_3(state->m_mmc5_vrom_regB[3], CHRROM);
- state->chr1_4(state->m_mmc5_vrom_regB[0], CHRROM);
- state->chr1_5(state->m_mmc5_vrom_regB[1], CHRROM);
- state->chr1_6(state->m_mmc5_vrom_regB[2], CHRROM);
- state->chr1_7(state->m_mmc5_vrom_regB[3], CHRROM);
- break;
- }
-}
-#endif
-
-static void mmc5_update_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int bank1, bank2, bank3;
-
- switch (state->m_mmc5_prg_mode)
- {
- case 0: // 32k banks
- state->prg32(state->m_mmc5_prg_regs[3] >> 2);
- break;
-
- case 1: // 16k banks
- // printf("problema 1: %x\n", state->m_mmc5_prg_regs[1]);
- bank1 = state->m_mmc5_prg_regs[1];
-
- if (!BIT(bank1, 7))
- {
- state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x06);
- state->m_prg_bank[1] = state->m_prg_chunks + (bank1 & 0x06) + 1;
- state->membank("bank1")->set_entry(state->m_prg_bank[0]);
- state->membank("bank2")->set_entry(state->m_prg_bank[1]);
- }
- else
- state->prg16_89ab(bank1 >> 1);
-
- state->prg16_cdef(state->m_mmc5_prg_regs[3] >> 1);
- break;
-
- case 2: // 16k-8k banks
- // printf("problema 2: %x %x\n", state->m_mmc5_prg_regs[1], state->m_mmc5_prg_regs[2]);
- bank1 = state->m_mmc5_prg_regs[1];
- bank3 = state->m_mmc5_prg_regs[2];
-
- if (!BIT(bank1, 7))
- {
- state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x06);
- state->m_prg_bank[1] = state->m_prg_chunks + (bank1 & 0x06) + 1;
- state->membank("bank1")->set_entry(state->m_prg_bank[0]);
- state->membank("bank2")->set_entry(state->m_prg_bank[1]);
- }
- else
- state->prg16_89ab((bank1 & 0x7f) >> 1);
-
- if (!BIT(bank3, 7))
- {
- state->m_prg_bank[2] = state->m_prg_chunks + (bank3 & 0x07);
- state->membank("bank3")->set_entry(state->m_prg_bank[2]);
- }
- else
- state->prg8_cd(bank3 & 0x7f);
-
- state->prg8_ef(state->m_mmc5_prg_regs[3]);
- break;
-
- case 3: // 8k banks
- // printf("problema 3: %x %x %x\n", state->m_mmc5_prg_regs[0], state->m_mmc5_prg_regs[1], state->m_mmc5_prg_regs[2]);
- bank1 = state->m_mmc5_prg_regs[0];
- bank2 = state->m_mmc5_prg_regs[1];
- bank3 = state->m_mmc5_prg_regs[2];
-
- if (!BIT(bank1, 7))
- {
- state->m_prg_bank[0] = state->m_prg_chunks + (bank1 & 0x07);
- state->membank("bank1")->set_entry(state->m_prg_bank[0]);
- }
- else
- state->prg8_89(bank1 & 0x7f);
-
- if (!BIT(bank2, 7))
- {
- state->m_prg_bank[1] = state->m_prg_chunks + (bank2 & 0x07);
- state->membank("bank2")->set_entry(state->m_prg_bank[1]);
- }
- else
- state->prg8_ab(bank2 & 0x7f);
-
- if (!BIT(bank3, 7))
- {
- state->m_prg_bank[2] = state->m_prg_chunks + (bank3 & 0x07);
- state->membank("bank3")->set_entry(state->m_prg_bank[2]);
- }
- else
- state->prg8_cd(bank3 & 0x7f);
-
- state->prg8_ef(state->m_mmc5_prg_regs[3]);
- break;
- }
-}
-
-static void mmc5_update_render_mode( running_machine &machine )
-{
-}
-
-void nes_state::mmc5_irq(int scanline, int vblank, int blanked )
-{
-#if 1
- if (scanline == 0)
- m_IRQ_status |= 0x40;
- else if (scanline > PPU_BOTTOM_VISIBLE_SCANLINE)
- m_IRQ_status &= ~0x40;
-#endif
-
- if (scanline == m_IRQ_count)
- {
- if (m_IRQ_enable)
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
-
- m_IRQ_status = 0xff;
- }
-
- /* FIXME: this is ok, but then we would need to update them again when we have the BG Hblank
- I leave it commented out until the PPU is updated for this */
- // if (ppu2c0x_is_sprite_8x16(m_ppu) || m_mmc5_last_chr_a)
- // mmc5_update_chr_a(device->machine());
- // else
- // mmc5_update_chr_b(device->machine());
-}
-
-static void mmc5_ppu_mirror( running_machine &machine, int page, int src )
-{
- nes_state *state = machine.driver_data<nes_state>();
- switch (src)
- {
- case 0: /* CIRAM0 */
- state->set_nt_page(page, CIRAM, 0, 1);
- break;
- case 1: /* CIRAM1 */
- state->set_nt_page(page, CIRAM, 1, 1);
- break;
- case 2: /* ExRAM */
- state->set_nt_page(page, EXRAM, 0, 1); // actually only works during rendering.
- break;
- case 3: /* Fill Registers */
- state->set_nt_page(page, MMC5FILL, 0, 0);
- break;
- default:
- fatalerror("This should never happen\n");
- break;
- }
-}
-
-READ8_MEMBER(nes_carts_state::exrom_l_r)
-{
- int retVal;
-
- /* $5c00 - $5fff: extended videoram attributes */
- if ((offset >= 0x1b00) && (offset <= 0x1eff))
- {
- return m_mapper_ram[offset - 0x1b00];
- }
-
- switch (offset)
- {
- case 0x1104: /* $5204 */
-#if 0
- if (current_scanline == MMC5_scanline)
- return 0x80;
- else
- return 0x00;
-#else
- retVal = m_IRQ_status;
- m_IRQ_status &= ~0x80;
- return retVal;
-#endif
-
- case 0x1105: /* $5205 */
- return (m_mult1 * m_mult2) & 0xff;
- case 0x1106: /* $5206 */
- return ((m_mult1 * m_mult2) & 0xff00) >> 8;
-
- default:
- logerror("** MMC5 uncaught read, offset: %04x\n", offset + 0x4100);
- return 0x00;
- }
-}
-
-
-WRITE8_MEMBER(nes_carts_state::exrom_l_w)
-{
- // LOG_MMC(("Mapper 5 write, offset: %04x, data: %02x\n", offset + 0x4100, data));
- /* Send $5000-$5015 to the sound chip */
- if ((offset >= 0xf00) && (offset <= 0xf15))
- {
- nes_psg_w(m_sound, space, offset & 0x1f, data);
- return;
- }
-
- /* $5c00 - $5fff: extended videoram attributes */
- if ((offset >= 0x1b00) && (offset <= 0x1eff))
- {
- if (m_MMC5_vram_protect == 0x03)
- m_mapper_ram[offset - 0x1b00] = data;
- return;
- }
-
- switch (offset)
- {
- case 0x1000: /* $5100 */
- m_mmc5_prg_mode = data & 0x03;
- // mmc5_update_prg(machine());
- LOG_MMC(("MMC5 rom bank mode: %02x\n", data));
- break;
-
- case 0x1001: /* $5101 */
- m_mmc5_chr_mode = data & 0x03;
- // update chr
- LOG_MMC(("MMC5 vrom bank mode: %02x\n", data));
- break;
-
- case 0x1002: /* $5102 */
- if (data == 0x02)
- m_MMC5_vram_protect |= 1;
- else
- m_MMC5_vram_protect = 0;
- LOG_MMC(("MMC5 vram protect 1: %02x\n", data));
- break;
- case 0x1003: /* 5103 */
- if (data == 0x01)
- m_MMC5_vram_protect |= 2;
- else
- m_MMC5_vram_protect = 0;
- LOG_MMC(("MMC5 vram protect 2: %02x\n", data));
- break;
-
- case 0x1004: /* $5104 - Extra VRAM (EXRAM) control */
- m_mmc5_vram_control = data & 0x03;
- // update render
- mmc5_update_render_mode(machine());
- LOG_MMC(("MMC5 exram control: %02x\n", data));
- break;
-
- case 0x1005: /* $5105 */
- mmc5_ppu_mirror(machine(), 0, data & 0x03);
- mmc5_ppu_mirror(machine(), 1, (data & 0x0c) >> 2);
- mmc5_ppu_mirror(machine(), 2, (data & 0x30) >> 4);
- mmc5_ppu_mirror(machine(), 3, (data & 0xc0) >> 6);
- // update render
- mmc5_update_render_mode(machine());
- break;
-
- /* tile data for MMC5 flood-fill NT mode */
- case 0x1006:
- m_MMC5_floodtile = data;
- break;
-
- /* attr data for MMC5 flood-fill NT mode */
- case 0x1007:
- switch (data & 3)
- {
- default:
- case 0: m_MMC5_floodattr = 0x00; break;
- case 1: m_MMC5_floodattr = 0x55; break;
- case 2: m_MMC5_floodattr = 0xaa; break;
- case 3: m_MMC5_floodattr = 0xff; break;
- }
- break;
-
- case 0x1013: /* $5113 */
- LOG_MMC(("MMC5 mid RAM bank select: %02x\n", data & 0x07));
- // FIXME: a few Koei games have both WRAM & BWRAM but here we don't support this (yet)
- if (m_battery)
- wram_bank(data, NES_BATTERY);
- else
- wram_bank(data, NES_WRAM);
- break;
-
-
- case 0x1014: /* $5114 */
- case 0x1015: /* $5115 */
- case 0x1016: /* $5116 */
- case 0x1017: /* $5117 */
- m_mmc5_prg_regs[offset & 3] = data;
- mmc5_update_prg(machine());
- break;
-
-#if 0
- // these do not work as expected... I guess we definitely need the bank update at proper times (with BG vs. sprite timing)
- case 0x1020: /* $5120 */
- case 0x1021: /* $5121 */
- case 0x1022: /* $5122 */
- case 0x1023: /* $5123 */
- case 0x1024: /* $5124 */
- case 0x1025: /* $5125 */
- case 0x1026: /* $5126 */
- case 0x1027: /* $5127 */
- data |= (m_mmc5_chr_high << 8);
- if (!m_mmc5_last_chr_a)
- {
- m_mmc5_vrom_regA[offset & 0x07] = data;
- m_mmc5_last_chr_a = 1;
- if (m_ppu->get_current_scanline() == 240 || !m_ppu->is_sprite_8x16())
- mmc5_update_chr_a(machine());
- }
- break;
-
-
- case 0x1028: /* $5128 */
- case 0x1029: /* $5129 */
- case 0x102a: /* $512a */
- case 0x102b: /* $512b */
- data |= (m_mmc5_chr_high << 8);
- m_mmc5_vrom_regB[offset & 0x03] = data;
- m_mmc5_last_chr_a = 0;
- if (m_ppu->get_current_scanline() == 240 || !m_ppu->is_sprite_8x16())
- mmc5_update_chr_b(machine());
- break;
-
- case 0x1030: /* $5130 */
- m_mmc5_chr_high = data & 0x03;
- if (m_mmc5_vram_control == 1)
- {
- // in this case m_mmc5_chr_high selects which 256KB of CHR ROM
- // is to be used for all background tiles on the screen.
- }
- break;
-
-#endif
-
- case 0x1020: /* $5120 */
- LOG_MMC(("MMC5 $5120 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[0] = data | (m_mmc5_high_chr << 8);
- // mapper5_sync_vrom(0);
- chr1_0(m_MMC5_vrom_bank[0], CHRROM);
- // m_nes_vram_sprite[0] = m_MMC5_vrom_bank[0] * 64;
- // vrom_next[0] = 4;
- // vrom_page_a = 1;
- // vrom_page_b = 0;
- break;
- }
- break;
- case 0x1021: /* $5121 */
- LOG_MMC(("MMC5 $5121 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x02:
- /* 2k switch */
- chr2_0(data | (m_mmc5_high_chr << 8), CHRROM);
- break;
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[1] = data | (m_mmc5_high_chr << 8);
- // mapper5_sync_vrom(0);
- chr1_1(m_MMC5_vrom_bank[1], CHRROM);
- // m_nes_vram_sprite[1] = m_MMC5_vrom_bank[0] * 64;
- // vrom_next[1] = 5;
- // vrom_page_a = 1;
- // vrom_page_b = 0;
- break;
- }
- break;
- case 0x1022: /* $5122 */
- LOG_MMC(("MMC5 $5122 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[2] = data | (m_mmc5_high_chr << 8);
- // mapper5_sync_vrom(0);
- chr1_2(m_MMC5_vrom_bank[2], CHRROM);
- // m_nes_vram_sprite[2] = m_MMC5_vrom_bank[0] * 64;
- // vrom_next[2] = 6;
- // vrom_page_a = 1;
- // vrom_page_b = 0;
- break;
- }
- break;
- case 0x1023: /* $5123 */
- LOG_MMC(("MMC5 $5123 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x01:
- chr4_0(data, CHRROM);
- break;
- case 0x02:
- /* 2k switch */
- chr2_2(data | (m_mmc5_high_chr << 8), CHRROM);
- break;
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[3] = data | (m_mmc5_high_chr << 8);
- // mapper5_sync_vrom(0);
- chr1_3(m_MMC5_vrom_bank[3], CHRROM);
- // m_nes_vram_sprite[3] = m_MMC5_vrom_bank[0] * 64;
- // vrom_next[3] = 7;
- // vrom_page_a = 1;
- // vrom_page_b = 0;
- break;
- }
- break;
- case 0x1024: /* $5124 */
- LOG_MMC(("MMC5 $5124 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[4] = data | (m_mmc5_high_chr << 8);
- // mapper5_sync_vrom(0);
- chr1_4(m_MMC5_vrom_bank[4], CHRROM);
- // m_nes_vram_sprite[4] = m_MMC5_vrom_bank[0] * 64;
- // vrom_next[0] = 0;
- // vrom_page_a = 0;
- // vrom_page_b = 0;
- break;
- }
- break;
- case 0x1025: /* $5125 */
- LOG_MMC(("MMC5 $5125 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x02:
- /* 2k switch */
- chr2_4(data | (m_mmc5_high_chr << 8), CHRROM);
- break;
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[5] = data | (m_mmc5_high_chr << 8);
- // mapper5_sync_vrom(0);
- chr1_5(m_MMC5_vrom_bank[5], CHRROM);
- // m_nes_vram_sprite[5] = m_MMC5_vrom_bank[0] * 64;
- // vrom_next[1] = 1;
- // vrom_page_a = 0;
- // vrom_page_b = 0;
- break;
- }
- break;
- case 0x1026: /* $5126 */
- LOG_MMC(("MMC5 $5126 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[6] = data | (m_mmc5_high_chr << 8);
- // mapper5_sync_vrom(0);
- chr1_6(m_MMC5_vrom_bank[6], CHRROM);
- // m_nes_vram_sprite[6] = m_MMC5_vrom_bank[0] * 64;
- // vrom_next[2] = 2;
- // vrom_page_a = 0;
- // vrom_page_b = 0;
- break;
- }
- break;
- case 0x1027: /* $5127 */
- LOG_MMC(("MMC5 $5127 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x00:
- /* 8k switch */
- chr8(data, CHRROM);
- break;
- case 0x01:
- /* 4k switch */
- chr4_4(data, CHRROM);
- break;
- case 0x02:
- /* 2k switch */
- chr2_6(data | (m_mmc5_high_chr << 8), CHRROM);
- break;
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[7] = data | (m_mmc5_high_chr << 8);
- // mapper5_sync_vrom(0);
- chr1_7(m_MMC5_vrom_bank[7], CHRROM);
- // m_nes_vram_sprite[7] = m_MMC5_vrom_bank[0] * 64;
- // vrom_next[3] = 3;
- // vrom_page_a = 0;
- // vrom_page_b = 0;
- break;
- }
- break;
- case 0x1028: /* $5128 */
- LOG_MMC(("MMC5 $5128 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[8] = data | (m_mmc5_high_chr << 8);
- // nes_vram[vrom_next[0]] = data * 64;
- // nes_vram[0 + (vrom_page_a*4)] = data * 64;
- // nes_vram[0] = data * 64;
- chr1_4(m_MMC5_vrom_bank[8], CHRROM);
- // mapper5_sync_vrom(1);
- if (!m_vrom_page_b)
- {
- m_vrom_page_a ^= 0x01;
- m_vrom_page_b = 1;
- }
- break;
- }
- break;
- case 0x1029: /* $5129 */
- LOG_MMC(("MMC5 $5129 vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x02:
- /* 2k switch */
- chr2_0(data | (m_mmc5_high_chr << 8), CHRROM);
- chr2_4(data | (m_mmc5_high_chr << 8), CHRROM);
- break;
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[9] = data | (m_mmc5_high_chr << 8);
- // nes_vram[vrom_next[1]] = data * 64;
- // nes_vram[1 + (vrom_page_a*4)] = data * 64;
- // nes_vram[1] = data * 64;
- chr1_5(m_MMC5_vrom_bank[9], CHRROM);
- // mapper5_sync_vrom(1);
- if (!m_vrom_page_b)
- {
- m_vrom_page_a ^= 0x01;
- m_vrom_page_b = 1;
- }
- break;
- }
- break;
- case 0x102a: /* $512a */
- LOG_MMC(("MMC5 $512a vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[10] = data | (m_mmc5_high_chr << 8);
- // nes_vram[vrom_next[2]] = data * 64;
- // nes_vram[2 + (vrom_page_a*4)] = data * 64;
- // nes_vram[2] = data * 64;
- chr1_6(m_MMC5_vrom_bank[10], CHRROM);
- // mapper5_sync_vrom(1);
- if (!m_vrom_page_b)
- {
- m_vrom_page_a ^= 0x01;
- m_vrom_page_b = 1;
- }
- break;
- }
- break;
- case 0x102b: /* $512b */
- LOG_MMC(("MMC5 $512b vrom select: %02x (mode: %d)\n", data, m_mmc5_chr_mode));
- switch (m_mmc5_chr_mode)
- {
- case 0x00:
- /* 8k switch */
- /* switches in first half of an 8K bank!) */
- chr4_0(data << 1, CHRROM);
- chr4_4(data << 1, CHRROM);
- break;
- case 0x01:
- /* 4k switch */
- chr4_0(data, CHRROM);
- chr4_4(data, CHRROM);
- break;
- case 0x02:
- /* 2k switch */
- chr2_2(data | (m_mmc5_high_chr << 8), CHRROM);
- chr2_6(data | (m_mmc5_high_chr << 8), CHRROM);
- break;
- case 0x03:
- /* 1k switch */
- m_MMC5_vrom_bank[11] = data | (m_mmc5_high_chr << 8);
- // nes_vram[vrom_next[3]] = data * 64;
- // nes_vram[3 + (vrom_page_a*4)] = data * 64;
- // nes_vram[3] = data * 64;
- chr1_7(m_MMC5_vrom_bank[11], CHRROM);
- // mapper5_sync_vrom(1);
- if (!m_vrom_page_b)
- {
- m_vrom_page_a ^= 0x01;
- m_vrom_page_b = 1;
- }
- break;
- }
- break;
-
- case 0x1030: /* $5130 */
- m_mmc5_high_chr = data & 0x03;
- if (m_mmc5_vram_control == 1)
- {
- // in this case m_mmc5_high_chr selects which 256KB of CHR ROM
- // is to be used for all background tiles on the screen.
- }
- break;
-
-
- case 0x1100: /* $5200 */
- m_mmc5_split_scr = data;
- // in EX2 and EX3 modes, no split screen
- if (m_mmc5_vram_control & 0x02)
- m_mmc5_split_scr &= 0x7f;
- m_mmc5_split_ctrl = data;
- break;
-
- case 0x1101: /* $5201 */
- m_mmc5_split_yst = (data >= 240) ? data - 16 : data;
- break;
-
- case 0x1102: /* $5202 */
- m_mmc5_split_bank = data;
- break;
-
- case 0x1103: /* $5203 */
- m_IRQ_count = data;
- m_MMC5_scanline = data;
- LOG_MMC(("MMC5 irq scanline: %d\n", m_IRQ_count));
- break;
- case 0x1104: /* $5204 */
- m_IRQ_enable = data & 0x80;
- LOG_MMC(("MMC5 irq enable: %02x\n", data));
- break;
- case 0x1105: /* $5205 */
- m_mult1 = data;
- break;
- case 0x1106: /* $5206 */
- m_mult2 = data;
- break;
-
- default:
- logerror("** MMC5 uncaught write, offset: %04x, data: %02x\n", offset + 0x4100, data);
- break;
- }
-}
-
-/*************************************************************
-
- NTBROM & Sunsoft-4 board emulation
-
- Part of this can be used also for Sunsoft Double Cassette
- System... which games use it?
-
- iNES: mapper 68
-
- *************************************************************/
-
-static void ntbrom_mirror( running_machine &machine, int mirror, int mirr0, int mirr1 )
-{
- nes_state *state = machine.driver_data<nes_state>();
- switch (mirror)
- {
- case 0x00:
- state->set_nt_mirroring(PPU_MIRROR_HORZ);
- break;
- case 0x01:
- state->set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- case 0x02:
- state->set_nt_mirroring(PPU_MIRROR_LOW);
- break;
- case 0x03:
- state->set_nt_mirroring(PPU_MIRROR_HIGH);
- break;
- case 0x10:
- state->set_nt_page(0, ROM, mirr0 | 0x80, 0);
- state->set_nt_page(1, ROM, mirr1 | 0x80, 0);
- state->set_nt_page(2, ROM, mirr0 | 0x80, 0);
- state->set_nt_page(3, ROM, mirr1 | 0x80, 0);
- break;
- case 0x11:
- state->set_nt_page(0, ROM, mirr0 | 0x80, 0);
- state->set_nt_page(1, ROM, mirr0 | 0x80, 0);
- state->set_nt_page(2, ROM, mirr1 | 0x80, 0);
- state->set_nt_page(3, ROM, mirr1 | 0x80, 0);
- break;
- case 0x12:
- state->set_nt_page(0, ROM, mirr0 | 0x80, 0);
- state->set_nt_page(1, ROM, mirr0 | 0x80, 0);
- state->set_nt_page(2, ROM, mirr0 | 0x80, 0);
- state->set_nt_page(3, ROM, mirr0 | 0x80, 0);
- break;
- case 0x13:
- state->set_nt_page(0, ROM, mirr1 | 0x80, 0);
- state->set_nt_page(1, ROM, mirr1 | 0x80, 0);
- state->set_nt_page(2, ROM, mirr1 | 0x80, 0);
- state->set_nt_page(3, ROM, mirr1 | 0x80, 0);
- break;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::ntbrom_w)
-{
- LOG_MMC(("ntbrom_w, offset %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- chr2_0(data, CHRROM);
- break;
- case 0x1000:
- chr2_2(data, CHRROM);
- break;
- case 0x2000:
- chr2_4(data, CHRROM);
- break;
- case 0x3000:
- chr2_6(data, CHRROM);
- break;
- case 0x4000:
- m_mmc_latch1 = data & 0x7f;
- ntbrom_mirror(machine(), m_mmc_reg[0], m_mmc_latch1, m_mmc_latch2);
- break;
- case 0x5000:
- m_mmc_latch2 = data & 0x7f;
- ntbrom_mirror(machine(), m_mmc_reg[0], m_mmc_latch1, m_mmc_latch2);
- break;
- case 0x6000:
- m_mmc_reg[0] = data & 0x13;
- ntbrom_mirror(machine(), m_mmc_reg[0], m_mmc_latch1, m_mmc_latch2);
- break;
- case 0x7000:
- prg16_89ab(data);
- break;
- default:
- LOG_MMC(("ntbrom_w uncaught write, offset: %04x, data: %02x\n", offset, data));
- break;
- }
-}
-
-/*************************************************************
-
- JxROM & Sunsoft 5A / 5B / FME7 board emulation
-
- Notice that Sunsoft-5B = FME7 + sound chip (the latter being
- currently unemulated in MESS)
-
- iNES: mapper 69
-
- *************************************************************/
-
-/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
- we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
- there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
-void nes_state::jxrom_irq( int scanline, int vblank, int blanked )
-{
- /* TODO: change to reflect the actual number of cycles spent */
- if ((m_IRQ_enable & 0x80) && (m_IRQ_enable & 0x01))
- {
- if (m_IRQ_count <= 114)
- {
- m_IRQ_count = 0xffff;
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- else
- m_IRQ_count -= 114;
- }
- else if (m_IRQ_enable & 0x01) // if enable bit 7 is not set, only decrement the counter!
- {
- if (m_IRQ_count <= 114)
- m_IRQ_count = 0xffff;
- else
- m_IRQ_count -= 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::jxrom_w)
-{
- LOG_MMC(("jxrom_w, offset %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6000)
- {
- case 0x0000:
- m_mmc_latch1 = data & 0x0f;
- break;
-
- case 0x2000:
- switch (m_mmc_latch1)
- {
- case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
- chr1_x(m_mmc_latch1, data, CHRROM);
- break;
-
- case 8:
- if (!(data & 0x40))
- {
- // is PRG ROM
- space.unmap_write(0x6000, 0x7fff);
- prg8_67(data & 0x3f);
- }
- else if (data & 0x80)
- {
- // is PRG RAM
- space.install_write_bank(0x6000, 0x7fff, "bank5");
- m_prg_bank[4] = m_battery_bank5_start + (data & 0x3f);
- membank("bank5")->set_entry(m_prg_bank[4]);
- }
- break;
-
- case 9:
- prg8_89(data);
- break;
- case 0x0a:
- prg8_ab(data);
- break;
- case 0x0b:
- prg8_cd(data);
- break;
- case 0x0c:
- switch (data & 0x03)
- {
- case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
- case 0x0d:
- m_IRQ_enable = data;
- break;
- case 0x0e:
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
- break;
- case 0x0f:
- m_IRQ_count = (m_IRQ_count & 0x00ff) | (data << 8);
- break;
- }
- break;
-
- /* Here we would have sound command for Sunsoft 5b variant */
- // case 0x4000:
- // case 0x6000:
-
- case 0x4000:
- LOG_MMC(("Sunsoft-5B Sound: Register select write, data: %02x\n", data));
- break;
- case 0x6000:
- LOG_MMC(("Sunsoft-5B Sound: Register write, data: %02x\n", data));
- break;
- default:
- logerror("jxrom_w uncaught %04x value: %02x\n", offset + 0x8000, data);
- break;
- }
-}
-
-/*************************************************************
-
- DxROM & Namcot 3433 - 3443 board emulation
-
- Games: Dragon Spirit - Aratanaru Densetsu, Namcot Mahjong, Quinty
-
- These are the same board, but DRROM (and Tengen 800004) have
- 4-screen mirroring
-
- iNES: mappers 88, 206 (same as 88 but possibly 4-screen mirroring)
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::dxrom_w)
-{
- LOG_MMC(("dxrom_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset >= 0x2000)
- return;
-
- switch (offset & 1)
- {
- case 1:
- switch (m_mmc_latch1 & 0x07)
- {
- case 0: chr2_0(data >> 1, CHRROM); break;
- case 1: chr2_2(data >> 1, CHRROM); break;
- case 2: chr1_4(data | 0x40, CHRROM); break;
- case 3: chr1_5(data | 0x40, CHRROM); break;
- case 4: chr1_6(data | 0x40, CHRROM); break;
- case 5: chr1_7(data | 0x40, CHRROM); break;
- case 6: prg8_89(data); break;
- case 7: prg8_ab(data); break;
- }
- break;
- case 0:
- m_mmc_latch1 = data;
- break;
- }
-}
-
-
-/*************************************************************
-
- Namcot 3453 board emulation
-
- Games: Devil Man
-
- These are the same as Namcot 34x3, but with additional mirroring
- control
-
- iNES: mapper 154
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::namcot3453_w)
-{
- LOG_MMC(("namcot3453_w, offset: %04x, data: %02x\n", offset, data));
-
- // additional mirroring control when writing to even addresses
- if (!(offset & 1))
- set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
-
- dxrom_w(space, offset, data, mem_mask);
-}
-
-/*************************************************************
-
- Namcot 3446 board emulation
-
- Games: Digital Devil Monogatari - Megami Tensei
-
- These are similar Namcot 34x3, but different bankswitch capabilities
-
- iNES: mapper 76
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::namcot3446_w)
-{
- LOG_MMC(("namcot3446_w, offset: %04x, data: %02x\n", offset, data));
-
- // NEStopia does not have this!
- if (offset >= 0x2000)
- {
- if (!(offset & 1))
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- return;
- }
-
- switch (offset & 1)
- {
- case 1:
- switch (m_mmc_latch1 & 0x07)
- {
- case 2: chr2_0(data, CHRROM); break;
- case 3: chr2_2(data, CHRROM); break;
- case 4: chr2_4(data, CHRROM); break;
- case 5: chr2_6(data, CHRROM); break;
- case 6: BIT(m_mmc_latch1, 6) ? prg8_cd(data) : prg8_89(data); break;
- case 7: prg8_ab(data); break;
- }
- break;
- case 0:
- m_mmc_latch1 = data;
- break;
- }
-}
-
-/*************************************************************
-
- Namcot 3425 board emulation
-
- Games: Dragon Buster
-
- These are similar Namcot 34x3, but with NT mirroring (two
- different modes)
-
- iNES: mapper 95
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::namcot3425_w)
-{
- UINT8 mode;
- LOG_MMC(("namcot3425_w, offset: %04x, data: %02x\n", offset, data));
- if (offset >= 0x2000)
- return;
-
- switch (offset & 1)
- {
- case 1:
- mode = m_mmc_latch1 & 0x07;
- switch (mode)
- {
- case 0: chr2_0(data >> 1, CHRROM); break;
- case 1: chr2_2(data >> 1, CHRROM); break;
- case 2:
- case 3:
- case 4:
- case 5:
- chr1_x(2 + mode, data, CHRROM);
- m_mmc_reg[mode - 2] = BIT(data, 5);
- if (!BIT(m_mmc_latch1, 7))
- {
- set_nt_page(0, CIRAM, m_mmc_reg[0], 1);
- set_nt_page(1, CIRAM, m_mmc_reg[1], 1);
- set_nt_page(2, CIRAM, m_mmc_reg[2], 1);
- set_nt_page(3, CIRAM, m_mmc_reg[3], 1);
- }
- else
- set_nt_mirroring(PPU_MIRROR_HORZ);
- break;
- case 6: prg8_89(data); break;
- case 7: prg8_ab(data); break;
- }
- break;
- case 0:
- m_mmc_latch1 = data;
- break;
- }
-}
-
-/*************************************************************
-
- Discrete Logic board IC 74x377 by Color Dreams / Nina-007 emulation
-
- Games: many Color Dreams and Wisdom Tree titles
-
- iNES: mapper 11
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::dis_74x377_w)
-{
- LOG_MMC(("dis_74x377_w, offset: %04x, data: %02x\n", offset, data));
-
- chr8(data >> 4, m_mmc_chr_source);
- prg32(data & 0x0f);
-}
-
-/*************************************************************
-
- Discrete Logic board IC 74x139x74 by Konami & Jaleco
-
- iNES: mapper 87
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::dis_74x139x74_m_w)
-{
- LOG_MMC(("dis_74x139x74_m_w, offset: %04x, data: %02x\n", offset, data));
-
- chr8(((data & 0x02) >> 1) | ((data & 0x01) << 1), CHRROM);
-}
-
-/*************************************************************
-
- Discrete Logic board IC 74x161x138
-
- Games: Crime Busters
-
- iNES: mapper 38
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::dis_74x161x138_m_w)
-{
- LOG_MMC(("dis_74x161x138_m_w, offset: %04x, data: %02x\n", offset, data));
-
- chr8(data >> 2, CHRROM);
- prg32(data);
-}
-
-/*************************************************************
-
- Discrete Logic board IC 74x161x161x32
-
- There are two variants (one with hardwired mirroring, the
- other with a mirroring control), making necessary two distinct
- mappers & pcb_id
-
- iNES: mappers 70 & 152
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::dis_74x161x161x32_w)
-{
- LOG_MMC(("dis_74x161x161x32_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring
- set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- chr8(data, CHRROM);
- prg16_89ab(data >> 4);
-}
-
-/*************************************************************
-
- Bandai LZ93D50 boards emulation
-
- There are several variants: plain board with or without SRAM,
- board + 24C01 EEPROM, board + 24C02 EEPROM, board + Barcode
- Reader (DATACH).
- We currently only emulate the base hardware.
-
- Games: Crayon Shin-Chan - Ora to Poi Poi, Dragon Ball Z Gaiden,
- Dragon Ball Z II & III, Rokudenashi Blues, SD Gundam
- Gaiden - KGM2, Dragon Ball Z, Magical Taruruuto-kun, SD Gundam
- Gaiden [with EEPROM], Dragon Ball, Dragon Ball 3, Famicom Jump,
- Famicom Jump II [no EEPROM], Datach Games
-
- At the moment, we don't support EEPROM I/O
-
- iNES: mappers 16, 153, 157 & 159
-
- In MESS: Supported
-
- *************************************************************/
-
-/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
- we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
- there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
-void nes_state::bandai_lz_irq(int scanline, int vblank, int blanked )
-{
- /* 114 is the number of cycles per scanline */
- /* TODO: change to reflect the actual number of cycles spent */
- if (m_IRQ_enable)
- {
- if (m_IRQ_count <= 114)
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_count = (0xffff - 114 + m_IRQ_count); // wrap around the 16 bits counter
- }
- m_IRQ_count -= 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::lz93d50_w)
-{
- LOG_MMC(("lz93d50_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x000f)
- {
- case 0: case 1: case 2: case 3:
- case 4: case 5: case 6: case 7:
- chr1_x(offset & 0x07, data, m_mmc_chr_source);
- break;
- case 8:
- prg16_89ab(data);
- break;
- case 9:
- switch (data & 0x03)
- {
- case 0: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
- case 0x0a:
- m_IRQ_enable = data & 0x01;
- break;
- case 0x0b:
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
- break;
- case 0x0c:
- m_IRQ_count = (m_IRQ_count & 0x00ff) | (data << 8);
- break;
- default:
- logerror("lz93d50_w uncaught write, offset: %04x, data: %02x\n", offset, data);
- break;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::lz93d50_m_w)
-{
- LOG_MMC(("lz93d50_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!m_battery && !m_wram)
- lz93d50_w(space, offset & 0x0f, data, mem_mask);
- else if (m_battery)
- m_battery_ram[offset] = data;
- else
- m_wram[offset] = data;
-}
-
-static void fjump2_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 mmc_helper = 0;
- int i;
-
- for (i = 0; i < 8; i++)
- mmc_helper |= ((state->m_mmc_reg[i] & 0x01) << 4);
-
- state->prg16_89ab(mmc_helper | state->m_mmc_latch1);
- state->prg16_cdef(mmc_helper | 0x0f);
-}
-
-WRITE8_MEMBER(nes_carts_state::fjump2_w)
-{
- LOG_MMC(("fjump2_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x000f)
- {
- case 0: case 1: case 2: case 3:
- case 4: case 5: case 6: case 7:
- m_mmc_reg[offset & 0x000f] = data;
- fjump2_set_prg(machine());
- break;
- case 8:
- m_mmc_latch1 = (data & 0x0f);
- fjump2_set_prg(machine());
- break;
- default:
- lz93d50_m_w(space, offset & 0x0f, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Bandai Karaoke Studio board emulation
-
- Games: Karaoke Studio
-
- Note: we currently do not emulate the mic
-
- iNES: mapper 188
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bandai_ks_w)
-{
- LOG_MMC(("bandai_ks_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab(data ^ 0x08);
-}
-
-/*************************************************************
-
- Bandai Oeka Kids board emulation
-
- Games: Oeka Kids - Anpanman no Hiragana Daisuki, Oeka
- Kids - Anpanman to Oekaki Shiyou!!
-
- iNES: mapper 96
-
- In MESS: Preliminary Support.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bandai_ok_w)
-{
- UINT8 mmc_helper;
- LOG_MMC(("mapper96_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data);
-
- m_mmc_latch1 = data;
- mmc_helper = (m_mmc_latch1 & 0x03) | (data & 0x04);
- chr4_0(mmc_helper, CHRRAM);
- chr4_4(0x03 | (data & 0x04), CHRRAM);
-}
-
-/*************************************************************
-
- Irem LROG017 - Discrete board emulation (74*161/161/21/138)
-
- Games: Napoleon Senki
-
- iNES: mapper 77
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::lrog017_w)
-{
- LOG_MMC(("lrog017_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data);
- chr2_0((data >> 4), CHRROM);
-}
-
-/*************************************************************
-
- Irem Holy Diver board emulation
-
- iNES: mapper 78 (shared with JF-16)
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::irem_hd_w)
-{
- LOG_MMC(("irem_hd_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- chr8(data >> 4, CHRROM);
- prg16_89ab(data);
-}
-
-/*************************************************************
-
- Irem TAM-S1 board emulation
-
- Games: Kaiketsu Yanchamaru
-
- iNES: mapper 97
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::tam_s1_w)
-{
- LOG_MMC(("tam_s1_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x4000)
- {
- set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- prg16_cdef(data);
- }
-}
-
-/*************************************************************
-
- Irem G-101 board emulation
-
- Major League uses hardwired mirroring
-
- iNES: mapper 32
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::g101_w)
-{
- LOG_MMC(("g101_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- // NEStopia here differs a little bit
- m_mmc_latch1 ? prg8_cd(data) : prg8_89(data);
- break;
- case 0x1000:
- m_mmc_latch1 = BIT(data, 1);
- if (!m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 0x2000:
- prg8_ab(data);
- break;
- case 0x3000:
- chr1_x(offset & 0x07, data, CHRROM);
- break;
- }
-}
-
-/*************************************************************
-
- Irem H-3001 board emulation
-
- Games: Daiku no Gen San 2 - Akage no Dan no Gyakushuu,
- Kaiketsu Yanchamaru 3, Spartan X 2
-
- iNES: mapper 65
-
- In MESS: Supported.
-
- *************************************************************/
-
-/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
- we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
- there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
-void nes_state::h3001_irq( int scanline, int vblank, int blanked )
-{
- if (m_IRQ_enable)
- {
- m_IRQ_count -= 114;
-
- if (m_IRQ_count <= 114)
- {
- m_IRQ_enable = 0;
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::h3001_w)
-{
- LOG_MMC(("h3001_w, offset %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7fff)
- {
- case 0x0000:
- prg8_89(data);
- break;
-
- case 0x1001:
- set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- case 0x1003:
- m_IRQ_enable = data & 0x80;
- break;
-
- case 0x1004:
- m_IRQ_count = m_IRQ_count_latch;
- break;
-
- case 0x1005:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0x00ff) | (data << 8);
- break;
-
- case 0x1006:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0xff00) | data;
- break;
-
- case 0x2000:
- prg8_ab(data);
- break;
-
- case 0x3000: case 0x3001: case 0x3002: case 0x3003:
- case 0x3004: case 0x3005: case 0x3006: case 0x3007:
- chr1_x(offset & 0x07, data, CHRROM);
- break;
-
- case 0x4000:
- prg8_cd(data);
- break;
-
- default:
- break;
- }
-}
-
-/*************************************************************
-
- Jaleco SS88006 board emulation, aka JF-27, JF-29, JF-30, ...,
- JF-38, JF-40, JF-41
-
- Games: Lord of King, Magic John, Moe Pro '90, Ninja Jajamaru,
- Pizza Pop, Plasma Ball
-
- iNES: mapper 18
-
- In MESS: Supported
-
- *************************************************************/
-
-/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
- we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
- there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
-void nes_state::ss88006_irq( int scanline, int vblank, int blanked )
-{
- /* Increment & check the IRQ scanline counter */
- if (m_IRQ_enable)
- {
- LOG_MMC(("scanline: %d, irq count: %04x\n", scanline, m_IRQ_count));
- if (m_IRQ_mode & 0x08)
- {
- if ((m_IRQ_count & 0x000f) < 114) // always true, but we only update the IRQ once per scanlines so we cannot be more precise :(
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_count = (m_IRQ_count & ~0x000f) | (0x0f - (114 & 0x0f) + (m_IRQ_count & 0x000f)); // sort of wrap around the counter
- }
- // decrements should not affect upper bits, so we don't do anything here (114 > 0x0f)
- }
- else if (m_IRQ_mode & 0x04)
- {
- if ((m_IRQ_count & 0x00ff) < 114)
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_count = (m_IRQ_count & ~0x00ff) | (0xff - 114 + (m_IRQ_count & 0x00ff)); // wrap around the 8 bits counter
- }
- else
- m_IRQ_count -= 114;
- }
- else if (m_IRQ_mode & 0x02)
- {
- if ((m_IRQ_count & 0x0fff) < 114)
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_count = (m_IRQ_count & ~0x0fff) | (0xfff - 114 + (m_IRQ_count & 0x0fff)); // wrap around the 12 bits counter
- }
- else
- m_IRQ_count -= 114;
- }
- else if (m_IRQ_count < 114)
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_count = (0xffff - 114 + m_IRQ_count); // wrap around the 16 bits counter
- }
- else
- m_IRQ_count -= 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::ss88006_w)
-{
- UINT8 bank;
- LOG_MMC(("mapper18_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7003)
- {
- case 0x0000:
- m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0xf0) | (data & 0x0f);
- prg8_89(m_mmc_prg_bank[0]);
- break;
- case 0x0001:
- m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0x0f) | (data << 4);
- prg8_89(m_mmc_prg_bank[0]);
- break;
- case 0x0002:
- m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0xf0) | (data & 0x0f);
- prg8_ab(m_mmc_prg_bank[1]);
- break;
- case 0x0003:
- m_mmc_prg_bank[1] = (m_mmc_prg_bank[1] & 0x0f) | (data << 4);
- prg8_ab(m_mmc_prg_bank[1]);
- break;
- case 0x1000:
- m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0xf0) | (data & 0x0f);
- prg8_cd(m_mmc_prg_bank[2]);
- break;
- case 0x1001:
- m_mmc_prg_bank[2] = (m_mmc_prg_bank[2] & 0x0f) | (data << 4);
- prg8_cd(m_mmc_prg_bank[2]);
- break;
-
- /* $9002, 3 (1002, 3) uncaught = Jaleco Baseball writes 0 */
- /* believe it's related to battery-backed ram enable/disable */
-
- case 0x2000: case 0x2001: case 0x2002: case 0x2003:
- case 0x3000: case 0x3001: case 0x3002: case 0x3003:
- case 0x4000: case 0x4001: case 0x4002: case 0x4003:
- case 0x5000: case 0x5001: case 0x5002: case 0x5003:
- bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0002) >> 1);
- if (offset & 0x0001)
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f)<< 4);
- else
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
-
- chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
- break;
-
- case 0x6000:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0xfff0) | (data & 0x0f);
- break;
- case 0x6001:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0xff0f) | ((data & 0x0f) << 4);
- break;
- case 0x6002:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0xf0ff) | ((data & 0x0f) << 8);
- break;
- case 0x6003:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0x0fff) | ((data & 0x0f) << 12);
- break;
-
- case 0x7000:
- m_IRQ_count = m_IRQ_count_latch;
- break;
- case 0x7001:
- m_IRQ_enable = data & 0x01;
- m_IRQ_mode = data & 0x0e;
- break;
-
- case 0x7002:
- switch (data & 0x03)
- {
- case 0: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 1: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
-
- default:
- logerror("Jaleco SS88006 uncaught write, addr: %04x, value: %02x\n", offset + 0x8000, data);
- break;
- }
-}
-
-/*************************************************************
-
- Jaleco JF-11, JF-12 & JF-14 boards emulation
-
- Games: Bio Senshi Dan, Mississippi Satsujin Jiken
-
- iNES: mapper 140
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::jf11_m_w)
-{
- LOG_MMC(("jf11_m_w, offset: %04x, data: %02x\n", offset, data));
- chr8(data, CHRROM);
- prg32(data >> 4);
-}
-
-/*************************************************************
-
- Jaleco JF-13 board emulation
-
- Games: Moero Pro Yakyuu
-
- Note: we don't emulate the additional sound hardware.
-
- iNES: mapper 86
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::jf13_m_w)
-{
- LOG_MMC(("jf13_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset == 0)
- {
- prg32((data >> 4) & 0x03);
- chr8(((data >> 4) & 0x04) | (data & 0x03), CHRROM);
- }
-
- if (offset == 0x1000)
- {
- LOG_MMC(("Jaleco JF-13 sound write, data: %02x\n", data));
- // according to NEStopia, this is the effect
- if ((data & 0x30) == 0x20)
- {
- // send command (data & 0x1f) to sound chip
- }
- }
-}
-
-/*************************************************************
-
- Jaleco JF-16 board emulation
-
- iNES: mapper 78 (shared with a diff Irem board)
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::jf16_w)
-{
- LOG_MMC(("jf16_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- chr8(data >> 4, CHRROM);
- prg16_89ab(data);
-}
-
-/*************************************************************
-
- Jaleco JF-17, JF-26 & JF-28 boards emulation
-
- Note: we don't emulate the additional sound hardware.
-
- Games: Moero!! Juudou Warriors, Moero!! Pro Tennis, Pinball
- Quest Jpn
-
- iNES: mapper 72
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::jf17_w)
-{
- LOG_MMC(("jf17_w, offset: %04x, data: %02x\n", offset, data));
-
- if (BIT(data, 7))
- prg16_89ab(data & 0x0f);
- if (BIT(data, 6))
- chr8(data & 0x0f, CHRROM);
- if (BIT(data, 5) && !BIT(data,4))
- LOG_MMC(("Jaleco JF-17 sound write, data: %02x\n", data & 0x1f));
-}
-
-/*************************************************************
-
- Jaleco JF-19 & JF-21 boards emulation
-
- Note: we don't emulate the additional sound hardware.
-
- Games: Moero Pro Soccer, Moero Pro Yakyuu '88
-
- iNES: mapper 92
-
- In MESS: Supported (no samples).
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::jf19_w)
-{
- LOG_MMC(("jf19_w, offset: %04x, data: %02x\n", offset, data));
-
- if (BIT(data, 7))
- prg16_cdef(data & 0x0f);
- if (BIT(data, 6))
- chr8(data & 0x0f, CHRROM);
- if (BIT(data, 5) && !BIT(data,4))
- LOG_MMC(("Jaleco JF-19 sound write, data: %02x\n", data & 0x1f));
-}
-
-/*************************************************************
-
- Konami VRC1 and Jaleco JF20, JF22
-
- Games: Exciting Boxing, Ganbare Goemon!, Tetsuwan Atom
-
- iNES: mapper 75
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::konami_vrc1_w)
-{
- LOG_MMC(("konami_vrc1_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- prg8_89(data);
- break;
- case 0x1000:
- set_nt_mirroring((data & 0x01) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x0f) | ((data & 0x02) << 3);
- m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x0f) | ((data & 0x04) << 2);
- chr4_0(m_mmc_vrom_bank[0], CHRROM);
- chr4_4(m_mmc_vrom_bank[1], CHRROM);
- break;
- case 0x2000:
- prg8_ab(data);
- break;
- case 0x4000:
- prg8_cd(data);
- break;
- case 0x6000:
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x10) | (data & 0x0f);
- chr4_0(m_mmc_vrom_bank[0], CHRROM);
- break;
- case 0x7000:
- m_mmc_vrom_bank[1] = (m_mmc_vrom_bank[1] & 0x10) | (data & 0x0f);
- chr4_4(m_mmc_vrom_bank[1], CHRROM);
- break;
- }
-}
-
-/*************************************************************
-
- Konami VRC-2
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::konami_vrc2_w)
-{
- UINT8 bank, shift, mask;
- UINT32 shifted_offs = (offset & 0x7000)
- | ((offset << (9 - m_vrc_ls_prg_a)) & 0x200)
- | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100);
- LOG_MMC(("konami_vrc2_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x1000)
- prg8_89(data);
- else if (offset < 0x2000)
- {
- switch (data & 0x03)
- {
- case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- }
- else if (offset < 0x3000)
- prg8_ab(data);
- else if (offset < 0x7000)
- {
- bank = ((shifted_offs & 0x7000) - 0x3000) / 0x0800 + BIT(shifted_offs, 9);
- shift = BIT(shifted_offs, 8) * 4;
- mask = (0xf0 >> shift);
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask)
- | (((data >> m_vrc_ls_chr) & 0x0f) << shift);
- chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
- }
- else
- logerror("konami_vrc2_w uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data);
-}
-
-/*************************************************************
-
- Konami VRC3
-
- Games: Salamander
-
- iNES: mapper 73
-
- In MESS: Supported. It also uses konami_irq.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::konami_vrc3_w)
-{
- LOG_MMC(("konami_vrc3_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- case 0x1000:
- /* dunno which address controls these */
- m_IRQ_count_latch = data;
- m_IRQ_enable_latch = data;
- break;
- case 0x2000:
- m_IRQ_enable = data;
- break;
- case 0x3000:
- m_IRQ_count &= ~0x0f;
- m_IRQ_count |= data & 0x0f;
- break;
- case 0x4000:
- m_IRQ_count &= ~0xf0;
- m_IRQ_count |= (data & 0x0f) << 4;
- break;
- case 0x7000:
- prg16_89ab(data);
- break;
- default:
- logerror("konami_vrc3_w uncaught write, offset %04x, data: %02x\n", offset, data);
- break;
- }
-}
-
-/*************************************************************
-
- Konami VRC-4
-
- In MESS: Supported
-
- *************************************************************/
-
-static void vrc4_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (state->m_mmc_latch1 & 0x02)
- {
- state->prg8_89(0xfe);
- state->prg8_cd(state->m_mmc_prg_bank[0]);
- }
- else
- {
- state->prg8_89(state->m_mmc_prg_bank[0]);
- state->prg8_cd(0xfe);
- }
-}
-
-void nes_state::konami_irq( int scanline, int vblank, int blanked )
-{
- /* Increment & check the IRQ scanline counter */
- if (m_IRQ_enable && (++m_IRQ_count == 0x100))
- {
- m_IRQ_count = m_IRQ_count_latch;
- m_IRQ_enable = m_IRQ_enable_latch;
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::konami_vrc4_w)
-{
- UINT8 bank, shift, mask;
- UINT32 shifted_offs = (offset & 0x7000)
- | ((offset << (9 - m_vrc_ls_prg_a)) & 0x200)
- | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100);
- LOG_MMC(("konami_vrc4_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x1000)
- {
- m_mmc_prg_bank[0] = data;
- vrc4_set_prg(machine());
- }
- else if (offset >= 0x2000 && offset < 0x3000)
- prg8_ab(data);
- else
- {
- switch (shifted_offs & 0x7300)
- {
- case 0x1000:
- case 0x1100:
- switch (data & 0x03)
- {
- case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
- case 0x1200:
- case 0x1300:
- m_mmc_latch1 = data & 0x02;
- vrc4_set_prg(machine());
- break;
- case 0x3000:
- case 0x3100:
- case 0x3200:
- case 0x3300:
- case 0x4000:
- case 0x4100:
- case 0x4200:
- case 0x4300:
- case 0x5000:
- case 0x5100:
- case 0x5200:
- case 0x5300:
- case 0x6000:
- case 0x6100:
- case 0x6200:
- case 0x6300:
- bank = ((shifted_offs & 0x7000) - 0x3000) / 0x0800 + BIT(shifted_offs, 9);
- shift = BIT(shifted_offs, 8) * 4;
- mask = (0xf0 >> shift);
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask) | ((data & 0x0f) << shift);
- chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
- break;
- case 0x7000:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0xf0) | (data & 0x0f);
- break;
- case 0x7100:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4);
- break;
- case 0x7200:
- m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
- m_IRQ_enable = data & 0x02;
- m_IRQ_enable_latch = data & 0x01;
- if (data & 0x02)
- m_IRQ_count = m_IRQ_count_latch;
- break;
- case 0x7300:
- m_IRQ_enable = m_IRQ_enable_latch;
- break;
- default:
- logerror("konami_vrc4_w uncaught write, addr: %04x value: %02x\n", shifted_offs + 0x8000, data);
- break;
- }
- }
-}
-
-/*************************************************************
-
- Konami VRC-6
-
- In MESS: Supported. It also uses konami_irq (there are IRQ
- issues though: see Akumajou Densetsu intro).
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::konami_vrc6_w)
-{
- UINT8 bank;
- UINT32 shifted_offs = (offset & 0x7000)
- | ((offset << (9 - m_vrc_ls_prg_a)) & 0x200)
- | ((offset << (8 - m_vrc_ls_prg_b)) & 0x100);
- LOG_MMC(("konami_vrc6_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x1000)
- prg16_89ab(data);
- else if (offset >= 0x4000 && offset < 0x5000)
- prg8_cd(data);
- else
- {
- switch (shifted_offs & 0x7300)
- {
- case 0x1000:
- case 0x1100:
- case 0x1200:
- case 0x2000:
- case 0x2100:
- case 0x2200:
- case 0x3000:
- case 0x3100:
- case 0x3200:
- LOG_MMC(("Konami VRC-6 Sound write, offset: %04x, data: %02x\n", shifted_offs & 0x7300, data));
- break;
- case 0x3300:
- switch (data & 0x0c)
- {
- case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 0x04: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 0x08: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 0x0c: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
- case 0x5000:
- case 0x5100:
- case 0x5200:
- case 0x5300:
- case 0x6000:
- case 0x6100:
- case 0x6200:
- case 0x6300:
- bank = ((shifted_offs & 0x7000) - 0x5000) / 0x0400 + ((shifted_offs & 0x0300) >> 8);
- chr1_x(bank, data, CHRROM);
- break;
- case 0x7000:
- m_IRQ_count_latch = data;
- break;
- case 0x7100:
- m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
- m_IRQ_enable = data & 0x02;
- m_IRQ_enable_latch = data & 0x01;
- if (data & 0x02)
- m_IRQ_count = m_IRQ_count_latch;
- break;
- case 0x7200:
- m_IRQ_enable = m_IRQ_enable_latch;
- break;
- default:
- logerror("konami_vrc6_w uncaught write, addr: %04x value: %02x\n", shifted_offs + 0x8000, data);
- break;
- }
- }
-}
-
-/*************************************************************
-
- Konami VRC7
-
- Games: Lagrange Point, Tiny Toon Adventures 2
-
- iNES: mapper 85
-
- In MESS: Supported. It also uses konami_irq.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::konami_vrc7_w)
-{
- UINT8 bank;
- LOG_MMC(("konami_vrc7_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7018)
- {
- case 0x0000:
- prg8_89(data);
- break;
- case 0x0008:
- case 0x0010:
- case 0x0018:
- prg8_ab(data);
- break;
-
- case 0x1000:
- prg8_cd(data);
- break;
-
- /* TODO: there are sound regs in here */
-
- case 0x2000:
- case 0x2008:
- case 0x2010:
- case 0x2018:
- case 0x3000:
- case 0x3008:
- case 0x3010:
- case 0x3018:
- case 0x4000:
- case 0x4008:
- case 0x4010:
- case 0x4018:
- case 0x5000:
- case 0x5008:
- case 0x5010:
- case 0x5018:
- bank = ((offset & 0x7000) - 0x2000) / 0x0800 + ((offset & 0x0018) ? 1 : 0);
- chr1_x(bank, data, m_mmc_chr_source);
- break;
-
- case 0x6000:
- switch (data & 0x03)
- {
- case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
- case 0x6008: case 0x6010: case 0x6018:
- m_IRQ_count_latch = data;
- break;
- case 0x7000:
- m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
- m_IRQ_enable = data & 0x02;
- m_IRQ_enable_latch = data & 0x01;
- if (data & 0x02)
- m_IRQ_count = m_IRQ_count_latch;
- break;
- case 0x7008: case 0x7010: case 0x7018:
- m_IRQ_enable = m_IRQ_enable_latch;
- break;
-
- default:
- logerror("konami_vrc7_w uncaught write, addr: %04x value: %02x\n", offset + 0x8000, data);
- break;
- }
-}
-
-/*************************************************************
-
- Namcot-163 board emulation
-
- Games: Battle Fleet, Family Circuit '91, Famista '90, '91,
- '92 & '94, Megami Tensei II, Top Striker, Wagyan Land 2 & 3
-
- iNES: mapper 19
-
- In MESS: Supported
-
- *************************************************************/
-
-/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
- we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
- there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
-void nes_state::namcot_irq( int scanline, int vblank, int blanked )
-{
- if (m_IRQ_enable)
- {
- if (m_IRQ_count >= (0x7fff - 114))
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_count = 0;
- }
- else
- m_IRQ_count += 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::namcot163_l_w)
-{
- LOG_MMC(("namcot163_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- switch (offset & 0x1800)
- {
- case 0x0800:
- LOG_MMC(("Namcot-163 sound reg write, data: %02x\n", data));
- break;
- case 0x1000: /* low byte of IRQ */
- m_IRQ_count = (m_IRQ_count & 0x7f00) | data;
- break;
- case 0x1800: /* high byte of IRQ, IRQ enable in high bit */
- m_IRQ_count = (m_IRQ_count & 0xff) | ((data & 0x7f) << 8);
- m_IRQ_enable = data & 0x80;
- break;
- }
-}
-
-READ8_MEMBER(nes_carts_state::namcot163_l_r)
-{
- LOG_MMC(("namcot163_l_r, offset: %04x\n", offset));
- offset += 0x100;
-
- switch (offset & 0x1800)
- {
- case 0x1000:
- return m_IRQ_count & 0xff;
- case 0x1800:
- return (m_IRQ_count >> 8) & 0xff;
- case 0x0800:
- LOG_MMC(("Namcot-163 sound reg read\n"));
- default:
- return 0x00;
- }
-}
-
-static void namcot163_set_mirror( running_machine &machine, UINT8 page, UINT8 data )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (!(data < 0xe0))
- state->set_nt_page(page, CIRAM, data & 0x01, 1);
- else
- state->set_nt_page(page, ROM, data, 0);
-}
-
-WRITE8_MEMBER(nes_carts_state::namcot163_w)
-{
- LOG_MMC(("namcot163_w, offset: %04x, data: %02x\n", offset, data));
- switch (offset & 0x7800)
- {
- case 0x0000: case 0x0800:
- case 0x1000: case 0x1800:
- case 0x2000: case 0x2800:
- case 0x3000: case 0x3800:
- chr1_x(offset / 0x800, data, CHRROM);
- break;
- case 0x4000:
- namcot163_set_mirror(machine(), 0, data);
- break;
- case 0x4800:
- namcot163_set_mirror(machine(), 1, data);
- break;
- case 0x5000:
- namcot163_set_mirror(machine(), 2, data);
- break;
- case 0x5800:
- namcot163_set_mirror(machine(), 3, data);
- break;
- case 0x6000:
- prg8_89(data & 0x3f);
- break;
- case 0x6800:
- m_mmc_latch1 = data & 0xc0; // this should enable High CHRRAM, but we still have to properly implement it!
- prg8_ab(data & 0x3f);
- break;
- case 0x7000:
- prg8_cd(data & 0x3f);
- break;
- case 0x7800:
- LOG_MMC(("Namcot-163 sound address write, data: %02x\n", data));
- break;
- }
-}
-
-/*************************************************************
-
- Sunsoft-1 board emulation
-
- Games: Atlantis no Nazo, Kanshakudama Nage Kantarou no
- Toukaidou Gojuusan Tsugi, Wing of Madoola, Fantasy Zone
-
- iNES: mapper 184 (Fantasy Zone uses this board with no
- CHRROM, and the register switches PRG banks)
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sunsoft1_m_w)
-{
- LOG_MMC(("sunsoft1_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if (m_chr_chunks)
- {
- chr4_0(data & 0x0f, CHRROM);
- chr4_4(data >> 4, CHRROM);
- }
- else
- prg16_89ab(data & 0x0f);
-}
-
-/*************************************************************
-
- Sunsoft-2 board emulation
-
- The two games using this board have incompatible mirroring
- wiring, making necessary two distinct mappers & pcb_id
-
- iNES: mapper 89 & 93
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sunsoft2_w)
-{
- UINT8 sunsoft_helper = (data & 0x07) | ((data & 0x80) ? 0x08 : 0x00);
- LOG_MMC(("sunsoft2_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!m_hard_mirroring) // there are two 'variants' depending on hardwired or mapper ctrl mirroring
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- if (m_chr_chunks)
- chr8(sunsoft_helper, CHRROM);
-
- prg16_89ab(data >> 4);
-}
-
-/*************************************************************
-
- Sunsoft-3 board emulation
-
- The two games using this board have incompatible mirroring
- wiring, making necessary two distinct mappers & pcb_id
-
- iNES: mapper 67
-
- *************************************************************/
-
-/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
- we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
- there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
-void nes_state::sunsoft3_irq( int scanline, int vblank, int blanked )
-{
- /* TODO: change to reflect the actual number of cycles spent: both using 114 or cycling 114,114,113
- produces a 1-line glitch in Fantasy Zone 2: it really requires the counter to be updated each CPU cycle! */
- if (m_IRQ_enable)
- {
- if (m_IRQ_count <= 114)
- {
- m_IRQ_enable = 0;
- m_IRQ_count = 0xffff;
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- else
- m_IRQ_count -= 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::sunsoft3_w)
-{
- LOG_MMC(("sunsoft3_w, offset %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7800)
- {
- case 0x0800:
- chr2_0(data, CHRROM);
- break;
- case 0x1800:
- chr2_2(data, CHRROM);
- break;
- case 0x2800:
- chr2_4(data, CHRROM);
- break;
- case 0x3800:
- chr2_6(data, CHRROM);
- break;
- case 0x4000:
- case 0x4800:
- m_IRQ_toggle ^= 1;
- if (m_IRQ_toggle)
- m_IRQ_count = (m_IRQ_count & 0x00ff) | (data << 8);
- else
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
- break;
- case 0x5800:
- m_IRQ_enable = BIT(data, 4);
- m_IRQ_toggle = 0;
- break;
- case 0x6800:
- switch (data & 3)
- {
- case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
- case 0x7800:
- prg16_89ab(data);
- break;
- default:
- LOG_MMC(("sunsoft3_w uncaught write, offset: %04x, data: %02x\n", offset, data));
- break;
- }
-}
-
-/*************************************************************
-
- Taito TC0190FMC + board emulation
-
- Games: Akira, Bakushou!! Jinsei Gekijou, Don Doko Don,
- Insector X, Operation Wolf, Power Blazer, Takeshi no
- Sengoku Fuuunji
-
- iNES: mapper 33
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::tc0190fmc_w)
-{
- LOG_MMC(("tc0190fmc_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7003)
- {
- case 0x0000:
- set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- prg8_89(data);
- break;
- case 0x0001:
- prg8_ab(data);
- break;
- case 0x0002:
- chr2_0(data, CHRROM);
- break;
- case 0x0003:
- chr2_2(data, CHRROM);
- break;
- case 0x2000:
- chr1_4(data, CHRROM);
- break;
- case 0x2001:
- chr1_5(data, CHRROM);
- break;
- case 0x2002:
- chr1_6(data, CHRROM);
- break;
- case 0x2003:
- chr1_7(data, CHRROM);
- break;
- }
-}
-
-/*************************************************************
-
- Taito TC0190FMC + PAL16R4 board emulation
-
- Games: Bakushou!! Jinsei Gekijou 3, Bubble Bobble 2,
- Captain Saver, Don Doko Don 2, Flintstones, Jetsons
-
- This is basically Mapper 33 + IRQ. Notably, IRQ works the
- same as MMC3 irq, BUT latch values are "inverted" (XOR'ed
- with 0xff) and there is a little delay (not implemented yet)
- We simply use MMC3 IRQ and XOR the value written in the
- register 0xc000 below
-
- iNES: mapper 48
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::tc0190fmc_p16_w)
-{
- LOG_MMC(("tc0190fmc_p16_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7003)
- {
- case 0x0000:
- prg8_89(data);
- break;
- case 0x0001:
- case 0x0002:
- case 0x0003:
- case 0x2000:
- case 0x2001:
- case 0x2002:
- case 0x2003:
- tc0190fmc_w(space, offset, data, mem_mask);
- break;
- case 0x4000:
- m_IRQ_count_latch = (0x100 - data) & 0xff;
- break;
- case 0x4001:
- m_IRQ_count = m_IRQ_count_latch;
- break;
- case 0x4002:
- m_IRQ_enable = 1;
- break;
- case 0x4003:
- m_IRQ_enable = 0;
- break;
- case 0x6000:
- set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- }
-}
-
-/*************************************************************
-
- Taito X1-005 board emulation
-
- Actually, Fudou Myouou Den uses a variant of the board with
- CIRAM, making necessary two distinct mappers & pcb_id.
-
- Also, we miss to emulate the security check at 0x7ef8 / 0x7ef9
- and the 0x80 ram!
-
- iNES: mappers 80 & 207
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::x1005_m_w)
-{
- LOG_MMC(("x1005_m_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x1ef0:
- chr2_0((data & 0x7f) >> 1, CHRROM);
- break;
- case 0x1ef1:
- chr2_2((data & 0x7f) >> 1, CHRROM);
- break;
- case 0x1ef2:
- chr1_4(data, CHRROM);
- break;
- case 0x1ef3:
- chr1_5(data, CHRROM);
- break;
- case 0x1ef4:
- chr1_6(data, CHRROM);
- break;
- case 0x1ef5:
- chr1_7(data, CHRROM);
- break;
- case 0x1ef6:
- case 0x1ef7:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- break;
- case 0x1ef8:
- case 0x1ef9:
- m_mmc_latch1 = data;
- break;
- case 0x1efa:
- case 0x1efb:
- prg8_89(data);
- break;
- case 0x1efc:
- case 0x1efd:
- prg8_ab(data);
- break;
- case 0x1efe:
- case 0x1eff:
- prg8_cd(data);
- break;
- default:
- logerror("mapper80_m_w uncaught addr: %04x, value: %02x\n", offset + 0x6000, data);
- break;
- }
-
- if (offset >= 0x1f00 && m_mapper_ram != NULL && m_mmc_latch1 == 0xa3)
- m_mapper_ram[offset & (m_mapper_ram_size - 1)] = data;
- else if (offset >= 0x1f00 && m_mapper_bram != NULL && m_mmc_latch1 == 0xa3)
- m_mapper_bram[offset & (m_mapper_bram_size - 1)] = data;
-}
-
-READ8_MEMBER(nes_carts_state::x1005_m_r)
-{
- LOG_MMC(("x1005a_m_r, offset: %04x\n", offset));
-
- if (offset >= 0x1f00 && m_mapper_ram != NULL && m_mmc_latch1 == 0xa3)
- return m_mapper_ram[offset & (m_mapper_ram_size - 1)];
- else if (offset >= 0x1f00 && m_mapper_bram != NULL && m_mmc_latch1 == 0xa3)
- return m_mapper_bram[offset & (m_mapper_bram_size - 1)];
-
- return 0xff;
-}
-
-WRITE8_MEMBER(nes_carts_state::x1005a_m_w)
-{
- LOG_MMC(("x1005a_m_w, offset: %04x, data: %02x\n", offset, data));
-
- // similar to x1005_m_w but mirroring is handled differently
- if (offset == 0x1ef6 || offset == 0x1ef7)
- return;
-
- switch (offset)
- {
- case 0x1ef0:
- set_nt_page(0, CIRAM, (data & 0x80) ? 1 : 0, 1);
- set_nt_page(1, CIRAM, (data & 0x80) ? 1 : 0, 1);
- break;
- case 0x1ef1:
- set_nt_page(2, CIRAM, (data & 0x80) ? 1 : 0, 1);
- set_nt_page(3, CIRAM, (data & 0x80) ? 1 : 0, 1);
- break;
- }
-
- x1005_m_w(space, offset, data, mem_mask);
-}
-
-/*************************************************************
-
- Taito X1-017 board emulation
-
- We miss to emulate the security check at 0x6000-0x73ff
- and the ram!
-
- Games: Kyuukyoku Harikiri Koushien, Kyuukyoku Harikiri
- Stadium, SD Keiji - Blader
-
- iNES: mapper 82
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void x1017_set_chr( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (state->m_mmc_latch1)
- {
- state->chr2_4(state->m_mmc_vrom_bank[0] >> 1, CHRROM);
- state->chr2_6(state->m_mmc_vrom_bank[1] >> 1, CHRROM);
- }
- else
- {
- state->chr2_0(state->m_mmc_vrom_bank[0] >> 1, CHRROM);
- state->chr2_2(state->m_mmc_vrom_bank[1] >> 1, CHRROM);
- }
- state->chr1_x(4 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[2], CHRROM);
- state->chr1_x(5 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[3], CHRROM);
- state->chr1_x(6 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[4], CHRROM);
- state->chr1_x(7 ^ state->m_mmc_latch1, state->m_mmc_vrom_bank[5], CHRROM);
-}
-
-WRITE8_MEMBER(nes_carts_state::x1017_m_w)
-{
- UINT8 reg = offset & 0x07;
- LOG_MMC(("x1017_m_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x1ef0:
- case 0x1ef1:
- if (m_mmc_vrom_bank[reg] != data)
- {
- m_mmc_vrom_bank[reg] = data;
- x1017_set_chr(machine());
- }
- break;
- case 0x1ef2:
- case 0x1ef3:
- case 0x1ef4:
- case 0x1ef5:
- if (m_mmc_vrom_bank[reg] != data)
- {
- m_mmc_vrom_bank[reg] = data;
- x1017_set_chr(machine());
- }
- break;
- case 0x1ef6:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- m_mmc_latch1 = ((data & 0x02) << 1);
- x1017_set_chr(machine());
- break;
- case 0x1ef7:
- case 0x1ef8:
- case 0x1ef9:
- m_mmc_reg[(offset & 0x0f) - 7] = data;
- break;
- case 0x1efa:
- prg8_89(data >> 2);
- break;
- case 0x1efb:
- prg8_ab(data >> 2);
- break;
- case 0x1efc:
- prg8_cd(data >> 2);
- break;
- default:
- logerror("x1017_m_w uncaught write, addr: %04x, value: %02x\n", offset + 0x6000, data);
- break;
- }
-}
-
-READ8_MEMBER(nes_carts_state::x1017_m_r)
-{
- LOG_MMC(("x1017_m_r, offset: %04x\n", offset));
-
- // 2+2+1 KB of Internal RAM can be independently enabled/disabled!
- if (offset < 0x0800 && m_mapper_bram != NULL && m_mmc_reg[0] == 0xca)
- return m_mapper_bram[offset & (m_mapper_bram_size - 1)];
- if (offset < 0x1000 && m_mapper_bram != NULL && m_mmc_reg[1] == 0x69)
- return m_mapper_bram[offset & (m_mapper_bram_size - 1)];
- if (offset < 0x1800 && m_mapper_bram != NULL && m_mmc_reg[2] == 0x84)
- return m_mapper_bram[offset & (m_mapper_bram_size - 1)];
-
- return 0xff;
-}
-
-/*************************************************************
-
- MISC UNLICENSED BOARDS
-
- *************************************************************/
-
-/*************************************************************
-
- AGCI 50282 bootleg board emulation
-
- Games: Death Race
-
- iNES: mapper 144
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::agci_50282_w)
-{
- LOG_MMC(("agci_50282_w, offset: %04x, data: %02x\n", offset, data));
-
- offset += 0x8000;
- data |= (space.read_byte(offset) & 1);
-
- chr8(data >> 4, CHRROM);
- prg32(data);
-}
-
-/*************************************************************
-
- AVE NINA-001 board emulation
-
- iNES: mapper 34
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::nina01_m_w)
-{
- LOG_MMC(("nina01_m_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x1ffd:
- prg32(data);
- break;
- case 0x1ffe:
- chr4_0(data, CHRROM);
- break;
- case 0x1fff:
- chr4_4(data, CHRROM);
- break;
- }
-}
-
-/*************************************************************
-
- AVE NINA-003, NINA-006 and MB-91 boards emulation
-
- Games: Krazy Kreatures, Poke Block, Puzzle, Pyramid,
- Solitaire, Ultimate League Soccer
-
- iNES: mapper 79
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::nina06_l_w)
-{
- LOG_MMC(("nina06_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!(offset & 0x0100))
- {
- prg32(data >> 3);
- chr8(data, CHRROM);
- }
-}
-
-/*************************************************************
-
- Active Entertainment Action 52 board emulation
-
- iNES: mapper 228
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::ae_act52_w)
-{
- int pbank, cbank;
- UINT8 pmode;
- LOG_MMC(("ae_act52_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(offset, 13) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- cbank = (data & 0x03) | ((offset & 0x0f) << 2);
- chr8(cbank, CHRROM);
-
- pmode = offset & 0x20;
- pbank = (offset & 0x1fc0) >> 6;
- if (pmode)
- {
- prg16_89ab(pbank);
- prg16_cdef(pbank);
- }
- else
- prg32(pbank >> 1);
-}
-
-
-/*************************************************************
-
- C & E Bootleg Board for Decathlon
-
- Games: Decathlon
-
- Pretty simple mapper: writes to 0x8065-0x80a4 set prg32 to
- data & 3; writes to 0x80a5-0x80e4 set chr8 to data & 7
-
- iNES: mapper 244
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::cne_decathl_w)
-{
- LOG_MMC(("cne_decathl_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x0065)
- return;
- if (offset < 0x00a5)
- {
- prg32((offset - 0x0065) & 0x03);
- return;
- }
- if (offset < 0x00e5)
- {
- chr8((offset - 0x00a5) & 0x07, CHRROM);
- }
-}
-
-/*************************************************************
-
- C & E Bootleg Board for Fong Shen Bang
-
- Games: Fong Shen Bang - Zhu Lu Zhi Zhan
-
- Simple mapper: writes to 0x6000-0x67ff set PRG and CHR banks.
- Namely, 0x6000->0x6003 select resp. prg8_89, prg8_ab, prg8_cd
- and prg8_ef. 0x6004->0x6007 select resp. crh2_0, chr2_2,
- chr2_4 and chr2_6. In 0x6800-0x7fff lies WRAM.
-
- iNES: mapper 246
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::cne_fsb_m_w)
-{
- LOG_MMC(("cne_fsb_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x0800)
- {
- switch (offset & 0x0007)
- {
- case 0x0000:
- prg8_89(data);
- break;
- case 0x0001:
- prg8_ab(data);
- break;
- case 0x0002:
- prg8_cd(data);
- break;
- case 0x0003:
- prg8_ef(data);
- break;
- case 0x0004:
- chr2_0(data, CHRROM);
- break;
- case 0x0005:
- chr2_2(data, CHRROM);
- break;
- case 0x0006:
- chr2_4(data, CHRROM);
- break;
- case 0x0007:
- chr2_6(data, CHRROM);
- break;
- }
- }
- else
- m_battery_ram[offset] = data;
-}
-
-/*************************************************************
-
- C & E Bootleg Board for Sheng Huo Lie Zhuan
-
- Games: Jing Ke Xin Zhuan, Sheng Huo Lie Zhuan
-
- Simple Mapper: writes to 0x4020-0x5fff sets prg32 to
- data>>4 and chr8 to data&f. We currently do not map
- writes to 0x4020-0x40ff (to do: verify if this produces
- issues)
-
- iNES: mapper 240
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::cne_shlz_l_w)
-{
- LOG_MMC(("cne_shlz_l_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data >> 4);
- chr8(data & 0x0f, CHRROM);
-}
-
-/*************************************************************
-
- Caltron 6 in 1 Board
-
- Games: 6 in 1 by Caltron
-
- iNES: mapper 41
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::caltron6in1_m_w)
-{
- LOG_MMC(("caltron6in1_m_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_latch1 = offset & 0xff;
- set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- prg32(offset & 0x07);
-}
-
-WRITE8_MEMBER(nes_carts_state::caltron6in1_w)
-{
- LOG_MMC(("caltron6in1_w, offset: %04x, data: %02x\n", offset, data));
-
- if (m_mmc_latch1 & 0x04)
- chr8(((m_mmc_latch1 & 0x18) >> 1) | (data & 0x03), CHRROM);
-}
-
-/*************************************************************
-
- Camerica Boards (BF9093, BF9097, BF909X, ALGNV11)
-
- Games: Linus Spacehead's Cosmic Crusade, Micro Machines,
- Mig-29, Stunt Kids
-
- To emulate NT mirroring for BF9097 board (missing in BF9093)
- we use crc_hack, however Fire Hawk is broken (but without
- mirroring there would be no helicopter graphics).
-
- iNES: mapper 71
-
- In MESS: Partially Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bf9093_w)
-{
- LOG_MMC(("bf9093_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- case 0x1000:
- if (!m_hard_mirroring)
- set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- break;
- case 0x4000:
- case 0x5000:
- case 0x6000:
- case 0x7000:
- prg16_89ab(data);
- break;
- }
-}
-
-/*************************************************************
-
- Camerica BF9096 & ALGQV11 Boards
-
- Games: Quattro Adventure, Quattro Arcade, Quattro Sports
-
- Writes to 0x8000-0x9fff set prg block to (data&0x18)>>1,
- writes to 0xa000-0xbfff set prg page to data&3. selected
- prg are: prg16_89ab = block|page, prg_cdef = 3|page.
- For more info on the hardware to bypass the NES lockout, see
- Kevtris' Camerica Mappers documentation.
-
- iNES: mapper 232
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void bf9096_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->prg16_89ab((state->m_mmc_latch2 & 0x03) | ((state->m_mmc_latch1 & 0x18) >> 1));
- state->prg16_cdef(0x03 | ((state->m_mmc_latch1 & 0x18) >> 1));
-}
-
-WRITE8_MEMBER(nes_carts_state::bf9096_w)
-{
- LOG_MMC(("bf9096_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x2000)
- m_mmc_latch1 = data;
- else
- m_mmc_latch2 = data;
-
- bf9096_set_prg(machine());
-}
-
-/*************************************************************
-
- Camerica Golden Five board
-
- Games: Pegasus 5 in 1
-
- iNES: mapper 104
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::golden5_w)
-{
- LOG_MMC(("golden5_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x4000)
- {
- if (data & 0x08)
- {
- m_mmc_prg_bank[0] = ((data & 0x07) << 4) | (m_mmc_prg_bank[0] & 0x0f);
- prg16_89ab(m_mmc_prg_bank[0]);
- prg16_cdef(((data & 0x07) << 4) | 0x0f);
- }
-
- }
- else
- {
- m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0x70) | (data & 0x0f);
- prg16_89ab(m_mmc_prg_bank[0]);
- }
-}
-
-/*************************************************************
-
- Cony Bootleg Board
-
- Games: Dragon Ball Party, Fatal Fury 2, Street Blaster II
- Pro, World Heroes 2
-
- iNES: mapper 83
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::cony_l_w)
-{
- LOG_MMC(("cony_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff
- m_mapper83_low_reg[offset & 0x03] = data;
-}
-
-READ8_MEMBER(nes_carts_state::cony_l_r)
-{
- LOG_MMC(("cony_l_r, offset: %04x\n", offset));
-
- if (offset == 0x0f00) // 0x5000
- {
- // read dipswitch bit! - currently unimplemented
- }
- if (offset >= 0x1000 && offset < 0x1103) // from 0x5100-0x51ff
- return m_mapper83_low_reg[offset & 0x03];
- else
- return 0x00;
-}
-
-static void cony_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->prg16_89ab(state->m_mapper83_reg[8] & 0x3f);
- state->prg16_cdef((state->m_mapper83_reg[8] & 0x30) | 0x0f);
-}
-
-static void cony_set_chr( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- // FIXME: here we emulate at least 3 different boards!!!
- // one board switches 1k VROM banks only
- // one writes to 0x8000 and then switches 2k VROM banks only
- // one writes to 0x831n (n=2,3,4,5) and then switches 2k VROM banks only
- // we should split them and possibly document the proper behavior of each variant
- if (state->m_mmc_latch1 && !state->m_mmc_latch2)
- {
- state->chr2_0(state->m_mapper83_reg[0], CHRROM);
- state->chr2_2(state->m_mapper83_reg[1], CHRROM);
- state->chr2_4(state->m_mapper83_reg[6], CHRROM);
- state->chr2_6(state->m_mapper83_reg[7], CHRROM);
- }
- else
- {
- state->chr1_0(state->m_mapper83_reg[0] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
- state->chr1_1(state->m_mapper83_reg[1] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
- state->chr1_2(state->m_mapper83_reg[2] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
- state->chr1_3(state->m_mapper83_reg[3] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
- state->chr1_4(state->m_mapper83_reg[4] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
- state->chr1_5(state->m_mapper83_reg[5] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
- state->chr1_6(state->m_mapper83_reg[6] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
- state->chr1_7(state->m_mapper83_reg[7] | ((state->m_mapper83_reg[8] & 0x30) << 4), CHRROM);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::cony_w)
-{
- LOG_MMC(("cony_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x0000:
- m_mmc_latch1 = 1;
- case 0x3000:
- case 0x30ff:
- case 0x31ff:
- m_mapper83_reg[8] = data;
- cony_set_prg(machine());
- cony_set_chr(machine());
- break;
- case 0x0100:
- m_mmc_reg[0] = data & 0x80;
- switch (data & 0x03)
- {
- case 0:
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- case 1:
- set_nt_mirroring(PPU_MIRROR_HORZ);
- break;
- case 2:
- set_nt_mirroring(PPU_MIRROR_LOW);
- break;
- case 3:
- set_nt_mirroring(PPU_MIRROR_HIGH);
- break;
- }
- break;
- case 0x0200:
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
- break;
- case 0x0201:
- m_IRQ_enable = m_mmc_reg[0];
- m_IRQ_count = (data << 8) | (m_IRQ_count & 0xff);
- break;
- case 0x0300:
- prg8_89(data);
- break;
- case 0x0301:
- prg8_ab(data);
- break;
- case 0x0302:
- prg8_cd(data);
- break;
- case 0x0312:
- case 0x0313:
- case 0x0314:
- case 0x0315:
- m_mmc_latch2 = 1;
- case 0x0310:
- case 0x0311:
- case 0x0316:
- case 0x0317:
- m_mapper83_reg[offset - 0x0310] = data;
- cony_set_chr(machine());
- break;
- case 0x0318:
- m_mapper83_reg[9] = data;
- cony_set_prg(machine());
- break;
- }
-}
-
-/*************************************************************
-
- Yoko Bootleg Board
-
- Games: Mortal Kombat II, Master Figther VI'
-
-
- Very similar to Cony board
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::yoko_l_w)
-{
- LOG_MMC(("cony_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset >= 0x1300) // from 0x5400
- m_mapper83_low_reg[offset & 0x03] = data;
-}
-
-READ8_MEMBER(nes_carts_state::yoko_l_r)
-{
- LOG_MMC(("cony_l_r, offset: %04x\n", offset));
-
- if (offset >= 0x0f00 && offset < 0x1300) // 0x5000
- {
- // read dipswitch bit! - currently unimplemented
- }
- if (offset >= 0x1300) // from 0x5400
- return m_mapper83_low_reg[offset & 0x03];
- else
- return 0x00;
-}
-
-static void yoko_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (state->m_mmc_reg[0] & 0x10)
- {
- int base = (state->m_mmc_reg[1] & 0x08) << 1;
- state->prg8_89(base | (state->m_mapper83_reg[0] & 0x0f));
- state->prg8_ab(base | (state->m_mapper83_reg[1] & 0x0f));
- state->prg8_cd(base | (state->m_mapper83_reg[2] & 0x0f));
- state->prg8_ef(base | 0x0f);
- }
- else if (state->m_mmc_reg[0] & 0x08)
- state->prg32(state->m_mmc_reg[1] >> 1);
- else
- {
- state->prg16_89ab(state->m_mmc_reg[1]);
- state->prg16_cdef(0xff);
- }
-}
-
-static void yoko_set_chr( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->chr2_0(state->m_mapper83_reg[4], CHRROM);
- state->chr2_2(state->m_mapper83_reg[5], CHRROM);
- state->chr2_4(state->m_mapper83_reg[6], CHRROM);
- state->chr2_6(state->m_mapper83_reg[7], CHRROM);
-}
-
-WRITE8_MEMBER(nes_carts_state::yoko_w)
-{
- LOG_MMC(("yoko_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x0c17)
- {
- case 0x0000:
- m_mmc_reg[1] = data;
- yoko_set_prg(machine());
- break;
- case 0x400:
- m_mmc_reg[0] = data;
- if (data & 1)
- set_nt_mirroring(PPU_MIRROR_HORZ);
- else
- set_nt_mirroring(PPU_MIRROR_VERT);
- yoko_set_prg(machine());
- break;
- case 0x0800:
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
- break;
- case 0x0801:
- m_IRQ_enable = m_mmc_reg[0] & 0x80;
- m_IRQ_count = (data << 8) | (m_IRQ_count & 0xff);
- break;
- case 0x0c00:
- case 0x0c01:
- case 0x0c02:
- m_mapper83_reg[offset & 3] = data;
- yoko_set_prg(machine());
- break;
- case 0x0c10:
- case 0x0c11:
- case 0x0c16:
- case 0x0c17:
- m_mapper83_reg[4 + (offset & 3)] = data;
- yoko_set_chr(machine());
- break;
- }
-}
-
-/*************************************************************
-
- Board DREAMTECH01
-
- Games: Korean Igo
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::dreamtech_l_w)
-{
- LOG_MMC(("dreamtech_l_w offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset == 0x1020) /* 0x5020 */
- prg16_89ab(data);
-}
-
-/*************************************************************
-
- Bootleg Board by Fukutake
-
- Games: Study Box
-
- iNES: mapper 186
-
- In MESS: Unsupported.
-
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::fukutake_l_w)
-{
- LOG_MMC(("fukutake_l_w offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset >= 0x200 && offset < 0x400)
- {
- if (offset & 1)
- prg16_89ab(data);
- else
- wram_bank(data >> 6, NES_WRAM);
- }
- else if (offset >= 0x400 && offset < 0xf00)
- m_mapper_ram[offset - 0x400] = data;
-}
-
-READ8_MEMBER(nes_carts_state::fukutake_l_r)
-{
- LOG_MMC(("fukutake_l_r offset: %04x\n", offset));
- offset += 0x100;
-
- if (offset >= 0x200 && offset < 0x400)
- {
- if (offset == 0x200 || offset == 0x201 || offset == 0x203)
- return 0x00;
- else if (offset == 0x202)
- return 0x40;
- else
- return 0xff;
- }
- else if (offset >= 0x400 && offset < 0xf00)
- return m_mapper_ram[offset - 0x400];
-
- return 0;
-}
-
-/*************************************************************
-
- Bootleg Board by Future Media
-
- Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun
-
- iNES: mapper 117
-
- In MESS: Unsupported.
-
- *************************************************************/
-
-void nes_state::futuremedia_irq( int scanline, int vblank, int blanked )
-{
- // if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
- {
- if (m_IRQ_enable && m_IRQ_count)
- {
- m_IRQ_count--;
- if (!m_IRQ_count)
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::futuremedia_w)
-{
- LOG_MMC(("futuremedia_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x0000:
- prg8_89(data);
- break;
- case 0x0001:
- prg8_ab(data);
- break;
- case 0x0002:
- prg8_cd(data);
- break;
- case 0x0003:
- prg8_ef(data);
- break;
- case 0x2000:
- case 0x2001:
- case 0x2002:
- case 0x2003:
- case 0x2004:
- case 0x2005:
- case 0x2006:
- case 0x2007:
- chr1_x(offset & 0x07, data, CHRROM);
- break;
-
- case 0x5000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- case 0x4001:
- m_IRQ_count_latch = data;
- break;
- case 0x4002:
- // IRQ cleared
- break;
- case 0x4003:
- m_IRQ_count = m_IRQ_count_latch;
- break;
- case 0x6000:
- m_IRQ_enable = data & 0x01;
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board 37017 (?) by Gouder
-
- Games: Street Fighter IV
-
- MMC3 clone. It also requires reads from 0x5000-0x7fff.
-
- iNES: mapper 208
-
- In MESS: Preliminary Support.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::gouder_sf4_l_w)
-{
- static const UINT8 conv_table[256] =
- {
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09,
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01,
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x49,0x19,0x09,0x59,0x49,0x19,0x09,
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x51,0x41,0x11,0x01,0x51,0x41,0x11,0x01,
- 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x10,0x40,0x50,0x00,0x10,0x40,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x08,0x18,0x48,0x58,0x08,0x18,0x48,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08,
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00,
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x58,0x48,0x18,0x08,0x58,0x48,0x18,0x08,
- 0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x59,0x50,0x40,0x10,0x00,0x50,0x40,0x10,0x00,
- 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x01,0x11,0x41,0x51,0x01,0x11,0x41,0x51,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x09,0x19,0x49,0x59,0x09,0x19,0x49,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
- };
-
- LOG_MMC(("gouder_sf4_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!(offset < 0x1700))
- m_mmc_reg[offset & 0x03] = data ^ conv_table[m_mmc_reg[4]];
- else if (!(offset < 0xf00))
- m_mmc_reg[4] = data;
- else if (!(offset < 0x700))
- prg32(((data >> 3) & 0x02) | (data & 0x01));
-}
-
-READ8_MEMBER(nes_carts_state::gouder_sf4_l_r)
-{
- LOG_MMC(("gouder_sf4_l_r, offset: %04x\n", offset));
-
- if (!(offset < 0x1700))
- return m_mmc_reg[offset & 0x03];
-
- return 0x00;
-}
-
-/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */
-static void gouder_sf4_prg_cb( running_machine &machine, int start, int bank )
-{
- return;
-}
-
-
-/*************************************************************
-
- Bootleg Board by Henggedianzi
-
- Games: Mei Guo Fu Hao, Shang Gu Shen Jian , Wang Zi Fu
- Chou Ji
-
- Writes to 0x8000-0xffff set prg32. Moreover, data&0x20 sets
- NT mirroring.
-
- iNES: mapper 177
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::henggedianzi_w)
-{
- LOG_MMC(("henggedianzi_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data);
- set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-}
-
-/*************************************************************
-
- Bootleg Board by Henggedianzi
-
- Games: Xing He Zhan Shi
-
- Writes to 0x5000-0x5fff set prg32 banks, writes to 0x8000-
- 0xffff set NT mirroring
-
- iNES: mapper 179
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::heng_xjzb_l_w)
-{
- LOG_MMC(("heng_xjzb_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x4100;
-
- if (offset & 0x5000)
- prg32(data >> 1);
-}
-
-WRITE8_MEMBER(nes_carts_state::heng_xjzb_w)
-{
- LOG_MMC(("heng_xjzb_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-}
-
-/*************************************************************
-
- Bootleg Board by HES (also used by others)
-
- Games: AV Hanafuda Club, AV Soccer, Papillon, Sidewinder,
- Total Funpack
-
- Actually, two variant: one for HES 6-in-1 with mirroring control
- and one for AV Soccer and others with hardwired mirroring
-
- iNES: mapper 113
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::hes6in1_l_w)
-{
- LOG_MMC(("hes6in1_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!(offset & 0x100))
- {
- prg32((data & 0x38) >> 3);
- chr8((data & 0x07) | ((data & 0x40) >> 3), CHRROM);
- set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::hes_l_w)
-{
- LOG_MMC(("hes_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!(offset & 0x100))
- {
- prg32((data & 0x38) >> 3);
- chr8((data & 0x07) | ((data & 0x40) >> 3), CHRROM);
- }
-}
-
-/*************************************************************
-
- Bootleg Board by Hosenkan
-
- Games: Pocahontas, Super Donkey Kong
-
- iNES: mapper 182
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::hosenkan_w)
-{
- LOG_MMC(("hosenkan_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7003)
- {
- case 0x0001:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 0x2000:
- m_mmc_latch1 = data;
- break;
- case 0x4000:
- switch (m_mmc_latch1)
- {
- case 0:
- chr2_0(data >> 1, CHRROM);
- break;
- case 1:
- chr1_5(data, CHRROM);
- break;
- case 2:
- chr2_2(data >> 1, CHRROM);
- break;
- case 3:
- chr1_7(data, CHRROM);
- break;
- case 4:
- prg8_89(data);
- break;
- case 5:
- prg8_ab(data);
- break;
- case 6:
- chr1_4(data, CHRROM);
- break;
- case 7:
- chr1_6(data, CHRROM);
- break;
- }
- break;
- case 0x6003:
- if (data)
- {
- m_IRQ_count = data;
- m_IRQ_enable = 1;
- }
- else
- m_IRQ_enable = 0;
- break;
- }
-}
-
-/*************************************************************
-
- Kaiser Board KS7058
-
- Games: Tui Do Woo Ma Jeung
-
- Writes to 0xf000-0xffff set 4k chr banks. Namely, if
- offset&0x80 is 0 the lower 4k are set, if it is 1 the
- upper 4k are set.
-
- iNES: mapper 171
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::ks7058_w)
-{
- LOG_MMC(("ks7058_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7080)
- {
- case 0x7000:
- chr4_0(data, CHRROM);
- break;
- case 0x7080:
- chr4_4(data, CHRROM);
- break;
- }
-}
-
-/*************************************************************
-
- Kaiser Board KS7022
-
- Games: 15 in 1
-
- iNES: mapper 175
-
- In MESS: Supported?
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::ks7022_w)
-{
- LOG_MMC(("ks7022_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset == 0)
- set_nt_mirroring(BIT(data, 2) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- if (offset == 0x2000)
- m_mmc_latch1 = data & 0x0f;
-}
-
-READ8_MEMBER(nes_carts_state::ks7022_r)
-{
- LOG_MMC(("ks7022_r, offset: %04x\n", offset));
-
- if (offset == 0x7ffc)
- {
- chr8(m_mmc_latch1, CHRROM);
- prg16_89ab(m_mmc_latch1);
- prg16_cdef(m_mmc_latch1);
- }
-
- return mmc_hi_access_rom(machine(), offset);
-}
-
-/*************************************************************
-
- Kaiser Board KS7032
-
- Games:
-
- iNES:
-
- In MESS:
-
- *************************************************************/
-
-static void ks7032_prg_update( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- state->prg8_67(state->m_mmc_reg[4]);
- state->prg8_89(state->m_mmc_reg[1]);
- state->prg8_ab(state->m_mmc_reg[2]);
- state->prg8_cd(state->m_mmc_reg[3]);
-}
-
-void nes_state::ks7032_irq( int scanline, int vblank, int blanked )
-{
- if (m_IRQ_enable)
- {
- if (m_IRQ_count >= (0xffff - 114))
- {
- m_IRQ_enable = 0;
- m_IRQ_count = m_IRQ_count_latch;
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- else
- m_IRQ_count += 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::ks7032_w)
-{
- LOG_MMC(("ks7032_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- m_IRQ_count = (m_IRQ_count & 0xfff0) | (data & 0x0f);
- break;
- case 0x1000:
- m_IRQ_count = (m_IRQ_count & 0xff0f) | ((data & 0x0f) << 4);
- break;
- case 0x2000:
- m_IRQ_count = (m_IRQ_count & 0xf0ff) | ((data & 0x0f) << 8);
- break;
- case 0x3000:
- m_IRQ_count = (m_IRQ_count & 0x0fff) | ((data & 0x0f) << 12);
- break;
- case 0x4000:
- m_IRQ_enable = 1;
- break;
- case 0x6000:
- m_mmc_latch1 = data & 0x07;
- break;
- case 0x7000:
- m_mmc_reg[m_mmc_latch1] = data;
- ks7032_prg_update(machine());
- break;
- }
-}
-
-/*************************************************************
-
- Kaiser Board KS202
-
- Games:
-
- iNES:
-
- In MESS: Supported?
-
- *************************************************************/
-
-
-WRITE8_MEMBER(nes_carts_state::ks202_w)
-{
- LOG_MMC(("ks202_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- m_IRQ_count = (m_IRQ_count & 0xfff0) | (data & 0x0f);
- break;
- case 0x1000:
- m_IRQ_count = (m_IRQ_count & 0xff0f) | ((data & 0x0f) << 4);
- break;
- case 0x2000:
- m_IRQ_count = (m_IRQ_count & 0xf0ff) | ((data & 0x0f) << 8);
- break;
- case 0x3000:
- m_IRQ_count = (m_IRQ_count & 0x0fff) | ((data & 0x0f) << 12);
- break;
- case 0x4000:
- m_IRQ_enable = 1;
- break;
- case 0x6000:
- m_mmc_latch1 = data & 0x07;
- break;
- case 0x7000:
- m_mmc_reg[m_mmc_latch1] = data;
- ks7032_prg_update(machine());
- switch (offset & 0xc00)
- {
- case 0x800:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- break;
- case 0xc00:
- chr1_x(offset & 0x07, data, CHRROM);
- break;
- }
- break;
- }
-}
-
-/*************************************************************
-
- Kaiser Board KS7017
-
- Games:
-
- iNES:
-
- In MESS: Not working
-
- *************************************************************/
-
-void nes_state::mmc_fds_irq( int scanline, int vblank, int blanked )
-{
- if (m_IRQ_enable)
- {
- if (m_IRQ_count <= 114)
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_enable = 0;
- m_IRQ_status |= 0x01;
- }
- else
- m_IRQ_count -= 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::ks7017_l_w)
-{
- LOG_MMC(("ks7022_w, offset: %04x, data: %02x\n", offset, data));
-
- offset += 0x100;
-
- if (offset >= 0xa00 && offset < 0xb00)
- m_mmc_latch1 = ((offset >> 2) & 0x03) | ((offset >> 4) & 0x04);
-
- if (offset >= 0x1000 && offset < 0x1100)
- prg16_89ab(m_mmc_latch1);
-}
-
-WRITE8_MEMBER(nes_carts_state::ks7017_extra_w)
-{
- LOG_MMC(("ks7017_extra_w, offset: %04x, data: %02x\n", offset, data));
-
- offset += 0x20;
-
- if (offset == 0x0020) /* 0x4020 */
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
-
- if (offset == 0x0021) /* 0x4021 */
- m_IRQ_count = (m_IRQ_count & 0x00ff) | (data << 8);
-
- if (offset == 0x0025) /* 0x4025 */
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-}
-
-READ8_MEMBER(nes_carts_state::ks7017_extra_r)
-{
- LOG_MMC(("ks7017_extra_r, offset: %04x\n", offset));
-
- m_IRQ_status &= ~0x01;
- return m_IRQ_status;
-}
-
-/*************************************************************
-
- Bootleg Board by Kay (for Panda Prince)
-
- Games: The Panda Prince, Sonic 3d Blast 6, SFZ2 '97, YuYu '97
- (and its title hack MK6), UMK3, Super Lion King 2
-
- MMC3 clone. This is basically KOF96 board + protection
-
- iNES: mapper 121
-
- In MESS: Most game works, with some graphical issues.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::kay_pp_l_w)
-{
- LOG_MMC(("kay_pp_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset >= 0x1000)
- {
- switch (data & 0x03)
- {
- case 0x00:
- case 0x01:
- m_mmc_reg[0] = 0x83;
- break;
- case 0x02:
- m_mmc_reg[0] = 0x42;
- break;
- case 0x03:
- m_mmc_reg[0] = 0x00;
- break;
- }
- }
-}
-
-READ8_MEMBER(nes_carts_state::kay_pp_l_r)
-{
- LOG_MMC(("kay_pp_l_r, offset: %04x\n", offset));
- offset += 0x100;
-
- if (offset >= 0x1000)
- return m_mmc_reg[0];
- else
- return 0xff;
-}
-
-static void kay_pp_update_regs( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- switch (state->m_mmc_reg[5] & 0x3f)
- {
- case 0x20:
- case 0x29:
- case 0x2b:
- case 0x3f:
- state->m_mmc_reg[7] = 1;
- state->m_mmc_reg[1] = state->m_mmc_reg[6];
- break;
- case 0x26:
- state->m_mmc_reg[7] = 0;
- state->m_mmc_reg[1] = state->m_mmc_reg[6];
- break;
- case 0x2c:
- state->m_mmc_reg[7] = 1;
- if (state->m_mmc_reg[6])
- state->m_mmc_reg[1] = state->m_mmc_reg[6];
- break;
-
- case 0x28:
- state->m_mmc_reg[7] = 0;
- state->m_mmc_reg[2] = state->m_mmc_reg[6];
- break;
-
- case 0x2a:
- state->m_mmc_reg[7] = 0;
- state->m_mmc_reg[3] = state->m_mmc_reg[6];
- break;
-
- case 0x2f:
- break;
-
- default:
- state->m_mmc_reg[5] = 0;
- break;
- }
-}
-
-static void kay_pp_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (state->m_mmc_reg[5] & 0x3f)
- {
- state->prg8_x(start, bank & 0x3f);
- state->prg8_ef(state->m_mmc_reg[1]);
- state->prg8_cd(state->m_mmc_reg[2]);
- state->prg8_ab(state->m_mmc_reg[3]);
- }
- else
- state->prg8_x(start, bank & 0x3f);
-}
-
-static void kay_pp_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5;
-
- if ((start & 0x04) == chr_page)
- bank |= 0x100;
-
- state->chr1_x(start, bank, source);
-}
-
-WRITE8_MEMBER(nes_carts_state::kay_pp_w)
-{
- LOG_MMC(("kay_pp_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6003)
- {
- case 0x0000:
- txrom_w(space, offset, data, mem_mask);
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
-
- case 0x0001:
- m_mmc_reg[6] = (BIT(data, 0) << 5) | (BIT(data, 1) << 4) | (BIT(data, 2) << 3)
- | (BIT(data, 3) << 2) | (BIT(data, 4) << 1) | BIT(data, 5);
- if (!m_mmc_reg[7])
- kay_pp_update_regs(machine());
- txrom_w(space, offset, data, mem_mask);
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
-
- case 0x0003:
- m_mmc_reg[5] = data;
- kay_pp_update_regs(machine());
- txrom_w(space, 0x0000, data, mem_mask);
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board by Kasing
-
- Games: AV Jiu Ji Mahjong, Bao Qing Tian, Thunderbolt 2,
- Shisen Mahjong 2
-
- MMC3 clone
-
- iNES: mapper 115
-
- In MESS: Supported
-
- *************************************************************/
-
-static void kasing_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (BIT(state->m_mmc_reg[0], 7))
- state->prg32(state->m_mmc_reg[0] >> 1);
- else
- state->prg8_x(start, bank);
-}
-
-WRITE8_MEMBER(nes_carts_state::kasing_m_w)
-{
- LOG_MMC(("kasing_m_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x01)
- {
- case 0x00:
- m_mmc_reg[0] = data;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- case 0x01:
- m_mmc_chr_base = (data & 0x01) ? 0x100 : 0x000;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board by Magic Series
-
- Games: Magic Dragon
-
- Very simple mapper: writes to 0x8000-0xffff set prg32 and chr8
- banks
-
- iNES: mapper 107
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::magics_md_w)
-{
- LOG_MMC(("magics_md_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data >> 1);
- chr8(data, CHRROM);
-}
-
-/*************************************************************
-
- Bootleg Board by Nanjing
-
- Games: A lot of pirate originals
-
- iNES: mapper 163
-
- In MESS: Unsupported.
-
- *************************************************************/
-
-void nes_state::nanjing_irq( int scanline, int vblank, int blanked )
-{
- if (BIT(m_mmc_reg[0], 7))
- {
- if (scanline == 127)
- {
- chr4_0(1, CHRRAM);
- chr4_4(1, CHRRAM);
- }
-
- if (scanline == 239)
- {
- chr4_0(0, CHRRAM);
- chr4_4(0, CHRRAM);
- }
- }
-
-}
-
-WRITE8_MEMBER(nes_carts_state::nanjing_l_w)
-{
- LOG_MMC(("nanjing_l_w, offset: %04x, data: %02x\n", offset, data));
-
- offset += 0x100;
-
- if (offset < 0x1000)
- return;
-
- if (offset == 0x1100) // 0x5100
- {
- if (data == 6)
- prg32(3);
- return;
- }
-
- if (offset == 0x1101) // 0x5101
- {
- UINT8 temp = m_mmc_count;
- m_mmc_count = data;
-
- if (temp & !data)
- m_mmc_latch2 ^= 0xff;
- }
-
- switch (offset & 0x300)
- {
- case 0x000:
- case 0x200:
- m_mmc_reg[BIT(offset, 9)] = data;
- if (!BIT(m_mmc_reg[0], 7) && m_ppu->get_current_scanline() <= 127)
- chr8(0, CHRRAM);
- break;
- case 0x300:
- m_mmc_latch1 = data;
- break;
- }
-
- prg32((m_mmc_reg[0] & 0x0f) | ((m_mmc_reg[1] & 0x0f) << 4));
-}
-
-READ8_MEMBER(nes_carts_state::nanjing_l_r)
-{
- UINT8 value = 0;
- LOG_MMC(("nanjing_l_r, offset: %04x\n", offset));
-
- offset += 0x100;
-
- if (offset < 0x1000)
- return 0;
-
- switch (offset & 0x700)
- {
- case 0x100:
- value = m_mmc_latch1;
- break;
- case 0x500:
- value = m_mmc_latch2 & m_mmc_latch1;
- break;
- case 0x000:
- case 0x200:
- case 0x300:
- case 0x400:
- case 0x600:
- case 0x700:
- value = 4;
- break;
- }
- return value;
-}
-
-/*************************************************************
-
- Bootleg Board by Nitra
-
- Games: Time Diver Avenger
-
- This acts basically like a MMC3 with different use of write
- address.
-
- iNES: mapper 250
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::nitra_w)
-{
- LOG_MMC(("nitra_w, offset: %04x, data: %02x\n", offset, data));
-
- txrom_w(space, (offset & 0x6000) | ((offset & 0x400) >> 10), offset & 0xff, mem_mask);
-}
-
-/*************************************************************
-
- NTDEC ASDER Bootleg Board
-
- Games: Cobra Mission, Fighting Hero III, Huang Di, Master
- Shooter
-
- iNES: mapper 112
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::ntdec_asder_w)
-{
- LOG_MMC(("ntdec_asder_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x0000:
- m_mmc_latch1 = data & 0x07;
- break;
- case 0x2000:
- switch (m_mmc_latch1)
- {
- case 0:
- prg8_89(data);
- break;
- case 1:
- prg8_ab(data);
- break;
- case 2:
- data &= 0xfe;
- chr1_0(data, CHRROM);
- chr1_1(data + 1, CHRROM);
- break;
- case 3:
- data &= 0xfe;
- chr1_2(data, CHRROM);
- chr1_3(data + 1, CHRROM);
- break;
- case 4:
- chr1_4(data, CHRROM);
- break;
- case 5:
- chr1_5(data, CHRROM);
- break;
- case 6:
- chr1_6(data, CHRROM);
- break;
- case 7:
- chr1_7(data, CHRROM);
- break;
- }
- break;
- case 0x6000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board by NTDEC for Fighting Hero
-
- Games: Fighting Hero
-
- Very simple mapper: writes to 0x6000-0x7fff swap PRG and
- CHR banks.
-
- iNES: mapper 193
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::ntdec_fh_m_w)
-{
- LOG_MMC(("ntdec_fh_m_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x03)
- {
- case 0:
- chr4_0(data >> 2, CHRROM);
- break;
- case 1:
- chr2_4(data >> 1, CHRROM);
- break;
- case 2:
- chr2_6(data >> 1 , CHRROM);
- break;
- case 3:
- prg8_89(data);
- break;
- }
-}
-
-/*************************************************************
-
- Open Corp DAOU306 board
-
- Games: Metal Force (K)
-
- iNES: mapper 156
-
- In MESS: Supported.
-
- Notes: Metal Force and Buzz & Waldog only use the the first
- 4 regs and no mirroring. Janggun ui Adeul uses all features
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::daou306_w)
-{
- LOG_MMC(("daou306_w, offset: %04x, data: %02x\n", offset, data));
- int reg = BIT(offset, 2) ? 8 : 0;
-
- switch (offset)
- {
- case 0x4000:
- case 0x4004:
- m_mmc_reg[reg + 0] = data;
- chr1_0(m_mmc_reg[0] | (m_mmc_reg[8] << 8), CHRROM);
- break;
- case 0x4001:
- case 0x4005:
- m_mmc_reg[reg + 1] = data;
- chr1_1(m_mmc_reg[1] | (m_mmc_reg[9] << 8), CHRROM);
- break;
- case 0x4002:
- case 0x4006:
- m_mmc_reg[reg + 2] = data;
- chr1_2(m_mmc_reg[2] | (m_mmc_reg[10] << 8), CHRROM);
- break;
- case 0x4003:
- case 0x4007:
- m_mmc_reg[reg + 3] = data;
- chr1_3(m_mmc_reg[3] | (m_mmc_reg[11] << 8), CHRROM);
- break;
- case 0x4008:
- case 0x400c:
- m_mmc_reg[reg + 4] = data;
- chr1_4(m_mmc_reg[4] | (m_mmc_reg[12] << 8), CHRROM);
- break;
- case 0x4009:
- case 0x400d:
- m_mmc_reg[reg + 5] = data;
- chr1_5(m_mmc_reg[5] | (m_mmc_reg[13] << 8), CHRROM);
- break;
- case 0x400a:
- case 0x400e:
- m_mmc_reg[reg + 6] = data;
- chr1_6(m_mmc_reg[6] | (m_mmc_reg[14] << 8), CHRROM);
- break;
- case 0x400b:
- case 0x400f:
- m_mmc_reg[reg + 7] = data;
- chr1_7(m_mmc_reg[7] | (m_mmc_reg[15] << 8), CHRROM);
- break;
- case 0x4010:
- prg16_89ab(data);
- break;
- case 0x4014:
- if (data & 1)
- set_nt_mirroring(PPU_MIRROR_HORZ);
- else
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- }
-}
-
-/*************************************************************
-
- RCM GS2015 Board
-
- Games: Bonza, Magic Jewelry 2
-
- Very simple mapper: writes to 0x8000-0xffff sets prg32
- to offset and chr8 to offset>>1 (when chrrom is present)
-
- iNES: mapper 216
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::gs2015_w)
-{
- LOG_MMC(("gs2015_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(offset);
- chr8(offset >> 1, m_mmc_chr_source);
-}
-
-/*************************************************************
-
- Bootleg Board by RCM for Tetris Family
-
- Games: Tetris Family 9 in 1, 20 in 1
-
- Simple Mapper: prg/chr/nt are swapped depending on the offset
- of writes in 0x8000-0xffff. offset&0x80 set NT mirroring,
- when (offset&0x30) is 0,3 prg32 is set; when it is 1,2
- two 16k prg banks are set. See below for the values used in
- these banks.
-
- iNES: mapper 61
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::rcm_tf_w)
-{
- LOG_MMC(("rcm_tf_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x30)
- {
- case 0x00:
- case 0x30:
- prg32(offset & 0x0f);
- break;
- case 0x10:
- case 0x20:
- prg16_89ab(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4));
- prg16_cdef(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4));
- break;
- }
- set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-}
-
-/*************************************************************
-
- Bootleg Board by Rex Soft
-
- Games: Dragon Ball Z 5, Dragon Ball Z Super
-
- MMC3 clone
-
- iNES: mapper 12
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::rex_dbz_l_w)
-{
- LOG_MMC(("rex_dbz_l_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_reg[0] = data;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
-}
-
-/* we would need to use this read handler in 0x6000-0x7fff as well */
-READ8_MEMBER(nes_carts_state::rex_dbz_l_r)
-{
- LOG_MMC(("rex_dbz_l_r, offset: %04x\n", offset));
- return 0x01;
-}
-
-static void rex_dbz_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int shift = (start < 4) ? 8 : 4;
-
- bank |= ((state->m_mmc_reg[0] << shift) & 0x100);
- state->chr1_x(start, bank, source);
-}
-
-/*************************************************************
-
- Rex Soft SL1632 Board
-
- Games: Samurai Spirits
-
- MMC3 clone
-
- iNES: mapper 14
-
- In MESS: Supported
-
- *************************************************************/
-
-static void rex_sl1632_set_prg( running_machine &machine, int prg_base, int prg_mask )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (state->m_mmc_reg[0] & 0x02)
- {
- mmc3_set_prg(machine, prg_base, prg_mask);
- }
- else
- {
- state->prg8_89(state->m_mmc_extra_bank[0]);
- state->prg8_ab(state->m_mmc_extra_bank[1]);
- state->prg8_cd(state->m_mmc_extra_bank[2]);
- state->prg8_ef(state->m_mmc_extra_bank[3]);
- }
-}
-
-static void rex_sl1632_set_chr( running_machine &machine, UINT8 chr, int chr_base, int chr_mask )
-{
- nes_state *state = machine.driver_data<nes_state>();
- static const UINT8 conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1};
- UINT8 chr_page = (state->m_mmc3_latch & 0x80) >> 5;
- UINT8 bank[8];
- UINT8 chr_base2[8];
- int i;
-
- if (state->m_mmc_reg[0] & 0x02)
- {
- for(i = 0; i < 8; i++)
- {
- bank[i] = state->m_mmc_vrom_bank[i];
- chr_base2[i] = chr_base | ((state->m_mmc_reg[0] << conv_table[i]) & 0x100);
- }
- }
- else
- {
- for(i = 0; i < 8; i++)
- {
- bank[i] = state->m_mmc_extra_bank[i + 4]; // first 4 state->m_mmc_extra_banks are PRG
- chr_base2[i] = chr_base;
- }
- }
-
- state->chr1_x(chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr);
- state->chr1_x(chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr);
- state->chr1_x(chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr);
- state->chr1_x(chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr);
- state->chr1_x(chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr);
- state->chr1_x(chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr);
- state->chr1_x(chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr);
- state->chr1_x(chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr);
-}
-
-WRITE8_MEMBER(nes_carts_state::rex_sl1632_w)
-{
- UINT8 map14_helper1, map14_helper2, mmc_helper, cmd;
- LOG_MMC(("rex_sl1632_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset == 0x2131)
- {
- m_mmc_reg[0] = data;
- rex_sl1632_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- rex_sl1632_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
-
- if (!(m_mmc_reg[0] & 0x02))
- set_nt_mirroring(BIT(m_mmc_reg[1], 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- }
-
- if (m_mmc_reg[0] & 0x02)
- {
- switch (offset & 0x6001)
- {
- case 0x0000:
- mmc_helper = m_mmc3_latch ^ data;
- m_mmc3_latch = data;
-
- /* Has PRG Mode changed? */
- if (mmc_helper & 0x40)
- rex_sl1632_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- /* Has CHR Mode changed? */
- if (mmc_helper & 0x80)
- rex_sl1632_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
-
- case 0x0001:
- cmd = m_mmc3_latch & 0x07;
- switch (cmd)
- {
- case 0: case 1: // these have to be changed due to the different way rex_sl1632_set_chr works (it handles 1k banks)!
- m_mmc_vrom_bank[2 * cmd] = data;
- m_mmc_vrom_bank[2 * cmd + 1] = data;
- rex_sl1632_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
- case 2: case 3: case 4: case 5:
- m_mmc_vrom_bank[cmd + 2] = data;
- rex_sl1632_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
- case 6:
- case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- rex_sl1632_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- }
- break;
-
- case 0x2000:
- set_nt_mirroring(BIT(m_mmc_reg[1], 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
- }
- else if (offset >= 0x3000 && offset <= 0x6003 )
- {
- map14_helper1 = (offset & 0x01) << 2;
- offset = ((offset & 0x02) | (offset >> 10)) >> 1;
- map14_helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 m_mmc_extra_banks are for PRG!
- m_mmc_extra_bank[map14_helper2] = (m_mmc_extra_bank[map14_helper2] & (0xf0 >> map14_helper1)) | ((data & 0x0f) << map14_helper1);
- rex_sl1632_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
- else
- {
- switch (offset & 0x7003)
- {
- case 0x0000:
- case 0x2000:
- m_mmc_extra_bank[offset >> 13] = data;
- rex_sl1632_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
-
- case 0x1000:
- m_mmc_reg[1] = data;
- set_nt_mirroring(BIT(m_mmc_reg[1], 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- }
- }
-}
-
-/*************************************************************
-
- Rumblestation Board
-
- Games: Rumblestation 15 in 1
-
- iNES: mapper 46
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::rumblestation_m_w)
-{
- LOG_MMC(("rumblestation_m_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & 0x01) | ((data & 0x0f) << 1);
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & 0x07) | ((data & 0xf0) >> 1);
- prg32(m_mmc_prg_bank[0]);
- chr8(m_mmc_vrom_bank[0], CHRROM);
-}
-
-WRITE8_MEMBER(nes_carts_state::rumblestation_w)
-{
- LOG_MMC(("rumblestation_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_prg_bank[0] = (m_mmc_prg_bank[0] & ~0x01) | (data & 0x01);
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & ~0x07) | ((data & 0x70) >> 4);
- prg32(m_mmc_prg_bank[0]);
- chr8(m_mmc_vrom_bank[0], CHRROM);
-}
-
-/*************************************************************
-
- Sachen 74x374 bootleg boards
-
- Games: Chess Academy, Chinese Checkers Jpn, Mahjong Academy,
- Olympic IQ, Poker II, Tasac [150], Poker III [243]
-
- iNES: mappers 150 & 243
-
- *************************************************************/
-
-static void sachen_set_mirror( running_machine &machine, UINT8 nt ) // used by mappers 137, 138, 139, 141
-{
- nes_state *state = machine.driver_data<nes_state>();
- switch (nt)
- {
- case 0:
- case 1:
- state->set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 2:
- state->set_nt_page(0, CIRAM, 0, 1);
- state->set_nt_page(1, CIRAM, 1, 1);
- state->set_nt_page(2, CIRAM, 1, 1);
- state->set_nt_page(3, CIRAM, 1, 1);
- break;
- case 3:
- state->set_nt_mirroring(PPU_MIRROR_LOW);
- break;
- default:
- LOG_MMC(("Mapper set NT to invalid value %02x", nt));
- break;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::sachen_74x374_l_w)
-{
- LOG_MMC(("sachen_74x374_l_w, offset: %04x, data: %02x\n", offset, data));
-
- /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
- if (!(offset & 0x100))
- {
- if (!(offset & 0x01))
- m_mmc_latch1 = data & 0x07;
- else
- {
- switch (m_mmc_latch1)
- {
- case 0x02:
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & ~0x08) | ((data << 3) & 0x08);
- chr8(m_mmc_vrom_bank[0], CHRROM);
- prg32(data & 0x01);
- break;
- case 0x04:
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & ~0x04) | ((data << 2) & 0x04);
- chr8(m_mmc_vrom_bank[0], CHRROM);
- break;
- case 0x05:
- prg32(data & 0x07);
- break;
- case 0x06:
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & ~0x03) | ((data << 0) & 0x03);
- chr8(m_mmc_vrom_bank[0], CHRROM);
- break;
- case 0x07:
- sachen_set_mirror(machine(), (data >> 1) & 0x03);
- break;
- default:
- break;
- }
- }
- }
-}
-
-READ8_MEMBER(nes_carts_state::sachen_74x374_l_r)
-{
- LOG_MMC(("sachen_74x374_l_r, offset: %04x", offset));
-
- /* read happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
- if (!(offset & 0x100))
- return (~m_mmc_latch1 & 0x3f) /* ^ dips*/; // we would need to check the Dips here
- else
- return 0;
-}
-
-WRITE8_MEMBER(nes_carts_state::sachen_74x374a_l_w)
-{
- LOG_MMC(("sachen_74x374a_l_w, offset: %04x, data: %02x\n", offset, data));
-
- /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
- if (!(offset & 0x100))
- {
- if (!(offset & 0x01))
- m_mmc_latch1 = data;
- else
- {
- switch (m_mmc_latch1 & 0x07)
- {
- case 0x00:
- prg32(0);
- chr8(3, CHRROM);
- break;
- case 0x02:
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & ~0x08) | ((data << 3) & 0x08);
- chr8(m_mmc_vrom_bank[0], CHRROM);
- break;
- case 0x04:
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & ~0x01) | ((data << 0) & 0x01);
- chr8(m_mmc_vrom_bank[0], CHRROM);
- break;
- case 0x05:
- prg32(data & 0x01);
- break;
- case 0x06:
- m_mmc_vrom_bank[0] = (m_mmc_vrom_bank[0] & ~0x06) | ((data << 1) & 0x06);
- chr8(m_mmc_vrom_bank[0], CHRROM);
- break;
- case 0x07:
- sachen_set_mirror(machine(), BIT(data, 0));
- break;
- default:
- break;
- }
- }
- }
-}
-
-/*************************************************************
-
- Sachen S8259 bootleg boards
-
- iNES: mapper 141 (A), 138 (B), 139 (C), 137 (D)
-
- *************************************************************/
-
-static void common_s8259_write_handler( address_space &space, offs_t offset, UINT8 data, int board )
-{
- running_machine &machine = space.machine();
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 bank_helper1, bank_helper2, shift, add1, add2, add3;
-
- /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
- if (!(offset & 0x100))
- {
- if (!(offset & 0x01))
- state->m_mmc_latch1 = data & 0x07;
- else
- {
- state->m_sachen_reg[state->m_mmc_latch1] = data;
-
- switch (state->m_mmc_latch1)
- {
- case 0x05:
- state->prg32(data);
- break;
- case 0x07:
- sachen_set_mirror(machine, BIT(data, 0) ? 0 : (data >> 1) & 0x03);
- break;
- default:
- if (board == SACHEN_8259D)
- {
- if (state->m_mmc_chr_source == CHRROM)
- {
- state->chr1_0((state->m_sachen_reg[0] & 0x07), CHRROM);
- state->chr1_1((state->m_sachen_reg[1] & 0x07) | (state->m_sachen_reg[4] << 4 & 0x10), CHRROM);
- state->chr1_2((state->m_sachen_reg[2] & 0x07) | (state->m_sachen_reg[4] << 3 & 0x10), CHRROM);
- state->chr1_3((state->m_sachen_reg[3] & 0x07) | (state->m_sachen_reg[4] << 2 & 0x10) | (state->m_sachen_reg[6] << 3 & 0x08), CHRROM);
- }
- }
- else
- {
- bank_helper1 = state->m_sachen_reg[7] & 0x01;
- bank_helper2 = (state->m_sachen_reg[4] & 0x07) << 3;
- shift = (board == SACHEN_8259A) ? 1 : (board == SACHEN_8259C) ? 2 : 0;
- add1 = (board == SACHEN_8259B) ? 0 : 1;
- add2 = (board == SACHEN_8259C) ? 2 : 0;
- add3 = (board == SACHEN_8259A) ? 1 : (board == SACHEN_8259C) ? 3 : 0;
-
- if (state->m_mmc_chr_source == CHRROM)
- {
- state->chr2_0(((state->m_sachen_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << shift, CHRROM);
- state->chr2_2(((state->m_sachen_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << shift | add1, CHRROM);
- state->chr2_4(((state->m_sachen_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << shift | add2, CHRROM);
- state->chr2_6(((state->m_sachen_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << shift | add3, CHRROM);
- }
- }
- break;
- }
- }
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::s8259_l_w)
-{
- LOG_MMC(("s8259_w, type: %d, offset: %04x, data: %02x\n", m_pcb_id, offset, data));
-
- common_s8259_write_handler(space, offset, data, m_pcb_id);
-}
-
-WRITE8_MEMBER(nes_carts_state::s8259_m_w)
-{
- LOG_MMC(("s8259_w, type: %d, offset: %04x, data: %02x\n", m_pcb_id, offset, data));
-
- common_s8259_write_handler(space, (offset + 0x100) & 0xfff, data, m_pcb_id);
-}
-
-
-/*************************************************************
-
- Sachen SA009 bootleg boards
-
- Games: Pipe 5
-
- iNES: mapper 160
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sa009_l_w)
-{
- LOG_MMC(("sa009_l_w, offset: %04x, data: %02x\n", offset, data));
-
- chr8(data, m_mmc_chr_source);
-}
-
-/*************************************************************
-
- Sachen SA0036 bootleg boards
-
- Games: Taiwan Mahjong 16
-
- iNES: mapper 149
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sa0036_w)
-{
- LOG_MMC(("sa0036_w, offset: %04x, data: %02x\n", offset, data));
-
- chr8(data >> 7, CHRROM);
-}
-
-/*************************************************************
-
- Sachen SA0037 bootleg boards
-
- Games: Mahjong World, Shisen Mahjong
-
- iNES: mapper 148
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sa0037_w)
-{
- LOG_MMC(("sa0037_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data >> 3);
- chr8(data, CHRROM);
-}
-
-/*************************************************************
-
- Sachen SA72007 bootleg boards
-
- Games: Sidewinder
-
- iNES: mapper 145
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sa72007_l_w)
-{
- LOG_MMC(("sa72007_l_w, offset: %04x, data: %02x\n", offset, data));
-
- /* only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
- if (!(offset & 0x100))
- chr8(data >> 7, CHRROM);
-}
-
-/*************************************************************
-
- Sachen SA72008 bootleg boards
-
- Games: Jovial Race, Qi Wang
-
- iNES: mapper 133
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sa72008_l_w)
-{
- LOG_MMC(("sa72008_l_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data >> 2);
- chr8(data, CHRROM);
-}
-
-/*************************************************************
-
- Sachen TCA-01 bootleg boards
-
- iNES: mapper 143
-
- Games: Dancing Blocks, Magic Mathematic
-
- In MESS: Supported.
-
- *************************************************************/
-
-READ8_MEMBER(nes_carts_state::tca01_l_r)
-{
- LOG_MMC(("tca01_l_r, offset: %04x\n", offset));
-
- /* the address is read only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
- if (!(offset & 0x100))
- return (~offset & 0x3f) | 0x40;
- else
- return 0x00;
-}
-
-/*************************************************************
-
- Sachen TCU-01 bootleg boards
-
- Games: Challenge of the Dragon, Chinese Kungfu
-
- iNES: mapper 147
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::tcu01_l_w)
-{
- LOG_MMC(("tcu01_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if ((offset & 0x103) == 0x002)
- {
- prg32(((data >> 6) & 0x02) | ((data >> 2) & 0x01));
- chr8(data >> 3, CHRROM);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::tcu01_m_w)
-{
- LOG_MMC(("tcu01_m_w, offset: %04x, data: %02x\n", offset, data));
-
- tcu01_l_w(space, (offset + 0x100) & 0xfff, data, mem_mask);
-}
-
-WRITE8_MEMBER(nes_carts_state::tcu01_w)
-{
- LOG_MMC(("tcu01_w, offset: %04x, data: %02x\n", offset, data));
-
- tcu01_l_w(space, (offset + 0x100) & 0xfff, data, mem_mask);
-}
-
-/*************************************************************
-
- Sachen TCU-02 bootleg boards
-
- Games: Mei Loi Siu Ji
-
- iNES: mapper 136
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::tcu02_l_w)
-{
- LOG_MMC(("tcu02_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if ((offset & 0x103) == 0x002)
- {
- m_mmc_latch1 = (data & 0x30) | ((data + 3) & 0x0f);
- chr8(m_mmc_latch1, CHRROM);
- }
-}
-
-READ8_MEMBER(nes_carts_state::tcu02_l_r)
-{
- LOG_MMC(("tcu02_l_r, offset: %04x\n", offset));
-
- if ((offset & 0x103) == 0x000)
- return m_mmc_latch1 | 0x40;
- else
- return 0x00;
-}
-
-
-/*************************************************************
-
- Subor bootleg board Type 0
-
- iNES: mapper 167
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::subor0_w)
-{
- UINT8 subor_helper1, subor_helper2;
- LOG_MMC(("subor0_w, offset: %04x, data: %02x\n", offset, data));
-
- m_subor_reg[(offset >> 13) & 0x03] = data;
- subor_helper1 = ((m_subor_reg[0] ^ m_subor_reg[1]) << 1) & 0x20;
- subor_helper2 = ((m_subor_reg[2] ^ m_subor_reg[3]) << 0) & 0x1f;
-
- if (m_subor_reg[1] & 0x08)
- {
- subor_helper1 += subor_helper2 & 0xfe;
- subor_helper2 = subor_helper1;
- subor_helper1 += 1;
- }
- else if (m_subor_reg[1] & 0x04)
- {
- subor_helper2 += subor_helper1;
- subor_helper1 = 0x1f;
- }
- else
- {
- subor_helper1 += subor_helper2;
- subor_helper2 = 0x20;
- }
-
- prg16_89ab(subor_helper1);
- prg16_cdef(subor_helper2);
-}
-
-/*************************************************************
-
- Subor bootleg board Type 1
-
- iNES: mapper 166
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::subor1_w)
-{
- UINT8 subor_helper1, subor_helper2;
- LOG_MMC(("subor1_w, offset: %04x, data: %02x\n", offset, data));
-
- m_subor_reg[(offset >> 13) & 0x03] = data;
- subor_helper1 = ((m_subor_reg[0] ^ m_subor_reg[1]) << 1) & 0x20;
- subor_helper2 = ((m_subor_reg[2] ^ m_subor_reg[3]) << 0) & 0x1f;
-
- if (m_subor_reg[1] & 0x08)
- {
- subor_helper1 += subor_helper2 & 0xfe;
- subor_helper2 = subor_helper1;
- subor_helper2 += 1;
- }
- else if (m_subor_reg[1] & 0x04)
- {
- subor_helper2 += subor_helper1;
- subor_helper1 = 0x1f;
- }
- else
- {
- subor_helper1 += subor_helper2;
- subor_helper2 = 0x07;
- }
-
- prg16_89ab(subor_helper1);
- prg16_cdef(subor_helper2);
-}
-
-/*************************************************************
-
- Bootleg Board by Super Game
-
- Games: Boogerman, Mortal Kombat III
-
- MMC3 clone. Also, it probably needs a hack to support both
- variants (Boogerman & MK3).
-
- iNES: mapper 215
-
- In MESS: Preliminary support.
-
- *************************************************************/
-
-static void sgame_boog_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (!(state->m_mmc_reg[0] & 0x80)) // if this is != 0 we should never even arrive here
- {
- if (state->m_mmc_reg[1] & 0x08)
- bank = (bank & 0x1f) | 0x20;
- else
- bank = (bank & 0x0f) | (state->m_mmc_reg[1] & 0x10);
-
- state->prg8_x(start, bank);
- }
-}
-
-static void sgame_boog_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if ((state->m_mmc_reg[1] & 0x04))
- bank |= 0x100;
- else
- bank = (bank & 0x7f) | ((state->m_mmc_reg[1] & 0x10) << 3);
-
- state->chr1_x(start, bank, source);
-}
-
-static void sgame_boog_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (state->m_mmc_reg[0] & 0x80)
- {
- state->prg16_89ab((state->m_mmc_reg[0] & 0xf0) | (state->m_mmc_reg[1] & 0x10));
- state->prg16_cdef((state->m_mmc_reg[0] & 0xf0) | (state->m_mmc_reg[1] & 0x10));
- }
- else
- mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
-}
-
-WRITE8_MEMBER(nes_carts_state::sgame_boog_l_w)
-{
- LOG_MMC(("sgame_boog_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset == 0x1000)
- {
- m_mmc_reg[0] = data;
- sgame_boog_set_prg(machine());
- }
- else if (offset == 0x1001)
- {
- m_mmc_reg[1] = data;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
- else if (offset == 0x1007)
- {
- m_mmc3_latch = 0;
- m_mmc_reg[2] = data;
- sgame_boog_set_prg(machine());
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::sgame_boog_m_w)
-{
- LOG_MMC(("sgame_boog_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset == 0x0000)
- {
- m_mmc_reg[0] = data;
- sgame_boog_set_prg(machine());
- }
- else if (offset == 0x0001)
- {
- m_mmc_reg[1] = data;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
- else if (offset == 0x0007)
- {
- m_mmc3_latch = 0;
- m_mmc_reg[2] = data;
- sgame_boog_set_prg(machine());
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::sgame_boog_w)
-{
- static const UINT8 conv_table[8] = {0,2,5,3,6,1,7,4};
- LOG_MMC(("sgame_boog_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- if (!m_mmc_reg[2])
- txrom_w(space, 0x0000, data, mem_mask);
- break;
-
- case 0x0001:
- if (!m_mmc_reg[2])
- txrom_w(space, 0x0001, data, mem_mask);
- else if (m_mmc_reg[3] && ((m_mmc_reg[0] & 0x80) == 0 || (m_mmc_latch1 & 0x07) < 6)) // if we use the prg16 banks and cmd=6,7 DON'T enter!
- {
- m_mmc_reg[3] = 0;
- txrom_w(space, 0x0001, data, mem_mask);
- }
- break;
-
- case 0x2000:
- if (!m_mmc_reg[2])
- txrom_w(space, 0x2000, data, mem_mask);
- else
- {
- data = (data & 0xc0) | conv_table[data & 0x07];
- m_mmc_reg[3] = 1;
- txrom_w(space, 0x0000, data, mem_mask);
- break;
- }
- break;
-
- case 0x4000:
- if (!m_mmc_reg[2])
- txrom_w(space, 0x4000, data, mem_mask);
- else
- set_nt_mirroring(((data >> 7) | data) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- case 0x4001:
- if (!m_mmc_reg[2])
- txrom_w(space, 0x4001, data, mem_mask);
- else
- txrom_w(space, 0x6001, data, mem_mask);
- break;
-
- case 0x6001:
- if (!m_mmc_reg[2])
- txrom_w(space, 0x6001, data, mem_mask);
- else
- {
- txrom_w(space, 0x4000, data, mem_mask);
- txrom_w(space, 0x4001, data, mem_mask);
- }
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board by Super Game
-
- Games: The Lion King
-
- MMC3 clone.
-
- iNES: mapper 114
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sgame_lion_m_w)
-{
- LOG_MMC(("sgame_lion_m_w, offset: %04x, data: %02x\n", offset, data));
-
- m_map114_reg = data;
-
- if (m_map114_reg & 0x80)
- {
- prg16_89ab(data & 0x1f);
- prg16_cdef(data & 0x1f);
- }
- else
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
-}
-
-WRITE8_MEMBER(nes_carts_state::sgame_lion_w)
-{
- static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4};
- LOG_MMC(("sgame_lion_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x6000)
- {
- switch (offset & 0x6000)
- {
- case 0x0000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 0x2000:
- m_map114_reg_enabled = 1;
- data = (data & 0xc0) | conv_table[data & 0x07];
- txrom_w(space, 0x0000, data, mem_mask);
- break;
- case 0x4000:
- if (m_map114_reg_enabled && (m_map114_reg & 0x80) == 0)
- {
- m_map114_reg_enabled = 0;
- txrom_w(space, 0x0001, data, mem_mask);
- }
- break;
- }
- }
- else
- {
- switch (offset & 0x03)
- {
- case 0x02:
- txrom_w(space, 0x6000, data, mem_mask);
- break;
- case 0x03:
- txrom_w(space, 0x6001, data, mem_mask);
- txrom_w(space, 0x4000, data, mem_mask);
- txrom_w(space, 0x4001, data, mem_mask);
- break;
- }
- }
-}
-
-/*************************************************************
-
- Tengen 800008 Board
-
- iNES: mapper 3?
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::tengen_800008_w)
-{
- LOG_MMC(("tengen_800008_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data >> 3);
- chr8(data, CHRROM);
-}
-
-/*************************************************************
-
- Tengen 800032 Board
-
- Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls
- & Croosbones, Xybots
-
- iNES: mapper 64
-
- In MESS: Partially Supported.
-
- *************************************************************/
-
-void nes_state::tengen_800032_irq( int scanline, int vblank, int blanked )
-{
- if (!m_IRQ_mode) // we are in scanline mode!
- {
- if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
- {
- if (!m_IRQ_reset)
- {
- if (!m_IRQ_count)
- m_IRQ_count = m_IRQ_count_latch;
- else
- {
- m_IRQ_count--;
- if (m_IRQ_enable && !blanked && !m_IRQ_count)
- {
- LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
- machine().primary_screen->vpos(), machine().primary_screen->hpos()));
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- }
- }
- else
- {
- m_IRQ_reset = 0;
- m_IRQ_count = m_IRQ_count_latch + 1;
- }
- }
- }
- /* otherwise, we are in CPU cycles mode --> decrement count of 114 every scanline
- --> in the meanwhile anything can have happened to IRQ_reset and we would not know
- --> Skulls and Crossbones does not show anything!! */
- else
- {
- // if (!m_IRQ_reset)
- {
- if (m_IRQ_count <= 114)
- m_IRQ_count = m_IRQ_count_latch;
- else
- {
- m_IRQ_count -= 114;
- if (m_IRQ_enable && !blanked && (m_IRQ_count <= 114))
- {
- LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
- machine().primary_screen->vpos(), machine().primary_screen->hpos()));
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- }
- }
- // else
- // {
- // state->m_IRQ_reset = 0;
- // state->m_IRQ_count = state->m_IRQ_count_latch + 1;
- // }
- }
-}
-
-static void tengen_800032_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 prg_mode = state->m_mmc_latch1 & 0x40;
-
- state->prg8_89(state->m_mmc_prg_bank[prg_mode ? 2: 0]);
- state->prg8_ab(state->m_mmc_prg_bank[prg_mode ? 0: 1]);
- state->prg8_cd(state->m_mmc_prg_bank[prg_mode ? 1: 2]);
-}
-
-static void tengen_800032_set_chr( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5;
-
- if (state->m_mmc_latch1 & 0x20)
- {
- state->chr1_x(0 ^ chr_page, state->m_mmc_vrom_bank[0], CHRROM);
- state->chr1_x(1 ^ chr_page, state->m_mmc_vrom_bank[8], CHRROM);
- state->chr1_x(2 ^ chr_page, state->m_mmc_vrom_bank[1], CHRROM);
- state->chr1_x(3 ^ chr_page, state->m_mmc_vrom_bank[9], CHRROM);
- }
- else
- {
- state->chr1_x(0 ^ chr_page, state->m_mmc_vrom_bank[0] & ~0x01, CHRROM);
- state->chr1_x(1 ^ chr_page, state->m_mmc_vrom_bank[0] | 0x01, CHRROM);
- state->chr1_x(2 ^ chr_page, state->m_mmc_vrom_bank[1] & ~0x01, CHRROM);
- state->chr1_x(3 ^ chr_page, state->m_mmc_vrom_bank[1] | 0x01, CHRROM);
- }
-
- state->chr1_x(4 ^ chr_page, state->m_mmc_vrom_bank[2], CHRROM);
- state->chr1_x(5 ^ chr_page, state->m_mmc_vrom_bank[3], CHRROM);
- state->chr1_x(6 ^ chr_page, state->m_mmc_vrom_bank[4], CHRROM);
- state->chr1_x(7 ^ chr_page, state->m_mmc_vrom_bank[5], CHRROM);
-}
-
-WRITE8_MEMBER(nes_carts_state::tengen_800032_w)
-{
- UINT8 map64_helper, cmd;
- LOG_MMC(("tengen_800032_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- map64_helper = m_mmc_latch1 ^ data;
- m_mmc_latch1 = data;
-
- /* Has PRG Mode changed? */
- if (map64_helper & 0x40)
- tengen_800032_set_prg(machine());
-
- /* Has CHR Mode changed? */
- if (map64_helper & 0xa0)
- tengen_800032_set_chr(machine());
- break;
-
- case 0x0001:
- cmd = m_mmc_latch1 & 0x0f;
- switch (cmd)
- {
- case 0: case 1:
- case 2: case 3:
- case 4: case 5:
- m_mmc_vrom_bank[cmd] = data;
- tengen_800032_set_chr(machine());
- break;
- case 6: case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- tengen_800032_set_prg(machine());
- break;
- case 8: case 9:
- m_mmc_vrom_bank[cmd - 2] = data;
- tengen_800032_set_chr(machine());
- break;
- case 0x0f:
- m_mmc_prg_bank[2] = data;
- tengen_800032_set_prg(machine());
- break;
- }
- break;
-
- case 0x2000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- case 0x4000:
- m_IRQ_count_latch = data;
- break;
-
- case 0x4001: /* $c001 - IRQ scanline latch */
- m_IRQ_mode = data & 0x01;
- m_IRQ_reset = 1;
- break;
-
- case 0x6000:
- m_IRQ_enable = 0;
- break;
-
- case 0x6001:
- m_IRQ_enable = 1;
- break;
-
- default:
- LOG_MMC(("Mapper 64 write. addr: %04x value: %02x\n", offset + 0x8000, data));
- break;
- }
-}
-
-/*************************************************************
-
- Tengen 800037 Board
-
- Games: Alien Syndrome
-
- iNES: mapper 158
-
- In MESS: Very preliminary support.
-
- *************************************************************/
-
-// probably wrong...
-static void tengen_800037_set_mirror( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 nt_mode = state->m_mmc_latch1 & 0x80;
-
- state->set_nt_page(0, ROM, state->m_mmc_vrom_bank[nt_mode ? 2 : 0], 0);
- state->set_nt_page(1, ROM, state->m_mmc_vrom_bank[nt_mode ? 3 : 0], 0);
- state->set_nt_page(2, ROM, state->m_mmc_vrom_bank[nt_mode ? 4 : 1], 0);
- state->set_nt_page(3, ROM, state->m_mmc_vrom_bank[nt_mode ? 5 : 1], 0);
-}
-
-WRITE8_MEMBER(nes_carts_state::tengen_800037_w)
-{
- UINT8 map158_helper, cmd;
- LOG_MMC(("tengen_800037_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- map158_helper = m_mmc_latch1 ^ data;
- m_mmc_latch1 = data;
-
- /* Has PRG Mode changed? */
- if (map158_helper & 0x40)
- tengen_800032_set_prg(machine());
-
- /* Has CHR Mode changed? */
- if (map158_helper & 0xa0)
- {
- tengen_800032_set_chr(machine());
- tengen_800037_set_mirror(machine());
- }
- break;
-
- case 0x0001:
- cmd = m_mmc_latch1 & 0x0f;
- switch (cmd)
- {
- case 0: case 1:
- case 2: case 3:
- case 4: case 5:
- m_mmc_vrom_bank[cmd] = data;
- tengen_800032_set_chr(machine());
- tengen_800037_set_mirror(machine());
- break;
- case 6: case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- tengen_800032_set_prg(machine());
- break;
- case 8: case 9:
- m_mmc_vrom_bank[cmd - 2] = data;
- tengen_800032_set_chr(machine());
- tengen_800037_set_mirror(machine());
- break;
- case 0x0f:
- m_mmc_prg_bank[2] = data;
- tengen_800032_set_prg(machine());
- break;
- }
- break;
-
- case 0x2000:
- break;
-
- default:
- tengen_800032_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board 22211 by TXC (Type A)
-
- Games: Creatom
-
- Info from NEStopia: this mapper features write to four
- registers (0x4100-0x4103). The third one is used to select
- PRG and CHR banks.
-
- iNES: mapper 132
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::txc_22211_l_w)
-{
- LOG_MMC(("txc_22211_l_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 4)
- m_txc_reg[offset & 0x03] = data;
-}
-
-READ8_MEMBER(nes_carts_state::txc_22211_l_r)
-{
- LOG_MMC(("txc_22211_l_r, offset: %04x\n", offset));
-
- if (offset == 0x0000)
- return (m_txc_reg[1] ^ m_txc_reg[2]) | 0x40;
- else
- return 0x00;
-}
-
-WRITE8_MEMBER(nes_carts_state::txc_22211_w)
-{
- LOG_MMC(("txc_22211_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(m_txc_reg[2] >> 2);
- chr8(m_txc_reg[2], CHRROM);
-}
-
-/*************************************************************
-
- Bootleg Board 22211 by TXC (Type B)
-
- Games: 1991 Du Ma Racing
-
- This mapper is basically the same as Type A. Only difference is
- in the way CHR banks are selected (see below)
-
- iNES: mapper 172
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::txc_22211b_w)
-{
- LOG_MMC(("txc_22211b_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(m_txc_reg[2] >> 2);
- chr8((((data ^ m_txc_reg[2]) >> 3) & 0x02) | (((data ^ m_txc_reg[2]) >> 5) & 0x01), CHRROM);
-}
-
-/*************************************************************
-
- Bootleg Board 22211 by TXC (Type C)
-
- Games: Mahjong Block, Xiao Ma Li
-
- This mapper is basically the same as 132 too. Only difference is
- in 0x4100 reads which expect also bit 0 to be set
-
- iNES: mapper 172
-
- In MESS: Supported.
-
- *************************************************************/
-
-READ8_MEMBER(nes_carts_state::txc_22211c_l_r)
-{
- LOG_MMC(("txc_22211c_l_r, offset: %04x\n", offset));
-
- if (offset == 0x0000)
- return (m_txc_reg[1] ^ m_txc_reg[2]) | 0x41;
- else
- return 0x00;
-}
-
-/*************************************************************
-
- Bootleg Board 'Thunder Warrior' by TXC
-
- Games: Master Fighter II, Master Fighter 3, Thunder Warrior
-
- MMC3 clone
-
- iNES: mapper 189
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::txc_tw_l_w)
-{
- LOG_MMC(("txctw_l_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32((data >> 4) | data);
-}
-
-WRITE8_MEMBER(nes_carts_state::txc_tw_m_w)
-{
- LOG_MMC(("txctw_m_w, offset: %04x, data: %04x\n", offset, data));
-
- txc_tw_l_w(space, offset & 0xff, data, mem_mask); // offset does not really count for this mapper
-}
-
-/* writes to 0x8000-0xffff are like MMC3 but no PRG bankswitch (beacuse it is handled by low writes) */
-static void txc_tw_prg_cb( running_machine &machine, int start, int bank )
-{
- return;
-}
-
-/*************************************************************
-
- Bootleg Board 'Strike Wolf' by TXC
-
- Games: Strike Wolf (also Policeman?? according to Nestopia)
-
- iNES: mapper 36
-
- Known Boards: Bootleg Board by TXC
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::txc_strikewolf_w)
-{
- LOG_MMC(("txc_strikewolf_w, offset: %04x, data: %02x\n", offset, data));
-
- if ((offset >= 0x400) && (offset < 0x7fff))
- {
- prg32(data >> 4);
- chr8(data & 0x0f, CHRROM);
- }
-}
-
-/*************************************************************
-
- Bootleg Board MXMDHTWO by TXC
-
- Games: Commandos, Journey to the West, Ma Bu Mi Zhen &
- Qu Wei Cheng Yu Wu, Si Lu Chuan Qi
-
- Simple Mapper: writes to 0x8000-0xffff sets the prg32 bank.
- Not sure if returning 0x50 for reads in 0x4100-0x5000 is correct.
-
- iNES: mapper 241
-
- In MESS: Supported.
-
- *************************************************************/
-
-READ8_MEMBER(nes_carts_state::txc_mxmdhtwo_l_r)
-{
- return 0x50;
-}
-
-WRITE8_MEMBER(nes_carts_state::txc_mxmdhtwo_w)
-{
- LOG_MMC(("txc_mxmdhtwo_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data);
-}
-
-/*************************************************************
-
- Waixing Board Type A
-
- Games: Columbus - Ougon no Yoake (C), Ji Jia Zhan Shi,
- Jia A Fung Yun, Wei Luo Chuan Qi
-
- This mapper is quite similar to MMC3, but with two differences:
- mirroring is not the same, and when VROM banks 8,9 are accessed
- they point to CHRRAM and not CHRROM.
-
- iNES: mapper 74
-
- In MESS: Supported
-
- *************************************************************/
-
-/* MIRROR_LOW and MIRROR_HIGH are swapped! */
-static void waixing_set_mirror( running_machine &machine, UINT8 nt )
-{
- nes_state *state = machine.driver_data<nes_state>();
- switch (nt)
- {
- case 0:
- case 1:
- state->set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 2:
- state->set_nt_mirroring(PPU_MIRROR_LOW);
- break;
- case 3:
- state->set_nt_mirroring(PPU_MIRROR_HIGH);
- break;
- default:
- LOG_MMC(("Mapper set NT to invalid value %02x", nt));
- break;
- }
-}
-
-/* Luo Ke Ren X only works with this */
-static void waixing_a_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int chr_src = (bank <= 9) ? CHRRAM : CHRROM;
- state->chr1_x(start, bank, chr_src);
-}
-
-/* Ji Jia Zhan Shi only works with this */
-static void waixing_a1_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int chr_src = ((bank == 8) || (bank == 9)) ? CHRRAM : CHRROM;
- state->chr1_x(start, bank, chr_src);
-}
-
-WRITE8_MEMBER(nes_carts_state::waixing_a_w)
-{
- LOG_MMC(("waixing_a_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x2000:
- waixing_set_mirror(machine(), data); //maybe data & 0x03?
- break;
-
- case 0x2001:
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Waixing Board Type B
-
- Games: Sugoro Quest (C)
-
- MMC3 clone. This is a minor modification of Mapper 74,
- in the sense that it is the same board except for the
- CHRRAM pages.
-
- iNES: mapper 191
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void waixing_b_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int chr_src = BIT(bank, 7) ? CHRRAM : CHRROM;
- state->chr1_x(start, bank, chr_src);
-}
-
-/*************************************************************
-
- Waixing Board Type C
-
- Games: Ying Lie Qun Xia Zhuan, Young Chivalry
-
- MMC3 clone. This is a minor modification of Mapper 74,
- in the sense that it is the same board except for the
- CHRRAM pages.
-
- iNES: mapper 192
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void waixing_c_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int chr_src = ((bank == 0x08) || (bank == 0x09) || (bank == 0x0a) || (bank == 0x0b)) ? CHRRAM : CHRROM;
- state->chr1_x(start, bank, chr_src);
-}
-
-/*************************************************************
-
- Waixing Board Type D
-
- Games: Super Robot Taisen (C)
-
- MMC3 clone. This is a minor modification of Mapper 74,
- in the sense that it is the same board except for the
- CHRRAM pages.
-
- iNES: mapper 194
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void waixing_d_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int chr_src = (bank < 0x02) ? CHRRAM : CHRROM;
- state->chr1_x(start, bank, chr_src);
-}
-
-/*************************************************************
-
- Waixing Board Type E
-
- Games: Captain Tsubasa Vol. II (C), Chaos World, God
- Slayer (C), Zu Qiu Xiao Jiang
-
- MMC3 clone. This is a minor modification of Mapper 74,
- in the sense that it is the same board except for the
- CHRRAM pages.
-
- iNES: mapper 195
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void waixing_e_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int chr_src = (bank < 0x04) ? CHRRAM : CHRROM;
- state->chr1_x(start, bank, chr_src);
-}
-
-/*************************************************************
-
- Waixing Board Type F
-
- Games: Tenchi wo Kurau II (C)
-
- MMC3 clone.
-
- iNES: mapper 198
-
- In MESS: Preliminary support.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::waixing_f_w)
-{
- UINT8 cmd;
- LOG_MMC(("waixing_f_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0001:
- cmd = m_mmc_latch1 & 0x07;
- if (cmd >= 6)
- {
- m_mmc_prg_bank[cmd - 6] = data & ((data > 0x3f) ? 0x4f : 0x3f);
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- }
- else
- waixing_a_w(space, offset, data, mem_mask);
- break;
-
- default:
- waixing_a_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Waixing Board Type G
-
- Games: San Guo Zhi 2, Dragon Ball Z Gaiden (C), Dragon
- Ball Z II (C)
-
- MMC3 clone
-
- iNES: mapper 199
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void waixing_g_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int chr_src = (bank < 0x08) ? CHRRAM : CHRROM;
- state->chr1_x(start, bank, chr_src);
-}
-
-static void waixing_g_set_chr( running_machine &machine, int chr_base, int chr_mask )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5;
-
- state->m_mmc3_chr_cb(machine, chr_page ^ 0, chr_base | (state->m_mmc_vrom_bank[0] & chr_mask), state->m_mmc_chr_source);
- state->m_mmc3_chr_cb(machine, chr_page ^ 1, chr_base | (state->m_mmc_vrom_bank[6] & chr_mask), state->m_mmc_chr_source);
- state->m_mmc3_chr_cb(machine, chr_page ^ 2, chr_base | (state->m_mmc_vrom_bank[1] & chr_mask), state->m_mmc_chr_source);
- state->m_mmc3_chr_cb(machine, chr_page ^ 3, chr_base | (state->m_mmc_vrom_bank[7] & chr_mask), state->m_mmc_chr_source);
- state->m_mmc3_chr_cb(machine, chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), state->m_mmc_chr_source);
- state->m_mmc3_chr_cb(machine, chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), state->m_mmc_chr_source);
- state->m_mmc3_chr_cb(machine, chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), state->m_mmc_chr_source);
- state->m_mmc3_chr_cb(machine, chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), state->m_mmc_chr_source);
-}
-
-WRITE8_MEMBER(nes_carts_state::waixing_g_w)
-{
- UINT8 MMC3_helper, cmd;
- LOG_MMC(("waixing_g_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- MMC3_helper = m_mmc_latch1 ^ data;
- m_mmc_latch1 = data;
-
- /* Has PRG Mode changed? */
- if (MMC3_helper & 0x40)
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- /* Has CHR Mode changed? */
- if (MMC3_helper & 0x80)
- waixing_g_set_chr(machine(), m_mmc_chr_base, m_mmc_chr_mask);
- break;
-
- case 0x0001:
- cmd = m_mmc_latch1 & 0x0f;
- switch (cmd)
- {
- case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
- case 2: case 3: case 4: case 5:
- m_mmc_vrom_bank[cmd] = data;
- waixing_g_set_chr(machine(), m_mmc_chr_base, m_mmc_chr_mask);
- break;
- case 6:
- case 7:
- case 8:
- case 9:
- m_mmc_prg_bank[cmd - 6] = data;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- case 0x0a: case 0x0b:
- m_mmc_vrom_bank[cmd - 4] = data;
- waixing_g_set_chr(machine(), m_mmc_chr_base, m_mmc_chr_mask);
- break;
- }
- break;
-
- default:
- waixing_a_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Waixing Board Type H
-
- Games: Ying Xiong Yuan Yi Jing Chuan Qi, Yong Zhe Dou E
- Long - Dragon Quest VII
-
- MMC3 clone. More info to come.
-
- iNES: mapper 245
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void waixing_h_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (source == CHRROM)
- state->chr1_x(start, bank, source);
-}
-
-WRITE8_MEMBER(nes_carts_state::waixing_h_w)
-{
- UINT8 cmd;
- LOG_MMC(("waixing_h_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0001:
- cmd = m_mmc3_latch & 0x07;
- switch (cmd)
- {
- case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank!
- m_mmc_prg_base = (data << 5) & 0x40;
- m_mmc_prg_mask = 0x3f;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- txrom_w(space, offset, data, mem_mask);
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
- break;
-
- case 0x2001:
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Waixing San Guo Zhi Board
-
- Games: San Guo Zhi
-
- This board uses Konami IRQ
-
- iNES: mapper 252
-
- In MESS: Unsupported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::waixing_sgz_w)
-{
- UINT8 mmc_helper, bank;
- LOG_MMC(("waixing_sgz_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- prg8_89(data);
- break;
- case 0x2000:
- prg8_ab(data);
- break;
- case 0x3000:
- case 0x4000:
- case 0x5000:
- case 0x6000:
- bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 3);
- mmc_helper = offset & 0x04;
- if (mmc_helper)
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
- else
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
- chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
- break;
- case 0x7000:
- switch (offset & 0x0c)
- {
- case 0x00:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0xf0) | (data & 0x0f);
- break;
- case 0x04:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4);
- break;
- case 0x08:
- m_IRQ_enable = data & 0x02;
- m_IRQ_enable_latch = data & 0x01;
- if (data & 0x02)
- m_IRQ_count = m_IRQ_count_latch;
- break;
- case 0x0c:
- m_IRQ_enable = m_IRQ_enable_latch;
- break;
- }
- break;
- }
-}
-
-
-/*************************************************************
-
- Waixing San Guo Zhong Lie Zhuan Board
-
- Games: Fan Kong Jing Ying, San Guo Zhong Lie Zhuan, Xing
- Ji Zheng Ba
-
- iNES: mapper 178
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::waixing_sgzlz_l_w)
-{
- LOG_MMC(("waixing_sgzlz_l_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x700:
- set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 0x701:
- m_mmc_latch1 = (m_mmc_latch1 & 0x0c) | ((data >> 1) & 0x03);
- prg32(m_mmc_latch1);
- break;
- case 0x702:
- m_mmc_latch1 = (m_mmc_latch1 & 0x03) | ((data << 2) & 0x0c);
- break;
- }
-}
-
-/*************************************************************
-
- Waixing Final Fantasy V Board
-
- Games: Darkseed, Digital Dragon, Final Fantasy V, Pocket
- Monster Red
-
- iNES: mapper 164
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::waixing_ffv_l_w)
-{
- UINT8 mmc_helper;
- LOG_MMC(("waixing_ffv_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100; /* the checks work better on addresses */
-
- if (0x1000 == (offset & 0x1200))
- {
- m_mmc_reg[BIT(offset, 8)] = data;
- mmc_helper = BIT(m_mmc_reg[1], 0) << 5;
- switch (m_mmc_reg[0] & 0x70)
- {
- case 0x00:
- case 0x20:
- case 0x40:
- case 0x60:
- prg16_89ab(mmc_helper | ((m_mmc_reg[0] >> 1) & 0x10) | (m_mmc_reg[0] & 0x0f));
- prg16_cdef(mmc_helper & 0x1f);
- break;
- case 0x50:
- prg32((mmc_helper >> 1) | (m_mmc_reg[0] & 0x0f));
- break;
- case 0x70:
- prg16_89ab(mmc_helper | ((m_mmc_reg[0] << 1) & 0x10) | (m_mmc_reg[0] & 0x0f));
- prg16_cdef(mmc_helper & 0x1f);
- break;
- }
- }
-}
-
-/*************************************************************
-
- Waixing Zhan Shi Board
-
- Games: Wai Xing Zhan Shi
-
- Simple mapper: writes to 0x8000-0xffff sets prg32 banks to
- (offset>>3)&f. written data&3 sets the mirroring (with
- switched high/low compared to the standard one).
-
- A crc check is required to support Dragon Quest VIII (which
- uses a slightly different board)
-
- iNES: mapper 242
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::waixing_zs_w)
-{
- LOG_MMC(("waixing_zs_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(offset >> 3);
-
- switch (data & 0x03)
- {
- case 0: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
-}
-
-/*************************************************************
-
- Waixing Dragon Quest VIII Board
-
- Games: Dragon Quest VIII
-
- Simple mapper: writes to 0x8000-0xffff sets prg32 banks to
- (offset>>3)&f.
-
- iNES: mapper 242
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::waixing_dq8_w)
-{
- LOG_MMC(("waixing_dq8_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(offset >> 3);
-}
-
-
-/*************************************************************
-
- Waixing PS2 board
-
- Games: Bao Xiao Tien Guo, Bio Hazard, Pokemon Gold, Subor (R)
-
- iNES: mapper 15
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::waixing_ps2_w)
-{
- UINT8 map15_flip = (data & 0x80) >> 7;
- UINT8 map15_helper = (data & 0x7f) << 1;
-
- LOG_MMC(("waixing_ps2_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- switch (offset & 0x0fff)
- {
- case 0x000:
- prg8_89((map15_helper + 0) ^ map15_flip);
- prg8_ab((map15_helper + 1) ^ map15_flip);
- prg8_cd((map15_helper + 2) ^ map15_flip);
- prg8_ef((map15_helper + 3) ^ map15_flip);
- break;
- case 0x001:
- map15_helper |= map15_flip;
- prg8_89(map15_helper);
- prg8_ab(map15_helper + 1);
- prg8_cd(map15_helper + 1);
- prg8_ef(map15_helper + 1);
- break;
- case 0x002:
- map15_helper |= map15_flip;
- prg8_89(map15_helper);
- prg8_ab(map15_helper);
- prg8_cd(map15_helper);
- prg8_ef(map15_helper);
- break;
- case 0x003:
- map15_helper |= map15_flip;
- prg8_89(map15_helper);
- prg8_ab(map15_helper + 1);
- prg8_cd(map15_helper);
- prg8_ef(map15_helper + 1);
- break;
- }
-}
-
-/*************************************************************
-
- Waixing Board with Security Chip
-
- Games: Duo Bao Xiao Ying Hao - Guang Ming yu An Hei Chuan Shuo,
- Myth Struggle, San Shi Liu Ji, Shui Hu Zhuan
-
- MMC3 clone
-
- iNES: mapper 249
-
- In MESS: Partially Supported.
-
- *************************************************************/
-
-static void waixing_sec_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (state->m_mmc_reg[0])
- bank = ((bank & 0x01)) | ((bank >> 3) & 0x02) | ((bank >> 1) & 0x04) | ((bank << 2) & 0x18);
-
- state->prg8_x(start, bank);
-}
-
-static void waixing_sec_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (state->m_mmc_reg[0])
- bank = ((bank & 0x03)) | ((bank >> 1) & 0x04) | ((bank >> 4) & 0x08) |
- ((bank >> 2) & 0x10) | ((bank << 3) & 0x20) | ((bank << 2) & 0xc0);
-
- state->chr1_x(start, bank, source);
-}
-
-WRITE8_MEMBER(nes_carts_state::waixing_sec_l_w)
-{
- LOG_MMC(("waixing_sec_l_w, offset: %04x, data: %02x\n", offset, data));
-
- offset += 0x100;
-
- if (offset == 0x1000)
- {
- m_mmc_reg[0] = data & 0x02;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
-}
-
-/*************************************************************
-
- Waixing SH2 Board
-
- Games: Fire Emblem (C) and Fire Emblem Gaiden (C)
-
- MMC3 clone with different access to CHR
-
- iNES: mapper 165
-
- In MESS: Partially Supported.
-
- *************************************************************/
-
-static void waixing_sh2_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- state->chr4_0(state->m_mmc_reg[0], state->m_mmc_reg[0] ? CHRRAM : CHRROM);
- state->chr4_4(state->m_mmc_reg[1], state->m_mmc_reg[1] ? CHRRAM : CHRROM);
-}
-
-READ8_MEMBER(nes_carts_state::waixing_sh2_chr_r)
-{
- int bank = offset >> 10;
- UINT8 val = m_chr_map[bank].access[offset & 0x3ff]; // this would be usual return value
- int chr_helper;
-
- switch (offset & 0xff8)
- {
- case 0xfd0: chr_helper = (bank & 0x4) | 0x0; break;
- case 0xfe8: chr_helper = (bank & 0x4) | 0x2; break;
- default: return val;
- }
-
- m_mmc_reg[offset >> 12] = chr_helper;
- if (offset & 0x1000)
- chr4_4(m_mmc_reg[1], m_mmc_reg[1] ? CHRRAM : CHRROM);
- else
- chr4_0(m_mmc_reg[0], m_mmc_reg[0] ? CHRRAM : CHRROM);
-
- return val;
-}
-
-/*************************************************************
-
- Board UNL-8237
-
- Games: Pocahontas 2
-
- MMC3 clone
-
- In MESS: Supported
-
- *************************************************************/
-
-static void unl_8237_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (!(state->m_mmc_reg[0] & 0x80))
- state->prg8_x(start, bank);
-}
-
-static void unl_8237_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- bank |= ((state->m_mmc_reg[1] << 6) & 0x100);
-
- state->chr1_x(start, bank, source);
-}
-
-WRITE8_MEMBER(nes_carts_state::unl_8237_l_w)
-{
- LOG_MMC(("unl_8237_l_w offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset == 0x1000)
- {
- m_mmc_reg[0] = data;
- if (m_mmc_reg[0] & 0x80)
- {
- if (m_mmc_reg[0] & 0x20)
- prg32((m_mmc_reg[0] & 0x0f) >> 1);
- else
- {
- prg16_89ab(m_mmc_reg[0] & 0x1f);
- prg16_cdef(m_mmc_reg[0] & 0x1f);
- }
- }
- else
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- }
-
- if (offset == 0x1001)
- {
- m_mmc_reg[1] = data;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::unl_8237_w)
-{
- static const UINT8 conv_table[8] = {0, 2, 6, 1, 7, 3, 4, 5};
- LOG_MMC(("unl_8237_w offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- case 0x1000:
- set_nt_mirroring((data | (data >> 7)) & 0x01 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- case 0x2000:
- case 0x3000:
- m_mmc_reg[2] = 1;
- data = (data & 0xc0) | conv_table[data & 0x07];
- txrom_w(space, 0x0000, data, mem_mask);
- break;
-
- case 0x4000:
- case 0x5000:
- if (m_mmc_reg[2])
- {
- m_mmc_reg[2] = 0;
- txrom_w(space, 0x0001, data, mem_mask);
- }
- break;
-
- case 0x6000:
- break;
-
- case 0x7000:
- txrom_w(space, 0x6001, data, mem_mask);
- txrom_w(space, 0x4000, data, mem_mask);
- txrom_w(space, 0x4001, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Board UNL-AX5705
-
- Games: Super Mario Bros. Pocker Mali (Crayon Shin-chan pirate hack)
-
- In MESS: Supported
-
- *************************************************************/
-
-static void unl_ax5705_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->prg8_89(state->m_mmc_prg_bank[0]);
- state->prg8_ab(state->m_mmc_prg_bank[1]);
-}
-
-WRITE8_MEMBER(nes_carts_state::unl_ax5705_w)
-{
- UINT8 bank;
- LOG_MMC(("unl_ax5705_w offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x700f)
- {
- case 0x0000:
- m_mmc_prg_bank[0] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2);
- unl_ax5705_set_prg(machine());
- break;
- case 0x0008:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 0x2000:
- m_mmc_prg_bank[1] = (data & 0x05) | ((data & 0x08) >> 2) | ((data & 0x02) << 2);
- unl_ax5705_set_prg(machine());
- break;
- /* CHR banks 0, 1, 4, 5 */
- case 0x2008:
- case 0x200a:
- case 0x4008:
- case 0x400a:
- bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
- chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
- break;
- case 0x2009:
- case 0x200b:
- case 0x4009:
- case 0x400b:
- bank = ((offset & 0x4000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4);
- chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
- break;
- /* CHR banks 2, 3, 6, 7 */
- case 0x4000:
- case 0x4002:
- case 0x6000:
- case 0x6002:
- bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
- chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
- break;
- case 0x4001:
- case 0x4003:
- case 0x6001:
- case 0x6003:
- bank = 2 + ((offset & 0x2000) ? 4 : 0) + ((offset & 0x0002) ? 1 : 0);
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x04) << 3) | ((data & 0x02) << 5) | ((data & 0x09) << 4);
- chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
- break;
- }
-}
-
-/*************************************************************
-
- Board UNL-CC-21
-
- Games: Mi Hun Che
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::unl_cc21_w)
-{
- LOG_MMC(("unl_cc21_w offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- chr8((offset & 0x01), CHRROM);
-}
-
-/*************************************************************
-
- Board UNL-KOF97
-
- Games: King of Fighters 97 (Rex Soft)
-
- MMC3 clone
-
- In MESS: Not working
-
- *************************************************************/
-
-static UINT8 unl_kof97_unscramble( UINT8 data )
-{
- return ((data >> 1) & 0x01) | ((data >> 4) & 0x02) | ((data << 2) & 0x04) | ((data >> 0) & 0xd8) | ((data << 3) & 0x20);
-}
-
-WRITE8_MEMBER(nes_carts_state::unl_kof97_w)
-{
- LOG_MMC(("unl_kof97_w offset: %04x, data: %02x\n", offset, data));
-
- /* Addresses 0x9000, 0xa000, 0xd000 & 0xf000 behaves differently than MMC3 */
- if (offset == 0x1000)
- {
- data = unl_kof97_unscramble(data);
- txrom_w(space, 0x0001, data, mem_mask);
- }
- else if (offset == 0x2000)
- {
- data = unl_kof97_unscramble(data);
- txrom_w(space, 0x0000, data, mem_mask);
- }
- else if (offset == 0x5000)
- {
- data = unl_kof97_unscramble(data);
- txrom_w(space, 0x4001, data, mem_mask);
- }
- else if (offset == 0x7000)
- {
- data = unl_kof97_unscramble(data);
- txrom_w(space, 0x6001, data, mem_mask);
- }
- else /* Other addresses behaves like MMC3, up to unscrambling data */
- {
- switch (offset & 0x6001)
- {
- case 0x0000:
- case 0x0001:
- case 0x4000:
- case 0x4001:
- case 0x6000:
- case 0x6001:
- case 0x2000: /* are these ever called?!? */
- case 0x2001:
- data = unl_kof97_unscramble(data);
- txrom_w(space, offset, data, mem_mask);
- break;
- }
- }
-}
-
-/*************************************************************
-
- Board UNL-KS7057
-
- Games: Street Fighter VI / Fight Street VI
-
- MMC3 clone (identical, but for switched address lines)
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::ks7057_w)
-{
- LOG_MMC(("ks7057_w, offset: %04x, data: %02x\n", offset, data));
- offset = (BIT(offset, 0) << 1) | BIT(offset, 1) | (offset & ~0x03);
- txrom_w(space, offset, data, mem_mask);
-}
-
-/*************************************************************
-
- Board UNL-T-230
-
- Games: Dragon Ball Z IV (Unl)
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::unl_t230_w)
-{
- UINT8 bank;
- LOG_MMC(("unl_t230_w offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x700c)
- {
- case 0x0000:
- break;
- case 0x2000:
- prg16_89ab(data);
- break;
-
- // the part below works like VRC-2. how was the original board wired up?
- // was there a VRC2? if so, we can use VRC-2 and add proper pin settings to xml!
- case 0x1000:
- case 0x1004:
- case 0x1008:
- case 0x100c:
- switch (data & 0x03)
- {
- case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
-
- case 0x3000:
- case 0x3004:
- case 0x3008:
- case 0x300c:
- case 0x4000:
- case 0x4004:
- case 0x4008:
- case 0x400c:
- case 0x5000:
- case 0x5004:
- case 0x5008:
- case 0x500c:
- case 0x6000:
- case 0x6004:
- case 0x6008:
- case 0x600c:
- bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 2);
- if (offset & 0x0004)
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | (data << 4);
- else
- m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
-
- chr1_x(bank, m_mmc_vrom_bank[bank], m_mmc_chr_source);
- break;
- case 0x7000:
- m_IRQ_count_latch &= ~0x0f;
- m_IRQ_count_latch |= data & 0x0f;
- break;
- case 0x7004:
- m_IRQ_count_latch &= ~0xf0;
- m_IRQ_count_latch |= (data << 4) & 0xf0;
- break;
- case 0x7008:
- m_IRQ_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
- m_IRQ_enable = data & 0x02;
- m_IRQ_enable_latch = data & 0x01;
- if (data & 0x02)
- m_IRQ_count = m_IRQ_count_latch;
- break;
-
- default:
- logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board for KOF96
-
- Games: The King of Fighters 96, Sonic 3D Blast 6, Street
- Fighter Zero 2
-
- MMC3 clone
-
- iNES: mapper 187
-
- In MESS: Preliminary Support.
-
- *************************************************************/
-
-static void kof96_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (!(state->m_mmc_reg[0] & 0x80))
- state->prg8_x(start, bank);
-}
-
-static void kof96_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5;
-
- if ((start & 0x04) == chr_page)
- bank |= 0x100;
-
- state->chr1_x(start, bank, source);
-}
-
-WRITE8_MEMBER(nes_carts_state::kof96_l_w)
-{
- UINT8 new_bank;
- LOG_MMC(("kof96_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset == 0x1000)
- {
- m_mmc_reg[0] = data;
-
- if (m_mmc_reg[0] & 0x80)
- {
- new_bank = (m_mmc_reg[0] & 0x1f);
-
- if (m_mmc_reg[0] & 0x20)
- prg32(new_bank >> 2);
- else
- {
- prg16_89ab(new_bank);
- prg16_cdef(new_bank);
- }
- }
- else
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- }
-
- if (offset >= 0x1000)
- {
- switch (data & 0x03)
- {
- case 0x00:
- case 0x01:
- m_mmc_reg[1] = 0x83;
- break;
- case 0x02:
- m_mmc_reg[1] = 0x42;
- break;
- case 0x03:
- m_mmc_reg[1] = 0x00;
- break;
- }
-
- }
-
- if (!m_mmc_reg[3] && offset > 0x1000)
- {
- m_mmc_reg[3] = 1;
- space.write_byte(0x4017, 0x40);
- }
-}
-
-READ8_MEMBER(nes_carts_state::kof96_l_r)
-{
- LOG_MMC(("kof96_l_r, offset: %04x\n", offset));
- offset += 0x100;
-
- if (!(offset < 0x1000))
- return m_mmc_reg[1];
- else
- return 0;
-}
-
-WRITE8_MEMBER(nes_carts_state::kof96_w)
-{
- LOG_MMC(("kof96_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6003)
- {
- case 0x0000:
- m_mmc_reg[2] = 1;
- txrom_w(space, 0x0000, data, mem_mask);
- break;
-
- case 0x0001:
- if (m_mmc_reg[2])
- txrom_w(space, 0x0001, data, mem_mask);
- break;
-
- case 0x0002:
- break;
-
- case 0x0003:
- m_mmc_reg[2] = 0;
-
- if (data == 0x28)
- prg8_cd(0x17);
- else if (data == 0x2a)
- prg8_ab(0x0f);
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board for MK2
-
- Games: Mortal Kombat II, Street Fighter III, Super Mario
- Kart Rider
-
- This board uses an IRQ system very similar to MMC3. We indeed
- use mapper4_irq, but there is some small glitch!
-
- iNES: mapper 91
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::mk2_m_w)
-{
- LOG_MMC(("mk2_m_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x1000)
- {
- case 0x0000:
- switch (offset & 0x03)
- {
- case 0x00: chr2_0(data, CHRROM); break;
- case 0x01: chr2_2(data, CHRROM); break;
- case 0x02: chr2_4(data, CHRROM); break;
- case 0x03: chr2_6(data, CHRROM); break;
- }
- break;
- case 0x1000:
- switch (offset & 0x03)
- {
- case 0x00: prg8_89(data); break;
- case 0x01: prg8_ab(data); break;
- case 0x02: m_IRQ_enable = 0; m_IRQ_count = 0; break;
- case 0x03: m_IRQ_enable = 1; m_IRQ_count = 7; break;
- }
- break;
- default:
- logerror("mk2_m_w uncaught addr: %04x value: %02x\n", offset + 0x6000, data);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board N625092
-
- Games: 400 in 1, 700 in 1, 1000 in 1
-
- iNES: mapper 221
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void n625092_set_prg( running_machine &machine, UINT8 reg1, UINT8 reg2 )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 map221_helper1, map221_helper2;
-
- map221_helper1 = !(reg1 & 0x01) ? reg2 :
- (reg1 & 0x80) ? reg2 : (reg2 & 0x06) | 0x00;
- map221_helper2 = !(reg1 & 0x01) ? reg2 :
- (reg1 & 0x80) ? 0x07 : (reg2 & 0x06) | 0x01;
-
- state->prg16_89ab(map221_helper1 | ((reg1 & 0x70) >> 1));
- state->prg16_cdef(map221_helper2 | ((reg1 & 0x70) >> 1));
-}
-
-WRITE8_MEMBER(nes_carts_state::n625092_w)
-{
- LOG_MMC(("n625092_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x4000)
- {
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- offset = (offset >> 1) & 0xff;
-
- if (m_mmc_latch1 != offset)
- {
- m_mmc_latch1 = offset;
- n625092_set_prg(machine(), m_mmc_latch1, m_mmc_latch2);
- }
- }
- else
- {
- offset &= 0x07;
-
- if (m_mmc_latch2 != offset)
- {
- m_mmc_latch2 = offset;
- n625092_set_prg(machine(), m_mmc_latch1, m_mmc_latch2);
- }
- }
-}
-
-/*************************************************************
-
- SC-127 Board
-
- Games: Wario World II (Kirby Hack)
-
- iNES: mapper 35
-
- In MESS: Supported
-
- *************************************************************/
-
-void nes_state::sc127_irq( int scanline, int vblank, int blanked )
-{
- if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE && m_IRQ_enable)
- {
- m_IRQ_count--;
-
- if (!blanked && (m_IRQ_count == 0))
- {
- LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
- machine().primary_screen->vpos(), machine().primary_screen->hpos()));
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_enable = 0;
- }
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::sc127_w)
-{
- LOG_MMC(("sc127_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x0000:
- prg8_89(data);
- break;
- case 0x0001:
- prg8_ab(data);
- break;
- case 0x0002:
- // m_mmc_prg_bank[offset & 0x02] = data;
- prg8_cd(data);
- break;
- case 0x1000:
- case 0x1001:
- case 0x1002:
- case 0x1003:
- case 0x1004:
- case 0x1005:
- case 0x1006:
- case 0x1007:
- // m_mmc_vrom_bank[offset & 0x07] = data;
- chr1_x(offset & 0x07, data, CHRROM);
- break;
- case 0x4002:
- m_IRQ_enable = 0;
- break;
- case 0x4003:
- m_IRQ_enable = 1;
- break;
- case 0x4005:
- m_IRQ_count = data;
- break;
- case 0x5001:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board SMB2J
-
- Games: Super Mario Bros. 2 Pirate (LF36)
-
- iNES: mapper 43
-
- In MESS: Supported? The only image I found is not working
- (not even in NEStopia).
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::smb2j_w)
-{
- int bank = (((offset >> 8) & 0x03) * 0x20) + (offset & 0x1f);
-
- LOG_MMC(("smb2j_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- if (offset & 0x0800)
- {
- if (offset & 0x1000)
- {
- if (bank * 2 >= m_prg_chunks)
- {
- membank("bank3")->set_base(m_wram);
- membank("bank4")->set_base(m_wram);
- }
- else
- {
- LOG_MMC(("smb2j_w, selecting upper 16KB bank of #%02x\n", bank));
- prg16_cdef(2 * bank + 1);
- }
- }
- else
- {
- if (bank * 2 >= m_prg_chunks)
- {
- membank("bank1")->set_base(m_wram);
- membank("bank2")->set_base(m_wram);
- }
- else
- {
- LOG_MMC(("smb2j_w, selecting lower 16KB bank of #%02x\n", bank));
- prg16_89ab(2 * bank);
- }
- }
- }
- else
- {
- if (bank * 2 >= m_prg_chunks)
- {
- membank("bank1")->set_base(m_wram);
- membank("bank2")->set_base(m_wram);
- membank("bank3")->set_base(m_wram);
- membank("bank4")->set_base(m_wram);
- }
- else
- {
- LOG_MMC(("smb2j_w, selecting 32KB bank #%02x\n", bank));
- prg32(bank);
- }
- }
-}
-
-/*************************************************************
-
- BTL-SMB2B
-
- Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2)
-
- This was marked as Alt. Levels. is it true?
-
- iNES: mapper 50
-
- In MESS: Supported.
-
- *************************************************************/
-
-void nes_state::smb2jb_irq(int scanline, int vblank, int blanked )
-{
- if (m_IRQ_enable)
- {
- if (m_IRQ_count < 0x1000)
- {
- if ((0x1000 - m_IRQ_count) <= 114)
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- else
- m_IRQ_count += 114;
- }
- else
- m_IRQ_count += 114;
-
- m_IRQ_count &= 0xffff; // according to docs is 16bit counter -> it wraps only after 0xffff
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::smb2jb_l_w)
-{
- UINT8 prg;
- LOG_MMC(("smb2jb_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- switch (offset & 0x160)
- {
- case 0x020:
- prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2);
- prg8_cd(prg);
- break;
- case 0x120:
- m_IRQ_enable = data & 0x01;
- break;
- }
-}
-
-/* This goes to 0x4020-0x403f */
-WRITE8_MEMBER(nes_carts_state::smb2jb_extra_w)
-{
- UINT8 prg;
- LOG_MMC(("smb2jb_extra_w, offset: %04x, data: %02x\n", offset, data));
-
- prg = (data & 0x08) | ((data & 0x06) >> 1) | ((data & 0x01) << 2);
- prg8_cd(prg);
-}
-
-/*************************************************************
-
- Bootleg Board for Super Fighter III
-
- MMC3 clone
-
- iNES: mapper 197
-
- In MESS: Supported.
-
- *************************************************************/
-
-static void unl_sf3_set_chr( running_machine &machine, UINT8 chr_source, int chr_base, int chr_mask )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->chr4_0(chr_base | ((state->m_mmc_vrom_bank[0] >> 1) & chr_mask), chr_source);
- state->chr2_4(chr_base | (state->m_mmc_vrom_bank[1] & chr_mask), chr_source);
- state->chr2_6(chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr_source);
-}
-
-WRITE8_MEMBER(nes_carts_state::unl_sf3_w)
-{
- UINT8 mmc_helper, cmd;
- LOG_MMC(("unl_sf3_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- mmc_helper = m_mmc3_latch ^ data;
- m_mmc3_latch = data;
-
- /* Has PRG Mode changed? */
- if (mmc_helper & 0x40)
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- /* Has CHR Mode changed? */
- if (mmc_helper & 0x80)
- unl_sf3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
-
- case 0x0001:
- cmd = m_mmc3_latch & 0x0f;
- switch (cmd)
- {
- case 0: case 2: case 4:
- m_mmc_vrom_bank[cmd >> 1] = data;
- unl_sf3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
- case 6:
- case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- }
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- Bootleg Board for Xiao Zhuan Yuan
-
- Games: Shu Qi Yu - Zhi Li Xiao Zhuan Yuan
-
- Very simple mapper: writes to 0x5ff1 set prg32 (to data>>1),
- while writes to 0x5ff2 set chr8
-
- iNES: mapper 176
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::unl_xzy_l_w)
-{
- LOG_MMC(("unl_xzy_l_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset)
- {
- case 0x1ef1: /* 0x5ff1 */
- prg32(data >> 1);
- break;
- case 0x1ef2: /* 0x5ff2 */
- chr8(data, CHRROM);
- break;
- }
-}
-
-/*************************************************************
-
- Board UNL-RACERMATE
-
- In MESS: *VERY* preliminary support. Also, it seems that this
- board saves to battery the CHRRAM!!!
-
- *************************************************************/
-
-static void racmate_update_banks( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->chr4_4(state->m_mmc_latch1 & 0x0f, state->m_mmc_chr_source);
- state->prg16_89ab(state->m_mmc_latch1 >> 1);
-}
-
-WRITE8_MEMBER(nes_carts_state::unl_racmate_w)
-{
- LOG_MMC(("unl_racmate_w offset: %04x, data: %02x\n", offset, data));
-
- if (offset == 0x3000)
- {
- m_mmc_latch1 = data;
- racmate_update_banks(machine());
- }
-}
-
-
-/*************************************************************
-
- Board UNL-FS304
-
- Games: A Link to the Past by Waixing
-
- iNES: mapper 162? (only found in UNIF format)
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::unl_fs304_l_w)
-{
- LOG_MMC(("unl_fs304_l_w, offset: %04x, data: %02x\n", offset, data));
- int bank;
- offset += 0x100;
-
- if (offset >= 0x1000)
- {
- m_mmc_reg[(offset >> 8) & 3] = data;
- bank = ((m_mmc_reg[2] & 0x0f) << 4) | BIT(m_mmc_reg[1], 1) | (m_mmc_reg[0] & 0x0e);
- prg32(bank);
- chr8(0, CHRRAM);
- }
-}
-
-
-/*************************************************************
-
- BOOTLEG CART VERSIONS OF FDS GAMES
-
- *************************************************************/
-
-/*************************************************************
-
- BTL-SUPERBROS11
-
- Games: Super Mario Bros. 11, Super Mario Bros. 17
-
- This acts basically like a MMC3 with different use of write
- address.
-
- iNES: mapper 196
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::btl_smb11_w)
-{
- LOG_MMC(("btl_smb11_w, offset: %04x, data: %02x\n", offset, data));
-
- txrom_w(space, (offset & 0x6000) | ((offset & 0x04) >> 2), data, mem_mask);
-}
-
-/*************************************************************
-
- BTL-MARIOBABY
-
- Games: Mario Baby, Ai Senshi Nicol
-
- iNES: mapper 42
-
- In MESS: Supported.
-
- *************************************************************/
-
-// is the code fine for ai senshi nicol?!?
-WRITE8_MEMBER(nes_carts_state::btl_mariobaby_w)
-{
- LOG_MMC(("btl_mariobaby_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset >= 0x7000)
- {
- switch (offset & 0x03)
- {
- case 0x00:
- prg8_67(data);
- break;
- case 0x01:
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 0x02:
- /* Check if IRQ is being enabled */
- if (!m_IRQ_enable && (data & 0x02))
- {
- m_IRQ_enable = 1;
- m_irq_timer->adjust(downcast<cpu_device *>(m_maincpu)->cycles_to_attotime(24576));
- }
- if (!(data & 0x02))
- {
- m_IRQ_enable = 0;
- m_irq_timer->adjust(attotime::never);
- }
- break;
- }
- }
-}
-
-/*************************************************************
-
- BTL-SMB2A
-
- Games: Super Mario Bros. 2 Pirate (Jpn version of SMB2)
-
- iNES: mapper 40
-
- In MESS: Supported.
-
- *************************************************************/
-
-void nes_state::btl_smb2a_irq( int scanline, int vblank, int blanked )
-{
- if (m_IRQ_enable)
- {
- if ((0xfff - m_IRQ_count) <= 114)
- {
- m_IRQ_count = (m_IRQ_count + 1) & 0xfff;
- m_IRQ_enable = 0;
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- else
- m_IRQ_count += 114;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::btl_smb2a_w)
-{
- LOG_MMC(("btl_smb2a_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6000)
- {
- case 0x0000:
- m_IRQ_enable = 0;
- m_IRQ_count = 0;
- break;
- case 0x2000:
- m_IRQ_enable = 1;
- break;
- case 0x6000:
- prg8_cd(data);
- break;
- }
-}
-
-/*************************************************************
-
- WHIRLWIND-2706
-
- Games: Meikyuu Jiin Dababa (FDS conversion)
-
- iNES: mapper 108
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::whirl2706_w)
-{
- LOG_MMC(("whirl2706_w, offset: %04x, data: %02x\n", offset, data));
- prg8_67(data);
-}
-
-/*************************************************************
-
- Bootleg Board used for FDS conversion
-
- Games: Tobidase Daisakusen (FDS conversion)
-
- iNES: mapper 120
-
- In MESS: Partially Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::btl_tobi_l_w)
-{
- LOG_MMC(("btl_tobi_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if ((offset & 0x43c0) == 0x41c0)
- prg8_67(data & 0x07);
-}
-
-/*************************************************************
-
- BTL-SMB3
-
- Games: Super Mario Bros. 3 Pirate
-
- iNES: mapper 106
-
- In MESS: Supported.
-
- *************************************************************/
-
-void nes_state::btl_smb3_irq( int scanline, int vblank, int blanked )
-{
- if (m_IRQ_enable)
- {
- if ((0xffff - m_IRQ_count) < 114)
- {
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- m_IRQ_enable = 0;
- }
-
- m_IRQ_count = (m_IRQ_count + 114) & 0xffff;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::btl_smb3_w)
-{
- LOG_MMC(("btl_smb3_w, offset: %04x, data: %02x\n", offset, data));
- switch (offset & 0x0f)
- {
- case 0x00:
- case 0x02:
- chr1_x(offset & 0x07, data & 0xfe, CHRROM);
- break;
- case 0x01:
- case 0x03:
- chr1_x(offset & 0x07, data | 0x01, CHRROM);
- break;
- case 0x04: case 0x05:
- case 0x06: case 0x07:
- chr1_x(offset & 0x07, data, CHRROM);
- break;
- case 0x08:
- prg8_89(data | 0x10);
- break;
- case 0x09:
- prg8_ab(data);
- break;
- case 0x0a:
- prg8_cd(data);
- break;
- case 0x0b:
- prg8_ef(data | 0x10);
- break;
- case 0x0c:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 0x0d:
- m_IRQ_count = 0;
- m_IRQ_enable = 0;
- break;
- case 0x0e:
- m_IRQ_count = (m_IRQ_count & 0xff00) | data;
- break;
- case 0x0f:
- m_IRQ_count = (m_IRQ_count & 0x00ff) | (data << 8);
- m_IRQ_enable = 1;
- break;
- }
-}
-
-/*************************************************************
-
- BTL-DRAGONNINJA
-
- Games: Dragon Ninja (Bootleg), Super Mario Bros. 8
-
- iNES: mapper 222
-
- In MESS: Unsupported.
-
- *************************************************************/
-
-/* Scanline based IRQ ? */
-void nes_state::btl_dn_irq(int scanline, int vblank, int blanked )
-{
- if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
- {
- if (!m_IRQ_count || ++m_IRQ_count < 240)
- return;
-
- m_IRQ_count = 0;
- LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
- machine().primary_screen->vpos(), machine().primary_screen->hpos()));
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::btl_dn_w)
-{
- UINT8 bank;
- LOG_MMC(("btl_dn_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x7003)
- {
- case 0x0000:
- prg8_89(data);
- break;
- case 0x1000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
- case 0x2000:
- prg8_ab(data);
- break;
- case 0x3000:
- case 0x3002:
- case 0x4000:
- case 0x4002:
- case 0x5000:
- case 0x5002:
- case 0x6000:
- case 0x6002:
- bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0002) >> 3);
- chr1_x(bank, data, CHRROM);
- break;
- case 0x7000:
- m_IRQ_count = data;
- break;
- }
-}
-
-/*************************************************************
-
- BTL-PIKACHUY2K
-
- Games: Pikachu Y2k
-
- iNES: mapper 254
-
- In MESS:
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::btl_pika_y2k_w)
-{
- LOG_MMC(("btl_pika_y2k_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x2001:
- m_mmc_latch2 = data;
- break;
-
- case 0x2000:
- m_mmc_reg[0] = 0;
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-// strange WRAM usage: it is protected at start, and gets unprotected after the first write to 0xa000
-WRITE8_MEMBER(nes_carts_state::btl_pika_y2k_m_w)
-{
- LOG_MMC(("btl_pika_y2k_m_w, offset: %04x, data: %02x\n", offset, data));
-
- m_wram[offset] = data;
-}
-
-READ8_MEMBER(nes_carts_state::btl_pika_y2k_m_r)
-{
- LOG_MMC(("btl_pika_y2k_m_r, offset: %04x\n", offset));
-
- return m_wram[offset] ^ (m_mmc_latch2 & m_mmc_reg[0]);
-}
-
-/*************************************************************
-
- MULTICART
-
- *************************************************************/
-
-/*************************************************************
-
- Board BMC-FK23C
-
- In MESS: partially supported (still to sort initial banking
- for many games)
-
- *************************************************************/
-
-#if 0
-static void fk23c_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (((state->m_mmc_reg[0] & 0x07) - 3) > 1 && (!(state->m_mmc_reg[3] & 0x02) || start < 2))
- {
- if (state->m_mmc_reg[0] & 0x03)
- bank = (bank & (0x3f >> (state->m_mmc_reg[0] & 0x03))) | (state->m_mmc_reg[1] << 1);
-
- state->prg8_x(start, bank);
- }
-}
-
-static void fk23c_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (!(state->m_mmc_reg[0] & 0x40) && (!(state->m_mmc_reg[3] & 0x02) || (start != 1 && start != 3)))
- state->chr1_x(start, ((state->m_mmc_reg[2] & 0x7f) << 3) | bank, source);
-}
-
-#endif
-
-static void fk23c_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 mask = (0x3f >> (state->m_mmc_reg[0] & 0x03));
-
- if ((state->m_mmc_reg[0] & 0x07) < 3)
- {
- if (!(state->m_mmc_reg[0] & 0x03))
- bank = (bank & mask) | ((state->m_mmc_reg[1] & (0x7f ^ mask)) << 1);
-
- state->prg8_x(start, bank);
- }
-}
-
-static void fk23c_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (!(state->m_mmc_reg[0] & 0x40) && (!(state->m_mmc_reg[3] & 0x02) || (start != 1 && start != 3)))
- state->chr1_x(start, ((state->m_mmc_reg[2] & 0x7f) << 3) | bank, source);
-}
-
-static void fk23c_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if ((state->m_mmc_reg[0] & 0x07) == 4)
- state->prg32((state->m_mmc_reg[1] & 0x7f) >> 1);
- else if ((state->m_mmc_reg[0] & 0x07) == 3)
- {
- state->prg16_89ab(state->m_mmc_reg[1] & 0x7f);
- state->prg16_cdef(state->m_mmc_reg[1] & 0x7f);
- }
- else
- {
- if (state->m_mmc_reg[3] & 0x02)
- {
- state->prg8_cd(state->m_mmc_reg[4]);
- state->prg8_ef(state->m_mmc_reg[5]);
- }
- else
- mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
- }
-}
-
-static void fk23c_set_chr( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (state->m_mmc_reg[0] & 0x40)
- state->chr8(state->m_mmc_reg[2] | state->m_mmc_cmd1, state->m_mmc_chr_source);
- else
+ for (int i = 0; i < ARRAY_LENGTH(pcb_list); i++)
{
- if (state->m_mmc_reg[3] & 0x02)
- {
- int base = (state->m_mmc_reg[2] & 0x7f) << 3;
- state->chr1_x(1, base | state->m_mmc_reg[6], state->m_mmc_chr_source);
- state->chr1_x(3, base | state->m_mmc_reg[7], state->m_mmc_chr_source);
- }
- else
- mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::fk23c_l_w)
-{
- LOG_MMC(("fk23c_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset >= 0x1000)
- {
- if (offset & (1 << 4)) // here it should be (4 + m_mmc_dipsetting)
- {
- m_mmc_reg[offset & 0x03] = data;
-
- fk23c_set_prg(machine());
- fk23c_set_chr(machine());
- }
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::fk23c_w)
-{
- LOG_MMC(("fk23c_w, offset: %04x, data: %02x\n", offset, data));
-
- if (m_mmc_reg[0] & 0x40)
- {
- if (m_mmc_reg[0] & 0x30)
- m_mmc_cmd1 = 0;
- else
- {
- m_mmc_cmd1 = data & 0x03;
- fk23c_set_chr(machine());
- }
- }
- else
- {
- switch (offset & 0x6001)
- {
- case 0x0001:
- if ((m_mmc_reg[3] & 0x02) && (m_mmc3_latch & 0x08))
- {
- m_mmc_reg[4 | (m_mmc3_latch & 0x03)] = data;
- fk23c_set_prg(machine());
- fk23c_set_chr(machine());
- }
- else
- txrom_w(space, offset, data, mem_mask);
- break;
-
- case 0x2000:
- set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
- }
-}
-
-
-/*************************************************************
-
- Board BMC-64IN1NOREPEAT
-
- Games: 64-in-1 Y2K
-
- In MESS: Supported
-
- *************************************************************/
-
-static void bmc_64in1nr_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 helper1 = (state->m_mmc_reg[1] & 0x1f);
- UINT8 helper2 = (helper1 << 1) | ((state->m_mmc_reg[1] & 0x40) >> 6);
-
- if (state->m_mmc_reg[0] & 0x80)
- {
- if (state->m_mmc_reg[1] & 0x80)
- state->prg32(helper1);
- else
- {
- state->prg16_89ab(helper2);
- state->prg16_cdef(helper2);
- }
- }
- else
- state->prg16_cdef(helper2);
-}
-
-WRITE8_MEMBER(nes_carts_state::bmc_64in1nr_l_w)
-{
- LOG_MMC(("bmc_64in1nr_l_w offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- switch (offset)
- {
- case 0x1000:
- case 0x1001:
- case 0x1002:
- case 0x1003:
- m_mmc_reg[offset & 0x03] = data;
- bmc_64in1nr_set_prg(machine());
- chr8(((m_mmc_reg[0] >> 1) & 0x03) | (m_mmc_reg[2] << 2), CHRROM);
- break;
- }
- if (offset == 0x1000) /* reg[0] also sets mirroring */
- set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-}
-
-WRITE8_MEMBER(nes_carts_state::bmc_64in1nr_w)
-{
- LOG_MMC(("bmc_64in1nr_w offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_reg[3] = data; // reg[3] is currently unused?!?
-}
-
-/*************************************************************
-
- Board BMC-190IN1
-
- Games: 190-in-1
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_190in1_w)
-{
- LOG_MMC(("bmc_190in1_w offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- offset >>= 2;
- prg16_89ab(offset);
- prg16_cdef(offset);
- chr8(offset, CHRROM);
-}
-
-/*************************************************************
-
- Board BMC-A65AS
-
- Games: 3-in-1 (N068)
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_a65as_w)
-{
- UINT8 helper = (data & 0x30) >> 1;
- LOG_MMC(("bmc_a65as_w offset: %04x, data: %02x\n", offset, data));
-
- if (data & 0x80)
- set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
- else
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- if (data & 0x40)
- prg32(data >> 1);
- else
- {
- prg16_89ab(helper | (data & 0x07));
- prg16_cdef(helper | 0x07);
- }
-}
-
-/*************************************************************
-
- Board BMC-GS2004
-
- Games: Tetris Family 6-in-1
-
- In MESS: Preliminary Support. It also misses WRAM handling
- (we need reads from 0x6000-0x7fff)
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_gs2004_w)
-{
- LOG_MMC(("bmc_gs2004_w offset: %04x, data: %02x\n", offset, data));
-
- prg32(data);
-}
-
-/*************************************************************
-
- Board BMC-GS2013
-
- Games: Tetris Family 12-in-1
-
- In MESS: Preliminary Support. It also misses WRAM handling
- (we need reads from 0x6000-0x7fff)
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_gs2013_w)
-{
- LOG_MMC(("bmc_gs2013_w offset: %04x, data: %02x\n", offset, data));
-
- if (data & 0x08)
- prg32(data & 0x09);
- else
- prg32(data & 0x07);
-}
-
-/*************************************************************
-
- Board BMC-SUPER24IN1SC03
-
- Games: Super 24-in-1
-
- In MESS: Partially Supported
-
- *************************************************************/
-
-static void bmc_s24in1sc03_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
- static const UINT8 masks[8] = {0x3f, 0x1f, 0x0f, 0x01, 0x03, 0x00, 0x00, 0x00};
- int prg_base = state->m_mmc_reg[1] << 1;
- int prg_mask = masks[state->m_mmc_reg[0] & 0x07];
-
- bank = prg_base | (bank & prg_mask);
- state->prg8_x(start, bank);
-}
-
-static void bmc_s24in1sc03_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr = BIT(state->m_mmc_reg[0], 5) ? CHRRAM : CHRROM;
- int chr_base = (state->m_mmc_reg[2] << 3) & 0xf00;
-
- state->chr1_x(start, chr_base | bank, chr);
-}
-
-WRITE8_MEMBER(nes_carts_state::bmc_s24in1sc03_l_w)
-{
- LOG_MMC(("bmc_s24in1sc03_l_w offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset == 0x1ff0)
- {
- m_mmc_reg[0] = data;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- }
-
- if (offset == 0x1ff1)
- {
- m_mmc_reg[1] = data;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- }
-
- if (offset == 0x1ff2)
- {
- m_mmc_reg[2] = data;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
-}
-
-/*************************************************************
-
- Board BMC-T-262
-
- Games: 4-in-1 (D-010), 8-in-1 (A-020)
-
- In MESS: Supported
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_t262_w)
-{
- UINT8 mmc_helper;
- LOG_MMC(("bmc_t262_w offset: %04x, data: %02x\n", offset, data));
-
- if (m_mmc_latch2 || offset == 0)
- {
- m_mmc_latch1 = (m_mmc_latch1 & 0x38) | (data & 0x07);
- prg16_89ab(m_mmc_latch1);
- }
- else
- {
- m_mmc_latch2 = 1;
- set_nt_mirroring(BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- mmc_helper = ((offset >> 3) & 0x20) | ((offset >> 2) & 0x18);
- m_mmc_latch1 = mmc_helper | (m_mmc_latch1 & 0x07);
- prg16_89ab(m_mmc_latch1);
- prg16_cdef(mmc_helper | 0x07);
- }
-}
-
-/*************************************************************
-
- Board BMC-WS
-
- Games: Super 40-in-1
-
- In MESS: Partially Supported (some games, like Galaxian, have
- issues)
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_ws_m_w)
-{
- UINT8 mmc_helper;
- LOG_MMC(("bmc_ws_m_w offset: %04x, data: %02x\n", offset, data));
-
- if (offset < 0x1000)
- {
- switch (offset & 0x01)
- {
- case 0:
- if (!m_mmc_latch1)
- {
- m_mmc_latch1 = data & 0x20;
- set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- mmc_helper = (~data & 0x08) >> 3;
- prg16_89ab(data & ~mmc_helper);
- prg16_cdef(data | mmc_helper);
- }
- break;
- case 1:
- if (!m_mmc_latch1)
- {
- chr8(data, CHRROM);
- }
- break;
- }
- }
-}
-
-/*************************************************************
-
- BMC-NOVELDIAMOND and BMC-999999in1
-
- Unknown Bootleg Multigame Board
- Games: I only found 'Novel Diamond 999999-in-1.unf' using
- this mapper (hence the code is used for BMC_NOVELDIAMOND
- board). The code is included here in case a mapper 54
- dump arises.
-
- iNES: mappers 54 and 213
-
- In MESS: Partial Support.
-
- *************************************************************/
-
-// Are this correct or should they work the same?
-WRITE8_MEMBER(nes_carts_state::novel1_w)
-{
- LOG_MMC(("novel1_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(offset & 0x03);
- chr8(offset & 0x07, CHRROM);
-}
-
-WRITE8_MEMBER(nes_carts_state::novel2_w)
-{
- LOG_MMC(("novel2_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(offset >> 1);
- chr8(offset >> 3, CHRROM);
-}
-
-/*************************************************************
-
- Board BMC-GKA
-
- Unknown Bootleg Multigame Board
- Games: 6 in 1, 54 in 1, 106 in 1
-
- iNES: mapper 57
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_gka_w)
-{
- LOG_MMC(("bmc_gka_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset & 0x0800)
- m_mmc_latch2 = data;
- else
- m_mmc_latch1 = data;
-
- if (m_mmc_latch2 & 0x80)
- prg32(2 | (m_mmc_latch2 >> 6));
- else
- {
- prg16_89ab((m_mmc_latch2 >> 5) & 0x03);
- prg16_cdef((m_mmc_latch2 >> 5) & 0x03);
- }
-
- set_nt_mirroring((m_mmc_latch2 & 0x08) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- chr8((m_mmc_latch1 & 0x03) | (m_mmc_latch2 & 0x07) | ((m_mmc_latch2 & 0x10) >> 1), CHRROM);
-}
-
-
-/*************************************************************
-
- Board UNL-STUDYNGAME
-
- Games: Study n Game 32 in 1
-
- iNES: mapper 39
-
- In MESS: Partially Supported (problems with PRG bankswitch,
- only keyboard exercise work).
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::sng32_w)
-{
- LOG_MMC(("sng32_w, offset: %04x, data: %02x\n", offset, data));
- prg32(data);
-}
-
-/*************************************************************
-
- Board BMC-GKB
-
- Unknown Bootleg Multigame Board
- Games: 68 in 1, 73 in 1, 98 in 1
-
- iNES: mapper 58
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_gkb_w)
-{
- UINT8 bank = (offset & 0x40) ? 0 : 1;
- LOG_MMC(("bmc_gkb_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab(offset & ~bank);
- prg16_cdef(offset | bank);
- chr8(offset >> 3, m_mmc_chr_source);
- set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-}
-
-/*************************************************************
-
- BMC-SUPER-700IN1
-
- Unknown Bootleg Multigame Board
- Games: Super 700 in 1
-
- iNES: mapper 62
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_super700in1_w)
-{
- LOG_MMC(("bmc_super700in1_w, offset :%04x, data: %02x\n", offset, data));
-
- chr8(((offset & 0x1f) << 2) | (data & 0x03), CHRROM);
-
- if (offset & 0x20)
- {
- prg16_89ab((offset & 0x40) | ((offset >> 8) & 0x3f));
- prg16_cdef((offset & 0x40) | ((offset >> 8) & 0x3f));
- }
- else
- {
- prg32(((offset & 0x40) | ((offset >> 8) & 0x3f)) >> 1);
- }
-
- set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-}
-
-/*************************************************************
-
- BMC-36IN1
-
- Unknown Bootleg Multigame Board
- Games: 36 in 1, 1200 in 1
-
- iNES: mapper 200
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_36in1_w)
-{
- LOG_MMC(("bmc_36in1_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab(offset & 0x07);
- prg16_cdef(offset & 0x07);
- chr8(offset & 0x07, CHRROM);
-
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-}
-
-/*************************************************************
-
- BMC-21IN1
-
- Unknown Bootleg Multigame Board
- Games: 8 in 1, 21 in 1
-
- iNES: mapper 201
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_21in1_w)
-{
- LOG_MMC(("bmc_21in1_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(offset & 0x03);
- chr8(offset & 0x03, CHRROM);
-}
-
-/*************************************************************
-
- BMC-150IN1
-
- Unknown Bootleg Multigame Board
- Games: 150 in 1
-
- iNES: mapper 202
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_150in1_w)
-{
- int bank = (offset >> 1) & 0x07;
-
- LOG_MMC(("bmc_150in1_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab(bank);
- prg16_cdef(bank + (((bank & 0x06) == 0x06) ? 1 : 0));
- chr8(bank, CHRROM);
-
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT);
-}
-
-/*************************************************************
-
- BMC-35IN1
-
- Unknown Bootleg Multigame Board
- Games: 35 in 1
-
- iNES: mapper 203
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_35in1_w)
-{
- LOG_MMC(("bmc_35in1_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab((data >> 2) & 0x03);
- prg16_cdef((data >> 2) & 0x03);
- chr8(data & 0x03, CHRROM);
-}
-
-/*************************************************************
-
- BMC-64IN1
-
- Unknown Bootleg Multigame Board
- Games: 64 in 1
-
- iNES: mapper 204
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_64in1_w)
-{
- int bank = (offset >> 1) & (offset >> 2) & 0x01;
-
- LOG_MMC(("bmc_64in1_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab(offset & ~bank);
- prg16_cdef(offset | bank);
- chr8(offset & ~bank, CHRROM);
-
- set_nt_mirroring(BIT(data, 4) ? PPU_MIRROR_HORZ: PPU_MIRROR_VERT);
-}
-
-/*************************************************************
-
- BMC-15IN1
-
- Unknown Bootleg Multigame Board
- Games: 3 in 1, 15 in 1
-
- iNES: mapper 205, MMC3 clone
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_15in1_m_w)
-{
- LOG_MMC(("bmc_15in1_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset & 0x0800)
- {
- m_mmc_prg_base = (data & 0x03) << 4;
- m_mmc_prg_mask = (data & 0x02) ? 0x0f : 0x1f;
- m_mmc_chr_base = (data & 0x03) << 7;
- m_mmc_chr_mask = (data & 0x02) ? 0x7f : 0xff;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
-}
-
-/*************************************************************
-
- BMC-SUPERHIK_300IN1
-
- Unknown Bootleg Multigame Board
- Games: 100000 in 1, Super HIK 300 in 1, 1997 in 1
-
- iNES: mapper 212
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_hik300_w)
-{
- LOG_MMC(("bmc_hik300_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- chr8(offset, CHRROM);
-
- if (offset < 0x4000)
- {
- prg16_89ab(offset);
- prg16_cdef(offset);
- }
- else
- prg32(offset >> 1);
-}
-
-/*************************************************************
-
- BMC-SUPERGUN-20IN1
-
- Unknown Bootleg Multigame Board
- Games: Super Gun 20 in 1
-
- iNES: mapper 214
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::supergun20in1_w)
-{
- LOG_MMC(("supergun20in1_w, offset: %04x, data: %02x\n", offset, data));
-
- prg16_89ab(offset >> 2);
- prg16_cdef(offset >> 2);
- chr8(offset, CHRROM);
-}
-
-/*************************************************************
-
- BMC-72IN1
-
- Unknown Bootleg Multigame Board
- Games: 72 in 1, 115 in 1 and other multigame carts
-
- iNES: mapper 225
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_72in1_w)
-{
- int hi_bank;
- int size_16;
- int bank;
-
- LOG_MMC(("bmc_72in1_w, offset: %04x, data: %02x\n", offset, data));
-
- chr8(offset, CHRROM);
- set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- hi_bank = offset & 0x40;
- size_16 = offset & 0x1000;
- bank = (offset & 0xf80) >> 7;
- if (size_16)
- {
- bank <<= 1;
- if (hi_bank)
- bank ++;
-
- prg16_89ab(bank);
- prg16_cdef(bank);
- }
- else
- prg32(bank);
-}
-
-/*************************************************************
-
- BMC-76IN1
-
- Unknown Bootleg Multigame Board
- Games: 76 in 1, Super 42 in 1
-
- iNES: mapper 226
-
- In MESS: Supported.
-
- *************************************************************/
-
-// does this work for super42in1 as well?!?
-WRITE8_MEMBER(nes_carts_state::bmc_76in1_w)
-{
- int hi_bank;
- int size_16;
- int bank;
-
- LOG_MMC(("bmc_76in1_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset & 0x01)
- m_mmc_latch2 = data;
- else
- m_mmc_latch1 = data;
-
- set_nt_mirroring(BIT(m_mmc_latch1, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- hi_bank = m_mmc_latch1 & 0x01;
- size_16 = m_mmc_latch1 & 0x20;
- bank = ((m_mmc_latch1 & 0x1e) >> 1) | ((m_mmc_latch1 & 0x80) >> 3) | ((m_mmc_latch2 & 0x01) << 5);
-
- if (size_16)
- {
- bank <<= 1;
- if (hi_bank)
- bank ++;
-
- prg16_89ab(bank);
- prg16_cdef(bank);
+ if (pcb_list[i].pcb_id == id)
+ return &pcb_list[i];
}
- else
- prg32(bank);
+ return NULL;
}
-/*************************************************************
-
- BMC-1200IN1
-
- Unknown Bootleg Multigame Board
- Games: 1200 in 1, 295 in 1, 76 in 1
-
- iNES: mapper 227
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_1200in1_w)
+int nes_cart_slot_device::nes_get_pcb_id( const char *slot )
{
- int hi_bank;
- int size_32;
- int bank;
-
- LOG_MMC(("bmc_1200in1_w, offset: %04x, data: %02x\n", offset, data));
+ const nes_pcb *pcb = nes_pcb_lookup(slot);
- hi_bank = offset & 0x04;
- size_32 = offset & 0x01;
- bank = ((offset & 0x78) >> 3) | ((offset & 0x0100) >> 4);
- if (!size_32)
- {
- bank <<= 1;
- if (hi_bank)
- bank ++;
-
- prg16_89ab(bank);
- prg16_cdef(bank);
- }
- else
- prg32(bank);
-
- if (!(offset & 0x80))
- {
- if (offset & 0x200)
- prg16_cdef(((bank << 1) & 0x38) + 7);
- else
- prg16_cdef(((bank << 1) & 0x38));
- }
+ if (pcb == NULL)
+ fatalerror("Unimplemented PCB type %s\n", slot);
- set_nt_mirroring(BIT(data, 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ return pcb->pcb_id;
}
-/*************************************************************
-
- BMC-31IN1
-
- Unknown Bootleg Multigame Board
- Games: 31 in 1
- iNES: mapper 229
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_31in1_w)
+const char * nes_cart_slot_device::nes_get_slot( int pcb_id )
{
- LOG_MMC(("bmc_31in1_w, offset: %04x, data: %02x\n", offset, data));
+ const nes_pcb *pcb = nes_id_lookup(pcb_id);
- set_nt_mirroring(BIT(data, 5) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- chr8(offset, CHRROM);
+ if (pcb == NULL)
+ fatalerror("Unimplemented PCB ID %d\n", pcb_id);
- if ((offset & 0x1e) == 0)
- {
- prg16_89ab(0);
- prg16_89ab(1);
- }
- else
- {
- prg16_89ab(offset & 0x1f);
- prg16_89ab(offset & 0x1f);
- }
+ return pcb->slot_opt;
}
-/*************************************************************
-
- BMC-22GAMES
-
- Unknown Bootleg Multigame Board
- Games: 22 in 1
-
- iNES: mapper 230
-
- In MESS: Partially Supported. It would need a reset
- to work (not possible yet)
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_22g_w)
-{
- LOG_MMC(("bmc_22g_w, offset: %04x, data: %02x\n", offset, data));
-
- if (1) // this should flip at reset
- {
- prg16_89ab(data & 0x07);
- }
- else
- {
- if (data & 0x20)
- {
- prg16_89ab((data & 0x1f) + 8);
- prg16_cdef((data & 0x1f) + 8);
- }
- else
- {
- prg16_89ab((data & 0x1f) + 8);
- prg16_cdef((data & 0x1f) + 9);
- }
- set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- }
-}
/*************************************************************
- BMC-20IN1
-
- Unknown Bootleg Multigame Board
- Games: 20 in 1
+ nes_pcb_reset
- iNES: mapper 231
+ Resets the mmc bankswitch areas to their defaults.
+ It returns a value "err" that indicates if it was
+ successful. Possible values for err are:
- In MESS: Supported.
+ 0 = success
+ 1 = no pcb found
+ 2 = pcb not supported
*************************************************************/
-WRITE8_MEMBER(nes_carts_state::bmc_20in1_w)
+struct nes_cart_lines
{
- LOG_MMC(("bmc_20in1_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- prg16_89ab((offset & 0x1e));
- prg16_cdef((offset & 0x1e) | ((offset & 0x20) ? 1 : 0));
-}
-
-/*************************************************************
-
- BMC-110IN1
-
- Known Boards: Unknown Bootleg Board
- Games: 110 in 1
-
- iNES: mapper 255
-
- In MESS: Preliminary support.
+ const char *tag;
+ int line;
+};
- *************************************************************/
+static const struct nes_cart_lines nes_cart_lines_table[] =
+{
+ { "PRG A0", 0 },
+ { "PRG A1", 1 },
+ { "PRG A2", 2 },
+ { "PRG A3", 3 },
+ { "PRG A4", 4 },
+ { "PRG A5", 5 },
+ { "PRG A6", 6 },
+ { "PRG A7", 7 },
+ { "CHR A10", 10 },
+ { "CHR A11", 11 },
+ { "CHR A12", 12 },
+ { "CHR A13", 13 },
+ { "CHR A14", 14 },
+ { "CHR A15", 15 },
+ { "CHR A16", 16 },
+ { "CHR A17", 17 },
+ { "NC", 127 },
+ { 0 }
+};
-WRITE8_MEMBER(nes_carts_state::bmc_110in1_w)
+static int nes_cart_get_line( const char *feature )
{
- UINT8 map255_helper1 = (offset >> 12) ? 0 : 1;
- UINT8 map255_helper2 = ((offset >> 8) & 0x40) | ((offset >> 6) & 0x3f);
-
- LOG_MMC(("bmc_110in1_w, offset: %04x, data: %02x\n", offset, data));
-
- set_nt_mirroring((offset & 0x2000) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- prg16_89ab(map255_helper1 & ~map255_helper2);
- prg16_cdef(map255_helper1 | map255_helper2);
- chr8(((offset >> 8) & 0x40) | (offset & 0x3f), CHRROM);
-}
+ const struct nes_cart_lines *nes_line = &nes_cart_lines_table[0];
-/*************************************************************
-
- BMC-SUPERBIG-7IN1
-
- Known Boards: Unknown Multigame Bootleg Board
- Games: Kunio 8 in 1, Super Big 7 in 1
-
- iNES: mapper 44
-
- In MESS: Supported. It also uses mmc3_irq.
+ if (feature == NULL)
+ return 128;
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_sbig7_w)
-{
- UINT8 page;
- LOG_MMC(("bmc_sbig7_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
+ while (nes_line->tag)
{
- case 0x2001: /* $a001 - Select 128K ROM/VROM base (0..5) or last 256K ROM/VRAM base (6) */
- page = (data & 0x07);
- if (page > 6)
- page = 6;
-
- m_mmc_prg_base = page << 4;
- m_mmc_prg_mask = (page > 5) ? 0x1f : 0x0f;
- m_mmc_chr_base = page << 7;
- m_mmc_chr_mask = (page > 5) ? 0xff : 0x7f;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
+ if (strcmp(nes_line->tag, feature) == 0)
break;
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
+ nes_line++;
}
-}
-
-/*************************************************************
-
- BMC-HIK8IN1
-
- Known Boards: Unknown Multigame Bootleg Board
- Games: Street Fighter V, various multigame carts
-
- iNES: mapper 45
-
- In MESS: Supported. It also uses mmc3_irq.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_hik8_m_w)
-{
- LOG_MMC(("bmc_hik8_m_w, offset: %04x, data: %02x\n", offset, data));
-
- /* This bit is the "register lock". Once register are locked, writes go to WRAM
- and there is no way to unlock them (except by resetting the machine) */
- if ((m_mmc_reg[3] & 0x40) && m_wram != NULL)
- m_wram[offset] = data;
- else
- {
- m_mmc_reg[m_mmc_count] = data;
- m_mmc_count = (m_mmc_count + 1) & 0x03;
-
- if (!m_mmc_count)
- {
- LOG_MMC(("bmc_hik8_m_w, command completed %02x %02x %02x %02x\n", m_mmc_reg[3],
- m_mmc_reg[2], m_mmc_reg[1], m_mmc_reg[0]));
- m_mmc_prg_base = m_mmc_reg[1];
- m_mmc_prg_mask = 0x3f ^ (m_mmc_reg[3] & 0x3f);
- m_mmc_chr_base = ((m_mmc_reg[2] & 0xf0) << 4) | m_mmc_reg[0];
- if (BIT(m_mmc_reg[2], 3))
- m_mmc_chr_mask = (1 << ((m_mmc_reg[2] & 7) + 1)) - 1;
- else if (m_mmc_reg[2])
- m_mmc_chr_mask = 0;
- else
- m_mmc_chr_mask = 0xff; // i.e. we use the vrom_bank with no masking
-
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
- }
+ return nes_line->line;
}
-/*************************************************************
-
- BMC-SUPERHIK-4IN1
-
- Known Boards: Unknown Multigame Bootleg Board
- Games: Super HIK 4 in 1
-
- iNES: mapper 49
-
- In MESS: Supported. It also uses mmc3_irq.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_hik4in1_m_w)
+void nes_cart_slot_device::call_load_pcb()
{
- LOG_MMC(("bmc_hik4in1_m_w, offset: %04x, data: %02x\n", offset, data));
+ UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_sram_size = 0;
+ // SETUP step 1: getting PRG, VROM, VRAM sizes
+ UINT32 prg_size = get_software_region_length("prg");
+ UINT32 vrom_size = get_software_region_length("chr");
+ vram_size = get_software_region_length("vram");
+ vram_size += get_software_region_length("vram2");
- /* mid writes only work when WRAM is enabled. not sure if I should
- change the condition to m_mmc_latch2==0x80 (i.e. what is the effect of
- the read-only bit?) */
- if (m_mmc3_wram_protect & 0x80)
- {
- if (data & 0x01) /* if this is 0, then we have 32k PRG blocks */
- {
- m_mmc_prg_base = (data & 0xc0) >> 2;
- m_mmc_prg_mask = 0x0f;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- }
- else
- prg32((data & 0x30) >> 4);
-
- m_mmc_chr_base = (data & 0xc0) << 1;
- m_mmc_chr_mask = 0x7f;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
-}
-
-/*************************************************************
-
- BMC-BALLGAMES-11IN1
-
- Known Boards: Unknown Multigame Bootleg Board
- Games: 11 in 1 Ball Games
-
- iNES: mapper 51
+ // validate the xml fields
+ if (!prg_size)
+ fatalerror("No PRG entry for this software! Please check if the xml list got corrupted\n");
+ if (prg_size < 0x8000)
+ fatalerror("PRG entry is too small! Please check if the xml list got corrupted\n");
- In MESS: Partially Supported.
-
- *************************************************************/
-
-static void bmc_ball11_set_banks( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->set_nt_mirroring((state->m_mmc_reg[0] == 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- if (state->m_mmc_reg[0] & 0x01)
- {
- state->prg32(state->m_mmc_reg[1]);
- }
+ // SETUP step 2: getting PCB and other settings
+ if (get_feature("slot"))
+ m_pcb_id = nes_get_pcb_id(get_feature("slot"));
else
- {
- state->prg16_89ab((state->m_mmc_reg[1] << 1) | (state->m_mmc_reg[0] >> 1));
- state->prg16_cdef((state->m_mmc_reg[1] << 1) | 0x07);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::bmc_ball11_m_w)
-{
- LOG_MMC(("bmc_ball11_m_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_reg[0] = ((data >> 1) & 0x01) | ((data >> 3) & 0x02);
- bmc_ball11_set_banks(machine());
-}
+ m_pcb_id = NO_BOARD;
-WRITE8_MEMBER(nes_carts_state::bmc_ball11_w)
-{
- LOG_MMC(("bmc_ball11_w, offset: %04x, data: %02x\n", offset, data));
+ // SETUP step 3: storing the info needed for emulation
+ if (get_software_region("bwram") != NULL)
+ battery_size = get_software_region_length("bwram");
- switch (offset & 0x6000)
+ if (m_pcb_id == BANDAI_LZ93EX1 || m_pcb_id == BANDAI_LZ93EX2)
{
- case 0x4000: // here we also update reg[0] upper bit
- m_mmc_reg[0] = (m_mmc_reg[0] & 0x01) | ((data >> 3) & 0x02);
- case 0x0000:
- case 0x2000:
- case 0x6000:
- m_mmc_reg[1] = data & 0x0f;
- bmc_ball11_set_banks(machine());
- break;
+ // allocate the 24C01 or 24C02 EEPROM
+ battery_size += 0x2000;
}
-}
-
-/*************************************************************
-
- BMC-MARIOPARTY-7IN1
-
- Known Boards: Unknown Multigame Bootleg Board
- Games: Mario 7 in 1
-
- MMC3 clone
-
- iNES: mapper 52
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_mario7in1_m_w)
-{
- UINT8 map52_helper1, map52_helper2;
- LOG_MMC(("bmc_mario7in1_m_w, offset: %04x, data: %02x\n", offset, data));
- /* mid writes only work when WRAM is enabled. not sure if I should
- change the condition to m_map52_reg_written == 0x80 (i.e. what is the effect of
- the read-only bit?) and it only can happen once! */
- if ((m_mmc3_wram_protect & 0x80) && !m_map52_reg_written)
+ if (m_pcb_id == BANDAI_DATACH)
{
- map52_helper1 = (data & 0x08);
- map52_helper2 = (data & 0x40);
-
- m_mmc_prg_base = map52_helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4);
- m_mmc_prg_mask = map52_helper1 ? 0x0f : 0x1f;
- m_mmc_chr_base = ((data & 0x20) << 4) | ((data & 0x04) << 6) | (map52_helper2 ? ((data & 0x10) << 3) : 0);
- m_mmc_chr_mask = map52_helper2 ? 0x7f : 0xff;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
-
- m_map52_reg_written = 1;
+ // allocate the 24C01 and 24C02 EEPROM
+ battery_size += 0x4000;
}
- else
- m_wram[offset] = data;
-}
-
-/*************************************************************
-
- BMC-GOLD-7IN1
-
- Known Boards: Unknown Multigame Bootleg Board
- Games: Super HIK Gold 7 in 1, Golden 7 in 1 and many more
-
- MMC3 clone, same as BMC-MARIOPARTY-7IN1 but with switched CHR
- bank lines
-
- iNES: mapper 52
- In MESS: Supported.
+ if (get_software_region("wram") != NULL)
+ prgram_size = get_software_region_length("wram");
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_gold7in1_m_w)
-{
- UINT8 map52_helper1, map52_helper2;
- LOG_MMC(("bmc_gold7in1_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if ((m_mmc3_wram_protect & 0x80) && !m_map52_reg_written)
+ if (get_feature("mirroring"))
{
- map52_helper1 = (data & 0x08);
- map52_helper2 = (data & 0x40);
-
- m_mmc_prg_base = map52_helper1 ? ((data & 0x07) << 4) : ((data & 0x06) << 4);
- m_mmc_prg_mask = map52_helper1 ? 0x0f : 0x1f;
- m_mmc_chr_base = ((data & 0x20) << 3) | ((data & 0x04) << 7) | (map52_helper2 ? ((data & 0x10) << 3) : 0);
- m_mmc_chr_mask = map52_helper2 ? 0x7f : 0xff;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
-
- m_map52_reg_written = BIT(data, 7); // mc_2hikg & mc_s3nt3 write here multiple time
- }
- else
- m_wram[offset] = data;
-}
-
-/*************************************************************
-
- BMC-GOLDENCARD-6IN1
-
- Known Boards: Unknown Bootleg Multigame Board
- Games: Golden Card 6 in 1
-
- MMC3 clone
-
- iNES: mapper 217
-
- In MESS: Supported.
-
- *************************************************************/
-
-// remove mask & base parameters!
-static void bmc_gc6in1_set_prg( running_machine &machine, int prg_base, int prg_mask )
-{
- nes_state *state = machine.driver_data<nes_state>();
- state->m_mmc_prg_base = (state->m_mmc_reg[1] & 0x08) ? 0 : (state->m_mmc_reg[1] & 0x10);
- state->m_mmc_prg_mask = (state->m_mmc_reg[1] & 0x08) ? 0x1f : 0x0f;
-
- state->m_mmc_prg_base |= ((state->m_mmc_reg[1] & 0x03) << 5);
-
- mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
-}
-
-static void bmc_gc6in1_set_chr( running_machine &machine, UINT8 chr )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_page = (state->m_mmc_latch1 & 0x80) >> 5;
- int chr_base = (state->m_mmc_reg[1] & 0x08) ? 0x00 : ((state->m_mmc_reg[1] & 0x10) << 3);
- int chr_mask = (state->m_mmc_reg[1] & 0x08) ? 0xff : 0x7f;
-
- chr_base |= ((state->m_mmc_reg[1] & 0x03) << 8);
-
- state->chr1_x(chr_page ^ 0, chr_base | ((state->m_mmc_vrom_bank[0] & ~0x01) & chr_mask), chr);
- state->chr1_x(chr_page ^ 1, chr_base | ((state->m_mmc_vrom_bank[0] | 0x01) & chr_mask), chr);
- state->chr1_x(chr_page ^ 2, chr_base | ((state->m_mmc_vrom_bank[1] & ~0x01) & chr_mask), chr);
- state->chr1_x(chr_page ^ 3, chr_base | ((state->m_mmc_vrom_bank[1] | 0x01) & chr_mask), chr);
- state->chr1_x(chr_page ^ 4, chr_base | (state->m_mmc_vrom_bank[2] & chr_mask), chr);
- state->chr1_x(chr_page ^ 5, chr_base | (state->m_mmc_vrom_bank[3] & chr_mask), chr);
- state->chr1_x(chr_page ^ 6, chr_base | (state->m_mmc_vrom_bank[4] & chr_mask), chr);
- state->chr1_x(chr_page ^ 7, chr_base | (state->m_mmc_vrom_bank[5] & chr_mask), chr);
-}
-
-WRITE8_MEMBER(nes_carts_state::bmc_gc6in1_l_w)
-{
- UINT8 bank;
- LOG_MMC(("bmc_gc6in1_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset == 0x1000)
- {
- m_mmc_reg[0] = data;
- if (data & 0x80)
+ const char *mirroring = get_feature("mirroring");
+ if (!strcmp(mirroring, "horizontal"))
+ m_cart->set_mirroring(PPU_MIRROR_HORZ);
+ if (!strcmp(mirroring, "vertical"))
+ m_cart->set_mirroring(PPU_MIRROR_VERT);
+ if (!strcmp(mirroring, "high"))
+ m_cart->set_mirroring(PPU_MIRROR_HIGH);
+ if (!strcmp(mirroring, "low"))
+ m_cart->set_mirroring(PPU_MIRROR_LOW);
+ if (!strcmp(mirroring, "4screen"))
{
- bank = (data & 0x0f) | ((m_mmc_reg[1] & 0x03) << 4);
- prg16_89ab(bank);
- prg16_cdef(bank);
- }
- else
- bmc_gc6in1_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- }
- else if (offset == 0x1001)
- {
- m_mmc_reg[1] = data;
- bmc_gc6in1_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- }
- else if (offset == 0x1007)
- {
- m_mmc_reg[2] = data;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::bmc_gc6in1_w)
-{
- UINT8 mmc_helper, cmd;
- static const UINT8 conv_table[8] = {0, 6, 3, 7, 5, 2, 4, 1};
- LOG_MMC(("bmc_gc6in1_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!m_mmc_reg[2]) // in this case we act like MMC3, only with alt prg/chr handlers
- {
- switch (offset & 0x6001)
- {
- case 0x0000:
- mmc_helper = m_mmc3_latch ^ data;
- m_mmc3_latch = data;
-
- /* Has PRG Mode changed? */
- if (mmc_helper & 0x40)
- bmc_gc6in1_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- /* Has CHR Mode changed? */
- if (mmc_helper & 0x80)
- bmc_gc6in1_set_chr(machine(), m_mmc_chr_source);
- break;
-
- case 0x0001:
- cmd = m_mmc3_latch & 0x07;
- switch (cmd)
- {
- case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
- case 2: case 3: case 4: case 5:
- m_mmc_vrom_bank[cmd] = data;
- bmc_gc6in1_set_chr(machine(), m_mmc_chr_source);
- break;
- case 6:
- case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- bmc_gc6in1_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- }
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
+ // A few boards uses 4-screen mirroring: Gauntlet (DDROM or TRR1ROM or Tengen 800004),
+ // Rad Racer II (TVROM), and Napoleon Senki (IREM LROG017 with 74*161/161/21/138)
+ m_cart->set_four_screen_vram(TRUE);
+ m_cart->set_mirroring(PPU_MIRROR_4SCREEN);
}
- }
- else
- {
- switch (offset & 0x6001)
- {
- case 0x0000:
- txrom_w(space, 0x4000, data, mem_mask);
- break;
-
- case 0x0001:
- data = (data & 0xc0) | conv_table[data & 0x07];
- mmc_helper = m_mmc3_latch ^ data;
- m_mmc3_latch = data;
-
- /* Has PRG Mode changed? */
- if (mmc_helper & 0x40)
- bmc_gc6in1_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- /* Has CHR Mode changed? */
- if (mmc_helper & 0x80)
- bmc_gc6in1_set_chr(machine(), m_mmc_chr_source);
-
- m_mmc_reg[3] = 1;
- break;
-
- case 0x2000:
- cmd = m_mmc3_latch & 0x07;
- if (m_mmc_reg[3])
- {
- m_mmc_reg[3] = 0;
- switch (cmd)
- {
- case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
- case 2: case 3: case 4: case 5:
- m_mmc_vrom_bank[cmd] = data;
- bmc_gc6in1_set_chr(machine(), m_mmc_chr_source);
- break;
- case 6:
- case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- bmc_gc6in1_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- }
- }
- break;
-
-
- case 0x2001:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- break;
-
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
- }
-}
-
-/*************************************************************
-
- BMC-FAMILY-4646B
-
- Known Boards: Unknown Multigame Bootleg Board (4646B)
- Games: 2 in 1 - Family Kid & Aladdin 4
-
- MMC3 clone
-
- iNES: mapper 134
-
- In MESS: Supported.
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_family4646_m_w)
-{
- LOG_MMC(("bmc_family4646_m_w, offset: %04x, data: %02x\n", offset, data));
-
- if (offset == 0x01)
- {
- m_mmc_prg_base = (data & 0x02) << 4;
- m_mmc_prg_mask = 0x1f;
- m_mmc_chr_base = (data & 0x20) << 3;
- m_mmc_chr_mask = 0xff;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- }
-}
-
-/*************************************************************
-
- BMC-VT5201
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_vt5201_w)
-{
- LOG_MMC(("bmc_vt5201_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_latch1 = BIT(offset, 8);
-
- // not sure about this mirroring bit!!
- // without it TN 95 in 1 has glitches in Lunar Ball; with it TN 95 in 1 has glitches in Galaxian!
- set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- if (BIT(offset, 7))
- {
- prg16_89ab((offset >> 4) & 0x07);
- prg16_cdef((offset >> 4) & 0x07);
- }
- else
- prg32((offset >> 5) & 0x03);
- chr8(offset, CHRROM);
-}
-
-READ8_MEMBER(nes_carts_state::bmc_vt5201_r)
-{
- LOG_MMC(("bmc_vt5201_r, offset: %04x\n", offset));
- // m_mmc_dipsetting = ioport("CARTDIPS")->read();
-
- if (m_mmc_latch1)
- return m_mmc_dipsetting; // cart mode, depending on the Dip Switches (always zero atm, given we have no way to add cart-based DIPs)
- else
- return mmc_hi_access_rom(machine(), offset);
-}
-
-/*************************************************************
-
- BMC-BS-5
-
- Games: a few 4 in 1 multicarts
-
- *************************************************************/
-
-static void bmc_bs5_update_banks( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- state->prg8_89(state->m_mmc_prg_bank[0]);
- state->prg8_ab(state->m_mmc_prg_bank[1]);
- state->prg8_cd(state->m_mmc_prg_bank[2]);
- state->prg8_ef(state->m_mmc_prg_bank[3]);
- state->chr2_0(state->m_mmc_vrom_bank[0], CHRROM);
- state->chr2_2(state->m_mmc_vrom_bank[1], CHRROM);
- state->chr2_4(state->m_mmc_vrom_bank[2], CHRROM);
- state->chr2_6(state->m_mmc_vrom_bank[3], CHRROM);
-}
-
-WRITE8_MEMBER(nes_carts_state::bmc_bs5_w)
-{
- UINT8 bs5_helper = (offset & 0xc00) >> 10;
- LOG_MMC(("bmc_bs5_w, offset: %04x, data: %02x\n", offset, data));
-// m_mmc_dipsetting = ioport("CARTDIPS")->read();
-
- switch (offset & 0x7000)
- {
- case 0x0000:
- m_mmc_vrom_bank[bs5_helper] = offset & 0x1f;
- break;
- case 0x2000:
- if (BIT(offset, m_mmc_dipsetting + 4)) // mmc_dipsetting is always zero atm, given we have no way to add cart-based DIPs
- m_mmc_prg_bank[bs5_helper] = offset & 0x0f;
- break;
- }
- bmc_bs5_update_banks(machine());
-}
-
-/*************************************************************
-
- BMC-810544-C-A1
-
- Games: 200-in-1 Elfland
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_810544_w)
-{
- UINT8 bank = (offset >> 7);
- LOG_MMC(("bmc_810544_w, offset: %04x, data: %02x\n", offset, data));
-
- if (!BIT(offset, 6))
- {
- prg16_89ab((bank << 1) | BIT(offset, 5));
- prg16_cdef((bank << 1) | BIT(offset, 5));
- }
- else
- prg32(bank);
-
- set_nt_mirroring(BIT(offset, 4) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- chr8(offset & 0x0f, CHRROM);
-}
-
-/*************************************************************
-
- BMC-NTD-03
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::bmc_ntd03_w)
-{
- UINT8 pbank, cbank;
- LOG_MMC(("bmc_ntd03_w, offset: %04x, data: %02x\n", offset, data));
-
- pbank = (offset >> 10) & 0x1e;
- cbank = ((offset & 0x300) >> 5) | (offset & 0x07);
-
- if (BIT(offset, 7))
- {
- prg16_89ab(pbank | BIT(offset, 6));
- prg16_cdef(pbank | BIT(offset, 6));
- }
- else
- prg32(pbank >> 1);
-
- set_nt_mirroring(BIT(offset, 10) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
-
- chr8(cbank, CHRROM);
-}
-
-/*************************************************************
-
- BMC-GHOSTBUSTERS63IN1
-
- in MESS: only preliminar support
-
- *************************************************************/
-
-static void bmc_gb63_update( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- state->set_nt_mirroring(BIT(state->m_mmc_reg[0], 6) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
-
- if (BIT(state->m_mmc_reg[0], 5))
- {
- state->prg16_89ab(state->m_mmc_reg[0] & 0x1f); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1!
- state->prg16_cdef(state->m_mmc_reg[0] & 0x1f); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1!
- }
- else
- state->prg32((state->m_mmc_reg[0] & 0x1f) >> 1); // FIXME: here probably we could also have PRGRAM, depending on mmc_latch1!
-
- if (BIT(state->m_mmc_reg[1], 2))
- state->chr8(0, CHRRAM);
-// else
-// state->chr8(0, CHRROM);
-}
-
-WRITE8_MEMBER(nes_carts_state::bmc_gb63_w)
-{
- LOG_MMC(("bmc_gb63_w, offset: %04x, data: %02x\n", offset, data));
-
- m_mmc_reg[offset & 1] = data;
- m_mmc_latch1 = BIT(m_mmc_reg[0], 7) | (BIT(m_mmc_reg[1], 0) << 1);
-
-}
-
-READ8_MEMBER(nes_carts_state::bmc_gb63_r)
-{
- LOG_MMC(("bmc_gb63_r, offset: %04x\n", offset));
- // m_mmc_dipsetting = ioport("CARTDIPS")->read();
-
- if (m_mmc_latch1 == 1)
- return 0xff; // open bus
- else
- return mmc_hi_access_rom(machine(), offset);
-}
-
-/*************************************************************
-
- UNL-EDU2000
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::edu2k_w)
-{
- LOG_MMC(("edu2k_w, offset: %04x, data: %02x\n", offset, data));
-
- prg32(data & 0x1f);
- wram_bank((data & 0xc0) >> 6, NES_WRAM);
-}
-
-/*************************************************************
-
- UNL-H2288
-
- *************************************************************/
-
-static void h2288_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- if (!(state->m_mmc_reg[0] & 0x40))
- state->prg8_x(start, bank);
-}
-
-WRITE8_MEMBER(nes_carts_state::h2288_l_w)
-{
- LOG_MMC(("h2288_l_w offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset >= 0x1800)
- {
- m_mmc_reg[offset & 1] = data;
- if (m_mmc_reg[0] & 0x40)
+ if (!strcmp(mirroring, "pcb_controlled"))
{
- UINT8 helper1 = (m_mmc_reg[0] & 0x05) | ((m_mmc_reg[0] >> 2) & 0x0a);
- UINT8 helper2 = BIT(m_mmc_reg[0], 1);
- prg16_89ab(helper1 & ~helper2);
- prg16_cdef(helper1 | helper2);
+ // A few boards have variants with hardcoded mirroring and variants with mapper
+ // controlled mirroring. We use a variable to avoid the need of dupe devices.
+ // See e.g. HES 6-in-1 vs other HES games, Irem Major League vs other G-101 games,
+ // Sunsoft-2 Shanghai vs Mito Koumon, Camerica BF9093 games vs BF9097 games, etc.
+ // Boards where all games control mirroring do not make real use of this.
+ m_cart->set_pcb_ctrl_mirror(TRUE);
}
- else
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
}
-}
-READ8_MEMBER(nes_carts_state::h2288_l_r)
-{
- LOG_MMC(("h2288_l_r offset: %04x\n", offset));
- offset += 0x100;
-
- if (offset >= 0x1000)
+ /* Check for pins in specific boards which require them */
+ if (m_pcb_id == STD_CNROM)
{
- int helper = offset >> 8;
- if (offset & 1)
- return helper | 0x01;
- else
- return helper ^ 0x01;
- }
-
- return 0;
-}
-
-WRITE8_MEMBER(nes_carts_state::h2288_w)
-{
- static const UINT8 conv_table[8] = {0, 3, 1, 5, 6, 7, 2, 4};
- LOG_MMC(("h2288_w, offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x6001)
- {
- case 0x0000:
- txrom_w(space, 0x0000, (data & 0xc0) | conv_table[data & 0x07], mem_mask);
- break;
+ int mask = 0, state = 0;
- default:
- txrom_w(space, offset, data, mem_mask);
- break;
- }
-}
-
-/*************************************************************
-
- UNL-SHJY3
-
- *************************************************************/
-
-/* I think the IRQ should only get fired if enough CPU cycles have passed, but we don't implement (yet) this part */
-void nes_state::shjy3_irq( int scanline, int vblank, int blanked )
-{
- if (m_IRQ_enable & 0x02)
- {
- if (m_IRQ_count == 0xff)
- {
- m_IRQ_count = m_IRQ_count_latch;
- m_IRQ_enable = m_IRQ_enable | ((m_IRQ_enable & 0x01) << 1);
- m_maincpu->set_input_line(M6502_IRQ_LINE, HOLD_LINE);
- }
- else
- m_IRQ_count++;
- }
-}
-
-static void shjy3_update( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int i;
-
- state->prg8_89(state->m_mmc_prg_bank[0]);
- state->prg8_ab(state->m_mmc_prg_bank[1]);
-
- for (i = 0; i < 8; i++)
- {
- UINT8 chr_bank = state->m_mmc_vrom_bank[i] | (state->m_mmc_extra_bank[i] << 4);
- if (state->m_mmc_vrom_bank[i] == 0xc8)
+ if (get_feature("chr-pin26") != NULL)
{
- state->m_mmc_latch1 = 0;
- continue;
+ mask |= 0x01;
+ state |= !strcmp(get_feature("chr-pin26"), "CE") ? 0x01 : 0;
}
- else if (state->m_mmc_vrom_bank[i] == 0x88)
+ if (get_feature("chr-pin27") != NULL)
{
- state->m_mmc_latch1 = 1;
- continue;
+ mask |= 0x02;
+ state |= !strcmp(get_feature("chr-pin27"), "CE") ? 0x02 : 0;
}
- if ((state->m_mmc_vrom_bank[i] == 4 || state->m_mmc_vrom_bank[i] == 5) && !state->m_mmc_latch1)
- state->chr1_x(i, chr_bank & 1, CHRRAM);
- else
- state->chr1_x(i, chr_bank, CHRROM);
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::shjy3_w)
-{
- UINT8 mmc_helper, shift;
- LOG_MMC(("shjy3_w, offset: %04x, data: %02x\n", offset, data));
- if (offset >= 0x3000 && offset <= 0x600c)
- {
- mmc_helper = ((offset & 8) | (offset >> 8)) >> 3;
- mmc_helper += 2;
- mmc_helper &= 7;
- shift = offset & 4;
-
- m_mmc_vrom_bank[mmc_helper] = (m_mmc_vrom_bank[mmc_helper] & (0xf0 >> shift)) | ((data & 0x0f) << shift);
- if (shift)
- m_mmc_extra_bank[mmc_helper] = data >> 4;
+ m_cart->set_ce(mask, state);
}
- else
- {
- switch (offset)
- {
- case 0x0010:
- m_mmc_prg_bank[0] = data;
- break;
- case 0x2010:
- m_mmc_prg_bank[1] = data;
- break;
- case 0x1400:
- switch (data & 0x03)
- {
- case 0: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- }
- break;
- case 0x7000:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0xf0) | (data & 0x0f);
- break;
- case 0x7004:
- m_IRQ_count_latch = (m_IRQ_count_latch & 0x0f) | ((data & 0x0f) << 4);
- break;
- case 0x7008:
- m_IRQ_enable = data & 0x03;
- if (m_IRQ_enable & 0x02)
- m_IRQ_count = m_IRQ_count_latch;
- break;
- }
- }
- shjy3_update(machine());
-}
-
-/*************************************************************
-
- UNL-603-5052
-
- MMC3 + protection access in 0x4020 - 0x7fff
-
- in MESS: Partial support
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::unl_6035052_extra_w)
-{
- LOG_MMC(("unl_6035052_extra_w, offset: %04x, data: %02x\n", offset, data));
- m_mmc_latch1 = data & 0x03;
- if (m_mmc_latch1 == 1)
- m_mmc_latch1 = 2;
-}
-
-READ8_MEMBER(nes_carts_state::unl_6035052_extra_r)
-{
- LOG_MMC(("unl_6035052_extra_r, offset: %04x\n", offset));
- return m_mmc_latch1;
-}
-
-
-/*************************************************************
- BMC-POWERJOY
-
- *************************************************************/
-
-static void pjoy84_prg_cb( running_machine &machine, int start, int bank )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 flip = (state->m_mmc3_latch & 0x40) ? 2 : 0;
-
- if (!(state->m_mmc_reg[3] & 0x03))
- state->prg8_x(start, bank);
- else if (start == flip)
+ if (m_pcb_id == TAITO_X1_005 && get_feature("x1-pin17") != NULL && get_feature("x1-pin31") != NULL)
{
- if ((state->m_mmc_reg[3] & 0x03) == 0x03)
- state->prg32(bank >> 2);
- else
- {
- state->prg16_89ab(bank >> 1);
- state->prg16_cdef(bank >> 1);
- }
+ if (!strcmp(get_feature("x1-pin17"), "CIRAM A10") && !strcmp(get_feature("x1-pin31"), "NC"))
+ m_cart->set_x1_005_alt(TRUE);
}
-}
-
-static void pjoy84_chr_cb( running_machine &machine, int start, int bank, int source )
-{
- nes_state *state = machine.driver_data<nes_state>();
- if (!(state->m_mmc_reg[3] & 0x10))
- state->chr1_x(start, bank, source);
-}
-
-INLINE void pjoy84_set_base_mask( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- state->m_mmc_prg_base = ((state->m_mmc_reg[0] & (0x06 | BIT(state->m_mmc_reg[0], 6))) << 4) |
- (BIT(state->m_mmc_reg[0], 4) << 7);
-
- state->m_mmc_chr_base = ((~state->m_mmc_reg[0] << 0) & 0x080 & state->m_mmc_reg[2]) |
- ((state->m_mmc_reg[0] << 4) & 0x080 & state->m_mmc_reg[0]) |
- ((state->m_mmc_reg[0] << 3) & 0x100) |
- ((state->m_mmc_reg[0] << 5) & 0x200);
-
- state->m_mmc_prg_mask = BIT(state->m_mmc_reg[0], 6) ? 0x0f : 0x1f;
- state->m_mmc_chr_mask = BIT(state->m_mmc_reg[0], 7) ? 0x7f : 0xff;
-}
-
-WRITE8_MEMBER(nes_carts_state::pjoy84_m_w)
-{
- LOG_MMC(("pjoy84_m_w offset: %04x, data: %02x\n", offset, data));
-
- switch (offset & 0x03)
+ if (m_pcb_id == KONAMI_VRC2)
{
- case 0x00:
- case 0x03:
- if (m_mmc_reg[3] & 0x80)
- return; // else we act as if offset & 3 = 1,2
- case 0x01:
- case 0x02:
- m_mmc_reg[offset & 0x03] = data;
- pjoy84_set_base_mask(machine());
- if (m_mmc_reg[3] & 0x10)
- chr8((m_mmc_chr_base >> 3) | (m_mmc_reg[2] & 0x0f), m_mmc_chr_source);
- else
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
+ m_cart->set_vrc_lines(nes_cart_get_line(get_feature("vrc2-pin3")),
+ nes_cart_get_line(get_feature("vrc2-pin4")),
+ (nes_cart_get_line(get_feature("vrc2-pin21")) != 10) ? 1 : 0);
+// mame_printf_error("VRC-2, pin3: A%d, pin4: A%d, pin21: %d\n", nes_cart_get_line(get_feature("vrc2-pin3")), nes_cart_get_line(get_feature("vrc2-pin4")),
+// nes_cart_get_line(get_feature("vrc2-pin21")));
}
-}
-
-/*************************************************************
-
- SOMERI TEAM
- iNES: mapper 116
-
- Emulation note about regs in MESS: currently,
- - state->m_mmc_cmd1 represent the board mode
- - state->m_mmc_reg[n] for n=0,1,2,3 represent the MMC1 regs
- - state->m_mmc_prg_bank[n] for n=0,...,3 represent the MMC3 PRG banks
- - state->m_mmc_vrom_bank[n] for n=0,...,5 represent the MMC3 CHR banks
- - state->m_mmc_prg_bank[n] for n=4,5 represent the VRC2 PRG banks
- - state->m_mmc_vrom_bank[n] for n=6,...,13 represent the VRC2 CHR banks
-
- In MESS: Preliminary support
-
- *************************************************************/
-
-// MMC1 Mode emulation
-static void someri_mmc1_set_prg( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 prg_mode = state->m_mmc_reg[0] & 0x0c;
- UINT8 prg_offset = state->m_mmc_reg[1] & 0x10;
-
- switch (prg_mode)
+ if (m_pcb_id == KONAMI_VRC4)
{
- case 0x00:
- case 0x04:
- state->prg32((prg_offset + state->m_mmc_reg[3]) >> 1);
- break;
- case 0x08:
- state->prg16_89ab(prg_offset + 0);
- state->prg16_cdef(prg_offset + state->m_mmc_reg[3]);
- break;
- case 0x0c:
- state->prg16_89ab(prg_offset + state->m_mmc_reg[3]);
- state->prg16_cdef(prg_offset + 0x0f);
- break;
+ m_cart->set_vrc_lines(nes_cart_get_line(get_feature("vrc4-pin3")),
+ nes_cart_get_line(get_feature("vrc4-pin4")),
+ 0);
+// mame_printf_error("VRC-4, pin3: A%d, pin4: A%d\n", nes_cart_get_line(get_feature("vrc4-pin3"), nes_cart_get_line(get_feature("vrc4-pin4"));
}
-}
-static void someri_mmc1_set_chr( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- UINT8 chr_mode = BIT(state->m_mmc_reg[0], 4);
-
- if (chr_mode)
+ if (m_pcb_id == KONAMI_VRC6)
{
- state->chr4_0(state->m_mmc_reg[1] & 0x1f, state->m_mmc_chr_source);
- state->chr4_4(state->m_mmc_reg[2] & 0x1f, state->m_mmc_chr_source);
+ m_cart->set_vrc_lines(nes_cart_get_line(get_feature("vrc6-pin9")),
+ nes_cart_get_line(get_feature("vrc6-pin10")),
+ 0);
+// mame_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", nes_cart_get_line(get_feature("vrc6-pin9"), nes_cart_get_line(get_feature("vrc6-pin10"));
}
- else
- state->chr8((state->m_mmc_reg[1] & 0x1f) >> 1, state->m_mmc_chr_source);
-}
-WRITE8_MEMBER(nes_carts_state::someri_mmc1_w)
-{
- assert(m_mmc_cmd1 == 2);
+ if (m_pcb_id == STD_HKROM || m_pcb_id == TAITO_X1_017)
+ mapper_sram_size = m_cart->get_mapper_sram_size();
- if (data & 0x80)
+ if (m_pcb_id == TAITO_X1_005 || m_pcb_id == NAMCOT_163)
{
- m_mmc1_count = 0;
- m_mmc1_latch = 0;
-
- m_mmc_reg[0] |= 0x0c;
- someri_mmc1_set_prg(machine());
- return;
+ if (get_feature("batt"))
+ mapper_sram_size = m_cart->get_mapper_sram_size();
}
- if (m_mmc1_count < 5)
- {
- if (m_mmc1_count == 0) m_mmc1_latch = 0;
- m_mmc1_latch >>= 1;
- m_mmc1_latch |= (data & 0x01) ? 0x10 : 0x00;
- m_mmc1_count++;
- }
- if (m_mmc1_count == 5)
- {
- switch (offset & 0x6000)
- {
- case 0x0000:
- m_mmc_reg[0] = m_mmc1_latch;
- switch (m_mmc_reg[0] & 0x03)
- {
- case 0: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break;
- case 2: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- }
- someri_mmc1_set_chr(machine());
- someri_mmc1_set_prg(machine());
- break;
- case 0x2000:
- m_mmc_reg[1] = m_mmc1_latch;
- someri_mmc1_set_chr(machine());
- someri_mmc1_set_prg(machine());
- break;
- case 0x4000:
- m_mmc_reg[2] = m_mmc1_latch;
- someri_mmc1_set_chr(machine());
- break;
- case 0x6000:
- m_mmc_reg[3] = m_mmc1_latch;
- someri_mmc1_set_prg(machine());
- break;
- }
+ // pirate variants of boards with bus conflict are often not suffering from it
+ // and actually games glitch if bus conflict is emulated...
+ if (get_feature("bus_conflict") && !strcmp(get_feature("bus_conflict"), "no"))
+ m_cart->set_bus_conflict(FALSE);
- m_mmc1_count = 0;
- }
-}
-// MMC3 Mode emulation
-WRITE8_MEMBER(nes_carts_state::someri_mmc3_w)
-{
- UINT8 mmc_helper, cmd;
+ // SETUP step 4: logging what we have found
+ logerror("Loaded game from softlist:\n");
+ logerror("-- PCB: %s", get_feature("pcb"));
+ if (m_pcb_id == UNSUPPORTED_BOARD)
+ logerror(" (currently not supported by MESS)");
+ logerror("\n-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000);
+ logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000);
+ logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000);
+ logerror("-- PRG NVWRAM: %d\n", m_cart->get_battery_size());
+ logerror("-- PRG WRAM: %d\n", m_cart->get_prgram_size());
- assert(m_mmc_cmd1 == 1);
- switch (offset & 0x6001)
+ // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data!
+ m_cart->prg_alloc(machine(), prg_size);
+ memcpy(m_cart->get_prg_base(), get_software_region("prg"), prg_size);
+ if (vrom_size)
{
- case 0x0000:
- mmc_helper = m_mmc3_latch ^ data;
- m_mmc3_latch = data;
-
- if (mmc_helper & 0x40)
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
-
- if (mmc_helper & 0x80)
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
-
- case 0x0001:
- cmd = m_mmc3_latch & 0x07;
- switch (cmd)
- {
- case 0: case 1:
- case 2: case 3: case 4: case 5:
- m_mmc_vrom_bank[cmd] = data;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
- case 6:
- case 7:
- m_mmc_prg_bank[cmd - 6] = data;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- }
- break;
-
- case 0x2000:
- set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
- 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; break;
- case 0x6001: m_IRQ_enable = 1; break;
+ m_cart->vrom_alloc(machine(), vrom_size);
+ memcpy(m_cart->get_vrom_base(), get_software_region("chr"), vrom_size);
}
-}
-// VRC2 Mode emulation
-WRITE8_MEMBER(nes_carts_state::someri_vrc2_w)
-{
- UINT8 bank, shift;
+ // SETUP steps 7: allocate the remaining pointer, when needed
+ if (vram_size)
+ m_cart->vram_alloc(machine(), vram_size);
+ if (prgram_size)
+ m_cart->prgram_alloc(machine(), prgram_size);
- assert(m_mmc_cmd1 == 0);
+ // also nes_smb2j_device needs WRAM initialized to 0xff? check!
+ if (m_pcb_id == UNL_SMB2J)
+ memset(m_cart->get_prgram_base(), 0xff, prgram_size);
- if (offset < 0x1000)
- {
- m_mmc_prg_bank[4] = data;
- prg8_89(m_mmc_prg_bank[4]);
- }
- else if (offset < 0x2000)
+ // Attempt to load a battery file for this ROM
+ // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.)
+ if (battery_size || mapper_sram_size)
{
- switch (data & 0x03)
+ UINT32 tot_size = battery_size + mapper_sram_size;
+ UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size);
+ battery_load(temp_nvram, tot_size, 0x00);
+ if (battery_size)
{
- case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
- case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
- case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
- case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ m_cart->battery_alloc(machine(), battery_size);
+ memcpy(m_cart->get_battery_base(), temp_nvram, battery_size);
}
- }
- else if (offset < 0x3000)
- {
- m_mmc_prg_bank[5] = data;
- prg8_ab(m_mmc_prg_bank[5]);
- }
- else if (offset < 0x7000)
- {
- bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1);
- shift = BIT(offset, 2) * 4;
- data = (data & 0x0f) << shift;
- m_mmc_vrom_bank[6 + bank] = data | m_mmc_chr_base;
- chr1_x(bank, m_mmc_vrom_bank[6 + bank], CHRROM);
- }
-}
+ if (mapper_sram_size)
+ memcpy(m_cart->get_mapper_sram_base(), temp_nvram + battery_size, mapper_sram_size);
-WRITE8_MEMBER(nes_carts_state::someri_w)
-{
- LOG_MMC(("someri_w mode %d, offset: %04x, data: %02x\n", m_mmc_cmd1, offset, data));
-
- switch (m_mmc_cmd1)
- {
- case 0x00: someri_vrc2_w(space, offset, data, mem_mask); break;
- case 0x01: someri_mmc3_w(space, offset, data, mem_mask); break;
- case 0x02: someri_mmc1_w(space, offset, data, mem_mask); break;
- }
-}
-
-static void someri_mode_update( running_machine &machine )
-{
- nes_state *state = machine.driver_data<nes_state>();
- int i;
-
- switch (state->m_mmc_cmd1)
- {
- case 0x00:
- state->prg8_89(state->m_mmc_prg_bank[4]);
- state->prg8_ab(state->m_mmc_prg_bank[5]);
- for (i = 0; i < 8; i++)
- state->chr1_x(i, state->m_mmc_vrom_bank[6 + i], CHRROM);
- break;
- case 0x01:
- mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
- mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
- break;
- case 0x02:
- someri_mmc1_set_prg(machine);
- someri_mmc1_set_chr(machine);
- break;
- }
-}
-
-WRITE8_MEMBER(nes_carts_state::someri_l_w)
-{
- LOG_MMC(("someri_l_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x100;
-
- if (offset & 0x100)
- {
- m_mmc_cmd1 = data & 0x03;
- m_mmc_chr_base = ((m_mmc_cmd1 & 0x04) << 6);
- if (m_mmc_cmd1 != 1)
- m_IRQ_enable = 0;
- someri_mode_update(machine());
- }
-}
-
-#ifdef UNUSED_FUNCTION
-/*************************************************************
-
- FUJIYA Board - mapper 170 according to NEStopia
-
- Which games are supposed to use this?
-
- *************************************************************/
-
-WRITE8_MEMBER(nes_carts_state::fujiya_m_w)
-{
- LOG_MMC(("fujiya_m_w, offset: %04x, data: %02x\n", offset, data));
- offset += 0x6000;
-
- if (offset == 0x6502 || offset == 0x7000)
- m_mmc_latch1 = (data & 0x40) << 1;
-}
-
-READ8_MEMBER(nes_carts_state::fujiya_m_r)
-{
- LOG_MMC(("fujiya_m_r, offset: %04x\n", offset));
- offset += 0x6000;
-
- if (offset == 0x7001 || offset == 0x7777)
- return m_mmc_latch1 | ((offset >> 8) & 0x7f);
-
- return 0;
-}
-#endif
-
-struct nes_memory_accessor
-{
- write8_delegate write;
- read8_delegate read;
-};
-
-struct nes_pcb_intf
-{
- int mmc_pcb;
- nes_memory_accessor mmc_l; /* $4100-$5fff read/write routines */
- nes_memory_accessor mmc_m; /* $6000-$7fff read/write routines */
- nes_memory_accessor mmc_h; /* $8000-$ffff read/write routines */
- ppu2c0x_latch_delegate mmc_ppu_latch;
- ppu2c0x_scanline_delegate mmc_scanline;
- ppu2c0x_hblank_delegate mmc_hblank;
-};
-
-
-#define NES_NOACCESS \
-{write8_delegate(), read8_delegate()}
-
-#define NES_READONLY(a) \
-{write8_delegate(), read8_delegate(FUNC(a), DEVICE_SELF, (nes_state *)0)}
-
-#define NES_WRITEONLY(a) \
-{write8_delegate(FUNC(a), DEVICE_SELF, (nes_state *)0), read8_delegate()}
-
-#define NES_READWRITE(a, b) \
-{write8_delegate(FUNC(a), DEVICE_SELF, (nes_state *)0), read8_delegate(FUNC(b), DEVICE_SELF, (nes_state *)0)}
-
-#define NES_SCANLINE_NULL \
- ppu2c0x_scanline_delegate()
-
-#define NES_HBLANK_NULL \
- ppu2c0x_hblank_delegate()
-
-#define NES_HBLANK(a) \
- ppu2c0x_hblank_delegate(FUNC(a), DEVICE_SELF, (nes_state *)0)
-
-#define NES_LATCH_NULL \
- ppu2c0x_latch_delegate()
-
- #define NES_LATCH(a) \
- ppu2c0x_latch_delegate(FUNC(a),DEVICE_SELF, (nes_state *)0)
-
-
-WRITE8_MEMBER(nes_carts_state::dummy_l_w)
-{
- logerror("write access, offset: %04x, data: %02x\n", offset + 0x4100, data);
-}
-
-WRITE8_MEMBER(nes_carts_state::dummy_m_w)
-{
- logerror("write access, offset: %04x, data: %02x\n", offset + 0x6000, data);
-}
-
-WRITE8_MEMBER(nes_carts_state::dummy_w)
-{
- logerror("write access, offset: %04x, data: %02x\n", offset + 0x8000, data);
-}
-
-READ8_MEMBER(nes_carts_state::dummy_l_r)
-{
- logerror("read access, offset: %04x\n", offset + 0x4100);
- return 0x00;
-}
-
-READ8_MEMBER(nes_carts_state::dummy_m_r)
-{
- logerror("read access, offset: %04x\n", offset + 0x6000);
- return 0x00;
-}
-
-READ8_MEMBER(nes_carts_state::dummy_r)
-{
- logerror("read access, offset: %04x\n", offset + 0x8000);
- return 0x00;
-}
-
-static const nes_pcb_intf nes_intf_list[] =
-{
- { STD_NROM, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { HVC_FAMBASIC, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { GG_NROM, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_UXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::uxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_UN1ROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::un1rom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_CPROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::cprom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_CNROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::cnrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BANDAI_PT554, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bandai_pt554_m_w), NES_WRITEONLY(nes_carts_state::cnrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_AXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::axrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_PXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::pxrom_w), NES_LATCH(nes_state::mmc2_latch), NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_FXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::fxrom_w), NES_LATCH(nes_state::mmc2_latch), NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_BXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_GXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::gxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_MXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::gxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_NXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ntbrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SUNSOFT_DCS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ntbrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_JXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::jxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::jxrom_irq) },
- { STD_SXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_SOROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_SXROM_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_SOROM_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_TXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { STD_TVROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { STD_TKROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { STD_HKROM, NES_NOACCESS, NES_READWRITE(nes_carts_state::hkrom_m_w, nes_carts_state::hkrom_m_r), NES_WRITEONLY(nes_carts_state::hkrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { STD_TQROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::tqrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { STD_TXSROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txsrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { STD_DXROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::dxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_DRROM, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::dxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { NAMCOT_34X3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::dxrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { NAMCOT_3425, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::namcot3425_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { NAMCOT_3446, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::namcot3446_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { NAMCOT_3453, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::namcot3453_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { STD_EXROM, NES_READWRITE(nes_carts_state::exrom_l_w, nes_carts_state::exrom_l_r), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc5_irq) },
- { NES_QJ, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::qj_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { PAL_ZZ, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::zz_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UXROM_CC, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::uxrom_cc_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- //
- { DIS_74X139X74, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::dis_74x139x74_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { DIS_74X377, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::dis_74x377_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { DIS_74X161X161X32, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::dis_74x161x161x32_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { DIS_74X161X138, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::dis_74x161x138_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BANDAI_LZ93, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::lz93d50_m_w), NES_WRITEONLY(nes_carts_state::lz93d50_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::bandai_lz_irq) },
- { BANDAI_LZ93EX, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::lz93d50_m_w), NES_WRITEONLY(nes_carts_state::lz93d50_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::bandai_lz_irq) },
- { BANDAI_FCG, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::lz93d50_m_w), NES_WRITEONLY(nes_carts_state::lz93d50_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::bandai_lz_irq) },
- { BANDAI_DATACH, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::lz93d50_m_w), NES_WRITEONLY(nes_carts_state::lz93d50_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::bandai_lz_irq) },
- { BANDAI_JUMP2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::fjump2_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::bandai_lz_irq) },
- { BANDAI_KARAOKE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bandai_ks_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BANDAI_OEKAKIDS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bandai_ok_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { IREM_G101, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::g101_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { IREM_LROG017, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::lrog017_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { IREM_H3001, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::h3001_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::h3001_irq) },
- { IREM_TAM_S1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::tam_s1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { IREM_HOLYDIV, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::irem_hd_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { JALECO_SS88006, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ss88006_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::ss88006_irq) },
- { JALECO_JF11, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::jf11_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { JALECO_JF13, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::jf13_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { JALECO_JF16, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::jf16_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { JALECO_JF17, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::jf17_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { JALECO_JF19, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::jf19_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { KONAMI_VRC1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::konami_vrc1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { KONAMI_VRC2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::konami_vrc2_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { KONAMI_VRC3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::konami_vrc3_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::konami_irq) },
- { KONAMI_VRC4, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::konami_vrc4_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::konami_irq) },
- { KONAMI_VRC6, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::konami_vrc6_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::konami_irq) },
- { KONAMI_VRC7, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::konami_vrc7_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::konami_irq) },
- { NAMCOT_163, NES_READWRITE(nes_carts_state::namcot163_l_w, nes_carts_state::namcot163_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::namcot163_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::namcot_irq) },
- { SUNSOFT_1, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sunsoft1_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SUNSOFT_2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sunsoft2_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SUNSOFT_3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sunsoft3_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::sunsoft3_irq) },
- { TAITO_TC0190FMC, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::tc0190fmc_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { TAITO_TC0190FMCP, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::tc0190fmc_p16_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { TAITO_X1_005, NES_NOACCESS, NES_READWRITE(nes_carts_state::x1005_m_w, nes_carts_state::x1005_m_r), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { TAITO_X1_005_A, NES_NOACCESS, NES_READWRITE(nes_carts_state::x1005a_m_w, nes_carts_state::x1005_m_r), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { TAITO_X1_017, NES_NOACCESS, NES_READWRITE(nes_carts_state::x1017_m_w, nes_carts_state::x1017_m_r), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- //
- { AGCI_50282, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::agci_50282_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { ACTENT_ACT52, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ae_act52_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { AVE_NINA01, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::nina01_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { AVE_NINA06, NES_WRITEONLY(nes_carts_state::nina06_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CNE_DECATHLON, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::cne_decathl_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CNE_FSB, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::cne_fsb_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CNE_SHLZ, NES_WRITEONLY(nes_carts_state::cne_shlz_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CALTRON_6IN1, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::caltron6in1_m_w), NES_WRITEONLY(nes_carts_state::caltron6in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CAMERICA_BF9093, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bf9093_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CAMERICA_BF9097, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bf9093_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CAMERICA_BF9096, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bf9096_w), NES_WRITEONLY(nes_carts_state::bf9096_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CAMERICA_GOLDENFIVE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::golden5_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { CONY_BOARD, NES_READWRITE(nes_carts_state::cony_l_w, nes_carts_state::cony_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::cony_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::sunsoft3_irq) },
- { YOKO_BOARD, NES_READWRITE(nes_carts_state::yoko_l_w, nes_carts_state::yoko_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::yoko_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::sunsoft3_irq) },
- { DREAMTECH_BOARD, NES_WRITEONLY(nes_carts_state::dreamtech_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { FUTUREMEDIA_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::futuremedia_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::futuremedia_irq) },
- { FUKUTAKE_BOARD, NES_READWRITE(nes_carts_state::fukutake_l_w, nes_carts_state::fukutake_l_r), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { GOUDER_37017, NES_READWRITE(nes_carts_state::gouder_sf4_l_w, nes_carts_state::gouder_sf4_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { HENGEDIANZI_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::henggedianzi_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { HENGEDIANZI_XJZB, NES_WRITEONLY(nes_carts_state::heng_xjzb_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::heng_xjzb_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { HES6IN1_BOARD, NES_WRITEONLY(nes_carts_state::hes6in1_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { HES_BOARD, NES_WRITEONLY(nes_carts_state::hes_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { HOSENKAN_BOARD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::hosenkan_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { KAISER_KS7058, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ks7058_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { KAISER_KS7022, NES_NOACCESS, NES_NOACCESS, NES_READWRITE(nes_carts_state::ks7022_w, nes_carts_state::ks7022_r), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { KAISER_KS7032, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ks7032_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::ks7032_irq) },
- { KAISER_KS202, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ks202_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::ks7032_irq) },
- { KAISER_KS7017, NES_WRITEONLY(nes_carts_state::ks7017_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc_fds_irq) },
- { KAY_PANDAPRINCE, NES_READWRITE(nes_carts_state::kay_pp_l_w, nes_carts_state::kay_pp_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::kay_pp_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { KASING_BOARD, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::kasing_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { SACHEN_74LS374, NES_READWRITE(nes_carts_state::sachen_74x374_l_w, nes_carts_state::sachen_74x374_l_r), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_74LS374_A, NES_WRITEONLY(nes_carts_state::sachen_74x374a_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_8259A, NES_WRITEONLY(nes_carts_state::s8259_l_w), NES_WRITEONLY(nes_carts_state::s8259_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_8259B, NES_WRITEONLY(nes_carts_state::s8259_l_w), NES_WRITEONLY(nes_carts_state::s8259_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_8259C, NES_WRITEONLY(nes_carts_state::s8259_l_w), NES_WRITEONLY(nes_carts_state::s8259_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_8259D, NES_WRITEONLY(nes_carts_state::s8259_l_w), NES_WRITEONLY(nes_carts_state::s8259_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_SA009, NES_WRITEONLY(nes_carts_state::sa009_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_SA0036, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sa0036_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_SA0037, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sa0037_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_SA72007, NES_WRITEONLY(nes_carts_state::sa72007_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_SA72008, NES_WRITEONLY(nes_carts_state::sa72008_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_TCA01, NES_READONLY(nes_carts_state::tca01_l_r), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_TCU01, NES_WRITEONLY(nes_carts_state::tcu01_l_w), NES_WRITEONLY(nes_carts_state::tcu01_m_w), NES_WRITEONLY(nes_carts_state::tcu01_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SACHEN_TCU02, NES_READWRITE(nes_carts_state::tcu02_l_w, nes_carts_state::tcu02_l_r), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SUBOR_TYPE0, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::subor0_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SUBOR_TYPE1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::subor1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { MAGICSERIES_MD, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::magics_md_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { NANJING_BOARD, NES_READWRITE(nes_carts_state::nanjing_l_w, nes_carts_state::nanjing_l_r), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::nanjing_irq) },
- { NITRA_TDA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::nitra_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { NTDEC_ASDER, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ntdec_asder_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { NTDEC_FIGHTINGHERO, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ntdec_fh_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { OPENCORP_DAOU306, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::daou306_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { RCM_GS2015, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::gs2015_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { RCM_TETRISFAMILY, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::rcm_tf_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { REXSOFT_DBZ5, NES_READWRITE(nes_carts_state::rex_dbz_l_w, nes_carts_state::rex_dbz_l_r), NES_READONLY(nes_carts_state::rex_dbz_l_r), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { REXSOFT_SL1632, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::rex_sl1632_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { RUMBLESTATION_BOARD, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::rumblestation_m_w), NES_WRITEONLY(nes_carts_state::rumblestation_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { SOMERI_SL12, NES_WRITEONLY(nes_carts_state::someri_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::someri_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { SUPERGAME_BOOGERMAN, NES_WRITEONLY(nes_carts_state::sgame_boog_l_w), NES_WRITEONLY(nes_carts_state::sgame_boog_m_w), NES_WRITEONLY(nes_carts_state::sgame_boog_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { SUPERGAME_LIONKING, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sgame_lion_m_w), NES_WRITEONLY(nes_carts_state::sgame_lion_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { TENGEN_800008, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::tengen_800008_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { TENGEN_800032, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::tengen_800032_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::tengen_800032_irq) },
- { TENGEN_800037, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::tengen_800037_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::tengen_800032_irq) },
- { TXC_22211A, NES_READWRITE(nes_carts_state::txc_22211_l_w, nes_carts_state::txc_22211_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txc_22211_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { TXC_22211B, NES_READWRITE(nes_carts_state::txc_22211_l_w, nes_carts_state::txc_22211_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txc_22211b_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { TXC_22211C, NES_READWRITE(nes_carts_state::txc_22211_l_w, nes_carts_state::txc_22211c_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txc_22211_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { TXC_TW, NES_WRITEONLY(nes_carts_state::txc_tw_l_w), NES_WRITEONLY(nes_carts_state::txc_tw_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { TXC_STRIKEWOLF, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txc_strikewolf_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { TXC_MXMDHTWO, NES_READONLY(nes_carts_state::txc_mxmdhtwo_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txc_mxmdhtwo_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { WAIXING_TYPE_A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_a_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_A_1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_a_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_B, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_a_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_C, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_a_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_D, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_a_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_E, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_a_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_F, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_f_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_G, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_g_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_H, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_h_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_TYPE_I, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff
- { WAIXING_TYPE_J, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff
- { WAIXING_SGZ, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_sgz_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::konami_irq) },
- { WAIXING_SGZLZ, NES_WRITEONLY(nes_carts_state::waixing_sgzlz_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { WAIXING_FFV, NES_WRITEONLY(nes_carts_state::waixing_ffv_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { WAIXING_ZS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_zs_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { WAIXING_DQ8, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_dq8_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { WAIXING_SECURITY, NES_WRITEONLY(nes_carts_state::waixing_sec_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WAIXING_SH2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) }, // this is MMC3 + possibly additional WRAM added in 0x5000-0x5fff
- { WAIXING_PS2, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::waixing_ps2_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_8237, NES_WRITEONLY(nes_carts_state::unl_8237_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::unl_8237_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UNL_AX5705, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::unl_ax5705_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_CC21, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::unl_cc21_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_KOF97, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::unl_kof97_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UNL_KS7057, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::ks7057_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UNL_T230, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::unl_t230_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::konami_irq) },
- { UNL_KOF96, NES_READWRITE(nes_carts_state::kof96_l_w, nes_carts_state::kof96_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::kof96_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UNL_MK2, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::mk2_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UNL_N625092, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::n625092_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_SC127, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sc127_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::sc127_irq) },
- { UNL_SMB2J, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::smb2j_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_SUPERFIGHTER3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::unl_sf3_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UNL_XZY, NES_WRITEONLY(nes_carts_state::unl_xzy_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_RACERMATE, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::unl_racmate_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_STUDYNGAME, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::sng32_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_603_5052, NES_READWRITE(nes_carts_state::unl_6035052_extra_w, nes_carts_state::unl_6035052_extra_r), NES_READWRITE(nes_carts_state::unl_6035052_extra_w, nes_carts_state::unl_6035052_extra_r), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UNL_EDU2K, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::edu2k_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { UNL_SHJY3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::shjy3_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::shjy3_irq) },
- { UNL_H2288, NES_READWRITE(nes_carts_state::h2288_l_w, nes_carts_state::h2288_l_r), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::h2288_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { UNL_FS304, NES_WRITEONLY(nes_carts_state::unl_fs304_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- //
- { BTL_AISENSHINICOL, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::btl_mariobaby_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BTL_DRAGONNINJA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::btl_dn_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::btl_dn_irq) },
- { BTL_MARIOBABY, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::btl_mariobaby_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BTL_SMB2A, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::btl_smb2a_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::btl_smb2a_irq) },
- { BTL_SMB2B, NES_WRITEONLY(nes_carts_state::smb2jb_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::smb2jb_irq) },
- { BTL_SMB3, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::btl_smb3_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::btl_smb3_irq) },
- { BTL_SUPERBROS11, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::btl_smb11_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BTL_TOBIDASE, NES_WRITEONLY(nes_carts_state::btl_tobi_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BTL_PIKACHUY2K, NES_NOACCESS, NES_READWRITE(nes_carts_state::btl_pika_y2k_m_w, nes_carts_state::btl_pika_y2k_m_r), NES_WRITEONLY(nes_carts_state::btl_pika_y2k_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { WHIRLWIND_2706, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::whirl2706_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- //
- { BMC_190IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_190in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_A65AS, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_a65as_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_GS2004, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_gs2004_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_GS2013, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_gs2013_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_NOVELDIAMOND, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::novel1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_9999999IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::novel2_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_T262, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_t262_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_WS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_ws_m_w), NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_GKA, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_gka_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_GKB, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_gkb_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_SUPER_700IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_super700in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_36IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_36in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_21IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_21in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_150IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_150in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_35IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_35in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_64IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_64in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_SUPERHIK_300IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_hik300_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_SUPERGUN_20IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::supergun20in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_72IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_72in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_76IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_76in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_SUPER_42IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_76in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_1200IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_1200in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_31IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_31in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_22GAMES, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_22g_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_20IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_20in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_110IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_110in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_64IN1NR, NES_WRITEONLY(nes_carts_state::bmc_64in1nr_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_64in1nr_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_S24IN1SC03, NES_WRITEONLY(nes_carts_state::bmc_s24in1sc03_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_HIK8IN1, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_hik8_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_SUPERHIK_4IN1, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_hik4in1_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_SUPERBIG_7IN1, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_sbig7_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_MARIOPARTY_7IN1, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_mario7in1_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_GOLD_7IN1, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_gold7in1_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_FAMILY_4646B, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_family4646_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_15IN1, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_15in1_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_BALLGAMES_11IN1, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_ball11_m_w), NES_WRITEONLY(nes_carts_state::bmc_ball11_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_GOLDENCARD_6IN1, NES_WRITEONLY(nes_carts_state::bmc_gc6in1_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_gc6in1_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_VT5201, NES_NOACCESS, NES_NOACCESS, NES_READWRITE(nes_carts_state::bmc_vt5201_w, nes_carts_state::bmc_vt5201_r), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_BENSHENG_BS5, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_bs5_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_810544, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_810544_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_NTD_03, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::bmc_ntd03_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_G63IN1, NES_NOACCESS, NES_NOACCESS, NES_READWRITE(nes_carts_state::bmc_gb63_w, nes_carts_state::bmc_gb63_r), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { BMC_FK23C, NES_WRITEONLY(nes_carts_state::fk23c_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::fk23c_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_FK23CA, NES_WRITEONLY(nes_carts_state::fk23c_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::fk23c_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- { BMC_PJOY84, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::pjoy84_m_w), NES_WRITEONLY(nes_carts_state::txrom_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::mmc3_irq) },
- //
- { FFE_MAPPER6, NES_WRITEONLY(nes_carts_state::mapper6_l_w), NES_NOACCESS, NES_WRITEONLY(nes_carts_state::mapper6_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::ffe_irq) },
- { FFE_MAPPER8, NES_NOACCESS, NES_NOACCESS, NES_WRITEONLY(nes_carts_state::mapper8_w), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- { FFE_MAPPER17, NES_WRITEONLY(nes_carts_state::mapper17_l_w), NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK(nes_state::ffe_irq) },
- // for debug and development
- { UNKNOWN_BOARD, NES_READWRITE(nes_carts_state::dummy_l_w, nes_carts_state::dummy_l_r), NES_READWRITE(nes_carts_state::dummy_m_w, nes_carts_state::dummy_m_r), NES_READWRITE(nes_carts_state::dummy_w, nes_carts_state::dummy_r), NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- //
- { UNSUPPORTED_BOARD, NES_NOACCESS, NES_NOACCESS, NES_NOACCESS, NES_LATCH_NULL, NES_SCANLINE_NULL, NES_HBLANK_NULL },
- //
-};
-
-const nes_pcb_intf *nes_pcb_intf_lookup( int pcb_id )
-{
- int i;
- for (i = 0; i < ARRAY_LENGTH(nes_intf_list); i++)
- {
- if (nes_intf_list[i].mmc_pcb == pcb_id)
- return &nes_intf_list[i];
- }
- return NULL;
-}
-
-void nes_state::pcb_handlers_setup()
-{
- const nes_pcb_intf *intf = nes_pcb_intf_lookup(m_pcb_id);
-
- if (intf == NULL)
- fatalerror("Missing PCB interface\n");
-
- if (intf)
- {
- m_mmc_write_low = intf->mmc_l.write;
- if (!m_mmc_write_low.isnull()) m_mmc_write_low.late_bind(*this);
- m_mmc_write_mid = intf->mmc_m.write;
- if (!m_mmc_write_mid.isnull()) m_mmc_write_mid.late_bind(*this);
- m_mmc_write = intf->mmc_h.write;
- if (!m_mmc_write.isnull()) m_mmc_write.late_bind(*this);
- m_mmc_read_low = intf->mmc_l.read;
- if (!m_mmc_read_low.isnull()) m_mmc_read_low.late_bind(*this);
- m_mmc_read_mid = intf->mmc_m.read; // in progress
- if (!m_mmc_read_mid.isnull()) m_mmc_read_mid.late_bind(*this);
- m_mmc_read = intf->mmc_h.read; // in progress
- if (!m_mmc_read.isnull()) m_mmc_read.late_bind(*this);
- ppu2c0x_latch_delegate latch = intf->mmc_ppu_latch;
- if (!latch.isnull()) latch.late_bind(*this);
- m_ppu->set_latch(latch);
- }
- else
- {
- logerror("PCB %d is not yet supported, defaulting to no mapper.\n", m_pcb_id);
- m_mmc_write_low = write8_delegate();
- m_mmc_write_mid = write8_delegate();
- m_mmc_write = write8_delegate();
- m_mmc_read_low = read8_delegate();
- m_mmc_read_mid = read8_delegate(); // in progress
- m_mmc_read = read8_delegate(); // in progress
- m_ppu->set_latch(ppu2c0x_latch_delegate());
- }
-
- m_mmc3_prg_cb = mmc3_base_prg_cb;
- m_mmc3_chr_cb = mmc3_base_chr_cb;
-
- switch (m_pcb_id)
- {
- case STD_TXSROM:
- m_mmc3_chr_cb = txsrom_chr_cb;
- break;
- case GOUDER_37017:
- m_mmc3_prg_cb = gouder_sf4_prg_cb;
- break;
- case KASING_BOARD:
- m_mmc3_prg_cb = kasing_prg_cb;
- break;
- case REXSOFT_DBZ5:
- m_mmc3_chr_cb = rex_dbz_chr_cb;
- break;
- case TXC_TW:
- m_mmc3_prg_cb = txc_tw_prg_cb;
- break;
- case WAIXING_TYPE_A:
- m_mmc3_chr_cb = waixing_a_chr_cb;
- break;
- case WAIXING_TYPE_A_1:
- m_mmc3_chr_cb = waixing_a1_chr_cb;
- break;
- case WAIXING_TYPE_B:
- m_mmc3_chr_cb = waixing_b_chr_cb;
- break;
- case WAIXING_TYPE_C:
- m_mmc3_chr_cb = waixing_c_chr_cb;
- break;
- case WAIXING_TYPE_D:
- m_mmc3_chr_cb = waixing_d_chr_cb;
- break;
- case WAIXING_TYPE_E:
- m_mmc3_chr_cb = waixing_e_chr_cb;
- break;
- case WAIXING_TYPE_G:
- m_mmc3_chr_cb = waixing_g_chr_cb;
- break;
- case WAIXING_TYPE_H:
- m_mmc3_chr_cb = waixing_h_chr_cb;
- break;
- case WAIXING_SECURITY:
- m_mmc3_prg_cb = waixing_sec_prg_cb;
- m_mmc3_chr_cb = waixing_sec_chr_cb;
- break;
- case WAIXING_SH2:
- m_mmc3_chr_cb = waixing_sh2_chr_cb;
- break;
- case UNL_8237:
- m_mmc3_prg_cb = unl_8237_prg_cb;
- m_mmc3_chr_cb = unl_8237_chr_cb;
- break;
- case UNL_H2288:
- m_mmc3_prg_cb = h2288_prg_cb;
- break;
- case SUPERGAME_BOOGERMAN:
- m_mmc3_prg_cb = sgame_boog_prg_cb;
- m_mmc3_chr_cb = sgame_boog_chr_cb;
- break;
- case UNL_KOF96:
- m_mmc3_prg_cb = kof96_prg_cb;
- m_mmc3_chr_cb = kof96_chr_cb;
- break;
- case KAY_PANDAPRINCE:
- m_mmc3_prg_cb = kay_pp_prg_cb;
- m_mmc3_chr_cb = kay_pp_chr_cb;
- break;
- case BMC_FK23C:
- case BMC_FK23CA:
- m_mmc3_prg_cb = fk23c_prg_cb;
- m_mmc3_chr_cb = fk23c_chr_cb;
- break;
- case BMC_S24IN1SC03:
- m_mmc3_prg_cb = bmc_s24in1sc03_prg_cb;
- m_mmc3_chr_cb = bmc_s24in1sc03_chr_cb;
- break;
- case BMC_PJOY84:
- m_mmc3_prg_cb = pjoy84_prg_cb;
- m_mmc3_chr_cb = pjoy84_chr_cb;
- break;
- }
-}
-
-/*************************************************************
-
- pcb_initialize
-
- Initialize all the necessary registers and quantities for
- emulation of each board
-
- *************************************************************/
-
-/* this is used by many boards (MMC3, MMC6 + most MMC3 pirate clone boards) */
-static void mmc3_common_initialize( running_machine &machine, int prg_mask, int chr_mask, int IRQ_type )
-{
- nes_state *state = machine.driver_data<nes_state>();
-
- state->m_mmc3_alt_irq = IRQ_type; // later MMC3 boards seem to use MMC6-type IRQ... more investigations are in progress at NESDev...
- state->m_mmc_prg_bank[0] = state->m_mmc_prg_bank[2] = 0xfe; // prg_bank[2] & prg_bank[3] remain always the same in most MMC3 variants
- state->m_mmc_prg_bank[1] = state->m_mmc_prg_bank[3] = 0xff; // but some pirate clone mappers change them after writing certain registers
- state->m_mmc3_latch = 0;
- state->m_mmc3_wram_protect = 0x80;
- state->m_mmc_prg_base = state->m_mmc_chr_base = 0;
- state->m_mmc_prg_mask = prg_mask;
- state->m_mmc_chr_mask = chr_mask;
- mmc3_set_prg(machine, state->m_mmc_prg_base, state->m_mmc_prg_mask);
- mmc3_set_chr(machine, state->m_mmc_chr_source, state->m_mmc_chr_base, state->m_mmc_chr_mask);
-}
-
-// WIP code
-int nes_state::pcb_initialize( int idx )
-{
- int err = 0, i;
-
- /* basic PRG config */
- prg32(0);
-
- /* some boards will not use this, but directly CHRROM (resp. CHRRAM) if the board only has VROM (resp. VRAM) */
- m_mmc_chr_source = m_chr_chunks ? CHRROM : CHRRAM;
- chr8(0, m_mmc_chr_source);
-
- /* Here, we init a few helpers: 4 prg banks and 16 chr banks - some mappers use them */
- for (i = 0; i < 4; i++)
- m_mmc_prg_bank[i] = 0;
- for (i = 0; i < 16; i++)
- m_mmc_vrom_bank[i] = 0;
- for (i = 0; i < 16; i++)
- m_mmc_extra_bank[i] = 0;
-
- m_mmc_latch1 = 0;
- m_mmc_latch2 = 0;
-
- /* Finally, we init IRQ-related quantities. */
- m_IRQ_enable = m_IRQ_enable_latch = 0;
- m_IRQ_count = m_IRQ_count_latch = 0;
- m_IRQ_toggle = 0;
-
- switch (idx)
- {
- /* many boards only needs PRG to point at first 32k and CHR at first 8k */
- case STD_NROM: // mapper 0
- case HVC_FAMBASIC:
- case GG_NROM:
- case UXROM_CC: // mapper 180
- case STD_CNROM: // mapper 3, 185
- case BANDAI_PT554:
- case TENGEN_800008:
- case STD_BXROM: // mapper 34
- case STD_GXROM: // mapper 66
- case STD_MXROM:
- case BANDAI_OEKAKIDS: // mapper 96
- case JALECO_JF11: // mapper 140
- case JALECO_JF13: // mapper 86
- case JALECO_JF19: // mapper 92
- case DIS_74X377: // mapper 11
- case DIS_74X161X138: // mapper 38
- case CALTRON_6IN1: // mapper 41
- case TXC_STRIKEWOLF: // mapper 36
- case UNL_STUDYNGAME: // mapper 39
- case RUMBLESTATION_BOARD: // mapper 46
- case BMC_GKB: // mapper 58
- case RCM_TETRISFAMILY: // mapper 61
- case BMC_SUPER_700IN1: // mapper 62
- case MAGICSERIES_MD: // mapper 107
- case HES_BOARD: // mapper 113
- case HES6IN1_BOARD: // mapper 113
- case SACHEN_SA72008: // mapper 133
- case SACHEN_TCU02: // mapper 136
- case SACHEN_SA72007: // mapper 145
- case SACHEN_TCU01: // mapper 147
- case SACHEN_SA009: // mapper 160
- case SACHEN_SA0037: // mapper 148
- case SACHEN_SA0036: // mapper 149
- case AGCI_50282: // mapper 144
- case KAISER_KS7058: // mapper 171
- case HENGEDIANZI_BOARD: // mapper 177
- case WAIXING_SGZLZ: // mapper 178
- case HENGEDIANZI_XJZB: // mapper 179
- case BMC_21IN1: // mapper 201
- case BMC_9999999IN1: // mapper 213
- case RCM_GS2015: // mapper 216
- case BMC_72IN1: // mapper 225
- case BMC_76IN1: // mapper 226
- case BMC_SUPER_42IN1: // mapper 226
- case ACTENT_ACT52: // mapper 228
- case CNE_SHLZ: // mapper 240
- case TXC_MXMDHTWO: // mapper 241
- case WAIXING_ZS: // mapper 242
- case WAIXING_DQ8: // mapper 242
- case CNE_DECATHLON: // mapper 244
- case UNL_CC21:
- case BMC_VT5201:
- case BMC_WS:
- case UNL_EDU2K:
- break;
-
- /* other boards need additional initialization */
- case STD_UXROM: // mapper 2
- case STD_UN1ROM: // mapper 94
- case STD_JXROM: // mapper 69
- case SUNSOFT_5B:
- case SUNSOFT_FME7:
- case NAMCOT_3425: // mapper 95
- case DIS_74X139X74: // mapper 87
- case DIS_74X161X161X32: // mapper 152 & 70
- case BANDAI_LZ93: // mapper 16, 157
- case BANDAI_LZ93EX: // same + EEPROM
- case BANDAI_DATACH:
- case BANDAI_FCG:
- case IREM_HOLYDIV: // mapper 78
- case IREM_G101: // mapper 32
- case IREM_H3001: // mapper 65
- case JALECO_SS88006: // mapper 18
- case JALECO_JF16: // mapper 78
- case JALECO_JF17: // mapper 72
- case KONAMI_VRC1: // mapper 75
- case KONAMI_VRC2:
- case KONAMI_VRC3: // mapper 73
- case KONAMI_VRC4:
- case KONAMI_VRC6:
- case SUNSOFT_3: // mapper 67
- case TAITO_TC0190FMC: // mapper 33
- case TAITO_TC0190FMCP: // mapper 48
- case TAITO_X1_005: // mapper 80
- case TAITO_X1_005_A: // mapper 207
- case TAITO_X1_017: // mapper 82
- case NTDEC_ASDER: // mapper 112
- case FUTUREMEDIA_BOARD: // mapper 117
- case BTL_DRAGONNINJA: // mapper 222
- case WAIXING_SGZ: // mapper 252
- case UNL_T230:
- case BMC_NTD_03:
- case KAISER_KS7022:
- case UNL_SHJY3:
- case KAISER_KS7017:
- case KAISER_KS7032:
- case KAISER_KS202:
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- break;
-
- case STD_CPROM: // mapper 13
- chr4_0(0, CHRRAM);
- chr4_4(0, CHRRAM);
- break;
- case STD_AXROM: // mapper 7
- set_nt_mirroring(PPU_MIRROR_LOW);
- break;
- case STD_SXROM: // mapper 1, 155
- case STD_SOROM:
- case STD_SXROM_A:
- case STD_SOROM_A:
- m_mmc1_latch = 0;
- m_mmc1_count = 0;
- m_mmc_reg[0] = 0x0f;
- m_mmc_reg[1] = m_mmc_reg[2] = m_mmc_reg[3] = 0;
- m_mmc1_reg_write_enable = 1;
- set_nt_mirroring(PPU_MIRROR_HORZ);
- mmc1_set_chr(machine());
- mmc1_set_prg(machine());
- if (m_battery || m_wram)
- wram_bank(0, (idx == STD_SOROM) ? NES_WRAM : NES_BATTERY);
- break;
- case STD_PXROM: // mapper 9
- m_mmc_reg[0] = m_mmc_reg[2] = 0;
- m_mmc_reg[1] = m_mmc_reg[3] = 0;
- m_mmc_latch1 = m_mmc_latch2 = 0xfe;
- prg8_89(0);
- prg8_ab((m_prg_chunks << 1) - 3);
- prg8_cd((m_prg_chunks << 1) - 2);
- prg8_ef((m_prg_chunks << 1) - 1);
- break;
- case STD_FXROM: // mapper 10
- m_mmc_reg[0] = m_mmc_reg[2] = 0;
- m_mmc_reg[1] = m_mmc_reg[3] = 0;
- m_mmc_latch1 = m_mmc_latch2 = 0xfe;
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- break;
- case STD_TXROM: // mapper 4
- case STD_TVROM:
- case STD_TKROM:
- case REXSOFT_DBZ5: // mapper 12
- case WAIXING_TYPE_A: // mapper 74
- case WAIXING_TYPE_A_1:
- case STD_TXSROM: // mapper 118
- case STD_TQROM: // mapper 119
- case WAIXING_SH2: // mapper 165
- case WAIXING_TYPE_B: // mapper 191
- case WAIXING_TYPE_C: // mapper 192
- case WAIXING_TYPE_D: // mapper 194
- case WAIXING_TYPE_E: // mapper 195
- case WAIXING_TYPE_H: // mapper 245
- case BTL_SUPERBROS11: // mapper 196
- case UNL_KS7057: // mapper 196 alt (for Street Fighter VI / Fight Street VI)
- case UNL_H2288: // mapper 123
- case UNL_KOF97:
- case UNL_603_5052:
- case NITRA_TDA: // mapper 250
- if (m_four_screen_vram) // only TXROM and DXROM have 4-screen mirroring
- {
- set_nt_page(0, CART_NTRAM, 0, 1);
- set_nt_page(1, CART_NTRAM, 1, 1);
- set_nt_page(2, CART_NTRAM, 2, 1);
- set_nt_page(3, CART_NTRAM, 3, 1);
- }
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
- case STD_HKROM: // MMC6 (basically the same as TxROM, but alt IRQ behaviour)
- mmc3_common_initialize(machine(), 0xff, 0xff, 1);
- m_mmc6_reg = 0xf0;
- m_mmc_latch2 = 0; // this is used differently here compared to MMC3
- break;
- case PAL_ZZ: // mapper 37
- mmc3_common_initialize(machine(), 0x07, 0x7f, 0);
- break;
- case NES_QJ: // mapper 47
- mmc3_common_initialize(machine(), 0x0f, 0x7f, 0);
- break;
- case STD_EXROM: // mapper 5
- m_MMC5_rom_bank_mode = 3;
- m_MMC5_vrom_bank_mode = 0;
- m_MMC5_vram_protect = 0;
- m_mmc5_high_chr = 0;
- m_mmc5_vram_control = 0;
- m_mmc5_split_scr = 0;
- memset(m_MMC5_vrom_bank, 0, ARRAY_LENGTH(m_MMC5_vrom_bank));
- m_mmc5_prg_mode = 3;
- m_mmc5_last_chr_a = 1;
- m_mmc5_prg_regs[0] = 0xfc;
- m_mmc5_prg_regs[1] = 0xfd;
- m_mmc5_prg_regs[2] = 0xfe;
- m_mmc5_prg_regs[3] = 0xff;
- memset(m_mmc5_vrom_regA, ~0, ARRAY_LENGTH(m_mmc5_vrom_regA));
- memset(m_mmc5_vrom_regB, ~0, ARRAY_LENGTH(m_mmc5_vrom_regB));
- prg16_89ab(m_prg_chunks - 2);
- prg16_cdef(m_prg_chunks - 1);
- break;
- case STD_NXROM: // mapper 68
- case SUNSOFT_DCS: // mapper 68
- m_mmc_reg[0] = 0;
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- break;
- case NAMCOT_34X3: // mapper 88
- case STD_DXROM: // mapper 206
- case STD_DRROM:
- if (m_four_screen_vram) // only TXROM and DXROM have 4-screen mirroring
- {
- set_nt_page(0, CART_NTRAM, 0, 1);
- set_nt_page(1, CART_NTRAM, 1, 1);
- set_nt_page(2, CART_NTRAM, 2, 1);
- set_nt_page(3, CART_NTRAM, 3, 1);
- }
- case NAMCOT_3453: // mapper 154
- prg16_89ab(m_prg_chunks - 2);
- prg16_cdef(m_prg_chunks - 1);
- break;
- case NAMCOT_3446: // mapper 76
- prg8_89(0);
- prg8_ab(1);
- prg16_cdef(m_prg_chunks - 1);
- chr2_0(0, CHRROM);
- chr2_2(1, CHRROM);
- chr2_4(2, CHRROM);
- chr2_6(3, CHRROM);
- break;
- case BANDAI_JUMP2: // mapper 153
- for (i = 0; i < 8; i++)
- m_mmc_reg[i] = 0;
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- fjump2_set_prg(machine());
- break;
- case BANDAI_KARAOKE: // mapper 188
- prg16_89ab(0);
- prg16_cdef((m_prg_chunks - 1) ^ 0x08);
- break;
- case IREM_LROG017: // mapper 77
- chr2_2(0, CHRROM);
- chr2_4(1, CHRROM);
- chr2_6(2, CHRROM);
- break;
- case IREM_TAM_S1: // mapper 97
- prg16_89ab(m_prg_chunks - 1);
- prg16_cdef(0);
- break;
- case KONAMI_VRC7: // mapper 85
- prg8_89(0);
- prg8_ab(0);
- prg8_cd(0);
- prg8_ef(0xff);
- break;
- case NAMCOT_163: // mapper 19
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- case SUNSOFT_1: // mapper 184
- case SUNSOFT_2: // mapper 89 & 93
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- if (!m_hard_mirroring)
- set_nt_mirroring(PPU_MIRROR_LOW);
- break;
-
- // mapper 14
- case REXSOFT_SL1632:
- m_mmc_extra_bank[2] = 0xfe;
- m_mmc_extra_bank[3] = 0xff;
- m_mmc_extra_bank[0] = m_mmc_extra_bank[1] = m_mmc_extra_bank[4] = m_mmc_extra_bank[5] = m_mmc_extra_bank[6] = 0;
- m_mmc_extra_bank[7] = m_mmc_extra_bank[8] = m_mmc_extra_bank[9] = m_mmc_extra_bank[0xa] = m_mmc_extra_bank[0xb] = 0;
- m_mmc_reg[0] = m_mmc_reg[1] = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
- // mapper 15
- case WAIXING_PS2:
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
-
- // mapper 35
- case UNL_SC127:
- // mapper 42
- case BTL_MARIOBABY:
- case BTL_AISENSHINICOL:
- prg32(0xff);
- break;
-
- // mapper 40
- case BTL_SMB2A:
- prg8_67(0xfe);
- prg8_89(0xfc);
- prg8_ab(0xfd);
- prg8_cd(0xfe);
- prg8_ef(0xff);
- break;
-
- // mapper 43
- case UNL_SMB2J:
- if (m_battery)
- memset(m_battery_ram, 0x2000, 0xff);
- else if (m_prg_ram)
- memset(m_wram, 0x2000, 0xff);
- break;
- // mapper 44
- case BMC_SUPERBIG_7IN1:
- // mapper 49
- case BMC_SUPERHIK_4IN1:
- mmc3_common_initialize(machine(), 0x0f, 0x7f, 0);
- break;
- // mapper 45
- case BMC_HIK8IN1:
- m_mmc_reg[0] = m_mmc_reg[1] = m_mmc_reg[2] = m_mmc_reg[3] = 0;
- mmc3_common_initialize(machine(), 0x3f, 0xff, 0);
- break;
-
- // mapper 50
- case BTL_SMB2B:
- prg8_67(0x0f);
- prg8_89(0x08);
- prg8_ab(0x09);
- prg8_cd(0);
- prg8_ef(0x0b);
- break;
- // mapper 51
- case BMC_BALLGAMES_11IN1:
- m_mmc_reg[0] = 0x01;
- m_mmc_reg[1] = 0x00;
- bmc_ball11_set_banks(machine());
- break;
- // mapper 52
- case BMC_MARIOPARTY_7IN1:
- case BMC_GOLD_7IN1:
- m_map52_reg_written = 0;
- mmc3_common_initialize(machine(), 0x1f, 0xff, 0);
- break;
- // mapper 54
- case BMC_NOVELDIAMOND:
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- // mapper 57
- case BMC_GKA:
- prg16_89ab(0);
- prg16_cdef(0);
- break;
-
- // mapper 64
- case TENGEN_800032:
- // mapper 158
- case TENGEN_800037:
- prg16_89ab(m_prg_chunks - 1);
- prg16_cdef(m_prg_chunks - 1);
- break;
- // mapper 71
- case CAMERICA_BF9097:
- set_nt_mirroring(PPU_MIRROR_HORZ);
- case CAMERICA_BF9093:
- prg32(0xff);
- break;
-
- // mapper 79 (& 146)
- case AVE_NINA06:
- set_nt_mirroring(PPU_MIRROR_HORZ);
- break;
-
- // mapper 83
- case CONY_BOARD:
- case YOKO_BOARD:
- m_mapper83_reg[9] = 0x0f;
- prg8_cd(0x1e);
- prg8_ef(0x1f);
- break;
-
- // mapper 91
- case UNL_MK2:
- set_nt_mirroring(PPU_MIRROR_VERT);
- prg16_89ab(m_prg_chunks - 1);
- prg16_cdef(m_prg_chunks - 1);
- break;
-
- // mapper 104
- case CAMERICA_GOLDENFIVE:
- prg16_89ab(0x00);
- prg16_cdef(0x0f);
- break;
- // mapper 106
- case BTL_SMB3:
- prg8_89((m_prg_chunks << 1) - 1);
- prg8_ab(0);
- prg8_cd(0);
- prg8_ef((m_prg_chunks << 1) - 1);
- break;
-
- // mapper 108
- case WHIRLWIND_2706:
- prg32(0xff);
- break;
-
- // mapper 114
- case SUPERGAME_LIONKING:
- m_map114_reg = m_map114_reg_enabled = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
- // mapper 115
- case KASING_BOARD:
- m_mmc_reg[0] = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
- // mapper 116
- case SOMERI_SL12:
- m_mmc_prg_base = m_mmc_chr_base = 0;
- m_mmc_prg_mask = 0xff;
- m_mmc_chr_mask = 0xff;
- m_mmc_cmd1 = 2; // mode
- m_mmc3_latch = 0;
- m_mmc3_wram_protect = 0;
- // MMC1 regs
- m_mmc1_count = 0;
- m_mmc_reg[0] = 0x0c;
- m_mmc_reg[1] = 0x00;
- m_mmc_reg[2] = 0x00;
- m_mmc_reg[3] = 0x00;
- // MMC3 regs
- m_mmc_prg_bank[0] = 0x3c;
- m_mmc_prg_bank[1] = 0x3d;
- m_mmc_prg_bank[2] = 0xfe;
- m_mmc_prg_bank[3] = 0xff;
- 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;
- // VRC2 regs
- m_mmc_prg_bank[4] = 0x00;
- m_mmc_prg_bank[5] = 0x01;
- for (i = 0; i < 8; ++i)
- m_mmc_vrom_bank[6 + i] = i;
- someri_mode_update(machine());
- break;
-
- // mapper 120
- case BTL_TOBIDASE:
- prg32(2);
- break;
-
- // mapper 121
- case KAY_PANDAPRINCE:
- m_mmc_reg[5] = m_mmc_reg[6] = m_mmc_reg[7] = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
-
- // mapper 126
- case BMC_PJOY84:
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- m_mmc_reg[0] = m_mmc_reg[1] = m_mmc_reg[2] = m_mmc_reg[3] = 0;
- pjoy84_set_base_mask(machine());
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
-
- // mapper 132
- case TXC_22211A:
- // mapper 172
- case TXC_22211B:
- // mapper 173
- case TXC_22211C:
- m_txc_reg[0] = m_txc_reg[1] = m_txc_reg[2] = m_txc_reg[3] = 0;
- break;
-
- // mapper 134
- case BMC_FAMILY_4646B:
- mmc3_common_initialize(machine(), 0x1f, 0xff, 0);
- break;
-
- // mapper 137
- case SACHEN_8259D:
- chr8(m_chr_chunks - 1, CHRROM);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- // mapper 138
- case SACHEN_8259B:
- // mapper 139
- case SACHEN_8259C:
- // mapper 141
- case SACHEN_8259A:
- // mapper 150
- case SACHEN_74LS374:
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- // mapper 143
- case SACHEN_TCA01:
- prg16_89ab(0);
- prg16_cdef(1);
- break;
-
- // mapper 156
- case OPENCORP_DAOU306:
- prg16_89ab(m_prg_chunks - 2);
- prg16_cdef(m_prg_chunks - 1);
- set_nt_mirroring(PPU_MIRROR_LOW);
- break;
- // mapper 163
- case NANJING_BOARD:
- m_mmc_count = 0xff;
- m_mmc_reg[0] = 0xff;
- m_mmc_reg[1] = 0;
- prg16_89ab(m_prg_chunks - 2);
- prg16_cdef(m_prg_chunks - 1);
- break;
- // mapper 164
- case WAIXING_FFV:
- prg16_89ab(0);
- prg16_cdef(0x1f);
- break;
- // mapper 166
- case SUBOR_TYPE1:
- m_subor_reg[0] = m_subor_reg[1] = m_subor_reg[2] = m_subor_reg[3] = 0;
- prg16_89ab(0);
- prg16_cdef(0x07);
- break;
- // mapper 167
- case SUBOR_TYPE0:
- m_subor_reg[0] = m_subor_reg[1] = m_subor_reg[2] = m_subor_reg[3] = 0;
- prg16_89ab(0);
- prg16_cdef(0x20);
- break;
-
- // mapper 176
- case UNL_XZY:
- // mapper 182
- case HOSENKAN_BOARD:
- prg32((m_prg_chunks - 1) >> 1);
- break;
-
- case FUKUTAKE_BOARD: // mapper 186
- prg16_89ab(0);
- prg16_cdef(0);
- break;
-
- // mapper 187
- case UNL_KOF96:
- m_mmc_reg[0] = m_mmc_reg[1] = m_mmc_reg[2] = m_mmc_reg[3] = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
- // mapper 189
- case TXC_TW:
- m_mmc_latch1 = 0;
- m_mmc_latch2 = 0x80;
- m_mmc_chr_base = 0;
- m_mmc_chr_mask = 0xff;
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
- // mapper 193
- case NTDEC_FIGHTINGHERO:
- prg32((m_prg_chunks - 1) >> 1);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- // mapper 197
- case UNL_SUPERFIGHTER3:
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- unl_sf3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
- // mapper 198
- case WAIXING_TYPE_F:
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- m_mmc_prg_bank[0] = 0x00;
- m_mmc_prg_bank[1] = 0x01;
- m_mmc_prg_bank[2] = 0x4e;
- m_mmc_prg_bank[3] = 0x4f;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
- // mapper 199
- case WAIXING_TYPE_G:
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- m_mmc_prg_bank[0] = 0x00;
- m_mmc_prg_bank[1] = 0x01;
- m_mmc_prg_bank[2] = 0x3e;
- m_mmc_prg_bank[3] = 0x3f;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- m_mmc_vrom_bank[0] = 0x00;
- m_mmc_vrom_bank[1] = 0x02;
- 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_mmc_vrom_bank[6] = 0x01;
- m_mmc_vrom_bank[7] = 0x03;
- waixing_g_set_chr(machine(), m_mmc_chr_base, m_mmc_chr_mask);
- break;
-
- // mapper 200
- case BMC_36IN1:
- prg16_89ab(m_prg_chunks - 1);
- prg16_cdef(m_prg_chunks - 1);
- break;
-
- // mapper 202
- case BMC_150IN1:
- // mapper 203
- case BMC_35IN1:
- // mapper 204
- case BMC_64IN1:
- // mapper 214
- case BMC_SUPERGUN_20IN1:
- prg16_89ab(0);
- prg16_cdef(0);
- break;
- // mapper 205
- case BMC_15IN1:
- mmc3_common_initialize(machine(), 0x1f, 0xff, 0);
- m_mmc_prg_base = 0x10; // this board has a diff prg_base
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
-
- // mapper 208
- case GOUDER_37017:
- m_mmc_reg[0] = m_mmc_reg[1] = m_mmc_reg[2] = m_mmc_reg[3] = m_mmc_reg[4] = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
- // mapper 212
- case BMC_SUPERHIK_300IN1:
- chr8(0xff, CHRROM);
- prg32(0xff);
- break;
-
- // mapper 215
- case SUPERGAME_BOOGERMAN:
- m_mmc_reg[0] = 0x00;
- m_mmc_reg[1] = 0xff;
- m_mmc_reg[2] = 0x04;
- m_mmc_reg[3] = 0;
- mmc3_common_initialize(machine(), 0x1f, 0xff, 0);
- sgame_boog_set_prg(machine());
- mmc3_set_chr(machine(), m_mmc_chr_source, m_mmc_chr_base, m_mmc_chr_mask);
- break;
-
- // mapper 217
- case BMC_GOLDENCARD_6IN1:
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- m_mmc_reg[0] = 0x00;
- m_mmc_reg[1] = 0xff;
- m_mmc_reg[2] = 0x03;
- m_mmc_reg[3] = 0;
- bmc_gc6in1_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- bmc_gc6in1_set_chr(machine(), m_mmc_chr_source);
- break;
- // mapper 221
- case UNL_N625092:
- prg16_89ab(0);
- prg16_cdef(0);
- break;
-
- // mapper 223?
- case WAIXING_TYPE_I:
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- m_mmc3_wram_protect = 0;
- break;
-
- // mapper 224?
- case WAIXING_TYPE_J:
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- m_mmc_prg_bank[0] = 0x01;
- m_mmc_prg_bank[1] = 0x02;
- m_mmc_prg_bank[2] = 0x7e;
- m_mmc_prg_bank[3] = 0x7f;
- mmc3_set_prg(machine(), m_mmc_prg_base, m_mmc_prg_mask);
- break;
-
- // mapper 227
- case BMC_1200IN1:
- prg16_89ab(0);
- prg16_cdef(0);
- break;
-
- // mapper 229
- case BMC_31IN1:
- prg16_89ab(0);
- prg16_cdef(1);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- // mapper 230
- case BMC_22GAMES:
- prg16_89ab(0);
- prg16_cdef(7);
- break;
- // mapper 231
- case BMC_20IN1:
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- // mapper 232
- case CAMERICA_BF9096:
- m_mmc_latch1 = 0x18;
- m_mmc_latch2 = 0x00;
- bf9096_set_prg(machine());
- break;
-
- // mapper 243
- case SACHEN_74LS374_A:
- m_mmc_vrom_bank[0] = 3;
- chr8(3, CHRROM);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
-
- // mapper 246
- case CNE_FSB:
- prg32(0xff);
- break;
- // mapper 249
- case WAIXING_SECURITY:
- m_mmc_reg[0] = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
-
- // mapper 254
- case BTL_PIKACHUY2K:
- m_mmc_reg[0] = 0xff;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
-
- // mapper 255
- case BMC_110IN1:
- prg16_89ab(0);
- prg16_cdef(1);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
-
- // UNIF only
- case BMC_64IN1NR:
- m_mmc_reg[0] = 0x80;
- m_mmc_reg[1] = 0x43;
- m_mmc_reg[2] = m_mmc_reg[3] = 0;
- bmc_64in1nr_set_prg(machine());
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- case BMC_190IN1:
- prg16_89ab(0);
- prg16_cdef(0);
- break;
- case BMC_A65AS:
- prg16_89ab(0);
- prg16_cdef(7);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
- case BMC_GS2004:
- case BMC_GS2013:
- prg32(0xff);
- break;
- case BMC_S24IN1SC03:
- m_mmc_reg[0] = 0x24;
- m_mmc_reg[1] = 0x9f;
- m_mmc_reg[2] = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
- case BMC_T262:
- m_mmc_latch1 = 0;
- m_mmc_latch2 = 0;
- prg16_89ab(0);
- prg16_cdef(7);
- break;
- case DREAMTECH_BOARD:
- prg16_89ab(0);
- prg16_cdef(8);
- break;
- case UNL_8237:
- m_mmc_reg[0] = m_mmc_reg[1] = m_mmc_reg[2] = 0;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- break;
- case UNL_AX5705:
- m_mmc_prg_bank[0] = 0;
- m_mmc_prg_bank[1] = 1;
- prg8_89(m_mmc_prg_bank[0]);
- prg8_ab(m_mmc_prg_bank[1]);
- prg8_cd(0xfe);
- prg8_ef(0xff);
- break;
- case UNL_RACERMATE:
- chr4_0(0, m_mmc_chr_source);
- chr4_4(0, m_mmc_chr_source);
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- break;
-
- case BMC_BENSHENG_BS5:
- m_mmc_prg_bank[0] = 0xff;
- m_mmc_prg_bank[1] = 0xff;
- m_mmc_prg_bank[2] = 0xff;
- m_mmc_prg_bank[3] = 0xff;
- bmc_bs5_update_banks(machine());
- break;
-
- case BMC_810544:
- prg16_89ab(0);
- prg16_cdef(0);
- set_nt_mirroring(PPU_MIRROR_VERT);
- break;
-
- case BMC_G63IN1:
- bmc_gb63_update(machine());
- break;
-
- case BMC_FK23C:
- m_mmc_reg[0] = 4;
- m_mmc_reg[1] = 0xff;
- m_mmc_reg[2] = m_mmc_reg[3] = 0;
- m_mmc_reg[4] = m_mmc_reg[5] = m_mmc_reg[6] = m_mmc_reg[7] = 0xff;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- fk23c_set_prg(machine());
- fk23c_set_chr(machine());
- break;
-
- case BMC_FK23CA:
- m_mmc_reg[0] = m_mmc_reg[1] = m_mmc_reg[2] = m_mmc_reg[3] = 0;
- m_mmc_reg[4] = m_mmc_reg[5] = m_mmc_reg[6] = m_mmc_reg[7] = 0xff;
- mmc3_common_initialize(machine(), 0xff, 0xff, 0);
- fk23c_set_prg(machine());
- fk23c_set_chr(machine());
- break;
-
-
- case FFE_MAPPER6:
- prg16_89ab(0);
- prg16_cdef(7);
- break;
- case FFE_MAPPER8:
- prg32(0);
- break;
- case FFE_MAPPER17:
- prg16_89ab(0);
- prg16_cdef(m_prg_chunks - 1);
- break;
-
- case UNSUPPORTED_BOARD:
- default:
- /* Mapper not supported */
- err = 2;
- break;
- }
-
- return err;
-}
-
-/*************************************************************
-
- nes_pcb_reset
-
- Resets the mmc bankswitch areas to their defaults.
- It returns a value "err" that indicates if it was
- successful. Possible values for err are:
-
- 0 = success
- 1 = no pcb found
- 2 = pcb not supported
-
- *************************************************************/
-
-int nes_state::nes_pcb_reset()
-{
- int err = 0;
- const nes_pcb_intf *intf = nes_pcb_intf_lookup(m_pcb_id);
-
- if (intf == NULL)
- fatalerror("Missing PCB interface\n");
-
- /* Set the mapper irq callback */
- ppu2c0x_scanline_delegate del_scanline;
- ppu2c0x_hblank_delegate del_hblank;
- if (intf) {
- del_scanline = intf->mmc_scanline;
- del_hblank = intf->mmc_hblank;
- if (!del_scanline.isnull()) del_scanline.late_bind(*this);
- if (!del_hblank.isnull()) del_hblank.late_bind(*this);
- } else {
- del_scanline = ppu2c0x_scanline_delegate();
- del_hblank = ppu2c0x_hblank_delegate();
+ if (temp_nvram)
+ auto_free(machine(), temp_nvram);
}
- m_ppu->set_scanline_callback(del_scanline);
- m_ppu->set_hblank_callback(del_hblank);
- err = pcb_initialize(m_pcb_id);
-
- return err;
}
diff --git a/src/mess/machine/nes_pirate.c b/src/mess/machine/nes_pirate.c
new file mode 100644
index 00000000000..64e7710d3ec
--- /dev/null
+++ b/src/mess/machine/nes_pirate.c
@@ -0,0 +1,1380 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for pirate cart PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the various PCBs used by Asian & Korean pirate games
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_pirate.h"
+
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_AGCI_50282 = &device_creator<nes_agci_device>;
+const device_type NES_DREAMTECH01 = &device_creator<nes_dreamtech_device>;
+const device_type NES_FUKUTAKE = &device_creator<nes_fukutake_device>;
+const device_type NES_FUTUREMEDIA = &device_creator<nes_futuremedia_device>;
+const device_type NES_MAGSERIES = &device_creator<nes_magseries_device>;
+const device_type NES_DAOU306 = &device_creator<nes_daou306_device>;
+const device_type NES_SUBOR0 = &device_creator<nes_subor0_device>;
+const device_type NES_SUBOR1 = &device_creator<nes_subor1_device>;
+const device_type NES_CC21 = &device_creator<nes_cc21_device>;
+const device_type NES_XIAOZY = &device_creator<nes_xiaozy_device>;
+const device_type NES_EDU2K = &device_creator<nes_edu2k_device>;
+const device_type NES_T230 = &device_creator<nes_t230_device>;
+const device_type NES_MK2 = &device_creator<nes_mk2_device>;
+const device_type NES_WHERO = &device_creator<nes_whero_device>;
+const device_type NES_43272 = &device_creator<nes_43272_device>;
+const device_type NES_TF1201 = &device_creator<nes_tf1201_device>;
+const device_type NES_CITYFIGHT = &device_creator<nes_cityfight_device>;
+
+
+nes_agci_device::nes_agci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_AGCI_50282, "NES Cart AGCI 50282 PCB", tag, owner, clock, "nes_agci50282", __FILE__)
+{
+}
+
+nes_dreamtech_device::nes_dreamtech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_DREAMTECH01, "NES Cart Dreamtech01 PCB", tag, owner, clock, "nes_dreamtech", __FILE__)
+{
+}
+
+nes_fukutake_device::nes_fukutake_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_FUKUTAKE, "NES Cart Fukutake Study Box PCB", tag, owner, clock, "nes_fukutake", __FILE__)
+{
+}
+
+nes_futuremedia_device::nes_futuremedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_FUTUREMEDIA, "NES Cart FutureMedia PCB", tag, owner, clock, "nes_futuremedia", __FILE__)
+{
+}
+
+nes_magseries_device::nes_magseries_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_MAGSERIES, "NES Cart Magical Series PCB", tag, owner, clock, "nes_magseries", __FILE__)
+{
+}
+
+nes_daou306_device::nes_daou306_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_DAOU306, "NES Cart Daou 306 PCB", tag, owner, clock, "nes_daou306", __FILE__)
+{
+}
+
+nes_subor0_device::nes_subor0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SUBOR0, "NES Cart Subor Type 0 PCB", tag, owner, clock, "nes_subor0", __FILE__)
+{
+}
+
+nes_subor1_device::nes_subor1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SUBOR1, "NES Cart Subor Type 1 PCB", tag, owner, clock, "nes_subor1", __FILE__)
+{
+}
+
+nes_cc21_device::nes_cc21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_CC21, "NES Cart CC-21 PCB", tag, owner, clock, "nes_cc21", __FILE__)
+{
+}
+
+nes_xiaozy_device::nes_xiaozy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_XIAOZY, "NES Cart Xiao Zhuan Yuan PCB", tag, owner, clock, "nes_xiaozy", __FILE__)
+{
+}
+
+nes_edu2k_device::nes_edu2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_EDU2K, "NES Cart Educational Computer 2000 PCB", tag, owner, clock, "nes_edu2k", __FILE__)
+{
+}
+
+nes_t230_device::nes_t230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_T230, "NES Cart T-230 PCB", tag, owner, clock, "nes_t230", __FILE__)
+{
+}
+
+nes_mk2_device::nes_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_MK2, "NES Cart Mortal Kombat 2 PCB", tag, owner, clock, "nes_mk2", __FILE__)
+{
+}
+
+nes_whero_device::nes_whero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WHERO, "NES Cart World Heroes PCB", tag, owner, clock, "nes_whero", __FILE__)
+{
+}
+
+nes_43272_device::nes_43272_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_43272, "NES Cart UNL-43272 PCB", tag, owner, clock, "nes_43272", __FILE__)
+{
+}
+
+nes_tf1201_device::nes_tf1201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TF1201, "NES Cart UNL-TF1201 PCB", tag, owner, clock, "nes_tf1201", __FILE__)
+{
+}
+
+nes_cityfight_device::nes_cityfight_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TF1201, "NES Cart City Fighter PCB", tag, owner, clock, "nes_cityfight", __FILE__)
+{
+}
+
+
+
+
+void nes_agci_device::device_start()
+{
+ common_start();
+}
+
+void nes_agci_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_dreamtech_device::device_start()
+{
+ common_start();
+}
+
+void nes_dreamtech_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(8);
+ chr8(0, m_chr_source);
+}
+
+void nes_fukutake_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+
+ // 2816 (?) bytes of RAM
+ m_ram = auto_alloc_array_clear(machine(), UINT8, 0xb00);
+ save_pointer(NAME(m_ram), 0xb00);
+}
+
+void nes_fukutake_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_futuremedia_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_clear));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+}
+
+void nes_futuremedia_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_clear = 0;
+ m_irq_enable = 0;
+ m_irq_count = m_irq_count_latch = 0;
+}
+
+void nes_magseries_device::device_start()
+{
+ common_start();
+}
+
+void nes_magseries_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_daou306_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_daou306_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 2);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_LOW);
+
+ memset(m_reg, 0, sizeof(m_reg));
+}
+
+void nes_subor0_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_subor0_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0x20);
+ chr8(0, m_chr_source);
+
+ memset(m_reg, 0, sizeof(m_reg));
+}
+
+void nes_subor1_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_subor1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0x07);
+ chr8(0, m_chr_source);
+
+ memset(m_reg, 0, sizeof(m_reg));
+}
+
+void nes_cc21_device::device_start()
+{
+ common_start();
+}
+
+void nes_cc21_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_xiaozy_device::device_start()
+{
+ common_start();
+}
+
+void nes_xiaozy_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32((m_prg_chunks - 1) >> 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_edu2k_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_edu2k_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_t230_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_mode));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_enable_latch));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_t230_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_mode = 0;
+ m_irq_enable = m_irq_enable_latch = 0;
+ m_irq_count = m_irq_count_latch = 0;
+
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+void nes_mk2_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_clear));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+}
+
+void nes_mk2_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 1);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+
+ m_irq_clear = 0;
+ m_irq_enable = 0;
+ m_irq_count = m_irq_count_latch = 0;
+}
+
+
+void nes_whero_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_enable_latch));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_whero_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0x100, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_enable_latch = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0;
+
+ m_reg = 0;
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+void nes_43272_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_43272_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32((m_prg_chunks - 1) >> 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0x81;
+}
+
+void nes_tf1201_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_prg));
+ save_item(NAME(m_swap));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_enable_latch));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_tf1201_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+ m_prg = 0;
+ m_swap = 0;
+ m_irq_enable = 0;
+ m_irq_enable_latch = 0;
+ m_irq_count = 0;
+}
+
+void nes_cityfight_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_prg_reg));
+ save_item(NAME(m_prg_mode));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_cityfight_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+ m_prg_reg = 0;
+ m_prg_mode = 0;
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ AGCI 50282 bootleg board emulation
+
+ Games: Death Race
+
+ iNES: mapper 144
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_agci_device::write_h)
+{
+ LOG_MMC(("agci write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ UINT8 temp = account_bus_conflict(offset, 0xff);
+ data = (data & temp) | (temp & 1);
+
+ chr8(data >> 4, CHRROM);
+ prg32(data);
+}
+
+/*-------------------------------------------------
+
+ Board DREAMTECH01
+
+ Games: Korean Igo
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_dreamtech_device::write_l)
+{
+ LOG_MMC(("dreamtech write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1020) /* 0x5020 */
+ prg16_89ab(data);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by Fukutake
+
+ Games: Study Box
+
+ iNES: mapper 186
+
+ In MESS: Unsupported.
+
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_fukutake_device::write_l)
+{
+ LOG_MMC(("fukutake write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset >= 0x200 && offset < 0x400)
+ {
+ if (offset & 1)
+ prg16_89ab(data);
+ else
+ m_latch = data >> 6;
+ }
+ else if (offset >= 0x400 && offset < 0xf00)
+ m_ram[offset - 0x400] = data;
+}
+
+READ8_MEMBER(nes_fukutake_device::read_l)
+{
+ LOG_MMC(("fukutake read_l, offset: %04x\n", offset));
+ offset += 0x100;
+
+ if (offset >= 0x200 && offset < 0x400)
+ {
+ if (offset == 0x200 || offset == 0x201 || offset == 0x203)
+ return 0x00;
+ else if (offset == 0x202)
+ return 0x40;
+ else
+ return 0xff;
+ }
+ else if (offset >= 0x400 && offset < 0xf00)
+ return m_ram[offset - 0x400];
+
+ return 0;
+}
+
+WRITE8_MEMBER(nes_fukutake_device::write_m)
+{
+ LOG_MMC(("fukutake write_m, offset: %04x, data: %02x\n", offset, data));
+ m_prgram[((m_latch * 0x2000) + offset) & (m_prgram_size - 1)] = data;
+}
+
+READ8_MEMBER(nes_fukutake_device::read_m)
+{
+ LOG_MMC(("fukutake read_m, offset: %04x\n", offset));
+ return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram_size - 1)];
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by Future Media
+
+ Games: Crayon Shin-chan (C), San Guo Zhi 4 - Chi Bi Feng Yun
+
+ iNES: mapper 117
+
+ In MESS: Unsupported.
+
+ -------------------------------------------------*/
+
+void nes_futuremedia_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ // if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ if (m_irq_enable && m_irq_count)
+ {
+ m_irq_count--;
+ if (!m_irq_count)
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+}
+
+WRITE8_MEMBER(nes_futuremedia_device::write_h)
+{
+ LOG_MMC(("futuremedia write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x0001:
+ prg8_ab(data);
+ break;
+ case 0x0002:
+ prg8_cd(data);
+ break;
+ case 0x0003:
+ prg8_ef(data);
+ break;
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ case 0x2004:
+ case 0x2005:
+ case 0x2006:
+ case 0x2007:
+ chr1_x(offset & 0x07, data, CHRROM);
+ break;
+
+ case 0x5000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x4001:
+ m_irq_count_latch = data;
+ break;
+ case 0x4002:
+ // IRQ cleared
+ break;
+ case 0x4003:
+ m_irq_count = m_irq_count_latch;
+ break;
+ case 0x6000:
+ m_irq_enable = data & 0x01;
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by Magic Series
+
+ Games: Magic Dragon
+
+ Very simple mapper: writes to 0x8000-0xffff set prg32 and chr8
+ banks
+
+ iNES: mapper 107
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_magseries_device::write_h)
+{
+ LOG_MMC(("magseries write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(data >> 1);
+ chr8(data, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Open Corp DAOU306 board
+
+ Games: Metal Force (K)
+
+ iNES: mapper 156
+
+ In MESS: Supported.
+
+ Notes: Metal Force and Buzz & Waldog only use the the first
+ 4 regs and no mirroring. Janggun ui Adeul uses all features
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_daou306_device::write_h)
+{
+ LOG_MMC(("daou306 write_h, offset: %04x, data: %02x\n", offset, data));
+ int reg = BIT(offset, 2) ? 8 : 0;
+
+ switch (offset)
+ {
+ case 0x4000:
+ case 0x4004:
+ m_reg[reg + 0] = data;
+ chr1_0(m_reg[0] | (m_reg[8] << 8), CHRROM);
+ break;
+ case 0x4001:
+ case 0x4005:
+ m_reg[reg + 1] = data;
+ chr1_1(m_reg[1] | (m_reg[9] << 8), CHRROM);
+ break;
+ case 0x4002:
+ case 0x4006:
+ m_reg[reg + 2] = data;
+ chr1_2(m_reg[2] | (m_reg[10] << 8), CHRROM);
+ break;
+ case 0x4003:
+ case 0x4007:
+ m_reg[reg + 3] = data;
+ chr1_3(m_reg[3] | (m_reg[11] << 8), CHRROM);
+ break;
+ case 0x4008:
+ case 0x400c:
+ m_reg[reg + 4] = data;
+ chr1_4(m_reg[4] | (m_reg[12] << 8), CHRROM);
+ break;
+ case 0x4009:
+ case 0x400d:
+ m_reg[reg + 5] = data;
+ chr1_5(m_reg[5] | (m_reg[13] << 8), CHRROM);
+ break;
+ case 0x400a:
+ case 0x400e:
+ m_reg[reg + 6] = data;
+ chr1_6(m_reg[6] | (m_reg[14] << 8), CHRROM);
+ break;
+ case 0x400b:
+ case 0x400f:
+ m_reg[reg + 7] = data;
+ chr1_7(m_reg[7] | (m_reg[15] << 8), CHRROM);
+ break;
+ case 0x4010:
+ prg16_89ab(data);
+ break;
+ case 0x4014:
+ if (data & 1)
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ else
+ set_nt_mirroring(PPU_MIRROR_VERT);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Subor bootleg board Type 0
+
+ iNES: mapper 167
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_subor0_device::write_h)
+{
+ UINT8 subor_helper1, subor_helper2;
+ LOG_MMC(("subor0 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ m_reg[(offset >> 13) & 0x03] = data;
+ subor_helper1 = ((m_reg[0] ^ m_reg[1]) << 1) & 0x20;
+ subor_helper2 = ((m_reg[2] ^ m_reg[3]) << 0) & 0x1f;
+
+ if (m_reg[1] & 0x08)
+ {
+ subor_helper1 += subor_helper2 & 0xfe;
+ subor_helper2 = subor_helper1;
+ subor_helper1 += 1;
+ }
+ else if (m_reg[1] & 0x04)
+ {
+ subor_helper2 += subor_helper1;
+ subor_helper1 = 0x1f;
+ }
+ else
+ {
+ subor_helper1 += subor_helper2;
+ subor_helper2 = 0x20;
+ }
+
+ prg16_89ab(subor_helper1);
+ prg16_cdef(subor_helper2);
+}
+
+/*-------------------------------------------------
+
+ Subor bootleg board Type 1
+
+ iNES: mapper 166
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_subor1_device::write_h)
+{
+ UINT8 subor_helper1, subor_helper2;
+ LOG_MMC(("subor1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ m_reg[(offset >> 13) & 0x03] = data;
+ subor_helper1 = ((m_reg[0] ^ m_reg[1]) << 1) & 0x20;
+ subor_helper2 = ((m_reg[2] ^ m_reg[3]) << 0) & 0x1f;
+
+ if (m_reg[1] & 0x08)
+ {
+ subor_helper1 += subor_helper2 & 0xfe;
+ subor_helper2 = subor_helper1;
+ subor_helper2 += 1;
+ }
+ else if (m_reg[1] & 0x04)
+ {
+ subor_helper2 += subor_helper1;
+ subor_helper1 = 0x1f;
+ }
+ else
+ {
+ subor_helper1 += subor_helper2;
+ subor_helper2 = 0x07;
+ }
+
+ prg16_89ab(subor_helper1);
+ prg16_cdef(subor_helper2);
+}
+
+/*-------------------------------------------------
+
+ Board UNL-CC-21
+
+ Games: Mi Hun Che
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_cc21_device::write_h)
+{
+ LOG_MMC(("cc21 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(BIT(offset, 1) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+ chr8((offset & 0x01), CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board for Xiao Zhuan Yuan
+
+ Games: Shu Qi Yu - Zhi Li Xiao Zhuan Yuan
+
+ Very simple mapper: writes to 0x5ff1 set prg32 (to data>>1),
+ while writes to 0x5ff2 set chr8
+
+ iNES: mapper 176
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_xiaozy_device::write_l)
+{
+ LOG_MMC(("xiaozy write_l, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1ef1: /* 0x5ff1 */
+ prg32(data >> 1);
+ break;
+ case 0x1ef2: /* 0x5ff2 */
+ chr8(data, CHRROM);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ UNL-EDU2000
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_edu2k_device::write_h)
+{
+ LOG_MMC(("edu2k write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(data & 0x1f);
+ m_latch = (data & 0xc0) >> 6;
+}
+
+WRITE8_MEMBER(nes_edu2k_device::write_m)
+{
+ LOG_MMC(("edu2k write_m, offset: %04x, data: %02x\n", offset, data));
+ m_prgram[((m_latch * 0x2000) + offset) & (m_prgram_size - 1)] = data;
+}
+
+READ8_MEMBER(nes_edu2k_device::read_m)
+{
+ LOG_MMC(("edu2k read_m, offset: %04x\n", offset));
+ return m_prgram[((m_latch * 0x2000) + offset) & (m_prgram_size - 1)];
+}
+
+/*-------------------------------------------------
+
+ Board UNL-T-230
+
+ Games: Dragon Ball Z IV (Unl)
+
+ This mapper appears to be similar to Konami VRC-2
+ but the game has no VROM and only 1 VRAM bank, so we
+ completely skip the chr bankswitch. If other games
+ using the same board and using CHR should surface,
+ we need to investigate this...
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+// Identical to Konami IRQ
+void nes_t230_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ /* Increment & check the IRQ scanline counter */
+ if (m_irq_enable && (++m_irq_count == 0x100))
+ {
+ m_irq_count = m_irq_count_latch;
+ m_irq_enable = m_irq_enable_latch;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+WRITE8_MEMBER(nes_t230_device::write_h)
+{
+ LOG_MMC(("t230 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x700c)
+ {
+ case 0x0000:
+ break;
+ case 0x2000:
+ prg16_89ab(data);
+ break;
+ case 0x1000:
+ case 0x1004:
+ case 0x1008:
+ case 0x100c:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+
+ case 0x7000:
+ m_irq_count_latch &= ~0x0f;
+ m_irq_count_latch |= data & 0x0f;
+ break;
+ case 0x7004:
+ m_irq_count_latch &= ~0xf0;
+ m_irq_count_latch |= (data << 4) & 0xf0;
+ break;
+ case 0x7008:
+ m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ m_irq_enable = data & 0x02;
+ m_irq_enable_latch = data & 0x01;
+ if (data & 0x02)
+ m_irq_count = m_irq_count_latch;
+ break;
+
+ default:
+ logerror("unl_t230_w uncaught offset: %04x value: %02x\n", offset, data);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board for MK2
+
+ Games: Mortal Kombat II, Street Fighter III, Super Mario
+ Kart Rider
+
+ This board uses an IRQ system very similar to MMC3. We indeed
+ use mapper4_irq, but there is some small glitch!
+
+ iNES: mapper 91
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+// Same IRQ as MMC3
+void nes_mk2_device::hblank_irq( int scanline, int vblank, int blanked )
+{
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ int prior_count = m_irq_count;
+ if ((m_irq_count == 0) || m_irq_clear)
+ m_irq_count = m_irq_count_latch;
+ else
+ m_irq_count--;
+
+ if (m_irq_enable && !blanked && (m_irq_count == 0) && (prior_count || m_irq_clear))
+ {
+ LOG_MMC(("irq fired, scanline: %d (MAME %d, beam pos: %d)\n", scanline,
+ machine().primary_screen->vpos(), machine().primary_screen->hpos()));
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+ m_irq_clear = 0;
+}
+
+WRITE8_MEMBER(nes_mk2_device::write_m)
+{
+ LOG_MMC(("mk2 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x1000)
+ {
+ case 0x0000:
+ switch (offset & 0x03)
+ {
+ case 0x00: chr2_0(data, CHRROM); break;
+ case 0x01: chr2_2(data, CHRROM); break;
+ case 0x02: chr2_4(data, CHRROM); break;
+ case 0x03: chr2_6(data, CHRROM); break;
+ }
+ break;
+ case 0x1000:
+ switch (offset & 0x03)
+ {
+ case 0x00: prg8_89(data); break;
+ case 0x01: prg8_ab(data); break;
+ case 0x02: m_irq_enable = 0; m_irq_count = 0; break;
+ case 0x03: m_irq_enable = 1; m_irq_count = 7; break;
+ }
+ break;
+ default:
+ logerror("mk2 write_m, uncaught addr: %04x value: %02x\n", offset + 0x6000, data);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+
+ UNL-WOLRDHERO board emulation
+
+
+ iNES:
+
+ -------------------------------------------------*/
+
+// Same as Konami VRC IRQ...
+void nes_whero_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ /* Increment & check the IRQ scanline counter */
+ if (m_irq_enable && (++m_irq_count == 0x100))
+ {
+ m_irq_count = m_irq_count_latch;
+ m_irq_enable = m_irq_enable_latch;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+WRITE8_MEMBER(nes_whero_device::write_h)
+{
+ int bank, shift, mask1, mask2;
+ LOG_MMC(("World Hero write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x70c3)
+ {
+ case 0x0000:
+ if (!m_reg)
+ prg8_89(data);
+ else
+ prg8_cd(data);
+ break;
+
+ case 0x1000:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+
+ case 0x1002:
+ case 0x1080:
+ if (m_reg != data & 2)
+ {
+ m_reg = data & 2;
+ // swap banks!
+ prg8_89(m_prg_bank[2]);
+ prg8_cd(m_prg_bank[0]);
+ }
+ break;
+
+ case 0x2000:
+ prg8_ab(data);
+ break;
+
+ case 0x3000: case 0x3001: case 0x3002: case 0x3003:
+ case 0x4000: case 0x4001: case 0x4002: case 0x4003:
+ case 0x5000: case 0x5001: case 0x5002: case 0x5003:
+ case 0x6000: case 0x6001: case 0x6002: case 0x6003:
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1);
+ shift = (offset & 1) << 2;
+ mask1 = shift ? 0x00f : 0xff0;
+ mask2 = shift ? 0xff0 : 0x00f;
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & mask1) | ((data << shift) & mask2);
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+
+ case 0x7000:
+ m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f);
+ break;
+
+ case 0x7001:
+ m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4);
+ break;
+
+ case 0x7002:
+ // m_irq_mode = data & 0x04; // currently not implemented: 0 = prescaler mode / 1 = CPU mode
+ m_irq_enable = data & 0x02;
+ m_irq_enable_latch = data & 0x01;
+ if (data & 0x02)
+ m_irq_count = m_irq_count_latch;
+ break;
+
+ case 0x7003:
+ m_irq_enable = m_irq_enable_latch;
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+
+ UNL-43272
+
+ Games: Gaau Hok Gwong Cheung
+
+ In MESS: Preliminary Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_43272_device::write_h)
+{
+ LOG_MMC(("unl_43272 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_latch & 0x81 == 0x81)
+ prg32((m_latch & 0x38) >> 3);
+
+ m_latch = offset & 0xffff;
+}
+
+
+READ8_MEMBER(nes_43272_device::read_h)
+{
+ UINT8 mask = (m_latch & 0x400) ? 0xfe : 0xff;
+ LOG_MMC(("unl_43272 read_h, offset: %04x\n", offset));
+
+ return hi_access_rom(offset & mask);
+}
+
+
+/*-------------------------------------------------
+
+ UNL-TF1201
+
+ Games:
+
+ In MESS: Preliminary Supported
+
+ -------------------------------------------------*/
+
+void nes_tf1201_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable_latch != m_irq_enable && scanline < 240)
+ m_irq_count -= 8;
+
+ if (m_irq_enable)
+ {
+ m_irq_count++;
+ if ((m_irq_count & 0xff) == 238)
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+void nes_tf1201_device::update_prg()
+{
+ prg8_89(m_swap ? 0xff : m_prg);
+ prg8_cd(m_swap ? m_prg : 0xff );
+}
+
+WRITE8_MEMBER(nes_tf1201_device::write_h)
+{
+ int bank;
+ LOG_MMC(("unl_tf1201 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ offset = (offset & 0x7003) | ((offset & 0x0c) >> 2); // nestopia does not OR here...
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ m_prg = data;
+ update_prg();
+ break;
+ case 0x1000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x1001:
+ m_swap = data & 0x03;
+ update_prg();
+ break;
+ case 0x2000:
+ prg8_ab(data);
+ break;
+ case 0x3000: case 0x3001: case 0x3002: case 0x3003:
+ case 0x4000: case 0x4001: case 0x4002: case 0x4003:
+ case 0x5000: case 0x5001: case 0x5002: case 0x5003:
+ case 0x6000: case 0x6001: case 0x6002: case 0x6003:
+ bank = (((offset - 0x3000) >> 11) | (offset & 0x1)) & 0x7;
+ if (offset & 2)
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
+ else
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
+ chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
+ break;
+ case 0x7000:
+ m_irq_count = (m_irq_count & 0xf0) | (data & 0x0f);
+ break;
+ case 0x7001:
+ case 0x7003:
+ m_irq_enable_latch = m_irq_enable;
+ m_irq_enable = BIT(data, 1);
+ break;
+ case 0x7002:
+ m_irq_count = (m_irq_count & 0x0f) | ((data & 0x0f) << 4);
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+
+ UNL-CITYFIGHT
+
+ Games:
+
+ Additional audio register not emulated yet!
+
+ In MESS: Preliminary Supported
+
+ -------------------------------------------------*/
+
+void nes_cityfight_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_enable)
+ {
+ if (m_irq_count <= 114)
+ {
+ m_irq_count = 0xffff;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ m_irq_count -= 114;
+ }
+}
+
+void nes_cityfight_device::update_prg()
+{
+ prg32(m_prg_reg >> 2);
+ if (!m_prg_mode)
+ prg8_cd(m_prg_reg);
+}
+
+WRITE8_MEMBER(nes_cityfight_device::write_h)
+{
+ int bank;
+ LOG_MMC(("unl_cityfight write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x700c)
+ {
+ case 0x1000:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ m_prg_reg = data & 0xc;
+ break;
+ case 0x1004:
+ case 0x1008:
+ case 0x100c:
+ if (offset & 0x800)
+ LOG_MMC(("Extended Audio write, data %x!", data & 0x0f));//pcmwrite(0x4011, (V & 0xf) << 3);
+ else
+ m_prg_reg = data & 0xc;
+ break;
+
+
+ case 0x2000: case 0x2004: case 0x2008: case 0x200c:
+ bank = 2 + BIT(offset, 3);
+ if (offset & 4)
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
+ else
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
+ chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
+ break;
+ case 0x3000: case 0x3004: case 0x3008: case 0x300c:
+ bank = 4 + BIT(offset, 3);
+ if (offset & 4)
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
+ else
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
+ chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
+ break;
+ case 0x5000: case 0x5004: case 0x5008: case 0x500c:
+ bank = 0 + BIT(offset, 3);
+ if (offset & 4)
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
+ else
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
+ chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
+ break;
+ case 0x6000: case 0x6004: case 0x6008: case 0x600c:
+ bank = 6 + BIT(offset, 3);
+ if (offset & 4)
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
+ else
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | ((data & 0x0f) << 0);
+ chr1_x(bank, m_mmc_vrom_bank[bank], m_chr_source);
+ break;
+
+ case 0x4000:
+ case 0x4004:
+ case 0x4008:
+ case 0x4003c:
+ m_prg_mode = data & 1;
+
+ case 0x7000:
+ m_irq_count = (m_irq_count & 0x1e0) | ((data & 0x0f) << 1);
+ break;
+ case 0x7004:
+ m_irq_count = (m_irq_count & 0x1e) | ((data & 0x0f) << 5);
+ break;
+ case 0x7008:
+ m_irq_enable = BIT(data, 1);
+ break;
+ }
+}
+
+
+#ifdef UNUSED_FUNCTION
+/*-------------------------------------------------
+
+ FUJIYA Board - mapper 170 according to NEStopia
+
+ Is this possibly for the Fujiya Famikase series
+ of educational titles? Is there any dump around?
+
+ -------------------------------------------------*/
+
+void nes_fujiya_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_fujiya_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+WRITE8_MEMBER(nes_fujiya_device::write_m)
+{
+ LOG_MMC(("fujiya write_m, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x6000;
+
+ if (offset == 0x6502 || offset == 0x7000)
+ m_latch = (data & 0x40) << 1;
+}
+
+READ8_MEMBER(nes_fujiya_device::read_m)
+{
+ LOG_MMC(("fujiya read_m, offset: %04x\n", offset));
+ offset += 0x6000;
+
+ if (offset == 0x7001 || offset == 0x7777)
+ return m_latch | ((offset >> 8) & 0x7f);
+
+ return (offset & 0xff00) >> 8; // open bus
+}
+#endif
diff --git a/src/mess/machine/nes_pirate.h b/src/mess/machine/nes_pirate.h
new file mode 100644
index 00000000000..35b04bfc694
--- /dev/null
+++ b/src/mess/machine/nes_pirate.h
@@ -0,0 +1,394 @@
+#ifndef __NES_PIR_H
+#define __NES_PIR_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_agci_device
+
+class nes_agci_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_agci_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_dreamtech_device
+
+class nes_dreamtech_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_dreamtech_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_fukutake_device
+
+class nes_fukutake_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_fukutake_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+ UINT8 *m_ram;
+};
+
+
+// ======================> nes_futuremedia_device
+
+class nes_futuremedia_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_futuremedia_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count, m_irq_count_latch;
+ UINT8 m_irq_clear;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_magseries_device
+
+class nes_magseries_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_magseries_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_daou306_device
+
+class nes_daou306_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_daou306_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[16];
+};
+
+
+// ======================> nes_subor0_device
+
+class nes_subor0_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_subor0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[4];
+};
+
+
+// ======================> nes_subor1_device
+
+class nes_subor1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_subor1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[4];
+};
+
+
+// ======================> nes_cc21_device
+
+class nes_cc21_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_cc21_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_xiaozy_device
+
+class nes_xiaozy_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_xiaozy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_edu2k_device
+
+class nes_edu2k_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_edu2k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_t230_device
+
+class nes_t230_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_t230_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count, m_irq_count_latch;
+ UINT8 m_irq_mode;
+ int m_irq_enable, m_irq_enable_latch;
+
+ UINT8 m_mmc_vrom_bank[8];
+};
+
+
+// ======================> nes_mk2_device
+
+class nes_mk2_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_mk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count, m_irq_count_latch;
+ UINT8 m_irq_clear;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_whero_device
+
+class nes_whero_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_whero_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg;
+ UINT8 m_mmc_vrom_bank[8];
+
+ UINT16 m_irq_count, m_irq_count_latch;
+ int m_irq_enable, m_irq_enable_latch;
+// int m_irq_mode;
+};
+
+
+// ======================> nes_43272_device
+
+class nes_43272_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_43272_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_latch;
+};
+
+
+// ======================> nes_tf1201_device
+
+class nes_tf1201_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_tf1201_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ void update_prg();
+ UINT8 m_prg, m_swap;
+ UINT16 m_irq_count;
+ int m_irq_enable, m_irq_enable_latch;
+
+ UINT8 m_mmc_vrom_bank[8];
+};
+
+
+// ======================> nes_cityfight_device
+
+class nes_cityfight_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_cityfight_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ void update_prg();
+ UINT8 m_prg_reg, m_prg_mode;
+ UINT16 m_irq_count;
+ int m_irq_enable;
+
+ UINT8 m_mmc_vrom_bank[8];
+};
+
+
+
+#ifdef UNUSED_FUNCTION
+// ======================> nes_fujiya_device
+
+class nes_fujiya_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_fujiya_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+#endif
+
+
+// device type definition
+extern const device_type NES_AGCI_50282;
+extern const device_type NES_DREAMTECH01;
+extern const device_type NES_FUKUTAKE;
+extern const device_type NES_FUTUREMEDIA;
+extern const device_type NES_MAGSERIES;
+extern const device_type NES_DAOU306;
+extern const device_type NES_SUBOR0;
+extern const device_type NES_SUBOR1;
+extern const device_type NES_CC21;
+extern const device_type NES_XIAOZY;
+extern const device_type NES_EDU2K;
+extern const device_type NES_T230;
+extern const device_type NES_MK2;
+extern const device_type NES_WHERO;
+extern const device_type NES_43272;
+extern const device_type NES_TF1201;
+extern const device_type NES_CITYFIGHT;
+extern const device_type NES_FUJIYA;
+
+#endif
diff --git a/src/mess/machine/nes_pt554.c b/src/mess/machine/nes_pt554.c
new file mode 100644
index 00000000000..d6f5ab28745
--- /dev/null
+++ b/src/mess/machine/nes_pt554.c
@@ -0,0 +1,113 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Bandai PT-554 PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following Bandai PT-554 PCB (a CNROM PCB + ADPCM sound chip)
+
+ TODO:
+ - emulate the mat controller
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_pt554.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_BANDAI_PT554 = &device_creator<nes_bandai_pt554_device>;
+
+
+nes_bandai_pt554_device::nes_bandai_pt554_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_cnrom_device(mconfig, NES_BANDAI_PT554, "NES Cart Bandai PT-554 PCB", tag, owner, clock, "nes_bandai_pt554", __FILE__),
+ m_samples(*this, "samples")
+{
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bandai PT-554 board emulation
+
+ This is used by Aerobics Studio. It is basically a CNROM board
+ with an Mitsubishi M50805 sound chip with an internal ROM which
+ is not dumpable at the moment
+
+ iNES: mapper 3?
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_bandai_pt554_device::write_m)
+{
+ LOG_MMC(("Bandai PT-554 Sound write, data: %02x\n", data));
+
+ if (!BIT(data, 6))
+ m_samples->start(data & 0x07, data & 0x07);
+ else
+ m_samples->stop(data & 0x07);
+}
+
+static const char *const pt554_sample_names[] =
+{
+ "*ftaerobi",
+ "00",
+ "01",
+ "02",
+ "03",
+ "04",
+ "05",
+ "06",
+ "07",
+ 0
+};
+
+static const samples_interface pt554_samples_interface =
+{
+ 8, /* channels */
+ pt554_sample_names
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( pt554 )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SAMPLES_ADD("samples", pt554_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions
+//-------------------------------------------------
+
+machine_config_constructor nes_bandai_pt554_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pt554 );
+}
diff --git a/src/mess/machine/nes_pt554.h b/src/mess/machine/nes_pt554.h
new file mode 100644
index 00000000000..a1f5cd2ea35
--- /dev/null
+++ b/src/mess/machine/nes_pt554.h
@@ -0,0 +1,29 @@
+#ifndef __NES_PT554_H
+#define __NES_PT554_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_bandai_pt554_device
+
+class nes_bandai_pt554_device : public nes_cnrom_device
+{
+public:
+ // construction/destruction
+ nes_bandai_pt554_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+private:
+ required_device<samples_device> m_samples;
+};
+
+
+
+
+// device type definition
+extern const device_type NES_BANDAI_PT554;
+
+#endif
diff --git a/src/mess/machine/nes_racermate.c b/src/mess/machine/nes_racermate.c
new file mode 100644
index 00000000000..17116c6a487
--- /dev/null
+++ b/src/mess/machine/nes_racermate.c
@@ -0,0 +1,93 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for RacerMate PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the UNL-RACERMATE PCB [mapper 168]
+
+ TODO:
+ - save VRAM
+ - emulate the bike controller?
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_racermate.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_RACERMATE = &device_creator<nes_racermate_device>;
+
+
+nes_racermate_device::nes_racermate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_RACERMATE, "NES Cart Racermate PCB", tag, owner, clock, "nes_racermate", __FILE__)
+{
+}
+
+
+
+void nes_racermate_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_racermate_device::pcb_reset()
+{
+// m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr4_0(0, CHRRAM);
+ chr4_4(0, CHRRAM);
+
+ m_latch = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Board UNL-RACERMATE
+
+ In MESS: *VERY* preliminary support. Also, it seems that this
+ board saves to battery the CHRRAM!!!
+
+ -------------------------------------------------*/
+
+void nes_racermate_device::update_banks()
+{
+ chr4_4(m_latch & 0x0f, m_chr_source);
+ prg16_89ab(m_latch >> 6);
+}
+
+WRITE8_MEMBER(nes_racermate_device::write_h)
+{
+ LOG_MMC(("racermate write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x3000)
+ {
+ m_latch = data;
+ update_banks();
+ }
+}
diff --git a/src/mess/machine/nes_racermate.h b/src/mess/machine/nes_racermate.h
new file mode 100644
index 00000000000..fd4729bd30b
--- /dev/null
+++ b/src/mess/machine/nes_racermate.h
@@ -0,0 +1,33 @@
+#ifndef __NES_RACERMATE_H
+#define __NES_RACERMATE_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_racermate_device
+
+class nes_racermate_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_racermate_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ void update_banks();
+ UINT8 m_latch;
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_RACERMATE;
+
+#endif
diff --git a/src/mess/machine/nes_rcm.c b/src/mess/machine/nes_rcm.c
new file mode 100644
index 00000000000..6eb5e9a2656
--- /dev/null
+++ b/src/mess/machine/nes_rcm.c
@@ -0,0 +1,304 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for RCM PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * RCM GS2015 [mapper 216]
+ * RCM GS2004
+ * RCM GS2013
+ * RCM Tetris Family 9in1 [mapper 61]
+ * RCM 3D Block
+
+ TODO:
+ - investigate why 3D Block does not work
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_rcm.h"
+
+#include "cpu/m6502/m6502.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_GS2015 = &device_creator<nes_gs2015_device>;
+const device_type NES_GS2004 = &device_creator<nes_gs2004_device>;
+const device_type NES_GS2013 = &device_creator<nes_gs2013_device>;
+const device_type NES_TF9IN1 = &device_creator<nes_tf9_device>;
+const device_type NES_3DBLOCK = &device_creator<nes_3dblock_device>;
+
+
+nes_gs2015_device::nes_gs2015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_GS2015, "NES Cart RCM GS-2015 PCB", tag, owner, clock, "nes_gs2015", __FILE__)
+{
+}
+
+nes_gs2004_device::nes_gs2004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_GS2004, "NES Cart RCM GS-2004 PCB", tag, owner, clock, "nes_gs2004", __FILE__)
+{
+}
+
+nes_gs2013_device::nes_gs2013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_GS2013, "NES Cart RCM GS-2013 PCB", tag, owner, clock, "nes_gs2013", __FILE__)
+{
+}
+
+nes_tf9_device::nes_tf9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TF9IN1, "NES Cart RCM Tetris Family 9 in 1 PCB", tag, owner, clock, "nes_tetrisfam", __FILE__)
+{
+}
+
+nes_3dblock_device::nes_3dblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_3DBLOCK, "NES Cart RCM 3D Block PCB", tag, owner, clock, "nes_3dblock", __FILE__)
+{
+}
+
+
+
+
+void nes_gs2015_device::device_start()
+{
+ common_start();
+}
+
+void nes_gs2015_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_gs2004_device::device_start()
+{
+ common_start();
+}
+
+void nes_gs2004_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0xff);
+ chr8(0, m_chr_source);
+}
+
+void nes_gs2013_device::device_start()
+{
+ common_start();
+}
+
+void nes_gs2013_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0xff);
+ chr8(0, m_chr_source);
+}
+
+void nes_tf9_device::device_start()
+{
+ common_start();
+}
+
+void nes_tf9_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_3dblock_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+ save_item(NAME(m_irq_count));
+}
+
+void nes_3dblock_device::pcb_reset()
+{
+ prg32(0);
+ chr8(0, CHRRAM);
+ m_reg[0] = 0;
+ m_reg[1] = 0;
+ m_reg[2] = 0;
+ m_reg[3] = 0;
+ m_irq_count = 0;
+}
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ RCM GS2015 Board
+
+ Games: Bonza, Magic Jewelry 2
+
+ Very simple mapper: writes to 0x8000-0xffff sets prg32
+ to offset and chr8 to offset>>1 (when chrrom is present)
+
+ iNES: mapper 216
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_gs2015_device::write_h)
+{
+ LOG_MMC(("gs2015 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(offset);
+ chr8(offset >> 1, m_chr_source);
+}
+
+READ8_MEMBER(nes_gs2015_device::read_m)
+{
+ LOG_MMC(("gs2015 read_m, offset: %04x\n", offset));
+ return 0; // Videopoker Bonza needs this (sort of protection? or related to inputs?)
+}
+
+/*-------------------------------------------------
+
+ Board BMC-GS2004
+
+ Games: Tetris Family 6-in-1
+
+ In MESS: Preliminary Support. It also misses WRAM handling
+ (we need reads from 0x6000-0x7fff)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_gs2004_device::write_h)
+{
+ LOG_MMC(("gs2004 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(data);
+}
+
+/*-------------------------------------------------
+
+ Board BMC-GS2013
+
+ Games: Tetris Family 12-in-1
+
+ In MESS: Preliminary Support. It also misses WRAM handling
+ (we need reads from 0x6000-0x7fff)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_gs2013_device::write_h)
+{
+ LOG_MMC(("gs2013 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (data & 0x08)
+ prg32(data & 0x09);
+ else
+ prg32(data & 0x07);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by RCM for Tetris Family
+
+ Games: Tetris Family 9 in 1, 20 in 1
+
+ Simple Mapper: prg/chr/nt are swapped depending on the offset
+ of writes in 0x8000-0xffff. offset&0x80 set NT mirroring,
+ when (offset&0x30) is 0,3 prg32 is set; when it is 1,2
+ two 16k prg banks are set. See below for the values used in
+ these banks.
+
+ iNES: mapper 61
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_tf9_device::write_h)
+{
+ LOG_MMC(("tetrisfam write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x30)
+ {
+ case 0x00:
+ case 0x30:
+ prg32(offset & 0x0f);
+ break;
+ case 0x10:
+ case 0x20:
+ prg16_89ab(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4));
+ prg16_cdef(((offset & 0x0f) << 1) | ((offset & 0x20) >> 4));
+ break;
+ }
+ set_nt_mirroring(BIT(data, 7) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board by RCM for 3-D Block
+
+ Games: 3-D Block Hwang Shinwei version
+
+ iNES:
+
+ In MESS: Very Preliminary Support. What is the purpose
+ of the writes to $4800-$4900-$4a00? These writes
+ also happens on the RCM version, which however works
+ (probably an unused leftover code in that version)
+
+ FCEUmm suggests it might be IRQ related, but
+ it does not seem to help much...
+
+ -------------------------------------------------*/
+
+void nes_3dblock_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (m_irq_count)
+ {
+ m_irq_count--;
+ if (!m_irq_count)
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+WRITE8_MEMBER(nes_3dblock_device::write_l)
+{
+ LOG_MMC(("3dblock write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ switch (offset)
+ {
+ case 0x800: // $4800
+ m_reg[0] = data;
+ break;
+ case 0x900: // $4900
+ m_reg[1] = data;
+ break;
+ case 0xa00: // $4a00
+ m_reg[2] = data;
+ break;
+ case 0xe00: // $4e00
+ m_reg[3] = data; m_irq_count = 0x10;
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_rcm.h b/src/mess/machine/nes_rcm.h
new file mode 100644
index 00000000000..2f4d0e2c67a
--- /dev/null
+++ b/src/mess/machine/nes_rcm.h
@@ -0,0 +1,103 @@
+#ifndef __NES_RCM_H
+#define __NES_RCM_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_gs2015_device
+
+class nes_gs2015_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_gs2015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l) { return read_m(space, offset, mem_mask); }
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_gs2004_device
+
+class nes_gs2004_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_gs2004_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_gs2013_device
+
+class nes_gs2013_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_gs2013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_tf9_device
+
+class nes_tf9_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_tf9_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_3dblock_device
+
+class nes_3dblock_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_3dblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_reg[4];
+ UINT8 m_irq_count;
+};
+
+
+
+
+// device type definition
+extern const device_type NES_GS2015;
+extern const device_type NES_GS2004;
+extern const device_type NES_GS2013;
+extern const device_type NES_TF9IN1;
+extern const device_type NES_3DBLOCK;
+
+#endif
diff --git a/src/mess/machine/nes_rexsoft.c b/src/mess/machine/nes_rexsoft.c
new file mode 100644
index 00000000000..326e6349f3e
--- /dev/null
+++ b/src/mess/machine/nes_rexsoft.c
@@ -0,0 +1,263 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Rex Soft PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Rex Soft DragonBall Z V [mapper 12]
+ * Rex Soft SL-1632 [mapper 14]
+
+ TODO:
+ - fix 0x6000-0x7fff accesses, write_m/read_m
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_rexsoft.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_REX_DBZ5 = &device_creator<nes_rex_dbz5_device>;
+const device_type NES_REX_SL1632 = &device_creator<nes_rex_sl1632_device>;
+
+
+nes_rex_dbz5_device::nes_rex_dbz5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_REX_DBZ5, "NES Cart Rex Soft DragonBall Z V PCB", tag, owner, clock, "nes_rex_dbz5", __FILE__)
+{
+}
+
+nes_rex_sl1632_device::nes_rex_sl1632_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_REX_SL1632, "NES Cart Rex Soft SL-1632 PCB", tag, owner, clock, "nes_rex_sl1632", __FILE__)
+{
+}
+
+
+
+
+void nes_rex_dbz5_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_extra));
+}
+
+void nes_rex_dbz5_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0xff, 0xff, 0);
+
+ m_extra = 0;
+}
+
+void nes_rex_sl1632_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_mode));
+ save_item(NAME(m_mirror));
+ save_item(NAME(m_extra_bank));
+}
+
+void nes_rex_sl1632_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_mode = 0;
+ m_mirror = 0;
+ memset(m_extra_bank, 0, sizeof(m_extra_bank));
+ m_extra_bank[2] = 0xfe;
+ m_extra_bank[3] = 0xff;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bootleg Board by Rex Soft
+
+ Games: Dragon Ball Z 5, Dragon Ball Z Super
+
+ MMC3 clone. Writes to 0x4100-0x5fff (or from 0x4020?)
+ possibly select higher VROM pages (to allow up to
+ 512 banks instead of 256 only): bit0 selects the
+ higher pages for PPU banks 0-3 (0x0000-0x0fff), while
+ bit4 selects the higher pages for PPU banks 4-7 (0x1000-0x1fff)
+
+ iNES: mapper 12
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_rex_dbz5_device::write_l)
+{
+ LOG_MMC(("rex_dbz write_l, offset: %04x, data: %02x\n", offset, data));
+
+ m_extra = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+}
+
+/* we would need to use this read handler in 0x6000-0x7fff as well */
+READ8_MEMBER(nes_rex_dbz5_device::read_l)
+{
+ LOG_MMC(("rex_dbz read_l, offset: %04x\n", offset));
+ return 0x01;
+}
+
+void nes_rex_dbz5_device::chr_cb(int start, int bank, int source)
+{
+ int shift = (start < 4) ? 8 : 4;
+
+ bank |= ((m_extra << shift) & 0x100);
+ chr1_x(start, bank, source);
+}
+
+/*-------------------------------------------------
+
+ Rex Soft SL1632 Board
+
+ Games: Samurai Spirits
+
+ MMC3 clone
+
+ iNES: mapper 14
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+void nes_rex_sl1632_device::set_prg(int prg_base, int prg_mask)
+{
+ if (m_mode & 0x02)
+ {
+ // here standard MMC3 bankswitch
+ UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0;
+
+ prg_cb(0, prg_base | (m_mmc_prg_bank[0 ^ prg_flip] & prg_mask));
+ prg_cb(1, prg_base | (m_mmc_prg_bank[1] & prg_mask));
+ prg_cb(2, prg_base | (m_mmc_prg_bank[2 ^ prg_flip] & prg_mask));
+ prg_cb(3, prg_base | (m_mmc_prg_bank[3] & prg_mask));
+ }
+ else
+ {
+ prg8_89(m_extra_bank[0]);
+ prg8_ab(m_extra_bank[1]);
+ prg8_cd(m_extra_bank[2]);
+ prg8_ef(m_extra_bank[3]);
+ }
+}
+
+void nes_rex_sl1632_device::set_chr(UINT8 chr, int chr_base, int chr_mask)
+{
+ static const UINT8 conv_table[8] = {5, 5, 5, 5, 3, 3, 1, 1};
+ UINT8 chr_page = (m_latch & 0x80) >> 5;
+ UINT8 bank[8];
+ UINT8 chr_base2[8];
+
+ if (m_mode & 0x02)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ // since the mapper acts on 1K CHR chunks, we have 8 banks which use the 6 m_mmc_vrom_bank from MMC3 base class
+ if (i < 4)
+ bank[i] = ((m_mmc_vrom_bank[i / 2] & 0xfe) | (i & 1));
+ else
+ bank[i] = m_mmc_vrom_bank[i - 2];
+ chr_base2[i] = chr_base | ((m_mode << conv_table[i]) & 0x100);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ bank[i] = m_extra_bank[i + 4]; // first 4 m_extra_banks are PRG
+ chr_base2[i] = chr_base;
+ }
+ }
+
+ chr1_x(chr_page ^ 0, chr_base2[0] | (bank[0] & chr_mask), chr);
+ chr1_x(chr_page ^ 1, chr_base2[1] | (bank[1] & chr_mask), chr);
+ chr1_x(chr_page ^ 2, chr_base2[2] | (bank[2] & chr_mask), chr);
+ chr1_x(chr_page ^ 3, chr_base2[3] | (bank[3] & chr_mask), chr);
+ chr1_x(chr_page ^ 4, chr_base2[4] | (bank[4] & chr_mask), chr);
+ chr1_x(chr_page ^ 5, chr_base2[5] | (bank[5] & chr_mask), chr);
+ chr1_x(chr_page ^ 6, chr_base2[6] | (bank[6] & chr_mask), chr);
+ chr1_x(chr_page ^ 7, chr_base2[7] | (bank[7] & chr_mask), chr);
+}
+
+WRITE8_MEMBER(nes_rex_sl1632_device::write_h)
+{
+ UINT8 helper1, helper2;
+ LOG_MMC(("rex_sl1632 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset == 0x2131)
+ {
+ m_mode = data;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+
+ if (!(m_mode & 0x02))
+ set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ }
+
+ if (m_mode & 0x02)
+ {
+ switch (offset & 0x6001)
+ {
+ case 0x2000:
+ set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+ }
+ else if (offset >= 0x3000 && offset <= 0x6003)
+ {
+ helper1 = (offset & 0x01) << 2;
+ offset = ((offset & 0x02) | (offset >> 10)) >> 1;
+ helper2 = ((offset + 2) & 0x07) + 4; // '+4' because first 4 m_extra_banks are for PRG!
+ m_extra_bank[helper2] = (m_extra_bank[helper2] & (0xf0 >> helper1)) | ((data & 0x0f) << helper1);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+ else
+ {
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ case 0x2000:
+ m_extra_bank[offset >> 13] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+
+ case 0x1000:
+ m_mirror = data;
+ set_nt_mirroring(BIT(m_mirror, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ }
+ }
+}
diff --git a/src/mess/machine/nes_rexsoft.h b/src/mess/machine/nes_rexsoft.h
new file mode 100644
index 00000000000..10eddc20bd2
--- /dev/null
+++ b/src/mess/machine/nes_rexsoft.h
@@ -0,0 +1,59 @@
+#ifndef __NES_REXSOFT_H
+#define __NES_REXSOFT_H
+
+#include "machine/nes_mmc3.h"
+
+
+// ======================> nes_rex_dbz5_device
+
+class nes_rex_dbz5_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_rex_dbz5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_m) { return read_l(space, offset, mem_mask); }
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual void chr_cb( int start, int bank, int source );
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_extra;
+};
+
+
+// ======================> nes_rex_sl1632_device
+
+class nes_rex_sl1632_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_rex_sl1632_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+protected:
+ virtual void set_prg(int prg_base, int prg_mask);
+ virtual void set_chr(UINT8 chr, int chr_base, int chr_mask);
+
+ UINT8 m_mode, m_mirror;
+ UINT8 m_extra_bank[12];
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_REX_DBZ5;
+extern const device_type NES_REX_SL1632;
+
+#endif
diff --git a/src/mess/machine/nes_sachen.c b/src/mess/machine/nes_sachen.c
new file mode 100644
index 00000000000..ac95f2e282b
--- /dev/null
+++ b/src/mess/machine/nes_sachen.c
@@ -0,0 +1,692 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Sachen PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Sachen SA-009 [mapper 160]
+ * Sachen SA-0036 [mapper 148]
+ * Sachen SA-0037 [mapper 149]
+ * Sachen SA-72007 [mapper 145]
+ * Sachen SA-72008 [mapper 133]
+ * Sachen TCA-01 [mapper 143]
+ * Sachen TCU-01 [mapper 147]
+ * Sachen TCU-02 [mapper 136]
+ * Sachen Discrete PCBs [mapper 150 & 243]
+ * Sachen 8259 [mapper 141 (A), 138 (B), 139 (C), 137 (D)]
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_sachen.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_SACHEN_SA009 = &device_creator<nes_sachen_sa009_device>;
+const device_type NES_SACHEN_SA0036 = &device_creator<nes_sachen_sa0036_device>;
+const device_type NES_SACHEN_SA0037 = &device_creator<nes_sachen_sa0037_device>;
+const device_type NES_SACHEN_SA72007 = &device_creator<nes_sachen_sa72007_device>;
+const device_type NES_SACHEN_SA72008 = &device_creator<nes_sachen_sa72008_device>;
+const device_type NES_SACHEN_TCA01 = &device_creator<nes_sachen_tca01_device>;
+const device_type NES_SACHEN_TCU01 = &device_creator<nes_sachen_tcu01_device>;
+const device_type NES_SACHEN_TCU02 = &device_creator<nes_sachen_tcu02_device>;
+const device_type NES_SACHEN_74X374 = &device_creator<nes_sachen_74x374_device>;
+const device_type NES_SACHEN_74X374_ALT = &device_creator<nes_sachen_74x374_alt_device>;
+const device_type NES_SACHEN_8259A = &device_creator<nes_sachen_8259a_device>;
+const device_type NES_SACHEN_8259B = &device_creator<nes_sachen_8259b_device>;
+const device_type NES_SACHEN_8259C = &device_creator<nes_sachen_8259c_device>;
+const device_type NES_SACHEN_8259D = &device_creator<nes_sachen_8259d_device>;
+
+
+nes_sachen_sa009_device::nes_sachen_sa009_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_SA009, "NES Cart Sachen SA009 PCB", tag, owner, clock, "nes_sa009", __FILE__)
+{
+}
+
+nes_sachen_sa0036_device::nes_sachen_sa0036_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_SA0036, "NES Cart Sachen sa0036 PCB", tag, owner, clock, "nes_sa0036", __FILE__)
+{
+}
+
+nes_sachen_sa0037_device::nes_sachen_sa0037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_SA0037, "NES Cart Sachen sa0037 PCB", tag, owner, clock, "nes_sa0037", __FILE__)
+{
+}
+
+nes_sachen_sa72007_device::nes_sachen_sa72007_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_SA72007, "NES Cart Sachen SA72007 PCB", tag, owner, clock, "nes_sa72007", __FILE__)
+{
+}
+
+nes_sachen_sa72008_device::nes_sachen_sa72008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_SA72008, "NES Cart Sachen SA72008 PCB", tag, owner, clock, "nes_sa72008", __FILE__)
+{
+}
+
+nes_sachen_tca01_device::nes_sachen_tca01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_TCA01, "NES Cart Sachen TCA-01 PCB", tag, owner, clock, "nes_tca01", __FILE__)
+{
+}
+
+nes_sachen_tcu01_device::nes_sachen_tcu01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_TCU01, "NES Cart Sachen TCU-01 PCB", tag, owner, clock, "nes_tcu01", __FILE__)
+{
+}
+
+nes_sachen_tcu02_device::nes_sachen_tcu02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_TCU02, "NES Cart Sachen TCU-02 PCB", tag, owner, clock, "nes_tcu02", __FILE__)
+{
+}
+
+nes_sachen_74x374_device::nes_sachen_74x374_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_sachen_74x374_device::nes_sachen_74x374_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SACHEN_74X374, "NES Cart Sachen 74*374 PCB", tag, owner, clock, "nes_s74x34", __FILE__)
+{
+}
+
+nes_sachen_74x374_alt_device::nes_sachen_74x374_alt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sachen_74x374_device(mconfig, NES_SACHEN_74X374_ALT, "NES Cart Sachen 74*374 Alt PCB", tag, owner, clock, "nes_s74x34a", __FILE__)
+{
+}
+
+nes_sachen_8259a_device::nes_sachen_8259a_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)
+ : nes_sachen_74x374_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_sachen_8259a_device::nes_sachen_8259a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sachen_74x374_device(mconfig, NES_SACHEN_8259A, "NES Cart Sachen 8259A PCB", tag, owner, clock, "nes_s8259a", __FILE__)
+{
+}
+
+nes_sachen_8259b_device::nes_sachen_8259b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259B, "NES Cart Sachen 8259B PCB", tag, owner, clock, "nes_s8259b", __FILE__)
+{
+}
+
+nes_sachen_8259c_device::nes_sachen_8259c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259C, "NES Cart Sachen 8259C PCB", tag, owner, clock, "nes_s8259c", __FILE__)
+{
+}
+
+nes_sachen_8259d_device::nes_sachen_8259d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sachen_8259a_device(mconfig, NES_SACHEN_8259D, "NES Cart Sachen 8259D PCB", tag, owner, clock, "nes_s8259d", __FILE__)
+{
+}
+
+
+
+
+void nes_sachen_sa009_device::device_start()
+{
+ common_start();
+}
+
+void nes_sachen_sa009_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_sachen_sa0036_device::device_start()
+{
+ common_start();
+}
+
+void nes_sachen_sa0036_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_sachen_sa0037_device::device_start()
+{
+ common_start();
+}
+
+void nes_sachen_sa0037_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_sachen_sa72007_device::device_start()
+{
+ common_start();
+}
+
+void nes_sachen_sa72007_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_sachen_sa72008_device::device_start()
+{
+ common_start();
+}
+
+void nes_sachen_sa72008_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_sachen_tca01_device::device_start()
+{
+ common_start();
+}
+
+void nes_sachen_tca01_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(1);
+ chr8(0, m_chr_source);
+}
+
+void nes_sachen_tcu01_device::device_start()
+{
+ common_start();
+}
+
+void nes_sachen_tcu01_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_sachen_tcu02_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_sachen_tcu02_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_sachen_74x374_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_sachen_74x374_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ m_mmc_vrom_bank = 0;
+}
+
+void nes_sachen_8259a_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_reg));
+}
+
+void nes_sachen_8259a_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+
+ m_latch = 0;
+ memset(m_reg, 0, sizeof(m_reg));
+}
+
+void nes_sachen_8259d_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(m_vrom_chunks - 1, CHRROM);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+
+ m_latch = 0;
+ memset(m_reg, 0, sizeof(m_reg));
+}
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Sachen SA009 bootleg boards
+
+ Games: Pipe 5
+
+ iNES: mapper 160
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sachen_sa009_device::write_l)
+{
+ LOG_MMC(("SA009 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(data, m_chr_source);
+}
+
+/*-------------------------------------------------
+
+ Sachen SA0036 bootleg boards
+
+ Games: Taiwan Mahjong 16
+
+ iNES: mapper 149
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sachen_sa0036_device::write_h)
+{
+ LOG_MMC(("sa0036 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ chr8(data >> 7, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Sachen SA0037 bootleg boards
+
+ Games: Mahjong World, Shisen Mahjong
+
+ iNES: mapper 148
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sachen_sa0037_device::write_h)
+{
+ LOG_MMC(("sa0037 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ prg32(data >> 3);
+ chr8(data, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Sachen SA72007 bootleg boards
+
+ Games: Sidewinder
+
+ iNES: mapper 145
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sachen_sa72007_device::write_l)
+{
+ LOG_MMC(("SA72007 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ /* only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ chr8(data >> 7, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Sachen SA72008 bootleg boards
+
+ Games: Jovial Race, Qi Wang
+
+ iNES: mapper 133
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sachen_sa72008_device::write_l)
+{
+ LOG_MMC(("SA72008 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(data >> 2);
+ chr8(data, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Sachen TCA-01 bootleg boards
+
+ iNES: mapper 143
+
+ Games: Dancing Blocks, Magic Mathematic
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(nes_sachen_tca01_device::read_l)
+{
+ LOG_MMC(("TCA-01 read_l, offset: %04x\n", offset));
+
+ /* the address is read only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ return (~offset & 0x3f) | 0x40;
+ else
+ return 0x00;
+}
+
+/*-------------------------------------------------
+
+ Sachen TCU-01 bootleg boards
+
+ Games: Challenge of the Dragon, Chinese Kungfu
+
+ iNES: mapper 147
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sachen_tcu01_device::write_l)
+{
+ LOG_MMC(("TCU-01 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ if ((offset & 0x103) == 0x002)
+ {
+ prg32(((data >> 6) & 0x02) | ((data >> 2) & 0x01));
+ chr8(data >> 3, CHRROM);
+ }
+}
+
+/*-------------------------------------------------
+
+ Sachen TCU-02 bootleg boards
+
+ Games: Wei Lai Xiao Zi
+
+ iNES: mapper 136
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sachen_tcu02_device::write_l)
+{
+ LOG_MMC(("TCU-02 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ if ((offset & 0x103) == 0x002)
+ {
+ m_latch = (data & 0x30) | ((data + 3) & 0x0f);
+ chr8(m_latch, CHRROM);
+ }
+}
+
+READ8_MEMBER(nes_sachen_tcu02_device::read_l)
+{
+ LOG_MMC(("TCU-02 read_l, offset: %04x\n", offset));
+
+ if ((offset & 0x103) == 0x000)
+ return m_latch | 0x40;
+ else
+ return 0x00;
+}
+
+/*-------------------------------------------------
+
+ Sachen 74x374 bootleg boards
+
+ Games: Chess Academy, Chinese Checkers Jpn, Mahjong Academy,
+ Olympic IQ, Poker II, Tasac [150], Poker III [243]
+
+ iNES: mappers 150 & 243
+
+ -------------------------------------------------*/
+
+void nes_sachen_74x374_device::set_mirror(UINT8 nt) // also used by mappers 137, 138, 139, 141
+{
+ switch (nt)
+ {
+ case 0:
+ case 1:
+ set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 2:
+ set_nt_page(0, CIRAM, 0, 1);
+ set_nt_page(1, CIRAM, 1, 1);
+ set_nt_page(2, CIRAM, 1, 1);
+ set_nt_page(3, CIRAM, 1, 1);
+ break;
+ case 3:
+ set_nt_mirroring(PPU_MIRROR_LOW);
+ break;
+ default:
+ LOG_MMC(("Mapper set NT to invalid value %02x", nt));
+ break;
+ }
+}
+
+
+WRITE8_MEMBER(nes_sachen_74x374_device::write_l)
+{
+ LOG_MMC(("Sachen 74*374 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ {
+ if (!(offset & 0x01))
+ m_latch = data & 0x07;
+ else
+ {
+ switch (m_latch)
+ {
+ case 0x02:
+ m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x08) | ((data << 3) & 0x08);
+ chr8(m_mmc_vrom_bank, CHRROM);
+ prg32(data & 0x01);
+ break;
+ case 0x04:
+ m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x04) | ((data << 2) & 0x04);
+ chr8(m_mmc_vrom_bank, CHRROM);
+ break;
+ case 0x05:
+ prg32(data & 0x07);
+ break;
+ case 0x06:
+ m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x03) | ((data << 0) & 0x03);
+ chr8(m_mmc_vrom_bank, CHRROM);
+ break;
+ case 0x07:
+ set_mirror((data >> 1) & 0x03);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+READ8_MEMBER(nes_sachen_74x374_device::read_l)
+{
+ LOG_MMC(("Sachen 74*374 read_l, offset: %04x", offset));
+
+ /* read happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ return (~m_latch & 0x3f) /* ^ dips*/; // we would need to check the Dips here
+ else
+ return 0;
+}
+
+WRITE8_MEMBER(nes_sachen_74x374_alt_device::write_l)
+{
+ LOG_MMC(("Sachen 74*374 Alt write_l, offset: %04x, data: %02x\n", offset, data));
+
+ /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ {
+ if (!(offset & 0x01))
+ m_latch = data;
+ else
+ {
+ switch (m_latch & 0x07)
+ {
+ case 0x00:
+ prg32(0);
+ chr8(3, CHRROM);
+ break;
+ case 0x02:
+ m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x08) | ((data << 3) & 0x08);
+ chr8(m_mmc_vrom_bank, CHRROM);
+ break;
+ case 0x04:
+ m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x01) | ((data << 0) & 0x01);
+ chr8(m_mmc_vrom_bank, CHRROM);
+ break;
+ case 0x05:
+ prg32(data & 0x01);
+ break;
+ case 0x06:
+ m_mmc_vrom_bank = (m_mmc_vrom_bank & ~0x06) | ((data << 1) & 0x06);
+ chr8(m_mmc_vrom_bank, CHRROM);
+ break;
+ case 0x07:
+ set_mirror(BIT(data, 0));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ Sachen S8259 bootleg boards
+
+ iNES: mapper 141 (A), 138 (B), 139 (C), 137 (D)
+
+ -------------------------------------------------*/
+
+void nes_sachen_8259a_device::chr_update()
+{
+ UINT8 bank_helper1 = m_reg[7] & 0x01;
+ UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3;
+
+ if (m_chr_source == CHRROM)
+ {
+ chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << 1 | 0, CHRROM);
+ chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << 1 | 1, CHRROM);
+ chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << 1 | 0, CHRROM);
+ chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << 1 | 1, CHRROM);
+ }
+}
+
+WRITE8_MEMBER(nes_sachen_8259a_device::write_l)
+{
+ LOG_MMC(("Sachen 8259 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ /* write happens only if we are at 0x4100 + k * 0x200, but 0x4100 is offset = 0 */
+ if (!(offset & 0x100))
+ {
+ if (!(offset & 0x01))
+ m_latch = data & 0x07;
+ else
+ {
+ m_reg[m_latch] = data;
+
+ switch (m_latch)
+ {
+ case 0x05:
+ prg32(data);
+ break;
+ case 0x07:
+ set_mirror(BIT(data, 0) ? 0 : (data >> 1) & 0x03);
+ break;
+ default:
+ chr_update();
+ break;
+ }
+ }
+ }
+}
+
+void nes_sachen_8259b_device::chr_update()
+{
+ UINT8 bank_helper1 = m_reg[7] & 0x01;
+ UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3;
+
+ if (m_chr_source == CHRROM)
+ {
+ chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2), CHRROM);
+ chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2), CHRROM);
+ chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2), CHRROM);
+ chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2), CHRROM);
+ }
+}
+
+void nes_sachen_8259c_device::chr_update()
+{
+ UINT8 bank_helper1 = m_reg[7] & 0x01;
+ UINT8 bank_helper2 = (m_reg[4] & 0x07) << 3;
+
+ if (m_chr_source == CHRROM)
+ {
+ chr2_0(((m_reg[bank_helper1 ? 0 : 0] & 0x07) | bank_helper2) << 2 | 0, CHRROM);
+ chr2_2(((m_reg[bank_helper1 ? 0 : 1] & 0x07) | bank_helper2) << 2 | 1, CHRROM);
+ chr2_4(((m_reg[bank_helper1 ? 0 : 2] & 0x07) | bank_helper2) << 2 | 2, CHRROM);
+ chr2_6(((m_reg[bank_helper1 ? 0 : 3] & 0x07) | bank_helper2) << 2 | 3, CHRROM);
+ }
+}
+
+void nes_sachen_8259d_device::chr_update()
+{
+ if (m_chr_source == CHRROM)
+ {
+ chr1_0((m_reg[0] & 0x07), CHRROM);
+ chr1_1((m_reg[1] & 0x07) | (m_reg[4] << 4 & 0x10), CHRROM);
+ chr1_2((m_reg[2] & 0x07) | (m_reg[4] << 3 & 0x10), CHRROM);
+ chr1_3((m_reg[3] & 0x07) | (m_reg[4] << 2 & 0x10) | (m_reg[6] << 3 & 0x08), CHRROM);
+ }
+}
diff --git a/src/mess/machine/nes_sachen.h b/src/mess/machine/nes_sachen.h
new file mode 100644
index 00000000000..49a88131c52
--- /dev/null
+++ b/src/mess/machine/nes_sachen.h
@@ -0,0 +1,259 @@
+#ifndef __NES_SACHEN_H
+#define __NES_SACHEN_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_sachen_sa009_device
+
+class nes_sachen_sa009_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_sa009_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sachen_sa0036_device
+
+class nes_sachen_sa0036_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_sa0036_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sachen_sa0037_device
+
+class nes_sachen_sa0037_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_sa0037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sachen_sa72007_device
+
+class nes_sachen_sa72007_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_sa72007_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sachen_sa72008_device
+
+class nes_sachen_sa72008_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_sa72008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sachen_tca01_device
+
+class nes_sachen_tca01_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_tca01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sachen_tcu01_device
+
+class nes_sachen_tcu01_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_tcu01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m) { write_l(space, (offset + 0x100) & 0xfff, data, mem_mask); }
+ virtual DECLARE_WRITE8_MEMBER(write_h) { write_l(space, (offset + 0x100) & 0xfff, data, mem_mask); }
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sachen_tcu02_device
+
+class nes_sachen_tcu02_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_tcu02_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_sachen_74x374_device
+
+class nes_sachen_74x374_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sachen_74x374_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);
+ nes_sachen_74x374_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+
+protected:
+ void set_mirror(UINT8 nt);
+ UINT8 m_latch, m_mmc_vrom_bank;
+};
+
+
+// ======================> nes_sachen_74x374_alt_device
+
+class nes_sachen_74x374_alt_device : public nes_sachen_74x374_device
+{
+public:
+ // construction/destruction
+ nes_sachen_74x374_alt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_READ8_MEMBER(read_l) { return 0xff; } // no read_l here
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+};
+
+
+// ======================> nes_sachen_8259a_device
+
+class nes_sachen_8259a_device : public nes_sachen_74x374_device
+{
+public:
+ // construction/destruction
+ nes_sachen_8259a_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);
+ nes_sachen_8259a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m) { write_l(space, (offset + 0x100) & 0xfff, data, mem_mask); }
+
+ virtual void pcb_reset();
+
+protected:
+ virtual void chr_update();
+ UINT8 m_reg[8];
+};
+
+
+// ======================> nes_sachen_8259b_device
+
+class nes_sachen_8259b_device : public nes_sachen_8259a_device
+{
+public:
+ // construction/destruction
+ nes_sachen_8259b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual void chr_update();
+};
+
+
+// ======================> nes_sachen_8259c_device
+
+class nes_sachen_8259c_device : public nes_sachen_8259a_device
+{
+public:
+ // construction/destruction
+ nes_sachen_8259c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+protected:
+ virtual void chr_update();
+};
+
+
+// ======================> nes_sachen_8259d_device
+
+class nes_sachen_8259d_device : public nes_sachen_8259a_device
+{
+public:
+ // construction/destruction
+ nes_sachen_8259d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void pcb_reset();
+
+protected:
+ virtual void chr_update();
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_SACHEN_SA009;
+extern const device_type NES_SACHEN_SA0036;
+extern const device_type NES_SACHEN_SA0037;
+extern const device_type NES_SACHEN_SA72007;
+extern const device_type NES_SACHEN_SA72008;
+extern const device_type NES_SACHEN_TCA01;
+extern const device_type NES_SACHEN_TCU01;
+extern const device_type NES_SACHEN_TCU02;
+extern const device_type NES_SACHEN_74X374;
+extern const device_type NES_SACHEN_74X374_ALT;
+extern const device_type NES_SACHEN_8259A;
+extern const device_type NES_SACHEN_8259B;
+extern const device_type NES_SACHEN_8259C;
+extern const device_type NES_SACHEN_8259D;
+
+#endif
diff --git a/src/mess/machine/nes_slot.c b/src/mess/machine/nes_slot.c
index 7f0260949d0..5b33a63934d 100644
--- a/src/mess/machine/nes_slot.c
+++ b/src/mess/machine/nes_slot.c
@@ -1,9 +1,133 @@
+/***********************************************************************************************************
+
+
+ Nintendo NES/FC cart emulation
+ (through slot devices)
+
+ TODO: add notes about driver connections + about open bus (and our sketchy implementation) + about bus conflict...
+
+ ***********************************************************************************************************/
+
+/*****************************************************************************************
+
+ Notes to be merged / split...
+
+ Many information about the mappers below come from the wonderful doc written by Disch.
+ Current info (when used) are based on v0.6.1 of his docs.
+ You can find the latest version of the doc at http://www.romhacking.net/docs/362/
+
+
+ Missing components:
+ * Currently, we are not emulating 4-screen mirroring (only 3 games use it)
+ * We need a better way to implement CPU cycle based IRQ. Currently we update their counter once every scanline
+ but, with this approach, every time 114 clocks have passed and for certain games it is too much!
+ * We need to emulate additional sound hardware in mappers 019, 024, 026, 069, 085 (and possibly other ones)
+ * We need to emulate EEPROM in mapper 016 and 159
+ * Barcode World (mapper 069) and Datach games (mapper 157) need Barcode Reader emulation
+ Notice that for mapper 157, the barcode reader enters in the irq, so glitches may be related to this!
+ * Karaoke Studio (mapper 188) misses input devices
+
+ Known issues on specific mappers:
+
+ * 000 F1 Race requires more precise PPU timing. It currently has plenty of 1-line glitches.
+ * 001 Yoshi flashes in-game. Back to the Future have heavily corrupted graphics (since forever).
+ * 001 SOROM boards do not properly handle the two WRAM/Battery banks
+ * 002, 003, 094, 097, 152 Bus conflict?
+ * 003 Firehouse Rescue has flashing graphics
+ * 004 Mendel Palace has never worked properly
+ * 004 Ninja Gaiden 2 has flashing bg graphics in the second level
+ * 005 has issues (see e.g. Just Breed or Metal Slader Glory), RAM banking needs hardware flags to determine size
+ * 007 Marble Madness has small graphics corruptions
+ * 014 in-game graphics is glitched
+ * 015 Shanghai Tycoon has corrupted graphics
+ * 033 has still some graphics problem (e.g. missing text in Akira)
+ * 034 Impossible Mission II does not show graphics
+ * 038 seems to miss inputs. separate reads?
+ * 042 Ai Senshi Nicol has broken graphics (our Mapper 42 implementation does not handle CHR banks)
+ * 048 Don Doko Don 2 freezes when you reach the first boss
+ * 051 only half of the games work
+ * 064 has many IRQ problems (due to the way we implement CPU based IRQ) - see Skull & Crossbones.
+ Klax has problems as well (even if it uses scanline based IRQ, according to Disch's docs).
+ * 067 some 1-line glitches that cannot be solved without a better implementation for cycle-based IRQs
+ * 071 Fire Hawk is flashing all the times.
+ * 072, 086, 092 lack samples support (maybe others as well)
+ * 073 16 bit IRQ mode is not implemented
+ * 077 Requires 4-screen mirroring. Currently, it is very glitchy
+ * 083 has serious glitches
+ * 088 Quinty has never worked properly
+ * 096 is preliminary (no correct chr switch in connection to PPU)
+ * 104 Not all the games work
+ * 107 Are the scrolling glitches (check status bar) correct? NEStopia behaves similarly
+ * 112 Master Shooter is not working and misses some graphics
+ * 117 In-game glitches
+ * 119 Pin Bot has glitches when the ball is in the upper half of the screen
+ * 133 Qi Wang starts with corrupted graphics (ingame seems better)
+ * 143 are Dancing Block borders (in the intro) correct?
+ * 158 In addition to IRQ problems (same as 64), mirroring was just a guess (wrong?). info needed!
+ * 164 preliminary - no sprites?
+ * 176 has some graphics problem
+ * 178 Fan Kong Jin Ying is not working (but not even in NEStopia)
+ * 180 Crazy Climber controller?
+ * 187, 198, 208, 215 have some PRG banking issues - preliminary!
+ * 188 needs mic input (reads from 0x6000-0x7fff)
+ * 197 Super Fighter 3 has some glitch in-game (maybe mirroring?)
+ * 222 is only preliminar (wrong IRQ, mirroring or CHR banking?)
+ * 225 115-in-1 has glitches in the menu (games seem fine)
+ * 229 is preliminary
+ * 230 not working yet (needs a value to flip at reset)
+ * 232 has graphics glitches
+ * 241 Commandos is not working (but not even in NEStopia)
+ * 242 In Dragon Quest VIII graphics of the main character is not drawn (it seems similar to Shanghai Tycoon [map15]
+ because in place of the missing graphics we get glitches in the left border)
+ * 249 only half of the games work (and Du Bao Ying Hao seems to suffer the same problem as DQ8 and Shanghai Tycoon)
+ * 255 does not really select game (same in NEStopia apparently)
+
+ A few Mappers suffer of hardware conflict: original dumpers have used the same mapper number for more than
+ a kind of boards. In these cases (and only in these cases) we exploit nes.hsi to set up accordingly
+ emulation. Games which requires this hack are the following:
+ * 032 - Major League needs hardwired mirroring (missing windows and glitched field in top view, otherwise)
+ * 034 - Impossible Mission II is not like BxROM games (it writes to 0x7ffd-0x7fff, instead of 0x8000). It is still
+ unplayable though (see above)
+ * 071 - Fire Hawk is different from other Camerica games (no hardwired mirroring). Without crc_hack no helicopter graphics
+ * 078 - Cosmo Carrier needs a different mirroring than Holy Diver
+ * 113 - HES 6-in-1 requires mirroring (check Bookyman playfield), while other games break with this (check AV Soccer)
+ * 153 - Famicom Jump II uses a different board (or the same in a very different way)
+ * 242 - DQ8 has no mirroring (missing graphics is due to other reasons though)
+
+ crc_hacks have been added also to handle a few wiring settings which would require submappers:
+ * CHR protection pins for mapper 185
+ * VRC-2, VRC-4 and VRC-6 line wiring
+
+ Details to investigate:
+ * 034 writes to 0x8000-0xffff should not be used for NINA-001 and BNROM, only unlicensed BxROM...
+ * 144 we ignore writes to 0x8000 while NEStopia does not. is it a problem?
+ * 240 we do not map writes to 0x4020-0x40ff. is this a problem?
+ * some other emus uses mapper 210 for mapper 019 games without additional sound hardware and mirroring capabilities
+ (in 210 mirroring is hardwired). However, simply initializing mirroring to Vertical in 019 seems to fix all glitches
+ in 210 games, so there seems to be no reason to have this duplicate mapper
+
+ Some mappers copy PRG rom in SRAM region. Below is a list of those which does it (in MESS) to further
+ investigate if we are supporting them in the right way (e.g. do any of the following have conflicts with SRAM?):
+ * 065 (Gimmick! breaks badly without it)
+ * 040, 042, 050
+
+ Remember that the MMC # does not equal the mapper #. In particular, Mapper 4 is
+ in fact MMC3, Mapper 9 is MMC2 and Mapper 10 is MMC4. Makes perfect sense, right?
+
+ TODO:
+ - add more info
+ - add missing mappers
+
+ ****************************************************************************************/
+
+
#include "emu.h"
#include "hashfile.h"
#include "machine/nes_slot.h"
#define NES_BATTERY_SIZE 0x2000
+
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
@@ -26,15 +150,33 @@ device_nes_cart_interface::device_nes_cart_interface(const machine_config &mconf
m_vrom(NULL),
m_vram(NULL),
m_battery(NULL),
- m_mapper_ram(NULL),
- m_mapper_bram(NULL),
+ m_ciram(NULL),
m_prg_size(0),
m_prgram_size(0),
m_vrom_size(0),
m_vram_size(0),
m_battery_size(0),
- m_mapper_ram_size(0),
- m_mapper_bram_size(0)
+ m_mapper_sram(NULL),
+ m_ext_ntram(NULL),
+ m_mapper_sram_size(0),
+ m_ext_ntram_size(0),
+ m_ce_mask(0),
+ m_ce_state(0),
+ m_vrc_ls_prg_a(0),
+ m_vrc_ls_prg_b(0),
+ m_vrc_ls_chr(0),
+ m_mirroring(PPU_MIRROR_NONE),
+ m_pcb_ctrl_mirror(FALSE),
+ m_four_screen_vram(FALSE),
+ m_has_trainer(FALSE),
+ m_x1_005_alt_mirroring(FALSE),
+ m_bus_conflict(TRUE),
+ m_prg_chunks(0),
+ m_prg_mask(0xffff),
+ m_chr_source(CHRRAM),
+ m_vrom_chunks(0),
+ m_vram_chunks(0),
+ m_prg_bank_map(NULL)
{
}
@@ -55,8 +197,57 @@ void device_nes_cart_interface::prg_alloc(running_machine &machine, size_t size)
{
if (m_prg == NULL)
{
- m_prg = auto_alloc_array(machine, UINT8, size);
+ m_prg = auto_alloc_array_clear(machine, UINT8, size);
m_prg_size = size;
+ m_prg_chunks = size / 0x4000;
+ m_prg_mask = ((m_prg_chunks << 1) - 1);
+
+// printf("first mask %x!\n", m_prg_mask);
+ if ((m_prg_chunks << 1) & m_prg_mask)
+ {
+ int mask_bits = 0, temp = (m_prg_chunks << 1), mapsize;
+ // contrary to what happens with later systems, like e.g. SNES or MD,
+ // only half a dozen of NES carts have PRG which is not a power of 2
+ // so we use this bank_map only as an exception
+ printf("uneven rom!\n");
+
+ // 1. redefine mask as (next power of 2)-1
+ for (; temp; )
+ {
+ mask_bits++;
+ temp >>= 1;
+ }
+ m_prg_mask = (1 << mask_bits) - 1;
+// printf("new mask %x!\n", m_prg_mask);
+ mapsize = (1 << mask_bits)/2;
+
+ // 2. create a bank_map for banks in the range mask/2 -> mask
+ m_prg_bank_map = auto_alloc_array_clear(machine, UINT16, mapsize);
+
+ // 3. fill the bank_map accounting for mirrors
+ int j;
+ for (j = mapsize; j < (m_prg_chunks << 1); j++)
+ m_prg_bank_map[j - mapsize] = j;
+
+ while (j % mapsize)
+ {
+ int k = 0, repeat_banks;
+ while ((j % (mapsize >> k)) && k < mask_bits)
+ k++;
+ repeat_banks = j % (mapsize >> (k - 1));
+ for (int l = 0; l < repeat_banks; l++)
+ m_prg_bank_map[(j - mapsize) + l] = m_prg_bank_map[(j - mapsize) + l - repeat_banks];
+ j += repeat_banks;
+ }
+
+ // check bank map!
+// for (int i = 0; i < mapsize; i++)
+// {
+// printf("bank %3d = %3d\t", i, m_prg_bank_map[i]);
+// if ((i%8) == 7)
+// printf("\n");
+// }
+ }
}
}
@@ -64,7 +255,7 @@ void device_nes_cart_interface::prgram_alloc(running_machine &machine, size_t si
{
if (m_prgram == NULL)
{
- m_prgram = auto_alloc_array(machine, UINT8, size);
+ m_prgram = auto_alloc_array_clear(machine, UINT8, size);
m_prgram_size = size;
}
}
@@ -73,8 +264,9 @@ void device_nes_cart_interface::vrom_alloc(running_machine &machine, size_t size
{
if (m_vrom == NULL)
{
- m_vrom = auto_alloc_array(machine, UINT8, size);
+ m_vrom = auto_alloc_array_clear(machine, UINT8, size);
m_vrom_size = size;
+ m_vrom_chunks = size / 0x2000;
}
}
@@ -82,8 +274,9 @@ void device_nes_cart_interface::vram_alloc(running_machine &machine, size_t size
{
if (m_vram == NULL)
{
- m_vram = auto_alloc_array(machine, UINT8, size);
+ m_vram = auto_alloc_array_clear(machine, UINT8, size);
m_vram_size = size;
+ m_vram_chunks = size / 0x2000;
}
}
@@ -91,27 +284,532 @@ void device_nes_cart_interface::battery_alloc(running_machine &machine, size_t s
{
if (m_battery == NULL)
{
- m_battery = auto_alloc_array(machine, UINT8, size);
+ m_battery = auto_alloc_array_clear(machine, UINT8, size);
m_battery_size = size;
}
}
-void device_nes_cart_interface::mapper_ram_alloc(running_machine &machine, size_t size)
+
+//-------------------------------------------------
+// PRG helpers
+//-------------------------------------------------
+
+inline int device_nes_cart_interface::prg_8k_bank_num(int bank_8k)
+{
+ if (m_prg_mask == ((m_prg_chunks << 1) - 1))
+ return bank_8k & m_prg_mask;
+
+ // only a few pirate games (less than a dozen) have PRG which is not power of 2
+ // so we treat it here separately, rather than forcing all games to use m_prg_bank_map
+
+ // case 1: if we are accessing a bank before the end of the image, just return that bank
+ if (bank_8k < ((m_prg_chunks << 1) - 1))
+ return bank_8k;
+
+ // case 2: otherwise return a mirror using the bank_map!
+// UINT8 temp = bank_8k;
+ bank_8k &= m_prg_mask;
+ bank_8k -= (m_prg_mask/2 + 1);
+// printf("bank: accessed %x (top: %x), returned %x\n", temp, (m_prg_chunks << 1) - 1, m_prg_bank_map[bank_8k]);
+ return m_prg_bank_map[bank_8k];
+}
+
+inline void device_nes_cart_interface::update_prg_banks(int prg_bank_start, int prg_bank_end)
+{
+ for (int prg_bank = prg_bank_start; prg_bank <= prg_bank_end; prg_bank++)
+ {
+ assert(prg_bank >= 0);
+ assert(prg_bank < ARRAY_LENGTH(m_prg_bank));
+ assert(prg_bank < ARRAY_LENGTH(m_prg_bank_mem));
+
+ m_prg_bank_mem[prg_bank]->set_entry(m_prg_bank[prg_bank]);
+ }
+}
+
+void device_nes_cart_interface::prg32(int bank)
+{
+ /* if there is only 16k PRG, return */
+ if (!(m_prg_chunks >> 1))
+ return;
+
+ /* assumes that bank references a 32k chunk */
+ bank = prg_8k_bank_num(bank * 4);
+
+ m_prg_bank[0] = bank + 0;
+ m_prg_bank[1] = bank + 1;
+ m_prg_bank[2] = bank + 2;
+ m_prg_bank[3] = bank + 3;
+ update_prg_banks(0, 3);
+}
+
+void device_nes_cart_interface::prg16_89ab(int bank)
+{
+ /* assumes that bank references a 16k chunk */
+ bank = prg_8k_bank_num(bank * 2);
+
+ m_prg_bank[0] = bank + 0;
+ m_prg_bank[1] = bank + 1;
+ update_prg_banks(0, 1);
+}
+
+void device_nes_cart_interface::prg16_cdef(int bank)
+{
+ /* assumes that bank references a 16k chunk */
+ bank = prg_8k_bank_num(bank * 2);
+
+ m_prg_bank[2] = bank + 0;
+ m_prg_bank[3] = bank + 1;
+ update_prg_banks(2, 3);
+}
+
+void device_nes_cart_interface::prg8_89(int bank)
+{
+ /* assumes that bank references an 8k chunk */
+ bank = prg_8k_bank_num(bank);
+
+ m_prg_bank[0] = bank;
+ update_prg_banks(0, 0);
+}
+
+void device_nes_cart_interface::prg8_ab(int bank)
+{
+ /* assumes that bank references an 8k chunk */
+ bank = prg_8k_bank_num(bank);
+
+ m_prg_bank[1] = bank;
+ update_prg_banks(1, 1);
+}
+
+void device_nes_cart_interface::prg8_cd(int bank)
+{
+ /* assumes that bank references an 8k chunk */
+ bank = prg_8k_bank_num(bank);
+
+ m_prg_bank[2] = bank;
+ update_prg_banks(2, 2);
+}
+
+void device_nes_cart_interface::prg8_ef(int bank)
+{
+ /* assumes that bank references an 8k chunk */
+ bank = prg_8k_bank_num(bank);
+
+ m_prg_bank[3] = bank;
+ update_prg_banks(3, 3);
+}
+
+/* We also define an additional helper to map 8k PRG-ROM to one of the banks (passed as parameter) */
+void device_nes_cart_interface::prg8_x(int start, int bank)
+{
+ assert(start < 4);
+
+ /* assumes that bank references an 8k chunk */
+ bank = prg_8k_bank_num(bank);
+
+ m_prg_bank[start] = bank;
+ update_prg_banks(start, start);
+}
+
+//-------------------------------------------------
+// CHR helpers
+//-------------------------------------------------
+
+inline void device_nes_cart_interface::chr_sanity_check( int source )
+{
+ if (source == CHRRAM && m_vram == NULL)
+ fatalerror("CHRRAM bankswitch with no VRAM\n");
+
+ if (source == CHRROM && m_vrom == NULL)
+ fatalerror("CHRROM bankswitch with no VROM\n");
+}
+
+void device_nes_cart_interface::chr8(int bank, int source)
+{
+ chr_sanity_check(source);
+
+ if (source == CHRRAM)
+ {
+ bank &= (m_vram_chunks - 1);
+ for (int i = 0; i < 8; i++)
+ {
+ m_chr_src[i] = source;
+ m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses!
+ m_chr_access[i] = &m_vram[m_chr_orig[i]];
+ }
+ }
+ else
+ {
+ bank &= (m_vrom_chunks - 1);
+ for (int i = 0; i < 8; i++)
+ {
+ m_chr_src[i] = source;
+ m_chr_orig[i] = (bank * 0x2000) + (i * 0x400); // for save state uses!
+ m_chr_access[i] = &m_vrom[m_chr_orig[i]];
+ }
+ }
+}
+
+void device_nes_cart_interface::chr4_x(int start, int bank, int source)
+{
+ chr_sanity_check(source);
+
+ if (source == CHRRAM)
+ {
+ bank &= ((m_vram_chunks << 1) - 1);
+ for (int i = 0; i < 4; i++)
+ {
+ m_chr_src[i + start] = source;
+ m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses!
+ m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]];
+ }
+ }
+ else
+ {
+ bank &= ((m_vrom_chunks << 1) - 1);
+ for (int i = 0; i < 4; i++)
+ {
+ m_chr_src[i + start] = source;
+ m_chr_orig[i + start] = (bank * 0x1000) + (i * 0x400); // for save state uses!
+ m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]];
+ }
+ }
+}
+
+void device_nes_cart_interface::chr2_x(int start, int bank, int source)
+{
+ chr_sanity_check(source);
+
+ if (source == CHRRAM)
+ {
+ bank &= ((m_vram_chunks << 2) - 1);
+ for (int i = 0; i < 2; i++)
+ {
+ m_chr_src[i + start] = source;
+ m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses!
+ m_chr_access[i + start] = &m_vram[m_chr_orig[i + start]];
+ }
+ }
+ else
+ {
+ bank &= ((m_vrom_chunks << 2) - 1);
+ for (int i = 0; i < 2; i++)
+ {
+ m_chr_src[i + start] = source;
+ m_chr_orig[i + start] = (bank * 0x800) + (i * 0x400); // for save state uses!
+ m_chr_access[i + start] = &m_vrom[m_chr_orig[i + start]];
+ }
+ }
+}
+
+void device_nes_cart_interface::chr1_x(int start, int bank, int source)
+{
+ chr_sanity_check(source);
+
+ if (source == CHRRAM)
+ {
+ bank &= ((m_vram_chunks << 3) - 1);
+ m_chr_src[start] = source;
+ m_chr_orig[start] = (bank * 0x400); // for save state uses!
+ m_chr_access[start] = &m_vram[m_chr_orig[start]];
+ }
+ else
+ {
+ bank &= ((m_vrom_chunks << 3) - 1);
+ m_chr_src[start] = source;
+ m_chr_orig[start] = (bank * 0x400); // for save state uses!
+ m_chr_access[start] = &m_vrom[m_chr_orig[start]];
+ }
+}
+
+//-------------------------------------------------
+// NT & Mirroring helpers
+//-------------------------------------------------
+
+void device_nes_cart_interface::set_nt_page(int page, int source, int bank, int writable)
+{
+ UINT8* base_ptr;
+
+ switch (source)
+ {
+ case CART_NTRAM:
+ base_ptr = m_ext_ntram;
+ break;
+ case MMC5FILL:
+ base_ptr = NULL;
+ break;
+ case VROM:
+ bank &= ((m_vrom_chunks << 3) - 1);
+ base_ptr = m_vrom;
+ break;
+ case EXRAM:
+ base_ptr = m_mapper_sram;
+ break;
+ case CIRAM:
+ default:
+ base_ptr = m_ciram;
+ break;
+ }
+
+ page &= 3; /* mask down to the 4 logical pages */
+ m_nt_src[page] = source;
+
+ if (base_ptr != NULL)
+ {
+ m_nt_orig[page] = bank * 0x400;
+ m_nt_access[page] = base_ptr + m_nt_orig[page];
+ }
+
+ m_nt_writable[page] = writable;
+}
+
+void device_nes_cart_interface::set_nt_mirroring(int mirroring)
{
- if (m_mapper_ram == NULL)
+ /* setup our videomem handlers based on mirroring */
+ switch (mirroring)
{
- m_mapper_ram = auto_alloc_array(machine, UINT8, size);
- m_mapper_ram_size = size;
+ case PPU_MIRROR_VERT:
+ set_nt_page(0, CIRAM, 0, 1);
+ set_nt_page(1, CIRAM, 1, 1);
+ set_nt_page(2, CIRAM, 0, 1);
+ set_nt_page(3, CIRAM, 1, 1);
+ break;
+
+ case PPU_MIRROR_HORZ:
+ set_nt_page(0, CIRAM, 0, 1);
+ set_nt_page(1, CIRAM, 0, 1);
+ set_nt_page(2, CIRAM, 1, 1);
+ set_nt_page(3, CIRAM, 1, 1);
+ break;
+
+ case PPU_MIRROR_HIGH:
+ set_nt_page(0, CIRAM, 1, 1);
+ set_nt_page(1, CIRAM, 1, 1);
+ set_nt_page(2, CIRAM, 1, 1);
+ set_nt_page(3, CIRAM, 1, 1);
+ break;
+
+ case PPU_MIRROR_LOW:
+ set_nt_page(0, CIRAM, 0, 1);
+ set_nt_page(1, CIRAM, 0, 1);
+ set_nt_page(2, CIRAM, 0, 1);
+ set_nt_page(3, CIRAM, 0, 1);
+ break;
+
+ case PPU_MIRROR_4SCREEN:
+ if (!m_ext_ntram) fatalerror("4-screen mirroring without on-cart NTRAM!\n");
+ set_nt_page(0, CART_NTRAM, 0, 1);
+ set_nt_page(1, CART_NTRAM, 1, 1);
+ set_nt_page(2, CART_NTRAM, 2, 1);
+ set_nt_page(3, CART_NTRAM, 3, 1);
+ break;
+
+ case PPU_MIRROR_NONE:
+ default:
+ set_nt_page(0, CIRAM, 0, 1);
+ set_nt_page(1, CIRAM, 0, 1);
+ set_nt_page(2, CIRAM, 1, 1);
+ set_nt_page(3, CIRAM, 1, 1);
+ break;
}
}
-void device_nes_cart_interface::mapper_bram_alloc(running_machine &machine, size_t size)
+//-------------------------------------------------
+// Other helpers
+//-------------------------------------------------
+
+// Helper function for the few mappers reading from 0x8000-0xffff for protection
+// so that they can access the ROM after the protection handling (which overwrites
+// the memory banks)
+UINT8 device_nes_cart_interface::hi_access_rom(UINT32 offset)
+{
+ int bank = (offset & 0x6000) >> 13;
+ return m_prg[m_prg_bank[bank] * 0x2000 + (offset & 0x1fff)];
+}
+
+// Helper function for the few mappers subject to bus conflict at write.
+// Tests by blargg showed that in many of the boards suffering of CPU/ROM
+// conflicts the behaviour can be accurately emulated by writing not the
+// original data, but data & rom[offset]
+UINT8 device_nes_cart_interface::account_bus_conflict(UINT32 offset, UINT8 data)
+{
+ // pirate variants of boards subject to bus conflict are often not subject to it
+ // so we allow to set m_bus_conflict to FALSE at loading time when necessary
+ if (m_bus_conflict)
+ return data & hi_access_rom(offset);
+ else
+ return data;
+}
+
+
+//-------------------------------------------------
+// PPU accessors
+//-------------------------------------------------
+
+WRITE8_MEMBER(device_nes_cart_interface::chr_w)
+{
+ int bank = offset >> 10;
+
+ if (m_chr_src[bank] == CHRRAM)
+ m_chr_access[bank][offset & 0x3ff] = data;
+}
+
+READ8_MEMBER(device_nes_cart_interface::chr_r)
+{
+ int bank = offset >> 10;
+ return m_chr_access[bank][offset & 0x3ff];
+}
+
+
+WRITE8_MEMBER(device_nes_cart_interface::nt_w)
+{
+ int page = ((offset & 0xc00) >> 10);
+
+ if (!m_nt_writable[page])
+ return;
+
+ m_nt_access[page][offset & 0x3ff] = data;
+}
+
+READ8_MEMBER(device_nes_cart_interface::nt_r)
+{
+ int page = ((offset & 0xc00) >> 10);
+ return m_nt_access[page][offset & 0x3ff];
+}
+
+
+//-------------------------------------------------
+// Base memory accessors (emulating open bus
+// behaviour and/or WRAM accesses)
+// Open bus emulation is defective, but it should
+// be enough for the few cases known to rely on
+// this (more in the comments at the top of the
+// source)
+//-------------------------------------------------
+
+READ8_MEMBER(device_nes_cart_interface::read_l)
+{
+ return ((offset + 0x4100) & 0xff00) >> 8; // open bus
+}
+
+READ8_MEMBER(device_nes_cart_interface::read_m)
+{
+ if (m_battery)
+ return m_battery[offset & (m_battery_size - 1)];
+ if (m_prgram)
+ return m_prgram[offset & (m_prgram_size - 1)];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+WRITE8_MEMBER(device_nes_cart_interface::write_l)
+{
+}
+
+WRITE8_MEMBER(device_nes_cart_interface::write_m)
+{
+ if (m_battery)
+ m_battery[offset & (m_battery_size - 1)] = data;
+ if (m_prgram)
+ m_prgram[offset & (m_prgram_size - 1)] = data;
+}
+
+WRITE8_MEMBER(device_nes_cart_interface::write_h)
+{
+}
+
+
+void device_nes_cart_interface::pcb_start(running_machine &machine, UINT8 *ciram_ptr)
{
- if (m_mapper_bram == NULL)
+ // Setup PRG
+ m_prg_bank_mem[0] = machine.root_device().membank("prg0");
+ m_prg_bank_mem[1] = machine.root_device().membank("prg1");
+ m_prg_bank_mem[2] = machine.root_device().membank("prg2");
+ m_prg_bank_mem[3] = machine.root_device().membank("prg3");
+ for (int i = 0; i < 4; i++)
+ {
+ int next_bank = m_prg_size / 0x2000;
+ m_prg_bank_mem[i]->configure_entries(0, m_prg_size / 0x2000, m_prg, 0x2000);
+ // MMC5 (and a few other PCBs) can also map WRAM/BWRAM in these banks, so we add here 4x8K banks for each RAM chip
+ if (m_battery)
+ {
+ if (m_battery_size / 0x2000 == 4)
+ {
+ m_prg_bank_mem[i]->configure_entries(next_bank, 4, m_battery, 0x2000);
+ }
+ if (m_battery_size / 0x2000 == 2)
+ {
+ m_prg_bank_mem[i]->configure_entries(next_bank + 0, 2, m_battery, 0x2000);
+ m_prg_bank_mem[i]->configure_entries(next_bank + 2, 2, m_battery, 0x2000);
+ }
+ if (m_battery_size / 0x2000 == 1)
+ {
+ m_prg_bank_mem[i]->configure_entries(next_bank + 0, 1, m_battery, 0x2000);
+ m_prg_bank_mem[i]->configure_entries(next_bank + 1, 1, m_battery, 0x2000);
+ m_prg_bank_mem[i]->configure_entries(next_bank + 2, 1, m_battery, 0x2000);
+ m_prg_bank_mem[i]->configure_entries(next_bank + 3, 1, m_battery, 0x2000);
+ }
+ next_bank += 4;
+ }
+ if (m_prgram)
+ {
+ if (m_prgram_size / 0x2000 == 4)
+ {
+ m_prg_bank_mem[i]->configure_entries(next_bank, 4, m_prgram, 0x2000);
+ }
+ if (m_prgram_size / 0x2000 == 2)
+ {
+ m_prg_bank_mem[i]->configure_entries(next_bank + 0, 2, m_prgram, 0x2000);
+ m_prg_bank_mem[i]->configure_entries(next_bank + 2, 2, m_prgram, 0x2000);
+ }
+ if (m_prgram_size / 0x2000 == 1)
+ {
+ m_prg_bank_mem[i]->configure_entries(next_bank + 0, 1, m_prgram, 0x2000);
+ m_prg_bank_mem[i]->configure_entries(next_bank + 1, 1, m_prgram, 0x2000);
+ m_prg_bank_mem[i]->configure_entries(next_bank + 2, 1, m_prgram, 0x2000);
+ m_prg_bank_mem[i]->configure_entries(next_bank + 3, 1, m_prgram, 0x2000);
+ }
+ next_bank += 4;
+ }
+
+ // ...but we always map the banks to PRG at start
+ m_prg_bank_mem[i]->set_entry(i);
+ m_prg_bank[i] = i;
+ }
+
+ // Setup CHR
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ chr8(0, m_chr_source);
+
+ // Setup NT
+ m_ciram = ciram_ptr;
+
+ if (m_four_screen_vram)
{
- m_mapper_bram = auto_alloc_array(machine, UINT8, size);
- m_mapper_bram_size = size;
+ m_ext_ntram_size = 0x2000;
+ m_ext_ntram = auto_alloc_array_clear(machine, UINT8, m_ext_ntram_size);
}
+
+ // at loading time we have configured m_mirroring, now setup NT pages
+ set_nt_mirroring(m_mirroring);
+}
+
+void device_nes_cart_interface::pcb_reg_postload(running_machine &machine)
+{
+ machine.save().register_postload(save_prepost_delegate(FUNC(device_nes_cart_interface::nes_banks_restore), this));
+}
+
+void device_nes_cart_interface::nes_banks_restore()
+{
+ for (int i = 0; i < 4; i++)
+ m_prg_bank_mem[i]->set_entry(m_prg_bank[i]);
+
+ for (int i = 0; i < 8; i++)
+ chr1_x(i, m_chr_orig[i] / 0x400, m_chr_src[i]);
+
+ for (int i = 0; i < 4; i++)
+ set_nt_page(i, m_nt_src[i], m_nt_orig[i], m_nt_writable[i]);
+
+ set_nt_mirroring(m_mirroring);
}
@@ -126,13 +824,8 @@ nes_cart_slot_device::nes_cart_slot_device(const machine_config &mconfig, const
device_t(mconfig, NES_CART_SLOT, "NES Cartridge Slot", tag, owner, clock),
device_image_interface(mconfig, *this),
device_slot_interface(mconfig, *this),
- m_chr_open_bus(0),
- m_ce_mask(0),
- m_ce_state(0),
- m_vrc_ls_prg_a(0),
- m_vrc_ls_prg_b(0),
- m_vrc_ls_chr(0),
m_crc_hack(0),
+ m_pcb_id(NO_BOARD),
m_must_be_loaded(1)
{
}
@@ -162,759 +855,89 @@ void nes_cart_slot_device::device_start()
void nes_cart_slot_device::device_config_complete()
{
- // inherit a copy of the static data
-// const nes_cart_interface *intf = reinterpret_cast<const nes_cart_interface *>(static_config());
-// if (intf != NULL)
-// {
-// *static_cast<nes_cart_interface *>(this) = *intf;
-// }
-
// set brief and instance name
update_names();
}
-//-------------------------------------------------
-// device_timer - handler timer events
-//-------------------------------------------------
+void nes_cart_slot_device::pcb_start(UINT8 *ciram_ptr)
+{
+ if (m_cart)
+ m_cart->pcb_start(machine(), ciram_ptr);
+}
+
+void nes_cart_slot_device::pcb_reset()
+{
+ if (m_cart)
+ m_cart->pcb_reset();
+}
/*-------------------------------------------------
call load
-------------------------------------------------*/
-struct nes_cart_lines
-{
- const char *tag;
- int line;
-};
+/*-------------------------------------------------
+
+ Load from xml list and identify the required slot device
+
+ -------------------------------------------------*/
-static const struct nes_cart_lines nes_cart_lines_table[] =
-{
- { "PRG A0", 0 },
- { "PRG A1", 1 },
- { "PRG A2", 2 },
- { "PRG A3", 3 },
- { "PRG A4", 4 },
- { "PRG A5", 5 },
- { "PRG A6", 6 },
- { "PRG A7", 7 },
- { "CHR A10", 10 },
- { "CHR A11", 11 },
- { "CHR A12", 12 },
- { "CHR A13", 13 },
- { "CHR A14", 14 },
- { "CHR A15", 15 },
- { "CHR A16", 16 },
- { "CHR A17", 17 },
- { "NC", 127 },
- { 0 }
-};
-
-static int nes_cart_get_line( const char *feature )
-{
- const struct nes_cart_lines *nes_line = &nes_cart_lines_table[0];
+/* Include emulation of NES PCBs for softlist */
+#include "machine/nes_pcb.c"
- if (feature == NULL)
- return 128;
- while (nes_line->tag)
- {
- if (strcmp(nes_line->tag, feature) == 0)
- break;
+/*-------------------------------------------------
+
+ Load .unf files (UNIF boards) and identify the required slot device
+
+ -------------------------------------------------*/
- nes_line++;
- }
+/* Include emulation of UNIF Boards for .unf files */
+#include "machine/nes_unif.c"
- return nes_line->line;
-}
-/* Set to generate prg & chr files when the cart is loaded */
-#define SPLIT_PRG 0
-#define SPLIT_CHR 0
+/*-------------------------------------------------
+
+ Load .nes files (iNES mappers) and identify the required slot devices
+
+ -------------------------------------------------*/
+
+/* Include emulation of iNES Mappers for .nes files */
+#include "machine/nes_ines.c"
+
bool nes_cart_slot_device::call_load()
{
if (m_cart)
{
- UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_ram_size = 0, mapper_bram_size = 0; // helper for regions to alloc at the end
-
if (software_entry() == NULL)
{
- const char *mapinfo = NULL;
- int mapint1 = 0, mapint2 = 0, mapint3 = 0, mapint4 = 0;
char magic[4];
/* Check first 4 bytes of the image to decide if it is UNIF or iNES */
/* Unfortunately, many .unf files have been released as .nes, so we cannot rely on extensions only */
- memset(magic, '\0', sizeof(magic));
fread(magic, 4);
if ((magic[0] == 'N') && (magic[1] == 'E') && (magic[2] == 'S')) /* If header starts with 'NES' it is iNES */
{
- UINT32 prg_size, vrom_size;
- UINT8 header[0x10];
- UINT8 mapper, local_options;
- bool ines20 = FALSE, has_trainer = FALSE, prg16k;
-
- // check if the image is recognized by nes.hsi
- mapinfo = hashfile_extrainfo(*this);
-
- // image_extrainfo() resets the file position back to start.
- fseek(0, SEEK_SET);
- // read out the header
- fread(&header, 0x10);
-
- // SETUP step 1: getting PRG, VROM, VRAM sizes
- prg16k = (header[4] == 1);
- prg_size = prg16k ? 2 * 0x4000 : header[4] * 0x4000;
- vrom_size = header[5] * 0x2000;
- vram_size = 0x4000;
-
- // SETUP step 2: getting PCB and other settings
- mapper = (header[6] & 0xf0) >> 4;
- local_options = header[6] & 0x0f;
-
- switch (header[7] & 0xc)
- {
- case 0x4:
- case 0xc:
- // probably the header got corrupted: don't trust upper bits for mapper
- break;
-
- case 0x8: // it's iNES 2.0 format
- ines20 = TRUE;
- case 0x0:
- default:
- mapper |= header[7] & 0xf0;
- break;
- }
-
- // use info from nes.hsi if available!
- if (mapinfo)
- {
- if (4 == sscanf(mapinfo,"%d %d %d %d", &mapint1, &mapint2, &mapint3, &mapint4))
- {
- /* image is present in nes.hsi: overwrite the header settings with these */
- mapper = mapint1;
- local_options = mapint2 & 0x0f;
- m_crc_hack = (mapint2 & 0xf0) >> 4; // this is used to differentiate among variants of the same Mapper (see below)
- prg16k = (mapint3 == 1);
- prg_size = prg16k ? 2 * 0x4000 : mapint3 * 0x4000;
- vrom_size = mapint4 * 0x2000;
- logerror("NES.HSI info: %d %d %d %d\n", mapint1, mapint2, mapint3, mapint4);
- }
- else
- {
- logerror("NES: [%s], Invalid mapinfo found\n", mapinfo);
- }
- }
- else
+ if (length() <= 0x10)
{
- logerror("NES: No extrainfo found\n");
- }
-
- // use extended iNES2.0 info if available!
- if (ines20)
- {
- mapper |= (header[8] & 0x0f) << 8;
- // header[8] & 0xf0 is used for submappers, but I haven't found any specific image to implement this
- prg_size += ((header[9] & 0x0f) << 8) * 0x4000;
- vrom_size += ((header[9] & 0xf0) << 4) * 0x2000;
- }
-
- // SETUP step 3: storing the info needed for emulation
- m_pcb_id = nes_get_mmc_id(machine(), mapper);
- m_cart->set_mirroring(BIT(local_options, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
- if (BIT(local_options, 1))
- battery_size = NES_BATTERY_SIZE; // with original iNES format we can only support 8K WRAM battery
- has_trainer = BIT(local_options, 2) ? TRUE : FALSE;
- m_cart->set_four_screen_vram(BIT(local_options, 3));
-
- if (ines20)
- {
- // PRGRAM/BWRAM (not fully supported, also due to lack of 2.0 files)
- if ((header[10] & 0x0f) > 0)
- prgram_size = 0x80 << ((header[10] & 0x0f) - 1);
- if ((header[10] & 0xf0) > 0)
- battery_size = 0x80 << ((header[10] & 0xf0) - 5);
- // VRAM
- vram_size = 0;
- if ((header[11] & 0x0f) > 0)
- vram_size = 0x80 << ((header[11] & 0x0f) - 1);
- // header[11] & 0xf0 is the size of battery backed VRAM, found so far in Racermate II only and not supported yet
- }
- else
- {
- // always map PRGRAM/WRAM in bank5 (eventually, this should be enabled only for some mappers)
- // and save it depending on has_battery
-
- // PRGRAM size is 8k for most games, but pirate carts often use different sizes,
- // so its size has been added recently to the iNES format spec, but almost no image uses it
- prgram_size = header[8] ? header[8] * 0x2000 : 0x2000;
- }
-
- // a few mappers correspond to multiple PCBs, so we need a few additional checks and tweaks
- switch (m_pcb_id)
- {
- case STD_CNROM:
- if (mapper == 185)
- {
- switch (m_crc_hack)
- {
- case 0x0: // pin26: CE, pin27: CE (B-Wings, Bird Week)
- m_ce_mask = 0x03;
- m_ce_state = 0x03;
- break;
- case 0x4: // pin26: CE, pin27: /CE (Mighty Bomb Jack, Spy Vs. Spy)
- m_ce_mask = 0x03;
- m_ce_state = 0x01;
- break;
- case 0x8: // pin26: /CE, pin27: CE (Sansu 1, 2, 3 Nen)
- m_ce_mask = 0x03;
- m_ce_state = 0x02;
- break;
- case 0xc: // pin26: /CE, pin27: /CE (Seicross v2.0)
- m_ce_mask = 0x03;
- m_ce_state = 0x00;
- break;
- }
- }
- break;
- case KONAMI_VRC2:
- if (mapper == 22)
- {
- m_vrc_ls_prg_a = 0;
- m_vrc_ls_prg_b = 1;
- m_vrc_ls_chr = 1;
- }
- if (mapper == 23 && !m_crc_hack)
- {
- m_vrc_ls_prg_a = 1;
- m_vrc_ls_prg_b = 0;
- m_vrc_ls_chr = 0;
- }
- if (mapper == 23 && m_crc_hack)
- {
- // here there are also Akumajou Special, Crisis Force, Parodius da!, Tiny Toons which are VRC-4
- m_vrc_ls_prg_a = 3;
- m_vrc_ls_prg_b = 2;
- m_pcb_id = KONAMI_VRC4; // this allows for konami_irq to be installed at reset
- }
- break;
- case KONAMI_VRC4:
- if (mapper == 21)
- {
- // Wai Wai World 2 & Ganbare Goemon Gaiden 2 (the latter with crc_hack)
- m_vrc_ls_prg_a = m_crc_hack ? 7 : 2;
- m_vrc_ls_prg_b = m_crc_hack ? 6 : 1;
- }
- if (mapper == 25) // here there is also Ganbare Goemon Gaiden which is VRC-2
- {
- m_vrc_ls_prg_a = m_crc_hack ? 2 : 0;
- m_vrc_ls_prg_b = m_crc_hack ? 3 : 1;
- }
- break;
- case KONAMI_VRC6:
- if (mapper == 24)
- {
- m_vrc_ls_prg_a = 1;
- m_vrc_ls_prg_b = 0;
- }
- if (mapper == 26)
- {
- m_vrc_ls_prg_a = 0;
- m_vrc_ls_prg_b = 1;
- }
- break;
- case IREM_G101:
- if (m_crc_hack)
- m_cart->set_mirroring(PPU_MIRROR_HIGH); // Major League has hardwired mirroring
- break;
- case DIS_74X161X161X32:
- if (mapper == 70)
- m_cart->set_mirroring(PPU_MIRROR_VERT); // only hardwired mirroring makes different mappers 70 & 152
- break;
- case SUNSOFT_2:
- if (mapper == 93)
- m_cart->set_mirroring(PPU_MIRROR_VERT); // only hardwired mirroring makes different mappers 89 & 93
- break;
- case STD_BXROM:
- if (m_crc_hack)
- m_pcb_id = AVE_NINA01; // Mapper 34 is used for 2 diff boards
- break;
- case BANDAI_LZ93:
- if (m_crc_hack)
- m_pcb_id = BANDAI_JUMP2; // Mapper 153 is used for 2 diff boards
- break;
- case IREM_HOLYDIV:
- if (m_crc_hack)
- m_pcb_id = JALECO_JF16; // Mapper 78 is used for 2 diff boards
- break;
- case CAMERICA_BF9093:
- if (m_crc_hack)
- m_pcb_id = CAMERICA_BF9097; // Mapper 71 is used for 2 diff boards
- break;
- case HES_BOARD:
- if (m_crc_hack)
- m_pcb_id = HES6IN1_BOARD; // Mapper 113 is used for 2 diff boards
- break;
- case WAIXING_ZS:
- if (m_crc_hack)
- m_pcb_id = WAIXING_DQ8; // Mapper 242 is used for 2 diff boards
- break;
- case BMC_GOLD_7IN1:
- if (m_crc_hack)
- m_pcb_id = BMC_MARIOPARTY_7IN1; // Mapper 52 is used for 2 diff boards
- break;
- case STD_EXROM:
- mapper_ram_size = 0x400;
- break;
- case TAITO_X1_017:
- mapper_ram_size = 0x1400;
- break;
- case TAITO_X1_005:
- case TAITO_X1_005_A:
- mapper_ram_size = 0x80;
- break;
- case NAMCOT_163:
- mapper_ram_size = 0x2000;
- break;
- case FUKUTAKE_BOARD:
- mapper_ram_size = 2816;
- break;
- //FIXME: we also have to fix Action 52 PRG loading somewhere...
- }
-
- // SETUP step 4: logging what we have found
- if (!ines20)
- {
- logerror("Loaded game in iNES format:\n");
- logerror("-- Mapper %d\n", mapper);
- logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000);
- logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000);
- logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000);
- if (battery_size)
- logerror("-- Battery found\n");
- if (has_trainer)
- logerror("-- Trainer found\n");
- if (m_cart->get_four_screen_vram())
- logerror("-- 4-screen VRAM\n");
- logerror("-- TV System: %s\n", ((header[10] & 3) == 0) ? "NTSC" : (header[10] & 1) ? "Both NTSC and PAL" : "PAL");
- }
- else
- {
- logerror("Loaded game in Extended iNES format:\n");
- logerror("-- Mapper: %d\n", mapper);
- logerror("-- Submapper: %d\n", (header[8] & 0xf0) >> 4);
- logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000);
- logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000);
- logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000);
- logerror("-- PRG NVWRAM: %d\n", header[10] & 0x0f);
- logerror("-- PRG WRAM: %d\n", (header[10] & 0xf0) >> 4);
- logerror("-- CHR NVWRAM: %d\n", header[11] & 0x0f);
- logerror("-- CHR WRAM: %d\n", (header[11] & 0xf0) >> 4);
- logerror("-- TV System: %s\n", (header[12] & 2) ? "Both NTSC and PAL" : (header[12] & 1) ? "PAL" : "NTSC");
- }
-
- // SETUP step 5: allocate pointers for PRG/VROM
- if (prg_size)
- m_cart->prg_alloc(machine(), prg_size);
- if (vrom_size)
- m_cart->vrom_alloc(machine(), vrom_size);
-
- if (has_trainer)
- fread(&m_cart->m_prgram[0x1000], 0x200);
-
-
- // SETUP step 6: at last load the data!
- // Read in the program chunks
- if (prg16k)
- {
- fread(m_cart->get_prg_base(), 0x4000);
- memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000);
- }
- else
- fread(m_cart->get_prg_base(), m_cart->get_prg_size());
-#if SPLIT_PRG
- {
- FILE *prgout;
- char outname[255];
-
- sprintf(outname, "%s.prg", filename());
- prgout = fopen(outname, "wb");
- if (prgout)
- {
- fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout);
- mame_printf_error("Created PRG chunk\n");
- }
-
- fclose(prgout);
+ logerror("%s only contains the iNES header and no data.\n", filename());
+ return IMAGE_INIT_FAIL;
}
-#endif
-
- // Read in any chr chunks
- if (m_cart->get_vrom_size())
- fread(m_cart->get_vrom_base(), m_cart->get_vrom_size());
-#if SPLIT_CHR
- if (state->m_chr_chunks > 0)
- {
- FILE *chrout;
- char outname[255];
-
- sprintf(outname, "%s.chr", filename());
- chrout= fopen(outname, "wb");
- if (chrout)
- {
- fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout);
- mame_printf_error("Created CHR chunk\n");
- }
- fclose(chrout);
- }
-#endif
+ call_load_ines();
}
else if ((magic[0] == 'U') && (magic[1] == 'N') && (magic[2] == 'I') && (magic[3] == 'F')) /* If header starts with 'UNIF' it is UNIF */
{
- // SETUP step 1: running through the file and getting PRG, VROM sizes
- UINT32 unif_ver = 0, chunk_length = 0, read_length = 0x20;
- UINT32 prg_start = 0, chr_start = 0;
- UINT32 size = length(), prg_size = 0, vrom_size = 0;
- UINT8 buffer[4], mirror = 0;
- char magic2[4];
- char unif_mapr[32]; // here we should store MAPR chunks
- bool mapr_chunk_found = FALSE, small_prg = FALSE;
-
- // allocate space to temporarily store PRG & CHR banks
- UINT8 *temp_prg = auto_alloc_array(machine(), UINT8, 256 * 0x4000);
- UINT8 *temp_chr = auto_alloc_array(machine(), UINT8, 256 * 0x2000);
- UINT8 temp_byte = 0;
-
- fread(&buffer, 4);
- unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
- logerror("Loaded game in UNIF format, version %d\n", unif_ver);
-
- if (size <= 0x20)
+ if (length() <= 0x20)
{
logerror("%s only contains the UNIF header and no data.\n", filename());
return IMAGE_INIT_FAIL;
}
- do
- {
- fseek(read_length, SEEK_SET);
-
- memset(magic2, '\0', sizeof(magic2));
- fread(&magic2, 4);
-
- /* We first run through the whole image to find a [MAPR] chunk. This is needed
- because, unfortunately, the MAPR chunk is not always the first chunk (see
- Super 24-in-1). When such a chunk is found, we set mapr_chunk_found=1 and
- we go back to load other chunks! */
- if (!mapr_chunk_found)
- {
- if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R'))
- {
- mapr_chunk_found = TRUE;
- logerror("[MAPR] chunk found: ");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- if (chunk_length <= 0x20)
- fread(&unif_mapr, chunk_length);
- logerror("%s\n", unif_mapr);
-
- /* now that we found the MAPR chunk, we can go back to load other chunks */
- fseek(0x20, SEEK_SET);
- read_length = 0x20;
- }
- else
- {
- logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- }
- else
- {
- /* What kind of chunk do we have here? */
- if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R'))
- {
- /* The [MAPR] chunk has already been read, so we skip it */
- /* TO DO: it would be nice to check if more than one MAPR chunk is present */
- logerror("[MAPR] chunk found (in the 2nd run). Already loaded.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'R') && (magic2[1] == 'E') && (magic2[2] == 'A') && (magic2[3] == 'D'))
- {
- logerror("[READ] chunk found. No support yet.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'N') && (magic2[1] == 'A') && (magic2[2] == 'M') && (magic2[3] == 'E'))
- {
- logerror("[NAME] chunk found. No support yet.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'W') && (magic2[1] == 'R') && (magic2[2] == 'T') && (magic2[3] == 'R'))
- {
- logerror("[WRTR] chunk found. No support yet.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'C') && (magic2[3] == 'I'))
- {
- logerror("[TVCI] chunk found.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- fread(&temp_byte, 1);
- logerror("Television Standard : %s\n", (temp_byte == 0) ? "NTSC" : (temp_byte == 1) ? "PAL" : "Does not matter");
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'S') && (magic2[3] == 'C')) // is this the same as TVCI??
- {
- logerror("[TVSC] chunk found. No support yet.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'D') && (magic2[1] == 'I') && (magic2[2] == 'N') && (magic2[3] == 'F'))
- {
- logerror("[DINF] chunk found. No support yet.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'C') && (magic2[1] == 'T') && (magic2[2] == 'R') && (magic2[3] == 'L'))
- {
- logerror("[CTRL] chunk found. No support yet.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'B') && (magic2[1] == 'A') && (magic2[2] == 'T') && (magic2[3] == 'R'))
- {
- logerror("[BATR] chunk found. No support yet.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'V') && (magic2[1] == 'R') && (magic2[2] == 'O') && (magic2[3] == 'R'))
- {
- logerror("[VROR] chunk found. No support yet.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'M') && (magic2[1] == 'I') && (magic2[2] == 'R') && (magic2[3] == 'R'))
- {
- logerror("[MIRR] chunk found.\n");
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- fread(&mirror, 1);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'P') && (magic2[1] == 'C') && (magic2[2] == 'K'))
- {
- logerror("[PCK%c] chunk found. No support yet.\n", magic2[3]);
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'C') && (magic2[1] == 'C') && (magic2[2] == 'K'))
- {
- logerror("[CCK%c] chunk found. No support yet.\n", magic2[3]);
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
-
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'P') && (magic2[1] == 'R') && (magic2[2] == 'G'))
- {
- logerror("[PRG%c] chunk found. ", magic2[3]);
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
- prg_size += chunk_length;
-
- if (chunk_length / 0x4000)
- logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000);
- else
- {
- small_prg = TRUE;
- logerror("This chunk is smaller than 16K: the emulation might have issues. Please report this file to the MESS forums.\n");
- }
-
- /* Read in the program chunks */
- fread(&temp_prg[prg_start], chunk_length);
-
- prg_start += chunk_length;
- read_length += (chunk_length + 8);
- }
- else if ((magic2[0] == 'C') && (magic2[1] == 'H') && (magic2[2] == 'R'))
- {
- logerror("[CHR%c] chunk found. ", magic2[3]);
- fread(&buffer, 4);
- chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
- vrom_size += chunk_length;
-
- logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000);
-
- /* Read in the vrom chunks */
- fread(&temp_chr[chr_start], chunk_length);
-
- chr_start += chunk_length;
- read_length += (chunk_length + 8);
- }
- else
- {
- logerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n");
- read_length = size;
- }
- }
- } while (size > read_length);
-
- if (!mapr_chunk_found)
- {
- auto_free(machine(), temp_prg);
- auto_free(machine(), temp_chr);
- fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted\n");
- }
-
- if (!prg_start)
- {
- auto_free(machine(), temp_prg);
- auto_free(machine(), temp_chr);
- fatalerror("No PRG found. Please report the problem at MESS Board.\n");
- }
-
- // SETUP step 2: getting PCB and other settings
- int pcb_id = 0, battery = 0, prgram = 0, vram_chunks = 0;
- unif_mapr_setup(unif_mapr, &pcb_id, &battery, &prgram, &vram_chunks);
-
- // SETUP step 3: storing the info needed for emulation
- m_pcb_id = pcb_id;
- if (battery)
- battery_size = NES_BATTERY_SIZE; // we should allow for smaller battery!
- prgram_size = prgram * 0x2000;
- vram_size = vram_chunks * 0x2000;
-
- m_cart->set_four_screen_vram(0);
- switch (mirror)
- {
- case 0: // Horizontal Mirroring (Hard Wired)
- m_cart->set_mirroring(PPU_MIRROR_HORZ);
- break;
- case 1: // Vertical Mirroring (Hard Wired)
- m_cart->set_mirroring(PPU_MIRROR_VERT);
- break;
- case 2: // Mirror All Pages From $2000 (Hard Wired)
- m_cart->set_mirroring(PPU_MIRROR_LOW);
- break;
- case 3: // Mirror All Pages From $2400 (Hard Wired)
- m_cart->set_mirroring(PPU_MIRROR_HIGH);
- break;
- case 4: // Four Screens of VRAM (Hard Wired)
- m_cart->set_four_screen_vram(1);
- break;
- case 5: // Mirroring Controlled By Mapper Hardware
- logerror("Mirroring handled by the board hardware.\n");
- // default to horizontal at start
- m_cart->set_mirroring(PPU_MIRROR_HORZ);
- break;
- default:
- logerror("Undocumented mirroring value.\n");
- // default to horizontal
- m_cart->set_mirroring(PPU_MIRROR_HORZ);
- break;
- }
-
- // SETUP step 4: logging what we have found
- logerror("-- Board %s\n", unif_mapr);
- logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000);
- logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000);
- logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000);
-
- // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data!
- if (prg_size == 0x4000)
- {
- m_cart->prg_alloc(machine(), 0x8000);
- memcpy(m_cart->get_prg_base(), temp_prg, 0x4000);
- memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000);
- }
- else
- {
- m_cart->prg_alloc(machine(), prg_size);
- memcpy(m_cart->get_prg_base(), temp_prg, prg_size);
- }
-
- if (small_prg) // This is not supported yet, so warn users about this
- mame_printf_error("Loaded UNIF file with non-16k PRG chunk. This is not supported in MESS yet.");
-
- if (vrom_size)
- {
- m_cart->vrom_alloc(machine(), vrom_size);
- memcpy(m_cart->get_vrom_base(), temp_chr, vrom_size);
- }
-
-#if SPLIT_PRG
- {
- FILE *prgout;
- char outname[255];
-
- sprintf(outname, "%s.prg", filename());
- prgout = fopen(outname, "wb");
- if (prgout)
- {
- fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout);
- mame_printf_error("Created PRG chunk\n");
- }
-
- fclose(prgout);
- }
-#endif
-
-#if SPLIT_CHR
- if (state->m_chr_chunks > 0)
- {
- FILE *chrout;
- char outname[255];
-
- sprintf(outname, "%s.chr", filename());
- chrout= fopen(outname, "wb");
- if (chrout)
- {
- fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout);
- mame_printf_error("Created CHR chunk\n");
- }
- fclose(chrout);
- }
-#endif
- // free the temporary copy of PRG/CHR
- auto_free(machine(), temp_prg);
- auto_free(machine(), temp_chr);
- logerror("UNIF support is only very preliminary.\n");
+ call_load_unif();
}
else
{
@@ -923,183 +946,7 @@ bool nes_cart_slot_device::call_load()
}
}
else
- {
- // SETUP step 1: getting PRG, VROM, VRAM sizes
- UINT32 prg_size = get_software_region_length("prg");
- UINT32 vrom_size = get_software_region_length("chr");
- UINT32 vram_size = get_software_region_length("vram");
- vram_size += get_software_region_length("vram2");
-
- // validate the xml fields
- if (!prg_size)
- fatalerror("No PRG entry for this software! Please check if the xml list got corrupted\n");
- if (prg_size < 0x8000)
- fatalerror("PRG entry is too small! Please check if the xml list got corrupted\n");
-
- // SETUP step 2: getting PCB and other settings
- if (get_feature("pcb"))
- m_pcb_id = nes_get_pcb_id(machine(), get_feature("pcb"));
- else
- m_pcb_id = NO_BOARD;
-
- // SETUP step 3: storing the info needed for emulation
- if (m_pcb_id == STD_TVROM || m_pcb_id == STD_DRROM || m_pcb_id == IREM_LROG017)
- m_cart->set_four_screen_vram(1);
- else
- m_cart->set_four_screen_vram(0);
-
- if (get_software_region("bwram") != NULL)
- battery_size = get_software_region_length("bwram");
-
- if (m_pcb_id == BANDAI_LZ93EX)
- {
- // allocate the 24C01 or 24C02 EEPROM
- battery_size += 0x2000;
- }
-
- if (m_pcb_id == BANDAI_DATACH)
- {
- // allocate the 24C01 and 24C02 EEPROM
- battery_size += 0x4000;
- }
-
- if (get_software_region("wram") != NULL)
- prgram_size = get_software_region_length("wram");
- if (get_software_region("mapper_ram") != NULL)
- mapper_ram_size = get_software_region_length("mapper_ram");
- if (get_software_region("mapper_bram") != NULL)
- mapper_bram_size = get_software_region_length("mapper_bram");
-
- if (get_feature("mirroring"))
- {
- const char *mirroring = get_feature("mirroring");
- if (!strcmp(mirroring, "horizontal"))
- m_cart->set_mirroring(PPU_MIRROR_HORZ);
- if (!strcmp(mirroring, "vertical"))
- m_cart->set_mirroring(PPU_MIRROR_VERT);
- if (!strcmp(mirroring, "high"))
- m_cart->set_mirroring(PPU_MIRROR_HIGH);
- if (!strcmp(mirroring, "low"))
- m_cart->set_mirroring(PPU_MIRROR_LOW);
- }
- else
- m_cart->set_mirroring(PPU_MIRROR_NONE);
-
- /* Check for pins in specific boards which require them */
- if (m_pcb_id == STD_CNROM)
- {
- if (get_feature("chr-pin26") != NULL)
- {
- m_ce_mask |= 0x01;
- m_ce_state |= !strcmp(get_feature("chr-pin26"), "CE") ? 0x01 : 0;
- }
- if (get_feature("chr-pin27") != NULL)
- {
- m_ce_mask |= 0x02;
- m_ce_state |= !strcmp(get_feature("chr-pin27"), "CE") ? 0x02 : 0;
- }
- }
-
- if (m_pcb_id == TAITO_X1_005 && get_feature("x1-pin17") != NULL && get_feature("x1-pin31") != NULL)
- {
- if (!strcmp(get_feature("x1-pin17"), "CIRAM A10") && !strcmp(get_feature("x1-pin31"), "NC"))
- m_pcb_id = TAITO_X1_005_A;
- }
-
- if (m_pcb_id == KONAMI_VRC2)
- {
- m_vrc_ls_prg_a = nes_cart_get_line(get_feature("vrc2-pin3"));
- m_vrc_ls_prg_b = nes_cart_get_line(get_feature("vrc2-pin4"));
- m_vrc_ls_chr = (nes_cart_get_line(get_feature("vrc2-pin21")) != 10) ? 1 : 0;
-// mame_printf_error("VRC-2, pin3: A%d, pin4: A%d, pin21: %s\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b, state->m_vrc_ls_chr ? "NC" : "A10");
- }
-
- if (m_pcb_id == KONAMI_VRC4)
- {
- m_vrc_ls_prg_a = nes_cart_get_line(get_feature("vrc4-pin3"));
- m_vrc_ls_prg_b = nes_cart_get_line(get_feature("vrc4-pin4"));
-// mame_printf_error("VRC-4, pin3: A%d, pin4: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b);
- }
-
- if (m_pcb_id == KONAMI_VRC6)
- {
- m_vrc_ls_prg_a = nes_cart_get_line(get_feature("vrc6-pin9"));
- m_vrc_ls_prg_b = nes_cart_get_line(get_feature("vrc6-pin10"));
-// mame_printf_error("VRC-6, pin9: A%d, pin10: A%d\n", state->m_vrc_ls_prg_a, state->m_vrc_ls_prg_b);
- }
-
- /* Check for other misc board variants */
- if (m_pcb_id == STD_SOROM)
- {
- if (get_feature("mmc1_type") != NULL && !strcmp(get_feature("mmc1_type"), "MMC1A"))
- m_pcb_id = STD_SOROM_A; // in MMC1-A PRG RAM is always enabled
- }
-
- if (m_pcb_id == STD_SXROM)
- {
- if (get_feature("mmc1_type") != NULL && !strcmp(get_feature("mmc1_type"), "MMC1A"))
- m_pcb_id = STD_SXROM_A; // in MMC1-A PRG RAM is always enabled
- }
-
- if (m_pcb_id == STD_NXROM || m_pcb_id == SUNSOFT_DCS)
- {
- if (get_software_region("minicart") != NULL) // check for dual minicart
- {
- m_pcb_id = SUNSOFT_DCS;
- // we shall load somewhere the minicart, but we still do not support this
- }
- }
-
- // SETUP step 4: logging what we have found
- logerror("Loaded game from softlist:\n");
- logerror("-- PCB: %s", get_feature("pcb"));
- if (m_pcb_id == UNSUPPORTED_BOARD)
- logerror(" (currently not supported by MESS)");
- logerror("\n-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000);
- logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000);
- logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000);
- logerror("-- PRG NVWRAM: %d\n", m_cart->get_battery_size());
- logerror("-- PRG WRAM: %d\n", m_cart->get_prgram_size());
-
- // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data!
- m_cart->prg_alloc(machine(), prg_size);
- memcpy(m_cart->get_prg_base(), get_software_region("prg"), prg_size);
- if (vrom_size)
- {
- m_cart->vrom_alloc(machine(), vrom_size);
- memcpy(m_cart->get_vrom_base(), get_software_region("chr"), vrom_size);
- }
- }
-
- // Allocate the remaining pointer, when needed
- if (vram_size)
- m_cart->vram_alloc(machine(), vram_size);
- if (prgram_size)
- m_cart->prgram_alloc(machine(), prgram_size);
- if (mapper_ram_size)
- m_cart->mapper_ram_alloc(machine(), mapper_ram_size);
-
- // Attempt to load a battery file for this ROM
- // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.)
- if (battery_size || mapper_bram_size)
- {
- UINT32 tot_size = battery_size + mapper_bram_size;
- UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size);
- battery_load(temp_nvram, tot_size, 0x00);
- if (battery_size)
- {
- m_cart->battery_alloc(machine(), battery_size);
- memcpy(m_cart->get_battery_base(), temp_nvram, battery_size);
- }
- if (mapper_bram_size)
- {
- m_cart->mapper_bram_alloc(machine(), mapper_bram_size);
- memcpy(m_cart->get_mapper_bram_base(), temp_nvram + battery_size, mapper_bram_size);
- }
-
- if (temp_nvram)
- auto_free(machine(), temp_nvram);
- }
+ call_load_pcb();
}
return IMAGE_INIT_PASS;
@@ -1114,14 +961,14 @@ void nes_cart_slot_device::call_unload()
{
if (m_cart)
{
- if (m_cart->get_battery_size() || m_cart->get_mapper_bram_size())
+ if (m_cart->get_battery_size() || m_cart->get_mapper_sram_size())
{
- UINT32 tot_size = m_cart->get_battery_size() + m_cart->get_mapper_bram_size();
+ UINT32 tot_size = m_cart->get_battery_size() + m_cart->get_mapper_sram_size();
UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size);
if (m_cart->get_battery_size())
memcpy(temp_nvram, m_cart->get_battery_base(), m_cart->get_battery_size());
- if (m_cart->get_mapper_bram_size())
- memcpy(temp_nvram + m_cart->get_battery_size(), m_cart->get_mapper_bram_base(), m_cart->get_mapper_bram_size());
+ if (m_cart->get_mapper_sram_size())
+ memcpy(temp_nvram + m_cart->get_battery_size(), m_cart->get_mapper_sram_base(), m_cart->get_mapper_sram_size());
battery_save(temp_nvram, tot_size);
if (temp_nvram)
@@ -1147,7 +994,27 @@ bool nes_cart_slot_device::call_softlist_load(char *swlist, char *swname, rom_en
const char * nes_cart_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
{
- return "rom";
+ if (open_image_file(options))
+ {
+ const char *slot_string = "nrom";
+ UINT32 len = core_fsize(m_file);
+ UINT8 *ROM = global_alloc_array(UINT8, len);
+
+ core_fread(m_file, ROM, len);
+
+ if ((ROM[0] == 'N') && (ROM[1] == 'E') && (ROM[2] == 'S'))
+ slot_string = get_default_card_ines(ROM, len);
+
+ if ((ROM[0] == 'U') && (ROM[1] == 'N') && (ROM[2] == 'I') && (ROM[3] == 'F'))
+ slot_string = get_default_card_unif(ROM, len);
+
+ global_free(ROM);
+ clear();
+
+ return slot_string;
+ }
+ else
+ return software_get_default_slot(config, options, this, "nrom");
}
@@ -1179,6 +1046,14 @@ READ8_MEMBER(nes_cart_slot_device::read_h)
return 0xff;
}
+READ8_MEMBER(nes_cart_slot_device::read_ex)
+{
+ if (m_cart)
+ return m_cart->read_ex(space, offset);
+ else
+ return 0xff;
+}
+
/*-------------------------------------------------
write
@@ -1202,31 +1077,23 @@ WRITE8_MEMBER(nes_cart_slot_device::write_h)
m_cart->write_h(space, offset, data);
}
-
-// CART DEVICE [TO BE MOVED TO SEPARATE SOURCE LATER]
-
-//-------------------------------------------------
-// nes_rom_device - constructor
-//-------------------------------------------------
-
-const device_type NES_ROM = &device_creator<nes_rom_device>;
-
-nes_rom_device::nes_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : device_t(mconfig, NES_ROM, "NES ROM", tag, owner, clock, "nes_rom", __FILE__),
- device_nes_cart_interface( mconfig, *this )
+WRITE8_MEMBER(nes_cart_slot_device::write_ex)
{
+ if (m_cart)
+ m_cart->write_ex(space, offset, data);
}
-nes_rom_device::nes_rom_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_t(mconfig, type, name, tag, owner, clock, shortname, source),
- device_nes_cart_interface( mconfig, *this )
-{
-}
//-------------------------------------------------
-// device_start - device-specific startup
+// partial hash function to be used by
+// device_image_partialhash_func
//-------------------------------------------------
-void nes_rom_device::device_start()
+void nes_partialhash(hash_collection &dest, const unsigned char *data,
+ unsigned long length, const char *functions)
{
+ if (length <= 16)
+ return;
+ dest.compute(&data[16], length - 16, functions);
}
+
diff --git a/src/mess/machine/nes_slot.h b/src/mess/machine/nes_slot.h
index bdc7ecb6ab5..3265fc38cc8 100644
--- a/src/mess/machine/nes_slot.h
+++ b/src/mess/machine/nes_slot.h
@@ -1,19 +1,153 @@
#ifndef __NES_SLOT_H__
#define __NES_SLOT_H__
-#include "includes/nes_mmc.h"
-
-
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
+// uncomment this for *very* verbose logging of most cart accesses
+//#define NES_PCB_DEBUG
+
+/* Boards */
+enum
+{
+ STD_NROM = 0,
+ STD_AXROM, STD_AMROM, STD_BXROM,
+ STD_CNROM, STD_CPROM,
+ STD_EXROM, STD_FXROM, STD_GXROM,
+ STD_HKROM, STD_PXROM,
+ STD_SXROM, STD_TXROM, STD_TXSROM,
+ STD_TKROM, STD_TQROM,
+ STD_UXROM, STD_UN1ROM, UXROM_CC,
+ HVC_FAMBASIC, NES_QJ, PAL_ZZ, STD_EVENT,
+ STD_SXROM_A, STD_SOROM, STD_SOROM_A,
+ /* Discrete components boards (by various manufacturer) */
+ DIS_74X161X138, DIS_74X139X74,
+ DIS_74X377, DIS_74X161X161X32,
+ /* Active Enterprises */
+ ACTENT_ACT52,
+ /* AGCI */
+ AGCI_50282,
+ /* AVE */
+ AVE_NINA01, AVE_NINA06, AVE_MAXI15,
+ /* Bandai */
+ BANDAI_FJUMP2, BANDAI_PT554,
+ BANDAI_DATACH, BANDAI_KARAOKE, BANDAI_OEKAKIDS,
+ BANDAI_FCG, BANDAI_LZ93, BANDAI_LZ93EX1, BANDAI_LZ93EX2,
+ /* Caltron */
+ CALTRON_6IN1,
+ /* Camerica */
+ CAMERICA_BF9093, CAMERICA_BF9096,
+ CAMERICA_GOLDENFIVE, GG_NROM,
+ /* Dreamtech */
+ DREAMTECH_BOARD,
+ /* Irem */
+ IREM_G101, IREM_H3001, IREM_LROG017,
+ IREM_TAM_S1, IREM_HOLYDIVR,
+ /* Jaleco */
+ JALECO_SS88006, JALECO_JF11, JALECO_JF13,
+ JALECO_JF16, JALECO_JF17, JALECO_JF17_ADPCM,
+ JALECO_JF19, JALECO_JF19_ADPCM, JALECO_JF23,
+ JALECO_JF24, JALECO_JF29, JALECO_JF33,
+ /* Konami */
+ KONAMI_VRC1, KONAMI_VRC2, KONAMI_VRC3,
+ KONAMI_VRC4, KONAMI_VRC6, KONAMI_VRC7,
+ /* Namcot */
+ NAMCOT_163, NAMCOT_175, NAMCOT_340,
+ NAMCOT_3425, NAMCOT_34X3, NAMCOT_3446,
+ /* NTDEC */
+ NTDEC_ASDER, NTDEC_FIGHTINGHERO,
+ /* Rex Soft */
+ REXSOFT_SL1632, REXSOFT_DBZ5,
+ /* Sachen */
+ SACHEN_8259A, SACHEN_8259B, SACHEN_8259C, SACHEN_8259D,
+ SACHEN_SA009, SACHEN_SA0036, SACHEN_SA0037,
+ SACHEN_SA72007, SACHEN_SA72008, SACHEN_TCA01,
+ SACHEN_TCU01, SACHEN_TCU02, SACHEN_SA9602B,
+ SACHEN_74LS374, SACHEN_74LS374_ALT, SACHEN_SHERO,
+ /* Sunsoft */
+ SUNSOFT_1, SUNSOFT_2, SUNSOFT_3, SUNSOFT_4,
+ SUNSOFT_DCS, SUNSOFT_5, SUNSOFT_FME7,
+ /* Taito */
+ TAITO_TC0190FMC, TAITO_TC0190FMCP,
+ TAITO_X1_005, TAITO_X1_017,
+ /* Tengen */
+ TENGEN_800008, TENGEN_800032, TENGEN_800037,
+ /* TXC */
+ TXC_22211, TXC_DUMARACING, TXC_MJBLOCK,
+ TXC_COMMANDOS, TXC_TW, TXC_STRIKEW,
+ /* Multigame Carts */
+ BMC_64IN1NR, BMC_190IN1, BMC_A65AS,
+ BMC_HIK8IN1, BMC_NOVEL1, BMC_NOVEL2, BMC_S24IN1SC03, BMC_T262,
+ BMC_WS, BMC_SUPERBIG_7IN1, BMC_SUPERHIK_4IN1, BMC_BALLGAMES_11IN1,
+ BMC_MARIOPARTY_7IN1, BMC_GOLD_7IN1, BMC_SUPER_700IN1, BMC_FAMILY_4646,
+ BMC_36IN1, BMC_21IN1, BMC_150IN1, BMC_35IN1, BMC_64IN1,
+ BMC_15IN1, BMC_SUPERHIK_300IN1, BMC_SUPERGUN_20IN1,
+ BMC_GOLDENCARD_6IN1, BMC_72IN1, BMC_SUPER_42IN1, BMC_76IN1,
+ BMC_31IN1, BMC_22GAMES, BMC_20IN1, BMC_110IN1,
+ BMC_70IN1, BMC_800IN1, BMC_1200IN1,
+ BMC_GKA, BMC_GKB, BMC_VT5201, BMC_BENSHIENG, BMC_810544,
+ BMC_NTD_03, BMC_G63IN1, BMC_FK23C, BMC_FK23CA, BMC_PJOY84,
+ BMC_POWERFUL_255, BMC_11160, BMC_G146, BMC_8157, BMC_830118C,
+ BMC_411120C, BMC_GOLD150, BMC_GOLD260, BMC_CH001, BMC_SUPER22,
+ BMC_12IN1, BMC_4IN1RESET, BMC_42IN1RESET,
+ /* Unlicensed */
+ UNL_8237, UNL_CC21, UNL_AX5705, UNL_KOF97, UNL_KS7057,
+ UNL_N625092, UNL_SC127, UNL_SMB2J, UNL_T230, UNL_MMALEE,
+ UNL_UXROM, UNL_MK2, UNL_XIAOZY, UNL_KOF96,
+ UNL_SF3, UNL_RACERMATE, UNL_EDU2K, UNL_LH32, UNL_LH10,
+ UNL_STUDYNGAME, UNL_603_5052, UNL_H2288, UNL_2708,
+ UNL_MALISB, UNL_BB, UNL_AC08, UNL_A9746, UNL_WORLDHERO,
+ UNL_43272, UNL_TF1201, UNL_CITYFIGHT,
+ /* Bootleg boards */
+ BTL_SMB2JA, BTL_MARIOBABY, BTL_AISENSHINICOL, BTL_TOBIDASE,
+ BTL_SMB2JB, BTL_SMB2JC, BTL_SMB3, BTL_SBROS11, BTL_DRAGONNINJA,
+ BTL_PIKACHUY2K, BTL_SHUIGUAN,
+ /* Misc: these are needed to convert mappers to boards, I will sort them later */
+ OPENCORP_DAOU306, HES_BOARD, SVISION16_BOARD, RUMBLESTATION_BOARD, JYCOMPANY_A, JYCOMPANY_B, JYCOMPANY_C,
+ MAGICSERIES_MD, KASING_BOARD, FUTUREMEDIA_BOARD, FUKUTAKE_BOARD, SOMARI_SL12,
+ HENGG_SRICH, HENGG_XHZS, HENGG_SHJY3, SUBOR_TYPE0, SUBOR_TYPE1,
+ KAISER_KS7058, KAISER_KS7032, KAISER_KS7022, KAISER_KS7017, KAISER_KS7012, KAISER_KS7013B, KAISER_KS202,
+ CNE_DECATHLON, CNE_FSB, CNE_SHLZ, CONY_BOARD, YOKO_BOARD,
+ RCM_GS2015, RCM_GS2004, RCM_GS2013, RCM_TF9IN1, RCM_3DBLOCK,
+ WAIXING_TYPE_A, WAIXING_TYPE_A1, WAIXING_TYPE_B, WAIXING_TYPE_C, WAIXING_TYPE_D,
+ WAIXING_TYPE_E, WAIXING_TYPE_F, WAIXING_TYPE_G, WAIXING_TYPE_H, WAIXING_TYPE_H1,
+ WAIXING_TYPE_I, WAIXING_TYPE_J, WAIXING_FS304,
+ WAIXING_SGZLZ, WAIXING_SGZ, WAIXING_WXZS, WAIXING_SECURITY, WAIXING_SH2,
+ WAIXING_DQ8, WAIXING_FFV, WAIXING_WXZS2, SUPERGAME_LIONKING, SUPERGAME_BOOGERMAN,
+ KAY_BOARD, HOSENKAN_BOARD, NITRA_TDA, GOUDER_37017, NANJING_BOARD,
+ WHIRLWIND_2706,
+ /* FFE boards, for mappers 6, 8, 17 */
+ FFE3_BOARD, FFE4_BOARD, FFE8_BOARD,
+ /* Unsupported (for place-holder boards, with no working emulation) & no-board (at init) */
+ UNSUPPORTED_BOARD, UNKNOWN_BOARD, NO_BOARD
+};
+
+
// ======================> nes_cart_interface
struct nes_cart_interface
{
};
+#define CHRROM 0
+#define CHRRAM 1
+
+
+#define CIRAM 0
+#define VROM 1
+#define EXRAM 2
+#define MMC5FILL 3
+#define CART_NTRAM 4
+
+
+#define PPU_MIRROR_NONE 0
+#define PPU_MIRROR_VERT 1
+#define PPU_MIRROR_HORZ 2
+#define PPU_MIRROR_HIGH 3
+#define PPU_MIRROR_LOW 4
+#define PPU_MIRROR_4SCREEN 5
+
// ======================> device_nes_cart_interface
@@ -25,67 +159,167 @@ public:
virtual ~device_nes_cart_interface();
// reading and writing
- virtual DECLARE_READ8_MEMBER(read_l) { return 0xff; }
- virtual DECLARE_READ8_MEMBER(read_m) { return 0xff; }
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_READ8_MEMBER(read_m);
virtual DECLARE_READ8_MEMBER(read_h) { return 0xff; }
- virtual DECLARE_WRITE8_MEMBER(write_l) { }
- virtual DECLARE_WRITE8_MEMBER(write_m) { }
- virtual DECLARE_WRITE8_MEMBER(write_h) { }
-
- virtual void prg_alloc(running_machine &machine, size_t size);
- virtual void prgram_alloc(running_machine &machine, size_t size);
- virtual void vrom_alloc(running_machine &machine, size_t size);
- virtual void vram_alloc(running_machine &machine, size_t size);
- virtual void battery_alloc(running_machine &machine, size_t size);
- virtual void mapper_ram_alloc(running_machine &machine, size_t size);
- virtual void mapper_bram_alloc(running_machine &machine, size_t size);
-
- virtual int get_mirroring() { return m_mirroring; }
- virtual void set_mirroring(int val) { m_mirroring = val; }
- virtual int get_four_screen_vram() { return m_four_screen_vram; }
- virtual void set_four_screen_vram(int val) { m_four_screen_vram = val; }
-
- virtual UINT8* get_prg_base() { return m_prg; }
- virtual UINT8* get_prgram_base() { return m_prgram; }
- virtual UINT8* get_vrom_base() { return m_vrom; }
- virtual UINT8* get_vram_base() { return m_vram; }
- virtual UINT8* get_battery_base() { return m_battery; }
- virtual UINT8* get_mapper_ram_base() { return m_mapper_ram; }
- virtual UINT8* get_mapper_bram_base() { return m_mapper_bram; }
-
- virtual UINT32 get_prg_size() { return m_prg_size; }
- virtual UINT32 get_prgram_size() { return m_prgram_size; }
- virtual UINT32 get_vrom_size() { return m_vrom_size; }
- virtual UINT32 get_vram_size() { return m_vram_size; }
- virtual UINT32 get_battery_size() { return m_battery_size; }
- virtual UINT32 get_mapper_ram_size() { return m_mapper_ram_size; }
- virtual UINT32 get_mapper_bram_size() { return m_mapper_bram_size; }
-
-//private:
+ virtual DECLARE_READ8_MEMBER(read_ex) { return 0xff; }
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual DECLARE_WRITE8_MEMBER(write_ex) { }
+
+ virtual DECLARE_READ8_MEMBER(chr_r);
+ virtual DECLARE_WRITE8_MEMBER(chr_w);
+ virtual DECLARE_READ8_MEMBER(nt_r);
+ virtual DECLARE_WRITE8_MEMBER(nt_w);
+
+ void prg_alloc(running_machine &machine, size_t size);
+ void prgram_alloc(running_machine &machine, size_t size);
+ void vrom_alloc(running_machine &machine, size_t size);
+ void vram_alloc(running_machine &machine, size_t size);
+ void battery_alloc(running_machine &machine, size_t size);
+
+ int get_mirroring() { return m_mirroring; }
+ void set_mirroring(int val) { m_mirroring = val; }
+ bool get_pcb_ctrl_mirror() { return m_pcb_ctrl_mirror; }
+ void set_pcb_ctrl_mirror(bool val) { m_pcb_ctrl_mirror = val; }
+ bool get_four_screen_vram() { return m_four_screen_vram; }
+ void set_four_screen_vram(bool val) { m_four_screen_vram = val; }
+ bool get_trainer() { return m_has_trainer; }
+ void set_trainer(bool val) { m_has_trainer = val; }
+
+ void set_ce(int mask, int state) { m_ce_mask = mask; m_ce_state = state; }
+ void set_vrc_lines(int PRG_A, int PRG_B, int CHR) { m_vrc_ls_prg_a = PRG_A; m_vrc_ls_prg_b = PRG_B; m_vrc_ls_chr = CHR; }
+ void set_x1_005_alt(bool val) { m_x1_005_alt_mirroring = val; }
+ void set_bus_conflict(bool val) { m_bus_conflict = val; }
+
+ UINT8* get_prg_base() { return m_prg; }
+ UINT8* get_prgram_base() { return m_prgram; }
+ UINT8* get_vrom_base() { return m_vrom; }
+ UINT8* get_vram_base() { return m_vram; }
+ UINT8* get_battery_base() { return m_battery; }
+ UINT8* get_mapper_sram_base() { return m_mapper_sram; }
+
+ UINT32 get_prg_size() { return m_prg_size; }
+ UINT32 get_prgram_size() { return m_prgram_size; }
+ UINT32 get_vrom_size() { return m_vrom_size; }
+ UINT32 get_vram_size() { return m_vram_size; }
+ UINT32 get_battery_size() { return m_battery_size; }
+ UINT32 get_mapper_sram_size() { return m_mapper_sram_size; }
+
+ virtual void ppu_latch(offs_t offset) {}
+ virtual void hblank_irq(int scanline, int vblank, int blanked) {}
+ virtual void scanline_irq(int scanline, int vblank, int blanked) {}
+
+ virtual void pcb_reset() {} // many pcb expect specific PRG/CHR banking at start
+ void pcb_start(running_machine &machine, UINT8 *ciram_ptr);
+ void pcb_reg_postload(running_machine &machine);
+ void nes_banks_restore();
+
+ UINT8 hi_access_rom(UINT32 offset); // helper ROM access for a bunch of PCB reading 0x8000-0xffff for protection too
+ UINT8 account_bus_conflict(UINT32 offset, UINT8 data);
+
+protected:
// internal state
- UINT8 *m_prg;
- UINT8 *m_prgram;
- UINT8 *m_vrom;
- UINT8 *m_vram;
- UINT8 *m_battery;
- UINT8 *m_mapper_ram;
- UINT8 *m_mapper_bram;
-
+ UINT8 *m_prg;
+ UINT8 *m_prgram;
+ UINT8 *m_vrom;
+ UINT8 *m_vram;
+ UINT8 *m_battery;
+ UINT8 *m_ciram;
+
UINT32 m_prg_size;
UINT32 m_prgram_size;
UINT32 m_vrom_size;
UINT32 m_vram_size;
UINT32 m_battery_size;
- UINT32 m_mapper_ram_size;
- UINT32 m_mapper_bram_size;
+
+ // these are specific of some boards but must be accessible from the driver
+ // E.g. additional save ram for HKROM, X1-005 & X1-017 boards, or ExRAM for MMC5
+ UINT8 *m_mapper_sram;
+ UINT8 *m_ext_ntram;
+ UINT32 m_mapper_sram_size;
+ UINT32 m_ext_ntram_size;
- int m_mirroring, m_four_screen_vram;
- bool m_has_battery, m_has_prgram;
+ int m_ce_mask;
+ int m_ce_state;
+ int m_vrc_ls_prg_a;
+ int m_vrc_ls_prg_b;
+ int m_vrc_ls_chr;
+
+ int m_mirroring;
+ bool m_pcb_ctrl_mirror, m_four_screen_vram, m_has_trainer;
+ bool m_x1_005_alt_mirroring; // temp hack for two kind of mirroring in Taito X1-005 boards (to be replaced with pin checking)
+ bool m_bus_conflict;
+
+ // PRG
+ inline int prg_8k_bank_num(int bank);
+ inline void update_prg_banks(int prg_bank_start, int prg_bank_end);
+ memory_bank *m_prg_bank_mem[4];
+ int m_prg_bank[4];
+ UINT32 m_prg_chunks;
+ UINT32 m_prg_mask;
+
+ // PRG helpers
+ void prg32(int bank);
+ void prg16_89ab(int bank);
+ void prg16_cdef(int bank);
+ void prg8_89(int bank);
+ void prg8_ab(int bank);
+ void prg8_cd(int bank);
+ void prg8_ef(int bank);
+ void prg8_x(int start, int bank);
+
+
+ // CHR
+ int m_chr_source; // global source for the 8 VROM banks
+ inline void chr_sanity_check(int source);
+
+ //these were previously called chr_map. they are a quick banking structure,
+ //because some of these change multiple times per scanline!
+ int m_chr_src[8]; //defines source of base pointer
+ int m_chr_orig[8]; //defines offset of 0x400 byte segment at base pointer
+ UINT8 *m_chr_access[8]; //source translated + origin -> valid pointer!
+
+ UINT32 m_vrom_chunks;
+ UINT32 m_vram_chunks;
+
+ // CHR helpers
+ void chr8(int bank, int source);
+ void chr4_x(int start, int bank, int source);
+ void chr4_0(int bank, int source){ chr4_x(0, bank, source); };
+ void chr4_4(int bank, int source){ chr4_x(4, bank, source); };
+ void chr2_x(int start, int bank, int source);
+ void chr2_0(int bank, int source) { chr2_x(0, bank, source); };
+ void chr2_2(int bank, int source) { chr2_x(2, bank, source); };
+ void chr2_4(int bank, int source) { chr2_x(4, bank, source); };
+ void chr2_6(int bank, int source) { chr2_x(6, bank, source); };
+ void chr1_x(int start, int bank, int source);
+ void chr1_0(int bank, int source) { chr1_x(0, bank, source); };
+ void chr1_1(int bank, int source) { chr1_x(1, bank, source); };
+ void chr1_2(int bank, int source) { chr1_x(2, bank, source); };
+ void chr1_3(int bank, int source) { chr1_x(3, bank, source); };
+ void chr1_4(int bank, int source) { chr1_x(4, bank, source); };
+ void chr1_5(int bank, int source) { chr1_x(5, bank, source); };
+ void chr1_6(int bank, int source) { chr1_x(6, bank, source); };
+ void chr1_7(int bank, int source) { chr1_x(7, bank, source); };
+
+
+ // NameTable & Mirroring
+ //these were previously called nt_page. they are a quick banking structure for a maximum of 4K of RAM/ROM/ExRAM
+ int m_nt_src[4];
+ int m_nt_orig[4];
+ int m_nt_writable[4];
+ UINT8 *m_nt_access[4]; //quick banking structure for a maximum of 4K of RAM/ROM/ExRAM
+
+ void set_nt_page(int page, int source, int bank, int writable);
+ void set_nt_mirroring(int mirroring);
+
+ UINT16 *m_prg_bank_map;
};
-extern void nes_partialhash(hash_collection &dest, const unsigned char *data, unsigned long length, const char *functions);
-
+void nes_partialhash(hash_collection &dest, const unsigned char *data, unsigned long length, const char *functions);
// ======================> nes_cart_slot_device
@@ -108,6 +342,10 @@ public:
virtual void call_unload();
virtual bool call_softlist_load(char *swlist, char *swname, rom_entry *start_entry);
+ void call_load_ines();
+ void call_load_unif();
+ void call_load_pcb();
+
virtual iodevice_t image_type() const { return IO_CARTSLOT; }
virtual bool is_readable() const { return 1; }
virtual bool is_writeable() const { return 0; }
@@ -121,32 +359,29 @@ public:
// slot interface overrides
virtual const char * get_default_card_software(const machine_config &config, emu_options &options);
+ const char * get_default_card_ines(UINT8 *ROM, UINT32 len);
+ const char * get_default_card_unif(UINT8 *ROM, UINT32 len);
+ const char * nes_get_slot(int pcb_id);
+ int nes_get_pcb_id(const char *slot);
// reading and writing
virtual DECLARE_READ8_MEMBER(read_l);
virtual DECLARE_READ8_MEMBER(read_m);
virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_READ8_MEMBER(read_ex);
virtual DECLARE_WRITE8_MEMBER(write_l);
virtual DECLARE_WRITE8_MEMBER(write_m);
virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual DECLARE_WRITE8_MEMBER(write_ex);
int get_pcb_id() { return m_pcb_id; };
+
+ void pcb_start(UINT8 *ciram_ptr);
+ void pcb_reset();
// temporarily here
- int m_chr_open_bus;
- int m_ce_mask;
- int m_ce_state;
- int m_vrc_ls_prg_a;
- int m_vrc_ls_prg_b;
- int m_vrc_ls_chr;
int m_crc_hack;
- int get_chr_open_bus() { return m_chr_open_bus; };
- int get_ce_mask() { return m_ce_mask; };
- int get_ce_state() { return m_ce_state; };
- int get_vrc_ls_prg_a() { return m_vrc_ls_prg_a; };
- int get_vrc_ls_prg_b() { return m_vrc_ls_prg_b; };
- int get_vrc_ls_chr() { return m_vrc_ls_chr; };
int get_crc_hack() { return m_crc_hack; };
void set_must_be_loaded(bool _must_be_loaded) { m_must_be_loaded = _must_be_loaded; }
@@ -174,37 +409,4 @@ extern const device_type NES_CART_SLOT;
#define MCFG_NES_CARTRIDGE_NOT_MANDATORY \
static_cast<nes_cart_slot_device *>(device)->set_must_be_loaded(FALSE);
-
-// CART DEVICE [TO BE MOVED TO SEPARATE SOURCE LATER]
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-// ======================> nes_rom_device
-
-class nes_rom_device : public device_t,
- public device_nes_cart_interface
-{
-public:
- // construction/destruction
- nes_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
- nes_rom_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);
-
- //protected:
- // device-level overrides
- virtual void device_start();
-
- // nescart_interface overrides
-// virtual DECLARE_READ8_MEMBER(read_l);
-// virtual DECLARE_READ8_MEMBER(read_m);
-// virtual DECLARE_READ8_MEMBER(read_h);
-// virtual DECLARE_WRITE8_MEMBER(write_l);
-// virtual DECLARE_WRITE8_MEMBER(write_m);
-// virtual DECLARE_WRITE8_MEMBER(write_h);
-};
-
-// device type definition
-extern const device_type NES_ROM;
-
#endif
diff --git a/src/mess/machine/nes_somari.c b/src/mess/machine/nes_somari.c
new file mode 100644
index 00000000000..0b234f521dd
--- /dev/null
+++ b/src/mess/machine/nes_somari.c
@@ -0,0 +1,375 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Somari Team PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the Somari Team PCBs [mapper 116]
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_somari.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_SOMARI = &device_creator<nes_somari_device>;
+
+
+nes_somari_device::nes_somari_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_SOMARI, "NES Cart Team Somari PCB", tag, owner, clock, "nes_somari", __FILE__)
+{
+}
+
+
+
+void nes_somari_device::device_start()
+{
+ common_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_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_latch));
+ save_item(NAME(m_mmc1_reg));
+
+ // VRC2
+ save_item(NAME(m_vrc_prg_bank));
+ save_item(NAME(m_vrc_vrom_bank));
+}
+
+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] = 0xfe;
+ m_mmc_prg_bank[3] = 0xff;
+ 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_alt_irq = 0;
+ m_irq_enable = 0;
+ m_irq_count = m_irq_count_latch = 0;
+ m_irq_clear = 0;
+
+ // MMC1 regs
+ m_count = 0;
+ m_mmc1_latch = 0;
+ m_mmc1_reg[0] = 0x0c;
+ m_mmc1_reg[1] = 0x00;
+ m_mmc1_reg[2] = 0x00;
+ 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();
+}
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ SOMERI TEAM
+
+ iNES: mapper 116
+
+
+ Emulation note about regs in MESS: 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_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
+
+ -------------------------------------------------*/
+
+// MMC1 Mode emulation
+void nes_somari_device::mmc1_set_prg()
+{
+ UINT8 prg_mode = m_mmc1_reg[0] & 0x0c;
+ UINT8 prg_offset = m_mmc1_reg[1] & 0x10;
+
+ switch (prg_mode)
+ {
+ 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;
+ }
+}
+
+void nes_somari_device::mmc1_set_chr()
+{
+ UINT8 chr_mode = BIT(m_mmc1_reg[0], 4);
+
+ if (chr_mode)
+ {
+ chr4_0(m_mmc1_reg[1] & 0x1f, m_chr_source);
+ chr4_4(m_mmc1_reg[2] & 0x1f, m_chr_source);
+ }
+ else
+ chr8((m_mmc1_reg[1] & 0x1f) >> 1, m_chr_source);
+}
+
+WRITE8_MEMBER(nes_somari_device::mmc1_w)
+{
+ assert(m_board_mode == 2);
+
+ if (data & 0x80)
+ {
+ m_count = 0;
+ m_mmc1_latch = 0;
+
+ m_mmc1_reg[0] |= 0x0c;
+ mmc1_set_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)
+ {
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ m_mmc1_reg[0] = m_mmc1_latch;
+ switch (m_mmc1_reg[0] & 0x03)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ }
+ mmc1_set_chr();
+ mmc1_set_prg();
+ break;
+ case 0x2000:
+ m_mmc1_reg[1] = m_mmc1_latch;
+ mmc1_set_chr();
+ mmc1_set_prg();
+ break;
+ case 0x4000:
+ m_mmc1_reg[2] = m_mmc1_latch;
+ mmc1_set_chr();
+ break;
+ case 0x6000:
+ m_mmc1_reg[3] = m_mmc1_latch;
+ mmc1_set_prg();
+ break;
+ }
+
+ m_count = 0;
+ }
+}
+
+// MMC3 Mode emulation
+WRITE8_MEMBER(nes_somari_device::mmc3_w)
+{
+ UINT8 mmc_helper, cmd;
+
+ assert(m_board_mode == 1);
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ mmc_helper = m_latch ^ data;
+ m_latch = data;
+
+ if (mmc_helper & 0x40)
+ set_prg(m_prg_base, m_prg_mask);
+
+ if (mmc_helper & 0x80)
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ 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;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ m_mmc_prg_bank[cmd - 6] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ }
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ 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; break;
+ case 0x6001: m_irq_enable = 1; break;
+ }
+}
+
+// VRC2 Mode emulation
+WRITE8_MEMBER(nes_somari_device::vrc2_w)
+{
+ UINT8 bank, shift;
+
+ assert(m_board_mode == 0);
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ m_vrc_prg_bank[0] = data;
+ prg8_89(m_vrc_prg_bank[0]);
+ break;
+
+ case 0x1000:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+
+ case 0x2000:
+ m_vrc_prg_bank[1] = data;
+ prg8_ab(m_vrc_prg_bank[1]);
+ break;
+
+ case 0x3000:
+ case 0x4000:
+ case 0x5000:
+ case 0x6000:
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + BIT(offset, 1);
+ shift = BIT(offset, 2) * 4;
+ data = (data & 0x0f) << shift;
+ m_vrc_vrom_bank[bank] = data | m_chr_base;
+ chr1_x(bank, m_vrc_vrom_bank[bank], CHRROM);
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_somari_device::write_h)
+{
+ LOG_MMC(("somari write_h, mode %d, offset: %04x, data: %02x\n", m_board_mode, offset, data));
+
+ switch (m_board_mode)
+ {
+ case 0x00: vrc2_w(space, offset, data, mem_mask); break;
+ case 0x01: mmc3_w(space, offset, data, mem_mask); break;
+ case 0x02: mmc1_w(space, offset, data, mem_mask); break;
+ }
+}
+
+void nes_somari_device::bank_update_switchmode()
+{
+ switch (m_board_mode)
+ {
+ case 0x00:
+ prg8_89(m_vrc_prg_bank[0]);
+ prg8_ab(m_vrc_prg_bank[1]);
+ for (int i = 0; i < 8; i++)
+ chr1_x(i, m_vrc_vrom_bank[i], CHRROM);
+ break;
+ case 0x01:
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 0x02:
+ mmc1_set_prg();
+ mmc1_set_chr();
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_somari_device::write_l)
+{
+ LOG_MMC(("somari write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset & 0x100)
+ {
+ m_board_mode = data & 0x03;
+ m_chr_base = ((m_board_mode & 0x04) << 6);
+ if (m_board_mode != 1)
+ m_irq_enable = 0;
+ bank_update_switchmode();
+ }
+}
diff --git a/src/mess/machine/nes_somari.h b/src/mess/machine/nes_somari.h
new file mode 100644
index 00000000000..2f201de9b9e
--- /dev/null
+++ b/src/mess/machine/nes_somari.h
@@ -0,0 +1,48 @@
+#ifndef __NES_SOMARI_H
+#define __NES_SOMARI_H
+
+#include "machine/nes_mmc3.h"
+
+
+// ======================> nes_somari_device
+
+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 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(mmc1_w);
+ virtual DECLARE_WRITE8_MEMBER(mmc3_w);
+ virtual DECLARE_WRITE8_MEMBER(vrc2_w);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+private:
+ void mmc1_set_prg();
+ void mmc1_set_chr();
+ void bank_update_switchmode();
+
+ UINT8 m_board_mode;
+
+ // MMC3 - inherited from txrom
+
+ // MMC1
+ UINT8 m_count;
+ UINT8 m_mmc1_latch;
+ UINT8 m_mmc1_reg[4];
+
+ // VRC2
+ UINT8 m_vrc_prg_bank[2];
+ UINT8 m_vrc_vrom_bank[8];
+};
+
+
+
+// device type definition
+extern const device_type NES_SOMARI;
+
+#endif
diff --git a/src/mess/machine/nes_sunsoft.c b/src/mess/machine/nes_sunsoft.c
new file mode 100644
index 00000000000..913da4a0643
--- /dev/null
+++ b/src/mess/machine/nes_sunsoft.c
@@ -0,0 +1,635 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Sunsoft PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Sunsoft-1 [mapper 184]
+ * Sunsoft-2 [mapper 89 & 93]
+ * Sunsoft-3 [mapper 67]
+ * Sunsoft-4 [mapper 68]
+ * Sunsoft FME7 & Sunsoft-5A [mapper 69]
+ * Sunsoft-5B [mapper 69]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_sunsoft.h"
+
+#include "cpu/m6502/m6502.h"
+#include "sound/ay8910.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_SUNSOFT_1 = &device_creator<nes_sunsoft_1_device>;
+const device_type NES_SUNSOFT_2 = &device_creator<nes_sunsoft_2_device>;
+const device_type NES_SUNSOFT_3 = &device_creator<nes_sunsoft_3_device>;
+const device_type NES_SUNSOFT_4 = &device_creator<nes_sunsoft_4_device>;
+const device_type NES_SUNSOFT_FME7 = &device_creator<nes_sunsoft_fme7_device>;
+const device_type NES_SUNSOFT_5 = &device_creator<nes_sunsoft_5_device>;
+
+
+nes_sunsoft_1_device::nes_sunsoft_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SUNSOFT_1, "NES Cart Sunsoft 1 PCB", tag, owner, clock, "nes_sun1", __FILE__)
+{
+}
+
+nes_sunsoft_2_device::nes_sunsoft_2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SUNSOFT_2, "NES Cart Sunsoft 2 PCB", tag, owner, clock, "nes_sun2", __FILE__)
+{
+}
+
+nes_sunsoft_3_device::nes_sunsoft_3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SUNSOFT_3, "NES Cart Sunsoft 3 PCB", tag, owner, clock, "nes_sun3", __FILE__)
+{
+}
+
+nes_sunsoft_4_device::nes_sunsoft_4_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_sunsoft_4_device::nes_sunsoft_4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SUNSOFT_4, "NES Cart Sunsoft 4 PCB", tag, owner, clock, "nes_sun4", __FILE__)
+{
+}
+
+nes_sunsoft_fme7_device::nes_sunsoft_fme7_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_sunsoft_fme7_device::nes_sunsoft_fme7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_SUNSOFT_4, "NES Cart Sunsoft FME7 PCB", tag, owner, clock, "nes_fme7", __FILE__)
+{
+}
+
+nes_sunsoft_5_device::nes_sunsoft_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sunsoft_fme7_device(mconfig, NES_SUNSOFT_5, "NES Cart Sunsoft 5A/5B PCB", tag, owner, clock, "nes_sun5", __FILE__),
+ m_ym2149(*this, "ay")
+{
+}
+
+
+void nes_sunsoft_1_device::device_start()
+{
+ common_start();
+}
+
+void nes_sunsoft_1_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_sunsoft_2_device::device_start()
+{
+ common_start();
+}
+
+void nes_sunsoft_2_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ if (m_pcb_ctrl_mirror)
+ set_nt_mirroring(PPU_MIRROR_LOW);
+}
+
+void nes_sunsoft_3_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_toggle));
+ save_item(NAME(m_irq_count));
+}
+
+void nes_sunsoft_3_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ m_irq_toggle = 0;
+ m_irq_count = 0;
+ m_irq_enable = 0;
+}
+
+void nes_sunsoft_4_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_wram_enable));
+}
+
+void nes_sunsoft_4_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_reg = 0;
+ m_latch1 = 0;
+ m_latch2 = 0;
+ m_wram_enable = 0;
+}
+
+void nes_sunsoft_fme7_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_wram_bank));
+ save_item(NAME(m_latch));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+}
+
+void nes_sunsoft_fme7_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_wram_bank = 0;
+
+ m_latch = 0;
+ m_irq_enable = 0;
+ m_irq_count = 0;
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Sunsoft-1 board emulation
+
+ Games: Atlantis no Nazo, Kanshakudama Nage Kantarou no
+ Toukaidou Gojuusan Tsugi, Wing of Madoola, Fantasy Zone
+
+ iNES: mapper 184 (Fantasy Zone uses this board with no
+ CHRROM, and the register switches PRG banks)
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sunsoft_1_device::write_m)
+{
+ LOG_MMC(("Sunsoft 1 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_vrom_chunks)
+ {
+ chr4_0(data & 0x0f, CHRROM);
+ chr4_4(data >> 4, CHRROM);
+ }
+ else
+ prg16_89ab(data & 0x0f);
+}
+
+/*-------------------------------------------------
+
+ Sunsoft-2 board emulation
+
+ The two games using this board have incompatible mirroring
+ wiring, making necessary two distinct mappers
+
+ iNES: mapper 89 & 93
+
+ -------------------------------------------------*/
+
+// there are two 'variants' depending on hardwired or mapper ctrl mirroring
+
+WRITE8_MEMBER(nes_sunsoft_2_device::write_h)
+{
+ UINT8 helper = (data & 0x07) | ((data & 0x80) ? 0x08 : 0x00);
+ LOG_MMC(("Sunsoft 2 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ if (m_pcb_ctrl_mirror)
+ set_nt_mirroring(BIT(data, 3) ? PPU_MIRROR_HIGH : PPU_MIRROR_LOW);
+
+ if (m_vrom_chunks)
+ chr8(helper, CHRROM);
+
+ prg16_89ab(data >> 4);
+}
+
+/*-------------------------------------------------
+
+ Sunsoft-3 board emulation
+
+ The two games using this board have incompatible mirroring
+ wiring, making necessary two distinct mappers & pcb_id
+
+ iNES: mapper 67
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+void nes_sunsoft_3_device::hblank_irq( int scanline, int vblank, int blanked )
+{
+ /* TODO: change to reflect the actual number of cycles spent: both using 114 or cycling 114,114,113
+ produces a 1-line glitch in Fantasy Zone 2: it really requires the counter to be updated each CPU cycle! */
+ if (m_irq_enable)
+ {
+ if (m_irq_count <= 114)
+ {
+ m_irq_enable = 0;
+ m_irq_count = 0xffff;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ m_irq_count -= 114;
+ }
+}
+
+WRITE8_MEMBER(nes_sunsoft_3_device::write_h)
+{
+ LOG_MMC(("Sunsoft 3 write_h, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7800)
+ {
+ case 0x0800:
+ chr2_0(data, CHRROM);
+ break;
+ case 0x1800:
+ chr2_2(data, CHRROM);
+ break;
+ case 0x2800:
+ chr2_4(data, CHRROM);
+ break;
+ case 0x3800:
+ chr2_6(data, CHRROM);
+ break;
+ case 0x4000:
+ case 0x4800:
+ m_irq_toggle ^= 1;
+ if (m_irq_toggle)
+ m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
+ else
+ m_irq_count = (m_irq_count & 0xff00) | data;
+ break;
+ case 0x5800:
+ m_irq_enable = BIT(data, 4);
+ m_irq_toggle = 0;
+ break;
+ case 0x6800:
+ switch (data & 3)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x7800:
+ prg16_89ab(data);
+ break;
+ default:
+ LOG_MMC(("Sunsoft 3 write_h uncaught write, offset: %04x, data: %02x\n", offset, data));
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Sunsoft-4 board emulation
+
+ Games: AfterBurner & Maharaja
+
+ iNES: mapper 68
+
+ -------------------------------------------------*/
+
+void nes_sunsoft_4_device::sun4_mirror( int mirror, int mirr0, int mirr1 )
+{
+ switch (mirror)
+ {
+ case 0x00:
+ set_nt_mirroring(PPU_MIRROR_VERT);
+ break;
+ case 0x01:
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ break;
+ case 0x02:
+ set_nt_mirroring(PPU_MIRROR_LOW);
+ break;
+ case 0x03:
+ set_nt_mirroring(PPU_MIRROR_HIGH);
+ break;
+ case 0x10:
+ set_nt_page(0, VROM, mirr0 | 0x80, 0);
+ set_nt_page(1, VROM, mirr1 | 0x80, 0);
+ set_nt_page(2, VROM, mirr0 | 0x80, 0);
+ set_nt_page(3, VROM, mirr1 | 0x80, 0);
+ break;
+ case 0x11:
+ set_nt_page(0, VROM, mirr0 | 0x80, 0);
+ set_nt_page(1, VROM, mirr0 | 0x80, 0);
+ set_nt_page(2, VROM, mirr1 | 0x80, 0);
+ set_nt_page(3, VROM, mirr1 | 0x80, 0);
+ break;
+ case 0x12:
+ set_nt_page(0, VROM, mirr0 | 0x80, 0);
+ set_nt_page(1, VROM, mirr0 | 0x80, 0);
+ set_nt_page(2, VROM, mirr0 | 0x80, 0);
+ set_nt_page(3, VROM, mirr0 | 0x80, 0);
+ break;
+ case 0x13:
+ set_nt_page(0, VROM, mirr1 | 0x80, 0);
+ set_nt_page(1, VROM, mirr1 | 0x80, 0);
+ set_nt_page(2, VROM, mirr1 | 0x80, 0);
+ set_nt_page(3, VROM, mirr1 | 0x80, 0);
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_sunsoft_4_device::sun4_write)
+{
+ LOG_MMC(("Sunsoft 4 write_h, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ chr2_0(data, CHRROM);
+ break;
+ case 0x1000:
+ chr2_2(data, CHRROM);
+ break;
+ case 0x2000:
+ chr2_4(data, CHRROM);
+ break;
+ case 0x3000:
+ chr2_6(data, CHRROM);
+ break;
+ case 0x4000:
+ m_latch1 = data & 0x7f;
+ sun4_mirror(m_reg, m_latch1, m_latch2);
+ break;
+ case 0x5000:
+ m_latch2 = data & 0x7f;
+ sun4_mirror(m_reg, m_latch1, m_latch2);
+ break;
+ case 0x6000:
+ m_reg = data & 0x13;
+ sun4_mirror(m_reg, m_latch1, m_latch2);
+ break;
+ case 0x7000:
+ prg16_89ab(data & 0x0f);
+ m_wram_enable = BIT(data, 4);
+ break;
+ default:
+ LOG_MMC(("Sunsoft 4 write_h uncaught write, offset: %04x, data: %02x\n", offset, data));
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_sunsoft_4_device::write_m)
+{
+ LOG_MMC(("Sunsoft 4 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_battery && m_wram_enable)
+ m_battery[offset & (m_battery_size - 1)] = data;
+ if (m_prgram && m_wram_enable)
+ m_prgram[offset & (m_prgram_size - 1)] = data;
+}
+
+READ8_MEMBER(nes_sunsoft_4_device::read_m)
+{
+ LOG_MMC(("Sunsoft 4 read_m, offset: %04x\n", offset));
+
+ if (m_battery && m_wram_enable)
+ return m_battery[offset & (m_battery_size - 1)];
+ if (m_prgram && m_wram_enable)
+ return m_prgram[offset & (m_prgram_size - 1)];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+/*-------------------------------------------------
+
+ JxROM & Sunsoft 5A / 5B / FME7 board emulation
+
+ Notice that Sunsoft-5B = FME7 + sound chip (the latter being
+ currently unemulated in MESS)
+
+ iNES: mapper 69
+
+ -------------------------------------------------*/
+
+/* Here, IRQ counter decrements every CPU cycle. Since we update it every scanline,
+ we need to decrement it by 114 (Each scanline consists of 341 dots and, on NTSC,
+ there are 3 dots to every 1 CPU cycle, hence 114 is the number of cycles per scanline ) */
+void nes_sunsoft_fme7_device::hblank_irq( int scanline, int vblank, int blanked )
+{
+ /* TODO: change to reflect the actual number of cycles spent */
+ if ((m_irq_enable & 0x80) && (m_irq_enable & 0x01))
+ {
+ if (m_irq_count <= 114)
+ {
+ m_irq_count = 0xffff;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ else
+ m_irq_count -= 114;
+ }
+ else if (m_irq_enable & 0x01) // if enable bit 7 is not set, only decrement the counter!
+ {
+ if (m_irq_count <= 114)
+ m_irq_count = 0xffff;
+ else
+ m_irq_count -= 114;
+ }
+}
+
+WRITE8_MEMBER(nes_sunsoft_fme7_device::fme7_write)
+{
+ LOG_MMC(("fme7_write, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6000)
+ {
+ case 0x0000:
+ m_latch = data & 0x0f;
+ break;
+
+ case 0x2000:
+ switch (m_latch)
+ {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ chr1_x(m_latch, data, CHRROM);
+ break;
+
+ case 8:
+ m_wram_bank = data;
+ break;
+ case 9:
+ prg8_89(data);
+ break;
+ case 0x0a:
+ prg8_ab(data);
+ break;
+ case 0x0b:
+ prg8_cd(data);
+ break;
+ case 0x0c:
+ switch (data & 0x03)
+ {
+ case 0x00: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 0x01: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 0x02: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 0x03: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+ break;
+ case 0x0d:
+ m_irq_enable = data;
+ break;
+ case 0x0e:
+ m_irq_count = (m_irq_count & 0xff00) | data;
+ break;
+ case 0x0f:
+ m_irq_count = (m_irq_count & 0x00ff) | (data << 8);
+ break;
+ }
+ break;
+
+ default:
+ logerror("Sunsoft FME7 write_h uncaught %04x value: %02x\n", offset + 0x8000, data);
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_sunsoft_fme7_device::write_m)
+{
+ UINT8 bank = m_wram_bank & 0x3f;
+ LOG_MMC(("Sunsoft FME7 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (!(m_wram_bank & 0x40)) // is PRG ROM, no write
+ return;
+ else if (m_wram_bank & 0x80) // is PRG RAM
+ {
+ if (m_battery)
+ m_battery[((bank * 0x2000) + offset) & (m_battery_size - 1)] = data;
+ if (m_prgram)
+ m_prgram[((bank * 0x2000) + offset) & (m_prgram_size - 1)] = data;
+ }
+}
+
+READ8_MEMBER(nes_sunsoft_fme7_device::read_m)
+{
+ UINT8 bank = m_wram_bank & 0x3f;
+ LOG_MMC(("Sunsoft FME7 read_m, offset: %04x\n", offset));
+
+ if (!(m_wram_bank & 0x40)) // is PRG ROM
+ return m_prg[((bank * 0x2000) + offset) & (m_prg_size - 1)];
+ else if (m_wram_bank & 0x80) // is PRG RAM
+ {
+ if (m_battery)
+ return m_battery[((bank * 0x2000) + offset) & (m_battery_size - 1)];
+ if (m_prgram)
+ return m_prgram[((bank * 0x2000) + offset) & (m_prgram_size - 1)];
+ }
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+
+/*-------------------------------------------------
+
+ Sunsoft 5B board emulation (FME7 + Sound)
+
+ Games: Gimmick!
+
+ iNES: mapper 69
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sunsoft_5_device::write_h)
+{
+ LOG_MMC(("sunsoft 5 write_h, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6000)
+ {
+ case 0x4000:
+ ay8910_address_w(m_ym2149, space, 0, data & 0x0f);
+ break;
+ case 0x6000:
+ ay8910_data_w(m_ym2149, space, 0, data);
+ break;
+ default:
+ fme7_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+static const ay8910_interface ay8910_config =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( sun_5b )
+//-------------------------------------------------
+
+// From NESdev wiki: The 5B's audio is driven by the CPU clock (1.78977267 MHz),
+// but like the NES's APU, the YM2149F has an optional clock divider which
+// halves the internal clock speed. By comparison of the produced pitches
+// in Gimmick! with the register values used, it appears that the 5B is a
+// YM2149F operating in this mode. To use an AY-3-8910 as a substitute,
+// you would need an external divider to reduce the clock speed by half.
+
+#define SUN5_NTSC_CLOCK (21477272.724 / 12)
+
+static MACHINE_CONFIG_FRAGMENT( sun_5b )
+
+ // additional sound hardware
+ MCFG_SPEAKER_STANDARD_MONO("addon")
+
+ MCFG_SOUND_ADD("ay", YM2149, SUN5_NTSC_CLOCK/2) // divide by 2 for the internal divider
+ MCFG_SOUND_CONFIG(ay8910_config)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nes_sunsoft_5_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( sun_5b );
+}
diff --git a/src/mess/machine/nes_sunsoft.h b/src/mess/machine/nes_sunsoft.h
new file mode 100644
index 00000000000..ef506232344
--- /dev/null
+++ b/src/mess/machine/nes_sunsoft.h
@@ -0,0 +1,140 @@
+#ifndef __NES_SUNSOFT_H
+#define __NES_SUNSOFT_H
+
+#include "machine/nes_nxrom.h"
+#include "sound/ay8910.h"
+
+
+// ======================> nes_sunsoft_1_device
+
+class nes_sunsoft_1_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sunsoft_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sunsoft_2_device
+
+class nes_sunsoft_2_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sunsoft_2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_sunsoft_3_device
+
+class nes_sunsoft_3_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sunsoft_3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+
+ UINT16 m_irq_count;
+ int m_irq_enable, m_irq_toggle;
+};
+
+
+// ======================> nes_sunsoft_4_device
+
+class nes_sunsoft_4_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sunsoft_4_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);
+ nes_sunsoft_4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(sun4_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { sun4_write(space, offset, data, mem_mask); }
+
+ virtual void pcb_reset();
+
+protected:
+ void sun4_mirror(int mirror, int mirr0, int mirr1);
+ int m_reg, m_latch1, m_latch2, m_wram_enable;
+};
+
+// ======================> nes_sunsoft_fme7_device
+
+class nes_sunsoft_fme7_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_sunsoft_fme7_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);
+ nes_sunsoft_fme7_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(fme7_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { fme7_write(space, offset, data, mem_mask); }
+
+ virtual void hblank_irq( int scanline, int vblank, int blanked );
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+ UINT16 m_irq_count;
+ int m_irq_enable;
+
+ UINT8 m_wram_bank;
+};
+
+
+// ======================> nes_sunsoft_5_device
+
+class nes_sunsoft_5_device : public nes_sunsoft_fme7_device
+{
+public:
+ // construction/destruction
+ nes_sunsoft_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+private:
+ required_device<ay8910_device> m_ym2149;
+};
+
+
+
+
+// device type definition
+extern const device_type NES_SUNSOFT_1;
+extern const device_type NES_SUNSOFT_2;
+extern const device_type NES_SUNSOFT_3;
+extern const device_type NES_SUNSOFT_4;
+extern const device_type NES_SUNSOFT_FME7;
+extern const device_type NES_SUNSOFT_5;
+
+#endif
diff --git a/src/mess/machine/nes_sunsoft_dcs.c b/src/mess/machine/nes_sunsoft_dcs.c
new file mode 100644
index 00000000000..f38daac472d
--- /dev/null
+++ b/src/mess/machine/nes_sunsoft_dcs.c
@@ -0,0 +1,302 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Sunsoft DCS PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the Sunsoft Dual Cassette System (DCS) PCB used by Nantettate!! Baseball + subslot
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_sunsoft_dcs.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// sub-cart device
+//-------------------------------------------------
+
+ntb_cart_interface::ntb_cart_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device),
+ m_rom(NULL),
+ m_rom_size(0)
+{
+}
+
+ntb_cart_interface::~ntb_cart_interface()
+{
+}
+
+//-------------------------------------------------
+// sub-cart slot device
+//-------------------------------------------------
+
+const device_type NES_NTB_SLOT = &device_creator<nes_ntb_slot_device>;
+
+nes_ntb_slot_device::nes_ntb_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, NES_NTB_SLOT, "NES NTB Cartridge Slot", tag, owner, clock),
+ device_image_interface(mconfig, *this),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+nes_ntb_slot_device::~nes_ntb_slot_device()
+{
+}
+
+
+void nes_ntb_slot_device::device_start()
+{
+ m_cart = dynamic_cast<ntb_cart_interface *>(get_card_device());
+}
+
+READ8_MEMBER(nes_ntb_slot_device::read)
+{
+ if (m_cart)
+ return m_cart->read(space, offset, mem_mask);
+
+ return 0xff;
+}
+
+
+bool nes_ntb_slot_device::call_load()
+{
+ if (m_cart)
+ {
+ UINT8 *ROM = m_cart->get_cart_base();
+
+ if (!ROM)
+ return IMAGE_INIT_FAIL;
+
+ if (software_entry() == NULL)
+ {
+ if (length() != 0x8000)
+ return IMAGE_INIT_FAIL;
+
+ fread(&ROM, 0x8000);
+ }
+ else
+ {
+ if (get_software_region_length("rom") != 0x8000)
+ return IMAGE_INIT_FAIL;
+
+ memcpy(ROM, get_software_region("rom"), 0x8000);
+ }
+ }
+
+ return IMAGE_INIT_PASS;
+}
+
+
+bool nes_ntb_slot_device::call_softlist_load(char *swlist, char *swname, rom_entry *start_entry)
+{
+ load_software_part_region(this, swlist, swname, start_entry );
+ return TRUE;
+}
+
+const char * nes_ntb_slot_device::get_default_card_software(const machine_config &config, emu_options &options)
+{
+ return software_get_default_slot(config, options, this, "ntbrom");
+}
+
+//-------------------------------------------------
+// NTB ROM device
+//-------------------------------------------------
+
+ROM_START( ntb_rom )
+ ROM_REGION(0x8000, "ntbrom", ROMREGION_ERASEFF)
+ROM_END
+
+const device_type NES_NTB_ROM = &device_creator<nes_ntb_rom_device>;
+
+nes_ntb_rom_device::nes_ntb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, NES_NTB_ROM, "NES NTB ROM", tag, owner, clock, "nes_ntbrom", __FILE__),
+ ntb_cart_interface( mconfig, *this )
+{
+}
+
+void nes_ntb_rom_device::device_start()
+{
+ m_rom = (UINT8*)memregion("ntbrom")->base();
+}
+
+const rom_entry *nes_ntb_rom_device::device_rom_region() const
+{
+ return ROM_NAME( ntb_rom );
+}
+
+UINT8 *nes_ntb_rom_device::get_cart_base()
+{
+ return m_rom;
+}
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_SUNSOFT_DCS = &device_creator<nes_sunsoft_dcs_device>;
+
+
+nes_sunsoft_dcs_device::nes_sunsoft_dcs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_sunsoft_4_device(mconfig, NES_SUNSOFT_DCS, "NES Cart Sunsoft DCS PCB", tag, owner, clock, "nes_dcs", __FILE__),
+ m_subslot(*this, "ntb_slot")
+{
+}
+
+
+void nes_sunsoft_dcs_device::device_start()
+{
+ common_start();
+ ntb_enable_timer = timer_alloc(TIMER_PROTECT);
+ ntb_enable_timer->reset();
+
+ save_item(NAME(m_latch1));
+ save_item(NAME(m_latch2));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_wram_enable));
+ save_item(NAME(m_exrom_enable));
+ save_item(NAME(m_timer_on));
+}
+
+void nes_sunsoft_dcs_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_reg = 0;
+ m_latch1 = 0;
+ m_latch2 = 0;
+ m_wram_enable = 0;
+ m_exrom_enable = 0;
+ m_timer_on = 0;
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Sunsoft-DCS board emulation
+
+ Games: Nantettatte!! Baseball
+
+ This board feature a subslot to load minicart containing
+ updated data?
+
+ iNES: mapper 68
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_sunsoft_dcs_device::write_h)
+{
+ LOG_MMC(("Sunsoft DCS write_h, offset %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x7000:
+ prg16_89ab(data & 0x07);
+ m_exrom_enable = !BIT(data, 3);
+ m_wram_enable = BIT(data, 4);
+ break;
+ default:
+ sun4_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+READ8_MEMBER(nes_sunsoft_dcs_device::read_h)
+{
+ LOG_MMC(("Sunsoft DCS read_h, offset: %04x\n", offset));
+
+ if (m_exrom_enable && m_subslot->m_cart && offset < 0x4000)
+ {
+ if (m_timer_on)
+ return m_subslot->m_cart->read(space, offset, mem_mask);
+ else
+ return ((offset + 0x8000) & 0xff00) >> 8; // after the timer is off, this returns open bus...
+ }
+ else
+ return hi_access_rom(offset);
+}
+
+WRITE8_MEMBER(nes_sunsoft_dcs_device::write_m)
+{
+ LOG_MMC(("Sunsoft DCS write_m, offset: %04x, data: %02x\n", offset, data));
+
+ if (m_battery && m_wram_enable)
+ m_battery[offset & (m_battery_size - 1)] = data;
+ if (m_prgram && m_wram_enable)
+ m_prgram[offset & (m_prgram_size - 1)] = data;
+ if (!m_wram_enable && !m_timer_on)
+ {
+ m_timer_on = 1;
+ // start NTB-ROM timer
+ ntb_enable_timer->adjust(machine().device<cpu_device>("maincpu")->cycles_to_attotime(107520));
+ }
+}
+
+READ8_MEMBER(nes_sunsoft_dcs_device::read_m)
+{
+ LOG_MMC(("Sunsoft DCS read_m, offset: %04x\n", offset));
+
+ if (m_battery && m_wram_enable)
+ return m_battery[offset & (m_battery_size - 1)];
+ if (m_prgram && m_wram_enable)
+ return m_prgram[offset & (m_prgram_size - 1)];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+//-------------------------------------------------
+// MACHINE_CONFIG_FRAGMENT( sub_slot )
+//-------------------------------------------------
+
+static SLOT_INTERFACE_START(ntb_cart)
+ SLOT_INTERFACE("ntbrom", NES_NTB_ROM)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( sub_slot )
+ MCFG_NTB_MINICART_ADD("ntb_slot", ntb_cart)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor nes_sunsoft_dcs_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( sub_slot );
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+void nes_sunsoft_dcs_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_PROTECT)
+ {
+ m_timer_on = 0;
+ ntb_enable_timer->reset();
+ }
+}
diff --git a/src/mess/machine/nes_sunsoft_dcs.h b/src/mess/machine/nes_sunsoft_dcs.h
new file mode 100644
index 00000000000..c3e20ea92b5
--- /dev/null
+++ b/src/mess/machine/nes_sunsoft_dcs.h
@@ -0,0 +1,136 @@
+#ifndef __NES_SUNSOFT_DCS_H
+#define __NES_SUNSOFT_DCS_H
+
+#include "machine/nes_sunsoft.h"
+
+
+// ======================> ntb_cart_interface
+
+class ntb_cart_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ ntb_cart_interface(const machine_config &mconfig, device_t &device);
+ virtual ~ntb_cart_interface();
+
+ // reading and writing
+ virtual DECLARE_READ8_MEMBER(read) { return m_rom[offset & (m_rom_size - 1)]; }
+
+ UINT8 *get_cart_base() { return m_rom; }
+
+protected:
+ // internal state
+ UINT8 *m_rom;
+ UINT32 m_rom_size;
+};
+
+// ======================> nes_ntb_slot_device
+
+class nes_ntb_slot_device : public device_t,
+ public device_image_interface,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ nes_ntb_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~nes_ntb_slot_device();
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete() { update_names(); }
+
+ // image-level overrides
+ virtual bool call_load();
+ virtual bool call_softlist_load(char *swlist, char *swname, rom_entry *start_entry);
+
+ virtual iodevice_t image_type() const { return IO_CARTSLOT; }
+ virtual bool is_readable() const { return 1; }
+ virtual bool is_writeable() const { return 0; }
+ virtual bool is_creatable() const { return 0; }
+ virtual bool must_be_loaded() const { return 0; }
+ virtual bool is_reset_on_load() const { return 1; }
+ virtual const char *image_interface() const { return "ntb_cart"; }
+ virtual const char *file_extensions() const { return "bin"; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+
+ // slot interface overrides
+ virtual const char * get_default_card_software(const machine_config &config, emu_options &options);
+
+ virtual DECLARE_READ8_MEMBER(read);
+
+ ntb_cart_interface* m_cart;
+};
+
+// device type definition
+extern const device_type NES_NTB_SLOT;
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+ ***************************************************************************/
+
+#define MCFG_NTB_MINICART_ADD(_tag, _slot_intf) \
+ MCFG_DEVICE_ADD(_tag, NES_NTB_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, NULL, NULL, false)
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> nes_ntb_rom_device
+
+class nes_ntb_rom_device : public device_t,
+ public ntb_cart_interface
+{
+public:
+ // construction/destruction
+ nes_ntb_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual UINT8* get_cart_base();
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+};
+
+// device type definition
+extern const device_type NES_NTB_ROM;
+
+
+
+// ======================> nes_sunsoft_dcs_device
+
+class nes_sunsoft_dcs_device : public nes_sunsoft_4_device
+{
+public:
+ // construction/destruction
+ nes_sunsoft_dcs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_READ8_MEMBER(read_h);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+private:
+ int m_timer_on, m_exrom_enable;
+ required_device<nes_ntb_slot_device> m_subslot;
+
+ static const device_timer_id TIMER_PROTECT = 0;
+ emu_timer *ntb_enable_timer;
+};
+
+
+
+// device type definition
+extern const device_type NES_SUNSOFT_DCS;
+
+#endif
diff --git a/src/mess/machine/nes_taito.c b/src/mess/machine/nes_taito.c
new file mode 100644
index 00000000000..c0b9f72676a
--- /dev/null
+++ b/src/mess/machine/nes_taito.c
@@ -0,0 +1,467 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Taito PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Taito TC0190FMC/TC0190FMR [mapper 33]
+ * Taito TC0190FMC+PAL16R4 [mapper 48]
+ * Taito X1-005 [mapper 80, 207]
+ * Taito X1-017 [mapper 82]
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_taito.h"
+
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_TC0190FMC = &device_creator<nes_tc0190fmc_device>;
+const device_type NES_TC0190FMC_PAL16R4 = &device_creator<nes_tc0190fmc_pal16r4_device>;
+const device_type NES_X1_005 = &device_creator<nes_x1_005_device>;
+const device_type NES_X1_017 = &device_creator<nes_x1_017_device>;
+
+
+nes_tc0190fmc_device::nes_tc0190fmc_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_tc0190fmc_device::nes_tc0190fmc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TC0190FMC, "NES Cart Taito TC0190FMC PCB", tag, owner, clock, "nes_tc0190fmc", __FILE__)
+{
+}
+
+nes_tc0190fmc_pal16r4_device::nes_tc0190fmc_pal16r4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_tc0190fmc_device(mconfig, NES_TC0190FMC_PAL16R4, "NES Cart Taito TC0190FMC + PAL16R4 PCB", tag, owner, clock, "nes_tc0190pal", __FILE__)
+{
+}
+
+nes_x1_005_device::nes_x1_005_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_X1_005, "NES Cart Taito X1-005 PCB", tag, owner, clock, "nes_x1_005", __FILE__)
+{
+}
+
+nes_x1_017_device::nes_x1_017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_X1_017, "NES Cart Taito X1-017 PCB", tag, owner, clock, "nes_x1_017", __FILE__)
+{
+}
+
+
+
+void nes_tc0190fmc_device::device_start()
+{
+ common_start();
+}
+
+void nes_tc0190fmc_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+}
+
+void nes_tc0190fmc_pal16r4_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+}
+
+void nes_tc0190fmc_pal16r4_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0;
+}
+
+void nes_x1_005_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+
+ m_x1_005_ram = auto_alloc_array_clear(machine(), UINT8, 0x80);
+ save_pointer(NAME(m_x1_005_ram), 0x80);
+
+ m_mapper_sram_size = 0x80;
+ m_mapper_sram = m_x1_005_ram;
+}
+
+void nes_x1_005_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_x1_017_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+ save_item(NAME(m_reg));
+ save_item(NAME(m_mmc_vrom_bank));
+
+ m_x1_017_ram = auto_alloc_array_clear(machine(), UINT8, 0x1400);
+ save_pointer(NAME(m_x1_017_ram), 0x1400);
+
+ m_mapper_sram_size = 0x1400;
+ m_mapper_sram = m_x1_017_ram;
+}
+
+void nes_x1_017_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+ memset(m_reg, 0, sizeof(m_reg));
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Taito TC0190FMC board emulation
+
+ Games: Akira, Bakushou!! Jinsei Gekijou, Don Doko Don,
+ Insector X, Operation Wolf, Power Blazer, Takeshi no
+ Sengoku Fuuunji
+
+ iNES: mapper 33
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_tc0190fmc_device::tc0190fmc_write)
+{
+ LOG_MMC(("tc0190fmc_write, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ prg8_89(data);
+ break;
+ case 0x0001:
+ prg8_ab(data);
+ break;
+ case 0x0002:
+ chr2_0(data, CHRROM);
+ break;
+ case 0x0003:
+ chr2_2(data, CHRROM);
+ break;
+ case 0x2000:
+ chr1_4(data, CHRROM);
+ break;
+ case 0x2001:
+ chr1_5(data, CHRROM);
+ break;
+ case 0x2002:
+ chr1_6(data, CHRROM);
+ break;
+ case 0x2003:
+ chr1_7(data, CHRROM);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Taito TC0190FMC + PAL16R4 board emulation
+
+ Games: Bakushou!! Jinsei Gekijou 3, Bubble Bobble 2,
+ Captain Saver, Don Doko Don 2, Flintstones, Jetsons
+
+ This is basically Mapper 33 + IRQ. Notably, IRQ works the
+ same as MMC3 irq, BUT latch values are "inverted" (XOR'ed
+ with 0xff) and there is a little delay (not implemented yet)
+ We simply use MMC3 IRQ and XOR the value written in the
+ register 0xc000 below
+
+ iNES: mapper 48
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_tc0190fmc_pal16r4_device::hblank_irq( int scanline, int vblank, int blanked )
+{
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ int prior_count = m_irq_count;
+ if (m_irq_count == 0)
+ m_irq_count = m_irq_count_latch;
+ else
+ m_irq_count--;
+
+ if (m_irq_enable && !blanked && (m_irq_count == 0) && prior_count)
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+WRITE8_MEMBER(nes_tc0190fmc_pal16r4_device::write_h)
+{
+ LOG_MMC(("tc0190fmc pal16r4 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7003)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x0001:
+ case 0x0002:
+ case 0x0003:
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ tc0190fmc_write(space, offset, data, mem_mask);
+ break;
+ case 0x4000:
+ m_irq_count_latch = (0x100 - data) & 0xff;
+ break;
+ case 0x4001:
+ m_irq_count = m_irq_count_latch;
+ break;
+ case 0x4002:
+ m_irq_enable = 1;
+ break;
+ case 0x4003:
+ m_irq_enable = 0;
+ break;
+ case 0x6000:
+ set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Taito X1-005 board emulation
+
+ Actually, Fudou Myouou Den uses a variant of the board with
+ CIRAM, making necessary two distinct mappers & pcb_id.
+
+ Also, we miss to emulate the security check at 0x7ef8 / 0x7ef9
+ and the 0x80 ram!
+
+ iNES: mappers 80 & 207
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_x1_005_device::write_m)
+{
+ LOG_MMC(("x1_005 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1ef0:
+ chr2_0((data & 0x7f) >> 1, CHRROM);
+ if (m_x1_005_alt_mirroring)
+ {
+ set_nt_page(0, CIRAM, (data & 0x80) ? 1 : 0, 1);
+ set_nt_page(1, CIRAM, (data & 0x80) ? 1 : 0, 1);
+ }
+ break;
+ case 0x1ef1:
+ chr2_2((data & 0x7f) >> 1, CHRROM);
+ if (m_x1_005_alt_mirroring)
+ {
+ set_nt_page(2, CIRAM, (data & 0x80) ? 1 : 0, 1);
+ set_nt_page(3, CIRAM, (data & 0x80) ? 1 : 0, 1);
+ }
+ break;
+ case 0x1ef2:
+ chr1_4(data, CHRROM);
+ break;
+ case 0x1ef3:
+ chr1_5(data, CHRROM);
+ break;
+ case 0x1ef4:
+ chr1_6(data, CHRROM);
+ break;
+ case 0x1ef5:
+ chr1_7(data, CHRROM);
+ break;
+ case 0x1ef6:
+ case 0x1ef7:
+ if (!m_x1_005_alt_mirroring)
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ break;
+ case 0x1ef8:
+ case 0x1ef9:
+ m_latch = data;
+ break;
+ case 0x1efa:
+ case 0x1efb:
+ prg8_89(data);
+ break;
+ case 0x1efc:
+ case 0x1efd:
+ prg8_ab(data);
+ break;
+ case 0x1efe:
+ case 0x1eff:
+ prg8_cd(data);
+ break;
+ default:
+ logerror("mapper80_m_w uncaught addr: %04x, value: %02x\n", offset + 0x6000, data);
+ break;
+ }
+
+ if (offset >= 0x1f00 && m_latch == 0xa3)
+ m_x1_005_ram[offset & 0x7f] = data;
+}
+
+READ8_MEMBER(nes_x1_005_device::read_m)
+{
+ LOG_MMC(("x1_005 read_m, offset: %04x\n", offset));
+
+ if (offset >= 0x1f00 && m_latch == 0xa3)
+ return m_x1_005_ram[offset & 0x7f];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
+
+/*-------------------------------------------------
+
+ Taito X1-017 board emulation
+
+ We miss to emulate the security check at 0x6000-0x73ff
+ and the ram!
+
+ Games: Kyuukyoku Harikiri Koushien, Kyuukyoku Harikiri
+ Stadium, SD Keiji - Blader
+
+ iNES: mapper 82
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_x1_017_device::set_chr()
+{
+ if (m_latch)
+ {
+ chr2_4(m_mmc_vrom_bank[0] >> 1, CHRROM);
+ chr2_6(m_mmc_vrom_bank[1] >> 1, CHRROM);
+ }
+ else
+ {
+ chr2_0(m_mmc_vrom_bank[0] >> 1, CHRROM);
+ chr2_2(m_mmc_vrom_bank[1] >> 1, CHRROM);
+ }
+ chr1_x(4 ^ m_latch, m_mmc_vrom_bank[2], CHRROM);
+ chr1_x(5 ^ m_latch, m_mmc_vrom_bank[3], CHRROM);
+ chr1_x(6 ^ m_latch, m_mmc_vrom_bank[4], CHRROM);
+ chr1_x(7 ^ m_latch, m_mmc_vrom_bank[5], CHRROM);
+}
+
+WRITE8_MEMBER(nes_x1_017_device::write_m)
+{
+ LOG_MMC(("x1017 write_m, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x1ef0:
+ case 0x1ef1:
+ case 0x1ef2:
+ case 0x1ef3:
+ case 0x1ef4:
+ case 0x1ef5:
+ if (m_mmc_vrom_bank[offset & 0x07] != data)
+ {
+ m_mmc_vrom_bank[offset & 0x07] = data;
+ set_chr();
+ }
+ break;
+ case 0x1ef6:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_VERT : PPU_MIRROR_HORZ);
+ if (m_latch != ((data & 0x02) << 1))
+ {
+ m_latch = ((data & 0x02) << 1);
+ set_chr();
+ }
+ break;
+ case 0x1ef7:
+ case 0x1ef8:
+ case 0x1ef9:
+ m_reg[(offset & 0x0f) - 7] = data;
+ break;
+ case 0x1efa:
+ prg8_89(data >> 2);
+ break;
+ case 0x1efb:
+ prg8_ab(data >> 2);
+ break;
+ case 0x1efc:
+ prg8_cd(data >> 2);
+ break;
+ default:
+ logerror("x1017_m_w uncaught write, addr: %04x, value: %02x\n", offset + 0x6000, data);
+ break;
+ }
+
+ // 2+2+1 KB of Internal RAM can be independently enabled/disabled!
+ if (offset < 0x0800 && m_reg[0] == 0xca)
+ m_x1_017_ram[0x0000 + (offset & 0x7ff)] = data;
+ if (offset < 0x1000 && m_reg[1] == 0x69)
+ m_x1_017_ram[0x0800 + (offset & 0x7ff)] = data;
+ if (offset < 0x1400 && m_reg[2] == 0x84)
+ m_x1_017_ram[0x1000 + (offset & 0x3ff)] = data;
+}
+
+READ8_MEMBER(nes_x1_017_device::read_m)
+{
+ LOG_MMC(("x1017 read_m, offset: %04x\n", offset));
+
+ // 2+2+1 KB of Internal RAM can be independently enabled/disabled!
+ if (offset < 0x0800 && m_reg[0] == 0xca)
+ return m_x1_017_ram[0x0000 + (offset & 0x7ff)];
+ if (offset < 0x1000 && m_reg[1] == 0x69)
+ return m_x1_017_ram[0x0800 + (offset & 0x7ff)];
+ if (offset < 0x1400 && m_reg[2] == 0x84)
+ return m_x1_017_ram[0x1000 + (offset & 0x3ff)];
+
+ return ((offset + 0x6000) & 0xff00) >> 8; // open bus
+}
diff --git a/src/mess/machine/nes_taito.h b/src/mess/machine/nes_taito.h
new file mode 100644
index 00000000000..0b07bccd705
--- /dev/null
+++ b/src/mess/machine/nes_taito.h
@@ -0,0 +1,102 @@
+#ifndef __NES_TAITO_H
+#define __NES_TAITO_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_tc0190fmc_device
+
+class nes_tc0190fmc_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_tc0190fmc_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);
+ nes_tc0190fmc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(tc0190fmc_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { tc0190fmc_write(space, offset, data, mem_mask); }
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_tc0190fmc_pal16r4_device
+
+class nes_tc0190fmc_pal16r4_device : public nes_tc0190fmc_device
+{
+public:
+ // construction/destruction
+ nes_tc0190fmc_pal16r4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+private:
+ UINT16 m_irq_count, m_irq_count_latch;
+ int m_irq_enable;
+};
+
+
+// ======================> nes_x1_005_device
+
+class nes_x1_005_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_x1_005_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ UINT8 m_latch;
+ // Taito X1-005 chip contains 80 bytes of internal ram, possibly battery backed up
+ UINT8 *m_x1_005_ram;
+};
+
+
+// ======================> nes_x1_017_device
+
+class nes_x1_017_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_x1_017_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_m);
+ virtual DECLARE_WRITE8_MEMBER(write_m);
+
+ virtual void pcb_reset();
+
+private:
+ void set_chr();
+ UINT8 m_latch;
+ UINT8 m_reg[3]; //mapper ram protect
+ UINT8 m_mmc_vrom_bank[6];
+ // Taito X1-017 chip contains 5K of internal ram, battery backed up
+ UINT8 *m_x1_017_ram;
+};
+
+
+
+
+// device type definition
+extern const device_type NES_TC0190FMC;
+extern const device_type NES_TC0190FMC_PAL16R4;
+extern const device_type NES_X1_005;
+extern const device_type NES_X1_017;
+
+
+#endif
diff --git a/src/mess/machine/nes_tengen.c b/src/mess/machine/nes_tengen.c
new file mode 100644
index 00000000000..61b6c733217
--- /dev/null
+++ b/src/mess/machine/nes_tengen.c
@@ -0,0 +1,382 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Tengen PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * Tengen 800008
+ * Tengen 800032 [mapper 64]
+ * Tengen 800037 [mapper 158]
+
+ TODO:
+ - emulated the IRQ delay in 800032 (possibly reason of Skull & Crossbones not working?)
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_tengen.h"
+
+#include "cpu/m6502/m6502.h"
+#include "video/ppu2c0x.h" // this has to be included so that IRQ functions can access PPU_BOTTOM_VISIBLE_SCANLINE
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_TENGEN_800008 = &device_creator<nes_tengen008_device>;
+const device_type NES_TENGEN_800032 = &device_creator<nes_tengen032_device>;
+const device_type NES_TENGEN_800037 = &device_creator<nes_tengen037_device>;
+
+
+nes_tengen008_device::nes_tengen008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TENGEN_800008, "NES Cart Tengen 800008 PCB", tag, owner, clock, "nes_tengen008", __FILE__)
+{
+}
+
+nes_tengen032_device::nes_tengen032_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_tengen032_device::nes_tengen032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TENGEN_800032, "NES Cart Tengen 800032 PCB", tag, owner, clock, "nes_tengen032", __FILE__)
+{
+}
+
+nes_tengen037_device::nes_tengen037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_tengen032_device(mconfig, NES_TENGEN_800037, "NES Cart Tengen 800037 PCB", tag, owner, clock, "nes_tengen037", __FILE__)
+{
+}
+
+
+
+
+void nes_tengen008_device::device_start()
+{
+ common_start();
+}
+
+void nes_tengen008_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_tengen032_device::device_start()
+{
+ common_start();
+ irq_timer = timer_alloc(TIMER_IRQ);
+ irq_timer->reset();
+
+ save_item(NAME(m_mmc_prg_bank));
+ save_item(NAME(m_mmc_vrom_bank));
+ save_item(NAME(m_latch));
+
+ save_item(NAME(m_irq_mode));
+ save_item(NAME(m_irq_reset));
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+}
+
+void nes_tengen032_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(m_prg_chunks - 1);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+ memset(m_mmc_prg_bank, 0, sizeof(m_mmc_prg_bank));
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+
+ m_latch = 0;
+ m_irq_mode = 0;
+ m_irq_reset = 0;
+ m_irq_enable = 0;
+ m_irq_count = m_irq_count_latch = 0;
+}
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Tengen 800008 Board
+
+ iNES: mapper 3?
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_tengen008_device::write_h)
+{
+ LOG_MMC(("tengen008 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ prg32(data >> 3);
+ chr8(data, CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Tengen 800032 Board
+
+ Games: Klax, Road Runner, Rolling Thunder, Shinobi, Skulls
+ & Crossbones, Xybots
+
+ This is very similar to MMC-3 (or more probably to the
+ Namcot predecessor of MMC-3), but with more registers
+ and with an alternative IRQ mode
+
+ iNES: mapper 64
+
+ In MESS: Partially Supported (there should be a small
+ delay between the IRQ and its execution, but that is not
+ emulated yet: this is possibly the problem with Skulls
+ & Crossbones)
+
+ -------------------------------------------------*/
+
+inline void nes_tengen032_device::irq_clock(int blanked)
+{
+ // From NESdev wiki: Regardless of the mode used to clock the counter, every time the counter is clocked,
+ // the following actions occur:
+ // - If Reset reg ($C001) was written to after previous clock, reload IRQ counter with IRQ Reload + 1
+ // - Otherwise, if IRQ Counter is 0, reload IRQ counter with IRQ Reload value
+ // - Otherwise, first decrement IRQ counter by 1, then if IRQ counter is now 0 and IRQs are enabled,
+ // trigger IRQ
+ if (m_irq_reset)
+ {
+ m_irq_reset = 0;
+ m_irq_count = m_irq_count_latch + 1;
+ }
+ else
+ {
+ if (!m_irq_count)
+ m_irq_count = m_irq_count_latch;
+ else
+ {
+ m_irq_count--;
+ if (m_irq_enable && !blanked && !m_irq_count)
+ {
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+ }
+ }
+}
+
+// we use the HBLANK IRQ latch from PPU for the scanline based IRQ mode
+// and a timer for the cycle based IRQ mode, which both call irq_clock
+
+void nes_tengen032_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_IRQ)
+ {
+ irq_clock(0);
+ }
+}
+
+
+void nes_tengen032_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ if (!m_irq_mode) // we are in scanline mode!
+ {
+ if (scanline < PPU_BOTTOM_VISIBLE_SCANLINE)
+ {
+ irq_clock(blanked);
+ }
+ }
+}
+
+void nes_tengen032_device::set_prg()
+{
+ UINT8 prg_mode = m_latch & 0x40;
+
+ prg8_89(m_mmc_prg_bank[prg_mode ? 2: 0]);
+ prg8_ab(m_mmc_prg_bank[prg_mode ? 0: 1]);
+ prg8_cd(m_mmc_prg_bank[prg_mode ? 1: 2]);
+}
+
+void nes_tengen032_device::chr_cb(int start, int bank, int source)
+{
+ chr1_x(start, bank, source);
+}
+
+void nes_tengen032_device::set_chr()
+{
+ UINT8 chr_page = (m_latch & 0x80) >> 5;
+
+ if (m_latch & 0x20)
+ {
+ chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0], CHRROM);
+ chr_cb(1 ^ chr_page, m_mmc_vrom_bank[6], CHRROM);
+ chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1], CHRROM);
+ chr_cb(3 ^ chr_page, m_mmc_vrom_bank[7], CHRROM);
+ }
+ else
+ {
+ chr_cb(0 ^ chr_page, m_mmc_vrom_bank[0] & ~0x01, CHRROM);
+ chr_cb(1 ^ chr_page, m_mmc_vrom_bank[0] | 0x01, CHRROM);
+ chr_cb(2 ^ chr_page, m_mmc_vrom_bank[1] & ~0x01, CHRROM);
+ chr_cb(3 ^ chr_page, m_mmc_vrom_bank[1] | 0x01, CHRROM);
+ }
+
+ chr_cb(4 ^ chr_page, m_mmc_vrom_bank[2], CHRROM);
+ chr_cb(5 ^ chr_page, m_mmc_vrom_bank[3], CHRROM);
+ chr_cb(6 ^ chr_page, m_mmc_vrom_bank[4], CHRROM);
+ chr_cb(7 ^ chr_page, m_mmc_vrom_bank[5], CHRROM);
+}
+
+WRITE8_MEMBER(nes_tengen032_device::tengen032_write)
+{
+ UINT8 helper, cmd;
+ LOG_MMC(("tengen032_write, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0000:
+ helper = m_latch ^ data;
+ m_latch = data;
+
+ // Has PRG Mode changed?
+ if (helper & 0x40)
+ set_prg();
+
+ // Has CHR Mode changed?
+ if (helper & 0xa0)
+ set_chr();
+ break;
+
+ case 0x0001:
+ cmd = m_latch & 0x0f;
+ switch (cmd)
+ {
+ case 0: case 1:
+ case 2: case 3:
+ case 4: case 5:
+ m_mmc_vrom_bank[cmd] = data;
+ set_chr();
+ break;
+ case 6: case 7:
+ m_mmc_prg_bank[cmd - 6] = data;
+ set_prg();
+ break;
+ case 8: case 9:
+ m_mmc_vrom_bank[cmd - 2] = data;
+ set_chr();
+ break;
+ case 0x0f:
+ m_mmc_prg_bank[2] = data;
+ set_prg();
+ break;
+ }
+ break;
+
+ case 0x2000:
+ set_nt_mirroring(BIT(data, 0) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+
+ case 0x4000:
+ m_irq_count_latch = data;
+ break;
+
+ case 0x4001: /* $c001 - IRQ scanline latch */
+ m_irq_mode = data & 0x01;
+ if (m_irq_mode)
+ irq_timer->adjust(attotime::zero, 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(4));
+ else
+ irq_timer->adjust(attotime::never);
+ m_irq_reset = 1;
+ break;
+
+ case 0x6000:
+ m_irq_enable = 0;
+ break;
+
+ case 0x6001:
+ m_irq_enable = 1;
+ break;
+
+ default:
+ LOG_MMC(("Tengen 800032 write. addr: %04x value: %02x\n", offset + 0x8000, data));
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Tengen 800037 Board
+
+ Games: Alien Syndrome
+
+ Same as above (mapper chip RAMBO-1) but CHR A17 output
+ is connected to CIRAM A10, so this differs from 800032
+ exactly in the same way as TLSROM differs from plain
+ MMC-3
+
+ iNES: mapper 158
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_tengen037_device::set_mirror()
+{
+ if (m_latch & 0x80)
+ {
+ set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[2],7), 1);
+ set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[3],7), 1);
+ set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[4],7), 1);
+ set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[5],7), 1);
+ }
+ else
+ {
+ set_nt_page(0, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1);
+ set_nt_page(1, CIRAM, BIT(m_mmc_vrom_bank[0],7), 1);
+ set_nt_page(2, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1);
+ set_nt_page(3, CIRAM, BIT(m_mmc_vrom_bank[1],7), 1);
+ }
+}
+
+void nes_tengen037_device::chr_cb( int start, int bank, int source )
+{
+ set_mirror(); // we could probably update only for one (e.g. the first) call, to slightly optimize the code
+ chr1_x(start, bank, source);
+}
+
+
+WRITE8_MEMBER(nes_tengen037_device::write_h)
+{
+ LOG_MMC(("tengen037 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x2000:
+ break;
+
+ default:
+ tengen032_write(space, offset, data, mem_mask);
+ break;
+ }
+}
diff --git a/src/mess/machine/nes_tengen.h b/src/mess/machine/nes_tengen.h
new file mode 100644
index 00000000000..e128f767d3d
--- /dev/null
+++ b/src/mess/machine/nes_tengen.h
@@ -0,0 +1,85 @@
+#ifndef __NES_TENGEN_H
+#define __NES_TENGEN_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_tengen008_device
+
+class nes_tengen008_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_tengen008_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_tengen032_device
+
+class nes_tengen032_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_tengen032_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);
+ nes_tengen032_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual DECLARE_WRITE8_MEMBER(tengen032_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { tengen032_write(space, offset, data, mem_mask); }
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ void set_prg();
+ void set_chr();
+ void irq_clock(int blanked);
+
+ UINT16 m_irq_count, m_irq_count_latch;
+ UINT8 m_irq_mode, m_irq_reset;
+ int m_irq_enable;
+
+ UINT8 m_latch;
+ UINT8 m_mmc_prg_bank[3];
+ UINT8 m_mmc_vrom_bank[8];
+
+ static const device_timer_id TIMER_IRQ = 0;
+ emu_timer *irq_timer;
+};
+
+
+// ======================> nes_tengen037_device
+
+class nes_tengen037_device : public nes_tengen032_device
+{
+public:
+ // construction/destruction
+ nes_tengen037_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void chr_cb(int start, int bank, int source);
+
+protected:
+ void set_mirror();
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_TENGEN_800008;
+extern const device_type NES_TENGEN_800032;
+extern const device_type NES_TENGEN_800037;
+
+#endif
diff --git a/src/mess/machine/nes_txc.c b/src/mess/machine/nes_txc.c
new file mode 100644
index 00000000000..2341d1654ef
--- /dev/null
+++ b/src/mess/machine/nes_txc.c
@@ -0,0 +1,267 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for TXC PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the following PCBs
+
+ * TXC 22111 [mapper 132]
+ * TXC Du Ma Racing [mapper 172]
+ * TXC Mahjong Block [mapper 172]
+ * TXC Strike Wolf [mapper 36]
+ * TXC Commandos (and many more) [mapper 241]
+
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_txc.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_TXC_22211 = &device_creator<nes_txc_22211_device>;
+const device_type NES_TXC_DUMARACING = &device_creator<nes_txc_dumarc_device>;
+const device_type NES_TXC_MJBLOCK = &device_creator<nes_txc_mjblock_device>;
+const device_type NES_TXC_STRIKEW = &device_creator<nes_txc_strikew_device>;
+const device_type NES_TXC_COMMANDOS = &device_creator<nes_txc_commandos_device>;
+
+
+nes_txc_22211_device::nes_txc_22211_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)
+ : nes_nrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_txc_22211_device::nes_txc_22211_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TXC_22211, "NES Cart TXC 22211 PCB", tag, owner, clock, "nes_txc_22211", __FILE__)
+{
+}
+
+nes_txc_dumarc_device::nes_txc_dumarc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txc_22211_device(mconfig, NES_TXC_DUMARACING, "NES Cart TXC Du Ma Racing PCB", tag, owner, clock, "nes_dumarc", __FILE__)
+{
+}
+
+nes_txc_mjblock_device::nes_txc_mjblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txc_22211_device(mconfig, NES_TXC_MJBLOCK, "NES Cart TXC Mahjong Block PCB", tag, owner, clock, "nes_mjblock", __FILE__)
+{
+}
+
+nes_txc_strikew_device::nes_txc_strikew_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TXC_STRIKEW, "NES Cart Strike Wolf PCB", tag, owner, clock, "nes_txc_strikew", __FILE__)
+{
+}
+
+nes_txc_commandos_device::nes_txc_commandos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_TXC_COMMANDOS, "NES Cart Commandos (and others) PCB", tag, owner, clock, "nes_txc_comm", __FILE__)
+{
+}
+
+
+
+
+void nes_txc_22211_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_txc_22211_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+ m_reg[0] = m_reg[1] = m_reg[2] = m_reg[3] = 0;
+}
+
+void nes_txc_strikew_device::device_start()
+{
+ common_start();
+}
+
+void nes_txc_strikew_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_txc_commandos_device::device_start()
+{
+ common_start();
+}
+
+void nes_txc_commandos_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Bootleg Board 22211 by TXC (Type A)
+
+ Games: Creatom
+
+ Info from NEStopia: this mapper features write to four
+ registers (0x4100-0x4103). The third one is used to select
+ PRG and CHR banks.
+
+ iNES: mapper 132
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_txc_22211_device::write_l)
+{
+ LOG_MMC(("TXC 22111 write_l, offset: %04x, data: %02x\n", offset, data));
+
+ if (offset < 4)
+ m_reg[offset & 0x03] = data;
+}
+
+READ8_MEMBER(nes_txc_22211_device::read_l)
+{
+ LOG_MMC(("TXC 22111 read_l, offset: %04x\n", offset));
+
+ if (offset == 0x0000)
+ return (m_reg[1] ^ m_reg[2]) | 0x40;
+ else
+ return 0x00;
+}
+
+WRITE8_MEMBER(nes_txc_22211_device::write_h)
+{
+ LOG_MMC(("TXC 22111 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(m_reg[2] >> 2);
+ chr8(m_reg[2], CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board 22211 by TXC (Type B)
+
+ Games: 1991 Du Ma Racing
+
+ This mapper is basically the same as Type A. Only difference is
+ in the way CHR banks are selected (see below)
+
+ iNES: mapper 172
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_txc_dumarc_device::write_h)
+{
+ LOG_MMC(("TXC Du Ma Racing write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(m_reg[2] >> 2);
+ chr8((((data ^ m_reg[2]) >> 3) & 0x02) | (((data ^ m_reg[2]) >> 5) & 0x01), CHRROM);
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board 22211 by TXC (Type C)
+
+ Games: Mahjong Block, Xiao Ma Li
+
+ This mapper is basically the same as 132 too. Only difference is
+ in 0x4100 reads which expect also bit 0 to be set
+
+ iNES: mapper 172
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(nes_txc_mjblock_device::read_l)
+{
+ LOG_MMC(("TXC mjblock read_l, offset: %04x\n", offset));
+
+ if (offset == 0x0000)
+ return (m_reg[1] ^ m_reg[2]) | 0x41;
+ else
+ return 0x00;
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board 'Strike Wolf' by TXC
+
+ Games: Strike Wolf (also Policeman?? according to Nestopia)
+
+ iNES: mapper 36
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_txc_strikew_device::write_h)
+{
+ LOG_MMC(("TXC Strike Wolf write_h, offset: %04x, data: %02x\n", offset, data));
+
+ // this pcb is subject to bus conflict
+ data = account_bus_conflict(offset, data);
+
+ if ((offset >= 0x400) && (offset < 0x7fff))
+ {
+ prg32(data >> 4);
+ chr8(data & 0x0f, CHRROM);
+ }
+}
+
+/*-------------------------------------------------
+
+ Bootleg Board MXMDHTWO by TXC
+
+ Games: Commandos, Journey to the West, Ma Bu Mi Zhen &
+ Qu Wei Cheng Yu Wu, Si Lu Chuan Qi
+
+ Simple Mapper: writes to 0x8000-0xffff sets the prg32 bank.
+ Not sure if returning 0x50 for reads in 0x4100-0x5000 is correct.
+
+ iNES: mapper 241
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+READ8_MEMBER(nes_txc_commandos_device::read_l)
+{
+ return 0x50;
+}
+
+WRITE8_MEMBER(nes_txc_commandos_device::write_h)
+{
+ LOG_MMC(("TXC Commandos write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(data);
+}
diff --git a/src/mess/machine/nes_txc.h b/src/mess/machine/nes_txc.h
new file mode 100644
index 00000000000..9199dc49a04
--- /dev/null
+++ b/src/mess/machine/nes_txc.h
@@ -0,0 +1,97 @@
+#ifndef __NES_TXC_H
+#define __NES_TXC_H
+
+#include "machine/nes_nxrom.h"
+
+
+// ======================> nes_txc_22211_device
+
+class nes_txc_22211_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_txc_22211_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);
+ nes_txc_22211_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_reg[4];
+};
+
+
+// ======================> nes_txc_dumarac_device
+
+class nes_txc_dumarc_device : public nes_txc_22211_device
+{
+public:
+ // construction/destruction
+ nes_txc_dumarc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+};
+
+
+// ======================> nes_txc_mjblock_device
+
+class nes_txc_mjblock_device : public nes_txc_22211_device
+{
+public:
+ // construction/destruction
+ nes_txc_mjblock_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_READ8_MEMBER(read_l);
+};
+
+
+// ======================> nes_txc_strikew_device
+
+class nes_txc_strikew_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_txc_strikew_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_txc_commandos_device
+
+class nes_txc_commandos_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_txc_commandos_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+
+
+// device type definition
+extern const device_type NES_TXC_22211;
+extern const device_type NES_TXC_DUMARACING;
+extern const device_type NES_TXC_MJBLOCK;
+extern const device_type NES_TXC_STRIKEW;
+extern const device_type NES_TXC_COMMANDOS;
+
+#endif
diff --git a/src/mess/machine/nes_unif.c b/src/mess/machine/nes_unif.c
index cf801d6ac85..11016f6e33d 100644
--- a/src/mess/machine/nes_unif.c
+++ b/src/mess/machine/nes_unif.c
@@ -9,6 +9,21 @@
****************************************************************************************/
+
+/* Set to generate prg & chr files when the cart is loaded */
+#define SPLIT_PRG 0
+#define SPLIT_CHR 0
+
+
+/*************************************************************
+
+ unif_list
+
+ Supported UNIF boards and corresponding handlers
+
+ *************************************************************/
+
+
struct unif
{
const char *board; /* UNIF board */
@@ -20,12 +35,6 @@ struct unif
};
-/*************************************************************
-
- Constants
-
-*************************************************************/
-
/* CHRRAM sizes */
enum
{
@@ -39,14 +48,6 @@ enum
CHRRAM_32
};
-/*************************************************************
-
- unif_list
-
- Supported UNIF boards and corresponding handlers
-
-*************************************************************/
-
static const unif unif_list[] =
{
/* UNIF NVW WRAM CRAM IDX*/
@@ -57,14 +58,14 @@ static const unif unif_list[] =
{ "NES-NROM", 0, 0, CHRRAM_0, STD_NROM},
{ "NES-NROM-128", 0, 0, CHRRAM_0, STD_NROM},
{ "NES-NROM-256", 0, 0, CHRRAM_0, STD_NROM},
- { "NES-NTBROM", 8, 0, CHRRAM_0, STD_NXROM},
+ { "NES-NTBROM", 8, 0, CHRRAM_0, SUNSOFT_DCS},
{ "NES-SLROM", 0, 0, CHRRAM_0, STD_SXROM},
{ "NES-TBROM", 0, 0, CHRRAM_0, STD_TXROM},
{ "NES-TFROM", 0, 0, CHRRAM_0, STD_TXROM},
{ "NES-TKROM", 8, 0, CHRRAM_0, STD_TXROM},
{ "NES-TLROM", 0, 0, CHRRAM_0, STD_TXROM},
{ "NES-UOROM", 0, 0, CHRRAM_8, STD_UXROM},
- { "UNL-22211", 0, 0, CHRRAM_0, TXC_22211A},
+ { "UNL-22211", 0, 0, CHRRAM_0, TXC_22211},
// mapper 172 & 173 are variant of this one... no UNIF?
{ "UNL-KOF97", 0, 0, CHRRAM_0, UNL_KOF97},
{ "UNL-SA-NROM", 0, 0, CHRRAM_0, SACHEN_TCA01},
@@ -85,57 +86,58 @@ static const unif unif_list[] =
{ "UNL-SA-72008", 0, 0, CHRRAM_0, SACHEN_SA72008},
{ "UNL-SA-0037", 0, 0, CHRRAM_0, SACHEN_SA0037},
{ "UNL-SA-0036", 0, 0, CHRRAM_0, SACHEN_SA0036},
- { "UNL-SA-9602B", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "UNL-SA-9602B", 0, 0, CHRRAM_0, SACHEN_SA9602B},
{ "UNL-SACHEN-8259A", 0, 0, CHRRAM_0, SACHEN_8259A},
{ "UNL-SACHEN-8259B", 0, 0, CHRRAM_0, SACHEN_8259B},
{ "BMC-190IN1", 0, 0, CHRRAM_0, BMC_190IN1},
{ "BMC-64IN1NOREPEAT", 0, 0, CHRRAM_0, BMC_64IN1NR}, //UNIF only!
{ "BMC-A65AS", 0, 0, CHRRAM_8, BMC_A65AS}, //UNIF only!
- { "BMC-GS-2004", 0, 0, CHRRAM_8, BMC_GS2004}, //UNIF only!
- { "BMC-GS-2013", 0, 0, CHRRAM_8, BMC_GS2013}, //UNIF only!
- { "BMC-NOVELDIAMOND9999999IN1", 0, 0, CHRRAM_0, BMC_NOVELDIAMOND},
+ { "BMC-GS-2004", 0, 0, CHRRAM_8, RCM_GS2004}, //UNIF only!
+ { "BMC-GS-2013", 0, 0, CHRRAM_8, RCM_GS2013}, //UNIF only!
+ { "BMC-NOVELDIAMOND9999999IN1", 0, 0, CHRRAM_0, BMC_NOVEL1},
{ "BMC-SUPER24IN1SC03", 8, 0, CHRRAM_8, BMC_S24IN1SC03},
{ "BMC-SUPERHIK8IN1", 8, 0, CHRRAM_0, BMC_HIK8IN1},
{ "BMC-T-262", 0, 0, CHRRAM_8, BMC_T262}, //UNIF only!
{ "BMC-WS", 0, 0, CHRRAM_0, BMC_WS}, //UNIF only!
{ "BMC-N625092", 0, 0, CHRRAM_0, UNL_N625092},
// below are boards which are not yet supported, but are used by some UNIF files. they are here as a reminder to what is missing to be added
- { "UNL-TEK90", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // related to JY Company? (i.e. mappers 90, 209, 211?)
- { "UNL-KS7017", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "UNL-TEK90", 0, 0, CHRRAM_0, JYCOMPANY_A}, // JY Company A (is TEK90 the real PCB name?)
+ { "UNL-KS7017", 0, 0, CHRRAM_0, KAISER_KS7017},
{ "UNL-KS7032", 0, 0, CHRRAM_0, KAISER_KS7032}, // mapper 142
- { "UNL-DANCE", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
{ "UNL-603-5052", 0, 0, CHRRAM_0, UNL_603_5052}, // mapper 238?
{ "UNL-EDU2000", 32, 0, CHRRAM_8, UNL_EDU2K},
{ "UNL-H2288", 0, 0, CHRRAM_0, UNL_H2288}, // mapper 123
- { "UNL-SHERO", 0, 0, CHRRAM_8, UNSUPPORTED_BOARD /*SACHEN_SHERO*/},
- { "UNL-TF1201", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD /*UNL_TF1201*/},
- { "UNL-DRIPGAME", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // [by Quietust - we need more info]}
- { "UNL-OneBus", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
- { "UNL-YOKO", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // similar to mapper 83, but not the same
- { "UNL-FS304", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // used in Zelda 3 by Waixing (support missing atm)
- { "UNL-43272", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // used in Gaau Hok Gwong Cheung (support missing atm)
- { "BTL-MARIO1-MALEE2", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 55?
+ { "UNL-SHERO", 0, 0, CHRRAM_8, SACHEN_SHERO},
+ { "UNL-YOKO", 0, 0, CHRRAM_0, YOKO_BOARD}, // similar to mapper 83, but not the same
+ { "UNL-FS304", 0, 8, CHRRAM_8, WAIXING_FS304}, // used in Zelda 3 by Waixing
+ { "UNL-43272", 0, 0, CHRRAM_0, UNL_43272}, // used in Gaau Hok Gwong Cheung
+ { "BTL-MARIO1-MALEE2", 0, 0, CHRRAM_0, UNL_MMALEE}, // mapper 55?
{ "BMC-FK23C", 0, 0, CHRRAM_0, BMC_FK23C},
{ "BMC-FK23CA", 0, 0, CHRRAM_0, BMC_FK23CA},
{ "BMC-GHOSTBUSTERS63IN1", 0, 0, CHRRAM_8, BMC_G63IN1 },
- { "BMC-BS-5", 0, 0, CHRRAM_0, BMC_BENSHENG_BS5},
+ { "BMC-BS-5", 0, 0, CHRRAM_0, BMC_BENSHIENG},
{ "BMC-810544-C-A1", 0, 0, CHRRAM_0, BMC_810544},
- { "BMC-411120-C", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
- { "BMC-8157", 0, 0, CHRRAM_8, UNSUPPORTED_BOARD /*BMC_8157*/},
- { "BMC-42IN1RESETSWITCH", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 60?
- { "BMC-830118C", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "BMC-411120-C", 0, 0, CHRRAM_0, BMC_411120C},
+ { "BMC-8157", 0, 0, CHRRAM_8, BMC_8157},
+ { "BMC-830118C", 0, 0, CHRRAM_0, BMC_830118C},
{ "BMC-D1038", 0, 0, CHRRAM_0, BMC_VT5201}, // mapper 60?
+ { "BMC-SUPERVISION16IN1", 0, 0, CHRRAM_0, SVISION16_BOARD}, // mapper 53
+ { "BMC-NTD-03", 0, 0, CHRRAM_0, BMC_NTD_03},
+ { "UNL-AC08", 0, 0, CHRRAM_0, UNL_AC08},
+ { "UNL-BB", 0, 0, CHRRAM_0, UNL_BB},
+ { "UNL-LH32", 0, 0, CHRRAM_0, UNL_LH32},
+ { "BMC-G-146", 0, 0, CHRRAM_0, BMC_G146},
+ { "BMC-11160", 0, 0, CHRRAM_0, BMC_11160},
+ { "UNL-MALISB", 0, 0, CHRRAM_0, UNL_MALISB},
+ { "UNL-TF1201", 0, 0, CHRRAM_0, UNL_TF1201},
{ "BMC-12-IN-1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
{ "BMC-70IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236?
{ "BMC-70IN1B", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 236?
- { "BMC-SUPERVISION16IN1", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 53
- { "BMC-NTD-03", 0, 0, CHRRAM_0, BMC_NTD_03},
- { "UNL-AC08", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
- { "UNL-BB", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
- { "UNL-LH32", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "BMC-42IN1RESETSWITCH", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // mapper 60?
+ { "UNL-DANCE", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
+ { "UNL-DRIPGAME", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}, // [by Quietust - we need more info]
{ "UNL-CITYFIGHT", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
- { "BMC-G-146", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD},
- { "BMC-11160", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}
+ { "UNL-OneBus", 0, 0, CHRRAM_0, UNSUPPORTED_BOARD}
};
const unif *nes_unif_lookup( const char *board )
@@ -175,3 +177,405 @@ void unif_mapr_setup( const char *board, int *pcb_id, int *battery, int *prgram,
else if (unif_board->chrram == CHRRAM_32)
*vram_chunks = 4;
}
+
+
+/*************************************************************
+
+ call_load_unif
+
+ *************************************************************/
+
+void nes_cart_slot_device::call_load_unif()
+{
+ UINT32 vram_size = 0, prgram_size = 0, battery_size = 0, mapper_sram_size = 0;
+ // SETUP step 1: running through the file and getting PRG, VROM sizes
+ UINT32 unif_ver = 0, chunk_length = 0, read_length = 0x20;
+ UINT32 prg_start = 0, chr_start = 0;
+ UINT32 size = length(), prg_size = 0, vrom_size = 0;
+ UINT8 buffer[4], mirror = 0;
+ char magic2[4];
+ char unif_mapr[32]; // here we should store MAPR chunks
+ bool mapr_chunk_found = FALSE, small_prg = FALSE;
+
+ // allocate space to temporarily store PRG & CHR banks
+ UINT8 *temp_prg = auto_alloc_array(machine(), UINT8, 256 * 0x4000);
+ UINT8 *temp_chr = auto_alloc_array(machine(), UINT8, 256 * 0x2000);
+ UINT8 temp_byte = 0;
+
+ fseek(4, SEEK_SET);
+ fread(&buffer, 4);
+ unif_ver = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+ logerror("Loaded game in UNIF format, version %d\n", unif_ver);
+
+ do
+ {
+ fseek(read_length, SEEK_SET);
+
+ memset(magic2, '\0', sizeof(magic2));
+ fread(&magic2, 4);
+
+ /* We first run through the whole image to find a [MAPR] chunk. This is needed
+ because, unfortunately, the MAPR chunk is not always the first chunk (see
+ Super 24-in-1). When such a chunk is found, we set mapr_chunk_found=1 and
+ we go back to load other chunks! */
+ if (!mapr_chunk_found)
+ {
+ if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R'))
+ {
+ mapr_chunk_found = TRUE;
+ logerror("[MAPR] chunk found: ");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ if (chunk_length <= 0x20)
+ fread(&unif_mapr, chunk_length);
+ logerror("%s\n", unif_mapr);
+
+ /* now that we found the MAPR chunk, we can go back to load other chunks */
+ fseek(0x20, SEEK_SET);
+ read_length = 0x20;
+ }
+ else
+ {
+ logerror("Skip this chunk. We need a [MAPR] chunk before anything else.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ }
+ else
+ {
+ /* What kind of chunk do we have here? */
+ if ((magic2[0] == 'M') && (magic2[1] == 'A') && (magic2[2] == 'P') && (magic2[3] == 'R'))
+ {
+ /* The [MAPR] chunk has already been read, so we skip it */
+ /* TO DO: it would be nice to check if more than one MAPR chunk is present */
+ logerror("[MAPR] chunk found (in the 2nd run). Already loaded.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'R') && (magic2[1] == 'E') && (magic2[2] == 'A') && (magic2[3] == 'D'))
+ {
+ logerror("[READ] chunk found. No support yet.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'N') && (magic2[1] == 'A') && (magic2[2] == 'M') && (magic2[3] == 'E'))
+ {
+ logerror("[NAME] chunk found. No support yet.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'W') && (magic2[1] == 'R') && (magic2[2] == 'T') && (magic2[3] == 'R'))
+ {
+ logerror("[WRTR] chunk found. No support yet.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'C') && (magic2[3] == 'I'))
+ {
+ logerror("[TVCI] chunk found.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ fread(&temp_byte, 1);
+ logerror("Television Standard : %s\n", (temp_byte == 0) ? "NTSC" : (temp_byte == 1) ? "PAL" : "Does not matter");
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'T') && (magic2[1] == 'V') && (magic2[2] == 'S') && (magic2[3] == 'C')) // is this the same as TVCI??
+ {
+ logerror("[TVSC] chunk found. No support yet.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'D') && (magic2[1] == 'I') && (magic2[2] == 'N') && (magic2[3] == 'F'))
+ {
+ logerror("[DINF] chunk found. No support yet.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'C') && (magic2[1] == 'T') && (magic2[2] == 'R') && (magic2[3] == 'L'))
+ {
+ logerror("[CTRL] chunk found. No support yet.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'B') && (magic2[1] == 'A') && (magic2[2] == 'T') && (magic2[3] == 'R'))
+ {
+ logerror("[BATR] chunk found. No support yet.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'V') && (magic2[1] == 'R') && (magic2[2] == 'O') && (magic2[3] == 'R'))
+ {
+ logerror("[VROR] chunk found. No support yet.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'M') && (magic2[1] == 'I') && (magic2[2] == 'R') && (magic2[3] == 'R'))
+ {
+ logerror("[MIRR] chunk found.\n");
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ fread(&mirror, 1);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'P') && (magic2[1] == 'C') && (magic2[2] == 'K'))
+ {
+ logerror("[PCK%c] chunk found. No support yet.\n", magic2[3]);
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'C') && (magic2[1] == 'C') && (magic2[2] == 'K'))
+ {
+ logerror("[CCK%c] chunk found. No support yet.\n", magic2[3]);
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'P') && (magic2[1] == 'R') && (magic2[2] == 'G'))
+ {
+ logerror("[PRG%c] chunk found. ", magic2[3]);
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+ prg_size += chunk_length;
+
+ if (chunk_length / 0x4000)
+ logerror("It consists of %d 16K-blocks.\n", chunk_length / 0x4000);
+ else
+ {
+ small_prg = TRUE;
+ logerror("This chunk is smaller than 16K: the emulation might have issues. Please report this file to the MESS forums.\n");
+ }
+
+ /* Read in the program chunks */
+ fread(&temp_prg[prg_start], chunk_length);
+
+ prg_start += chunk_length;
+ read_length += (chunk_length + 8);
+ }
+ else if ((magic2[0] == 'C') && (magic2[1] == 'H') && (magic2[2] == 'R'))
+ {
+ logerror("[CHR%c] chunk found. ", magic2[3]);
+ fread(&buffer, 4);
+ chunk_length = buffer[0] | (buffer[1] << 8) | (buffer[2] << 16) | (buffer[3] << 24);
+ vrom_size += chunk_length;
+
+ logerror("It consists of %d 8K-blocks.\n", chunk_length / 0x2000);
+
+ /* Read in the vrom chunks */
+ fread(&temp_chr[chr_start], chunk_length);
+
+ chr_start += chunk_length;
+ read_length += (chunk_length + 8);
+ }
+ else
+ {
+ logerror("Unsupported UNIF chunk or corrupted header. Please report the problem at MESS Board.\n");
+ read_length = size;
+ }
+ }
+ } while (size > read_length);
+
+ if (!mapr_chunk_found)
+ {
+ auto_free(machine(), temp_prg);
+ auto_free(machine(), temp_chr);
+ fatalerror("UNIF should have a [MAPR] chunk to work. Check if your image has been corrupted\n");
+ }
+
+ if (!prg_start)
+ {
+ auto_free(machine(), temp_prg);
+ auto_free(machine(), temp_chr);
+ fatalerror("No PRG found. Please report the problem at MESS Board.\n");
+ }
+
+ // SETUP step 2: getting PCB and other settings
+ int pcb_id = 0, battery = 0, prgram = 0, vram_chunks = 0;
+ unif_mapr_setup(unif_mapr, &pcb_id, &battery, &prgram, &vram_chunks);
+
+ // SETUP step 3: storing the info needed for emulation
+ m_pcb_id = pcb_id;
+ if (battery)
+ battery_size = NES_BATTERY_SIZE; // we should allow for smaller battery!
+ prgram_size = prgram * 0x2000;
+ vram_size = vram_chunks * 0x2000;
+
+ m_cart->set_four_screen_vram(FALSE);
+ switch (mirror)
+ {
+ case 0: // Horizontal Mirroring (Hard Wired)
+ m_cart->set_mirroring(PPU_MIRROR_HORZ);
+ break;
+ case 1: // Vertical Mirroring (Hard Wired)
+ m_cart->set_mirroring(PPU_MIRROR_VERT);
+ break;
+ case 2: // Mirror All Pages From $2000 (Hard Wired)
+ m_cart->set_mirroring(PPU_MIRROR_LOW);
+ break;
+ case 3: // Mirror All Pages From $2400 (Hard Wired)
+ m_cart->set_mirroring(PPU_MIRROR_HIGH);
+ break;
+ case 4: // Four Screens of VRAM (Hard Wired)
+ m_cart->set_four_screen_vram(TRUE);
+ m_cart->set_mirroring(PPU_MIRROR_4SCREEN);
+ break;
+ case 5: // Mirroring Controlled By Mapper Hardware
+ logerror("Mirroring handled by the board hardware.\n");
+ // default to horizontal at start
+ m_cart->set_mirroring(PPU_MIRROR_HORZ);
+ break;
+ default:
+ logerror("Undocumented mirroring value.\n");
+ // default to horizontal
+ m_cart->set_mirroring(PPU_MIRROR_HORZ);
+ break;
+ }
+
+ // SETUP step 4: logging what we have found
+ logerror("-- Board %s\n", unif_mapr);
+ logerror("-- PRG 0x%x (%d x 16k chunks)\n", prg_size, prg_size / 0x4000);
+ logerror("-- VROM 0x%x (%d x 8k chunks)\n", vrom_size, vrom_size / 0x2000);
+ logerror("-- VRAM 0x%x (%d x 8k chunks)\n", vram_size, vram_size / 0x2000);
+
+ // SETUP steps 5/6: allocate pointers for PRG/VROM and load the data!
+ if (prg_size == 0x4000)
+ {
+ m_cart->prg_alloc(machine(), 0x8000);
+ memcpy(m_cart->get_prg_base(), temp_prg, 0x4000);
+ memcpy(m_cart->get_prg_base() + 0x4000, m_cart->get_prg_base(), 0x4000);
+ }
+ else
+ {
+ m_cart->prg_alloc(machine(), prg_size);
+ memcpy(m_cart->get_prg_base(), temp_prg, prg_size);
+ }
+
+ if (small_prg) // This is not supported yet, so warn users about this
+ mame_printf_error("Loaded UNIF file with non-16k PRG chunk. This is not supported in MESS yet.");
+
+ if (vrom_size)
+ {
+ m_cart->vrom_alloc(machine(), vrom_size);
+ memcpy(m_cart->get_vrom_base(), temp_chr, vrom_size);
+ }
+
+#if SPLIT_PRG
+ {
+ FILE *prgout;
+ char outname[255];
+
+ sprintf(outname, "%s.prg", filename());
+ prgout = fopen(outname, "wb");
+ if (prgout)
+ {
+ fwrite(m_cart->get_prg_base(), 1, 0x4000 * m_cart->get_prg_size(), prgout);
+ mame_printf_error("Created PRG chunk\n");
+ }
+
+ fclose(prgout);
+ }
+#endif
+
+#if SPLIT_CHR
+ if (state->m_chr_chunks > 0)
+ {
+ FILE *chrout;
+ char outname[255];
+
+ sprintf(outname, "%s.chr", filename());
+ chrout= fopen(outname, "wb");
+ if (chrout)
+ {
+ fwrite(m_cart->get_vrom_base(), 1, m_cart->get_vrom_size(), chrout);
+ mame_printf_error("Created CHR chunk\n");
+ }
+ fclose(chrout);
+ }
+#endif
+ // free the temporary copy of PRG/CHR
+ auto_free(machine(), temp_prg);
+ auto_free(machine(), temp_chr);
+
+ // SETUP steps 7: allocate the remaining pointer, when needed
+ if (vram_size)
+ m_cart->vram_alloc(machine(), vram_size);
+ if (prgram_size)
+ m_cart->prgram_alloc(machine(), prgram_size);
+
+ // Attempt to load a battery file for this ROM
+ // A few boards have internal RAM with a battery (MMC6, Taito X1-005 & X1-017, etc.)
+ if (battery_size || mapper_sram_size)
+ {
+ UINT32 tot_size = battery_size + mapper_sram_size;
+ UINT8 *temp_nvram = auto_alloc_array(machine(), UINT8, tot_size);
+ battery_load(temp_nvram, tot_size, 0x00);
+ if (battery_size)
+ {
+ m_cart->battery_alloc(machine(), battery_size);
+ memcpy(m_cart->get_battery_base(), temp_nvram, battery_size);
+ }
+ if (mapper_sram_size)
+ memcpy(m_cart->get_mapper_sram_base(), temp_nvram + battery_size, mapper_sram_size);
+
+ if (temp_nvram)
+ auto_free(machine(), temp_nvram);
+ }
+
+ logerror("UNIF support is only very preliminary.\n");
+}
+
+const char * nes_cart_slot_device::get_default_card_unif(UINT8 *ROM, UINT32 len)
+{
+ UINT32 chunk_length = 0, read_length = 0x20;
+ int pcb_id = 0, battery = 0, prgram = 0, vram_chunks = 0;
+ char unif_mapr[32];
+
+ do
+ {
+ if ((ROM[read_length + 0] == 'M') && (ROM[read_length + 1] == 'A') && (ROM[read_length + 2] == 'P') && (ROM[read_length + 3] == 'R'))
+ {
+ chunk_length = ROM[read_length + 4] | (ROM[read_length + 5] << 8) | (ROM[read_length + 6] << 16) | (ROM[read_length + 7] << 24);
+
+ if (chunk_length <= 0x20)
+ memcpy(unif_mapr, ROM + read_length + 8, chunk_length);
+
+ read_length += (chunk_length + 8);
+ }
+ else
+ {
+ chunk_length = ROM[read_length + 4] | (ROM[read_length + 5] << 8) | (ROM[read_length + 6] << 16) | (ROM[read_length + 7] << 24);
+ read_length += (chunk_length + 8);
+ }
+ } while (len > read_length);
+
+ unif_mapr_setup(unif_mapr, &pcb_id, &battery, &prgram, &vram_chunks);
+
+ return nes_get_slot(pcb_id);
+}
diff --git a/src/mess/machine/nes_waixing.c b/src/mess/machine/nes_waixing.c
new file mode 100644
index 00000000000..f42aba83a92
--- /dev/null
+++ b/src/mess/machine/nes_waixing.c
@@ -0,0 +1,1245 @@
+/***********************************************************************************************************
+
+
+ NES/Famicom cartridge emulation for Waixing PCBs
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+ Here we emulate the various PCBs used by Waixing for its games
+
+ TODO:
+ - investigate the PPU issues causing some games not to have sprites...
+
+ ***********************************************************************************************************/
+
+
+#include "emu.h"
+#include "machine/nes_waixing.h"
+
+#include "cpu/m6502/m6502.h"
+
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
+
+
+//-------------------------------------------------
+// constructor
+//-------------------------------------------------
+
+const device_type NES_WAIXING_A = &device_creator<nes_waixing_a_device>;
+const device_type NES_WAIXING_A1 = &device_creator<nes_waixing_a1_device>;
+const device_type NES_WAIXING_B = &device_creator<nes_waixing_b_device>;
+const device_type NES_WAIXING_C = &device_creator<nes_waixing_c_device>;
+const device_type NES_WAIXING_D = &device_creator<nes_waixing_d_device>;
+const device_type NES_WAIXING_E = &device_creator<nes_waixing_e_device>;
+const device_type NES_WAIXING_F = &device_creator<nes_waixing_f_device>;
+const device_type NES_WAIXING_G = &device_creator<nes_waixing_g_device>;
+const device_type NES_WAIXING_H = &device_creator<nes_waixing_h_device>;
+const device_type NES_WAIXING_H1 = &device_creator<nes_waixing_h1_device>;
+const device_type NES_WAIXING_I = &device_creator<nes_waixing_i_device>;
+const device_type NES_WAIXING_J = &device_creator<nes_waixing_j_device>;
+const device_type NES_WAIXING_SH2 = &device_creator<nes_waixing_sh2_device>;
+const device_type NES_WAIXING_SEC = &device_creator<nes_waixing_sec_device>;
+const device_type NES_WAIXING_SGZ = &device_creator<nes_waixing_sgz_device>;
+const device_type NES_WAIXING_SGZLZ = &device_creator<nes_waixing_sgzlz_device>;
+const device_type NES_WAIXING_FFV = &device_creator<nes_waixing_ffv_device>;
+const device_type NES_WAIXING_WXZS = &device_creator<nes_waixing_wxzs_device>;
+const device_type NES_WAIXING_DQ8 = &device_creator<nes_waixing_dq8_device>;
+const device_type NES_WAIXING_WXZS2 = &device_creator<nes_waixing_wxzs2_device>;
+const device_type NES_WAIXING_FS304 = &device_creator<nes_waixing_fs304_device>;
+
+
+nes_waixing_a_device::nes_waixing_a_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)
+ : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_waixing_a_device::nes_waixing_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_WAIXING_A, "NES Cart Waixing Type A PCB", tag, owner, clock, "nes_waixing_a", __FILE__)
+{
+}
+
+nes_waixing_a1_device::nes_waixing_a1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_A1, "NES Cart Waixing Type A (Alt) PCB", tag, owner, clock, "nes_waixing_a1", __FILE__)
+{
+}
+
+nes_waixing_b_device::nes_waixing_b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_B, "NES Cart Waixing Type B PCB", tag, owner, clock, "nes_waixing_b", __FILE__)
+{
+}
+
+nes_waixing_c_device::nes_waixing_c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_C, "NES Cart Waixing Type C PCB", tag, owner, clock, "nes_waixing_c", __FILE__)
+{
+}
+
+nes_waixing_d_device::nes_waixing_d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_D, "NES Cart Waixing Type D PCB", tag, owner, clock, "nes_waixing_d", __FILE__)
+{
+}
+
+nes_waixing_e_device::nes_waixing_e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_E, "NES Cart Waixing Type E PCB", tag, owner, clock, "nes_waixing_e", __FILE__)
+{
+}
+
+nes_waixing_f_device::nes_waixing_f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_F, "NES Cart Waixing Type F PCB", tag, owner, clock, "nes_waixing_f", __FILE__)
+{
+}
+
+nes_waixing_g_device::nes_waixing_g_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_G, "NES Cart Waixing Type G PCB", tag, owner, clock, "nes_waixing_g", __FILE__)
+{
+}
+
+nes_waixing_h_device::nes_waixing_h_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)
+ : nes_txrom_device(mconfig, type, name, tag, owner, clock, shortname, source)
+{
+}
+
+nes_waixing_h_device::nes_waixing_h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_WAIXING_H, "NES Cart Waixing Type H PCB", tag, owner, clock, "nes_waixing_h", __FILE__)
+{
+}
+
+nes_waixing_h1_device::nes_waixing_h1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_h_device(mconfig, NES_WAIXING_H1, "NES Cart Waixing Type H (Alt) PCB", tag, owner, clock, "nes_waixing_h1", __FILE__)
+{
+}
+
+nes_waixing_i_device::nes_waixing_i_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_I, "NES Cart Waixing Type I PCB", tag, owner, clock, "nes_waixing_i", __FILE__)
+{
+}
+
+nes_waixing_j_device::nes_waixing_j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_waixing_a_device(mconfig, NES_WAIXING_J, "NES Cart Waixing Type J PCB", tag, owner, clock, "nes_waixing_j", __FILE__)
+{
+}
+
+nes_waixing_sh2_device::nes_waixing_sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_WAIXING_SH2, "NES Cart Waixing SH2 PCB", tag, owner, clock, "nes_waixing_sh2", __FILE__)
+{
+}
+
+nes_waixing_sec_device::nes_waixing_sec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_txrom_device(mconfig, NES_WAIXING_SEC, "NES Cart Waixing Security Chip PCB", tag, owner, clock, "nes_waixing_sec", __FILE__)
+{
+}
+
+nes_waixing_sgz_device::nes_waixing_sgz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WAIXING_SGZ, "NES Cart Waixing San Guo Zhi PCB", tag, owner, clock, "nes_waixing_sgz", __FILE__)
+{
+}
+
+nes_waixing_sgzlz_device::nes_waixing_sgzlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WAIXING_SGZLZ, "NES Cart Waixing San Guo Zhong Lie Zhuan PCB", tag, owner, clock, "nes_waixing_sgzlz", __FILE__)
+{
+}
+
+nes_waixing_ffv_device::nes_waixing_ffv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WAIXING_FFV, "NES Cart Waixing Final Fantasy V PCB", tag, owner, clock, "nes_waixing_ffv", __FILE__)
+{
+}
+
+nes_waixing_wxzs_device::nes_waixing_wxzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WAIXING_WXZS, "NES Cart Waixing Wai Xing Zhan Shi PCB", tag, owner, clock, "nes_waixing_wxzs", __FILE__)
+{
+}
+
+nes_waixing_dq8_device::nes_waixing_dq8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WAIXING_DQ8, "NES Cart Waixing Dragon Quest VIII PCB", tag, owner, clock, "nes_waixing_dq8", __FILE__)
+{
+}
+
+nes_waixing_wxzs2_device::nes_waixing_wxzs2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WAIXING_WXZS2, "NES Cart Waixing Wai Xing Zhan Shi 2 PCB", tag, owner, clock, "nes_waixing_wxzs2", __FILE__)
+{
+}
+
+nes_waixing_fs304_device::nes_waixing_fs304_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : nes_nrom_device(mconfig, NES_WAIXING_FS304, "NES Cart Waixing FS-304 PCB", tag, owner, clock, "nes_waixing_fs304", __FILE__)
+{
+}
+
+
+void nes_waixing_a_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(mapper_ram));
+}
+
+void nes_waixing_a_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0xff, 0xff, 0);
+
+ memset(mapper_ram, 0, sizeof(mapper_ram));
+}
+
+void nes_waixing_f_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0xff, 0xff, 0);
+
+ memset(mapper_ram, 0, sizeof(mapper_ram));
+ m_mmc_prg_bank[0] = 0x00;
+ m_mmc_prg_bank[1] = 0x01;
+ m_mmc_prg_bank[2] = 0x4e;
+ m_mmc_prg_bank[3] = 0x4f;
+ set_prg(m_prg_base, m_prg_mask);
+}
+
+void nes_waixing_g_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0xff, 0xff, 0);
+
+ memset(mapper_ram, 0, sizeof(mapper_ram));
+ m_mmc_prg_bank[0] = 0x00;
+ m_mmc_prg_bank[1] = 0x01;
+ m_mmc_prg_bank[2] = 0x3e;
+ m_mmc_prg_bank[3] = 0x3f;
+ m_mmc_vrom_bank[0] = 0x00;
+ m_mmc_vrom_bank[1] = 0x02;
+ 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_mmc_vrom_bank[6] = 0x01;
+ m_mmc_vrom_bank[7] = 0x03;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+}
+
+void nes_waixing_j_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_waixing_j_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ mmc3_common_initialize(0xff, 0xff, 0);
+
+ m_reg[0] = 0x01;
+ m_reg[1] = 0x02;
+ m_reg[2] = 0x7e;
+ m_reg[3] = 0x7f;
+ set_prg(m_prg_base, m_prg_mask);
+}
+
+void nes_waixing_sh2_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_waixing_sh2_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg[0] = m_reg[1] = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_waixing_sec_device::device_start()
+{
+ mmc3_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_waixing_sec_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+
+ m_reg = 0;
+ mmc3_common_initialize(0xff, 0xff, 0);
+}
+
+void nes_waixing_sgz_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_irq_enable));
+ save_item(NAME(m_irq_enable_latch));
+ save_item(NAME(m_irq_count));
+ save_item(NAME(m_irq_count_latch));
+ save_item(NAME(m_mmc_vrom_bank));
+}
+
+void nes_waixing_sgz_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(m_prg_chunks - 1);
+ chr8(0, m_chr_source);
+
+ m_irq_enable = 0;
+ m_irq_enable_latch = 0;
+ m_irq_count = 0;
+ m_irq_count_latch = 0;
+
+ memset(m_mmc_vrom_bank, 0, sizeof(m_mmc_vrom_bank));
+}
+
+void nes_waixing_sgzlz_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_latch));
+}
+
+void nes_waixing_sgzlz_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_latch = 0;
+}
+
+void nes_waixing_ffv_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_waixing_ffv_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg16_89ab(0);
+ prg16_cdef(0x1f);
+ chr8(0, m_chr_source);
+
+ m_reg[0] = m_reg[1] = 0;
+}
+
+void nes_waixing_wxzs_device::device_start()
+{
+ common_start();
+}
+
+void nes_waixing_wxzs_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_waixing_dq8_device::device_start()
+{
+ common_start();
+}
+
+void nes_waixing_dq8_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+}
+
+void nes_waixing_wxzs2_device::device_start()
+{
+ common_start();
+}
+
+void nes_waixing_wxzs2_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+ set_nt_mirroring(PPU_MIRROR_VERT);
+}
+
+void nes_waixing_fs304_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_waixing_fs304_device::pcb_reset()
+{
+ m_chr_source = m_vrom_chunks ? CHRROM : CHRRAM;
+ prg32(0);
+ chr8(0, m_chr_source);
+
+ m_reg[0] = m_reg[1] = 0;
+}
+
+
+
+
+
+/*-------------------------------------------------
+ mapper specific handlers
+ -------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Waixing Board Type A
+
+ Games: Columbus - Ougon no Yoake (C), Ji Jia Zhan Shi,
+ Jia A Fung Yun, Wei Luo Chuan Qi
+
+ This mapper is quite similar to MMC3, but with two differences:
+ mirroring is not the same, and when VROM banks 8,9 are accessed
+ they point to CHRRAM and not CHRROM.
+
+ iNES: mapper 74
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+/* MIRROR_LOW and MIRROR_HIGH are swapped! */
+void nes_waixing_a_device::set_mirror(UINT8 nt)
+{
+ switch (nt)
+ {
+ case 0:
+ case 1:
+ set_nt_mirroring(nt ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 2:
+ set_nt_mirroring(PPU_MIRROR_LOW);
+ break;
+ case 3:
+ set_nt_mirroring(PPU_MIRROR_HIGH);
+ break;
+ default:
+ LOG_MMC(("Mapper set NT to invalid value %02x", nt));
+ break;
+ }
+}
+
+/* Luo Ke Ren X only works with this */
+void nes_waixing_a_device::chr_cb(int start, int bank, int source)
+{
+ int chr_src = (bank <= 9) ? CHRRAM : CHRROM;
+ chr1_x(start, bank, chr_src);
+}
+
+/* Ji Jia Zhan Shi only works with this */
+void nes_waixing_a1_device::chr_cb(int start, int bank, int source)
+{
+ int chr_src = ((bank == 8) || (bank == 9)) ? CHRRAM : CHRROM;
+ chr1_x(start, bank, chr_src);
+}
+
+WRITE8_MEMBER(nes_waixing_a_device::waixing_write)
+{
+ LOG_MMC(("waixing_write, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x2000:
+ set_mirror(data); //maybe data & 0x03?
+ break;
+
+ case 0x2001:
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+READ8_MEMBER(nes_waixing_a_device::read_l)
+{
+ LOG_MMC(("waixing read_l, offset: %04x\n", offset));
+ offset += 0x100;
+ if (offset >= 0x1000 && offset < 0x1400)
+ return mapper_ram[offset & 0x3ff];
+ else
+ return 0xff;
+}
+
+WRITE8_MEMBER(nes_waixing_a_device::write_l)
+{
+ LOG_MMC(("waixing write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+ if (offset >= 0x1000 && offset < 0x1400)
+ mapper_ram[offset & 0x3ff] = data;
+}
+
+
+/*-------------------------------------------------
+
+ Waixing Board Type B
+
+ Games: Sugoro Quest (C)
+
+ MMC3 clone. This is a minor modification of Mapper 74,
+ in the sense that it is the same board except for the
+ CHRRAM pages.
+
+ iNES: mapper 191
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_waixing_b_device::chr_cb(int start, int bank, int source)
+{
+ int chr_src = BIT(bank, 7) ? CHRRAM : CHRROM;
+ chr1_x(start, bank, chr_src);
+}
+
+/*-------------------------------------------------
+
+ Waixing Board Type C
+
+ Games: Ying Lie Qun Xia Zhuan, Young Chivalry
+
+ MMC3 clone. This is a minor modification of Mapper 74,
+ in the sense that it is the same board except for the
+ CHRRAM pages.
+
+ iNES: mapper 192
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_waixing_c_device::chr_cb(int start, int bank, int source)
+{
+ int chr_src = ((bank == 0x08) || (bank == 0x09) || (bank == 0x0a) || (bank == 0x0b)) ? CHRRAM : CHRROM;
+ chr1_x(start, bank, chr_src);
+}
+
+/*-------------------------------------------------
+
+ Waixing Board Type D
+
+ Games: Super Robot Taisen (C)
+
+ MMC3 clone. This is a minor modification of Mapper 74,
+ in the sense that it is the same board except for the
+ CHRRAM pages.
+
+ iNES: mapper 194
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_waixing_d_device::chr_cb(int start, int bank, int source)
+{
+ int chr_src = (bank < 0x02) ? CHRRAM : CHRROM;
+ chr1_x(start, bank, chr_src);
+}
+
+/*-------------------------------------------------
+
+ Waixing Board Type E
+
+ Games: Captain Tsubasa Vol. II (C), Chaos World, God
+ Slayer (C), Zu Qiu Xiao Jiang
+
+ MMC3 clone. This is a minor modification of Mapper 74,
+ in the sense that it is the same board except for the
+ CHRRAM pages.
+
+ iNES: mapper 195
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_waixing_e_device::chr_cb(int start, int bank, int source)
+{
+ int chr_src = (bank < 0x04) ? CHRRAM : CHRROM;
+ chr1_x(start, bank, chr_src);
+}
+
+
+/*-------------------------------------------------
+
+ Waixing Board Type F
+
+ Games: Tenchi wo Kurau II (C)
+
+ MMC3 clone.
+
+ iNES: mapper 198
+
+ In MESS: Preliminary support.
+
+ -------------------------------------------------*/
+
+void nes_waixing_f_device::chr_cb(int start, int bank, int source)
+{
+ chr1_x(start, bank, CHRRAM);
+}
+
+void nes_waixing_f_device::prg_cb(int start, int bank)
+{
+// if (bank > 0x3f)
+// bank = 0x40 | (bank & 0xf);
+ prg8_x(start, bank);
+}
+
+void nes_waixing_f_device::set_prg( int prg_base, int prg_mask )
+{
+ UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0;
+
+ prg_cb(0, m_mmc_prg_bank[0 ^ prg_flip]);
+ prg_cb(1, m_mmc_prg_bank[1]);
+ prg_cb(2, m_mmc_prg_bank[2 ^ prg_flip]);
+ prg_cb(3, m_mmc_prg_bank[3]);
+}
+
+WRITE8_MEMBER(nes_waixing_f_device::write_h)
+{
+ UINT8 cmd;
+ LOG_MMC(("waixing_f write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ cmd = m_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
+ case 2: case 3: case 4: case 5:
+ m_mmc_vrom_bank[cmd] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ m_mmc_prg_bank[cmd - 6] = data;
+ //printf("prg bank %d value %x\n", cmd - 6, data);
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ }
+ break;
+
+ case 0x2001:
+ break;
+
+ default:
+ waixing_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Waixing Board Type G
+
+ Games: San Guo Zhi 2, Dragon Ball Z Gaiden (C), Dragon
+ Ball Z II (C)
+
+ MMC3 clone, capable of switching all 4 PRG banks
+
+ iNES: mapper 199
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_waixing_g_device::chr_cb(int start, int bank, int source)
+{
+ int chr_src = (bank < 0x08) ? CHRRAM : CHRROM;
+ chr1_x(start, bank, chr_src);
+}
+
+void nes_waixing_g_device::set_chr(UINT8 chr, int chr_base, int chr_mask)
+{
+ UINT8 chr_page = (m_latch & 0x80) >> 5;
+
+ chr_cb(chr_page ^ 0, chr_base | (m_mmc_vrom_bank[0] & chr_mask), chr);
+ chr_cb(chr_page ^ 1, chr_base | (m_mmc_vrom_bank[6] & chr_mask), chr);
+ chr_cb(chr_page ^ 2, chr_base | (m_mmc_vrom_bank[1] & chr_mask), chr);
+ chr_cb(chr_page ^ 3, chr_base | (m_mmc_vrom_bank[7] & chr_mask), chr);
+ chr_cb(chr_page ^ 4, chr_base | (m_mmc_vrom_bank[2] & chr_mask), chr);
+ chr_cb(chr_page ^ 5, chr_base | (m_mmc_vrom_bank[3] & chr_mask), chr);
+ chr_cb(chr_page ^ 6, chr_base | (m_mmc_vrom_bank[4] & chr_mask), chr);
+ chr_cb(chr_page ^ 7, chr_base | (m_mmc_vrom_bank[5] & chr_mask), chr);
+}
+
+WRITE8_MEMBER(nes_waixing_g_device::write_h)
+{
+ UINT8 cmd;
+ LOG_MMC(("waixing_g write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ cmd = m_latch & 0x0f;
+ switch (cmd)
+ {
+ case 0: case 1:
+ case 2: case 3: case 4: case 5:
+ m_mmc_vrom_bank[cmd] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ m_mmc_prg_bank[cmd - 6] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ case 0x0a: case 0x0b:
+ m_mmc_vrom_bank[cmd - 4] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ }
+ break;
+
+ default:
+ waixing_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Waixing Board Type H
+
+ Games: Ying Xiong Yuan Yi Jing Chuan Qi, Yong Zhe Dou E
+ Long - Dragon Quest VII
+
+ MMC3 clone. More info to come.
+
+ Notice that Chinese Zelda translation stops working if
+ WRAM protect bit is ignored (i.e. if writes to 0x2001
+ are skipped)! OTOH, Chinese Monster Maker 1/2 translations
+ and Zheng Ba ShiJi stop working if WRAM protect is
+ accounted. So we split the board into two subtypes
+
+ iNES: mapper 245
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+void nes_waixing_h_device::chr_cb(int start, int bank, int source)
+{
+ if (source == CHRROM)
+ chr1_x(start, bank, source);
+}
+
+WRITE8_MEMBER(nes_waixing_h_device::write_h)
+{
+ UINT8 cmd;
+ LOG_MMC(("waixing_h write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ cmd = m_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank!
+ m_prg_base = (data << 5) & 0x40;
+ m_prg_mask = 0x3f;
+ set_prg(m_prg_base, m_prg_mask);
+ case 1:
+ case 2: case 3: case 4: case 5:
+ m_mmc_vrom_bank[cmd] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ m_mmc_prg_bank[cmd - 6] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ case 0x0a: case 0x0b: // CHR switches in 1K banks only, and bank1 & bank3 are controlled by these
+ m_mmc_vrom_bank[cmd - 4] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ }
+ break;
+
+ case 0x2001:
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+WRITE8_MEMBER(nes_waixing_h1_device::write_h)
+{
+ UINT8 cmd;
+ LOG_MMC(("waixing_h1 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ cmd = m_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: // in this case we set prg_base in addition to m_mmc_vrom_bank!
+ m_prg_base = (data << 5) & 0x40;
+ m_prg_mask = 0x3f;
+ set_prg(m_prg_base, m_prg_mask);
+ case 1:
+ case 2: case 3: case 4: case 5:
+ m_mmc_vrom_bank[cmd] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ m_mmc_prg_bank[cmd - 6] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ case 0x0a: case 0x0b: // CHR switches in 1K banks only, and bank1 & bank3 are controlled by these
+ m_mmc_vrom_bank[cmd - 4] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ }
+ break;
+
+ default:
+ txrom_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Waixing Board Type J
+
+ Games: Final Fantasy III (C)
+
+ MMC3 clone.
+
+ In MESS: Preliminary support.
+
+ -------------------------------------------------*/
+
+void nes_waixing_j_device::set_prg( int prg_base, int prg_mask )
+{
+ UINT8 prg_flip = (m_latch & 0x40) ? 2 : 0;
+
+ prg_cb(0, m_reg[0 ^ prg_flip]);
+ prg_cb(1, m_reg[1]);
+ prg_cb(2, m_reg[2 ^ prg_flip]);
+ prg_cb(3, m_reg[3]);
+}
+
+WRITE8_MEMBER(nes_waixing_j_device::write_h)
+{
+ UINT8 cmd;
+ LOG_MMC(("waixing_f write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x6001)
+ {
+ case 0x0001:
+ cmd = m_latch & 0x07;
+ switch (cmd)
+ {
+ case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
+ case 2: case 3: case 4: case 5:
+ m_mmc_vrom_bank[cmd] = data;
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ break;
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ m_reg[cmd - 6] = data;
+ set_prg(m_prg_base, m_prg_mask);
+ break;
+ }
+ break;
+
+// case 0x2001:
+// break;
+
+ default:
+ waixing_write(space, offset, data, mem_mask);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Waixing SH2 Board
+
+ Games: Fire Emblem (C) and Fire Emblem Gaiden (C)
+
+ MMC3 clone with different access to CHR
+
+ iNES: mapper 165
+
+ In MESS: Partially Supported.
+
+ -------------------------------------------------*/
+
+void nes_waixing_sh2_device::chr_cb(int start, int bank, int source)
+{
+ chr4_0(m_reg[0], m_reg[0] ? CHRRAM : CHRROM);
+ chr4_4(m_reg[1], m_reg[1] ? CHRRAM : CHRROM);
+}
+
+READ8_MEMBER(nes_waixing_sh2_device::chr_r)
+{
+ int bank = offset >> 10;
+ UINT8 val = m_chr_access[bank][offset & 0x3ff]; // this would be usual return value
+ int chr_helper;
+
+ switch (offset & 0xff8)
+ {
+ case 0xfd0: chr_helper = (bank & 0x4) | 0x0; break;
+ case 0xfe8: chr_helper = (bank & 0x4) | 0x2; break;
+ default: return val;
+ }
+
+ m_reg[offset >> 12] = chr_helper;
+ if (offset & 0x1000)
+ chr4_4(m_reg[1], m_reg[1] ? CHRRAM : CHRROM);
+ else
+ chr4_0(m_reg[0], m_reg[0] ? CHRRAM : CHRROM);
+
+ return val;
+}
+
+/*-------------------------------------------------
+
+ Waixing Board with Security Chip
+
+ Games: Duo Bao Xiao Ying Hao - Guang Ming yu An Hei Chuan Shuo,
+ Myth Struggle, San Shi Liu Ji, Shui Hu Zhuan
+
+ MMC3 clone
+
+ iNES: mapper 249
+
+ In MESS: Partially Supported.
+
+ -------------------------------------------------*/
+
+void nes_waixing_sec_device::prg_cb(int start, int bank)
+{
+ if (m_reg)
+ bank = BITSWAP8(bank & 0x1f,7,6,5,2,1,3,4,0);
+
+ prg8_x(start, bank);
+}
+
+void nes_waixing_sec_device::chr_cb(int start, int bank, int source)
+{
+ if (m_reg)
+ bank = BITSWAP8(bank, 5,4,2,6,7,3,1,0);
+
+ chr1_x(start, bank, source);
+}
+
+WRITE8_MEMBER(nes_waixing_sec_device::write_l)
+{
+ LOG_MMC(("waixing_sec write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100;
+
+ if (offset == 0x1000)
+ {
+ m_reg = data & 0x02;
+ set_prg(m_prg_base, m_prg_mask);
+ set_chr(m_chr_source, m_chr_base, m_chr_mask);
+ }
+}
+
+/*-------------------------------------------------
+
+ Waixing San Guo Zhi Board
+
+ Games: San Guo Zhi
+
+ This board uses Konami IRQ
+
+ iNES: mapper 252
+
+ In MESS: Unsupported.
+
+ -------------------------------------------------*/
+
+// same as Konami IRQ
+void nes_waixing_sgz_device::hblank_irq(int scanline, int vblank, int blanked)
+{
+ /* Increment & check the IRQ scanline counter */
+ if (m_irq_enable && (++m_irq_count == 0x100))
+ {
+ m_irq_count = m_irq_count_latch;
+ m_irq_enable = m_irq_enable_latch;
+ machine().device("maincpu")->execute().set_input_line(M6502_IRQ_LINE, HOLD_LINE);
+ }
+}
+
+WRITE8_MEMBER(nes_waixing_sgz_device::write_h)
+{
+ UINT8 helper, bank;
+ LOG_MMC(("waixing_sgz write_h, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset & 0x7000)
+ {
+ case 0x0000:
+ prg8_89(data);
+ break;
+ case 0x2000:
+ prg8_ab(data);
+ break;
+ case 0x3000:
+ case 0x4000:
+ case 0x5000:
+ case 0x6000:
+ bank = ((offset & 0x7000) - 0x3000) / 0x0800 + ((offset & 0x0008) >> 3);
+ helper = offset & 0x04;
+ if (helper)
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0x0f) | ((data & 0x0f) << 4);
+ else
+ m_mmc_vrom_bank[bank] = (m_mmc_vrom_bank[bank] & 0xf0) | (data & 0x0f);
+ chr1_x(bank, m_mmc_vrom_bank[bank], CHRROM);
+ break;
+ case 0x7000:
+ switch (offset & 0x0c)
+ {
+ case 0x00:
+ m_irq_count_latch = (m_irq_count_latch & 0xf0) | (data & 0x0f);
+ break;
+ case 0x04:
+ m_irq_count_latch = (m_irq_count_latch & 0x0f) | ((data & 0x0f) << 4);
+ break;
+ case 0x08:
+ m_irq_enable = data & 0x02;
+ m_irq_count_latch = data & 0x01;
+ if (data & 0x02)
+ m_irq_count = m_irq_count_latch;
+ break;
+ case 0x0c:
+ m_irq_enable = m_irq_enable_latch;
+ break;
+ }
+ break;
+ }
+}
+
+
+/*-------------------------------------------------
+
+ Waixing San Guo Zhong Lie Zhuan Board
+
+ Games: Fan Kong Jing Ying, San Guo Zhong Lie Zhuan, Xing
+ Ji Zheng Ba
+
+ iNES: mapper 178
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_waixing_sgzlz_device::write_l)
+{
+ LOG_MMC(("waixing_sgzlz write_l, offset: %04x, data: %02x\n", offset, data));
+
+ switch (offset)
+ {
+ case 0x700:
+ set_nt_mirroring(data ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ break;
+ case 0x701:
+ m_latch = (m_latch & 0x0c) | ((data >> 1) & 0x03);
+ prg32(m_latch);
+ break;
+ case 0x702:
+ m_latch = (m_latch & 0x03) | ((data << 2) & 0x0c);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Waixing Final Fantasy V Board
+
+ Games: Darkseed, Digital Dragon, Final Fantasy V, Pocket
+ Monster Red
+
+ iNES: mapper 164
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_waixing_ffv_device::write_l)
+{
+ UINT8 helper;
+ LOG_MMC(("waixing_ffv write_l, offset: %04x, data: %02x\n", offset, data));
+ offset += 0x100; /* the checks work better on addresses */
+
+ if ((offset & 0x1200) == 0x1000)
+ {
+ m_reg[BIT(offset, 8)] = data;
+ helper = BIT(m_reg[1], 0) << 5;
+ switch (m_reg[0] & 0x70)
+ {
+ case 0x00:
+ case 0x20:
+ case 0x40:
+ case 0x60:
+ prg16_89ab(helper | ((m_reg[0] >> 1) & 0x10) | (m_reg[0] & 0x0f));
+ prg16_cdef(helper & 0x1f);
+ break;
+ case 0x50:
+ prg32((helper >> 1) | (m_reg[0] & 0x0f));
+ break;
+ case 0x70:
+ prg16_89ab(helper | ((m_reg[0] << 1) & 0x10) | (m_reg[0] & 0x0f));
+ prg16_cdef(helper & 0x1f);
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------
+
+ Waixing Zhan Shi Board
+
+ Games: Wai Xing Zhan Shi
+
+ Simple mapper: writes to 0x8000-0xffff sets prg32 banks to
+ (offset>>3)&f. written data&3 sets the mirroring (with
+ switched high/low compared to the standard one).
+
+ A crc check is required to support Dragon Quest VIII (which
+ uses a slightly different board)
+
+ iNES: mapper 242
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_waixing_wxzs_device::write_h)
+{
+ LOG_MMC(("waixing_zs write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(offset >> 3);
+
+ switch (data & 0x03)
+ {
+ case 0: set_nt_mirroring(PPU_MIRROR_VERT); break;
+ case 1: set_nt_mirroring(PPU_MIRROR_HORZ); break;
+ case 2: set_nt_mirroring(PPU_MIRROR_LOW); break;
+ case 3: set_nt_mirroring(PPU_MIRROR_HIGH); break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Waixing Dragon Quest VIII Board
+
+ Games: Dragon Quest VIII
+
+ Simple mapper: writes to 0x8000-0xffff sets prg32 banks to
+ (offset>>3)&f.
+
+ iNES: mapper 242
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_waixing_dq8_device::write_h)
+{
+ LOG_MMC(("waixing_dq8 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ prg32(offset >> 3);
+}
+
+
+/*-------------------------------------------------
+
+ Waixing WXZS2 / PS2 board
+
+ Games: Wai Xing Zhan Shi 2 (aka Phantasy Star 2),
+ Bao Xiao Tien Guo, Bio Hazard, Pokemon Gold, Subor (R)
+
+ iNES: mapper 15
+
+ In MESS: Supported
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_waixing_wxzs2_device::write_h)
+{
+ UINT8 flip = (data & 0x80) >> 7;
+ UINT8 helper = (data & 0x7f) << 1;
+
+ LOG_MMC(("waixing_wxzs2 write_h, offset: %04x, data: %02x\n", offset, data));
+
+ set_nt_mirroring(BIT(data, 6) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+
+ switch (offset & 0x0fff)
+ {
+ case 0x000:
+ prg8_89((helper + 0) ^ flip);
+ prg8_ab((helper + 1) ^ flip);
+ prg8_cd((helper + 2) ^ flip);
+ prg8_ef((helper + 3) ^ flip);
+ break;
+ case 0x001:
+ helper |= flip;
+ prg8_89(helper);
+ prg8_ab(helper + 1);
+ prg8_cd(helper + 1);
+ prg8_ef(helper + 1);
+ break;
+ case 0x002:
+ helper |= flip;
+ prg8_89(helper);
+ prg8_ab(helper);
+ prg8_cd(helper);
+ prg8_ef(helper);
+ break;
+ case 0x003:
+ helper |= flip;
+ prg8_89(helper);
+ prg8_ab(helper + 1);
+ prg8_cd(helper);
+ prg8_ef(helper + 1);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+
+ Board UNL-FS304
+
+ Games: A Link to the Past by Waixing
+
+ iNES: mapper 162? (only found in UNIF format)
+
+ In MESS: Supported.
+
+ -------------------------------------------------*/
+
+WRITE8_MEMBER(nes_waixing_fs304_device::write_l)
+{
+ LOG_MMC(("fs304 write_l, offset: %04x, data: %02x\n", offset, data));
+ int bank;
+ offset += 0x100;
+
+ if (offset >= 0x1000)
+ {
+ m_reg[(offset >> 8) & 3] = data;
+ bank = ((m_reg[2] & 0x0f) << 4) | BIT(m_reg[1], 1) | (m_reg[0] & 0x0e);
+ prg32(bank);
+ chr8(0, CHRRAM);
+ }
+}
diff --git a/src/mess/machine/nes_waixing.h b/src/mess/machine/nes_waixing.h
new file mode 100644
index 00000000000..6b35527f41f
--- /dev/null
+++ b/src/mess/machine/nes_waixing.h
@@ -0,0 +1,394 @@
+#ifndef __NES_WAIXING_H
+#define __NES_WAIXING_H
+
+#include "machine/nes_mmc3.h"
+
+
+// ======================> nes_waixing_a_device
+
+class nes_waixing_a_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_a_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);
+ nes_waixing_a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(read_l);
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual DECLARE_WRITE8_MEMBER(waixing_write);
+ virtual DECLARE_WRITE8_MEMBER(write_h) { waixing_write(space, offset, data, mem_mask); }
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+protected:
+ void set_mirror(UINT8 nt);
+ UINT8 mapper_ram[0x400];
+};
+
+
+// ======================> nes_waixing_a1_device
+
+class nes_waixing_a1_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_a1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void chr_cb(int start, int bank, int source);
+};
+
+
+// ======================> nes_waixing_b_device
+
+class nes_waixing_b_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_b_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void chr_cb(int start, int bank, int source);
+};
+
+
+// ======================> nes_waixing_c_device
+
+class nes_waixing_c_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void chr_cb(int start, int bank, int source);
+};
+
+
+// ======================> nes_waixing_d_device
+
+class nes_waixing_d_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void chr_cb(int start, int bank, int source);
+};
+
+
+// ======================> nes_waixing_e_device
+
+class nes_waixing_e_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void chr_cb(int start, int bank, int source);
+};
+
+
+// ======================> nes_waixing_f_device
+
+class nes_waixing_f_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_f_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+private:
+ virtual void set_prg(int prg_base, int prg_mask);
+};
+
+
+// ======================> nes_waixing_g_device
+
+class nes_waixing_g_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_g_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+protected:
+ virtual void set_chr(UINT8 chr, int chr_base, int chr_mask);
+};
+
+
+// ======================> nes_waixing_h_device
+
+class nes_waixing_h_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_h_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);
+ nes_waixing_h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+ virtual void chr_cb(int start, int bank, int source);
+
+ // This PCB does not have 1K of internal RAM, so it's not derived from nes_waixing_a_device!!
+};
+
+
+// ======================> nes_waixing_h1_device
+
+class nes_waixing_h1_device : public nes_waixing_h_device
+{
+public:
+ // construction/destruction
+ nes_waixing_h1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ // This variant does not ignore the wram protect!
+};
+
+
+// ======================> nes_waixing_i_device
+
+class nes_waixing_i_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_i_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // still to emulate this variant
+};
+
+
+// ======================> nes_waixing_j_device
+
+class nes_waixing_j_device : public nes_waixing_a_device
+{
+public:
+ // construction/destruction
+ nes_waixing_j_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+
+protected:
+ virtual void set_prg(int prg_base, int prg_mask);
+ UINT8 m_reg[4];
+};
+
+
+// ======================> nes_waixing_sh2_device
+
+class nes_waixing_sh2_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_sh2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_READ8_MEMBER(chr_r);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_reg[2];
+};
+
+
+// ======================> nes_waixing_sec_device
+
+class nes_waixing_sec_device : public nes_txrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_sec_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+ virtual void prg_cb(int start, int bank);
+ virtual void chr_cb(int start, int bank, int source);
+
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_reg;
+};
+
+
+// ======================> nes_waixing_sgz_device
+
+class nes_waixing_sgz_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_sgz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void hblank_irq(int scanline, int vblank, int blanked);
+ virtual void pcb_reset();
+
+protected:
+ UINT16 m_irq_count, m_irq_count_latch;
+ int m_irq_enable, m_irq_enable_latch;
+
+ UINT8 m_mmc_vrom_bank[8];
+};
+
+
+// ======================> nes_waixing_sgzlz_device
+
+class nes_waixing_sgzlz_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_sgzlz_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_latch;
+};
+
+
+// ======================> nes_waixing_ffv_device
+
+class nes_waixing_ffv_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_ffv_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_reg[2];
+};
+
+
+// ======================> nes_waixing_wxzs_device
+
+class nes_waixing_wxzs_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_wxzs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_waixing_dq8_device
+
+class nes_waixing_dq8_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_dq8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_waixing_wxzs2_device
+
+class nes_waixing_wxzs2_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_wxzs2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_h);
+
+ virtual void pcb_reset();
+};
+
+
+// ======================> nes_waixing_fs304_device
+
+class nes_waixing_fs304_device : public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_waixing_fs304_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual DECLARE_WRITE8_MEMBER(write_l);
+
+ virtual void pcb_reset();
+
+protected:
+ UINT8 m_reg[2];
+};
+
+
+
+
+
+// device type definition
+extern const device_type NES_WAIXING_A;
+extern const device_type NES_WAIXING_A1;
+extern const device_type NES_WAIXING_B;
+extern const device_type NES_WAIXING_C;
+extern const device_type NES_WAIXING_D;
+extern const device_type NES_WAIXING_E;
+extern const device_type NES_WAIXING_F;
+extern const device_type NES_WAIXING_G;
+extern const device_type NES_WAIXING_H;
+extern const device_type NES_WAIXING_H1;
+extern const device_type NES_WAIXING_I;
+extern const device_type NES_WAIXING_J;
+extern const device_type NES_WAIXING_SH2;
+extern const device_type NES_WAIXING_SEC;
+extern const device_type NES_WAIXING_SGZ;
+extern const device_type NES_WAIXING_SGZLZ;
+extern const device_type NES_WAIXING_FFV;
+extern const device_type NES_WAIXING_WXZS;
+extern const device_type NES_WAIXING_DQ8;
+extern const device_type NES_WAIXING_WXZS2;
+extern const device_type NES_WAIXING_FS304;
+
+
+#endif