From c488308495840ae060f4c8953c4a7be601b0c8ca Mon Sep 17 00:00:00 2001
From: kazblox <>
Date: Sun, 12 Mar 2017 19:42:44 -0400
Subject: nes: Add Subor Type 2 board. (nw)
nes: Fix debug output when reading iNES headers. (nw)
nes/ppu2c0x: Improved PAL clone timings. (nw)
nes/n2a03: Refactored clock definitions [includes other drivers using the
N2A03] (nw)
nes: Improved refresh rates and timings to reflect nesdev (nw)
nes: Softlist improvements and corrections [koko, mkgoogoo and others] (nw)
nes: Verified koko in the softlist as a good dump (nw)
nes: Softlist additions [subor5, subor6, subor10, subor11, subor13, doolybld]
(nw)
New not working machines added: Subor SB-486, M82 Display Unit (PAL) (nw)
nes: Marked drpcjr as NOT WORKING due to missing hardware. (nw)
New working machines added: Micro Genius IQ-501, Micro Genius IQ-502, Dendy Classic 2 (nw)
nes: marked dendy as a clone of iq501 (nw)
---
hash/nes.xml | 290 ++++++++++++++++++++++++----------
scripts/src/bus.lua | 2 +
src/devices/bus/nes/konami.cpp | 10 +-
src/devices/bus/nes/nes_carts.cpp | 1 +
src/devices/bus/nes/nes_carts.h | 1 +
src/devices/bus/nes/nes_ines.hxx | 6 +-
src/devices/bus/nes/nes_pcb.hxx | 1 +
src/devices/bus/nes/nes_slot.h | 2 +-
src/devices/bus/nes/pirate.cpp | 120 --------------
src/devices/bus/nes/pirate.h | 38 -----
src/devices/bus/nes/subor.cpp | 325 ++++++++++++++++++++++++++++++++++++++
src/devices/bus/nes/subor.h | 78 +++++++++
src/devices/bus/nes/sunsoft.cpp | 6 +-
src/devices/cpu/m6502/n2a03.h | 10 +-
src/devices/video/ppu2c0x.cpp | 16 +-
src/devices/video/ppu2c0x.h | 58 ++++---
src/mame/audio/dkong.cpp | 4 +-
src/mame/drivers/cham24.cpp | 3 +-
src/mame/drivers/famibox.cpp | 2 +-
src/mame/drivers/multigam.cpp | 2 +-
src/mame/drivers/nes.cpp | 118 ++++++++++----
src/mame/drivers/playch10.cpp | 4 +-
src/mame/drivers/punchout.cpp | 4 +-
src/mame/drivers/vsnes.cpp | 6 +-
src/mame/includes/nes.h | 4 -
src/mame/mame.lst | 7 +-
26 files changed, 787 insertions(+), 331 deletions(-)
create mode 100644 src/devices/bus/nes/subor.cpp
create mode 100644 src/devices/bus/nes/subor.h
diff --git a/hash/nes.xml b/hash/nes.xml
index da222b15c20..56794f211c1 100644
--- a/hash/nes.xml
+++ b/hash/nes.xml
@@ -8906,6 +8906,31 @@
+
+ Dooly Bravo Land
+ 1992
+ Daou Infosys
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Door Door (Jpn)
1985
@@ -22341,14 +22366,14 @@
-
-
-
-
-
-
+
+
+
-
+
+
+
+
@@ -47070,11 +47095,18 @@ preliminary proto for the PAL version, still running on NTSC systems) or the gfx
+
+
+
+
+
+
+
-
+
-
+
@@ -62144,30 +62176,6 @@ preliminary proto for the PAL version, still running on NTSC systems) or the gfx
-
- Subor Kara OK
- 19??
- Subor
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Karaoke (Asia, Chinese)
19??
@@ -69277,24 +69285,23 @@ Also notice that VRAM & WRAM are probably incorrect for some of these sets, at t
-
+
+
GSD Super Student Computer Cartridge (Chi)
19??
- <unknown>
+ Gao Sheng Da
+
+
-
-
-
-
@@ -69503,7 +69510,7 @@ Also notice that VRAM & WRAM are probably incorrect for some of these sets, at t
ABM Study Card V5.0 (Chi)
- 19??
+ 1995?
<unknown>
@@ -69525,8 +69532,8 @@ Also notice that VRAM & WRAM are probably incorrect for some of these sets, at t
ASDER PC-95 (Asia?)
- 19??
- <unknown>
+ 1995?
+ Asder
@@ -69703,8 +69710,8 @@ Also notice that VRAM & WRAM are probably incorrect for some of these sets, at t
Hong Da Study Cartridge (Chi)
- 19??
- <unknown>
+ 1995?
+ Hong Da
@@ -69830,27 +69837,6 @@ Also notice that VRAM & WRAM are probably incorrect for some of these sets, at t
-
- Xiao Ba Wang Zhong Ying Wen Dian Nao Xue Xi Ji III (Chi)
- 19??
- Subor
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Cang Ku Shi Jia Dong Nao Jin (Chi)
19??
@@ -69917,25 +69903,80 @@ Also notice that VRAM & WRAM are probably incorrect for some of these sets, at t
+
+ Subor v13.0 (Chi)
+ 2000?
+ Subor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Subor v11.0 (Chi)
+ 2000?
+ Subor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Subor v10.0 (Chi)
+ 199?
+ Subor
+
+
+
+
+
+
+
+
+
+
+
+
Subor v8.0 (Chi)
@@ -69951,16 +69992,51 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
-
-
-
+
+
+
+
+ Subor v6.0 (Chi)
+ 199?
+ Subor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Subor v5.0 (Chi)
+ 1996
+ Subor
+
+
+
+
+
+
+
+
+
+
Subor v4.0 (Chi)
- 19??
+ 1995
Subor
@@ -69970,7 +70046,7 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
-
+
@@ -69980,19 +70056,39 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
+
+ Subor v3.0 (Chi, with Dr. Mario)
+ 1994
+ Subor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- Subor v3.0 (Chi)
- 19??
+ Subor v3.0 (Chi, with Chinese Chess)
+ 1994
Subor
+
-
+
@@ -70000,7 +70096,7 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
Subor v1.1 (Chi)
- 19??
+ 1993?
Subor
@@ -70023,7 +70119,7 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
Subor v1.0 (Rus)
- 19??
+ 1994
Subor
@@ -70033,7 +70129,7 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
-
+
@@ -70045,7 +70141,7 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
Subor v1.0 (Rus, Alt)
- 19??
+ 1994
Subor
@@ -70055,7 +70151,7 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
-
+
@@ -70063,7 +70159,7 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
Magistr v1.0 (Rus)
- 19??
+ 199?
<unknown>
@@ -70084,7 +70180,7 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
Simba's v1.0 (Rus)
- 19??
+ 199?
<unknown>
@@ -70145,6 +70241,28 @@ Subor v15.0 (this shows Windows 2002 on the title screen)
+
+ Subor Karaoke
+ 19??
+ Subor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Ren Shi Ma Xue Xi v1.0 (Chi)
19??
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index b05cc795e85..faf3fbb7840 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -1909,6 +1909,8 @@ if (BUSES["NES"]~=null) then
MAME_DIR .. "src/devices/bus/nes/sachen.h",
MAME_DIR .. "src/devices/bus/nes/somari.cpp",
MAME_DIR .. "src/devices/bus/nes/somari.h",
+ MAME_DIR .. "src/devices/bus/nes/subor.cpp",
+ MAME_DIR .. "src/devices/bus/nes/subor.h",
MAME_DIR .. "src/devices/bus/nes/sunsoft.cpp",
MAME_DIR .. "src/devices/bus/nes/sunsoft.h",
MAME_DIR .. "src/devices/bus/nes/sunsoft_dcs.cpp",
diff --git a/src/devices/bus/nes/konami.cpp b/src/devices/bus/nes/konami.cpp
index e807b813091..fd6de204003 100644
--- a/src/devices/bus/nes/konami.cpp
+++ b/src/devices/bus/nes/konami.cpp
@@ -39,8 +39,6 @@
#define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
-#define N2A03_DEFAULTCLOCK (21477272.724 / 12)
-
//-------------------------------------------------
// constructor
//-------------------------------------------------
@@ -642,7 +640,9 @@ static MACHINE_CONFIG_FRAGMENT( vrc6 )
// additional sound hardware
MCFG_SPEAKER_STANDARD_MONO("addon")
- MCFG_SOUND_ADD("vrc6snd", VRC6, N2A03_DEFAULTCLOCK)
+ // TODO: this is not how VRC6 clock signaling works!
+ // The board uses the CLK pin in reality, not hardcoded NTSC values!
+ MCFG_SOUND_ADD("vrc6snd", VRC6, XTAL_21_4772MHz/12)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5)
MACHINE_CONFIG_END
@@ -774,7 +774,9 @@ static MACHINE_CONFIG_FRAGMENT( vrc7 )
// additional sound hardware
MCFG_SPEAKER_STANDARD_MONO("addon")
- MCFG_SOUND_ADD("ym", YM2413, N2A03_DEFAULTCLOCK)
+ // TODO: this is not how VRC7 clock signaling works!
+ // The board uses the CLK pin in reality, not hardcoded NTSC values!
+ MCFG_SOUND_ADD("ym", YM2413, XTAL_21_4772MHz/12)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.5)
MACHINE_CONFIG_END
diff --git a/src/devices/bus/nes/nes_carts.cpp b/src/devices/bus/nes/nes_carts.cpp
index cc692ee9f0d..5d04a57b77d 100644
--- a/src/devices/bus/nes/nes_carts.cpp
+++ b/src/devices/bus/nes/nes_carts.cpp
@@ -216,6 +216,7 @@ SLOT_INTERFACE_START(nes_cart)
SLOT_INTERFACE_INTERNAL("daou_306", NES_DAOU306)
SLOT_INTERFACE_INTERNAL("subor0", NES_SUBOR0)
SLOT_INTERFACE_INTERNAL("subor1", NES_SUBOR1)
+ SLOT_INTERFACE_INTERNAL("subor2", NES_SUBOR2)
SLOT_INTERFACE_INTERNAL("cc21", NES_CC21)
SLOT_INTERFACE_INTERNAL("xiaozy", NES_XIAOZY)
SLOT_INTERFACE_INTERNAL("edu2k", NES_EDU2K)
diff --git a/src/devices/bus/nes/nes_carts.h b/src/devices/bus/nes/nes_carts.h
index 13fa3f20037..85bc4b429fb 100644
--- a/src/devices/bus/nes/nes_carts.h
+++ b/src/devices/bus/nes/nes_carts.h
@@ -55,6 +55,7 @@
#include "rexsoft.h"
#include "sachen.h"
#include "somari.h"
+#include "subor.h"
#include "tengen.h"
#include "txc.h"
#include "waixing.h"
diff --git a/src/devices/bus/nes/nes_ines.hxx b/src/devices/bus/nes/nes_ines.hxx
index 760fa9b130e..a515afe7dec 100644
--- a/src/devices/bus/nes/nes_ines.hxx
+++ b/src/devices/bus/nes/nes_ines.hxx
@@ -691,7 +691,7 @@ void nes_cart_slot_device::call_load_ines()
if (!ines20)
{
logerror("Loaded game in iNES format:\n");
- logerror("-- Mapper %d\n", mapper);
+ logerror("-- Mapper %u\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);
@@ -707,8 +707,8 @@ void nes_cart_slot_device::call_load_ines()
else
{
logerror("Loaded game in Extended iNES format:\n");
- logerror("-- Mapper: %d\n", mapper);
- logerror("-- Submapper: %d\n", (header[8] & 0xf0) >> 4);
+ logerror("-- Mapper: %u\n", mapper);
+ logerror("-- Submapper: %u\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);
diff --git a/src/devices/bus/nes/nes_pcb.hxx b/src/devices/bus/nes/nes_pcb.hxx
index 5496c7e2e0f..8d91645f300 100644
--- a/src/devices/bus/nes/nes_pcb.hxx
+++ b/src/devices/bus/nes/nes_pcb.hxx
@@ -185,6 +185,7 @@ static const nes_pcb pcb_list[] =
{ "daou_306", OPENCORP_DAOU306 },
{ "subor0", SUBOR_TYPE0 },
{ "subor1", SUBOR_TYPE1 },
+ { "subor2", SUBOR_TYPE2 },
{ "cc21", UNL_CC21 },
{ "xiaozy", UNL_XIAOZY },
{ "edu2k", UNL_EDU2K },
diff --git a/src/devices/bus/nes/nes_slot.h b/src/devices/bus/nes/nes_slot.h
index 2cdb784e78a..04c79c3c831 100644
--- a/src/devices/bus/nes/nes_slot.h
+++ b/src/devices/bus/nes/nes_slot.h
@@ -113,7 +113,7 @@ enum
/* 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,
+ HENGG_SRICH, HENGG_XHZS, HENGG_SHJY3, SUBOR_TYPE0, SUBOR_TYPE1, SUBOR_TYPE2,
KAISER_KS7058, KAISER_KS7032, KAISER_KS7022, KAISER_KS7017,
KAISER_KS7012, KAISER_KS7013B, KAISER_KS202, KAISER_KS7031,
KAISER_KS7016, KAISER_KS7037,
diff --git a/src/devices/bus/nes/pirate.cpp b/src/devices/bus/nes/pirate.cpp
index 059293ede9d..cded3deb09d 100644
--- a/src/devices/bus/nes/pirate.cpp
+++ b/src/devices/bus/nes/pirate.cpp
@@ -41,8 +41,6 @@ const device_type NES_FUKUTAKE = device_creator;
const device_type NES_FUTUREMEDIA = device_creator;
const device_type NES_MAGSERIES = device_creator;
const device_type NES_DAOU306 = device_creator;
-const device_type NES_SUBOR0 = device_creator;
-const device_type NES_SUBOR1 = device_creator;
const device_type NES_CC21 = device_creator;
const device_type NES_XIAOZY = device_creator;
const device_type NES_EDU2K = device_creator;
@@ -84,16 +82,6 @@ nes_daou306_device::nes_daou306_device(const machine_config &mconfig, const char
{
}
-nes_subor0_device::nes_subor0_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t 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_t 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_t clock)
: nes_nrom_device(mconfig, NES_CC21, "NES Cart CC-21 PCB", tag, owner, clock, "nes_cc21", __FILE__)
{
@@ -236,38 +224,6 @@ void nes_daou306_device::pcb_reset()
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();
@@ -730,82 +686,6 @@ WRITE8_MEMBER(nes_daou306_device::write_h)
}
}
-/*-------------------------------------------------
-
- Subor bootleg board Type 0
-
- iNES: mapper 167
-
- -------------------------------------------------*/
-
-WRITE8_MEMBER(nes_subor0_device::write_h)
-{
- uint8_t 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_t 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
diff --git a/src/devices/bus/nes/pirate.h b/src/devices/bus/nes/pirate.h
index 3a8bd1c09ea..b17ce1ada9d 100644
--- a/src/devices/bus/nes/pirate.h
+++ b/src/devices/bus/nes/pirate.h
@@ -118,44 +118,6 @@ private:
};
-// ======================> 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_t clock);
-
- // device-level overrides
- virtual void device_start() override;
- virtual DECLARE_WRITE8_MEMBER(write_h) override;
-
- virtual void pcb_reset() override;
-
-private:
- uint8_t 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_t clock);
-
- // device-level overrides
- virtual void device_start() override;
- virtual DECLARE_WRITE8_MEMBER(write_h) override;
-
- virtual void pcb_reset() override;
-
-private:
- uint8_t m_reg[4];
-};
-
-
// ======================> nes_cc21_device
class nes_cc21_device : public nes_nrom_device
diff --git a/src/devices/bus/nes/subor.cpp b/src/devices/bus/nes/subor.cpp
new file mode 100644
index 00000000000..65bf2e18e7e
--- /dev/null
+++ b/src/devices/bus/nes/subor.cpp
@@ -0,0 +1,325 @@
+// license:BSD-3-Clause
+// copyright-holders:Kaz
+/***********************************************************************************************************
+
+ NES/Famicom cartridge emulation for Subor PCBs
+
+ TODO:
+ - Implement Type 2 variant for Subor Karaoke.
+ (Subor Karaoke updates banks differently.)
+ - Check and verify CHR banking in Type 2 boards
+ - Investigate connection with DANCE 2000 board; likely made by ex-Subor staff!
+
+ ***********************************************************************************************************/
+
+#include "emu.h"
+#include "subor.h"
+
+#ifdef NES_PCB_DEBUG
+#define VERBOSE 1
+#else
+#define VERBOSE 0
+#endif
+
+#define LOG_MMC(...) do { if (VERBOSE) logerror(__VA_ARGS__); } while (0)
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type NES_SUBOR0 = device_creator;
+const device_type NES_SUBOR1 = device_creator;
+const device_type NES_SUBOR2 = device_creator;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// nes_subor0_device - constructor
+//-------------------------------------------------
+
+nes_subor0_device::nes_subor0_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nes_nrom_device(mconfig, NES_SUBOR0, "NES Cart Subor Type 0 PCB", tag, owner, clock, "nes_subor0", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// nes_subor1_device - constructor
+//-------------------------------------------------
+
+nes_subor1_device::nes_subor1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nes_nrom_device(mconfig, NES_SUBOR1, "NES Cart Subor Type 1 PCB", tag, owner, clock, "nes_subor1", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// nes_subor2_device - constructor
+//-------------------------------------------------
+
+nes_subor2_device::nes_subor2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : nes_nrom_device(mconfig, NES_SUBOR2, "NES Cart Subor Type 2 PCB", tag, owner, clock, "nes_subor2", __FILE__),
+ m_switch_reg(0),
+ m_bank_reg(0),
+ m_chr_banking(0),
+ m_page(0)
+{
+}
+
+/*-------------------------------------------------
+ device_start
+-------------------------------------------------*/
+
+void nes_subor0_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_subor1_device::device_start()
+{
+ common_start();
+ save_item(NAME(m_reg));
+}
+
+void nes_subor2_device::device_start()
+{
+ common_start();
+
+ save_item(NAME(m_switch_reg));
+ save_item(NAME(m_bank_reg));
+ save_item(NAME(m_chr_banking));
+}
+
+/*-------------------------------------------------
+ pcb_reset
+-------------------------------------------------*/
+
+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::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_subor2_device::pcb_reset()
+{
+ m_switch_reg = 0;
+ m_bank_reg = 0;
+ m_chr_banking = true;
+ m_page = 0;
+
+ prg16_89ab(0);
+ prg16_cdef(0);
+}
+
+/*-------------------------------------------------
+ mapper specific handlers
+-------------------------------------------------*/
+
+/*-------------------------------------------------
+
+ Subor educational cartridge board Type 0:
+ iNES Mapper 167
+
+ Subor educational cartridge board Type 1:
+ iNES Mapper 166
+
+ Subor educational cartridge board Type 2:
+ No iNES mapper as of yet.
+
+ Notes on Type 2 variants:
+ Implementation based upon VirtuaNESUp source code
+ and studying VirtuaNESEx. The latter makes the
+ read at 0x5300 return 0x8F, perhaps as a form
+ of copy protection?
+
+ There are two revisions of Type 2 that are
+ currently known;
+
+ Subor v5.0- 16k/32k PRG banking combo
+
+ Subor Karaoke- 32k PRG banking
+
+-------------------------------------------------*/
+
+/*-------------------------------------------------
+ ppu_latch
+-------------------------------------------------*/
+
+void nes_subor2_device::ppu_latch(offs_t offset)
+{
+ /* CHR banks are conditionally changed midframe */
+ /* If this is split off onto the external PPU latch, every edge case works */
+ if (m_chr_banking)
+ {
+ if ( (m_page == 2) || (m_page == 1 && m_switch_reg == 2) )
+ {
+ chr4_0(1, CHRRAM);
+ }
+ else
+ {
+ chr4_0(0, CHRRAM);
+ }
+ }
+}
+
+/*-------------------------------------------------
+ nt
+-------------------------------------------------*/
+
+READ8_MEMBER(nes_subor2_device::nt_r)
+{
+ int page = ((offset & 0xc00) >> 10);
+
+ /* Nametable reads report the current page; this seems to work without issues */
+ m_page = page;
+
+ return m_nt_access[page][offset & 0x3ff];
+}
+
+/*-------------------------------------------------
+ update_banks
+-------------------------------------------------*/
+
+void nes_subor2_device::update_banks()
+{
+ switch (m_switch_reg)
+ {
+ case 0x00:
+ case 0x02:
+ m_chr_banking = true;
+ set_nt_mirroring(PPU_MIRROR_VERT);
+ break;
+ case 0x01:
+ case 0x03:
+ m_chr_banking = true;
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ break;
+ case 0x05:
+ /* Subor v11.0 needs this, and VirtuaNESEx keeps it specific to this cart */
+ /* But leaving it as it is doesn't seem to be an issue for now */
+ m_chr_banking = false;
+ set_nt_mirroring(PPU_MIRROR_HORZ);
+ break;
+ }
+
+ if (m_switch_reg >= 0x04)
+ {
+ prg32(m_bank_reg);
+ }
+ else
+ {
+ prg16_89ab(m_bank_reg);
+ prg16_cdef(0);
+ }
+}
+
+/*-------------------------------------------------
+ read
+-------------------------------------------------*/
+
+READ8_MEMBER(nes_subor2_device::read_l)
+{
+ LOG_MMC("subor2 read_l, offset: %04x\n", offset);
+
+ if (offset == 0x1200)
+ {
+ return 0x8F;
+ }
+ return m_open_bus;
+}
+
+/*-------------------------------------------------
+ write
+-------------------------------------------------*/
+
+WRITE8_MEMBER(nes_subor0_device::write_h)
+{
+ uint8_t 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);
+}
+
+WRITE8_MEMBER(nes_subor1_device::write_h)
+{
+ uint8_t 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);
+}
+
+WRITE8_MEMBER(nes_subor2_device::write_l)
+{
+ LOG_MMC("subor2 write_l, offset: %04x, data: %02x\n", offset, data);
+
+ switch (offset)
+ {
+ case 0x0F00:
+ m_bank_reg = data;
+ update_banks();
+ break;
+ case 0x1100:
+ m_switch_reg = data & 7;
+ update_banks();
+ break;
+ }
+}
\ No newline at end of file
diff --git a/src/devices/bus/nes/subor.h b/src/devices/bus/nes/subor.h
new file mode 100644
index 00000000000..167561f3b36
--- /dev/null
+++ b/src/devices/bus/nes/subor.h
@@ -0,0 +1,78 @@
+// license:BSD-3-Clause
+// copyright-holders:Kaz
+#ifndef MAME_BUS_NES_SUBOR_H
+#define MAME_BUS_NES_SUBOR_H
+
+#include "nxrom.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> 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_t clock);
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual DECLARE_WRITE8_MEMBER(write_h) override;
+
+ virtual void pcb_reset() override;
+
+private:
+ uint8_t 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_t clock);
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual DECLARE_WRITE8_MEMBER(write_h) override;
+
+ virtual void pcb_reset() override;
+
+private:
+ uint8_t m_reg[4];
+};
+
+// ======================> nes_subor2_device
+
+class nes_subor2_device :
+ public nes_nrom_device
+{
+public:
+ // construction/destruction
+ nes_subor2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // device-level overrides
+ virtual void device_start() override;
+ virtual DECLARE_READ8_MEMBER(nt_r) override;
+ virtual DECLARE_WRITE8_MEMBER(write_l) override;
+ virtual DECLARE_READ8_MEMBER(read_l) override;
+
+ virtual void ppu_latch(offs_t offset) override;
+ virtual void pcb_reset() override;
+
+private:
+ void update_banks();
+ uint8_t m_switch_reg, m_bank_reg, m_chr_banking, m_page;
+};
+
+// device type definition
+extern const device_type NES_SUBOR0;
+extern const device_type NES_SUBOR1;
+extern const device_type NES_SUBOR2;
+
+#endif /* MAME_BUS_NES_SUBOR_H */
\ No newline at end of file
diff --git a/src/devices/bus/nes/sunsoft.cpp b/src/devices/bus/nes/sunsoft.cpp
index 82bb39ed1eb..2394d67dad8 100644
--- a/src/devices/bus/nes/sunsoft.cpp
+++ b/src/devices/bus/nes/sunsoft.cpp
@@ -608,14 +608,14 @@ WRITE8_MEMBER(nes_sunsoft_5_device::write_h)
// 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
+ // TODO: this is not how Sunsoft 5B clock signaling works!
+ // The board uses the CLK pin in reality, not hardcoded NTSC values!
+ MCFG_SOUND_ADD("ay", YM2149, (XTAL_21_4772MHz/12)/2) // divide by 2 for the internal divider
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "addon", 0.50)
MACHINE_CONFIG_END
diff --git a/src/devices/cpu/m6502/n2a03.h b/src/devices/cpu/m6502/n2a03.h
index 9a236839c59..3faff1fb202 100644
--- a/src/devices/cpu/m6502/n2a03.h
+++ b/src/devices/cpu/m6502/n2a03.h
@@ -72,7 +72,15 @@ private:
};
-#define N2A03_DEFAULTCLOCK (21477272.724 / 12)
+/* These are the official XTAL values and clock rates used by Nintendo for
+ manufacturing throughout the production of the 2A03. PALC_APU_CLOCK is
+ the clock rate devised by UMC(?) for PAL Famicom clone hardware. */
+
+#define N2A03_NTSC_XTAL XTAL_21_4772MHz
+#define N2A03_PAL_XTAL XTAL_26_601712MHz
+#define NTSC_APU_CLOCK (N2A03_NTSC_XTAL/12) /* 1.7897726666... MHz */
+#define PAL_APU_CLOCK (N2A03_PAL_XTAL/16) /* 1.662607 MHz */
+#define PALC_APU_CLOCK (N2A03_PAL_XTAL/15) /* 1.77344746666... MHz */
enum {
N2A03_IRQ_LINE = m6502_device::IRQ_LINE,
diff --git a/src/devices/video/ppu2c0x.cpp b/src/devices/video/ppu2c0x.cpp
index 670e504b351..0d787209d15 100644
--- a/src/devices/video/ppu2c0x.cpp
+++ b/src/devices/video/ppu2c0x.cpp
@@ -79,6 +79,7 @@ const device_type PPU_2C02 = device_creator;
const device_type PPU_2C03B = device_creator;
const device_type PPU_2C04 = device_creator;
const device_type PPU_2C07 = device_creator;
+const device_type PPU_PALC = device_creator;
const device_type PPU_2C05_01 = device_creator;
const device_type PPU_2C05_02 = device_creator;
const device_type PPU_2C05_03 = device_creator;
@@ -152,6 +153,7 @@ ppu2c0x_device::ppu2c0x_device(const machine_config &mconfig, device_type type,
memset(m_palette_ram, 0, ARRAY_LENGTH(m_palette_ram));
m_scanlines_per_frame = PPU_NTSC_SCANLINES_PER_FRAME;
+ m_vblank_first_scanline = PPU_VBLANK_FIRST_SCANLINE;
/* usually, no security value... */
m_security_value = 0;
@@ -181,6 +183,13 @@ ppu2c07_device::ppu2c07_device(const machine_config &mconfig, const char *tag, d
m_scanlines_per_frame = PPU_PAL_SCANLINES_PER_FRAME;
}
+// PAL clones
+ppupalc_device::ppupalc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_device(mconfig, PPU_PALC, "Generic PAL Clone PPU", tag, owner, clock, "ppupalc", __FILE__)
+{
+ m_scanlines_per_frame = PPU_PAL_SCANLINES_PER_FRAME;
+ m_vblank_first_scanline = PPU_VBLANK_FIRST_SCANLINE_PALC;
+}
+
// The PPU_2C05 variants have different protection value, set at device start, but otherwise are all the same...
// Vs. Unisystem (Ninja Jajamaru Kun)
ppu2c05_01_device::ppu2c05_01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : ppu2c0x_device(mconfig, PPU_2C05_01, "2C05_01 PPU", tag, owner, clock, "ppu2c05_01", __FILE__)
@@ -254,6 +263,7 @@ void ppu2c0x_device::device_start()
save_item(NAME(m_back_color));
save_item(NAME(m_scan_scale));
save_item(NAME(m_scanlines_per_frame));
+ save_item(NAME(m_vblank_first_scanline));
save_item(NAME(m_regs));
save_item(NAME(m_palette_ram));
save_item(NAME(m_draw_phase));
@@ -469,7 +479,7 @@ void ppu2c0x_device::device_timer(emu_timer &timer, device_timer_id id, int para
{
case TIMER_HBLANK:
blanked = (m_regs[PPU_CONTROL1] & (PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES)) == 0;
- vblank = ((m_scanline >= PPU_VBLANK_FIRST_SCANLINE - 1) && (m_scanline < m_scanlines_per_frame - 1)) ? 1 : 0;
+ vblank = ((m_scanline >= m_vblank_first_scanline - 1) && (m_scanline < m_scanlines_per_frame - 1)) ? 1 : 0;
//update_scanline();
@@ -489,7 +499,7 @@ void ppu2c0x_device::device_timer(emu_timer &timer, device_timer_id id, int para
case TIMER_SCANLINE:
blanked = (m_regs[PPU_CONTROL1] & (PPU_CONTROL1_BACKGROUND | PPU_CONTROL1_SPRITES)) == 0;
- vblank = ((m_scanline >= PPU_VBLANK_FIRST_SCANLINE - 1) && (m_scanline < m_scanlines_per_frame - 1)) ? 1 : 0;
+ vblank = ((m_scanline >= m_vblank_first_scanline - 1) && (m_scanline < m_scanlines_per_frame - 1)) ? 1 : 0;
int next_scanline;
/* if a callback is available, call it */
@@ -505,7 +515,7 @@ void ppu2c0x_device::device_timer(emu_timer &timer, device_timer_id id, int para
// logerror("starting scanline %d (MAME %d, beam %d)\n", m_scanline, device->m_screen->vpos(), device->m_screen->hpos());
/* Note: this is called at the _end_ of each scanline */
- if (m_scanline == PPU_VBLANK_FIRST_SCANLINE)
+ if (m_scanline == m_vblank_first_scanline)
{
// logerror("vblank starting\n");
/* We just entered VBLANK */
diff --git a/src/devices/video/ppu2c0x.h b/src/devices/video/ppu2c0x.h
index d426630eb64..ec050df8d8c 100644
--- a/src/devices/video/ppu2c0x.h
+++ b/src/devices/video/ppu2c0x.h
@@ -47,33 +47,34 @@ enum
// bit definitions for (some of) the registers
enum
{
- PPU_CONTROL0_INC = 0x04,
- PPU_CONTROL0_SPR_SELECT = 0x08,
- PPU_CONTROL0_CHR_SELECT = 0x10,
- PPU_CONTROL0_SPRITE_SIZE = 0x20,
- PPU_CONTROL0_NMI = 0x80,
-
- PPU_CONTROL1_DISPLAY_MONO = 0x01,
- PPU_CONTROL1_BACKGROUND_L8 = 0x02,
- PPU_CONTROL1_SPRITES_L8 = 0x04,
- PPU_CONTROL1_BACKGROUND = 0x08,
- PPU_CONTROL1_SPRITES = 0x10,
- PPU_CONTROL1_COLOR_EMPHASIS = 0xe0,
-
- PPU_STATUS_8SPRITES = 0x20,
- PPU_STATUS_SPRITE0_HIT = 0x40,
- PPU_STATUS_VBLANK = 0x80
+ PPU_CONTROL0_INC = 0x04,
+ PPU_CONTROL0_SPR_SELECT = 0x08,
+ PPU_CONTROL0_CHR_SELECT = 0x10,
+ PPU_CONTROL0_SPRITE_SIZE = 0x20,
+ PPU_CONTROL0_NMI = 0x80,
+
+ PPU_CONTROL1_DISPLAY_MONO = 0x01,
+ PPU_CONTROL1_BACKGROUND_L8 = 0x02,
+ PPU_CONTROL1_SPRITES_L8 = 0x04,
+ PPU_CONTROL1_BACKGROUND = 0x08,
+ PPU_CONTROL1_SPRITES = 0x10,
+ PPU_CONTROL1_COLOR_EMPHASIS = 0xe0,
+
+ PPU_STATUS_8SPRITES = 0x20,
+ PPU_STATUS_SPRITE0_HIT = 0x40,
+ PPU_STATUS_VBLANK = 0x80
};
enum
{
- PPU_NTSC_SCANLINES_PER_FRAME = 262,
- PPU_PAL_SCANLINES_PER_FRAME = 312,
+ PPU_NTSC_SCANLINES_PER_FRAME = 262,
+ PPU_PAL_SCANLINES_PER_FRAME = 312,
- PPU_BOTTOM_VISIBLE_SCANLINE = 239,
- PPU_VBLANK_FIRST_SCANLINE = 241,
- PPU_VBLANK_LAST_SCANLINE_NTSC = 260,
- PPU_VBLANK_LAST_SCANLINE_PAL = 310
+ PPU_BOTTOM_VISIBLE_SCANLINE = 239,
+ PPU_VBLANK_FIRST_SCANLINE = 241,
+ PPU_VBLANK_FIRST_SCANLINE_PALC = 291,
+ PPU_VBLANK_LAST_SCANLINE_NTSC = 260,
+ PPU_VBLANK_LAST_SCANLINE_PAL = 310
// Both the scanline immediately before and immediately after VBLANK
// are non-rendering and non-vblank.
@@ -96,6 +97,8 @@ enum
MCFG_PPU2C0X_ADD(_tag, PPU_2C04)
#define MCFG_PPU2C07_ADD(_tag) \
MCFG_PPU2C0X_ADD(_tag, PPU_2C07)
+#define MCFG_PPUPALC_ADD(_tag) \
+ MCFG_PPU2C0X_ADD(_tag, PPU_PALC)
#define MCFG_PPU2C05_01_ADD(_tag) \
MCFG_PPU2C0X_ADD(_tag, PPU_2C05_01)
#define MCFG_PPU2C05_02_ADD(_tag) \
@@ -189,7 +192,7 @@ public:
required_device m_cpu;
std::unique_ptr m_bitmap; /* target bitmap */
- std::unique_ptr m_spriteram; /* sprite ram */
+ std::unique_ptr m_spriteram; /* sprite ram */
std::unique_ptr m_colortable; /* color table modified at run time */
std::unique_ptr m_colortable_mono; /* monochromatic color table modified at run time */
int m_scanline; /* scanline count */
@@ -210,9 +213,10 @@ public:
int m_sprite_page; /* current sprite page */
int m_back_color; /* background color */
int m_color_base;
- uint8_t m_palette_ram[0x20]; /* shouldn't be in main memory! */
+ uint8_t m_palette_ram[0x20]; /* shouldn't be in main memory! */
int m_scan_scale; /* scan scale */
int m_scanlines_per_frame; /* number of scanlines per frame */
+ int m_vblank_first_scanline; /* the very first scanline where VBLANK occurs */
int m_security_value; /* 2C05 protection */
int m_tilecount; /* MMC5 can change attributes to subsets of the 34 visible tiles */
int m_draw_phase; /* MMC5 uses different regs for BG and OAM */
@@ -261,6 +265,11 @@ public:
ppu2c07_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
};
+class ppupalc_device : public ppu2c0x_device {
+public:
+ ppupalc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+};
+
class ppu2c05_01_device : public ppu2c0x_device {
public:
ppu2c05_01_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
@@ -288,6 +297,7 @@ extern const device_type PPU_2C02; // NTSC NES
extern const device_type PPU_2C03B; // Playchoice 10
extern const device_type PPU_2C04; // Vs. Unisystem
extern const device_type PPU_2C07; // PAL NES
+extern const device_type PPU_PALC; // PAL Clones
extern const device_type PPU_2C05_01; // Vs. Unisystem (Ninja Jajamaru Kun)
extern const device_type PPU_2C05_02; // Vs. Unisystem (Mighty Bomb Jack)
extern const device_type PPU_2C05_03; // Vs. Unisystem (Gumshoe)
diff --git a/src/mame/audio/dkong.cpp b/src/mame/audio/dkong.cpp
index 28d6d366719..196e9a040fd 100644
--- a/src/mame/audio/dkong.cpp
+++ b/src/mame/audio/dkong.cpp
@@ -1429,11 +1429,11 @@ MACHINE_CONFIG_END
MACHINE_CONFIG_FRAGMENT( dkong3_audio )
- MCFG_CPU_ADD("n2a03a", N2A03,N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("n2a03a", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(dkong3_sound1_map)
MCFG_CPU_VBLANK_INT_DRIVER("screen", dkong_state, nmi_line_pulse)
- MCFG_CPU_ADD("n2a03b", N2A03,N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("n2a03b", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(dkong3_sound2_map)
MCFG_CPU_VBLANK_INT_DRIVER("screen", dkong_state, nmi_line_pulse)
diff --git a/src/mame/drivers/cham24.cpp b/src/mame/drivers/cham24.cpp
index a6ad7a89a63..09e79421f4c 100644
--- a/src/mame/drivers/cham24.cpp
+++ b/src/mame/drivers/cham24.cpp
@@ -311,10 +311,9 @@ GFXDECODE_END
static MACHINE_CONFIG_START( cham24, cham24_state )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", N2A03, N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("maincpu", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(cham24_map)
-
/* video hardware */
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(60)
diff --git a/src/mame/drivers/famibox.cpp b/src/mame/drivers/famibox.cpp
index 31ba4eca55d..d9576552172 100644
--- a/src/mame/drivers/famibox.cpp
+++ b/src/mame/drivers/famibox.cpp
@@ -546,7 +546,7 @@ void famibox_state::machine_start()
static MACHINE_CONFIG_START( famibox, famibox_state )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", N2A03, N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("maincpu", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(famibox_map)
/* video hardware */
diff --git a/src/mame/drivers/multigam.cpp b/src/mame/drivers/multigam.cpp
index dee9c71d0fb..103e8b87b3a 100644
--- a/src/mame/drivers/multigam.cpp
+++ b/src/mame/drivers/multigam.cpp
@@ -1214,7 +1214,7 @@ MACHINE_START_MEMBER(multigam_state,supergm3)
static MACHINE_CONFIG_START( multigam, multigam_state )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", N2A03, N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("maincpu", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(multigam_map)
diff --git a/src/mame/drivers/nes.cpp b/src/mame/drivers/nes.cpp
index 2e22e40df43..c14797a03c1 100644
--- a/src/mame/drivers/nes.cpp
+++ b/src/mame/drivers/nes.cpp
@@ -56,16 +56,16 @@ void nes_state::ppu_nmi(int *ppu_regs)
static MACHINE_CONFIG_START( nes, nes_state )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", N2A03, NTSC_CLOCK)
+ MCFG_CPU_ADD("maincpu", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(nes_map)
MCFG_SCREEN_ADD("screen", RASTER)
- MCFG_SCREEN_REFRESH_RATE(60.098)
+ MCFG_SCREEN_REFRESH_RATE(60.0988)
// This isn't used so much to calulate the vblank duration (the PPU code tracks that manually) but to determine
// the number of cycles in each scanline for the PPU scanline timer. Since the PPU has 20 vblank scanlines + 2
// non-rendering scanlines, we compensate. This ends up being 2500 cycles for the non-rendering portion, 2273
// cycles for the actual vblank period.
- MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((113.66/(NTSC_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_NTSC-PPU_VBLANK_FIRST_SCANLINE+1+2)))
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((113.66/(NTSC_APU_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_NTSC-PPU_VBLANK_FIRST_SCANLINE+1+2)))
MCFG_SCREEN_SIZE(32*8, 262)
MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 30*8-1)
MCFG_SCREEN_UPDATE_DRIVER(nes_state, screen_update_nes)
@@ -97,15 +97,13 @@ static MACHINE_CONFIG_START( nes, nes_state )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( nespal, nes )
-
/* basic machine hardware */
// MCFG_CPU_MODIFY("maincpu")
-// MCFG_CPU_CLOCK(PAL_CLOCK) // this doesn't get inherited by the APU with DERIVED_CLOCK!
+// MCFG_CPU_CLOCK(PAL_APU_CLOCK) // this doesn't get inherited by the APU with DERIVED_CLOCK!
- MCFG_CPU_REPLACE("maincpu", N2A03, PAL_CLOCK)
+ MCFG_CPU_REPLACE("maincpu", N2A03, PAL_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(nes_map)
-
MCFG_DEVICE_REMOVE("ppu")
MCFG_PPU2C07_ADD("ppu")
MCFG_PPU2C0X_CPU("maincpu")
@@ -113,36 +111,44 @@ static MACHINE_CONFIG_DERIVED( nespal, nes )
/* video hardware */
MCFG_SCREEN_MODIFY("screen")
- MCFG_SCREEN_REFRESH_RATE(53.355)
- MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((106.53/(PAL_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_PAL-PPU_VBLANK_FIRST_SCANLINE+1+2)))
+ MCFG_SCREEN_REFRESH_RATE(50.0070)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((106.53/(PAL_APU_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_PAL-PPU_VBLANK_FIRST_SCANLINE+1+2)))
MCFG_SCREEN_SIZE(32*8, 312)
MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 30*8-1)
+MACHINE_CONFIG_END
+static MACHINE_CONFIG_DERIVED( famicom, nes )
+ MCFG_DEVICE_REMOVE("ctrl1")
+ MCFG_DEVICE_REMOVE("ctrl2")
+ MCFG_NES_CONTROL_PORT_ADD("ctrl1", fc_control_port1_devices, "joypad")
+ MCFG_NES_CONTROL_PORT_ADD("ctrl2", fc_control_port2_devices, "joypad")
+ MCFG_FC_EXPANSION_PORT_ADD("exp", fc_expansion_devices, nullptr)
+ MCFG_NESCTRL_BRIGHTPIXEL_CB(nes_state, bright_pixel)
+ MCFG_SOFTWARE_LIST_ADD("flop_list", "famicom_flop")
+ MCFG_SOFTWARE_LIST_ADD("cass_list", "famicom_cass")
MACHINE_CONFIG_END
-static MACHINE_CONFIG_DERIVED( dendy, nes )
-
- /* basic machine hardware */
+static MACHINE_CONFIG_DERIVED( nespalc, nespal )
// MCFG_CPU_MODIFY( "maincpu" )
-// MCFG_CPU_CLOCK( 26601712/15 ) // this doesn't get inherited by the APU with DERIVED_CLOCK!
+// MCFG_CPU_CLOCK(PALC_APU_CLOCK) // this doesn't get inherited by the APU with DERIVED_CLOCK!
- MCFG_CPU_REPLACE("maincpu", N2A03, 26601712/15 )/* 26.601712MHz / 15 == 1.77344746666... MHz */
+ MCFG_CPU_REPLACE("maincpu", N2A03, PALC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(nes_map)
+ /* UMC 6538 and friends -- extends time for rendering dummy scanlines */
MCFG_DEVICE_REMOVE("ppu")
- MCFG_PPU2C07_ADD("ppu")
+ MCFG_PPUPALC_ADD("ppu")
MCFG_PPU2C0X_CPU("maincpu")
MCFG_PPU2C0X_SET_NMI(nes_state, ppu_nmi)
/* video hardware */
MCFG_SCREEN_MODIFY("screen")
- MCFG_SCREEN_REFRESH_RATE(50.00697796827)
- MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((106.53/(PAL_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_PAL-PPU_VBLANK_FIRST_SCANLINE+1+2)))
-
+ MCFG_SCREEN_REFRESH_RATE(50.0070)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC((113.66/(PALC_APU_CLOCK/1000000)) * (PPU_VBLANK_LAST_SCANLINE_PAL-PPU_VBLANK_FIRST_SCANLINE_PALC+1+2)))
MACHINE_CONFIG_END
-static MACHINE_CONFIG_DERIVED( famicom, nes )
+static MACHINE_CONFIG_DERIVED( famipalc, nespalc )
MCFG_DEVICE_REMOVE("ctrl1")
MCFG_DEVICE_REMOVE("ctrl2")
MCFG_NES_CONTROL_PORT_ADD("ctrl1", fc_control_port1_devices, "joypad")
@@ -150,10 +156,16 @@ static MACHINE_CONFIG_DERIVED( famicom, nes )
MCFG_FC_EXPANSION_PORT_ADD("exp", fc_expansion_devices, nullptr)
MCFG_NESCTRL_BRIGHTPIXEL_CB(nes_state, bright_pixel)
- MCFG_SOFTWARE_LIST_ADD("flop_list", "famicom_flop")
MCFG_SOFTWARE_LIST_ADD("cass_list", "famicom_cass")
MACHINE_CONFIG_END
+static MACHINE_CONFIG_DERIVED( suborkbd, famipalc )
+ /* TODO: emulate the parallel port bus! */
+ MCFG_DEVICE_MODIFY("exp")
+ MCFG_SLOT_DEFAULT_OPTION("subor_keyboard")
+ MCFG_SLOT_FIXED(true)
+MACHINE_CONFIG_END
+
void nes_state::setup_disk(nes_disksys_device *slot)
{
if (slot)
@@ -285,6 +297,13 @@ ROM_START( m82 )
ROM_LOAD( "m82_v1_0.bin", 0x10000, 0x4000, CRC(7d56840a) SHA1(cbd2d14fa073273ba58367758f40d67fd8a9106d) )
ROM_END
+ROM_START( m82p )
+ /* same as m82 */
+ ROM_REGION( 0x14000, "maincpu", 0 ) /* Main RAM + program banks */
+ /* Banks to be mapped at 0xe000? More investigations needed... */
+ ROM_LOAD( "m82_v1_0.bin", 0x10000, 0x4000, CRC(7d56840a) SHA1(cbd2d14fa073273ba58367758f40d67fd8a9106d) )
+ROM_END
+
// see http://www.disgruntleddesigner.com/chrisc/drpcjr/index.html
// and http://www.disgruntleddesigner.com/chrisc/drpcjr/DrPCJrMemMap.txt
ROM_START( drpcjr )
@@ -296,14 +315,30 @@ ROM_START( drpcjr )
// ROM_LOAD("drpcjr_v1_5_gg.bin", 0x10000, 0x8000, CRC(98f2033b) SHA1(93c114da787a19279d1a46667c2f69b49e25d4f1) )
ROM_END
+ROM_START( iq501 )
+ ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM */
+ROM_END
+
+ROM_START( iq502 )
+ ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM */
+ROM_END
+
ROM_START( dendy )
ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM */
ROM_END
+ROM_START( dendy2 )
+ ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM */
+ROM_END
+
ROM_START( gchinatv )
ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM */
ROM_END
+ROM_START( sb486 )
+ ROM_REGION( 0x10000, "maincpu", ROMREGION_ERASE00 ) /* Main RAM */
+ROM_END
+
/***************************************************************************
Game driver(s)
@@ -311,12 +346,37 @@ ROM_END
***************************************************************************/
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME */
-CONS( 1985, nes, 0, 0, nes, nes, driver_device, 0, "Nintendo", "Nintendo Entertainment System / Famicom (NTSC)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
-CONS( 1987, nespal, nes, 0, nespal, nes, driver_device, 0, "Nintendo", "Nintendo Entertainment System (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
-CONS( 1983, famicom, nes, 0, famicom, famicom, nes_state, famicom, "Nintendo", "Famicom (NTSC)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
-CONS( 1983, fds, nes, 0, fds, famicom, nes_state, famicom, "Nintendo", "Famicom (w/ Disk System add-on)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
-CONS( 1986, famitwin, nes, 0, famitwin, famicom, nes_state, famicom, "Sharp", "Famicom Twin", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
-CONS( 198?, m82, nes, 0, nes, nes, driver_device, 0, "Nintendo", "M82 Display Unit", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
-CONS( 1996, drpcjr, nes, 0, famicom, famicom, nes_state, famicom, "Bung", "Doctor PC Jr", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
-CONS( 1992, dendy, nes, 0, dendy, nes, driver_device, 0, "Steepler", "Dendy Classic", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
-CONS( 198?, gchinatv, nes, 0, nespal, nes, driver_device, 0, "Golden China", "Golden China TV Game", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+
+/* Nintendo Entertainment System hardware */
+CONS( 1985, nes, 0, 0, nes, nes, driver_device, 0, "Nintendo", "Nintendo Entertainment System / Famicom (NTSC)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+CONS( 1987, nespal, nes, 0, nespal, nes, driver_device, 0, "Nintendo", "Nintendo Entertainment System (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+// M82 Display Unit
+// supports up to twelve cartridge slots
+CONS( 198?, m82, nes, 0, nes, nes, driver_device, 0, "Nintendo", "M82 Display Unit (NTSC)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+CONS( 198?, m82p, nes, 0, nespal, nes, driver_device, 0, "Nintendo", "M82 Display Unit (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+
+/* Famicom hardware */
+CONS( 1983, famicom, 0, 0, famicom, famicom, nes_state, famicom, "Nintendo", "Famicom", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+CONS( 1983, fds, famicom, 0, fds, famicom, nes_state, famicom, "Nintendo", "Famicom (w/ Disk System add-on)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+CONS( 1986, famitwin, famicom, 0, famitwin, famicom, nes_state, famicom, "Sharp", "Famicom Twin", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+
+/* Clone hardware */
+/* Many knockoffs using derivatives of the UMC board design, later incorporated into single CMOS chips, were manufactured before and past the end of the Famicom's timeline. */
+
+/* !! PAL clones documented here !! */
+// Famicom-based
+CONS( 1992, iq501, 0, 0, famipalc, nes, nes_state, famicom, "Micro Genius", "IQ-501", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+CONS( 1992, iq502, 0, 0, famipalc, nes, nes_state, famicom, "Micro Genius", "IQ-502", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+CONS( 1992, dendy, iq501, 0, famipalc, nes, nes_state, famicom, "Steepler", "Dendy Classic 1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+CONS( 1992, dendy2, iq502, 0, famipalc, nes, nes_state, famicom, "Steepler", "Dendy Classic 2", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+CONS( 198?, gchinatv, 0, 0, famipalc, nes, nes_state, famicom, "Golden China", "Golden China TV Game", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+
+// Subor/Xiao Ba Wang hardware and derivatives
+// These clones implement a keyboard and a parallel port for printing from a word processor. Later models have mice, PS/2 ports, serial ports and a floppy drive.
+CONS( 1993, sb486, 0, 0, suborkbd, nes, nes_state, famicom, "Subor", "SB-486", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
+
+/* !! NTSC clones documented here !! */
+// Famicom-based
+// Bung hardware
+// Mice, keyboard, etc, including a floppy drive that allows you to run games with a selection of 4 internal "mappers" available on the system.
+CONS( 1996, drpcjr, 0, 0, famicom, famicom, nes_state, famicom, "Bung", "Doctor PC Jr", MACHINE_IMPERFECT_GRAPHICS | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
\ No newline at end of file
diff --git a/src/mame/drivers/playch10.cpp b/src/mame/drivers/playch10.cpp
index f3a5a5f8722..0e42d8bb727 100644
--- a/src/mame/drivers/playch10.cpp
+++ b/src/mame/drivers/playch10.cpp
@@ -303,8 +303,6 @@ Notes & Todo:
#include "screen.h"
#include "speaker.h"
-/* clock frequency */
-#define N2A03_DEFAULTCLOCK (21477272.724 / 12)
/******************************************************************************/
@@ -654,7 +652,7 @@ static MACHINE_CONFIG_START( playch10, playch10_state )
MCFG_CPU_IO_MAP(bios_io_map)
MCFG_CPU_VBLANK_INT_DRIVER("top", playch10_state, playch10_interrupt)
- MCFG_CPU_ADD("cart", N2A03, N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("cart", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(cart_map)
diff --git a/src/mame/drivers/punchout.cpp b/src/mame/drivers/punchout.cpp
index 0003da071d5..d3bc387214c 100644
--- a/src/mame/drivers/punchout.cpp
+++ b/src/mame/drivers/punchout.cpp
@@ -648,7 +648,7 @@ static MACHINE_CONFIG_START( punchout, punchout_state )
MCFG_CPU_IO_MAP(punchout_io_map)
MCFG_CPU_VBLANK_INT_DRIVER("top", punchout_state, vblank_irq)
- MCFG_CPU_ADD("audiocpu", N2A03, XTAL_21_4772MHz/12)
+ MCFG_CPU_ADD("audiocpu", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(punchout_sound_map)
MCFG_CPU_VBLANK_INT_DRIVER("top", punchout_state, nmi_line_pulse)
@@ -681,7 +681,7 @@ static MACHINE_CONFIG_START( punchout, punchout_state )
MCFG_GENERIC_LATCH_8_ADD("soundlatch")
MCFG_GENERIC_LATCH_8_ADD("soundlatch2")
- MCFG_SOUND_ADD("vlm", VLM5030, XTAL_21_4772MHz/6)
+ MCFG_SOUND_ADD("vlm", VLM5030, N2A03_NTSC_XTAL/6)
MCFG_DEVICE_ADDRESS_MAP(AS_0, punchout_vlm_map)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.50)
MACHINE_CONFIG_END
diff --git a/src/mame/drivers/vsnes.cpp b/src/mame/drivers/vsnes.cpp
index 0b27c15c664..8895a0710cf 100644
--- a/src/mame/drivers/vsnes.cpp
+++ b/src/mame/drivers/vsnes.cpp
@@ -1702,7 +1702,7 @@ INPUT_PORTS_END
static MACHINE_CONFIG_START( vsnes, vsnes_state )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", N2A03,N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("maincpu", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(vsnes_cpu1_map)
/* some carts also trigger IRQs */
MCFG_MACHINE_RESET_OVERRIDE(vsnes_state,vsnes)
@@ -1769,10 +1769,10 @@ MACHINE_CONFIG_END
static MACHINE_CONFIG_START( vsdual, vsnes_state )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", N2A03,N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("maincpu", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(vsnes_cpu1_map)
/* some carts also trigger IRQs */
- MCFG_CPU_ADD("sub", N2A03,N2A03_DEFAULTCLOCK)
+ MCFG_CPU_ADD("sub", N2A03, NTSC_APU_CLOCK)
MCFG_CPU_PROGRAM_MAP(vsnes_cpu2_map)
/* some carts also trigger IRQs */
MCFG_MACHINE_RESET_OVERRIDE(vsnes_state,vsdual)
diff --git a/src/mame/includes/nes.h b/src/mame/includes/nes.h
index d6ce3d7761f..c9d5ec6470f 100644
--- a/src/mame/includes/nes.h
+++ b/src/mame/includes/nes.h
@@ -21,12 +21,8 @@
CONSTANTS
***************************************************************************/
-#define NTSC_CLOCK N2A03_DEFAULTCLOCK /* 1.789772 MHz */
-#define PAL_CLOCK (26601712.0/16) /* 1.662607 MHz */
-
#define NES_BATTERY_SIZE 0x2000
-
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 41f28100984..2168a84ad29 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -29101,13 +29101,18 @@ nprsp //
neptunp2 //
@source:nes.cpp
-dendy // Dendy (Classic russian famiclone)
+iq501 // Micro Genius IQ-501
+iq502 // Micro Genius IQ-502
+dendy // Dendy Classic (Russian import of IQ-501 famiclone)
+dendy2 // Dendy Classic 2 (Russian import of IQ-502 famiclone)
+sb486 // Subor/Xiao Ba Wang SB-486
drpcjr // Bung Doctor PC Jr
famicom // Nintendo Family Computer (a.k.a. Famicom)
famitwin // Sharp Famicom Twin System
fds // Nintendo Family Computer (a.k.a. Famicom) + Disk System add-on
gchinatv // Golden China TV Game Centre (Chinese famiclone)
m82 // Nintendo M82 Display Unit
+m82p // Nintendo M82 Display Unit PAL
nes // Nintendo Entertainment System
nespal // Nintendo Entertainment System PAL
--
cgit v1.2.3