summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author David Shah <davey1576@gmail.com>2018-02-07 19:09:56 +0000
committer Olivier Galibert <galibert@pobox.com>2018-02-07 20:09:56 +0100
commit304abd860c8f13f39979bcf300b9a3eb4b6aec47 (patch)
treeb85c705e2c4db5b66dbfb1aa2f1e6e2a72c4d788
parent86670b17acf9f3801b9eb207d7c34bb2a9975c6a (diff)
Several nes_vt Fixes and Improvements (#3178)
* Add 89 in 1 mini console * Add mc_cb280, similar to sy889 * More VTxx ROMs * Add more nes_vt systems * Add SY888B * Add support for VTxx systems with scrambled instructions (FC Pocket, DGUN2573) * Add support for Family Pocket, and more FC Pocket games * Small fixes and reclassifications (nw) * Support for VTxx scrambled banking (thanks NewRisingSun for help) * New palette code from NewRisingSun, etc * Various VT03 fixes, several systems including ZDog now working * nes_vt comment/status updates (nw) * Refactor m6502_vtscr (nw)
-rw-r--r--scripts/target/mame/mess.lua2
-rw-r--r--src/devices/video/ppu2c0x.cpp3
-rw-r--r--src/devices/video/ppu2c0x.h1
-rw-r--r--src/devices/video/ppu2c0x_vt.cpp190
-rw-r--r--src/devices/video/ppu2c0x_vt.h12
-rw-r--r--src/mame/drivers/nes_vt.cpp748
-rw-r--r--src/mame/machine/m6502_vtscr.cpp97
-rw-r--r--src/mame/machine/m6502_vtscr.h58
-rw-r--r--src/mame/mame.lst12
9 files changed, 905 insertions, 218 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index ccd0b44fa27..6c8c86560ff 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -2542,6 +2542,8 @@ files {
MAME_DIR .. "src/mame/audio/vboy.cpp",
MAME_DIR .. "src/mame/audio/vboy.h",
MAME_DIR .. "src/mame/drivers/gamecube.cpp",
+ MAME_DIR .. "src/mame/machine/m6502_vtscr.cpp",
+ MAME_DIR .. "src/mame/machine/m6502_vtscr.h",
}
createMESSProjects(_target, _subtarget, "nokia")
diff --git a/src/devices/video/ppu2c0x.cpp b/src/devices/video/ppu2c0x.cpp
index 86c265e9035..4370d9328d4 100644
--- a/src/devices/video/ppu2c0x.cpp
+++ b/src/devices/video/ppu2c0x.cpp
@@ -1329,6 +1329,9 @@ uint16_t ppu2c0x_device::get_vram_dest() {
return m_videomem_addr;
}
+void ppu2c0x_device::set_vram_dest(uint16_t dest) {
+ m_videomem_addr = dest;
+}
/*************************************
*
diff --git a/src/devices/video/ppu2c0x.h b/src/devices/video/ppu2c0x.h
index 11eff9624ce..38218e28628 100644
--- a/src/devices/video/ppu2c0x.h
+++ b/src/devices/video/ppu2c0x.h
@@ -159,6 +159,7 @@ public:
dev.m_use_sprite_write_limitation = false;
}
uint16_t get_vram_dest();
+ void set_vram_dest(uint16_t dest);
protected:
// registers definition
diff --git a/src/devices/video/ppu2c0x_vt.cpp b/src/devices/video/ppu2c0x_vt.cpp
index bfd18d3d68a..e396999a950 100644
--- a/src/devices/video/ppu2c0x_vt.cpp
+++ b/src/devices/video/ppu2c0x_vt.cpp
@@ -24,6 +24,8 @@ ppu_vt03_device::ppu_vt03_device(const machine_config &mconfig, const char *tag,
m_read_bg(*this),
m_read_sp(*this)
{
+ for(int i = 0; i < 6; i++)
+ m_2012_2017_descramble[i] = 2 + i;
}
READ8_MEMBER(ppu_vt03_device::palette_read)
@@ -40,90 +42,75 @@ READ8_MEMBER(ppu_vt03_device::palette_read)
void ppu_vt03_device::set_new_pen(int i)
{
- if(m_pal_mode == PAL_MODE_NEW_RGB) {
- uint16_t rgbval = (m_newpal[i&0x7f] & 0xff) | ((m_newpal[(i&0x7f)+0x80] & 0xff)<<8);
- uint8_t blue = (rgbval & 0x001f) << 3;
- uint8_t green = (rgbval & 0x3e0) >> 2;
- uint8_t red = (rgbval & 0x7C00) >> 7;
- m_palette->set_pen_color(i & 0x7f, rgb_t(red, green, blue));
+ if((i < 0x20) && ((i & 0x3) == 0)) {
+ m_palette->set_pen_color(i & 0x7f, rgb_t(0, 0, 0));
} else {
- // TODO: should this be tidied up?
- uint16_t palval = (m_newpal[i&0x7f] & 0x3f) | ((m_newpal[(i&0x7f)+0x80] & 0x3f)<<6);
-
- uint8_t rhue = palval & 0x0F;
- uint8_t rlum = (palval >> 4) & 0x0F;
- uint8_t rsat = (palval >> 8) & 0x0F;
- //See http://wiki.nesdev.com/w/index.php/VT03%2B_Enhanced_Palette#Inverted_extended_color_numbers
- bool inverted = (rlum < ((rsat + 1) >> 1) || rlum > (15 - (rsat >>1)));
- if(inverted && (m_pal_mode != PAL_MODE_NEW_VG)) {
- rsat = 16 - rsat;
- rlum = (rlum - 8) & 0x0F;
- uint8_t hue_lut[16] = {0xD, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x0, 0xE, 0xF};
- rhue = hue_lut[rhue];
- }
-
- // Get base color
- double hue = 287.0;
-
- double Kr = 0.2989;
- double Kb = 0.1145;
- double Ku = 2.029;
- double Kv = 1.140;
-
- double sat;
- double y, u, v;
- double rad;
- int R, G, B;
- switch (rhue)
- {
- case 0:
- sat = 0; rad = 0;
- y = 1.0;
- break;
-
- case 13:
- sat = 0; rad = 0;
- y = 0.77;
- break;
-
- case 14:
- case 15:
- sat = 0; rad = 0; y = 0;
- break;
-
- default:
- sat = (m_pal_mode == PAL_MODE_NEW_VG) ? 0.5 : 0.7;
- rad = M_PI * ((rhue * 30 + hue) / 180.0);
- y = (m_pal_mode == PAL_MODE_NEW_VG) ? 0.4 : 0.9;
- break;
+ if(m_pal_mode == PAL_MODE_NEW_RGB) {
+ uint16_t rgbval = (m_newpal[i&0x7f] & 0xff) | ((m_newpal[(i&0x7f)+0x80] & 0xff)<<8);
+ uint8_t blue = (rgbval & 0x001f) << 3;
+ uint8_t green = (rgbval & 0x3e0) >> 2;
+ uint8_t red = (rgbval & 0x7C00) >> 7;
+ m_palette->set_pen_color(i & 0x7f, rgb_t(red, green, blue));
+ } else if(m_pal_mode == PAL_MODE_NEW_RGB12) {
+ uint16_t rgbval = (m_newpal[i&0x7f] & 0x3f) | ((m_newpal[(i&0x7f)+0x80] & 0x3f)<<6);
+ uint8_t red = (rgbval & 0x000f) << 4;
+ uint8_t green = (rgbval & 0x0f0);
+ uint8_t blue = (rgbval & 0xf00) >> 4;
+ m_palette->set_pen_color(i & 0x7f, rgb_t(red, green, blue));
+ } else {
+ // Credit to NewRisingSun
+ uint16_t palval = (m_newpal[i&0x7f] & 0x3f) | ((m_newpal[(i&0x7f)+0x80] & 0x3f)<<6);
+ int nPhase = (palval >>0) &0xF;
+ int nLuma = (palval >>4) &0xF;
+ int nChroma = (palval >>8) &0xF;
+ float phaseOffset = -11.0;
+ //bool inverted = false;
+ if ((nLuma < (nChroma+1) >>1 || nLuma > 15 -(nChroma >>1)) && (m_pal_mode != PAL_MODE_NEW_VG)) {
+ //inverted = true;
+ // Strange color number wrap-around. Is this for protection reasons, or a bug of the original hardware?
+ // The VT03 data sheet advises programmers that 4 <= nLuma*2 +nChroma <= 0x1F, which does not correspond exactly to this condition.
+ static const unsigned char altPhases[16] = { 13, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 0, 14, 15};
+ static const float altPhaseOffset[16] = { -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, -5, 0, -5, -5, -5}; // Slight tweak in phase 6 for Z-Dog
+ phaseOffset += altPhaseOffset[nPhase]; // These "alternative" colors seem to be slightly shifted in addition to being wrapped-around, at least in EmuVT.
+ nPhase = altPhases[nPhase];
+ nChroma = 16 -nChroma;
+ nLuma = (nLuma -8) &0xF;
+ }
+ float fLuma = (nLuma-4) /9.625; // Value determined from matching saturation =0 phases 1-12
+ float fChroma = nChroma /18.975; // Value determined from matching phases 0 and 13 across all luminance and saturation levels
+ float fPhase = ((nPhase-2) *30.0 +phaseOffset) *M_PI /180.0;
+ if(m_pal_mode == PAL_MODE_NEW_VG) {
+ if(fPhase > 0 && fPhase < 13) {
+ fLuma /= 1.5;
+ fChroma /= 2;
+ }
+ }
+ float Y = fLuma;
+ float C = fChroma;
+ if (nPhase == 0 || nPhase >12) C =0.0;// Phases 0 and 13-15 are grays
+ if (nPhase == 0) Y += fChroma; // Phase 0 is the upper bound of the waveform
+ if (nPhase ==13) Y -= fChroma; // Phase 13 is the lower bound of the waveform
+ if (nPhase >=14) Y = 0.0; // Phases 14 and 15 always black
+
+ float V = sin(fPhase) *C *1.05; // 1.05 needed to get closer to EmuVT palette's color levels in phases 1-12
+ float U = cos(fPhase) *C *1.05;
+ float R = Y + 1.1400*V + 0.0000*U;
+ float G = Y - 0.5807*V - 0.3940*U;
+ float B = Y - 0.0000*V + 2.0290*U;
+ if (R <0.0) R =0.0;
+ if (R >1.0) R =1.0;
+ if (G <0.0) G =0.0;
+ if (G >1.0) G =1.0;
+ if (B <0.0) B =0.0;
+ if (B >1.0) B =1.0;
+ int RV = R *255.0;
+ int GV = G *255.0;
+ int BV = B *255.0;
+
+ m_palette->set_pen_color(i & 0x7f, rgb_t(RV, GV ,BV));
}
-
- sat *= (rsat / 15.0);
- y *= (rlum / 15.0);
- u = sat * cos(rad);
- v = sat * sin(rad);
-
- /* Transform to RGB */
- R = (y + Kv * v) * 255.0;
- G = (y - (Kb * Ku * u + Kr * Kv * v) / (1 - Kb - Kr)) * 255.0;
- B = (y + Ku * u) * 255.0;
-
- /* Clipping, in case of saturation */
- if (R < 0)
- R = 0;
- if (R > 255)
- R = 255;
- if (G < 0)
- G = 0;
- if (G > 255)
- G = 255;
- if (B < 0)
- B = 0;
- if (B > 255)
- B = 255;
-
- m_palette->set_pen_color(i & 0x7f, rgb_t(R, G ,B));
}
+
}
@@ -147,7 +134,13 @@ WRITE8_MEMBER(ppu_vt03_device::palette_write)
READ8_MEMBER( ppu_vt03_device::read )
{
- return ppu2c0x_device::read(space,offset);
+ if(offset <= 0xf) {
+ return ppu2c0x_device::read(space,offset);
+ } else if(offset <= 0x1f) {
+ return get_201x_reg(offset & 0x0f);
+ } else {
+ return 0;
+ }
}
void ppu_vt03_device::init_palette(palette_device &palette, int first_entry)
@@ -187,15 +180,13 @@ void ppu_vt03_device::device_reset()
m_read_sp.resolve_safe(0);
for (int i = 0;i < 0xff;i++)
m_newpal[i] = 0x0;
- set_2010_reg(0x00);
- set_2010_reg(0x80);
- set_2010_reg(0x00);
// todo: what are the actual defaults for these?
for (int i = 0;i < 0x20;i++)
set_201x_reg(i, 0x00);
init_palette(*m_palette, 0);
+
m_read_bg4_bg3 = 0;
m_va34 = 0;
}
@@ -233,6 +224,7 @@ void ppu_vt03_device::make_sprite_pixel_data(uint8_t &pixel_data, int flipx)
ppu2c0x_device::make_sprite_pixel_data(pixel_data, flipx);
int is4bpp = get_201x_reg(0x0) & 0x04;
+ int is16pix = get_201x_reg(0x0) & 0x01;
if (is4bpp)
{
@@ -242,6 +234,12 @@ void ppu_vt03_device::make_sprite_pixel_data(uint8_t &pixel_data, int flipx)
pixel_data |= (((m_extplanebuf[0] & 1) << 5) | ((m_extplanebuf[1] & 1) << 6));
m_extplanebuf[0] = m_extplanebuf[0] >> 1;
m_extplanebuf[1] = m_extplanebuf[1] >> 1;
+
+ if(is16pix) {
+ uint8_t pix0 = pixel_data & 0x03;
+ uint8_t pix1 = (pixel_data >> 5) & 0x03;
+ pixel_data = pix1 | (pix0 << 5);
+ }
}
else
{
@@ -268,7 +266,12 @@ void ppu_vt03_device::draw_sprite_pixel(int sprite_xpos, int color, int pixel, u
/* this mode makes use of the extra planes to increase sprite width instead
we probably need to split them out again and draw them at xpos+8 with a
cliprect - not seen used yet */
- bitmap.pix16(m_scanline, sprite_xpos + pixel) = pixel_data + (machine().rand()&3);
+ if((pixel_data & 0x03) != 0)
+ bitmap.pix16(m_scanline, sprite_xpos + pixel) = (pixel_data & 0x03) + (4 * color);
+ if(((pixel_data >> 5) & 0x03) != 0)
+ bitmap.pix16(m_scanline, sprite_xpos + pixel + 8) = ((pixel_data >> 5) & 0x03) + (4 * color);
+ //ppu2c0x_device::draw_sprite_pixel(sprite_xpos, color, pixel, pixel_data & 0x03, bitmap);
+ //ppu2c0x_device::draw_sprite_pixel(sprite_xpos, color, pixel + 8, (pixel_data >> 5) & 0x03, bitmap);
}
}
else
@@ -345,7 +348,7 @@ void ppu_vt03_device::draw_tile_pixel(uint8_t pix, int color, uint16_t back_pen,
}
else
{
- pen = back_pen; // fixme backpen logic probably differs on vt03 due to extra colours
+ pen = 0; // fixme backpen logic probably differs on vt03 due to extra colours
}
*dest = pen;
}
@@ -409,31 +412,32 @@ WRITE8_MEMBER(ppu_vt03_device::write)
break;
case 0x11:
+ m_201x_regs[0x1] = data;
break;
case 0x12:
- m_201x_regs[0x2] = data;
+ m_201x_regs[m_2012_2017_descramble[0]] = data;
break;
case 0x13:
- m_201x_regs[0x3] = data;
+ m_201x_regs[m_2012_2017_descramble[1]] = data;
break;
case 0x14:
- m_201x_regs[0x4] = data;
+ m_201x_regs[m_2012_2017_descramble[2]] = data;
break;
case 0x15:
- m_201x_regs[0x5] = data;
+ m_201x_regs[m_2012_2017_descramble[3]] = data;
break;
case 0x16:
- m_201x_regs[0x6] = data;
+ m_201x_regs[m_2012_2017_descramble[4]] = data;
break;
case 0x17:
logerror("set reg 7 %02x\n", data);
- m_201x_regs[0x7] = data;
+ m_201x_regs[m_2012_2017_descramble[5]] = data;
break;
case 0x18:
diff --git a/src/devices/video/ppu2c0x_vt.h b/src/devices/video/ppu2c0x_vt.h
index da9857aae38..aa62b29622c 100644
--- a/src/devices/video/ppu2c0x_vt.h
+++ b/src/devices/video/ppu2c0x_vt.h
@@ -30,10 +30,15 @@
#define MCFG_PPU_VT03_SET_PAL_MODE(pmode) \
ppu_vt03_device::set_palette_mode(*device, pmode);
+#define MCFG_PPU_VT03_SET_DESCRAMBLE(dsc) \
+ ppu_vt03_device::set_201x_descramble(*device, dsc);
+
+
enum vtxx_pal_mode {
PAL_MODE_VT0x,
PAL_MODE_NEW_RGB,
- PAL_MODE_NEW_VG
+ PAL_MODE_NEW_VG,
+ PAL_MODE_NEW_RGB12,
};
class ppu_vt03_device : public ppu2c0x_device {
@@ -44,6 +49,7 @@ public:
template <class Object> static devcb_base &set_read_sp_callback(device_t &device, Object &&cb) { return downcast<ppu_vt03_device &>(device).m_read_sp.set_callback(std::forward<Object>(cb)); }
static void set_palette_mode(device_t &device, vtxx_pal_mode pmode) { downcast<ppu_vt03_device &>(device).m_pal_mode = pmode; }
+ static void set_201x_descramble(device_t &device, const uint8_t descramble[6]) { for (int i = 0; i < 6; i++) downcast<ppu_vt03_device &>(device).m_2012_2017_descramble[i] = descramble[i]; }
virtual DECLARE_READ8_MEMBER(read) override;
virtual DECLARE_WRITE8_MEMBER(write) override;
@@ -86,7 +92,9 @@ private:
palette_device *m_palette;
uint8_t m_201x_regs[0x20];
-
+
+ uint8_t m_2012_2017_descramble[0x6];
+
vtxx_pal_mode m_pal_mode = PAL_MODE_VT0x;
void set_2010_reg(uint8_t data);
diff --git a/src/mame/drivers/nes_vt.cpp b/src/mame/drivers/nes_vt.cpp
index 6642fea66ed..0ba760e8472 100644
--- a/src/mame/drivers/nes_vt.cpp
+++ b/src/mame/drivers/nes_vt.cpp
@@ -20,13 +20,22 @@
VT16 - ?
VT18 - ?
-
- VT3x - used in SY889
- Uses SQI rather than parallel flash
- Vaguely OneBus compatible but some registers different ($411C in particular)
- Uses RGB format for palettes
- Credit to NewRisingSun2 for much of the reverse engineering
-
+
+ VT33 (?) - used in FC Pocket, dgun2573
+ Adds scrambled opcodes (XORed with 0xA1) and RGB444 palette mode,
+ and more advanced PCM modes (CPU and video working, sound NYI)
+
+ VT368 (?) - used in DGUN2561, lexcyber
+ Various enhancements not yet emulated. Different banking, possibly an ALU,
+ larger palette space
+
+ VT36x (?) - used in SY889
+ Uses SQI rather than parallel flash
+ Vaguely OneBus compatible but some registers different ($411C in particular)
+ Uses RGB format for palettes
+ Credit to NewRisingSun2 for much of the reverse engineering
+ same chipset used in Mogis M320, but uses more advanced feature set.
+
(more)
VT1682 - NOT compatible with NES, different video system, sound CPU (4x
@@ -35,15 +44,14 @@
todo (VT03):
- Super Mario Bros 3 crashes after title screen, some kind of memory map issue
- possibly with MMC3 emulation mode
-
APU refactoring to allow for mostly doubled up functionality + PCM channel
*more*
todo (newer VTxx):
- everything
+ new PCM audio in FC Pocket and DGUN-2573
+ add support for VT368 (?) in DGUN-2561 and lexcyber
+ add support for the VT369 (?) featurs used by the MOGIS M320
todo (general)
@@ -65,16 +73,25 @@
#include "cpu/m6502/n2a03.h"
#include "machine/bankdev.h"
#include "video/ppu2c0x_vt.h"
-#include "cpu/m6502/m6502.h"
+#include "machine/m6502_vtscr.h"
#include "screen.h"
#include "speaker.h"
+enum class vt_scramble_mode {
+ NO_SCRAMBLE = 0,
+ WAIXING = 1,
+ PJOY = 2,
+ HUMMER = 3,
+ SP69 = 4
+};
+
class nes_vt_state : public nes_base_state
{
public:
nes_vt_state(const machine_config &mconfig, device_type type, const char *tag)
: nes_base_state(mconfig, type, tag)
, m_ntram(nullptr)
+ , m_chrram(nullptr)
, m_ppu(*this, "ppu")
, m_apu(*this, "apu")
, m_prg(*this, "prg")
@@ -83,6 +100,8 @@ public:
, m_prgbank2(*this, "prg_bank2")
, m_prgbank3(*this, "prg_bank3")
, m_prgrom(*this, "mainrom")
+ , m_csel(*this, "CARTSEL")
+
{ }
/* APU handling */
@@ -102,7 +121,19 @@ public:
/* VT03 extension handling */
DECLARE_WRITE8_MEMBER(vt03_410x_w);
+ DECLARE_READ8_MEMBER(vt03_410x_r);
+
+ DECLARE_WRITE8_MEMBER(vt03_410x_pjoy_w);
+ DECLARE_WRITE8_MEMBER(vt03_410x_hum_w);
+ DECLARE_WRITE8_MEMBER(vt03_410x_sp69_w);
+
DECLARE_WRITE8_MEMBER(vt03_8000_w);
+ DECLARE_WRITE8_MEMBER(vt03_8000_pjoy_w);
+ DECLARE_WRITE8_MEMBER(vt03_8000_hum_w);
+ DECLARE_WRITE8_MEMBER(vt03_8000_sp69_w);
+
+ void scrambled_410x_w(uint16_t offset, uint8_t data, vt_scramble_mode scram);
+ void scrambled_8000_w(address_space &space, uint16_t offset, uint8_t data, vt_scramble_mode scram);
DECLARE_WRITE8_MEMBER(vt03_4034_w);
DECLARE_WRITE8_MEMBER(vt03_41bx_w);
@@ -112,23 +143,52 @@ public:
DECLARE_WRITE8_MEMBER(vt03_48ax_w);
DECLARE_READ8_MEMBER(vt03_48ax_r);
+
+ DECLARE_WRITE8_MEMBER(vt03_413x_w);
+ DECLARE_READ8_MEMBER(vt03_413x_r);
+ DECLARE_READ8_MEMBER(vt03_414f_r);
+ DECLARE_READ8_MEMBER(vt03_415c_r);
+
+ DECLARE_READ8_MEMBER(vthh_414a_r);
+ DECLARE_WRITE8_MEMBER(vtfp_411e_w);
+ DECLARE_WRITE8_MEMBER(vtfp_4a00_w);
+ DECLARE_WRITE8_MEMBER(vtfp_412c_w);
+ DECLARE_WRITE8_MEMBER(vtfa_412c_w);
+ DECLARE_READ8_MEMBER(vtfp_412d_r);
+ DECLARE_WRITE8_MEMBER(vtfp_411d_w);
+ DECLARE_WRITE8_MEMBER(vtfp_4242_w);
+ DECLARE_READ8_MEMBER(vtfp_4119_r);
+
+ DECLARE_READ8_MEMBER(vtfa_412c_r);
/* OneBus read callbacks for getting sprite and tile data during rendering*/
DECLARE_READ8_MEMBER(spr_r);
DECLARE_READ8_MEMBER(chr_r);
+ DECLARE_WRITE8_MEMBER(chr_w);
+
void nes_vt(machine_config &config);
+
+ void nes_vt_hum(machine_config &config);
+ void nes_vt_pjoy(machine_config &config);
+ void nes_vt_sp69(machine_config &config);
+
+
void nes_vt_xx(machine_config &config);
void nes_vt_hh(machine_config &config);
void nes_vt_cy(machine_config &config);
void nes_vt_dg(machine_config &config);
void nes_vt_bt(machine_config &config);
void nes_vt_vg(machine_config &config);
+ void nes_vt_fp(machine_config &config);
+ void nes_vt_fa(machine_config &config);
private:
/* expansion nametable - todo, see if we can refactor NES code to be reusable without having to add full NES bus etc. */
std::unique_ptr<uint8_t[]> m_ntram;
+ std::unique_ptr<uint8_t[]> m_chrram;
+
DECLARE_READ8_MEMBER(nt_r);
DECLARE_WRITE8_MEMBER(nt_w);
@@ -137,8 +197,10 @@ private:
void video_irq(bool hblank, int scanline, int vblank, int blanked);
uint8_t m_410x[0xc];
- uint8_t m_411c;
- uint8_t m_412c;
+ uint8_t m_413x[8];
+
+ uint8_t m_411c, m_411d, m_4242;
+ uint32_t m_ahigh;
uint8_t m_vdma_ctrl;
int m_timer_irq_enabled;
@@ -167,6 +229,7 @@ private:
required_memory_bank m_prgbank3;
required_region_ptr<uint8_t> m_prgrom;
+ optional_ioport m_csel;
uint16_t decode_nt_addr(uint16_t addr);
void do_dma(uint8_t data, bool broken);
};
@@ -191,7 +254,7 @@ uint32_t nes_vt_state::get_banks(uint8_t bnk)
// 8000 needs to bank in 60000 ( bank 0x30 )
void nes_vt_state::update_banks()
{
- uint32_t amod = (m_412c & 0x04) ? 0x800 : 0x0;
+ uint32_t amod = m_ahigh >> 13;
uint8_t bank;
@@ -240,6 +303,38 @@ uint16_t nes_vt_state::decode_nt_addr(uint16_t addr) {
WRITE8_MEMBER(nes_vt_state::vt03_410x_w)
{
+ scrambled_410x_w(offset, data, vt_scramble_mode::NO_SCRAMBLE);
+}
+
+READ8_MEMBER(nes_vt_state::vt03_410x_r)
+{
+ return m_410x[offset];
+}
+
+WRITE8_MEMBER(nes_vt_state::vt03_410x_hum_w)
+{
+ scrambled_410x_w(offset, data, vt_scramble_mode::HUMMER);
+}
+WRITE8_MEMBER(nes_vt_state::vt03_410x_pjoy_w)
+{
+ scrambled_410x_w(offset, data, vt_scramble_mode::PJOY);
+}
+WRITE8_MEMBER(nes_vt_state::vt03_410x_sp69_w)
+{
+ scrambled_410x_w(offset, data, vt_scramble_mode::SP69);
+}
+// Source: https://wiki.nesdev.com/w/index.php/NES_2.0_submappers/Proposals#NES_2.0_Mapper_256
+
+static const uint16_t descram_4107_4108[5][2] = {
+ {0x7, 0x8},
+ {0x7, 0x8},
+ {0x8, 0x7},
+ {0x7, 0x8},
+ {0x7, 0x8},
+};
+
+void nes_vt_state::scrambled_410x_w(uint16_t offset, uint8_t data, vt_scramble_mode scram)
+{
switch (offset)
{
case 0x0:
@@ -254,6 +349,7 @@ WRITE8_MEMBER(nes_vt_state::vt03_410x_w)
break;
case 0x2:
+ //logerror("vt03_4102_w %02x\n", data);
// load latched value and start counting
m_410x[0x2] = data; // value doesn't matter?
m_timer_val = m_410x[0x1];
@@ -261,12 +357,15 @@ WRITE8_MEMBER(nes_vt_state::vt03_410x_w)
break;
case 0x3:
+ //logerror("vt03_4103_w %02x\n", data);
+ m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
// disable timer irq
m_410x[0x3] = data; // value doesn't matter?
m_timer_irq_enabled = 0;
break;
case 0x4:
+ //logerror("vt03_4104_w %02x\n", data);
// enable timer irq
m_410x[0x4] = data; // value doesn't matter?
m_timer_irq_enabled = 1;
@@ -283,12 +382,12 @@ WRITE8_MEMBER(nes_vt_state::vt03_410x_w)
break;
case 0x7:
- m_410x[0x7] = data;
+ m_410x[descram_4107_4108[(int)scram][0]] = data;
update_banks();
break;
case 0x8:
- m_410x[0x8] = data;
+ m_410x[descram_4107_4108[(int)scram][1]] = data;
update_banks();
break;
@@ -338,10 +437,58 @@ WRITE8_MEMBER(nes_vt_state::vt03_411c_w)
WRITE8_MEMBER(nes_vt_state::vt03_412c_w)
{
logerror("vt03_412c_w %02x\n", data);
- m_412c = data;
+ m_ahigh = (data & 0x04) ? (1 << 24) : 0x0;
update_banks();
}
+WRITE8_MEMBER(nes_vt_state::vtfp_412c_w)
+{
+ logerror("vtfp_412c_w %02x\n", data);
+ m_ahigh = (data & 0x01) ? (1 << 25) : 0x0;
+ update_banks();
+}
+
+WRITE8_MEMBER(nes_vt_state::vtfp_4242_w)
+{
+ logerror("vtfp_4242_w %02x\n", data);
+ m_4242 = data;
+}
+
+
+WRITE8_MEMBER(nes_vt_state::vtfp_411d_w)
+{
+ logerror("vtfp_411d_w %02x\n", data);
+ m_411d = data;
+ update_banks();
+}
+
+WRITE8_MEMBER(nes_vt_state::vtfa_412c_w)
+{
+ logerror("vtfp_412c_w %02x\n", data);
+ m_ahigh = 0;
+ m_ahigh |= (data & 0x01) ? (1 << 25) : 0x0;
+ m_ahigh |= (data & 0x02) ? (1 << 24) : 0x0;
+
+ //m_ahigh |= (m_csel->read() == 0x01) ? (1 << 25) : 0x0;
+ update_banks();
+}
+
+READ8_MEMBER(nes_vt_state::vtfa_412c_r)
+{
+ return m_csel->read();
+}
+
+READ8_MEMBER(nes_vt_state::vtfp_412d_r)
+{
+ return m_csel->read();
+}
+
+READ8_MEMBER(nes_vt_state::vtfp_4119_r)
+{
+ return 0x00;
+}
+
+
READ8_MEMBER(nes_vt_state::vt03_41bx_r)
{
switch(offset) {
@@ -369,6 +516,52 @@ READ8_MEMBER(nes_vt_state::vt03_48ax_r)
}
}
+WRITE8_MEMBER(nes_vt_state::vt03_413x_w)
+{
+ logerror("vt03_413x_w %02x %02x\n", offset, data);
+ // VT168 style ALU ??
+ m_413x[offset] = data;
+ if(offset == 0x5) {
+ uint32_t res = uint32_t((m_413x[5] << 8) | m_413x[4]) * uint32_t((m_413x[1] << 8) | m_413x[0]);
+ m_413x[0] = res & 0xFF;
+ m_413x[1] = (res >> 8) & 0xFF;
+ m_413x[2] = (res >> 16) & 0xFF;
+ m_413x[3] = (res >> 24) & 0xFF;
+ m_413x[6] = 0x00;
+
+ } else if(offset == 0x6) {
+ /*uint32_t res = uint32_t((m_413x[5] << 8) | m_413x[4]) * uint32_t((m_413x[1] << 8) | m_413x[0]);
+ m_413x[0] = res & 0xFF;
+ m_413x[1] = (res >> 8) & 0xFF;
+ m_413x[2] = (res >> 16) & 0xFF;
+ m_413x[3] = (res >> 24) & 0xFF;*/
+ m_413x[6] = 0x00;
+ }
+
+}
+
+
+READ8_MEMBER(nes_vt_state::vt03_413x_r)
+{
+ logerror("vt03_413x_r %02x\n", offset);
+ return m_413x[offset];
+}
+
+READ8_MEMBER(nes_vt_state::vt03_414f_r)
+{
+ return 0xff;
+}
+
+READ8_MEMBER(nes_vt_state::vt03_415c_r)
+{
+ return 0xff;
+}
+
+READ8_MEMBER(nes_vt_state::vthh_414a_r)
+{
+ return 0x80;
+}
+
uint32_t nes_vt_state::screen_update_vt(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
@@ -379,16 +572,50 @@ uint32_t nes_vt_state::screen_update_vt(screen_device &screen, bitmap_ind16 &bit
READ8_MEMBER(nes_vt_state::spr_r)
{
- int realaddr = calculate_real_video_address(offset, 0, 1);
- return m_prgrom[realaddr & (m_romsize-1)];
+ if(m_4242 & 0x1 || m_411d & 0x04) {
+ return m_chrram[offset];
+ } else {
+ int realaddr = calculate_real_video_address(offset, 0, 1);
+ return m_prgrom[realaddr & (m_romsize-1)];
+ }
}
READ8_MEMBER(nes_vt_state::chr_r)
{
- int realaddr = calculate_real_video_address(offset, 1, 0);
- return m_prgrom[realaddr & (m_romsize-1)];
+ if(m_4242 & 0x1 || m_411d & 0x04) {
+ return m_chrram[offset];
+ } else {
+ int realaddr = calculate_real_video_address(offset, 1, 0);
+ return m_prgrom[realaddr & (m_romsize-1)];
+ }
+}
+
+
+WRITE8_MEMBER(nes_vt_state::chr_w)
+{
+ if(m_4242 & 0x1 || m_411d & 0x04) {
+ logerror("vram write %04x %02x\n", offset, data);
+ m_chrram[offset] = data;
+ }
+ /*int realaddr = calculate_real_video_address(offset, 1, 0);
+ return m_prgrom[realaddr & (m_romsize-1)];*/
}
+WRITE8_MEMBER(nes_vt_state::vtfp_411e_w) {
+ logerror("411e_w %02x\n", data);
+ if(data == 0x05)
+ dynamic_cast<m6502_vtscr&>(*m_maincpu).set_next_scramble(true);
+ else if(data == 0x00)
+ dynamic_cast<m6502_vtscr&>(*m_maincpu).set_next_scramble(false);
+}
+
+WRITE8_MEMBER(nes_vt_state::vtfp_4a00_w) {
+ logerror("4a00_w %02x\n", data);
+ //if(data == 0x80)
+ // dynamic_cast<m6502_vtscr&>(*m_maincpu).set_scramble(false);
+}
+
+
PALETTE_INIT_MEMBER(nes_vt_state, nesvt)
{
m_ppu->init_palette(palette, 0);
@@ -418,7 +645,7 @@ void nes_vt_state::video_irq(bool hblank, int scanline, int vblank, int blanked)
if (m_timer_val < 0)
{
- if (m_timer_irq_enabled)
+ if (m_timer_irq_enabled && !blanked)
{
logerror("scanline_irq %d\n", scanline);
irqstate = 1;
@@ -428,8 +655,8 @@ void nes_vt_state::video_irq(bool hblank, int scanline, int vblank, int blanked)
if (irqstate)
m_maincpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE);
- else
- m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
+ //else
+ // m_maincpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
}
}
@@ -442,6 +669,7 @@ READ8_MEMBER(nes_vt_state::nt_r)
WRITE8_MEMBER(nes_vt_state::nt_w)
{
+ //logerror("nt wr %04x %02x", offset, data);
m_ntram[decode_nt_addr(offset)] = data;
}
@@ -458,6 +686,8 @@ void nes_vt_state::machine_start()
m_prgbank3->configure_entries(0, m_numbanks, &m_prgrom[0x00000], 0x2000);
save_item(NAME(m_410x));
+ save_item(NAME(m_413x));
+
save_item(NAME(m_8000_addr_latch));
save_item(NAME(m_timer_irq_enabled));
@@ -467,12 +697,18 @@ void nes_vt_state::machine_start()
m_ntram = std::make_unique<uint8_t[]>(0x2000);
save_pointer(NAME(m_ntram.get()), 0x2000);
+ m_chrram = std::make_unique<uint8_t[]>(0x2000);
+ save_pointer(NAME(m_chrram.get()), 0x2000);
+
m_ppu->set_scanline_callback(ppu2c0x_device::scanline_delegate(FUNC(nes_vt_state::scanline_irq),this));
m_ppu->set_hblank_callback(ppu2c0x_device::scanline_delegate(FUNC(nes_vt_state::hblank_irq),this));
// m_ppu->set_hblank_callback(ppu2c0x_device::hblank_delegate(FUNC(device_nes_cart_interface::hblank_irq),m_cartslot->m_cart));
// 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(nes_vt_state::nt_r),this), write8_delegate(FUNC(nes_vt_state::nt_w),this));
+ m_ppu->space(AS_PROGRAM).install_readwrite_handler(0, 0x1fff, read8_delegate(FUNC(nes_vt_state::chr_r),this), write8_delegate(FUNC(nes_vt_state::chr_w),this));
+
+
}
void nes_vt_state::machine_reset()
@@ -491,7 +727,10 @@ void nes_vt_state::machine_reset()
m_410x[0xa] = 0x00;
m_410x[0xb] = 0x00;
m_411c = 0x00;
- m_412c = 0x00;
+ m_411d = 0x00;
+ m_4242 = 0x00;
+
+ m_ahigh = (m_csel->read() == 0x01) ? (1 << 25) : 0x0;
m_timer_irq_enabled = 0;
m_timer_running = 0;
m_timer_val = 0;
@@ -705,96 +944,144 @@ int nes_vt_state::calculate_real_video_address(int addr, int extended, int readt
}
}
- uint32_t amod = (m_412c & 0x04) ? (1 << 24) : 0x0;
- return amod | finaladdr;
+ return m_ahigh | finaladdr;
}
/*
nes_vt_state::vt03_8000_w notes
- this is used by
- VT03dogA.bin
- at least, but even in EmuVT the sprite graphics there are corrupt
- so I'm not sure if it's just an incomplete demo, or there is more to this
+ used for MMC3/other mapper compatibility
+ some consoles have scrambled registers for crude copy protection
*/
-// MMC3 compatibility mode
-WRITE8_MEMBER(nes_vt_state::vt03_8000_w)
+static const uint8_t descram_8000_mmc3[5][8] = {
+ {0x6, 0x7, 0x2, 0x3, 0x4, 0x5, 0x7, 0x8},
+ {0x5, 0x4, 0x3, 0x2, 0x7, 0x6, 0x7, 0x8},
+ {0x6, 0x7, 0x2, 0x3, 0x4, 0x5, 0x8, 0x7},
+ {0x6, 0x7, 0x2, 0x3, 0x4, 0x5, 0x7, 0x8},
+ {0x6, 0x7, 0x2, 0x3, 0x4, 0x5, 0x7, 0x8},
+};
+
+void nes_vt_state::scrambled_8000_w(address_space &space, uint16_t offset, uint8_t data, vt_scramble_mode scram)
{
- //logerror("%s: vt03_8000_w (%04x) %02x\n", machine().describe_context(), offset+0x8000, data );
uint16_t addr = offset + 0x8000;
- if((addr < 0xA000) && !(addr & 0x01)) {
- // Bank select
- m_8000_addr_latch = data & 0x07;
- // Bank config
- m_410x[0x05] &= 0x3F;
- m_410x[0x05] |= (data & 0xC0);
+ if((m_411d & 0x01) && (m_411d & 0x03)) {
+ //CNROM compat
+ logerror("vtxx_cnrom_8000_w (%04x) %02x\n", offset+0x8000, data );
+ m_ppu->set_201x_reg(0x6, data * 8);
+ m_ppu->set_201x_reg(0x7, data * 8 + 2);
+ m_ppu->set_201x_reg(0x2, data * 8 + 4);
+ m_ppu->set_201x_reg(0x3, data * 8 + 5);
+ m_ppu->set_201x_reg(0x4, data * 8 + 6);
+ m_ppu->set_201x_reg(0x5, data * 8 + 7);
+
+ } else if(m_411d & 0x01) {
+ //MMC1 compat, TODO
+ logerror("vtxx_mmc1_8000_w (%04x) %02x\n", offset+0x8000, data );
+
+ } else if(m_411d & 0x02) {
+ //UNROM compat
+ logerror("vtxx_unrom_8000_w (%04x) %02x\n", offset+0x8000, data );
+
+ m_410x[0x7] = ((data & 0x0F) << 1);
+ m_410x[0x8] = ((data & 0x0F) << 1) + 1;
update_banks();
- } else if((addr < 0xA000) && (addr & 0x01)) {
- switch(m_8000_addr_latch) {
- case 0x00:
- m_ppu->set_201x_reg(0x6, data);
- break;
-
- case 0x01:
- m_ppu->set_201x_reg(0x7, data);
- break;
-
- case 0x02: // hand?
- m_ppu->set_201x_reg(0x2, data);
- break;
-
- case 0x03: // dog?
- m_ppu->set_201x_reg(0x3, data);
- break;
-
- case 0x04: // ball thrown
- m_ppu->set_201x_reg(0x4, data);
- break;
-
- case 0x05: // ball thrown
- m_ppu->set_201x_reg(0x5, data);
- break;
- case 0x06:
- m_410x[0x7] = data;
- //m_410x[0x9] = data;
- update_banks();
- break;
-
- case 0x07:
- m_410x[0x8] = data;
- update_banks();
- break;
- }
- } else if((addr >= 0xA000) && (addr < 0xC000) && !(addr & 0x01)) {
- // Mirroring
- m_410x[0x6] &= 0xFE;
- m_410x[0x6] |= data & 0x01;
- } else if((addr >= 0xA000) && (addr < 0xC000) && (addr & 0x01)) {
- // PRG RAM control, ignore
- } else if((addr >= 0xC000) && (addr < 0xE000) && !(addr & 0x01)) {
- // IRQ latch
- vt03_410x_w(space, 1, data);
- } else if((addr >= 0xC000) && (addr < 0xE000) && (addr & 0x01)) {
- // IRQ reload
- vt03_410x_w(space, 2, data);
- } else if((addr >= 0xE000) && !(addr & 0x01)) {
- // IRQ disable
- vt03_410x_w(space, 3, data);
- } else if((addr >= 0xE000) && (addr & 0x01)) {
- // IRQ enable
- vt03_410x_w(space, 4, data);
} else {
+ //logerror("vtxx_mmc3_8000_w (%04x) %02x\n", offset+0x8000, data );
+
+ //MMC3 compat
+ if((addr < 0xA000) && !(addr & 0x01)) {
+ // Bank select
+ m_8000_addr_latch = data & 0x07;
+ // Bank config
+ m_410x[0x05] = data & ~(1 << 5);
+ update_banks();
+ } else if((addr < 0xA000) && (addr & 0x01)) {
+ switch(m_410x[0x05] & 0x07) {
+ case 0x00:
+ m_ppu->set_201x_reg(descram_8000_mmc3[(int)scram][0], data);
+ break;
+
+ case 0x01:
+ m_ppu->set_201x_reg(descram_8000_mmc3[(int)scram][1], data);
+ break;
+
+ case 0x02: // hand?
+ m_ppu->set_201x_reg(descram_8000_mmc3[(int)scram][2], data);
+ break;
+
+ case 0x03: // dog?
+ m_ppu->set_201x_reg(descram_8000_mmc3[(int)scram][3], data);
+ break;
+
+ case 0x04: // ball thrown
+ m_ppu->set_201x_reg(descram_8000_mmc3[(int)scram][4], data);
+ break;
+
+ case 0x05: // ball thrown
+ m_ppu->set_201x_reg(descram_8000_mmc3[(int)scram][5], data);
+ break;
+ case 0x06:
+ m_410x[descram_8000_mmc3[(int)scram][6]] = data;
+ //m_410x[0x9] = data;
+ update_banks();
+ break;
+
+ case 0x07:
+ m_410x[descram_8000_mmc3[(int)scram][7]] = data;
+ update_banks();
+ break;
+ }
+ } else if((addr >= 0xA000) && (addr < 0xC000) && !(addr & 0x01)) {
+ // Mirroring
+ m_410x[0x6] &= 0xFE;
+ m_410x[0x6] |= data & 0x01;
+ } else if((addr >= 0xA000) && (addr < 0xC000) && (addr & 0x01)) {
+ // PRG RAM control, ignore
+ } else if((addr >= 0xC000) && (addr < 0xE000) && !(addr & 0x01)) {
+ // IRQ latch
+ vt03_410x_w(space, 1, data);
+ } else if((addr >= 0xC000) && (addr < 0xE000) && (addr & 0x01)) {
+ // IRQ reload
+ vt03_410x_w(space, 2, data);
+ } else if((addr >= 0xE000) && !(addr & 0x01)) {
+ // IRQ disable
+ vt03_410x_w(space, 3, data);
+ } else if((addr >= 0xE000) && (addr & 0x01)) {
+ // IRQ enable
+ vt03_410x_w(space, 4, data);
+ } else {
+ }
}
+}
+// MMC3 compatibility mode
+WRITE8_MEMBER(nes_vt_state::vt03_8000_w)
+{
+ scrambled_8000_w(space, offset, data, vt_scramble_mode::NO_SCRAMBLE);
+ //logerror("%s: vt03_8000_w (%04x) %02x\n", machine().describe_context(), offset+0x8000, data );
+}
+WRITE8_MEMBER(nes_vt_state::vt03_8000_hum_w)
+{
+ scrambled_8000_w(space, offset, data, vt_scramble_mode::HUMMER);
+}
+WRITE8_MEMBER(nes_vt_state::vt03_8000_pjoy_w)
+{
+ scrambled_8000_w(space, offset, data, vt_scramble_mode::PJOY);
+}
+
+WRITE8_MEMBER(nes_vt_state::vt03_8000_sp69_w)
+{
+ scrambled_8000_w(space, offset, data, vt_scramble_mode::SP69);
}
/* APU plumbing, this is because we have a plain M6502 core in the VT03, otherwise this is handled in the core */
READ8_MEMBER(nes_vt_state::psg1_4014_r)
{
- return m_apu->read(space, 0x14);
+ //return m_apu->read(space, 0x14);
+ return 0x00;
}
READ8_MEMBER(nes_vt_state::psg1_4015_r)
@@ -837,10 +1124,18 @@ void nes_vt_state::do_dma(uint8_t data, bool broken)
}
uint16_t src_addr = (data << 8) | (src_nib_74 << 4);
logerror("vthh dma start ctrl=%02x addr=%04x\n", m_vdma_ctrl, src_addr);
+ if(dma_mode == 1) {
+ logerror("vdma dest %04x\n", m_ppu->get_vram_dest());
+ }
if(broken && (dma_mode == 1) && ((m_ppu->get_vram_dest() & 0xFF00) == 0x3F00)
&& !(m_ppu->get_201x_reg(0x1) & 0x80)) {
length -= 1;
src_addr += 1;
+ } else if((dma_mode == 1) && ((m_ppu->get_vram_dest() & 0xFF00) == 0x3F01)
+ && !(m_ppu->get_201x_reg(0x1) & 0x80)) {
+ // Legacy mode for DGUN-2573 compat
+ m_ppu->set_vram_dest(0x3F00);
+ ppu_vt03_device::set_palette_mode(*m_ppu, PAL_MODE_VT0x);
}
for (int i = 0; i < length; i++)
{
@@ -850,7 +1145,7 @@ void nes_vt_state::do_dma(uint8_t data, bool broken)
} else {
m_maincpu->space(AS_PROGRAM).write_byte(0x2004, spriteData);
}
- if(((src_addr + i) & 0xFF) == length) break;
+ //if(((src_addr + i) & 0xFF) == length && (i != 0)) break;
}
// should last (length * 4 - 1) CPU cycles.
@@ -860,11 +1155,12 @@ void nes_vt_state::do_dma(uint8_t data, bool broken)
WRITE8_MEMBER(nes_vt_state::vt03_4034_w)
{
+ logerror("vt03_4034_w %02x\n", data);
m_vdma_ctrl = data;
}
static ADDRESS_MAP_START( nes_vt_map, AS_PROGRAM, 8, nes_vt_state )
- AM_RANGE(0x0000, 0x1fff) AM_MASK(0x07FF) AM_RAM
+ AM_RANGE(0x0000, 0x07ff) AM_RAM
AM_RANGE(0x2000, 0x3fff) AM_MASK(0x001F) AM_DEVREADWRITE("ppu", ppu2c0x_device, read, write) /* PPU registers */
AM_RANGE(0x4000, 0x4013) AM_DEVREADWRITE("apu", nesapu_device, read, write)
@@ -875,23 +1171,48 @@ static ADDRESS_MAP_START( nes_vt_map, AS_PROGRAM, 8, nes_vt_state )
AM_RANGE(0x4034, 0x4034) AM_WRITE(vt03_4034_w)
- AM_RANGE(0x4100, 0x410b) AM_WRITE(vt03_410x_w)
+ AM_RANGE(0x4100, 0x410b) AM_READ(vt03_410x_r) AM_WRITE(vt03_410x_w)
AM_RANGE(0x8000, 0xffff) AM_DEVICE("prg", address_map_bank_device, amap8)
AM_RANGE(0x8000, 0xffff) AM_WRITE(vt03_8000_w)
AM_RANGE(0x6000, 0x7fff) AM_RAM
ADDRESS_MAP_END
+
/* Some later VT models have more RAM */
static ADDRESS_MAP_START( nes_vt_xx_map, AS_PROGRAM, 8, nes_vt_state )
AM_IMPORT_FROM(nes_vt_map)
AM_RANGE(0x0800, 0x0fff) AM_RAM
ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( nes_vt_hum_map, AS_PROGRAM, 8, nes_vt_state )
+AM_IMPORT_FROM(nes_vt_map)
+AM_RANGE(0x4100, 0x410b) AM_WRITE(vt03_410x_hum_w)
+AM_RANGE(0x8000, 0xffff) AM_WRITE(vt03_8000_hum_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( nes_vt_pjoy_map, AS_PROGRAM, 8, nes_vt_state )
+AM_IMPORT_FROM(nes_vt_map)
+AM_RANGE(0x4100, 0x410b) AM_WRITE(vt03_410x_pjoy_w)
+AM_RANGE(0x8000, 0xffff) AM_WRITE(vt03_8000_pjoy_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( nes_vt_sp69_map, AS_PROGRAM, 8, nes_vt_state )
+AM_IMPORT_FROM(nes_vt_map)
+AM_RANGE(0x4100, 0x410b) AM_WRITE(vt03_410x_sp69_w)
+AM_RANGE(0x8000, 0xffff) AM_WRITE(vt03_8000_sp69_w)
+ADDRESS_MAP_END
+
+
static ADDRESS_MAP_START( nes_vt_cy_map, AS_PROGRAM, 8, nes_vt_state )
AM_IMPORT_FROM(nes_vt_xx_map)
AM_RANGE(0x41b0, 0x41bf) AM_READ(vt03_41bx_r) AM_WRITE(vt03_41bx_w)
AM_RANGE(0x48a0, 0x48af) AM_READ(vt03_48ax_r) AM_WRITE(vt03_48ax_w)
+ AM_RANGE(0x4130, 0x4136) AM_READ(vt03_413x_r) AM_WRITE(vt03_413x_w)
+ AM_RANGE(0x414F, 0x414F) AM_READ(vt03_414f_r)
+ AM_RANGE(0x415C, 0x415C ) AM_READ(vt03_415c_r)
+
ADDRESS_MAP_END
static ADDRESS_MAP_START( nes_vt_bt_map, AS_PROGRAM, 8, nes_vt_state )
@@ -909,13 +1230,17 @@ static ADDRESS_MAP_START( nes_vt_hh_map, AS_PROGRAM, 8, nes_vt_state )
AM_RANGE(0x4016, 0x4016) AM_READWRITE(nes_in0_r, nes_in0_w)
AM_RANGE(0x4017, 0x4017) AM_READ(nes_in1_r) AM_WRITE(psg1_4017_w)
- AM_RANGE(0x4100, 0x410b) AM_WRITE(vt03_410x_w)
+ AM_RANGE(0x4100, 0x410b) AM_READ(vt03_410x_r) AM_WRITE(vt03_410x_w)
AM_RANGE(0x8000, 0xffff) AM_DEVICE("prg", address_map_bank_device, amap8)
AM_RANGE(0x8000, 0xffff) AM_WRITE(vt03_8000_w)
AM_RANGE(0x4034, 0x4034) AM_WRITE(vt03_4034_w)
AM_RANGE(0x4014, 0x4014) AM_READ(psg1_4014_r) AM_WRITE(vt_hh_sprite_dma_w)
+
+ AM_RANGE(0x414A, 0x414A) AM_READ(vthh_414a_r)
+ AM_RANGE(0x411d, 0x411d) AM_WRITE(vtfp_411d_w)
+
AM_RANGE(0x6000, 0x7fff) AM_RAM
ADDRESS_MAP_END
@@ -928,7 +1253,7 @@ static ADDRESS_MAP_START( nes_vt_dg_map, AS_PROGRAM, 8, nes_vt_state )
AM_RANGE(0x4016, 0x4016) AM_READWRITE(nes_in0_r, nes_in0_w)
AM_RANGE(0x4017, 0x4017) AM_READ(nes_in1_r) AM_WRITE(psg1_4017_w)
- AM_RANGE(0x4100, 0x410b) AM_WRITE(vt03_410x_w)
+ AM_RANGE(0x4100, 0x410b) AM_READ(vt03_410x_r) AM_WRITE(vt03_410x_w)
AM_RANGE(0x411c, 0x411c) AM_WRITE(vt03_411c_w)
@@ -940,6 +1265,26 @@ static ADDRESS_MAP_START( nes_vt_dg_map, AS_PROGRAM, 8, nes_vt_state )
AM_RANGE(0x6000, 0x7fff) AM_RAM
ADDRESS_MAP_END
+static ADDRESS_MAP_START( nes_vt_fp_map, AS_PROGRAM, 8, nes_vt_state )
+ AM_IMPORT_FROM(nes_vt_hh_map)
+ AM_RANGE(0x411e, 0x411e) AM_WRITE(vtfp_411e_w)
+ AM_RANGE(0x4a00, 0x4a00) AM_WRITE(vtfp_4a00_w)
+ AM_RANGE(0x412c, 0x412c) AM_WRITE(vtfp_412c_w)
+ AM_RANGE(0x412d, 0x412d) AM_READ(vtfp_412d_r)
+ AM_RANGE(0x4242, 0x4242) AM_WRITE(vtfp_4242_w)
+ AM_RANGE(0x4119, 0x4119) AM_READ(vtfp_4119_r)
+
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( nes_vt_fa_map, AS_PROGRAM, 8, nes_vt_state )
+
+ AM_IMPORT_FROM(nes_vt_dg_map)
+
+ AM_RANGE(0x412c, 0x412c) AM_READ(vtfa_412c_r) AM_WRITE(vtfa_412c_w)
+ AM_RANGE(0x4242, 0x4242) AM_WRITE(vtfp_4242_w)
+
+ADDRESS_MAP_END
+
static ADDRESS_MAP_START( prg_map, AS_PROGRAM, 8, nes_vt_state )
AM_RANGE(0x0000, 0x1fff) AM_ROMBANK("prg_bank0")
AM_RANGE(0x2000, 0x3fff) AM_ROMBANK("prg_bank1")
@@ -993,9 +1338,17 @@ static GFXDECODE_START( vt03_helper )
GFXDECODE_END
+static const uint8_t descram_ppu_2012_2017[5][6] = {
+ {0x2, 0x3, 0x4, 0x5, 0x6, 0x7},
+ {0x3, 0x2, 0x7, 0x6, 0x5, 0x4},
+ {0x2, 0x3, 0x4, 0x5, 0x6, 0x7},
+ {0x7, 0x6, 0x5, 0x4, 0x2, 0x3},
+ {0x4, 0x7, 0x2, 0x6, 0x5, 0x3},
+};
+
MACHINE_CONFIG_START(nes_vt_state::nes_vt)
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", M6502, NTSC_APU_CLOCK) // selectable speed?
+ MCFG_CPU_ADD("maincpu", M6502_VTSCR, NTSC_APU_CLOCK) // selectable speed?
MCFG_CPU_PROGRAM_MAP(nes_vt_map)
MCFG_SCREEN_ADD("screen", RASTER)
@@ -1043,6 +1396,32 @@ MACHINE_CONFIG_START(nes_vt_state::nes_vt)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
MACHINE_CONFIG_END
+MACHINE_CONFIG_DERIVED(nes_vt_state::nes_vt_hum, nes_vt)
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(nes_vt_hum_map)
+
+ MCFG_PPU_VT03_MODIFY("ppu")
+ MCFG_PPU_VT03_SET_DESCRAMBLE(descram_ppu_2012_2017[3]);
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_DERIVED(nes_vt_state::nes_vt_pjoy, nes_vt)
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(nes_vt_pjoy_map)
+
+ MCFG_PPU_VT03_MODIFY("ppu")
+ MCFG_PPU_VT03_SET_DESCRAMBLE(descram_ppu_2012_2017[2]);
+MACHINE_CONFIG_END
+
+
+MACHINE_CONFIG_DERIVED(nes_vt_state::nes_vt_sp69, nes_vt)
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(nes_vt_sp69_map)
+
+ MCFG_PPU_VT03_MODIFY("ppu")
+ MCFG_PPU_VT03_SET_DESCRAMBLE(descram_ppu_2012_2017[4]);
+MACHINE_CONFIG_END
+
+
MACHINE_CONFIG_DERIVED(nes_vt_state::nes_vt_xx, nes_vt)
MCFG_CPU_MODIFY("maincpu")
MCFG_CPU_PROGRAM_MAP(nes_vt_xx_map)
@@ -1095,8 +1474,37 @@ MACHINE_CONFIG_DERIVED(nes_vt_state::nes_vt_hh, nes_vt_xx)
MACHINE_CONFIG_END
static INPUT_PORTS_START( nes_vt )
+PORT_START("CARTSEL")
INPUT_PORTS_END
+MACHINE_CONFIG_DERIVED(nes_vt_state::nes_vt_fp, nes_vt_xx)
+MCFG_CPU_MODIFY("maincpu")
+MCFG_CPU_PROGRAM_MAP(nes_vt_fp_map)
+
+MCFG_PPU_VT03_MODIFY("ppu")
+MCFG_PPU_VT03_SET_PAL_MODE(PAL_MODE_NEW_RGB12);
+MACHINE_CONFIG_END
+
+MACHINE_CONFIG_DERIVED(nes_vt_state::nes_vt_fa, nes_vt_xx)
+MCFG_CPU_MODIFY("maincpu")
+MCFG_CPU_PROGRAM_MAP(nes_vt_fa_map)
+
+MACHINE_CONFIG_END
+
+
+static INPUT_PORTS_START( nes_vt_fp )
+ PORT_START("CARTSEL")
+ PORT_DIPNAME( 0x06, 0x00, "Cartridge Select" ) PORT_CODE(KEYCODE_3) PORT_TOGGLE
+ PORT_DIPSETTING( 0x00, "472-in-1" )
+ PORT_DIPSETTING( 0x06, "128-in-1" )
+MACHINE_CONFIG_END
+
+static INPUT_PORTS_START( nes_vt_fa )
+ PORT_START("CARTSEL")
+ PORT_DIPNAME( 0x01, 0x00, "Cartridge Select" ) PORT_CODE(KEYCODE_3) PORT_TOGGLE
+ PORT_DIPSETTING( 0x00, "508-in-1" )
+ PORT_DIPSETTING( 0x01, "130-in-1" )
+MACHINE_CONFIG_END
ROM_START( vdogdeme )
@@ -1273,6 +1681,11 @@ ROM_START( sy889 )
ROM_REGION( 0x800000, "mainrom", 0 )
ROM_LOAD( "sy889_w25q64.bin", 0x00000, 0x800000, CRC(fcdaa6fc) SHA1(0493747facf2172b8af22010851668bb18cbb3e4) )
ROM_END
+
+ROM_START( sy888b )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "sy888b_f25q32.bin", 0x00000, 0x400000, CRC(a8298c33) SHA1(7112dd13d5fb5f9f9d496816758defd22773ec6e) )
+ROM_END
#if 0
ROM_START( mc_15kin1 )
ROM_REGION( 0x200000, "mainrom", 0 )
@@ -1291,7 +1704,7 @@ ROM_END
#endif
ROM_START( dgun2573 )
ROM_REGION( 0x2000000, "mainrom", 0 )
- ROM_LOAD( "dgun2573.bin", 0x00000, 0x2000000, CRC(cde71a53) SHA1(d0d4c1965876291861781ecde46b1142b062f1f3) )
+ ROM_LOAD( "dgun2573.bin", 0x00000, 0x2000000, BAD_DUMP CRC(cde71a53) SHA1(d0d4c1965876291861781ecde46b1142b062f1f3) )
ROM_END
ROM_START( bittboy )
@@ -1299,6 +1712,61 @@ ROM_START( bittboy )
ROM_LOAD( "bittboy_flash_read_S29GL256N-TF-V2.bin", 0x00000, 0x2000000, CRC(24c802d7) SHA1(c1300ff799b93b9b53060b94d3985db4389c5d3a) )
ROM_END
+ROM_START( mc_89in1 )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "89in1.bin", 0x00000, 0x400000, CRC(b97f8ce5) SHA1(1a8e67f2b58a671ceec2b0ed18ec5954a71ae63a) )
+ROM_END
+
+ROM_START( mc_cb280 )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "w25q32.u5", 0x00000, 0x400000, CRC(c9541bdf) SHA1(f0ce46f18658ca5dbed881e5a80460e59820bbd0) )
+ROM_END
+
+ROM_START( mc_pg150 )
+ ROM_REGION( 0x2000000, "mainrom", 0 )
+ ROM_LOAD( "pocketgames150-in1.bin", 0x00000, 0x2000000, CRC(32f1176b) SHA1(2cfd9b61ebdfc328f020ae9bd5e5e2219321e828) )
+ROM_END
+
+ROM_START( mc_hh210 )
+ ROM_REGION( 0x1000000, "mainrom", 0 )
+ ROM_LOAD( "msp55lv128t.u4", 0x00000, 0x1000000, CRC(9ba520d4) SHA1(627f811b24314197e289a2ade668ff4115421bed) )
+ROM_END
+
+ROM_START( dvnimbus )
+ ROM_REGION( 0x1000000, "mainrom", 0 )
+ ROM_LOAD( "2012-7-4-V1.BIN", 0x00000, 0x1000000, CRC(a91d7aa6) SHA1(9421b70b281bb630752bc352c3715258044c0bbe) )
+ROM_END
+
+ROM_START( cbrs8 )
+ ROM_REGION( 0x1000000, "mainrom", 0 )
+ ROM_LOAD( "RS-8.bin", 0x00000, 0x1000000, BAD_DUMP CRC(10b2bed0) SHA1(0453a1e6769818ccf25dcf22b2c6198a5688a1d4) )
+ROM_END
+
+ROM_START( mc_tv200 )
+ ROM_REGION( 0x800000, "mainrom", 0 )
+ ROM_LOAD( "S29GL064N90.bin", 0x00000, 0x800000, CRC(ae1905d2) SHA1(11582055713ba937c1ad32c4ada8683eebc1c83c) )
+ROM_END
+
+ROM_START( fcpocket )
+ ROM_REGION( 0x8000000, "mainrom", 0 )
+ ROM_LOAD( "S29GL01GP.bin", 0x00000, 0x8000000, CRC(8703b18a) SHA1(07943443294e80ca93f83181c8bdbf950b87c52f) )
+ROM_END
+
+ROM_START( mog_m320 )
+ ROM_REGION( 0x800000, "mainrom", 0 )
+ ROM_LOAD( "W25Q64FV.bin", 0x00000, 0x800000, CRC(3c5e1b36) SHA1(4bcbf35ebf2b1714ccde5de758a89a6a39528f89) )
+ROM_END
+
+ROM_START( fapocket )
+ ROM_REGION( 0x4000000, "mainrom", 0 )
+ ROM_LOAD( "S29GL512N.bin", 0x00000, 0x4000000, CRC(37d0fb06) SHA1(0146a2fae32e23b65d4032c508f0d12cedd399c3) )
+ROM_END
+
+ROM_START( zdog )
+ ROM_REGION( 0x400000, "mainrom", 0 )
+ ROM_LOAD( "zdog.bin", 0x00000, 0x400000, CRC(5ed3485b) SHA1(5ab0e9370d4ed1535205deb0456878c4e400dd81) )
+ROM_END
+
// earlier version of vdogdemo
CONS( 200?, vdogdeme, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "VRT", "V-Dog (prototype, earlier)", MACHINE_NOT_WORKING )
@@ -1325,52 +1793,86 @@ CONS( 200?, vgpmini, 0, 0, nes_vt_vg, nes_vt, nes_vt_state, 0, "<unknown>",
// emulation
CONS( 200?, dgun2500, 0, 0, nes_vt_dg, nes_vt, nes_vt_state, 0, "dreamGEAR", "dreamGEAR Wireless Motion Control with 130 games (DGUN-2500)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND)
-// these are NOT VT03, but something newer but based around the same basic designs
-// (no visible tiles in ROM using standard decodes tho, might need moving out of here)
-// dgun2561 at least boots, but no visible gfx due to missing PPU features
-CONS( 2012, dgun2561, 0, 0, nes_vt_dg, nes_vt, nes_vt_state, 0, "dreamGEAR", "dreamGEAR My Arcade Portable Gaming System (DGUN-2561)", MACHINE_NOT_WORKING )
-CONS( 2015, dgun2573, 0, 0, nes_vt_hh, nes_vt, nes_vt_state, 0, "dreamGEAR", "dreamGEAR My Arcade Gamer V Portable Gaming System (DGUN-2573)", MACHINE_NOT_WORKING )
+// don't even get to menu. very enhanced chipset, VT368/9?
+CONS( 2012, dgun2561, 0, 0, nes_vt_cy, nes_vt, nes_vt_state, 0, "dreamGEAR", "dreamGEAR My Arcade Portable Gaming System (DGUN-2561)", MACHINE_NOT_WORKING )
CONS( 200?, lexcyber, 0, 0, nes_vt_cy, nes_vt, nes_vt_state, 0, "Lexibook", "Lexibook Compact Cyber Arcade", MACHINE_NOT_WORKING )
+// boots, same platform with scrambled opcodes as FC pocket
+// palette issues in some games because they actually use the old VT style palette
+// but no way to switch?
+// some menu gfx broken, probably because this is a bad dump
+CONS( 2015, dgun2573, 0, 0, nes_vt_fp, nes_vt, nes_vt_state, 0, "dreamGEAR", "dreamGEAR My Arcade Gamer V Portable Gaming System (DGUN-2573)", MACHINE_WRONG_COLORS | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+
// these are VT1682 based and have scrambled CPU opcodes. Will need VT1682 CPU and PPU
// to be emulated
// (no visible tiles in ROM using standard decodes tho, might need moving out of here)
CONS( 200?, ii8in1, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "Intec", "InterAct 8-in-1", MACHINE_NOT_WORKING )
CONS( 200?, ii32in1, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "Intec", "InterAct 32-in-1", MACHINE_NOT_WORKING )
-// this has 'Shark' and 'Octopus' etc. like mc_dgear but the graphics are entirely corrupt for any game using the extended modes, bad dump or different banking?
-CONS( 200?, mc_sp69, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "Sports Game 69 in 1", MACHINE_NOT_WORKING )
+// this has 'Shark' and 'Octopus' etc. like mc_dgear but uses scrambled bank registers
+CONS( 200?, mc_sp69, 0, 0, nes_vt_sp69, nes_vt, nes_vt_state, 0, "<unknown>", "Sports Game 69 in 1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND)
-// doesn't boot
-CONS( 200?, mc_sam60, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "Hummer Technology Co., Ltd.", "Samuri (60 in 1)", MACHINE_NOT_WORKING )
+// Hummer systems, scrambled bank register
+CONS( 200?, mc_sam60, 0, 0, nes_vt_hum, nes_vt, nes_vt_state, 0, "Hummer Technology Co., Ltd.", "Samuri (60 in 1)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 200?, zdog, 0, 0, nes_vt_hum, nes_vt, nes_vt_state, 0, "Hummer Technology Co., Ltd.", "ZDog (44 in 1)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
// titles below don't seem to use the enhanced modes, so probably VT01 / VT02 or plain standalone famiclones?
// very plain menus
-CONS( 200?, pjoyn50, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "PowerJoy Navigator 50 in 1", MACHINE_NOT_WORKING )
-CONS( 200?, pjoys30, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "PowerJoy Supermax 30 in 1", MACHINE_NOT_WORKING )
-CONS( 200?, pjoys60, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "PowerJoy Supermax 60 in 1", MACHINE_NOT_WORKING )
+CONS( 200?, pjoyn50, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "PowerJoy Navigator 50 in 1", MACHINE_IMPERFECT_GRAPHICS )
+CONS( 200?, pjoys30, 0, 0, nes_vt_pjoy, nes_vt, nes_vt_state, 0, "<unknown>", "PowerJoy Supermax 30 in 1", MACHINE_IMPERFECT_GRAPHICS )
+CONS( 200?, pjoys60, 0, 0, nes_vt_pjoy, nes_vt, nes_vt_state, 0, "<unknown>", "PowerJoy Supermax 60 in 1", MACHINE_IMPERFECT_GRAPHICS )
// has a non-enhanced version of 'Octopus' as game 30
-CONS( 200?, sarc110, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "Super Arcade 110 (set 1)", MACHINE_NOT_WORKING )
-CONS( 200?, sarc110a, sarc110, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "Super Arcade 110 (set 2)", MACHINE_NOT_WORKING )
+CONS( 200?, sarc110, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "Super Arcade 110 (set 1)", MACHINE_IMPERFECT_GRAPHICS )
+CONS( 200?, sarc110a, sarc110, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "Super Arcade 110 (set 2)", MACHINE_IMPERFECT_GRAPHICS )
// both offer chinese or english menus
CONS( 200?, mc_110cb, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "CoolBoy", "110 in 1 CoolBaby (CoolBoy RS-1S)", MACHINE_IMPERFECT_GRAPHICS )
CONS( 200?, mc_138cb, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "CoolBoy", "138 in 1 CoolBaby (CoolBoy RS-5, PCB060-10009011V1.3)", MACHINE_IMPERFECT_GRAPHICS )
+// doesn't boot, bad dump
+CONS( 201?, cbrs8, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "CoolBoy", "CoolBoy RS-8 168 in 1", MACHINE_NOT_WORKING )
+
CONS( 200?, gprnrs1, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "Game Prince RS-1", MACHINE_IMPERFECT_GRAPHICS )
CONS( 200?, gprnrs16, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "Game Prince RS-16", MACHINE_IMPERFECT_GRAPHICS )
// unsorted, these were all in nes.xml listed as ONE BUS systems
CONS( 200?, mc_dg101, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "dreamGEAR", "dreamGEAR 101 in 1", MACHINE_IMPERFECT_GRAPHICS ) // dreamGear, but no enhanced games?
-CONS( 200?, mc_aa2, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "100 in 1 Arcade Action II (AT-103)", MACHINE_NOT_WORKING )
+CONS( 200?, mc_aa2, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "100 in 1 Arcade Action II (AT-103)", MACHINE_IMPERFECT_GRAPHICS )
CONS( 200?, mc_105te, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "2011 Super HiK 105 in 1 Turbo Edition", MACHINE_NOT_WORKING )
-CONS( 200?, mc_8x6cb, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "CoolBoy", "888888 in 1 (Coolboy AEF-390)", MACHINE_NOT_WORKING )
-CONS( 200?, mc_9x6ss, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "999999 in 1 (PXP2 Slim Station)", MACHINE_NOT_WORKING )
-CONS( 200?, mc_9x6sa, mc_9x6ss, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "999999 in 1 (8 bit Slim Station, NEWPXP-DVT22-A PCB)", MACHINE_NOT_WORKING )
+CONS( 200?, mc_8x6cb, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "CoolBoy", "888888 in 1 (Coolboy AEF-390)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+CONS( 200?, mc_9x6ss, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "999999 in 1 (PXP2 Slim Station)", MACHINE_IMPERFECT_GRAPHICS )
+CONS( 200?, mc_9x6sa, mc_9x6ss, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "999999 in 1 (8 bit Slim Station, NEWPXP-DVT22-A PCB)", MACHINE_IMPERFECT_GRAPHICS )
CONS( 200?, mc_7x6ss, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "777777 in 1 (8 bit Slim Station, NEWPXP-DVT22-A PCB)", MACHINE_IMPERFECT_GRAPHICS )
CONS( 200?, mc_8x6ss, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "888888 in 1 (8 bit Slim Station, NEWPXP-DVT22-A PCB)", MACHINE_IMPERFECT_GRAPHICS )
CONS( 2004, mc_dcat8, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "100 in 1 (D-CAT8 8bit Console, set 1) (v5.01.11-frd, BL 20041217)", MACHINE_IMPERFECT_GRAPHICS )
CONS( 2004, mc_dcat8a, mc_dcat8, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "100 in 1 (D-CAT8 8bit Console, set 2)", MACHINE_IMPERFECT_GRAPHICS )
+
// Runs well, minor GFX issues in intro
-CONS( 2017, sy889, 0, 0, nes_vt_hh, nes_vt, nes_vt_state, 0, "SY Corp", "SY-889 300 in 1 Handheld", MACHINE_NOT_WORKING )
+CONS( 2017, sy889, 0, 0, nes_vt_hh, nes_vt, nes_vt_state, 0, "SY Corp", "SY-889 300 in 1 Handheld", MACHINE_IMPERFECT_GRAPHICS )
+CONS( 2016, sy888b, 0, 0, nes_vt_hh, nes_vt, nes_vt_state, 0, "SY Corp", "SY-888B 288 in 1 Handheld", MACHINE_IMPERFECT_GRAPHICS )
+
+// Same hardware as SY-889
+CONS( 201?, mc_cb280, 0, 0, nes_vt_hh, nes_vt, nes_vt_state, 0, "CoolBoy", "Coolboy RS-18 (280 in 1)", MACHINE_IMPERFECT_GRAPHICS )
+
// Runs well, only issues in SMB3 which crashes
-CONS( 2017, bittboy, 0, 0, nes_vt_bt, nes_vt, nes_vt_state, 0, "BittBoy", "BittBoy Mini FC 300 in 1", MACHINE_NOT_WORKING )
+CONS( 2017, bittboy, 0, 0, nes_vt_bt, nes_vt, nes_vt_state, 0, "BittBoy", "BittBoy Mini FC 300 in 1", MACHINE_IMPERFECT_GRAPHICS )
+// Runs well, all games seem to work
+CONS( 201?, mc_89in1, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "<unknown>", "89 in 1 Mini Game Console (060-92023011V1.0)", MACHINE_IMPERFECT_GRAPHICS )
+// Broken GFX, investigate
+CONS( 201?, mc_pg150, 0, 0, nes_vt_bt, nes_vt, nes_vt_state, 0, "<unknown>", "Pocket Games 150 in 1", MACHINE_NOT_WORKING )
+// No title screen, but press start and menu and games run fine. Makes odd
+// memory accesses which probably explain broken title screen
+CONS( 201?, mc_hh210, 0, 0, nes_vt_xx, nes_vt, nes_vt_state, 0, "<unknown>", "Handheld 210 in 1", MACHINE_NOT_WORKING )
+// First half of games don't work, probably bad dump
+CONS( 201?, dvnimbus, 0, 0, nes_vt_vg, nes_vt, nes_vt_state, 0, "<unknown>", "DVTech Nimbus 176 in 1", MACHINE_NOT_WORKING )
+// Works fine, VT02 based
+CONS( 201?, mc_tv200, 0, 0, nes_vt, nes_vt, nes_vt_state, 0, "Thumbs Up", "200 in 1 Retro TV Game", MACHINE_IMPERFECT_GRAPHICS )
+// New platform with scrambled opcodes, same as DGUN-2561. Runs fine with minor GFX and sound issues in menu
+// Use DIP switch to select console or cartridge, as cartridge is fake and just toggles a GPIO
+CONS( 2016, fcpocket, 0, 0, nes_vt_fp, nes_vt_fp, nes_vt_state, 0, "<unknown>", "FC Pocket 600 in 1", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND )
+// Probably VT09 or similar
+// Use DIP switch to select console or cartridge, as cartridge is fake and just toggles a ROM high address bit
+// (which can also be overriden by GPIO)
+CONS( 2017, fapocket, 0, 0, nes_vt_fa, nes_vt_fa, nes_vt_state, 0, "<unknown>", "Family Pocket 638 in 1", MACHINE_IMPERFECT_GRAPHICS )
+
+// Plays intro music but then crashes. same hardware as SY-88x but uses more features
+CONS( 2016, mog_m320, 0, 0, nes_vt_hh, nes_vt, nes_vt_state, 0, "MOGIS", "MOGIS M320 246 in 1 Handheld", MACHINE_NOT_WORKING )
diff --git a/src/mame/machine/m6502_vtscr.cpp b/src/mame/machine/m6502_vtscr.cpp
new file mode 100644
index 00000000000..e8f76bae096
--- /dev/null
+++ b/src/mame/machine/m6502_vtscr.cpp
@@ -0,0 +1,97 @@
+// license:BSD-3-Clause
+// copyright-holders:David Shah
+/***************************************************************************
+
+ m6502_vtscr.cpp
+
+ 6502 with VRT VTxx instruction scrambling
+
+ Scrambling in newer NES-based VTxx systems (FC pocket, etc) seems to be
+ enabled with a write of 5 to 0x411E, then is activated at the next jump?
+ When enabled, opcodes are to be XORed with 0xA1
+
+ Another form of scrambling is used in the VRT VT1682, this is not yet
+ implemented at all in MAME (it's used for the MiWi2 and InterAct consoles).
+ This is simpler, permanently activated and consists of swapping opcode bits
+ 7 and 2.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "m6502_vtscr.h"
+
+DEFINE_DEVICE_TYPE(M6502_VTSCR, m6502_vtscr, "m6502_vtscr", "M6502 with VTxx scrambling")
+
+m6502_vtscr::m6502_vtscr(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ m6502_device(mconfig, M6502_VTSCR, tag, owner, clock)
+{
+}
+
+void m6502_vtscr::device_start()
+{
+ mintf = std::make_unique<mi_decrypt>();
+ set_scramble(false);
+ init();
+}
+
+void m6502_vtscr::set_next_scramble(bool scr)
+{
+ downcast<mi_decrypt &>(*mintf).m_next_scramble = scr;
+}
+
+void m6502_vtscr::set_scramble(bool scr)
+{
+ downcast<mi_decrypt &>(*mintf).m_next_scramble = scr;
+ downcast<mi_decrypt &>(*mintf).m_scramble_en = scr;
+}
+
+
+void m6502_vtscr::device_reset()
+{
+ set_scramble(false);
+ m6502_device::device_reset();
+}
+
+bool m6502_vtscr::mi_decrypt::toggle_scramble(uint8_t op) {
+ return (op == 0x4C) || (op == 0x00) || (op == 0x6C);
+}
+
+
+uint8_t m6502_vtscr::mi_decrypt::read_sync(uint16_t adr)
+{
+ uint8_t res = direct->read_byte(adr);
+ if(m_scramble_en)
+ {
+ res = descramble(res);
+ }
+
+ if(toggle_scramble(res))
+ {
+ m_scramble_en = m_next_scramble;
+ }
+ return res;
+}
+
+uint8_t m6502_vtscr::mi_decrypt::descramble(uint8_t op)
+{
+ return op ^ 0xA1;
+}
+
+util::disasm_interface *m6502_vtscr::create_disassembler()
+{
+ return new disassembler(downcast<mi_decrypt *>(mintf.get()));
+}
+
+m6502_vtscr::disassembler::disassembler(mi_decrypt *mi) : mintf(mi)
+{
+}
+
+u32 m6502_vtscr::disassembler::interface_flags() const
+{
+ return SPLIT_DECRYPTION;
+}
+
+u8 m6502_vtscr::disassembler::decrypt8(u8 value, offs_t pc, bool opcode) const
+{
+ return opcode && mintf->m_scramble_en ? mintf->descramble(value) : value;
+}
diff --git a/src/mame/machine/m6502_vtscr.h b/src/mame/machine/m6502_vtscr.h
new file mode 100644
index 00000000000..bb24cdb2719
--- /dev/null
+++ b/src/mame/machine/m6502_vtscr.h
@@ -0,0 +1,58 @@
+// license:BSD-3-Clause
+// copyright-holders:David Shah
+/***************************************************************************
+
+ m6502_vtscr.h
+
+ 6502 with VRT VTxx instruction scrambling
+
+***************************************************************************/
+
+#ifndef MAME_CPU_M6502_VTSCR_H
+#define MAME_CPU_M6502_VTSCR_H
+
+#pragma once
+
+#include "cpu/m6502/m6502.h"
+#include "cpu/m6502/m6502d.h"
+
+class m6502_vtscr : public m6502_device {
+public:
+ m6502_vtscr(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void set_next_scramble(bool scr);
+ void set_scramble(bool scr);
+
+protected:
+ class mi_decrypt : public mi_default_normal {
+ public:
+
+ bool m_scramble_en = false;
+ bool m_next_scramble = false;
+
+ virtual ~mi_decrypt() {}
+ virtual uint8_t read_sync(uint16_t adr) override;
+
+ uint8_t descramble(uint8_t op);
+ bool toggle_scramble(uint8_t op);
+
+ };
+
+ class disassembler : public m6502_disassembler {
+ public:
+ mi_decrypt *mintf;
+
+ disassembler(mi_decrypt *m);
+ virtual ~disassembler() = default;
+ virtual u32 interface_flags() const override;
+ virtual u8 decrypt8(u8 value, offs_t pc, bool opcode) const override;
+ };
+
+ virtual void device_reset() override;
+ virtual void device_start() override;
+ virtual util::disasm_interface *create_disassembler() override;
+};
+
+DECLARE_DEVICE_TYPE(M6502_VTSCR, m6502_vtscr)
+
+#endif // MAME_CPU_M6502_VTSCR_H
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 1c63421d7bb..76f5ca6e9a3 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -29799,8 +29799,20 @@ gprnrs16
vgpocket
vgpmini
sy889
+sy888b
dgun2573
bittboy
+mc_89in1
+mc_cb280
+mc_pg150
+mc_hh210
+dvnimbus
+cbrs8
+mc_tv200
+fcpocket
+mog_m320
+fapocket
+zdog
@source:newbrain.cpp
newbrain //