summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author MooglyGuy <MooglyGuy@users.noreply.github.com>2022-01-07 16:32:21 +0100
committer GitHub <noreply@github.com>2022-01-08 02:32:21 +1100
commita3cc6df3495d4fd390c51170acaeaafe267ad964 (patch)
tree177a3d095e5f31fbc5b521f38054318e2c730758
parent6cb03e6627bcca748b6f114ecd53b5da33c55f6f (diff)
-Significant updates to the CD-i driver [Ryan Holtz] (#9102)
-mcd212: Assorted changes. [Ryan Holtz] * Replaced verboselog with logmacro. * Corrected end-of-line region control handling, fixing garbage in The Apprentice. * Fixed screen bitmap handling to be more in line with MAME standards. * Simplified region-control handling. * Removed historical reliance on debug machine switches. * Converted to use a map() function rather than an internal switch. * Converted to use dipalette and rgb_t internally instead of separate CLUT arrays. * Optimized by replacing rgb_t usage with uint32_t values. * Optimized by calculating plane transparency on the fly. * Templatized mix_lines to reduce inner-loop branching. * Fixed a clamping issue with pre-calculated DYUV limits. * Reduce effective color depth back to 6:6:6 to match hardware. -cdrom: Allow recognizing CDI/2352 in cuesheets. [Ryan Holtz] -cdic: Various audio-related changes. [Ryan Holtz] * Attempt to descramble sectors that don't initially appear sensible. * Added support for playing CDDA sectors. * Fixed faulty logic in TOC processing.
-rw-r--r--hash/cdi.xml2
-rw-r--r--src/lib/util/cdrom.cpp5
-rw-r--r--src/mame/drivers/cdi.cpp151
-rw-r--r--src/mame/includes/cdi.h11
-rw-r--r--src/mame/machine/cdicdic.cpp378
-rw-r--r--src/mame/machine/cdicdic.h9
-rw-r--r--src/mame/video/mcd212.cpp1824
-rw-r--r--src/mame/video/mcd212.h359
8 files changed, 1451 insertions, 1288 deletions
diff --git a/hash/cdi.xml b/hash/cdi.xml
index 1eba5394983..8eb754ef06d 100644
--- a/hash/cdi.xml
+++ b/hash/cdi.xml
@@ -10700,7 +10700,7 @@ license:CC0
<publisher>The Vision Factory</publisher>
<part name="cdrom" interface="cdi_cdrom">
<diskarea name="cdrom">
- <disk name="the apprentice (cdi-ready)" sha1="7e1f612f1c36dabdc304abf2d17200b5faa4e180" status="baddump"/>
+ <disk name="the apprentice (cdi-ready)" sha1="3a66337c20b9157e64228847ee3d153f80c25e4e"/>
</diskarea>
</part>
</software>
diff --git a/src/lib/util/cdrom.cpp b/src/lib/util/cdrom.cpp
index 8545ed4725a..a935cd50612 100644
--- a/src/lib/util/cdrom.cpp
+++ b/src/lib/util/cdrom.cpp
@@ -970,6 +970,11 @@ static void cdrom_get_info_from_type_string(const char *typestring, uint32_t *tr
*trktype = CD_TRACK_MODE2_RAW;
*datasize = 2352;
}
+ else if (!strcmp(typestring, "CDI/2352"))
+ {
+ *trktype = CD_TRACK_MODE2_RAW;
+ *datasize = 2352;
+ }
else if (!strcmp(typestring, "AUDIO"))
{
*trktype = CD_TRACK_AUDIO;
diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp
index 37095ebe8ac..40cb2e4d876 100644
--- a/src/mame/drivers/cdi.cpp
+++ b/src/mame/drivers/cdi.cpp
@@ -92,7 +92,7 @@ void cdi_state::cdimono1_mem(address_map &map)
map(0x318000, 0x31ffff).noprw();
map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */
map(0x400000, 0x47ffff).rom().region("maincpu", 0);
- map(0x4fffe0, 0x4fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w));
+ map(0x4fffe0, 0x4fffff).m(m_mcd212, FUNC(mcd212_device::map));
map(0x500000, 0x57ffff).ram();
map(0xd00000, 0xdfffff).ram(); // DVC RAM block 1
map(0xe00000, 0xe7ffff).rw(FUNC(cdi_state::dvc_r), FUNC(cdi_state::dvc_w));
@@ -106,13 +106,9 @@ void cdi_state::cdimono2_mem(address_map &map)
#if ENABLE_UART_PRINTING
map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable));
#endif
- //map(0x300000, 0x303bff).rw("cdic", FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w));
- //map(0x303c00, 0x303fff).rw("cdic", FUNC(cdicdic_device::regs_r), FUNC(cdicdic_device::regs_w));
- //map(0x310000, 0x317fff).rw("slave", FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w));
- //map(0x318000, 0x31ffff).noprw();
map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */
map(0x400000, 0x47ffff).rom().region("maincpu", 0);
- map(0x4fffe0, 0x4fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w));
+ map(0x4fffe0, 0x4fffff).m(m_mcd212, FUNC(mcd212_device::map));
}
void cdi_state::cdi910_mem(address_map &map)
@@ -124,15 +120,9 @@ void cdi_state::cdi910_mem(address_map &map)
#if ENABLE_UART_PRINTING
map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable));
#endif
-// map(0x300000, 0x303bff).rw("cdic", FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w));
-// map(0x303c00, 0x303fff).rw("cdic", FUNC(cdicdic_device::regs_r), FUNC(cdicdic_device::regs_w));
-// map(0x310000, 0x317fff).rw("slave_hle", FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w));
-// map(0x318000, 0x31ffff).noprw();
map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */
- map(0x4fffe0, 0x4fffff).rw(m_mcd212, FUNC(mcd212_device::regs_r), FUNC(mcd212_device::regs_w));
-// map(0x500000, 0x57ffff).ram();
+ map(0x4fffe0, 0x4fffff).m(m_mcd212, FUNC(mcd212_device::map));
map(0x500000, 0xffffff).noprw();
-// map(0xe00000, 0xefffff).ram(); // DVC
}
@@ -141,69 +131,12 @@ void cdi_state::cdi910_mem(address_map &map)
*************************/
static INPUT_PORTS_START( cdi )
- PORT_START("DEBUG")
- PORT_CONFNAME( 0x01, 0x00, "Plane A Disable")
- PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
- PORT_CONFSETTING( 0x01, DEF_STR( On ) )
- PORT_CONFNAME( 0x02, 0x00, "Plane B Disable")
- PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
- PORT_CONFSETTING( 0x02, DEF_STR( On ) )
- PORT_CONFNAME( 0x04, 0x00, "Force Backdrop Color")
- PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
- PORT_CONFSETTING( 0x04, DEF_STR( On ) )
- PORT_CONFNAME( 0xf0, 0x00, "Backdrop Color")
- PORT_CONFSETTING( 0x00, "Black" )
- PORT_CONFSETTING( 0x10, "Half-Bright Blue" )
- PORT_CONFSETTING( 0x20, "Half-Bright Green" )
- PORT_CONFSETTING( 0x30, "Half-Bright Cyan" )
- PORT_CONFSETTING( 0x40, "Half-Bright Red" )
- PORT_CONFSETTING( 0x50, "Half-Bright Magenta" )
- PORT_CONFSETTING( 0x60, "Half-Bright Yellow" )
- PORT_CONFSETTING( 0x70, "Half-Bright White" )
- PORT_CONFSETTING( 0x80, "Black (Alternate)" )
- PORT_CONFSETTING( 0x90, "Blue" )
- PORT_CONFSETTING( 0xa0, "Green" )
- PORT_CONFSETTING( 0xb0, "Cyan" )
- PORT_CONFSETTING( 0xc0, "Red" )
- PORT_CONFSETTING( 0xd0, "Magenta" )
- PORT_CONFSETTING( 0xe0, "Yellow" )
- PORT_CONFSETTING( 0xf0, "White" )
INPUT_PORTS_END
static INPUT_PORTS_START( cdimono2 )
- PORT_START("DEBUG")
- PORT_CONFNAME( 0x01, 0x00, "Plane A Disable")
- PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
- PORT_CONFSETTING( 0x01, DEF_STR( On ) )
- PORT_CONFNAME( 0x02, 0x00, "Plane B Disable")
- PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
- PORT_CONFSETTING( 0x02, DEF_STR( On ) )
- PORT_CONFNAME( 0x04, 0x00, "Force Backdrop Color")
- PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
- PORT_CONFSETTING( 0x04, DEF_STR( On ) )
- PORT_CONFNAME( 0xf0, 0x00, "Backdrop Color")
- PORT_CONFSETTING( 0x00, "Black" )
- PORT_CONFSETTING( 0x10, "Half-Bright Blue" )
- PORT_CONFSETTING( 0x20, "Half-Bright Green" )
- PORT_CONFSETTING( 0x30, "Half-Bright Cyan" )
- PORT_CONFSETTING( 0x40, "Half-Bright Red" )
- PORT_CONFSETTING( 0x50, "Half-Bright Magenta" )
- PORT_CONFSETTING( 0x60, "Half-Bright Yellow" )
- PORT_CONFSETTING( 0x70, "Half-Bright White" )
- PORT_CONFSETTING( 0x80, "Black (Alternate)" )
- PORT_CONFSETTING( 0x90, "Blue" )
- PORT_CONFSETTING( 0xa0, "Green" )
- PORT_CONFSETTING( 0xb0, "Cyan" )
- PORT_CONFSETTING( 0xc0, "Red" )
- PORT_CONFSETTING( 0xd0, "Magenta" )
- PORT_CONFSETTING( 0xe0, "Yellow" )
- PORT_CONFSETTING( 0xf0, "White" )
INPUT_PORTS_END
-
static INPUT_PORTS_START( quizard )
- PORT_INCLUDE( cdi )
-
PORT_START("P0")
PORT_DIPNAME( 0x07, 0x05, "Settings" )
PORT_DIPSETTING( 0x00, "1 Coin, 0 Bonus Limit, 0 Bonus Number" )
@@ -419,40 +352,33 @@ static const uint16_t cdi220_lcd_char[20*22] =
0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0400, 0x0400, 0x0400, 0x0400
};
-void cdi_state::draw_lcd(int y)
+uint32_t cdi_state::screen_update_cdimono1_lcd(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- if (y >= 22 || !m_slave_hle.found())
- return;
-
- uint32_t *scanline = &m_lcdbitmap.pix(y);
+ if (!m_slave_hle.found())
+ return 0;
- for (int lcd = 0; lcd < 8; lcd++)
+ for (int y = 0; y < 22; y++)
{
- uint16_t data = (m_slave_hle->get_lcd_state()[lcd*2] << 8) |
- m_slave_hle->get_lcd_state()[lcd*2 + 1];
- for (int x = 0; x < 20; x++)
+ uint32_t *scanline = &bitmap.pix(y);
+
+ for (int lcd = 0; lcd < 8; lcd++)
{
- if (data & cdi220_lcd_char[y*20 + x])
- {
- scanline[(7 - lcd)*24 + x] = rgb_t::white();
- }
- else
+ uint16_t data = (m_slave_hle->get_lcd_state()[lcd*2] << 8) |
+ m_slave_hle->get_lcd_state()[lcd*2 + 1];
+ for (int x = 0; x < 20; x++)
{
- scanline[(7 - lcd)*24 + x] = rgb_t::black();
+ if (data & cdi220_lcd_char[y*20 + x])
+ {
+ scanline[(7 - lcd)*24 + x] = rgb_t::white();
+ }
+ else
+ {
+ scanline[(7 - lcd)*24 + x] = rgb_t::black();
+ }
}
}
}
-}
-void cdi_state::video_start()
-{
- if (m_lcd)
- m_lcd->register_screen_bitmap(m_lcdbitmap);
-}
-
-uint32_t cdi_state::screen_update_cdimono1_lcd(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
-{
- copybitmap(bitmap, m_lcdbitmap, 0, 0, 0, 0, cliprect);
return 0;
}
@@ -470,14 +396,15 @@ void cdi_state::cdimono1_base(machine_config &config)
MCD212(config, m_mcd212, CLOCK_A);
m_mcd212->set_screen("screen");
m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w));
- m_mcd212->set_scanline_callback(FUNC(cdi_state::draw_lcd));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(50);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
- screen.set_size(384, 302);
- screen.set_visarea(0, 384-1, 22, 302-1); // TODO: dynamic resolution
- screen.set_screen_update("mcd212", FUNC(mcd212_device::screen_update));
+ screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
+ screen.set_size(384, 312);
+ screen.set_visarea(0, 384-1, 0, 312-1); // TODO: dynamic resolution
+ screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update));
+ screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank));
SCREEN(config, m_lcd, SCREEN_TYPE_RASTER);
m_lcd->set_refresh_hz(50);
@@ -509,10 +436,6 @@ void cdi_state::cdimono1_base(machine_config &config)
DMADAC(config, m_dmadac[1]);
m_dmadac[1]->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
- CDDA(config, m_cdda);
- m_cdda->add_route(ALL_OUTPUTS, "lspeaker", 1.0);
- m_cdda->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
-
MK48T08(config, "mk48t08");
}
@@ -525,14 +448,15 @@ void cdi_state::cdimono2(machine_config &config)
MCD212(config, m_mcd212, CLOCK_A);
m_mcd212->set_screen("screen");
m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w));
- m_mcd212->set_scanline_callback(FUNC(cdi_state::draw_lcd));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
- screen.set_size(384, 302);
- screen.set_visarea(0, 384-1, 22, 302-1); // TODO: dynamic resolution
- screen.set_screen_update("mcd212", FUNC(mcd212_device::screen_update));
+ screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
+ screen.set_size(384, 312);
+ screen.set_visarea(0, 384-1, 0, 312-1); // TODO: dynamic resolution
+ screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update));
+ screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank));
SCREEN(config, m_lcd, SCREEN_TYPE_RASTER);
m_lcd->set_refresh_hz(60);
@@ -561,10 +485,6 @@ void cdi_state::cdimono2(machine_config &config)
DMADAC(config, m_dmadac[1]);
m_dmadac[1]->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
- CDDA(config, m_cdda);
- m_cdda->add_route(ALL_OUTPUTS, "lspeaker", 1.0);
- m_cdda->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
-
MK48T08(config, "mk48t08");
}
@@ -576,14 +496,15 @@ void cdi_state::cdi910(machine_config &config)
MCD212(config, m_mcd212, CLOCK_A);
m_mcd212->set_screen("screen");
m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w));
- m_mcd212->set_scanline_callback(FUNC(cdi_state::draw_lcd));
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(50);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(0));
+ screen.set_video_attributes(VIDEO_UPDATE_SCANLINE);
screen.set_size(384, 312);
screen.set_visarea(0, 384-1, 32, 312-1); // TODO: dynamic resolution
- screen.set_screen_update("mcd212", FUNC(mcd212_device::screen_update));
+ screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update));
+ screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank));
SCREEN(config, m_lcd, SCREEN_TYPE_RASTER);
m_lcd->set_refresh_hz(60);
@@ -612,10 +533,6 @@ void cdi_state::cdi910(machine_config &config)
DMADAC(config, m_dmadac[1]);
m_dmadac[1]->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
- CDDA(config, m_cdda);
- m_cdda->add_route(ALL_OUTPUTS, "lspeaker", 1.0);
- m_cdda->add_route(ALL_OUTPUTS, "rspeaker", 1.0);
-
MK48T08(config, "mk48t08");
}
diff --git a/src/mame/includes/cdi.h b/src/mame/includes/cdi.h
index 5b9f88e456b..d3e7445087f 100644
--- a/src/mame/includes/cdi.h
+++ b/src/mame/includes/cdi.h
@@ -21,14 +21,13 @@ public:
cdi_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
+ , m_lcd(*this, "lcd")
, m_planea(*this, "mcd212:planea")
, m_slave_hle(*this, "slave_hle")
, m_servo(*this, "servo")
, m_slave(*this, "slave")
, m_cdic(*this, "cdic")
- , m_cdda(*this, "cdda")
, m_mcd212(*this, "mcd212")
- , m_lcd(*this, "lcd")
, m_dmadac(*this, "dac%u", 1U)
{ }
@@ -43,10 +42,9 @@ protected:
void cdimono1_mem(address_map &map);
required_device<scc68070_device> m_maincpu;
+ optional_device<screen_device> m_lcd;
private:
- virtual void video_start() override;
-
enum servo_portc_bit_t
{
INV_JUC_OUT = (1 << 2),
@@ -54,7 +52,6 @@ private:
INV_CADDYSWITCH_IN = (1 << 7)
};
- void draw_lcd(int y);
uint32_t screen_update_cdimono1_lcd(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void cdi910_mem(address_map &map);
@@ -72,13 +69,9 @@ private:
optional_device<m68hc05c8_device> m_servo;
optional_device<m68hc05c8_device> m_slave;
optional_device<cdicdic_device> m_cdic;
- required_device<cdda_device> m_cdda;
required_device<mcd212_device> m_mcd212;
- optional_device<screen_device> m_lcd;
required_device_array<dmadac_sound_device, 2> m_dmadac;
-
- bitmap_rgb32 m_lcdbitmap;
};
class quizard_state : public cdi_state
diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp
index 68f39f75535..96fadf2b0bd 100644
--- a/src/mame/machine/cdicdic.cpp
+++ b/src/mame/machine/cdicdic.cpp
@@ -97,6 +97,162 @@ const uint16_t cdicdic_device::s_crc_ccitt_table[256] =
#define CRC_CCITT_ROUND(accum, data) (((accum << 8) | data) ^ s_crc_ccitt_table[accum >> 8])
+const uint8_t cdicdic_device::s_sector_scramble[2448] =
+{
+ // Sector sync area is not scrambled
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // Remaining data is scrambled
+ 0x01, 0x80, 0x00, 0x60, 0x00, 0x28, 0x00, 0x1e, 0x80, 0x08, 0x60, 0x06, 0xa8, 0x02, 0xfe, 0x81,
+ 0x80, 0x60, 0x60, 0x28, 0x28, 0x1e, 0x9e, 0x88, 0x68, 0x66, 0xae, 0xaa, 0xfc, 0x7f, 0x01, 0xe0,
+ 0x00, 0x48, 0x00, 0x36, 0x80, 0x16, 0xe0, 0x0e, 0xc8, 0x04, 0x56, 0x83, 0x7e, 0xe1, 0xe0, 0x48,
+ 0x48, 0x36, 0xb6, 0x96, 0xf6, 0xee, 0xc6, 0xcc, 0x52, 0xd5, 0xfd, 0x9f, 0x01, 0xa8, 0x00, 0x7e,
+ 0x80, 0x20, 0x60, 0x18, 0x28, 0x0a, 0x9e, 0x87, 0x28, 0x62, 0x9e, 0xa9, 0xa8, 0x7e, 0xfe, 0xa0,
+ 0x40, 0x78, 0x30, 0x22, 0x94, 0x19, 0xaf, 0x4a, 0xfc, 0x37, 0x01, 0xd6, 0x80, 0x5e, 0xe0, 0x38,
+ 0x48, 0x12, 0xb6, 0x8d, 0xb6, 0xe5, 0xb6, 0xcb, 0x36, 0xd7, 0x56, 0xde, 0xbe, 0xd8, 0x70, 0x5a,
+ 0xa4, 0x3b, 0x3b, 0x53, 0x53, 0x7d, 0xfd, 0xe1, 0x81, 0x88, 0x60, 0x66, 0xa8, 0x2a, 0xfe, 0x9f,
+ 0x00, 0x68, 0x00, 0x2e, 0x80, 0x1c, 0x60, 0x09, 0xe8, 0x06, 0xce, 0x82, 0xd4, 0x61, 0x9f, 0x68,
+ 0x68, 0x2e, 0xae, 0x9c, 0x7c, 0x69, 0xe1, 0xee, 0xc8, 0x4c, 0x56, 0xb5, 0xfe, 0xf7, 0x00, 0x46,
+ 0x80, 0x32, 0xe0, 0x15, 0x88, 0x0f, 0x26, 0x84, 0x1a, 0xe3, 0x4b, 0x09, 0xf7, 0x46, 0xc6, 0xb2,
+ 0xd2, 0xf5, 0x9d, 0x87, 0x29, 0xa2, 0x9e, 0xf9, 0xa8, 0x42, 0xfe, 0xb1, 0x80, 0x74, 0x60, 0x27,
+ 0x68, 0x1a, 0xae, 0x8b, 0x3c, 0x67, 0x51, 0xea, 0xbc, 0x4f, 0x31, 0xf4, 0x14, 0x47, 0x4f, 0x72,
+ 0xb4, 0x25, 0xb7, 0x5b, 0x36, 0xbb, 0x56, 0xf3, 0x7e, 0xc5, 0xe0, 0x53, 0x08, 0x3d, 0xc6, 0x91,
+ 0x92, 0xec, 0x6d, 0x8d, 0xed, 0xa5, 0x8d, 0xbb, 0x25, 0xb3, 0x5b, 0x35, 0xfb, 0x57, 0x03, 0x7e,
+ 0x81, 0xe0, 0x60, 0x48, 0x28, 0x36, 0x9e, 0x96, 0xe8, 0x6e, 0xce, 0xac, 0x54, 0x7d, 0xff, 0x61,
+ 0x80, 0x28, 0x60, 0x1e, 0xa8, 0x08, 0x7e, 0x86, 0xa0, 0x62, 0xf8, 0x29, 0x82, 0x9e, 0xe1, 0xa8,
+ 0x48, 0x7e, 0xb6, 0xa0, 0x76, 0xf8, 0x26, 0xc2, 0x9a, 0xd1, 0xab, 0x1c, 0x7f, 0x49, 0xe0, 0x36,
+ 0xc8, 0x16, 0xd6, 0x8e, 0xde, 0xe4, 0x58, 0x4b, 0x7a, 0xb7, 0x63, 0x36, 0xa9, 0xd6, 0xfe, 0xde,
+ 0xc0, 0x58, 0x50, 0x3a, 0xbc, 0x13, 0x31, 0xcd, 0xd4, 0x55, 0x9f, 0x7f, 0x28, 0x20, 0x1e, 0x98,
+ 0x08, 0x6a, 0x86, 0xaf, 0x22, 0xfc, 0x19, 0x81, 0xca, 0xe0, 0x57, 0x08, 0x3e, 0x86, 0x90, 0x62,
+ 0xec, 0x29, 0x8d, 0xde, 0xe5, 0x98, 0x4b, 0x2a, 0xb7, 0x5f, 0x36, 0xb8, 0x16, 0xf2, 0x8e, 0xc5,
+ 0xa4, 0x53, 0x3b, 0x7d, 0xd3, 0x61, 0x9d, 0xe8, 0x69, 0x8e, 0xae, 0xe4, 0x7c, 0x4b, 0x61, 0xf7,
+ 0x68, 0x46, 0xae, 0xb2, 0xfc, 0x75, 0x81, 0xe7, 0x20, 0x4a, 0x98, 0x37, 0x2a, 0x96, 0x9f, 0x2e,
+ 0xe8, 0x1c, 0x4e, 0x89, 0xf4, 0x66, 0xc7, 0x6a, 0xd2, 0xaf, 0x1d, 0xbc, 0x09, 0xb1, 0xc6, 0xf4,
+ 0x52, 0xc7, 0x7d, 0x92, 0xa1, 0xad, 0xb8, 0x7d, 0xb2, 0xa1, 0xb5, 0xb8, 0x77, 0x32, 0xa6, 0x95,
+ 0xba, 0xef, 0x33, 0x0c, 0x15, 0xc5, 0xcf, 0x13, 0x14, 0x0d, 0xcf, 0x45, 0x94, 0x33, 0x2f, 0x55,
+ 0xdc, 0x3f, 0x19, 0xd0, 0x0a, 0xdc, 0x07, 0x19, 0xc2, 0x8a, 0xd1, 0xa7, 0x1c, 0x7a, 0x89, 0xe3,
+ 0x26, 0xc9, 0xda, 0xd6, 0xdb, 0x1e, 0xdb, 0x48, 0x5b, 0x76, 0xbb, 0x66, 0xf3, 0x6a, 0xc5, 0xef,
+ 0x13, 0x0c, 0x0d, 0xc5, 0xc5, 0x93, 0x13, 0x2d, 0xcd, 0xdd, 0x95, 0x99, 0xaf, 0x2a, 0xfc, 0x1f,
+ 0x01, 0xc8, 0x00, 0x56, 0x80, 0x3e, 0xe0, 0x10, 0x48, 0x0c, 0x36, 0x85, 0xd6, 0xe3, 0x1e, 0xc9,
+ 0xc8, 0x56, 0xd6, 0xbe, 0xde, 0xf0, 0x58, 0x44, 0x3a, 0xb3, 0x53, 0x35, 0xfd, 0xd7, 0x01, 0x9e,
+ 0x80, 0x68, 0x60, 0x2e, 0xa8, 0x1c, 0x7e, 0x89, 0xe0, 0x66, 0xc8, 0x2a, 0xd6, 0x9f, 0x1e, 0xe8,
+ 0x08, 0x4e, 0x86, 0xb4, 0x62, 0xf7, 0x69, 0x86, 0xae, 0xe2, 0xfc, 0x49, 0x81, 0xf6, 0xe0, 0x46,
+ 0xc8, 0x32, 0xd6, 0x95, 0x9e, 0xef, 0x28, 0x4c, 0x1e, 0xb5, 0xc8, 0x77, 0x16, 0xa6, 0x8e, 0xfa,
+ 0xe4, 0x43, 0x0b, 0x71, 0xc7, 0x64, 0x52, 0xab, 0x7d, 0xbf, 0x61, 0xb0, 0x28, 0x74, 0x1e, 0xa7,
+ 0x48, 0x7a, 0xb6, 0xa3, 0x36, 0xf9, 0xd6, 0xc2, 0xde, 0xd1, 0x98, 0x5c, 0x6a, 0xb9, 0xef, 0x32,
+ 0xcc, 0x15, 0x95, 0xcf, 0x2f, 0x14, 0x1c, 0x0f, 0x49, 0xc4, 0x36, 0xd3, 0x56, 0xdd, 0xfe, 0xd9,
+ 0x80, 0x5a, 0xe0, 0x3b, 0x08, 0x13, 0x46, 0x8d, 0xf2, 0xe5, 0x85, 0x8b, 0x23, 0x27, 0x59, 0xda,
+ 0xba, 0xdb, 0x33, 0x1b, 0x55, 0xcb, 0x7f, 0x17, 0x60, 0x0e, 0xa8, 0x04, 0x7e, 0x83, 0x60, 0x61,
+ 0xe8, 0x28, 0x4e, 0x9e, 0xb4, 0x68, 0x77, 0x6e, 0xa6, 0xac, 0x7a, 0xfd, 0xe3, 0x01, 0x89, 0xc0,
+ 0x66, 0xd0, 0x2a, 0xdc, 0x1f, 0x19, 0xc8, 0x0a, 0xd6, 0x87, 0x1e, 0xe2, 0x88, 0x49, 0xa6, 0xb6,
+ 0xfa, 0xf6, 0xc3, 0x06, 0xd1, 0xc2, 0xdc, 0x51, 0x99, 0xfc, 0x6a, 0xc1, 0xef, 0x10, 0x4c, 0x0c,
+ 0x35, 0xc5, 0xd7, 0x13, 0x1e, 0x8d, 0xc8, 0x65, 0x96, 0xab, 0x2e, 0xff, 0x5c, 0x40, 0x39, 0xf0,
+ 0x12, 0xc4, 0x0d, 0x93, 0x45, 0xad, 0xf3, 0x3d, 0x85, 0xd1, 0xa3, 0x1c, 0x79, 0xc9, 0xe2, 0xd6,
+ 0xc9, 0x9e, 0xd6, 0xe8, 0x5e, 0xce, 0xb8, 0x54, 0x72, 0xbf, 0x65, 0xb0, 0x2b, 0x34, 0x1f, 0x57,
+ 0x48, 0x3e, 0xb6, 0x90, 0x76, 0xec, 0x26, 0xcd, 0xda, 0xd5, 0x9b, 0x1f, 0x2b, 0x48, 0x1f, 0x76,
+ 0x88, 0x26, 0xe6, 0x9a, 0xca, 0xeb, 0x17, 0x0f, 0x4e, 0x84, 0x34, 0x63, 0x57, 0x69, 0xfe, 0xae,
+ 0xc0, 0x7c, 0x50, 0x21, 0xfc, 0x18, 0x41, 0xca, 0xb0, 0x57, 0x34, 0x3e, 0x97, 0x50, 0x6e, 0xbc,
+ 0x2c, 0x71, 0xdd, 0xe4, 0x59, 0x8b, 0x7a, 0xe7, 0x63, 0x0a, 0xa9, 0xc7, 0x3e, 0xd2, 0x90, 0x5d,
+ 0xac, 0x39, 0xbd, 0xd2, 0xf1, 0x9d, 0x84, 0x69, 0xa3, 0x6e, 0xf9, 0xec, 0x42, 0xcd, 0xf1, 0x95,
+ 0x84, 0x6f, 0x23, 0x6c, 0x19, 0xed, 0xca, 0xcd, 0x97, 0x15, 0xae, 0x8f, 0x3c, 0x64, 0x11, 0xeb,
+ 0x4c, 0x4f, 0x75, 0xf4, 0x27, 0x07, 0x5a, 0x82, 0xbb, 0x21, 0xb3, 0x58, 0x75, 0xfa, 0xa7, 0x03,
+ 0x3a, 0x81, 0xd3, 0x20, 0x5d, 0xd8, 0x39, 0x9a, 0x92, 0xeb, 0x2d, 0x8f, 0x5d, 0xa4, 0x39, 0xbb,
+ 0x52, 0xf3, 0x7d, 0x85, 0xe1, 0xa3, 0x08, 0x79, 0xc6, 0xa2, 0xd2, 0xf9, 0x9d, 0x82, 0xe9, 0xa1,
+ 0x8e, 0xf8, 0x64, 0x42, 0xab, 0x71, 0xbf, 0x64, 0x70, 0x2b, 0x64, 0x1f, 0x6b, 0x48, 0x2f, 0x76,
+ 0x9c, 0x26, 0xe9, 0xda, 0xce, 0xdb, 0x14, 0x5b, 0x4f, 0x7b, 0x74, 0x23, 0x67, 0x59, 0xea, 0xba,
+ 0xcf, 0x33, 0x14, 0x15, 0xcf, 0x4f, 0x14, 0x34, 0x0f, 0x57, 0x44, 0x3e, 0xb3, 0x50, 0x75, 0xfc,
+ 0x27, 0x01, 0xda, 0x80, 0x5b, 0x20, 0x3b, 0x58, 0x13, 0x7a, 0x8d, 0xe3, 0x25, 0x89, 0xdb, 0x26,
+ 0xdb, 0x5a, 0xdb, 0x7b, 0x1b, 0x63, 0x4b, 0x69, 0xf7, 0x6e, 0xc6, 0xac, 0x52, 0xfd, 0xfd, 0x81,
+ 0x81, 0xa0, 0x60, 0x78, 0x28, 0x22, 0x9e, 0x99, 0xa8, 0x6a, 0xfe, 0xaf, 0x00, 0x7c, 0x00, 0x21,
+ 0xc0, 0x18, 0x50, 0x0a, 0xbc, 0x07, 0x31, 0xc2, 0x94, 0x51, 0xaf, 0x7c, 0x7c, 0x21, 0xe1, 0xd8,
+ 0x48, 0x5a, 0xb6, 0xbb, 0x36, 0xf3, 0x56, 0xc5, 0xfe, 0xd3, 0x00, 0x5d, 0xc0, 0x39, 0x90, 0x12,
+ 0xec, 0x0d, 0x8d, 0xc5, 0xa5, 0x93, 0x3b, 0x2d, 0xd3, 0x5d, 0x9d, 0xf9, 0xa9, 0x82, 0xfe, 0xe1,
+ 0x80, 0x48, 0x60, 0x36, 0xa8, 0x16, 0xfe, 0x8e, 0xc0, 0x64, 0x50, 0x2b, 0x7c, 0x1f, 0x61, 0xc8,
+ 0x28, 0x56, 0x9e, 0xbe, 0xe8, 0x70, 0x4e, 0xa4, 0x34, 0x7b, 0x57, 0x63, 0x7e, 0xa9, 0xe0, 0x7e,
+ 0xc8, 0x20, 0x56, 0x98, 0x3e, 0xea, 0x90, 0x4f, 0x2c, 0x34, 0x1d, 0xd7, 0x49, 0x9e, 0xb6, 0xe8,
+ 0x76, 0xce, 0xa6, 0xd4, 0x7a, 0xdf, 0x63, 0x18, 0x29, 0xca, 0x9e, 0xd7, 0x28, 0x5e, 0x9e, 0xb8,
+ 0x68, 0x72, 0xae, 0xa5, 0xbc, 0x7b, 0x31, 0xe3, 0x54, 0x49, 0xff, 0x76, 0xc0, 0x26, 0xd0, 0x1a,
+ 0xdc, 0x0b, 0x19, 0xc7, 0x4a, 0xd2, 0xb7, 0x1d, 0xb6, 0x89, 0xb6, 0xe6, 0xf6, 0xca, 0xc6, 0xd7,
+ 0x12, 0xde, 0x8d, 0x98, 0x65, 0xaa, 0xab, 0x3f, 0x3f, 0x50, 0x10, 0x3c, 0x0c, 0x11, 0xc5, 0xcc,
+ 0x53, 0x15, 0xfd, 0xcf, 0x01, 0x94, 0x00, 0x6f, 0x40, 0x2c, 0x30, 0x1d, 0xd4, 0x09, 0x9f, 0x46,
+ 0xe8, 0x32, 0xce, 0x95, 0x94, 0x6f, 0x2f, 0x6c, 0x1c, 0x2d, 0xc9, 0xdd, 0x96, 0xd9, 0xae, 0xda,
+ 0xfc, 0x5b, 0x01, 0xfb, 0x40, 0x43, 0x70, 0x31, 0xe4, 0x14, 0x4b, 0x4f, 0x77, 0x74, 0x26, 0xa7,
+ 0x5a, 0xfa, 0xbb, 0x03, 0x33, 0x41, 0xd5, 0xf0, 0x5f, 0x04, 0x38, 0x03, 0x52, 0x81, 0xfd, 0xa0,
+ 0x41, 0xb8, 0x30, 0x72, 0x94, 0x25, 0xaf, 0x5b, 0x3c, 0x3b, 0x51, 0xd3, 0x7c, 0x5d, 0xe1, 0xf9,
+ 0x88, 0x42, 0xe6, 0xb1, 0x8a, 0xf4, 0x67, 0x07, 0x6a, 0x82, 0xaf, 0x21, 0xbc, 0x18, 0x71, 0xca,
+ 0xa4, 0x57, 0x3b, 0x7e, 0x93, 0x60, 0x6d, 0xe8, 0x2d, 0x8e, 0x9d, 0xa4, 0x69, 0xbb, 0x6e, 0xf3,
+ 0x6c, 0x45, 0xed, 0xf3, 0x0d, 0x85, 0xc5, 0xa3, 0x13, 0x39, 0xcd, 0xd2, 0xd5, 0x9d, 0x9f, 0x29,
+ 0xa8, 0x1e, 0xfe, 0x88, 0x40, 0x66, 0xb0, 0x2a, 0xf4, 0x1f, 0x07, 0x48, 0x02, 0xb6, 0x81, 0xb6,
+ 0xe0, 0x76, 0xc8, 0x26, 0xd6, 0x9a, 0xde, 0xeb, 0x18, 0x4f, 0x4a, 0xb4, 0x37, 0x37, 0x56, 0x96,
+ 0xbe, 0xee, 0xf0, 0x4c, 0x44, 0x35, 0xf3, 0x57, 0x05, 0xfe, 0x83, 0x00, 0x61, 0xc0, 0x28, 0x50,
+ 0x1e, 0xbc, 0x08, 0x71, 0xc6, 0xa4, 0x52, 0xfb, 0x7d, 0x83, 0x61, 0xa1, 0xe8, 0x78, 0x4e, 0xa2,
+ 0xb4, 0x79, 0xb7, 0x62, 0xf6, 0xa9, 0x86, 0xfe, 0xe2, 0xc0, 0x49, 0x90, 0x36, 0xec, 0x16, 0xcd,
+ 0xce, 0xd5, 0x94, 0x5f, 0x2f, 0x78, 0x1c, 0x22, 0x89, 0xd9, 0xa6, 0xda, 0xfa, 0xdb, 0x03, 0x1b,
+ 0x41, 0xcb, 0x70, 0x57, 0x64, 0x3e, 0xab, 0x50, 0x7f, 0x7c, 0x20, 0x21, 0xd8, 0x18, 0x5a, 0x8a,
+ 0xbb, 0x27, 0x33, 0x5a, 0x95, 0xfb, 0x2f, 0x03, 0x5c, 0x01, 0xf9, 0xc0, 0x42, 0xd0, 0x31, 0x9c,
+ 0x14, 0x69, 0xcf, 0x6e, 0xd4, 0x2c, 0x5f, 0x5d, 0xf8, 0x39, 0x82, 0x92, 0xe1, 0xad, 0x88, 0x7d,
+ 0xa6, 0xa1, 0xba, 0xf8, 0x73, 0x02, 0xa5, 0xc1, 0xbb, 0x10, 0x73, 0x4c, 0x25, 0xf5, 0xdb, 0x07,
+ 0x1b, 0x42, 0x8b, 0x71, 0xa7, 0x64, 0x7a, 0xab, 0x63, 0x3f, 0x69, 0xd0, 0x2e, 0xdc, 0x1c, 0x59,
+ 0xc9, 0xfa, 0xd6, 0xc3, 0x1e, 0xd1, 0xc8, 0x5c, 0x56, 0xb9, 0xfe, 0xf2, 0xc0, 0x45, 0x90, 0x33,
+ 0x2c, 0x15, 0xdd, 0xcf, 0x19, 0x94, 0x0a, 0xef, 0x47, 0x0c, 0x32, 0x85, 0xd5, 0xa3, 0x1f, 0x39,
+ 0xc8, 0x12, 0xd6, 0x8d, 0x9e, 0xe5, 0xa8, 0x4b, 0x3e, 0xb7, 0x50, 0x76, 0xbc, 0x26, 0xf1, 0xda,
+ 0xc4, 0x5b, 0x13, 0x7b, 0x4d, 0xe3, 0x75, 0x89, 0xe7, 0x26, 0xca, 0x9a, 0xd7, 0x2b, 0x1e, 0x9f,
+ 0x48, 0x68, 0x36, 0xae, 0x96, 0xfc, 0x6e, 0xc1, 0xec, 0x50, 0x4d, 0xfc, 0x35, 0x81, 0xd7, 0x20,
+ 0x5e, 0x98, 0x38, 0x6a, 0x92, 0xaf, 0x2d, 0xbc, 0x1d, 0xb1, 0xc9, 0xb4, 0x56, 0xf7, 0x7e, 0xc6,
+ 0xa0, 0x52, 0xf8, 0x3d, 0x82, 0x91, 0xa1, 0xac, 0x78, 0x7d, 0xe2, 0xa1, 0x89, 0xb8, 0x66, 0xf2,
+ 0xaa, 0xc5, 0xbf, 0x13, 0x30, 0x0d, 0xd4, 0x05, 0x9f, 0x43, 0x28, 0x31, 0xde, 0x94, 0x58, 0x6f,
+ 0x7a, 0xac, 0x23, 0x3d, 0xd9, 0xd1, 0x9a, 0xdc, 0x6b, 0x19, 0xef, 0x4a, 0xcc, 0x37, 0x15, 0xd6,
+ 0x8f, 0x1e, 0xe4, 0x08, 0x4b, 0x46, 0xb7, 0x72, 0xf6, 0xa5, 0x86, 0xfb, 0x22, 0xc3, 0x59, 0x91,
+ 0xfa, 0xec, 0x43, 0x0d, 0xf1, 0xc5, 0x84, 0x53, 0x23, 0x7d, 0xd9, 0xe1, 0x9a, 0xc8, 0x6b, 0x16,
+ 0xaf, 0x4e, 0xfc, 0x34, 0x41, 0xd7, 0x70, 0x5e, 0xa4, 0x38, 0x7b, 0x52, 0xa3, 0x7d, 0xb9, 0xe1,
+ 0xb2, 0xc8, 0x75, 0x96, 0xa7, 0x2e, 0xfa, 0x9c, 0x43, 0x29, 0xf1, 0xde, 0xc4, 0x58, 0x53, 0x7a,
+ 0xbd, 0xe3, 0x31, 0x89, 0xd4, 0x66, 0xdf, 0x6a, 0xd8, 0x2f, 0x1a, 0x9c, 0x0b, 0x29, 0xc7, 0x5e,
+ 0xd2, 0xb8, 0x5d, 0xb2, 0xb9, 0xb5, 0xb2, 0xf7, 0x35, 0x86, 0x97, 0x22, 0xee, 0x99, 0x8c, 0x6a,
+ 0xe5, 0xef, 0x0b, 0x0c, 0x07, 0x45, 0xc2, 0xb3, 0x11, 0xb5, 0xcc, 0x77, 0x15, 0xe6, 0x8f, 0x0a,
+ 0xe4, 0x07, 0x0b, 0x42, 0x87, 0x71, 0xa2, 0xa4, 0x79, 0xbb, 0x62, 0xf3, 0x69, 0x85, 0xee, 0xe3,
+ 0x0c, 0x49, 0xc5, 0xf6, 0xd3, 0x06, 0xdd, 0xc2, 0xd9, 0x91, 0x9a, 0xec, 0x6b, 0x0d, 0xef, 0x45,
+ 0x8c, 0x33, 0x25, 0xd5, 0xdb, 0x1f, 0x1b, 0x48, 0x0b, 0x76, 0x87, 0x66, 0xe2, 0xaa, 0xc9, 0xbf,
+ 0x16, 0xf0, 0x0e, 0xc4, 0x04, 0x53, 0x43, 0x7d, 0xf1, 0xe1, 0x84, 0x48, 0x63, 0x76, 0xa9, 0xe6,
+ 0xfe, 0xca, 0xc0, 0x57, 0x10, 0x3e, 0x8c, 0x10, 0x65, 0xcc, 0x2b, 0x15, 0xdf, 0x4f, 0x18, 0x34,
+ 0x0a, 0x97, 0x47, 0x2e, 0xb2, 0x9c, 0x75, 0xa9, 0xe7, 0x3e, 0xca, 0x90, 0x57, 0x2c, 0x3e, 0x9d,
+ 0xd0, 0x69, 0x9c, 0x2e, 0xe9, 0xdc, 0x4e, 0xd9, 0xf4, 0x5a, 0xc7, 0x7b, 0x12, 0xa3, 0x4d, 0xb9,
+ 0xf5, 0xb2, 0xc7, 0x35, 0x92, 0x97, 0x2d, 0xae, 0x9d, 0xbc, 0x69, 0xb1, 0xee, 0xf4, 0x4c, 0x47,
+ 0x75, 0xf2, 0xa7, 0x05, 0xba, 0x83, 0x33, 0x21, 0xd5, 0xd8, 0x5f, 0x1a, 0xb8, 0x0b, 0x32, 0x87,
+ 0x55, 0xa2, 0xbf, 0x39, 0xb0, 0x12, 0xf4, 0x0d, 0x87, 0x45, 0xa2, 0xb3, 0x39, 0xb5, 0xd2, 0xf7,
+ 0x1d, 0x86, 0x89, 0xa2, 0xe6, 0xf9, 0x8a, 0xc2, 0xe7, 0x11, 0x8a, 0x8c, 0x67, 0x25, 0xea, 0x9b,
+ 0x0f, 0x2b, 0x44, 0x1f, 0x73, 0x48, 0x25, 0xf6, 0x9b, 0x06, 0xeb, 0x42, 0xcf, 0x71, 0x94, 0x24,
+ 0x6f, 0x5b, 0x6c, 0x3b, 0x6d, 0xd3, 0x6d, 0x9d, 0xed, 0xa9, 0x8d, 0xbe, 0xe5, 0xb0, 0x4b, 0x34,
+ 0x37, 0x57, 0x56, 0xbe, 0xbe, 0xf0, 0x70, 0x44, 0x24, 0x33, 0x5b, 0x55, 0xfb, 0x7f, 0x03, 0x60,
+ 0x01, 0xe8, 0x00, 0x4e, 0x80, 0x34, 0x60, 0x17, 0x68, 0x0e, 0xae, 0x84, 0x7c, 0x63, 0x61, 0xe9,
+ 0xe8, 0x4e, 0xce, 0xb4, 0x54, 0x77, 0x7f, 0x66, 0xa0, 0x2a, 0xf8, 0x1f, 0x02, 0x88, 0x01, 0xa6,
+ 0x80, 0x7a, 0xe0, 0x23, 0x08, 0x19, 0xc6, 0x8a, 0xd2, 0xe7, 0x1d, 0x8a, 0x89, 0xa7, 0x26, 0xfa,
+ 0x9a, 0xc3, 0x2b, 0x11, 0xdf, 0x4c, 0x58, 0x35, 0xfa, 0x97, 0x03, 0x2e, 0x81, 0xdc, 0x60, 0x59,
+ 0xe8, 0x3a, 0xce, 0x93, 0x14, 0x6d, 0xcf, 0x6d, 0x94, 0x2d, 0xaf, 0x5d, 0xbc, 0x39, 0xb1, 0xd2,
+ 0xf4, 0x5d, 0x87, 0x79, 0xa2, 0xa2, 0xf9, 0xb9, 0x82, 0xf2, 0xe1, 0x85, 0x88, 0x63, 0x26, 0xa9,
+ 0xda, 0xfe, 0xdb, 0x00, 0x5b, 0x40, 0x3b, 0x70, 0x13, 0x64, 0x0d, 0xeb, 0x45, 0x8f, 0x73, 0x24,
+ 0x25, 0xdb, 0x5b, 0x1b, 0x7b, 0x4b, 0x63, 0x77, 0x69, 0xe6, 0xae, 0xca, 0xfc, 0x57, 0x01, 0xfe,
+ 0x80, 0x40, 0x60, 0x30, 0x28, 0x14, 0x1e, 0x8f, 0x48, 0x64, 0x36, 0xab, 0x56, 0xff, 0x7e, 0xc0,
+ 0x20, 0x50, 0x18, 0x3c, 0x0a, 0x91, 0xc7, 0x2c, 0x52, 0x9d, 0xfd, 0xa9, 0x81, 0xbe, 0xe0, 0x70,
+ 0x48, 0x24, 0x36, 0x9b, 0x56, 0xeb, 0x7e, 0xcf, 0x60, 0x54, 0x28, 0x3f, 0x5e, 0x90, 0x38, 0x6c,
+ 0x12, 0xad, 0xcd, 0xbd, 0x95, 0xb1, 0xaf, 0x34, 0x7c, 0x17, 0x61, 0xce, 0xa8, 0x54, 0x7e, 0xbf,
+ 0x60, 0x70, 0x28, 0x24, 0x1e, 0x9b, 0x48, 0x6b, 0x76, 0xaf, 0x66, 0xfc, 0x2a, 0xc1, 0xdf, 0x10,
+ 0x58, 0x0c, 0x3a, 0x85, 0xd3, 0x23, 0x1d, 0xd9, 0xc9, 0x9a, 0xd6, 0xeb, 0x1e, 0xcf, 0x48, 0x54,
+ 0x36, 0xbf, 0x56, 0xf0, 0x3e, 0xc4, 0x10, 0x53, 0x4c, 0x3d, 0xf5, 0xd1, 0x87, 0x1c, 0x62, 0x89,
+ 0xe9, 0xa6, 0xce, 0xfa, 0xd4, 0x43, 0x1f, 0x71, 0xc8, 0x24, 0x56, 0x9b, 0x7e, 0xeb, 0x60, 0x4f,
+ 0x68, 0x34, 0x2e, 0x97, 0x5c, 0x6e, 0xb9, 0xec, 0x72, 0xcd, 0xe5, 0x95, 0x8b, 0x2f, 0x27, 0x5c,
+ 0x1a, 0xb9, 0xcb, 0x32, 0xd7, 0x55, 0x9e, 0xbf, 0x28, 0x70, 0x1e, 0xa4, 0x08, 0x7b, 0x46, 0xa3,
+ 0x72, 0xf9, 0xe5, 0x82, 0xcb, 0x21, 0x97, 0x58, 0x6e, 0xba, 0xac, 0x73, 0x3d, 0xe5, 0xd1, 0x8b,
+ 0x1c, 0x67, 0x49, 0xea, 0xb6, 0xcf, 0x36, 0xd4, 0x16, 0xdf, 0x4e, 0xd8, 0x34, 0x5a, 0x97, 0x7b,
+ 0x2e, 0xa3, 0x5c, 0x79, 0xf9, 0xe2, 0xc2, 0xc9, 0x91, 0x96, 0xec, 0x6e, 0xcd, 0xec, 0x55, 0x8d,
+ 0xff, 0x25, 0x80, 0x1b, 0x20, 0x0b, 0x58, 0x07, 0x7a, 0x82, 0xa3, 0x21, 0xb9, 0xd8, 0x72, 0xda,
+ 0xa5, 0x9b, 0x3b, 0x2b, 0x53, 0x5f, 0x7d, 0xf8, 0x21, 0x82, 0x98, 0x61, 0xaa, 0xa8, 0x7f, 0x3e,
+ 0xa0, 0x10, 0x78, 0x0c, 0x22, 0x85, 0xd9, 0xa3, 0x1a, 0xf9, 0xcb, 0x02, 0xd7, 0x41, 0x9e, 0xb0,
+ 0x68, 0x74, 0x2e, 0xa7, 0x5c, 0x7a, 0xb9, 0xe3, 0x32, 0xc9, 0xd5, 0x96, 0xdf, 0x2e, 0xd8, 0x1c,
+ 0x5a, 0x89, 0xfb, 0x26, 0xc3, 0x5a, 0xd1, 0xfb, 0x1c, 0x43, 0x49, 0xf1, 0xf6, 0xc4, 0x46, 0xd3,
+ 0x72, 0xdd, 0xe5, 0x99
+};
+
+
//**************************************************************************
// MEMBER FUNCTIONS
//**************************************************************************
@@ -406,6 +562,24 @@ void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data)
}
}
+void cdicdic_device::play_cdda_sector(const uint8_t *data)
+{
+ m_dmadac[0]->set_frequency(44100);
+ m_dmadac[1]->set_frequency(44100);
+ m_dmadac[0]->set_volume(0x100);
+ m_dmadac[1]->set_volume(0x100);
+
+ int16_t samples[2][2352/4];
+ for (uint16_t i = 0; i < 2352/4; i++)
+ {
+ samples[0][i] = (int16_t)((data[(i * 4) + 1] << 8) | data[(i * 4) + 0]);
+ samples[1][i] = (int16_t)((data[(i * 4) + 3] << 8) | data[(i * 4) + 2]);
+ }
+
+ m_dmadac[0]->transfer(0, 1, 1, SECTOR_SIZE/4, samples[0]);
+ m_dmadac[1]->transfer(0, 1, 1, SECTOR_SIZE/4, samples[1]);
+}
+
void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data)
{
if ((coding & CODING_CHAN_MASK) > CODING_STEREO || (coding & CODING_BPS_MASK) == CODING_BPS_MPEG || (coding & CODING_RATE_MASK) == CODING_RATE_RESV)
@@ -533,6 +707,7 @@ void cdicdic_device::process_audio_map()
else
{
m_decode_addr = 0xffff;
+ m_audio_sector_counter = m_audio_format_sectors;
}
if (was_decoding)
@@ -550,6 +725,63 @@ void cdicdic_device::update_interrupt_state()
m_intreq_callback(interrupt_active ? ASSERT_LINE : CLEAR_LINE);
}
+void cdicdic_device::descramble_sector(uint8_t *buffer)
+{
+ for (uint32_t i = 12; i < SECTOR_SIZE; i++)
+ {
+ buffer[i] ^= s_sector_scramble[i];
+ }
+}
+
+bool cdicdic_device::is_valid_sector(const uint8_t *buffer)
+{
+ const uint32_t real_lba = m_curr_lba + 150;
+ const uint8_t mins = real_lba / (60 * 75);
+ const uint8_t secs = (real_lba / 75) % 60;
+ const uint8_t frac = real_lba % 75;
+ const uint8_t mins_bcd = ((mins / 10) << 4) | (mins % 10);
+ const uint8_t secs_bcd = ((secs / 10) << 4) | (secs % 10);
+ const uint8_t frac_bcd = ((frac / 10) << 4) | (frac % 10);
+
+ // Verify MSF
+ if (mins_bcd != buffer[SECTOR_MINUTES] || secs_bcd != buffer[SECTOR_SECONDS] || frac_bcd != buffer[SECTOR_FRACS])
+ {
+ LOGMASKED(LOG_SECTORS, "Not valid sector, MSF (%02x:%02x:%02x vs. %02x:%02x:%02x\n", mins_bcd, secs_bcd, frac_bcd, buffer[SECTOR_MINUTES], buffer[SECTOR_SECONDS], buffer[SECTOR_FRACS]);
+ return false;
+ }
+
+ // Verify mode
+ if (buffer[SECTOR_MODE] != 1 && buffer[SECTOR_MODE] != 2)
+ {
+ LOGMASKED(LOG_SECTORS, "Not valid sector, mode %02x\n", buffer[SECTOR_MODE]);
+ return false;
+ }
+
+ // Verify duplicate info
+ if (buffer[SECTOR_FILE1] != buffer[SECTOR_FILE2])
+ {
+ LOGMASKED(LOG_SECTORS, "Not valid sector, file %02x vs. %02x\n", buffer[SECTOR_FILE1], buffer[SECTOR_FILE2]);
+ return false;
+ }
+ if (buffer[SECTOR_CHAN1] != buffer[SECTOR_CHAN2])
+ {
+ LOGMASKED(LOG_SECTORS, "Not valid sector, channel %02x vs. %02x\n", buffer[SECTOR_CHAN1], buffer[SECTOR_CHAN2]);
+ return false;
+ }
+ if (buffer[SECTOR_SUBMODE1] != buffer[SECTOR_SUBMODE2])
+ {
+ LOGMASKED(LOG_SECTORS, "Not valid sector, channel %02x vs. %02x\n", buffer[SECTOR_SUBMODE1], buffer[SECTOR_SUBMODE2]);
+ return false;
+ }
+ if (buffer[SECTOR_CODING1] != buffer[SECTOR_CODING2])
+ {
+ LOGMASKED(LOG_SECTORS, "Not valid sector, coding %02x vs. %02x\n", buffer[SECTOR_CODING1], buffer[SECTOR_CODING2]);
+ return false;
+ }
+
+ return true;
+}
+
bool cdicdic_device::is_mode2_sector_selected(const uint8_t *buffer)
{
if ((buffer[SECTOR_FILE2] << 8) != m_file)
@@ -701,6 +933,38 @@ void cdicdic_device::process_disc_sector()
uint8_t buffer[2560] = { 0 };
cdrom_read_data(m_cd, m_curr_lba, buffer, CD_TRACK_RAW_DONTCARE);
+ // Detect (badly) if we're dealing with a byteswapped loose-bin image
+ if (buffer[0] == 0xff && buffer[1] == 0x00)
+ {
+ LOGMASKED(LOG_SECTORS, "Byteswapping\n");
+ m_cd_byteswap = true;
+ }
+
+ if (m_cd_byteswap)
+ {
+ for (uint16_t i = 0; i < 2560; i += 2)
+ {
+ std::swap(buffer[i], buffer[i + 1]);
+ }
+ }
+
+ if (!is_valid_sector(buffer))
+ {
+ uint8_t descramble_buffer[2560];
+ memcpy(descramble_buffer, buffer, sizeof(descramble_buffer));
+ LOGMASKED(LOG_SECTORS, "Sector seems to be encoded, attempting to apply descrambling\n");
+ descramble_sector(descramble_buffer);
+
+ if (!is_valid_sector(descramble_buffer))
+ {
+ LOGMASKED(LOG_SECTORS, "Sector remains invalid after descrambling, giving up and proceeding as normal\n");
+ }
+ else
+ {
+ memcpy(buffer, descramble_buffer, sizeof(descramble_buffer));
+ }
+ }
+
LOGMASKED(LOG_SECTORS, "Sector header data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
buffer[ 0], buffer[ 1], buffer[ 2], buffer[ 3], buffer[ 4], buffer[ 5], buffer[ 6], buffer[ 7], buffer[ 8], buffer[ 9],
buffer[10], buffer[11], buffer[12], buffer[13], buffer[14], buffer[15], buffer[16], buffer[17], buffer[18], buffer[19],
@@ -724,17 +988,116 @@ void cdicdic_device::process_disc_sector()
play_audio_sector(buffer[SECTOR_CODING2], buffer + SECTOR_DATA);
}
}
+ else if (m_disc_mode == DISC_CDDA)
+ {
+ m_audio_sector_counter = 2;
+ m_decoding_audio_map = false;
+
+ play_cdda_sector(buffer);
+
+ if (frac != 0)
+ {
+ return;
+ }
+ }
// Calculate subcode data
uint8_t subcode_buffer[96];
memset(subcode_buffer, 0, sizeof(subcode_buffer));
- if (m_disc_command == DISC_TOC)
+ if (m_disc_mode == DISC_TOC)
{
- uint32_t entry_index = 0;
- for (; buffer[entry_index * 5] != 0; entry_index++);
+ uint8_t *toc_buffer = buffer;
+ const cdrom_toc *toc = cdrom_get_toc(m_cd);
+ uint32_t entry_count = 0;
+
+ // Determine total frame count for data, and total audio track count
+ uint32_t frames = toc->tracks[0].pregap;
+ int audio_tracks = 0;
+ int other_tracks = 0;
+ uint32_t audio_starts[CD_MAX_TRACKS];
+ for (uint32_t i = 0; i < toc->numtrks; i++)
+ {
+ if (toc->tracks[i].trktype != CD_TRACK_AUDIO)
+ {
+ frames += toc->tracks[i].frames + toc->tracks[i].extraframes;
+ }
+ else
+ {
+ audio_starts[audio_tracks++] = toc->tracks[i].logframeofs;
+ }
+ }
+
+ // Determine last-frame MSF
+ const uint8_t total_mins = frames / (60 * 75);
+ const uint8_t total_secs = (frames / 75) % 60;
+ const uint8_t total_frac = frames % 75;
+
+ // Specify any audio tracks first
+ for (int i = 0; i < audio_tracks; i++)
+ {
+ const uint8_t audio_mins = audio_starts[i] / (60 * 75);
+ const uint8_t audio_secs = (audio_starts[i] / 75) % 60;
+ const uint8_t audio_frac = audio_starts[i] % 75;
+ const uint8_t audio_mins_bcd = ((audio_mins / 10) << 4) | (audio_mins % 10);
+ const uint8_t audio_secs_bcd = ((audio_secs / 10) << 4) | (audio_secs % 10);
+ const uint8_t audio_frac_bcd = ((audio_frac / 10) << 4) | (audio_frac % 10);
+
+ const uint8_t track_bcd = (((i + 1) / 10) << 4) | ((i + 1) % 10);
- uint8_t *toc_data = &buffer[(m_curr_lba % entry_index) * 5];
+ for (int j = 0; j < 3; j++)
+ {
+ *toc_buffer++ = 0x01; // Track type (CD-DA)
+ *toc_buffer++ = track_bcd; // Track number
+ *toc_buffer++ = audio_mins_bcd;
+ *toc_buffer++ = audio_secs_bcd;
+ *toc_buffer++ = audio_frac_bcd;
+ entry_count++;
+ }
+ }
+
+ // Packet A0 (lead-in)
+ for (int i = 0; i < 3; i++)
+ {
+ *toc_buffer++ = (other_tracks > 0) ? 0x41 : 0x01;
+ *toc_buffer++ = 0xa0;
+ *toc_buffer++ = 0x01;
+ *toc_buffer++ = (other_tracks > 0) ? 0x10 : 0x00;
+ *toc_buffer++ = 0x00;
+ entry_count++;
+ }
+
+ // Packet A1
+ for (int i = 0; i < 3; i++)
+ {
+ *toc_buffer++ = (audio_tracks > 0) ? 0x01 : 0x41;
+ *toc_buffer++ = 0xa1;
+ if (audio_tracks > 0)
+ {
+ uint8_t last_audio_track = (uint8_t)(audio_tracks - 1);
+ *toc_buffer++ = ((last_audio_track / 10) << 4) | (last_audio_track % 10);
+ }
+ else
+ {
+ *toc_buffer++ = 0x00;
+ }
+ *toc_buffer++ = 0x00;
+ *toc_buffer++ = 0x00;
+ entry_count++;
+ }
+
+ // Packet A2 (lead-out)
+ for (int i = 0; i < 3; i++)
+ {
+ *toc_buffer++ = (audio_tracks > 0) ? 0x01 : 0x41;
+ *toc_buffer++ = 0xa2;
+ *toc_buffer++ = ((total_mins / 10) << 4) | (total_mins % 10);
+ *toc_buffer++ = ((total_secs / 10) << 4) | (total_secs % 10);
+ *toc_buffer++ = ((total_frac / 10) << 4) | (total_frac % 10);
+ entry_count++;
+ }
+
+ uint8_t *toc_data = &buffer[(m_curr_lba % entry_count) * 5];
subcode_buffer[SUBCODE_Q_CONTROL] = toc_data[0];
subcode_buffer[SUBCODE_Q_TRACK] = 0x00;
@@ -751,7 +1114,7 @@ void cdicdic_device::process_disc_sector()
}
else
{
- subcode_buffer[SUBCODE_Q_CONTROL] = (m_disc_command == DISC_CDDA ? 0x01 : 0x41);
+ subcode_buffer[SUBCODE_Q_CONTROL] = (m_disc_mode == DISC_CDDA ? 0x01 : 0x41);
subcode_buffer[SUBCODE_Q_TRACK] = 0x01;
subcode_buffer[SUBCODE_Q_INDEX] = 0x01;
subcode_buffer[SUBCODE_Q_MODE1_MINS] = mins_bcd;
@@ -1096,7 +1459,6 @@ cdicdic_device::cdicdic_device(const machine_config &mconfig, const char *tag, d
, m_memory_space(*this, ":maincpu", AS_PROGRAM)
, m_dmadac(*this, ":dac%u", 1U)
, m_scc(*this, ":maincpu")
- , m_cdda(*this, ":cdda")
, m_cdrom_dev(*this, ":cdrom")
, m_clock2(clock)
{
@@ -1176,6 +1538,8 @@ void cdicdic_device::device_reset()
m_interrupt_vector = 0x0f;
m_data_buffer = 0;
+ m_cd_byteswap = false;
+
m_disc_command = 0;
m_disc_mode = 0;
m_disc_spinup_counter = 0;
@@ -1190,13 +1554,11 @@ void cdicdic_device::device_reset()
{
// Console case (has CDROM device)
m_cd = m_cdrom_dev->get_cdrom_file();
- m_cdda->set_cdrom(m_cd);
}
else
{
// Arcade case
m_cd = cdrom_open(machine().rom_load().get_disk_handle(":cdrom"));
- m_cdda->set_cdrom(m_cd);
}
m_audio_timer->adjust(attotime::from_hz(75), 0, attotime::from_hz(75));
diff --git a/src/mame/machine/cdicdic.h b/src/mame/machine/cdicdic.h
index 0feacafb5dc..9075b77cb0d 100644
--- a/src/mame/machine/cdicdic.h
+++ b/src/mame/machine/cdicdic.h
@@ -86,6 +86,9 @@ private:
SECTOR_HEADER = 12,
+ SECTOR_MINUTES = 12,
+ SECTOR_SECONDS = 13,
+ SECTOR_FRACS = 14,
SECTOR_MODE = 15,
SECTOR_FILE1 = 16,
@@ -153,7 +156,6 @@ private:
required_address_space m_memory_space;
required_device_array<dmadac_sound_device, 2> m_dmadac;
required_device<scc68070_device> m_scc;
- required_device<cdda_device> m_cdda;
optional_device<cdrom_image_device> m_cdrom_dev;
uint32_t m_clock2;
@@ -173,6 +175,7 @@ private:
uint16_t m_data_buffer; // CDIC Data Buffer Register (0x303ffe)
cdrom_file *m_cd;
+ bool m_cd_byteswap;
emu_timer *m_sector_timer;
uint8_t m_disc_command;
@@ -195,8 +198,11 @@ private:
void play_raw_group(const uint8_t *data);
void play_xa_group(const uint8_t coding, const uint8_t *data);
void play_audio_sector(const uint8_t coding, const uint8_t *data);
+ void play_cdda_sector(const uint8_t *data);
void process_audio_map();
+ void descramble_sector(uint8_t *buffer);
+ bool is_valid_sector(const uint8_t *buffer);
bool is_mode2_sector_selected(const uint8_t *buffer);
bool is_mode2_audio_selected(const uint8_t *buffer);
@@ -219,6 +225,7 @@ private:
static const int16_t s_xa_filter_coef[4][2];
static const int32_t s_samples_per_sector;
static const uint16_t s_crc_ccitt_table[256];
+ static const uint8_t s_sector_scramble[2448];
};
// device type definition
diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp
index c6e32759101..36d5f67530b 100644
--- a/src/mame/video/mcd212.cpp
+++ b/src/mame/video/mcd212.cpp
@@ -26,52 +26,66 @@ TODO:
#include "screen.h"
-#define ENABLE_VERBOSE_LOG 0
-
+#define LOG_UNKNOWNS (1U << 1)
+#define LOG_REGISTERS (1U << 2)
+#define LOG_ICA (1U << 3)
+#define LOG_DCA (1U << 4)
+#define LOG_VSR (1U << 5)
+#define LOG_STATUS (1U << 6)
+#define LOG_MAIN_REG_READS (1U << 7)
+#define LOG_MAIN_REG_WRITES (1U << 8)
+#define LOG_CLUT (1U << 9)
+#define LOG_ALL (LOG_UNKNOWNS | LOG_REGISTERS | LOG_ICA | LOG_DCA | LOG_VSR | LOG_STATUS | LOG_MAIN_REG_READS | LOG_MAIN_REG_WRITES | LOG_CLUT)
+
+#define VERBOSE (0)
+#include "logmacro.h"
// device type definition
DEFINE_DEVICE_TYPE(MCD212, mcd212_device, "mcd212", "MCD212 VDSC")
-#if ENABLE_VERBOSE_LOG
-static inline void ATTR_PRINTF(3,4) verboselog(device_t& device, int n_level, const char *s_fmt, ...)
+inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t region_idx)
{
- if( VERBOSE_LEVEL >= n_level )
- {
- va_list v;
- char buf[ 32768 ];
- va_start( v, s_fmt );
- vsprintf( buf, s_fmt, v );
- va_end( v );
- device.logerror("%s: %s", device.machine().describe_context(), buf );
- }
+ return (uint8_t)((m_region_control[region_idx] & RC_WF) >> RC_WF_SHIFT);
+}
+
+inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_region_op(const uint32_t region_idx)
+{
+ return (m_region_control[region_idx] & RC_OP) >> RC_OP_SHIFT;
}
-#else
-#define verboselog(x,y,z, ...)
-#endif
void mcd212_device::update_region_arrays()
{
- int latched_rf0 = 0;
- int latched_rf1 = 0;
- int latched_wfa = m_channel[0].weight_factor_a[0];
- int latched_wfb = m_channel[1].weight_factor_b[0];
- int reg = 0;
+ bool latched_rf[2] { false, false };
+ uint8_t latched_wfa = m_weight_factor[0][0];
+ uint8_t latched_wfb = m_weight_factor[1][0];
- for(int x = 0; x < 768; x++)
+ if (BIT(m_image_coding_method, ICM_NR_BIT))
{
- if(m_channel[0].image_coding_method & MCD212_ICM_NR)
+ if (get_region_op(0) == 0 && get_region_op(4) == 0)
{
- for(int flag = 0; flag < 2; flag++)
+ std::fill_n(m_weight_factor[0], std::size(m_weight_factor[0]), latched_wfa);
+ std::fill_n(m_weight_factor[1], std::size(m_weight_factor[1]), latched_wfb);
+ std::fill_n(m_region_flag[0], std::size(m_region_flag[0]), false);
+ std::fill_n(m_region_flag[1], std::size(m_region_flag[1]), false);
+ return;
+ }
+
+ for (int x = 0; x < 768; x++)
+ {
+ for (int flag = 0; flag < 2; flag++)
{
- for(int reg_ = 0; reg_ < 4; reg_++)
+ for (int region = 0; region < 4; region++)
{
- if(m_channel[0].region_control[reg_] == 0)
+ const int region_idx = (flag << 2) + region;
+ const uint32_t region_ctrl = m_region_control[region_idx];
+ const uint32_t region_op = get_region_op(region_idx);
+ if (region_op == 0)
{
break;
}
- if(x == (m_channel[0].region_control[flag*4 + reg_] & MCD212_RC_X))
+ if (x == (region_ctrl & RC_X))
{
- switch((m_channel[0].region_control[flag*4 + reg_] & MCD212_RC_OP) >> MCD212_RC_OP_SHIFT)
+ switch (region_op)
{
case 0: // End of region control for line
break;
@@ -80,106 +94,71 @@ void mcd212_device::update_region_arrays()
case 3: // Not used
break;
case 4: // Change weight of plane A
- latched_wfa = (m_channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
+ latched_wfa = get_weight_factor(region_idx);
break;
case 5: // Not used
break;
case 6: // Change weight of plane B
- latched_wfb = (m_channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
+ latched_wfb = get_weight_factor(region_idx);
break;
case 7: // Not used
break;
case 8: // Reset region flag
- if(flag)
- {
- latched_rf1 = 0;
- }
- else
- {
- latched_rf0 = 0;
- }
+ latched_rf[flag] = false;
break;
case 9: // Set region flag
- if(flag)
- {
- latched_rf1 = 1;
- }
- else
- {
- latched_rf0 = 1;
- }
+ latched_rf[flag] = true;
break;
case 10: // Not used
case 11: // Not used
break;
case 12: // Reset region flag and change weight of plane A
- latched_wfa = (m_channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
- if(flag)
- {
- latched_rf1 = 0;
- }
- else
- {
- latched_rf0 = 0;
- }
+ latched_wfa = get_weight_factor(region_idx);
+ latched_rf[flag] = false;
break;
case 13: // Set region flag and change weight of plane A
- latched_wfa = (m_channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
- if(flag)
- {
- latched_rf1 = 1;
- }
- else
- {
- latched_rf0 = 1;
- }
+ latched_wfa = get_weight_factor(region_idx);
+ latched_rf[flag] = true;
break;
case 14: // Reset region flag and change weight of plane B
- latched_wfb = (m_channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
- if(flag)
- {
- latched_rf1 = 0;
- }
- else
- {
- latched_rf0 = 0;
- }
+ latched_wfb = get_weight_factor(region_idx);
+ latched_rf[flag] = false;
break;
case 15: // Set region flag and change weight of plane B
- latched_wfb = (m_channel[0].region_control[flag*4 + reg_] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
- if(flag)
- {
- latched_rf1 = 1;
- }
- else
- {
- latched_rf0 = 1;
- }
+ latched_wfb = get_weight_factor(region_idx);
+ latched_rf[flag] = true;
break;
}
}
}
}
+ m_weight_factor[0][x] = latched_wfa;
+ m_weight_factor[1][x] = latched_wfb;
+ m_region_flag[0][x] = latched_rf[0];
+ m_region_flag[1][x] = latched_rf[1];
}
- else
+ }
+ else
+ {
+ int region_idx = 0;
+ for (int x = 0; x < 768; x++)
{
- if(reg < 8)
+ if (region_idx < 8)
{
- int flag = (m_channel[0].region_control[reg] & MCD212_RC_RF) >> MCD212_RC_RF_SHIFT;
- if(!(m_channel[0].region_control[reg] & MCD212_RC_OP))
+ const int flag = BIT(m_region_control[region_idx], RC_RF_BIT);
+ const uint32_t region_ctrl = m_region_control[region_idx];
+ const uint32_t region_op = get_region_op(region_idx);
+ if (region_op == 0)
{
- for(; x < 768; x++)
- {
- m_channel[0].weight_factor_a[x] = latched_wfa;
- m_channel[1].weight_factor_b[x] = latched_wfb;
- m_region_flag_0[x] = latched_rf0;
- m_region_flag_1[x] = latched_rf1;
- }
- break;
+ std::fill_n(m_weight_factor[0] + x, std::size(m_weight_factor[0]) - x, latched_wfa);
+ std::fill_n(m_weight_factor[1] + x, std::size(m_weight_factor[1]) - x, latched_wfb);
+ std::fill_n(m_region_flag[0] + x, std::size(m_region_flag[0]) - x, false);
+ std::fill_n(m_region_flag[1] + x, std::size(m_region_flag[1]) - x, false);
+ return;
}
- if(x == (m_channel[0].region_control[reg] & MCD212_RC_X))
+ if (x == (region_ctrl & RC_X))
{
- switch((m_channel[0].region_control[reg] & MCD212_RC_OP) >> MCD212_RC_OP_SHIFT)
+ switch (region_op)
{
case 0: // End of region control for line
break;
@@ -188,104 +167,56 @@ void mcd212_device::update_region_arrays()
case 3: // Not used
break;
case 4: // Change weight of plane A
- latched_wfa = (m_channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
+ latched_wfa = get_weight_factor(region_idx);
break;
case 5: // Not used
break;
case 6: // Change weight of plane B
- latched_wfb = (m_channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
+ latched_wfb = get_weight_factor(region_idx);
break;
case 7: // Not used
break;
case 8: // Reset region flag
- if(flag)
- {
- latched_rf1 = 0;
- }
- else
- {
- latched_rf0 = 0;
- }
+ latched_rf[flag] = false;
break;
case 9: // Set region flag
- if(flag)
- {
- latched_rf1 = 1;
- }
- else
- {
- latched_rf0 = 1;
- }
+ latched_rf[flag] = true;
break;
case 10: // Not used
case 11: // Not used
break;
case 12: // Reset region flag and change weight of plane A
- latched_wfa = (m_channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
- if(flag)
- {
- latched_rf1 = 0;
- }
- else
- {
- latched_rf0 = 0;
- }
+ latched_wfa = get_weight_factor(region_idx);
+ latched_rf[flag] = false;
break;
case 13: // Set region flag and change weight of plane A
- latched_wfa = (m_channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
- if(flag)
- {
- latched_rf1 = 1;
- }
- else
- {
- latched_rf0 = 1;
- }
+ latched_wfa = get_weight_factor(region_idx);
+ latched_rf[flag] = true;
break;
case 14: // Reset region flag and change weight of plane B
- latched_wfb = (m_channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
- if(flag)
- {
- latched_rf1 = 0;
- }
- else
- {
- latched_rf0 = 0;
- }
+ latched_wfb = get_weight_factor(region_idx);
+ latched_rf[flag] = false;
break;
case 15: // Set region flag and change weight of plane B
- latched_wfb = (m_channel[0].region_control[reg] & MCD212_RC_WF) >> MCD212_RC_WF_SHIFT;
- if(flag)
- {
- latched_rf1 = 1;
- }
- else
- {
- latched_rf0 = 1;
- }
+ latched_wfb = get_weight_factor(region_idx);
+ latched_rf[flag] = true;
break;
}
- reg++;
+ region_idx++;
}
}
+ m_weight_factor[0][x] = latched_wfa;
+ m_weight_factor[1][x] = latched_wfb;
+ m_region_flag[0][x] = latched_rf[0];
+ m_region_flag[1][x] = latched_rf[1];
}
- m_channel[0].weight_factor_a[x] = latched_wfa;
- m_channel[1].weight_factor_b[x] = latched_wfb;
- m_region_flag_0[x] = latched_rf0;
- m_region_flag_1[x] = latched_rf1;
}
}
-void mcd212_device::set_vsr(int channel, uint32_t value)
-{
- m_channel[channel].vsr = value & 0x0000ffff;
- m_channel[channel].dcr &= 0xffc0;
- m_channel[channel].dcr |= (value >> 16) & 0x003f;
-}
-
-void mcd212_device::set_register(int channel, uint8_t reg, uint32_t value)
+template <int Channel>
+void mcd212_device::set_register(uint8_t reg, uint32_t value)
{
- switch(reg)
+ switch (reg)
{
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: // CLUT 0 - 63
case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
@@ -295,97 +226,97 @@ void mcd212_device::set_register(int channel, uint8_t reg, uint32_t value)
case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
- verboselog(*this, 11, " %04xxxxx: %d: CLUT[%d] = %08x\n", channel * 0x20, channel, m_channel[channel].clut_bank * 0x40 + (reg - 0x80), value );
- m_channel[0].clut_r[m_channel[channel].clut_bank * 0x40 + (reg - 0x80)] = (uint8_t)(value >> 16) & 0xfc;
- m_channel[0].clut_g[m_channel[channel].clut_bank * 0x40 + (reg - 0x80)] = (uint8_t)(value >> 8) & 0xfc;
- m_channel[0].clut_b[m_channel[channel].clut_bank * 0x40 + (reg - 0x80)] = (uint8_t)(value >> 0) & 0xfc;
- break;
+ {
+ const uint8_t clut_index = m_clut_bank[Channel] * 0x40 + (reg - 0x80);
+ LOGMASKED(LOG_CLUT, "%s: Channel %d: CLUT[%d] = %08x\n", machine().describe_context(), Channel, clut_index, value);
+ m_clut[clut_index] = value & 0x00fcfcfc;
+ } break;
case 0xc0: // Image Coding Method
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Image Coding Method = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].image_coding_method = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Channel 0: Image Coding Method = %08x\n", machine().describe_context(), value);
+ m_image_coding_method = value;
}
break;
case 0xc1: // Transparency Control
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Transparency Control = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].transparency_control = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Transparency Control = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_transparency_control = value;
}
break;
case 0xc2: // Plane Order
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Plane Order = %08x\n", channel * 0x20, channel, value & 7);
- m_channel[channel].plane_order = value & 0x00000007;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Plane Order = %08x\n", machine().describe_context(), screen().vpos(), value & 7);
+ m_plane_order = value & 0x00000007;
}
break;
case 0xc3: // CLUT Bank Register
- verboselog(*this, 6, " %04xxxxx: %d: CLUT Bank Register = %08x\n", channel * 0x20, channel, value & 3);
- m_channel[channel].clut_bank = channel ? (2 | (value & 0x00000001)) : (value & 0x00000003);
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel %d: CLUT Bank Register = %08x\n", machine().describe_context(), screen().vpos(), Channel, value & 3);
+ m_clut_bank[Channel] = Channel ? (2 | (value & 0x00000001)) : (value & 0x00000003);
break;
case 0xc4: // Transparent Color A
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Transparent Color A = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].transparent_color_a = value & 0xfcfcfc;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Transparent Color A = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_transparent_color[0] = value & 0x00fcfcfc;
}
break;
case 0xc6: // Transparent Color B
- if(channel == 1)
+ if (Channel == 1)
{
- verboselog(*this, 6, " %04xxxxx: %d: Transparent Color B = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].transparent_color_b = value & 0xfcfcfc;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 1: Transparent Color B = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_transparent_color[1] = value & 0x00fcfcfc;
}
break;
case 0xc7: // Mask Color A
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Mask Color A = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].mask_color_a = value & 0xfcfcfc;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Mask Color A = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_mask_color[0] = value & 0x00fcfcfc;
}
break;
case 0xc9: // Mask Color B
- if(channel == 1)
+ if (Channel == 1)
{
- verboselog(*this, 6, " %04xxxxx: %d: Mask Color B = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].mask_color_b = value & 0xfcfcfc;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 1: Mask Color B = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_mask_color[1] = value & 0x00fcfcfc;
}
break;
case 0xca: // Delta YUV Absolute Start Value A
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Delta YUV Absolute Start Value A = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].dyuv_abs_start_a = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Delta YUV Absolute Start Value A = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_dyuv_abs_start[0] = value;
}
break;
case 0xcb: // Delta YUV Absolute Start Value B
- if(channel == 1)
+ if (Channel == 1)
{
- verboselog(*this, 6, " %04xxxxx: %d: Delta YUV Absolute Start Value B = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].dyuv_abs_start_b = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 1: Delta YUV Absolute Start Value B = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_dyuv_abs_start[1] = value;
}
break;
case 0xcd: // Cursor Position
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Cursor Position = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].cursor_position = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Cursor Position = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_cursor_position = value;
}
break;
case 0xce: // Cursor Control
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 11, " %04xxxxx: %d: Cursor Control = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].cursor_control = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Cursor Control = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_cursor_control = value;
}
break;
case 0xcf: // Cursor Pattern
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 11, " %04xxxxx: %d: Cursor Pattern[%d] = %04x\n", channel * 0x20, channel, (value >> 16) & 0x000f, value & 0x0000ffff);
- m_channel[channel].cursor_pattern[(value >> 16) & 0x000f] = value & 0x0000ffff;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Cursor Pattern[%d] = %04x\n", machine().describe_context(), screen().vpos(), (value >> 16) & 0x000f, value & 0x0000ffff);
+ m_cursor_pattern[(value >> 16) & 0x000f] = value & 0x0000ffff;
}
break;
case 0xd0: // Region Control 0-7
@@ -396,273 +327,273 @@ void mcd212_device::set_register(int channel, uint8_t reg, uint32_t value)
case 0xd5:
case 0xd6:
case 0xd7:
- verboselog(*this, 6, " %04xxxxx: %d: Region Control %d = %08x\n", channel * 0x20, channel, reg & 7, value );
- m_channel[0].region_control[reg & 7] = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel %d: Region Control %d = %08x\n", machine().describe_context(), screen().vpos(), Channel, reg & 7, value);
+ m_region_control[reg & 7] = value;
update_region_arrays();
break;
case 0xd8: // Backdrop Color
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Backdrop Color = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].backdrop_color = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Backdrop Color = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_backdrop_color = value;
}
break;
case 0xd9: // Mosaic Pixel Hold Factor A
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Mosaic Pixel Hold Factor A = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].mosaic_hold_a = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Mosaic Pixel Hold Factor A = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_mosaic_hold[0] = value;
}
break;
case 0xda: // Mosaic Pixel Hold Factor B
- if(channel == 1)
+ if (Channel == 1)
{
- verboselog(*this, 6, " %04xxxxx: %d: Mosaic Pixel Hold Factor B = %08x\n", channel * 0x20, channel, value );
- m_channel[channel].mosaic_hold_b = value;
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 1: Mosaic Pixel Hold Factor B = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_mosaic_hold[1] = value;
}
break;
case 0xdb: // Weight Factor A
- if(channel == 0)
+ if (Channel == 0)
{
- verboselog(*this, 6, " %04xxxxx: %d: Weight Factor A = %08x\n", channel * 0x20, channel, value );
- memset(m_channel[channel].weight_factor_a, value & 0x000000ff, 768);
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 0: Weight Factor A = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_weight_factor[0][0] = (uint8_t)value;
update_region_arrays();
}
break;
case 0xdc: // Weight Factor B
- if(channel == 1)
+ if (Channel == 1)
{
- verboselog(*this, 6, " %04xxxxx: %d: Weight Factor B = %08x\n", channel * 0x20, channel, value );
- memset(m_channel[channel].weight_factor_b, value & 0x000000ff, 768);
+ LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Channel 1: Weight Factor B = %08x\n", machine().describe_context(), screen().vpos(), value);
+ m_weight_factor[1][0] = (uint8_t)value;
update_region_arrays();
}
break;
}
}
-uint32_t mcd212_device::get_vsr(int channel)
+template <int Channel>
+inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr()
+{
+ return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel];
+}
+
+template <int Channel>
+inline ATTR_FORCE_INLINE void mcd212_device::set_vsr(uint32_t value)
{
- return ((m_channel[channel].dcr & 0x3f) << 16) | m_channel[channel].vsr;
+ m_vsr[Channel] = value & 0x0000ffff;
+ m_dcr[Channel] &= 0xffc0;
+ m_dcr[Channel] |= (value >> 16) & 0x003f;
}
-void mcd212_device::set_dcp(int channel, uint32_t value)
+template <int Channel>
+inline ATTR_FORCE_INLINE void mcd212_device::set_dcp(uint32_t value)
{
- m_channel[channel].dcp = value & 0x0000ffff;
- m_channel[channel].ddr &= 0xffc0;
- m_channel[channel].ddr |= (value >> 16) & 0x003f;
+ m_dcp[Channel] = value & 0x0000ffff;
+ m_ddr[Channel] &= 0xffc0;
+ m_ddr[Channel] |= (value >> 16) & 0x003f;
}
-uint32_t mcd212_device::get_dcp(int channel)
+template <int Channel>
+inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_dcp()
{
- return ((m_channel[channel].ddr & 0x3f) << 16) | m_channel[channel].dcp;
+ return ((m_ddr[Channel] & 0x3f) << 16) | m_dcp[Channel];
}
-void mcd212_device::set_display_parameters(int channel, uint8_t value)
+template <int Channel>
+inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t value)
{
- m_channel[channel].ddr &= 0xf0ff;
- m_channel[channel].ddr |= (value & 0x0f) << 8;
- m_channel[channel].dcr &= 0xf7ff;
- m_channel[channel].dcr |= (value & 0x10) << 7;
+ m_ddr[Channel] &= 0xf0ff;
+ m_ddr[Channel] |= (value & 0x0f) << 8;
+ m_dcr[Channel] &= 0xf7ff;
+ m_dcr[Channel] |= (value & 0x10) << 7;
}
void mcd212_device::update_visible_area()
{
- const rectangle &visarea = screen().visible_area();
- rectangle visarea1;
+ rectangle visarea;
attoseconds_t period = screen().frame_period().attoseconds();
- int width = 0;
- if((m_channel[0].dcr & (MCD212_DCR_CF | MCD212_DCR_FD)) && (m_channel[0].csrw & MCD212_CSR1W_ST))
- {
- width = 360;
- }
- else
- {
- width = 384;
- }
+ const bool st_set = (m_csrw[0] & CSR1W_ST) != 0;
+ const bool fd_set = (m_dcr[0] & (DCR_CF | DCR_FD)) != 0;
+ int total_width = 384;
+ if (fd_set && st_set)
+ total_width = 360;
- visarea1.max_x = width-1;
- visarea1.min_x = visarea.min_x;
- visarea1.min_y = visarea.min_y;
- visarea1.max_y = visarea.max_y;
+ const bool pal = !(m_dcr[0] & DCR_FD);
+ const int total_height = (pal ? 312 : 262);
- screen().configure(width, 302, visarea1, period);
+ int visible_height = 240;
+ if (pal && !st_set)
+ visible_height = 280;
+
+ m_ica_height = total_height - visible_height;
+ m_total_height = total_height;
+
+ visarea.min_y = m_ica_height;
+ visarea.max_y = total_height - 1;
+ visarea.min_x = 0;
+ visarea.max_x = total_width - 1;
+
+ screen().configure(total_width, total_height, visarea, period);
}
uint32_t mcd212_device::get_screen_width()
{
- if((m_channel[0].dcr & (MCD212_DCR_CF | MCD212_DCR_FD)) && (m_channel[0].csrw & MCD212_CSR1W_ST))
+ if ((m_dcr[0] & (DCR_CF | DCR_FD)) && (m_csrw[0] & CSR1W_ST))
{
return 720;
}
return 768;
}
-void mcd212_device::process_ica(int channel)
+template <int Channel>
+void mcd212_device::process_ica()
{
- uint16_t *ica = channel ? m_planeb.target() : m_planea.target();
- uint32_t addr = 0x000400/2;
+ uint16_t *ica = Channel ? m_planeb.target() : m_planea.target();
+ uint32_t addr = 0x200;
uint32_t cmd = 0;
- while(1)
+
+ const int max_to_process = m_ica_height * 120;
+ for (int i = 0; i < max_to_process; i++)
{
- uint8_t stop = 0;
cmd = ica[addr++] << 16;
cmd |= ica[addr++];
- switch((cmd & 0xff000000) >> 24)
+ switch ((cmd & 0xff000000) >> 24)
{
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // STOP
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- verboselog(*this, 11, "%08x: %08x: ICA %d: STOP\n", addr * 2 + channel * 0x200000, cmd, channel );
- stop = 1;
- break;
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: STOP\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
+ return;
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: // NOP
case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
- verboselog(*this, 12, "%08x: %08x: ICA %d: NOP\n", addr * 2 + channel * 0x200000, cmd, channel );
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: NOP\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
break;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: // RELOAD DCP
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
- verboselog(*this, 11, "%08x: %08x: ICA %d: RELOAD DCP\n", addr * 2 + channel * 0x200000, cmd, channel );
- set_dcp(channel, cmd & 0x001fffff);
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP: %06x\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel, cmd & 0x001fffff );
+ set_dcp<Channel>(cmd & 0x003ffffc);
break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // RELOAD DCP and STOP
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
- verboselog(*this, 11, "%08x: %08x: ICA %d: RELOAD DCP and STOP\n", addr * 2 + channel * 0x200000, cmd, channel );
- set_dcp(channel, cmd & 0x001fffff);
- stop = 1;
- break;
- case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: // RELOAD ICA
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP and STOP: %06x\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel, cmd & 0x001fffff );
+ set_dcp<Channel>(cmd & 0x003ffffc);
+ return;
+ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: // RELOAD VSR (ICA)
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
- verboselog(*this, 11, "%08x: %08x: ICA %d: RELOAD ICA\n", addr * 2 + channel * 0x200000, cmd, channel );
- addr = (cmd & 0x001fffff) / 2;
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel, cmd & 0x001fffff );
+ addr = (cmd & 0x0007ffff) / 2;
break;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: // RELOAD VSR and STOP
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
- verboselog(*this, 11, "%08x: %08x: ICA %d: RELOAD VSR and STOP\n", addr * 2 + channel * 0x200000, cmd, channel );
- set_vsr(channel, cmd & 0x001fffff);
- stop = 1;
- break;
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR and STOP: VSR = %05x\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel, cmd & 0x001fffff );
+ set_vsr<Channel>(cmd & 0x003fffff);
+ return;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: // INTERRUPT
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
- verboselog(*this, 11, "%08x: %08x: ICA %d: INTERRUPT\n", addr * 2 + channel * 0x200000, cmd, channel );
- m_channel[1].csrr |= 1 << (2 - channel);
- if(m_channel[1].csrr & (MCD212_CSR2R_IT1 | MCD212_CSR2R_IT2))
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: INTERRUPT\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
+ m_csrr[1] |= 1 << (2 - Channel);
+ if (m_csrr[1] & (CSR2R_IT1 | CSR2R_IT2))
m_int_callback(ASSERT_LINE);
break;
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // RELOAD DISPLAY PARAMETERS
- verboselog(*this, 6, "%08x: %08x: ICA %d: RELOAD DISPLAY PARAMETERS\n", addr * 2 + channel * 0x200000, cmd, channel );
- set_display_parameters(channel, cmd & 0x1f);
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
+ set_display_parameters<Channel>(cmd & 0x1f);
break;
default:
- set_register(channel, cmd >> 24, cmd & 0x00ffffff);
+ LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: SET REGISTER %02x = %06x\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel, cmd >> 24, cmd & 0x00ffffff );
+ set_register<Channel>(cmd >> 24, cmd & 0x00ffffff);
break;
}
- if(stop)
- {
- break;
- }
}
}
-void mcd212_device::process_dca(int channel)
+template <int Channel>
+void mcd212_device::process_dca()
{
- uint16_t *dca = channel ? m_planeb.target() : m_planea.target();
- uint32_t addr = (m_channel[channel].dca & 0x0007ffff) / 2; //(get_dcp(mcd212, channel) & 0x0007ffff) / 2; // m_channel[channel].dca / 2;
+ if (screen().vpos() == m_ica_height)
+ {
+ m_dca[Channel] = get_dcp<Channel>();
+ }
+
+ uint16_t *dca = Channel ? m_planeb.target() : m_planea.target();
+ uint32_t addr = (m_dca[Channel] & 0x0007ffff) / 2;
uint32_t cmd = 0;
uint32_t count = 0;
uint32_t max = 64;
- uint8_t addr_changed = 0;
- //printf( "max = %d\n", max );
- while(1)
+ bool addr_changed = false;
+ bool processing = true;
+
+ while (processing && count < max)
{
- uint8_t stop = 0;
cmd = dca[addr++] << 16;
cmd |= dca[addr++];
count += 4;
- switch((cmd & 0xff000000) >> 24)
+ switch ((cmd & 0xff000000) >> 24)
{
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // STOP
case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- verboselog(*this, 11, "%08x: %08x: DCA %d: STOP\n", addr * 2 + channel * 0x200000, cmd, channel );
- stop = 1;
+ LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: STOP\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
+ processing = false;
break;
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: // NOP
case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
- verboselog(*this, 12, "%08x: %08x: DCA %d: NOP\n", addr * 2 + channel * 0x200000, cmd, channel );
+ LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: NOP\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
break;
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: // RELOAD DCP
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
- verboselog(*this, 11, "%08x: %08x: DCA %d: RELOAD DCP (NOP)\n", addr * 2 + channel * 0x200000, cmd, channel );
+ LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP (NOP)\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: // RELOAD DCP and STOP
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
- verboselog(*this, 11, "%08x: %08x: DCA %d: RELOAD DCP and STOP\n", addr * 2 + channel * 0x200000, cmd, channel );
- set_dcp(channel, cmd & 0x001fffff);
- addr = (cmd & 0x0007ffff) / 2;
- addr_changed = 1;
- stop = 1;
- break;
+ LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP and STOP\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
+ set_dcp<Channel>(cmd & 0x003ffffc);
+ m_dca[Channel] = cmd & 0x0007fffc;
+ return;
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: // RELOAD VSR
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
- verboselog(*this, 11, "%08x: %08x: DCA %d: RELOAD VSR\n", addr * 2 + channel * 0x200000, cmd, channel );
- set_vsr(channel, cmd & 0x001fffff);
+ LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel, cmd & 0x001fffff );
+ set_vsr<Channel>(cmd & 0x003fffff);
break;
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: // RELOAD VSR and STOP
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
- verboselog(*this, 11, "%08x: %08x: DCA %d: RELOAD VSR and STOP\n", addr * 2 + channel * 0x200000, cmd, channel );
- set_vsr(channel, cmd & 0x001fffff);
- stop = 1;
+ LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR and STOP: %06x\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel, cmd & 0x001fffff );
+ set_vsr<Channel>(cmd & 0x003fffff);
+ processing = false;
break;
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: // INTERRUPT
case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
- verboselog(*this, 11, "%08x: %08x: DCA %d: INTERRUPT\n", addr * 2 + channel * 0x200000, cmd, channel );
- m_channel[1].csrr |= 1 << (2 - channel);
- if(m_channel[1].csrr & (MCD212_CSR2R_IT1 | MCD212_CSR2R_IT2))
+ LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: INTERRUPT\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
+ m_csrr[1] |= 1 << (2 - Channel);
+ if (m_csrr[1] & (CSR2R_IT1 | CSR2R_IT2))
m_int_callback(ASSERT_LINE);
break;
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: // RELOAD DISPLAY PARAMETERS
- verboselog(*this, 6, "%08x: %08x: DCA %d: RELOAD DISPLAY PARAMETERS\n", addr * 2 + channel * 0x200000, cmd, channel );
- set_display_parameters(channel, cmd & 0x1f);
+ LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Channel * 0x200000, cmd, Channel );
+ set_display_parameters<Channel>(cmd & 0x1f);
break;
default:
- set_register(channel, cmd >> 24, cmd & 0x00ffffff);
+ set_register<Channel>(cmd >> 24, cmd & 0x00ffffff);
break;
}
- if(stop != 0 || count == max)
- {
- break;
- }
}
- if(!addr_changed)
- {
- if(count < max)
- {
- addr += (max - count) >> 1;
- }
- }
- m_channel[channel].dca = addr * 2;
-}
-static inline uint8_t MCD212_LIM(int32_t in)
-{
- if(in < 0)
- {
- return 0;
- }
- else if(in > 255)
+ if (!addr_changed)
{
- return 255;
+ addr += (max - count) >> 1;
}
- return (uint8_t)in;
+
+ m_dca[Channel] = addr * 2;
}
-static inline uint8_t BYTE_TO_CLUT(int channel, int icm, uint8_t byte)
+template <int Channel>
+static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte)
{
- switch(icm)
+ switch (icm)
{
case 1:
return byte;
case 3:
- if(channel)
+ if (Channel == 1)
{
return 0x80 + (byte & 0x7f);
}
@@ -671,13 +602,13 @@ static inline uint8_t BYTE_TO_CLUT(int channel, int icm, uint8_t byte)
return byte & 0x7f;
}
case 4:
- if(!channel)
+ if (Channel == 0)
{
return byte & 0x7f;
}
break;
case 11:
- if(channel)
+ if (Channel == 1)
{
return 0x80 + (byte & 0x0f);
}
@@ -691,109 +622,139 @@ static inline uint8_t BYTE_TO_CLUT(int channel, int icm, uint8_t byte)
return 0;
}
-void mcd212_device::process_vsr(int channel, uint8_t *pixels_r, uint8_t *pixels_g, uint8_t *pixels_b)
+template <int Channel>
+inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control()
{
- uint8_t *data = reinterpret_cast<uint8_t *>(channel ? m_planeb.target() : m_planea.target());
- uint32_t vsr = get_vsr(channel) & 0x0007ffff;
- uint8_t done = 0;
- uint32_t x = 0;
- uint32_t icm_mask = channel ? MCD212_ICM_MODE2 : MCD212_ICM_MODE1;
- uint32_t icm_shift = channel ? MCD212_ICM_MODE2_SHIFT : MCD212_ICM_MODE1_SHIFT;
- uint8_t icm = (m_channel[0].image_coding_method & icm_mask) >> icm_shift;
- uint8_t *clut_r = m_channel[0].clut_r;
- uint8_t *clut_g = m_channel[0].clut_g;
- uint8_t *clut_b = m_channel[0].clut_b;
- uint8_t mosaic_enable = ((m_channel[channel].ddr & MCD212_DDR_FT) == MCD212_DDR_FT_MOSAIC);
- uint8_t mosaic_factor = 1 << (((m_channel[channel].ddr & MCD212_DDR_MT) >> MCD212_DDR_MT_SHIFT) + 1);
- int mosaic_index = 0;
- uint32_t width = get_screen_width();
+ return (m_transparency_control >> (Channel ? 8 : 0)) & 0x0f;
+}
+
+template <int Channel>
+inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_icm()
+{
+ const uint32_t mask = Channel ? ICM_MODE2 : ICM_MODE1;
+ const uint32_t shift = Channel ? ICM_MODE2_SHIFT : ICM_MODE1_SHIFT;
+ return (m_image_coding_method & mask) >> shift;
+}
+
+template <int Channel>
+inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable()
+{
+ return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC;
+}
+
+template <int Channel>
+inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor()
+{
+ return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1);
+}
+
+template <int Channel>
+void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent)
+{
+ const uint8_t *data = reinterpret_cast<uint8_t *>(Channel ? m_planeb.target() : m_planea.target());
+ const uint8_t icm = get_icm<Channel>();
+ const uint32_t width = get_screen_width();
+ const uint8_t transp_ctrl = get_transparency_control<Channel>();
- //printf( "vsr before: %08x: ", vsr );
- //fflush(stdout);
+ uint32_t vsr = get_vsr<Channel>();
- if(!icm || !vsr)
+ if (!icm || !vsr || (transp_ctrl == TCR_COND_1))
{
- memset(pixels_r, 0x10, width);
- memset(pixels_g, 0x10, width);
- memset(pixels_b, 0x10, width);
+ std::fill_n(pixels, width, 0x00101010);
+ std::fill_n(transparent, width, true);
return;
}
- while(!done)
+ const uint8_t mosaic_enable = get_mosaic_enable<Channel>();
+ const uint8_t mosaic_factor = get_mosaic_factor<Channel>();
+
+ const uint32_t dyuv_abs_start = m_dyuv_abs_start[Channel];
+ const uint8_t start_y = (dyuv_abs_start >> 16) & 0x000000ff;
+ const uint8_t start_u = (dyuv_abs_start >> 8) & 0x000000ff;
+ const uint8_t start_v = (dyuv_abs_start >> 0) & 0x000000ff;
+
+ const uint32_t transparent_color = m_transparent_color[Channel];
+ const uint8_t transp_ctrl_masked = transp_ctrl & 0x07;
+ const bool transp_always = (transp_ctrl_masked == TCR_COND_1);
+ const bool invert_transp_condition = BIT(transp_ctrl, 3);
+ const int region_flag_index = 1 - (transp_ctrl_masked & 1);
+ const bool *region_flags = m_region_flag[region_flag_index];
+ const bool use_region_flag = (transp_ctrl_masked >= TCR_COND_RF0_1 && transp_ctrl_masked <= TCR_COND_RF1KEY_1);
+ bool use_color_key = (transp_ctrl_masked == TCR_COND_KEY_1 || transp_ctrl_masked == TCR_COND_RF0KEY_1 || transp_ctrl_masked == TCR_COND_RF1KEY_1);
+
+ int mosaic_index = 0;
+ bool done = false;
+ uint32_t x = 0;
+
+ LOGMASKED(LOG_VSR, "Scanline %d: VSR Channel %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Channel, icm, vsr);
+
+ while (!done)
{
uint8_t byte = data[(vsr & 0x0007ffff) ^ 1];
+ LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: VSR[%05x] = %02x\n", screen().vpos(), Channel, (vsr & 0x0007ffff), byte);
vsr++;
- switch(m_channel[channel].ddr & MCD212_DDR_FT)
+ switch (m_ddr[Channel] & DDR_FT)
{
- case MCD212_DDR_FT_BMP:
- case MCD212_DDR_FT_BMP2:
- case MCD212_DDR_FT_MOSAIC:
- if(m_channel[channel].dcr & MCD212_DCR_CM)
+ case DDR_FT_BMP:
+ case DDR_FT_BMP2:
+ case DDR_FT_MOSAIC:
+ if ((m_ddr[Channel] & DDR_FT) == DDR_FT_BMP)
+ {
+ LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: BMP\n", screen().vpos(), Channel);
+ }
+ else if ((m_ddr[Channel] & DDR_FT) == DDR_FT_BMP2)
+ {
+ LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: BMP2\n", screen().vpos(), Channel);
+ }
+ else if ((m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC)
+ {
+ LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: MOSAIC\n", screen().vpos(), Channel);
+ }
+ if (m_dcr[Channel] & DCR_CM)
{
// 4-bit Bitmap
- verboselog(*this, 0, "%s", "Unsupported display mode: 4-bit Bitmap\n" );
+ LOGMASKED(LOG_UNKNOWNS, "%s", "Unsupported display mode: 4-bit Bitmap\n" );
}
else
{
// 8-bit Bitmap
- if(icm == 5)
+ if (icm == 5)
{
- BYTE68K bY;
- BYTE68K bU;
- BYTE68K bV;
- switch(channel)
- {
- case 0:
- bY = (m_channel[0].dyuv_abs_start_a >> 16) & 0x000000ff;
- bU = (m_channel[0].dyuv_abs_start_a >> 8) & 0x000000ff;
- bV = (m_channel[0].dyuv_abs_start_a >> 0) & 0x000000ff;
- break;
- case 1:
- bY = (m_channel[1].dyuv_abs_start_b >> 16) & 0x000000ff;
- bU = (m_channel[1].dyuv_abs_start_b >> 8) & 0x000000ff;
- bV = (m_channel[1].dyuv_abs_start_b >> 0) & 0x000000ff;
- break;
- default:
- bY = bU = bV = 0x80;
- break;
- }
- for(; x < width; x += 2)
- {
- BYTE68K b0 = byte;
- BYTE68K bU1 = bU + m_ab.deltaUV[b0];
- BYTE68K bY0 = bY + m_ab.deltaY[b0];
-
- BYTE68K b1 = data[(vsr & 0x0007ffff) ^ 1];
- BYTE68K bV1 = bV + m_ab.deltaUV[b1];
- BYTE68K bY1 = bY0 + m_ab.deltaY[b1];
-
- BYTE68K bU0 = (bU + bU1) >> 1;
- BYTE68K bV0 = (bV + bV1) >> 1;
+ use_color_key = false;
- BYTE68K *pbLimit;
+ LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: DYUV\n", screen().vpos(), Channel);
+ uint8_t y = start_y;
+ uint8_t u = start_u;
+ uint8_t v = start_v;
+ for (; x < width; x += 2)
+ {
+ const uint8_t byte1 = data[(vsr++ & 0x0007ffff) ^ 1];
+ const uint8_t u1 = u + m_delta_uv_lut[byte];
+ const uint8_t y0 = y + m_delta_y_lut[byte];
- vsr++;
+ const uint8_t v1 = v + m_delta_uv_lut[byte1];
+ const uint8_t y1 = y0 + m_delta_y_lut[byte1];
- bY = bY0;
- bU = bU0;
- bV = bV0;
+ const uint8_t u0 = (u + u1) >> 1;
+ const uint8_t v0 = (v + v1) >> 1;
- pbLimit = m_ab.limit + bY + BYTE68K_MAX;
+ uint32_t *limit_r = m_dyuv_limit_r_lut + y0 + 0xff;
+ uint32_t *limit_g = m_dyuv_limit_g_lut + y0 + 0xff;
+ uint32_t *limit_b = m_dyuv_limit_b_lut + y0 + 0xff;
- pixels_r[x + 0] = pixels_r[x + 1] = pbLimit[m_ab.matrixVR[bV]];
- pixels_g[x + 0] = pixels_g[x + 1] = pbLimit[m_ab.matrixUG[bU] + m_ab.matrixVG[bV]];
- pixels_b[x + 0] = pixels_b[x + 1] = pbLimit[m_ab.matrixUB[bU]];
+ uint32_t entry = limit_r[m_dyuv_v_to_r[v0]] | limit_g[m_dyuv_u_to_g[u0] + m_dyuv_v_to_g[v0]] | limit_b[m_dyuv_u_to_b[u0]];
+ pixels[x] = pixels[x + 1] = entry;
+ transparent[x] = (transp_always || (use_region_flag && region_flags[x])) != invert_transp_condition;
+ transparent[x + 1] = (transp_always || (use_region_flag && region_flags[x])) != invert_transp_condition;
- if(mosaic_enable)
+ if (mosaic_enable)
{
- for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
+ for (mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
{
- pixels_r[x + 0 + mosaic_index*2] = pixels_r[x + 0];
- pixels_g[x + 0 + mosaic_index*2] = pixels_g[x + 0];
- pixels_b[x + 0 + mosaic_index*2] = pixels_b[x + 0];
- pixels_r[x + 1 + mosaic_index*2] = pixels_r[x + 1];
- pixels_g[x + 1 + mosaic_index*2] = pixels_g[x + 1];
- pixels_b[x + 1 + mosaic_index*2] = pixels_b[x + 1];
+ pixels[x + 0 + mosaic_index*2] = pixels[x];
+ pixels[x + 1 + mosaic_index*2] = pixels[x + 1];
+ transparent[x + 0 + mosaic_index*2] = transparent[x];
+ transparent[x + 1 + mosaic_index*2] = transparent[x + 1];
}
x += mosaic_factor * 2;
}
@@ -802,194 +763,170 @@ void mcd212_device::process_vsr(int channel, uint8_t *pixels_r, uint8_t *pixels_
x += 2;
}
- bY = bY1;
- bU = bU1;
- bV = bV1;
-
- pbLimit = m_ab.limit + bY + BYTE68K_MAX;
+ limit_r = m_dyuv_limit_r_lut + y1 + 0xff;
+ limit_g = m_dyuv_limit_g_lut + y1 + 0xff;
+ limit_b = m_dyuv_limit_b_lut + y1 + 0xff;
- pixels_r[x + 0] = pixels_r[x + 1] = pbLimit[m_ab.matrixVR[bV]];
- pixels_g[x + 0] = pixels_g[x + 1] = pbLimit[m_ab.matrixUG[bU] + m_ab.matrixVG[bV]];
- pixels_b[x + 0] = pixels_b[x + 1] = pbLimit[m_ab.matrixUB[bU]];
+ entry = limit_r[m_dyuv_v_to_r[v1]] | limit_g[m_dyuv_u_to_g[u1] + m_dyuv_v_to_g[v1]] | limit_b[m_dyuv_u_to_b[u1]];
+ pixels[x] = pixels[x + 1] = entry;
+ transparent[x] = (transp_always || (use_region_flag && region_flags[x])) != invert_transp_condition;
+ transparent[x + 1] = (transp_always || (use_region_flag && region_flags[x])) != invert_transp_condition;
- if(mosaic_enable)
+ if (mosaic_enable)
{
- for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
+ for (mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
{
- pixels_r[x + 0 + mosaic_index*2] = pixels_r[x + 0];
- pixels_g[x + 0 + mosaic_index*2] = pixels_g[x + 0];
- pixels_b[x + 0 + mosaic_index*2] = pixels_b[x + 0];
- pixels_r[x + 1 + mosaic_index*2] = pixels_r[x + 1];
- pixels_g[x + 1 + mosaic_index*2] = pixels_g[x + 1];
- pixels_b[x + 1 + mosaic_index*2] = pixels_b[x + 1];
+ pixels[x + 0 + mosaic_index*2] = pixels[x];
+ pixels[x + 1 + mosaic_index*2] = pixels[x + 1];
+ transparent[x + 0 + mosaic_index*2] = transparent[x];
+ transparent[x + 1 + mosaic_index*2] = transparent[x + 1];
}
x += (mosaic_factor * 2) - 2;
}
- byte = data[(vsr & 0x0007ffff) ^ 1];
+ byte = data[(vsr++ & 0x0007ffff) ^ 1];
- vsr++;
+ y = y1;
+ u = u1;
+ v = v1;
}
- set_vsr(channel, (vsr - 1) & 0x0007ffff);
+ set_vsr<Channel>(vsr - 1);
}
- else if(icm == 1 || icm == 3 || icm == 4)
+ else if (icm == 1 || icm == 3 || icm == 4)
{
- for(; x < width; x += 2)
+ for (; x < width; x += 2)
{
- uint8_t clut_entry = BYTE_TO_CLUT(channel, icm, byte);
- pixels_r[x + 0] = clut_r[clut_entry];
- pixels_g[x + 0] = clut_g[clut_entry];
- pixels_b[x + 0] = clut_b[clut_entry];
- pixels_r[x + 1] = clut_r[clut_entry];
- pixels_g[x + 1] = clut_g[clut_entry];
- pixels_b[x + 1] = clut_b[clut_entry];
- if(mosaic_enable)
+ uint32_t entry = m_clut[BYTE_TO_CLUT<Channel>(icm, byte)];
+ pixels[x] = pixels[x + 1] = entry;
+ transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x])) != invert_transp_condition;
+ transparent[x + 1] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x + 1])) != invert_transp_condition;
+ if (mosaic_enable)
{
- for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
+ for (mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
{
- pixels_r[x + 0 + mosaic_index*2] = pixels_r[x + 0];
- pixels_g[x + 0 + mosaic_index*2] = pixels_g[x + 0];
- pixels_b[x + 0 + mosaic_index*2] = pixels_b[x + 0];
- pixels_r[x + 1 + mosaic_index*2] = pixels_r[x + 1];
- pixels_g[x + 1 + mosaic_index*2] = pixels_g[x + 1];
- pixels_b[x + 1 + mosaic_index*2] = pixels_b[x + 1];
+ pixels[x + 0 + mosaic_index*2] = pixels[x];
+ pixels[x + 1 + mosaic_index*2] = pixels[x + 1];
+ transparent[x + 0 + mosaic_index*2] = transparent[x];
+ transparent[x + 1 + mosaic_index*2] = transparent[x + 1];
}
x += (mosaic_factor * 2) - 2;
}
byte = data[(vsr & 0x0007ffff) ^ 1];
vsr++;
}
- set_vsr(channel, (vsr - 1) & 0x0007ffff);
+ set_vsr<Channel>(vsr - 1);
}
- else if(icm == 11)
+ else if (icm == 11)
{
- for(; x < width; x += 2)
+ for (; x < width; x += 2)
{
- uint8_t even_entry = BYTE_TO_CLUT(channel, icm, byte >> 4);
- uint8_t odd_entry = BYTE_TO_CLUT(channel, icm, byte);
- if(mosaic_enable)
+ const uint32_t even_entry = m_clut[BYTE_TO_CLUT<Channel>(icm, byte >> 4)];
+ const uint32_t odd_entry = m_clut[BYTE_TO_CLUT<Channel>(icm, byte)];
+ const bool even_pre_transparent = transp_always || (use_color_key && (even_entry == transparent_color));
+ const bool odd_pre_transparent = transp_always || (use_color_key && (odd_entry == transparent_color));
+ if (mosaic_enable)
{
- for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
+ for (int mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
{
- pixels_r[x + mosaic_index] = clut_r[even_entry];
- pixels_g[x + mosaic_index] = clut_g[even_entry];
- pixels_b[x + mosaic_index] = clut_b[even_entry];
+ pixels[x + mosaic_index] = even_entry;
+ transparent[x + mosaic_index] = (even_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition;
}
- for(mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++)
+ for (int mosaic_index = mosaic_factor; mosaic_index < mosaic_factor * 2; mosaic_index++)
{
- pixels_r[x + mosaic_factor + mosaic_index] = clut_r[odd_entry];
- pixels_g[x + mosaic_factor + mosaic_index] = clut_g[odd_entry];
- pixels_b[x + mosaic_factor + mosaic_index] = clut_b[odd_entry];
+ pixels[x + mosaic_index] = odd_entry;
+ transparent[x + mosaic_index] = (odd_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition;
}
x += (mosaic_factor * 2) - 2;
}
else
{
- pixels_r[x + 0] = clut_r[even_entry];
- pixels_g[x + 0] = clut_g[even_entry];
- pixels_b[x + 0] = clut_b[even_entry];
- pixels_r[x + 1] = clut_r[odd_entry];
- pixels_g[x + 1] = clut_g[odd_entry];
- pixels_b[x + 1] = clut_b[odd_entry];
+ pixels[x] = even_entry;
+ transparent[x] = (even_pre_transparent || (use_region_flag && region_flags[x])) != invert_transp_condition;
+
+ pixels[x + 1] = odd_entry;
+ transparent[x + 1] = (odd_pre_transparent || (use_region_flag && region_flags[x + 1])) != invert_transp_condition;
}
byte = data[(vsr & 0x0007ffff) ^ 1];
vsr++;
}
- set_vsr(channel, (vsr - 1) & 0x0007ffff);
+ set_vsr<Channel>(vsr - 1);
}
else
{
- for(; x < width; x++)
- {
- pixels_r[x] = 0x10;
- pixels_g[x] = 0x10;
- pixels_b[x] = 0x10;
- }
+ std::fill_n(pixels + x, width - x, 0x00101010);
+ std::fill_n(transparent + x, width - x, true);
}
}
- done = 1;
+ done = true;
break;
- case MCD212_DDR_FT_RLE:
- if(m_channel[channel].dcr & MCD212_DCR_CM)
+ case DDR_FT_RLE:
+ LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: RLE\n", screen().vpos(), Channel);
+ if (m_dcr[Channel] & DCR_CM)
{
- verboselog(*this, 0, "%s", "Unsupported display mode: 4-bit RLE\n" );
- done = 1;
+ LOGMASKED(LOG_UNKNOWNS, "%s", "Unsupported display mode: 4-bit RLE\n" );
+ done = true;
}
else
{
- if(byte & 0x80)
+ if (byte & 0x80)
{
// Run length
uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1];
- if(!length)
+ LOGMASKED(LOG_VSR, "Byte %02x w/ run length %02x at %d\n", byte, length, x);
+ const uint32_t entry = m_clut[BYTE_TO_CLUT<Channel>(icm, byte & 0x7f)];
+ const bool pre_transparent = (transp_always || (use_color_key && entry == transparent_color));
+ if (!length)
{
- uint8_t clut_entry = BYTE_TO_CLUT(channel, icm, byte);
- uint8_t r = clut_r[clut_entry];
- uint8_t g = clut_g[clut_entry];
- uint8_t b = clut_b[clut_entry];
// Go to the end of the line
- for(; x < width; x++)
+ std::fill_n(pixels + x, width - x, entry);
+ for (int transp_index = x; transp_index < width; transp_index++)
{
- pixels_r[x] = r;
- pixels_g[x] = g;
- pixels_b[x] = b;
- x++;
- pixels_r[x] = r;
- pixels_g[x] = g;
- pixels_b[x] = b;
+ transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[x])) != invert_transp_condition;
}
- done = 1;
- set_vsr(channel, vsr);
+ done = true;
+ set_vsr<Channel>(vsr);
}
else
{
- int end = x + (length * 2);
- uint8_t clut_entry = BYTE_TO_CLUT(channel, icm, byte);
- uint8_t r = clut_r[clut_entry];
- uint8_t g = clut_g[clut_entry];
- uint8_t b = clut_b[clut_entry];
- for(; x < end && x < width; x++)
+ int end = std::min(width, x + (length * 2));
+ std::fill_n(pixels + x, end - x, entry);
+ for (int transp_index = x; transp_index < end; transp_index++)
{
- pixels_r[x] = r;
- pixels_g[x] = g;
- pixels_b[x] = b;
- x++;
- pixels_r[x] = r;
- pixels_g[x] = g;
- pixels_b[x] = b;
+ transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[x])) != invert_transp_condition;
}
- if(x >= width)
+ if (x >= width)
{
- done = 1;
- set_vsr(channel, vsr);
+ done = true;
+ set_vsr<Channel>(vsr);
}
+ x = end;
}
}
else
{
+ LOGMASKED(LOG_VSR, "Byte %02x, single at %d\n", byte, x);
// Single pixel
- uint8_t clut_entry = BYTE_TO_CLUT(channel, icm, byte);
- pixels_r[x] = clut_r[clut_entry];
- pixels_g[x] = clut_g[clut_entry];
- pixels_b[x] = clut_b[clut_entry];
+ const uint32_t entry = m_clut[BYTE_TO_CLUT<Channel>(icm, byte)];
+ const bool pre_transparent = (transp_always || (use_color_key && entry == transparent_color));
+
+ pixels[x] = entry;
+ transparent[x] = (pre_transparent || (use_region_flag && region_flags[x])) != invert_transp_condition;
x++;
- pixels_r[x] = clut_r[clut_entry];
- pixels_g[x] = clut_g[clut_entry];
- pixels_b[x] = clut_b[clut_entry];
+
+ pixels[x] = entry;
+ transparent[x] = (pre_transparent || (use_region_flag && region_flags[x])) != invert_transp_condition;
x++;
- if(x >= width)
+
+ if (x >= width)
{
- done = 1;
- set_vsr(channel, vsr);
+ done = true;
+ set_vsr<Channel>(vsr);
}
}
}
break;
}
}
-
- //printf( ": vsr after: %08x\n", vsr);
- //mcd212_set_vsr(&state->m_mcd212_regs, channel, vsr);
}
const uint32_t mcd212_device::s_4bpp_color[16] =
@@ -998,208 +935,143 @@ const uint32_t mcd212_device::s_4bpp_color[16] =
0x00101010, 0x001010e6, 0x0010e610, 0x0010e6e6, 0x00e61010, 0x00e610e6, 0x00e6e610, 0x00e6e6e6
};
-void mcd212_device::mix_lines(uint8_t *plane_a_r, uint8_t *plane_a_g, uint8_t *plane_a_b, uint8_t *plane_b_r, uint8_t *plane_b_g, uint8_t *plane_b_b, uint32_t *out)
+template <bool MosaicA, bool MosaicB, bool OrderAB>
+void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out)
{
- uint8_t debug_mode = machine().root_device().ioport("DEBUG")->read();
- uint8_t global_plane_a_disable = debug_mode & 1;
- uint8_t global_plane_b_disable = debug_mode & 2;
- uint8_t debug_backdrop_enable = debug_mode & 4;
- uint8_t debug_backdrop_index = debug_mode >> 4;
- uint32_t backdrop = debug_backdrop_enable ? s_4bpp_color[debug_backdrop_index] : s_4bpp_color[m_channel[0].backdrop_color];
- uint8_t transparency_mode_a = (m_channel[0].transparency_control >> 0) & 0x0f;
- uint8_t transparency_mode_b = (m_channel[0].transparency_control >> 8) & 0x0f;
- uint8_t transparent_color_a_r = (uint8_t)(m_channel[0].transparent_color_a >> 16);
- uint8_t transparent_color_a_g = (uint8_t)(m_channel[0].transparent_color_a >> 8);
- uint8_t transparent_color_a_b = (uint8_t)(m_channel[0].transparent_color_a >> 0);
- uint8_t transparent_color_b_r = (uint8_t)(m_channel[1].transparent_color_b >> 16);
- uint8_t transparent_color_b_g = (uint8_t)(m_channel[1].transparent_color_b >> 8);
- uint8_t transparent_color_b_b = (uint8_t)(m_channel[1].transparent_color_b >> 0);
- uint8_t image_coding_method_a = m_channel[0].image_coding_method & 0x0000000f;
- uint8_t image_coding_method_b = (m_channel[0].image_coding_method >> 8) & 0x0000000f;
- bool dyuv_enable_a = (image_coding_method_a == 5);
- bool dyuv_enable_b = (image_coding_method_b == 5);
- uint8_t mosaic_enable_a = (m_channel[0].mosaic_hold_a & 0x800000) >> 23;
- uint8_t mosaic_enable_b = (m_channel[1].mosaic_hold_b & 0x800000) >> 23;
- uint8_t mosaic_count_a = (m_channel[0].mosaic_hold_a & 0x0000ff) << 1;
- uint8_t mosaic_count_b = (m_channel[1].mosaic_hold_b & 0x0000ff) << 1;
- for(int x = 0; x < 768; x++)
+ const uint32_t backdrop = s_4bpp_color[m_backdrop_color];
+ const uint8_t mosaic_count_a = (m_mosaic_hold[0] & 0x0000ff) << 1;
+ const uint8_t mosaic_count_b = (m_mosaic_hold[1] & 0x0000ff) << 1;
+
+ uint8_t *weight_a = &m_weight_factor[0][0];
+ uint8_t *weight_b = &m_weight_factor[1][0];
+
+ if (!(m_transparency_control & TCR_DISABLE_MX))
{
- out[x] = backdrop;
- if(!(m_channel[0].transparency_control & MCD212_TCR_DISABLE_MX))
+ for (int x = 0; x < 768; x++, weight_a++, transparent_a++, weight_b++, transparent_b++)
{
- uint8_t abr = MCD212_LIM(((MCD212_LIM((int32_t)plane_a_r[x] - 16) * m_channel[0].weight_factor_a[x]) >> 6) + ((MCD212_LIM((int32_t)plane_b_r[x] - 16) * m_channel[1].weight_factor_b[x]) >> 6) + 16);
- uint8_t abg = MCD212_LIM(((MCD212_LIM((int32_t)plane_a_g[x] - 16) * m_channel[0].weight_factor_a[x]) >> 6) + ((MCD212_LIM((int32_t)plane_b_g[x] - 16) * m_channel[1].weight_factor_b[x]) >> 6) + 16);
- uint8_t abb = MCD212_LIM(((MCD212_LIM((int32_t)plane_a_b[x] - 16) * m_channel[0].weight_factor_a[x]) >> 6) + ((MCD212_LIM((int32_t)plane_b_b[x] - 16) * m_channel[1].weight_factor_b[x]) >> 6) + 16);
- out[x] = (abr << 16) | (abg << 8) | abb;
+ const uint8_t weight_a_cur = *weight_a;
+ const uint8_t weight_b_cur = *weight_b;
+
+ const uint32_t plane_a_cur = plane_a[x];
+ const uint32_t plane_b_cur = plane_b[x];
+
+ const int32_t plane_a_r = (int32_t)(uint8_t)(plane_a_cur >> 16);
+ const int32_t plane_b_r = (int32_t)(uint8_t)(plane_b_cur >> 16);
+ const int32_t plane_a_g = (int32_t)(uint8_t)(plane_a_cur >> 8);
+ const int32_t plane_b_g = (int32_t)(uint8_t)(plane_b_cur >> 8);
+ const int32_t plane_a_b = (int32_t)(uint8_t)plane_a_cur;
+ const int32_t plane_b_b = (int32_t)(uint8_t)plane_b_cur;
+ const int32_t weighted_a_r = (plane_a_r > 16) ? (((plane_a_r - 16) * weight_a_cur) >> 6) : 0;
+ const int32_t weighted_a_g = (plane_a_g > 16) ? (((plane_a_g - 16) * weight_a_cur) >> 6) : 0;
+ const int32_t weighted_a_b = (plane_a_b > 16) ? (((plane_a_b - 16) * weight_a_cur) >> 6) : 0;
+ const int32_t weighted_b_r = ((plane_b_r > 16) ? (((plane_b_r - 16) * weight_b_cur) >> 6) : 0) + weighted_a_r;
+ const int32_t weighted_b_g = ((plane_b_g > 16) ? (((plane_b_g - 16) * weight_b_cur) >> 6) : 0) + weighted_a_g;
+ const int32_t weighted_b_b = ((plane_b_b > 16) ? (((plane_b_b - 16) * weight_b_cur) >> 6) : 0) + weighted_a_b;
+ const uint8_t out_r = (weighted_b_r > 255) ? 255 : (uint8_t)weighted_b_r;
+ const uint8_t out_g = (weighted_b_g > 255) ? 255 : (uint8_t)weighted_b_g;
+ const uint8_t out_b = (weighted_b_b > 255) ? 255 : (uint8_t)weighted_b_b;
+ out[x] = (out_r << 16) | (out_g << 8) | out_b;
}
- else
+ }
+ else
+ {
+ for (int x = 0; x < 768; x++, weight_a++, transparent_a++, weight_b++, transparent_b++)
{
- uint8_t plane_enable_a = 0;
- uint8_t plane_enable_b = 0;
- uint8_t plane_a_r_cur = mosaic_enable_a ? plane_a_r[x - (x % mosaic_count_a)] : plane_a_r[x];
- uint8_t plane_a_g_cur = mosaic_enable_a ? plane_a_g[x - (x % mosaic_count_a)] : plane_a_g[x];
- uint8_t plane_a_b_cur = mosaic_enable_a ? plane_a_b[x - (x % mosaic_count_a)] : plane_a_b[x];
- uint8_t plane_b_r_cur = mosaic_enable_b ? plane_b_r[x - (x % mosaic_count_b)] : plane_b_r[x];
- uint8_t plane_b_g_cur = mosaic_enable_b ? plane_b_g[x - (x % mosaic_count_b)] : plane_b_g[x];
- uint8_t plane_b_b_cur = mosaic_enable_b ? plane_b_b[x - (x % mosaic_count_b)] : plane_b_b[x];
- switch(transparency_mode_a)
- {
- case 0:
- plane_enable_a = 0;
- break;
- case 1:
- plane_enable_a = (plane_a_r_cur != transparent_color_a_r || plane_a_g_cur != transparent_color_a_g || plane_a_b_cur != transparent_color_a_b);
- break;
- case 3:
- plane_enable_a = !m_region_flag_0[x];
- break;
- case 4:
- plane_enable_a = !m_region_flag_1[x];
- break;
- case 5:
- plane_enable_a = (plane_a_r_cur != transparent_color_a_r || plane_a_g_cur != transparent_color_a_g || plane_a_b_cur != transparent_color_a_b) && (dyuv_enable_a || m_region_flag_0[x] == 0);
- break;
- case 6:
- plane_enable_a = (plane_a_r_cur != transparent_color_a_r || plane_a_g_cur != transparent_color_a_g || plane_a_b_cur != transparent_color_a_b) && (dyuv_enable_a || m_region_flag_1[x] == 0);
- break;
- case 8:
- plane_enable_a = 1;
- break;
- case 9:
- plane_enable_a = (plane_a_r_cur == transparent_color_a_r && plane_a_g_cur == transparent_color_a_g && plane_a_b_cur == transparent_color_a_b);
- break;
- case 11:
- plane_enable_a = m_region_flag_0[x];
- break;
- case 12:
- plane_enable_a = m_region_flag_1[x];
- break;
- case 13:
- plane_enable_a = (plane_a_r_cur == transparent_color_a_r && plane_a_g_cur == transparent_color_a_g && plane_a_b_cur == transparent_color_a_b) || dyuv_enable_a || m_region_flag_0[x] == 1;
- break;
- case 14:
- plane_enable_a = (plane_a_r_cur == transparent_color_a_r && plane_a_g_cur == transparent_color_a_g && plane_a_b_cur == transparent_color_a_b) || dyuv_enable_a || m_region_flag_1[x] == 1;
- break;
- default:
- verboselog(*this, 0, "Unhandled transparency mode for plane A: %d\n", transparency_mode_a);
- plane_enable_a = 1;
- break;
- }
- switch(transparency_mode_b)
- {
- case 0:
- plane_enable_b = 0;
- break;
- case 1:
- plane_enable_b = (plane_b_r_cur != transparent_color_b_r || plane_b_g_cur != transparent_color_b_g || plane_b_b_cur != transparent_color_b_b);
- break;
- case 3:
- plane_enable_b = !m_region_flag_0[x];
- break;
- case 4:
- plane_enable_b = !m_region_flag_1[x];
- break;
- case 5:
- plane_enable_b = (plane_b_r_cur != transparent_color_b_r || plane_b_g_cur != transparent_color_b_g || plane_b_b_cur != transparent_color_b_b) && (dyuv_enable_b || m_region_flag_0[x] == 0);
- break;
- case 6:
- plane_enable_b = (plane_b_r_cur != transparent_color_b_r || plane_b_g_cur != transparent_color_b_g || plane_b_b_cur != transparent_color_b_b) && (dyuv_enable_b || m_region_flag_1[x] == 0);
- break;
- case 8:
- plane_enable_b = 1;
- break;
- case 9:
- plane_enable_b = (plane_b_r_cur == transparent_color_b_r && plane_b_g_cur == transparent_color_b_g && plane_b_b_cur == transparent_color_b_b);
- break;
- case 11:
- plane_enable_b = m_region_flag_0[x];
- break;
- case 12:
- plane_enable_b = m_region_flag_1[x];
- break;
- case 13:
- plane_enable_b = (plane_b_r_cur == transparent_color_b_r && plane_b_g_cur == transparent_color_b_g && plane_b_b_cur == transparent_color_b_b) || dyuv_enable_b || m_region_flag_0[x] == 1;
- break;
- case 14:
- plane_enable_b = (plane_b_r_cur == transparent_color_b_r && plane_b_g_cur == transparent_color_b_g && plane_b_b_cur == transparent_color_b_b) || dyuv_enable_b || m_region_flag_1[x] == 1;
- break;
- default:
- verboselog(*this, 0, "Unhandled transparency mode for plane B: %d\n", transparency_mode_b);
- plane_enable_b = 1;
- break;
- }
- if(global_plane_a_disable)
+ if (OrderAB)
{
- plane_enable_a = 0;
- }
- if(global_plane_b_disable)
- {
- plane_enable_b = 0;
+ if (!(*transparent_a))
+ {
+ const uint32_t plane_a_cur = MosaicA ? plane_a[x - (x % mosaic_count_a)] : plane_a[x];
+ const uint8_t weight_a_cur = *weight_a;
+ const int32_t plane_a_r = (int32_t)(uint8_t)(plane_a_cur >> 16);
+ const int32_t plane_a_g = (int32_t)(uint8_t)(plane_a_cur >> 8);
+ const int32_t plane_a_b = (int32_t)(uint8_t)plane_a_cur;
+ const uint8_t weighted_a_r = std::clamp(((plane_a_r > 16) ? (((plane_a_r - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255);
+ const uint8_t weighted_a_g = std::clamp(((plane_a_g > 16) ? (((plane_a_g - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255);
+ const uint8_t weighted_a_b = std::clamp(((plane_a_b > 16) ? (((plane_a_b - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255);
+ out[x] = (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b;
+ }
+ else if (!(*transparent_b))
+ {
+ const uint32_t plane_b_cur = MosaicB ? plane_b[x - (x % mosaic_count_b)] : plane_b[x];
+ const uint8_t weight_b_cur = *weight_b;
+ const int32_t plane_b_r = (int32_t)(uint8_t)(plane_b_cur >> 16);
+ const int32_t plane_b_g = (int32_t)(uint8_t)(plane_b_cur >> 8);
+ const int32_t plane_b_b = (int32_t)(uint8_t)plane_b_cur;
+ const uint8_t weighted_b_r = std::clamp(((plane_b_r > 16) ? (((plane_b_r - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255);
+ const uint8_t weighted_b_g = std::clamp(((plane_b_g > 16) ? (((plane_b_g - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255);
+ const uint8_t weighted_b_b = std::clamp(((plane_b_b > 16) ? (((plane_b_b - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255);
+ out[x] = (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b;
+ }
+ else
+ {
+ out[x] = backdrop;
+ }
}
- plane_a_r_cur = MCD212_LIM(((MCD212_LIM((int32_t)plane_a_r_cur - 16) * m_channel[0].weight_factor_a[x]) >> 6) + 16);
- plane_a_g_cur = MCD212_LIM(((MCD212_LIM((int32_t)plane_a_g_cur - 16) * m_channel[0].weight_factor_a[x]) >> 6) + 16);
- plane_a_b_cur = MCD212_LIM(((MCD212_LIM((int32_t)plane_a_b_cur - 16) * m_channel[0].weight_factor_a[x]) >> 6) + 16);
- plane_b_r_cur = MCD212_LIM(((MCD212_LIM((int32_t)plane_b_r_cur - 16) * m_channel[1].weight_factor_b[x]) >> 6) + 16);
- plane_b_g_cur = MCD212_LIM(((MCD212_LIM((int32_t)plane_b_g_cur - 16) * m_channel[1].weight_factor_b[x]) >> 6) + 16);
- plane_b_b_cur = MCD212_LIM(((MCD212_LIM((int32_t)plane_b_b_cur - 16) * m_channel[1].weight_factor_b[x]) >> 6) + 16);
- switch(m_channel[0].plane_order)
+ else
{
- case MCD212_POR_AB:
- if(plane_enable_a)
- {
- out[x] = (plane_a_r_cur << 16) | (plane_a_g_cur << 8) | plane_a_b_cur;
- }
- else if(plane_enable_b)
- {
- out[x] = (plane_b_r_cur << 16) | (plane_b_g_cur << 8) | plane_b_b_cur;
- }
- break;
- case MCD212_POR_BA:
- if(plane_enable_b)
- {
- out[x] = (plane_b_r_cur << 16) | (plane_b_g_cur << 8) | plane_b_b_cur;
- }
- else if(plane_enable_a)
- {
- out[x] = (plane_a_r_cur << 16) | (plane_a_g_cur << 8) | plane_a_b_cur;
- }
- break;
+ if (!(*transparent_b))
+ {
+ const uint32_t plane_b_cur = MosaicB ? plane_b[x - (x % mosaic_count_b)] : plane_b[x];
+ const uint8_t weight_b_cur = *weight_b;
+ const int32_t plane_b_r = (int32_t)(uint8_t)(plane_b_cur >> 16);
+ const int32_t plane_b_g = (int32_t)(uint8_t)(plane_b_cur >> 8);
+ const int32_t plane_b_b = (int32_t)(uint8_t)plane_b_cur;
+ const uint8_t weighted_b_r = std::clamp(((plane_b_r > 16) ? (((plane_b_r - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255);
+ const uint8_t weighted_b_g = std::clamp(((plane_b_g > 16) ? (((plane_b_g - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255);
+ const uint8_t weighted_b_b = std::clamp(((plane_b_b > 16) ? (((plane_b_b - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255);
+ out[x] = (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b;
+ }
+ else if (!(*transparent_a))
+ {
+ const uint32_t plane_a_cur = MosaicA ? plane_a[x - (x % mosaic_count_a)] : plane_a[x];
+ const uint8_t weight_a_cur = *weight_a;
+ const int32_t plane_a_r = (int32_t)(uint8_t)(plane_a_cur >> 16);
+ const int32_t plane_a_g = (int32_t)(uint8_t)(plane_a_cur >> 8);
+ const int32_t plane_a_b = (int32_t)(uint8_t)plane_a_cur;
+ const uint8_t weighted_a_r = std::clamp(((plane_a_r > 16) ? (((plane_a_r - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255);
+ const uint8_t weighted_a_g = std::clamp(((plane_a_g > 16) ? (((plane_a_g - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255);
+ const uint8_t weighted_a_b = std::clamp(((plane_a_b > 16) ? (((plane_a_b - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255);
+ out[x] = (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b;
+ }
+ else
+ {
+ out[x] = backdrop;
+ }
}
}
}
}
-void mcd212_device::draw_cursor(uint32_t *scanline, int y)
+void mcd212_device::draw_cursor(uint32_t *scanline)
{
- if(m_channel[0].cursor_control & MCD212_CURCNT_EN)
+ if (m_cursor_control & CURCNT_EN)
{
- uint16_t curx = m_channel[0].cursor_position & 0x3ff;
- uint16_t cury = ((m_channel[0].cursor_position >> 12) & 0x3ff) + 22;
- if(y >= cury && y < (cury + 16))
+ uint16_t y = (uint16_t)screen().vpos();
+ const uint16_t cursor_x = m_cursor_position & 0x3ff;
+ const uint16_t cursor_y = ((m_cursor_position >> 12) & 0x3ff) + m_ica_height;
+ if (y >= cursor_y && y < (cursor_y + 16))
{
- uint32_t color = s_4bpp_color[m_channel[0].cursor_control & MCD212_CURCNT_COLOR];
- y -= cury;
- if(m_channel[0].cursor_control & MCD212_CURCNT_CUW)
+ uint32_t color = s_4bpp_color[m_cursor_control & CURCNT_COLOR];
+ y -= cursor_y;
+ if (m_cursor_control & CURCNT_CUW)
{
- for(int x = curx; x < curx + 64 && x < 768; x++)
+ for (int x = cursor_x; x < cursor_x + 64 && x < 768; x++)
{
- if(m_channel[0].cursor_pattern[y] & (1 << (15 - ((x - curx) >> 2))))
+ if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 2))))
{
scanline[(x++)/2] = color;
scanline[(x++)/2] = color;
scanline[(x++)/2] = color;
scanline[(x/2)] = color;
}
- else
- {
- }
}
}
else
{
- for(int x = curx; x < curx + 32 && x < 768; x++)
+ for (int x = cursor_x; x < cursor_x + 32 && x < 768; x++)
{
- if(m_channel[0].cursor_pattern[y] & (1 << (15 - ((x - curx) >> 1))))
+ if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 1))))
{
scanline[(x++)/2] = color;
scanline[x/2] = color;
@@ -1210,200 +1082,275 @@ void mcd212_device::draw_cursor(uint32_t *scanline, int y)
}
}
-void mcd212_device::draw_scanline(int y)
+void mcd212_device::draw_scanline(bitmap_rgb32 &bitmap)
{
- uint8_t plane_a_r[768], plane_a_g[768], plane_a_b[768];
- uint8_t plane_b_r[768], plane_b_g[768], plane_b_b[768];
+ uint32_t plane_a[768];
+ uint32_t plane_b[768];
+ bool transparent_a[768];
+ bool transparent_b[768];
uint32_t out[768];
- process_vsr(0, plane_a_r, plane_a_g, plane_a_b);
- process_vsr(1, plane_b_r, plane_b_g, plane_b_b);
+ process_vsr<0>(plane_a, transparent_a);
+ process_vsr<1>(plane_b, transparent_b);
- mix_lines(plane_a_r, plane_a_g, plane_a_b, plane_b_r, plane_b_g, plane_b_b, out);
+ const uint8_t mosaic_enable_a = (m_mosaic_hold[0] & 0x800000) >> 23;
+ const uint8_t mosaic_enable_b = (m_mosaic_hold[1] & 0x800000) >> 22;
+ const uint8_t mixing_mode = (mosaic_enable_a | mosaic_enable_b) | (BIT(m_plane_order, 0) << 2);
+ switch (mixing_mode & 7)
+ {
+ case 0: // No Mosaic A/B, A->B->Backdrop plane ordering
+ mix_lines<false, false, true>(plane_a, transparent_a, plane_b, transparent_b, out);
+ break;
+ case 1: // Mosaic A, No Mosaic B, A->B->Backdrop plane ordering
+ mix_lines<true, false, true>(plane_a, transparent_a, plane_b, transparent_b, out);
+ break;
+ case 2: // No Mosaic A, Mosaic B, A->B->Backdrop plane ordering
+ mix_lines<false, true, true>(plane_a, transparent_a, plane_b, transparent_b, out);
+ break;
+ case 3: // Mosaic A/B, A->B->Backdrop plane ordering
+ mix_lines<true, true, true>(plane_a, transparent_a, plane_b, transparent_b, out);
+ break;
+ case 4: // No Mosaic A/B, B->A->Backdrop plane ordering
+ mix_lines<false, false, false>(plane_a, transparent_a, plane_b, transparent_b, out);
+ break;
+ case 5: // Mosaic A, No Mosaic B, B->A->Backdrop plane ordering
+ mix_lines<true, false, false>(plane_a, transparent_a, plane_b, transparent_b, out);
+ break;
+ case 6: // No Mosaic A, Mosaic B, B->A->Backdrop plane ordering
+ mix_lines<false, true, false>(plane_a, transparent_a, plane_b, transparent_b, out);
+ break;
+ case 7: // Mosaic A/B, B->A->Backdrop plane ordering
+ mix_lines<true, true, false>(plane_a, transparent_a, plane_b, transparent_b, out);
+ break;
+ }
- uint32_t *const scanline = &m_bitmap.pix(y);
- for(int x = 0; x < 384; x++)
+ uint32_t *const scanline = &bitmap.pix(screen().vpos());
+ for (int x = 0; x < 384; x++)
{
- scanline[x] = out[x*2];
+ scanline[x] = 0xff000000 | out[x*2];
}
- draw_cursor(scanline, y);
+ draw_cursor(scanline);
+}
+
+void mcd212_device::map(address_map &map)
+{
+ map(0x00, 0x01).w(FUNC(mcd212_device::csr2_w));
+ map(0x01, 0x01).r(FUNC(mcd212_device::csr2_r));
+ map(0x02, 0x03).rw(FUNC(mcd212_device::dcr2_r), FUNC(mcd212_device::dcr2_w));
+ map(0x04, 0x05).rw(FUNC(mcd212_device::vsr2_r), FUNC(mcd212_device::vsr2_w));
+ map(0x08, 0x09).rw(FUNC(mcd212_device::ddr2_r), FUNC(mcd212_device::ddr2_w));
+ map(0x0a, 0x0b).rw(FUNC(mcd212_device::dca2_r), FUNC(mcd212_device::dca2_w));
+
+ map(0x10, 0x11).w(FUNC(mcd212_device::csr1_w));
+ map(0x11, 0x11).r(FUNC(mcd212_device::csr1_r));
+ map(0x12, 0x13).rw(FUNC(mcd212_device::dcr1_r), FUNC(mcd212_device::dcr1_w));
+ map(0x14, 0x15).rw(FUNC(mcd212_device::vsr1_r), FUNC(mcd212_device::vsr1_w));
+ map(0x18, 0x19).rw(FUNC(mcd212_device::ddr1_r), FUNC(mcd212_device::ddr1_w));
+ map(0x1a, 0x1b).rw(FUNC(mcd212_device::dca1_r), FUNC(mcd212_device::dca1_w));
+}
+
+uint8_t mcd212_device::csr1_r()
+{
+ LOGMASKED(LOG_STATUS, "%s: Control/Status Register 1 Read: %02x\n", machine().describe_context(), m_csrr[0]);
+ return m_csrr[0];
+}
+
+void mcd212_device::csr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Control/Status Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_csrw[0]);
+ update_visible_area();
+}
+
+uint16_t mcd212_device::dcr1_r(offs_t offset, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Display Command Register 1 Read: %04x & %08x\n", machine().describe_context(), m_dcr[0], mem_mask);
+ return m_dcr[0];
+}
+
+void mcd212_device::dcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Display Command Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_dcr[0]);
+ update_visible_area();
+}
+
+uint16_t mcd212_device::vsr1_r(offs_t offset, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Video Start Register 1 Read: %04x & %08x\n", machine().describe_context(), m_vsr[0], mem_mask);
+ return m_vsr[0];
+}
+
+void mcd212_device::vsr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Video Start Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_vsr[0]);
+}
+
+uint16_t mcd212_device::ddr1_r(offs_t offset, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Display Decoder Register 1 Read: %04x & %08x\n", machine().describe_context(), m_ddr[0], mem_mask);
+ return m_ddr[0];
+}
+
+void mcd212_device::ddr1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Display Decoder Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ddr[0]);
}
-uint16_t mcd212_device::regs_r(offs_t offset, uint16_t mem_mask)
+uint16_t mcd212_device::dca1_r(offs_t offset, uint16_t mem_mask)
{
- uint8_t channel = 1 - (offset / 8);
+ LOGMASKED(LOG_STATUS, "%s: DCA Pointer 1 Read: %04x & %08x\n", machine().describe_context(), m_dca[0], mem_mask);
+ return m_dca[0];
+}
- switch(offset)
+void mcd212_device::dca1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: DCA Pointer 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_dca[0]);
+}
+
+uint8_t mcd212_device::csr2_r()
+{
+ if (machine().side_effects_disabled())
{
- case 0x00/2:
- case 0x10/2:
- if(ACCESSING_BITS_0_7)
- {
- verboselog(*this, 12, "mcd212_r: Status Register %d: %02x & %04x\n", channel + 1, m_channel[1 - (offset / 8)].csrr, mem_mask);
- if(channel == 0 || machine().side_effects_disabled())
- {
- return m_channel[channel].csrr;
- }
- else
- {
- uint8_t old_csr = m_channel[1].csrr;
- m_channel[1].csrr &= ~(MCD212_CSR2R_IT1 | MCD212_CSR2R_IT2);
- if (old_csr & (MCD212_CSR2R_IT1 | MCD212_CSR2R_IT2))
- m_int_callback(CLEAR_LINE);
- return old_csr;
- }
- }
- else
- {
- verboselog(*this, 2, "mcd212_r: Unknown Register %d: %04x\n", channel + 1, mem_mask);
- }
- break;
- case 0x02/2:
- case 0x12/2:
- verboselog(*this, 2, "mcd212_r: Display Command Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, m_channel[1 - (offset / 8)].dcr, mem_mask);
- return m_channel[1 - (offset / 8)].dcr;
- case 0x04/2:
- case 0x14/2:
- verboselog(*this, 2, "mcd212_r: Video Start Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, m_channel[1 - (offset / 8)].vsr, mem_mask);
- return m_channel[1 - (offset / 8)].vsr;
- case 0x08/2:
- case 0x18/2:
- verboselog(*this, 2, "mcd212_r: Display Decoder Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, m_channel[1 - (offset / 8)].ddr, mem_mask);
- return m_channel[1 - (offset / 8)].ddr;
- case 0x0a/2:
- case 0x1a/2:
- verboselog(*this, 2, "mcd212_r: DCA Pointer Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, m_channel[1 - (offset / 8)].dcp, mem_mask);
- return m_channel[1 - (offset / 8)].dcp;
- default:
- verboselog(*this, 2, "mcd212_r: Unknown Register %d & %04x\n", (1 - (offset / 8)) + 1, mem_mask);
- break;
+ return m_csrr[1];
}
- return 0;
+ const uint8_t data = m_csrr[1];
+ LOGMASKED(LOG_STATUS, "%s: Status Register 2: %02x\n", machine().describe_context(), data);
+
+ m_csrr[1] &= ~(CSR2R_IT1 | CSR2R_IT2);
+ if (data & (CSR2R_IT1 | CSR2R_IT2))
+ m_int_callback(CLEAR_LINE);
+
+ return data;
+}
+
+void mcd212_device::csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Control/Status Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_csrw[1]);
+}
+
+uint16_t mcd212_device::dcr2_r(offs_t offset, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Display Command Register 2 Read: %04x & %08x\n", machine().describe_context(), m_dcr[1], mem_mask);
+ return m_dcr[1];
+}
+
+void mcd212_device::dcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Display Command Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_dcr[1]);
}
-void mcd212_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+uint16_t mcd212_device::vsr2_r(offs_t offset, uint16_t mem_mask)
{
- switch(offset)
+ LOGMASKED(LOG_STATUS, "%s: Video Start Register 2 Read: %04x & %08x\n", machine().describe_context(), m_vsr[1], mem_mask);
+ return m_vsr[1];
+}
+
+void mcd212_device::vsr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Video Start Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_vsr[1]);
+}
+
+uint16_t mcd212_device::ddr2_r(offs_t offset, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Display Decoder Register 2 Read: %04x & %08x\n", machine().describe_context(), m_ddr[1], mem_mask);
+ return m_ddr[1];
+}
+
+void mcd212_device::ddr2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: Display Decoder Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_ddr[1]);
+}
+
+uint16_t mcd212_device::dca2_r(offs_t offset, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: DCA Pointer 2 Read: %04x & %08x\n", machine().describe_context(), m_dca[1], mem_mask);
+ return m_dca[1];
+}
+
+void mcd212_device::dca2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
+{
+ LOGMASKED(LOG_STATUS, "%s: DCA Pointer 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask);
+ COMBINE_DATA(&m_dca[1]);
+}
+
+WRITE_LINE_MEMBER(mcd212_device::screen_vblank)
+{
+ if (state)
{
- case 0x00/2:
- case 0x10/2:
- verboselog(*this, 2, "mcd212_w: Status Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask);
- COMBINE_DATA(&m_channel[1 - (offset / 8)].csrw);
- update_visible_area();
- break;
- case 0x02/2:
- case 0x12/2:
- verboselog(*this, 2, "mcd212_w: Display Command Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask);
- COMBINE_DATA(&m_channel[1 - (offset / 8)].dcr);
- update_visible_area();
- break;
- case 0x04/2:
- case 0x14/2:
- verboselog(*this, 2, "mcd212_w: Video Start Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask);
- COMBINE_DATA(&m_channel[1 - (offset / 8)].vsr);
- break;
- case 0x08/2:
- case 0x18/2:
- verboselog(*this, 2, "mcd212_w: Display Decoder Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask);
- COMBINE_DATA(&m_channel[1 - (offset / 8)].ddr);
- break;
- case 0x0a/2:
- case 0x1a/2:
- verboselog(*this, 2, "mcd212_w: DCA Pointer Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask);
- COMBINE_DATA(&m_channel[1 - (offset / 8)].dcp);
- break;
- default:
- verboselog(*this, 2, "mcd212_w: Unknown Register %d: %04x & %04x\n", (1 - (offset / 8)) + 1, data, mem_mask);
- break;
+ // Process ICA
+ m_csrr[0] &= 0x7f;
+ if (m_dcr[0] & DCR_ICA)
+ process_ica<0>();
+ if (m_dcr[1] & DCR_ICA)
+ process_ica<1>();
}
}
-TIMER_CALLBACK_MEMBER( mcd212_device::perform_scan )
+uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
- int scanline = screen().vpos();
+ int scanline = screen.vpos();
- if(1)
+ if (scanline >= m_ica_height)
{
- if(scanline == 0)
- {
- // Process ICA
- verboselog(*this, 6, "%s", "Frame Start\n" );
- m_channel[0].csrr &= 0x7f;
- for(int index = 0; index < 2; index++)
- {
- if(m_channel[index].dcr & MCD212_DCR_ICA)
- {
- process_ica(index);
- }
- }
- }
- else if(scanline >= 22)
- {
- m_channel[0].csrr |= 0x80;
- // Process VSR
- draw_scanline(scanline);
- // Process DCA
- for(int index = 0; index < 2; index++)
- {
- if(m_channel[index].dcr & MCD212_DCR_DCA)
- {
- if(scanline == 22)
- {
- m_channel[index].dca = get_dcp(index);
- }
- process_dca(index);
- }
- }
- if(scanline == 301)
- {
- m_channel[0].csrr ^= 0x20;
- }
- }
+ m_csrr[0] |= 0x80;
+
+ // Process DCA
+ if (m_dcr[0] & DCR_DCA)
+ process_dca<0>();
+ if (m_dcr[1] & DCR_DCA)
+ process_dca<1>();
+
+ // Process VSR
+ draw_scanline(bitmap);
+ }
- if (!m_scanline_callback.isnull())
- m_scanline_callback(scanline);
+ if (scanline == (m_total_height - 1))
+ {
+ m_csrr[0] ^= 0x20;
}
- m_scan_timer->adjust(screen().time_until_pos(( scanline + 1 ) % 302, 0));
+
+ return 0;
}
void mcd212_device::device_reset()
{
- for(auto & elem : m_channel)
- {
- elem.csrr = 0;
- elem.csrw = 0;
- elem.dcr = 0;
- elem.vsr = 0;
- elem.ddr = 0;
- elem.dcp = 0;
- elem.dca = 0;
- memset(elem.clut_r, 0, 256);
- memset(elem.clut_g, 0, 256);
- memset(elem.clut_b, 0, 256);
- elem.image_coding_method = 0;
- elem.transparency_control = 0;
- elem.plane_order = 0;
- elem.clut_bank = 0;
- elem.transparent_color_a = 0;
- elem.transparent_color_b = 0;
- elem.mask_color_a = 0;
- elem.mask_color_b = 0;
- elem.dyuv_abs_start_a = 0;
- elem.dyuv_abs_start_b = 0;
- elem.cursor_position = 0;
- elem.cursor_control = 0;
- memset((uint8_t*)&elem.cursor_pattern, 0, 16 * sizeof(uint32_t));
- memset((uint8_t*)&elem.region_control, 0, 8 * sizeof(uint32_t));
- elem.backdrop_color = 0;
- elem.mosaic_hold_a = 0;
- elem.mosaic_hold_b = 0;
- memset(elem.weight_factor_a, 0, 768);
- memset(elem.weight_factor_b, 0, 768);
- }
- memset(m_region_flag_0, 0, 768);
- memset(m_region_flag_1, 0, 768);
+ std::fill_n(m_csrr, 2, 0);
+ std::fill_n(m_csrw, 2, 0);
+ std::fill_n(m_dcr, 2, 0);
+ std::fill_n(m_vsr, 2, 0);
+ std::fill_n(m_ddr, 2, 0);
+ std::fill_n(m_dcp, 2, 0);
+ std::fill_n(m_dca, 2, 0);
+ std::fill_n(m_clut, 256, 0);
+ m_image_coding_method = 0;
+ m_transparency_control = 0;
+ m_plane_order = 0;
+ std::fill_n(m_clut_bank, 2, 0);
+ std::fill_n(m_transparent_color, 2, 0);
+ std::fill_n(m_mask_color, 2, 0);
+ std::fill_n(m_dyuv_abs_start, 2, 0);
+ m_cursor_position = 0;
+ m_cursor_control = 0;
+ std::fill_n(m_cursor_pattern, std::size(m_cursor_pattern), 0);
+ std::fill_n(m_region_control, 8, 0);
+ m_backdrop_color = 0;
+ std::fill_n(m_mosaic_hold, 2, 0);
+ std::fill_n(m_weight_factor[0], std::size(m_weight_factor[0]), 0);
+ std::fill_n(m_weight_factor[1], std::size(m_weight_factor[1]), 0);
+ std::fill_n(m_region_flag[0], std::size(m_region_flag[0]), false);
+ std::fill_n(m_region_flag[1], std::size(m_region_flag[1]), false);
+ m_ica_height = 32;
+ m_total_height = 312;
m_int_callback(CLEAR_LINE);
}
@@ -1416,7 +1363,6 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev
: device_t(mconfig, MCD212, tag, owner, clock)
, device_video_interface(mconfig, *this)
, m_int_callback(*this)
- , m_scanline_callback(*this)
, m_planea(*this, "planea")
, m_planeb(*this, "planeb")
{
@@ -1431,7 +1377,6 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev
void mcd212_device::device_resolve_objects()
{
m_int_callback.resolve_safe();
- m_scanline_callback.resolve();
}
//-------------------------------------------------
@@ -1440,110 +1385,55 @@ void mcd212_device::device_resolve_objects()
void mcd212_device::device_start()
{
- ab_init();
-
- screen().register_screen_bitmap(m_bitmap);
-
- m_scan_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::perform_scan), this));
- m_scan_timer->adjust(screen().time_until_pos(0, 0));
-
- save_item(NAME(m_region_flag_0));
- save_item(NAME(m_region_flag_1));
- save_item(NAME(m_channel[0].csrr));
- save_item(NAME(m_channel[0].csrw));
- save_item(NAME(m_channel[0].dcr));
- save_item(NAME(m_channel[0].vsr));
- save_item(NAME(m_channel[0].ddr));
- save_item(NAME(m_channel[0].dcp));
- save_item(NAME(m_channel[0].dca));
- save_item(NAME(m_channel[0].clut_r));
- save_item(NAME(m_channel[0].clut_g));
- save_item(NAME(m_channel[0].clut_b));
- save_item(NAME(m_channel[0].image_coding_method));
- save_item(NAME(m_channel[0].transparency_control));
- save_item(NAME(m_channel[0].plane_order));
- save_item(NAME(m_channel[0].clut_bank));
- save_item(NAME(m_channel[0].transparent_color_a));
- save_item(NAME(m_channel[0].transparent_color_b));
- save_item(NAME(m_channel[0].mask_color_a));
- save_item(NAME(m_channel[0].mask_color_b));
- save_item(NAME(m_channel[0].dyuv_abs_start_a));
- save_item(NAME(m_channel[0].dyuv_abs_start_b));
- save_item(NAME(m_channel[0].cursor_position));
- save_item(NAME(m_channel[0].cursor_control));
- save_item(NAME(m_channel[0].cursor_pattern));
- save_item(NAME(m_channel[0].region_control));
- save_item(NAME(m_channel[0].backdrop_color));
- save_item(NAME(m_channel[0].mosaic_hold_a));
- save_item(NAME(m_channel[0].mosaic_hold_b));
- save_item(NAME(m_channel[0].weight_factor_a));
- save_item(NAME(m_channel[0].weight_factor_b));
- save_item(NAME(m_channel[1].csrr));
- save_item(NAME(m_channel[1].csrw));
- save_item(NAME(m_channel[1].dcr));
- save_item(NAME(m_channel[1].vsr));
- save_item(NAME(m_channel[1].ddr));
- save_item(NAME(m_channel[1].dcp));
- save_item(NAME(m_channel[1].dca));
- save_item(NAME(m_channel[1].clut_r));
- save_item(NAME(m_channel[1].clut_g));
- save_item(NAME(m_channel[1].clut_b));
- save_item(NAME(m_channel[1].image_coding_method));
- save_item(NAME(m_channel[1].transparency_control));
- save_item(NAME(m_channel[1].plane_order));
- save_item(NAME(m_channel[1].clut_bank));
- save_item(NAME(m_channel[1].transparent_color_a));
- save_item(NAME(m_channel[1].transparent_color_b));
- save_item(NAME(m_channel[1].mask_color_a));
- save_item(NAME(m_channel[1].mask_color_b));
- save_item(NAME(m_channel[1].dyuv_abs_start_a));
- save_item(NAME(m_channel[1].dyuv_abs_start_b));
- save_item(NAME(m_channel[1].cursor_position));
- save_item(NAME(m_channel[1].cursor_control));
- save_item(NAME(m_channel[1].cursor_pattern));
- save_item(NAME(m_channel[1].region_control));
- save_item(NAME(m_channel[1].backdrop_color));
- save_item(NAME(m_channel[1].mosaic_hold_a));
- save_item(NAME(m_channel[1].mosaic_hold_b));
- save_item(NAME(m_channel[1].weight_factor_a));
- save_item(NAME(m_channel[1].weight_factor_b));
-}
-
-void mcd212_device::ab_init()
-{
- // Delta decoding array.
- static const BYTE68K abDelta[16] = { 0, 1, 4, 9, 16, 27, 44, 79, 128, 177, 212, 229, 240, 247, 252, 255 };
-
- // Initialize delta decoding arrays for each unsigned byte value b.
- for (WORD68K d = 0; d < BYTE68K_MAX + 1; d++)
- {
- m_ab.deltaY[d] = abDelta[d & 15];
- }
+ static const uint8_t s_dyuv_deltas[16] = { 0, 1, 4, 9, 16, 27, 44, 79, 128, 177, 212, 229, 240, 247, 252, 255 };
- // Initialize delta decoding arrays for each unsigned byte value b.
- for (WORD68K d = 0; d < (BYTE68K_MAX + 1); d++)
+ for (uint16_t d = 0; d < 0x100; d++)
{
- m_ab.deltaUV[d] = abDelta[d >> 4];
+ m_delta_y_lut[d] = s_dyuv_deltas[d & 15];
+ m_delta_uv_lut[d] = s_dyuv_deltas[d >> 4];
}
- // Initialize color limit and clamp arrays.
- for (WORD68K w = 0; w < 3 * BYTE68K_MAX; w++)
+ for (uint16_t w = 0; w < 3 * 0xff; w++)
{
- m_ab.limit[w] = (w < BYTE68K_MAX + 16) ? 0 : w <= 16 + 2 * BYTE68K_MAX ? w - BYTE68K_MAX - 16 : BYTE68K_MAX;
- m_ab.clamp[w] = (w < BYTE68K_MAX + 32) ? 16 : w <= 16 + 2 * BYTE68K_MAX ? w - BYTE68K_MAX - 16 : BYTE68K_MAX;
+ const uint8_t limit = (w < 0xff + 16) ? 0 : w <= 16 + 2 * 0xff ? w - 0x10f : 0xff;
+ m_dyuv_limit_r_lut[w] = limit << 16;
+ m_dyuv_limit_g_lut[w] = limit << 8;
+ m_dyuv_limit_b_lut[w] = limit;
}
- for (SWORD68K sw = 0; sw < 0x100; sw++)
+ for (int16_t sw = 0; sw < 0x100; sw++)
{
- m_ab.matrixUB[sw] = (444 * (sw - 128)) / 256;
- m_ab.matrixUG[sw] = - (86 * (sw - 128)) / 256;
- m_ab.matrixVG[sw] = - (179 * (sw - 128)) / 256;
- m_ab.matrixVR[sw] = (351 * (sw - 128)) / 256;
+ m_dyuv_u_to_b[sw] = (444 * (sw - 128)) / 256;
+ m_dyuv_u_to_g[sw] = - (86 * (sw - 128)) / 256;
+ m_dyuv_v_to_g[sw] = - (179 * (sw - 128)) / 256;
+ m_dyuv_v_to_r[sw] = (351 * (sw - 128)) / 256;
}
-}
-uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
-{
- copybitmap(bitmap, m_bitmap, 0, 0, 0, 0, cliprect);
- return 0;
+ save_item(NAME(m_region_flag[0]));
+ save_item(NAME(m_region_flag[1]));
+ save_item(NAME(m_ica_height));
+ save_item(NAME(m_total_height));
+ save_item(NAME(m_csrr));
+ save_item(NAME(m_csrw));
+ save_item(NAME(m_dcr));
+ save_item(NAME(m_vsr));
+ save_item(NAME(m_ddr));
+ save_item(NAME(m_dcp));
+ save_item(NAME(m_dca));
+ save_item(NAME(m_clut));
+ save_item(NAME(m_image_coding_method));
+ save_item(NAME(m_transparency_control));
+ save_item(NAME(m_plane_order));
+ save_item(NAME(m_clut_bank));
+ save_item(NAME(m_transparent_color));
+ save_item(NAME(m_mask_color));
+ save_item(NAME(m_dyuv_abs_start));
+ save_item(NAME(m_cursor_position));
+ save_item(NAME(m_cursor_control));
+ save_item(NAME(m_cursor_pattern));
+ save_item(NAME(m_region_control));
+ save_item(NAME(m_backdrop_color));
+ save_item(NAME(m_mosaic_hold));
+ save_item(NAME(m_weight_factor[0]));
+ save_item(NAME(m_weight_factor[1]));
}
diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h
index 1701c36cd94..3b9a379c9ba 100644
--- a/src/mame/video/mcd212.h
+++ b/src/mame/video/mcd212.h
@@ -27,178 +27,22 @@ TODO:
#pragma once
-#define MCD212_CURCNT_COLOR 0x00000f // Cursor color
-#define MCD212_CURCNT_CUW 0x008000 // Cursor width
-#define MCD212_CURCNT_COF 0x070000 // Cursor off time
-#define MCD212_CURCNT_COF_SHIFT 16
-#define MCD212_CURCNT_CON 0x280000 // Cursor on time
-#define MCD212_CURCNT_CON_SHIFT 19
-#define MCD212_CURCNT_BLKC 0x400000 // Blink type
-#define MCD212_CURCNT_EN 0x800000 // Cursor enable
-
-#define MCD212_ICM_CS 0x400000 // CLUT select
-#define MCD212_ICM_NR 0x080000 // Number of region flags
-#define MCD212_ICM_EV 0x040000 // External video
-#define MCD212_ICM_MODE2 0x000f00 // Plane 2
-#define MCD212_ICM_MODE2_SHIFT 8
-#define MCD212_ICM_MODE1 0x00000f // Plane 1
-#define MCD212_ICM_MODE1_SHIFT 0
-
-#define MCD212_TCR_DISABLE_MX 0x800000 // Mix disable
-#define MCD212_TCR_TB 0x000f00 // Plane B
-#define MCD212_TCR_TB_SHIFT 8
-#define MCD212_TCR_TA 0x00000f // Plane A
-#define MCD212_TCR_COND_1 0x0 // Transparent if: Always (Plane Disabled)
-#define MCD212_TCR_COND_KEY_1 0x1 // Transparent if: Color Key = True
-#define MCD212_TCR_COND_XLU_1 0x2 // Transparent if: Transparency Bit = 1
-#define MCD212_TCR_COND_RF0_1 0x3 // Transparent if: Region Flag 0 = True
-#define MCD212_TCR_COND_RF1_1 0x4 // Transparent if: Region Flag 1 = True
-#define MCD212_TCR_COND_RF0KEY_1 0x5 // Transparent if: Region Flag 0 = True || Color Key = True
-#define MCD212_TCR_COND_RF1KEY_1 0x6 // Transparent if: Region Flag 1 = True || Color Key = True
-#define MCD212_TCR_COND_UNUSED0 0x7 // Unused
-#define MCD212_TCR_COND_0 0x8 // Transparent if: Never (No Transparent Area)
-#define MCD212_TCR_COND_KEY_0 0x9 // Transparent if: Color Key = False
-#define MCD212_TCR_COND_XLU_0 0xa // Transparent if: Transparency Bit = 0
-#define MCD212_TCR_COND_RF0_0 0xb // Transparent if: Region Flag 0 = False
-#define MCD212_TCR_COND_RF1_0 0xc // Transparent if: Region Flag 1 = False
-#define MCD212_TCR_COND_RF0KEY_0 0xd // Transparent if: Region Flag 0 = False && Color Key = False
-#define MCD212_TCR_COND_RF1KEY_0 0xe // Transparent if: Region Flag 1 = False && Color Key = False
-#define MCD212_TCR_COND_UNUSED1 0xf // Unused
-
-#define MCD212_POR_AB 0 // Plane A in front of Plane B
-#define MCD212_POR_BA 1 // Plane B in front of Plane A
-
-#define MCD212_RC_X 0x0003ff // X position
-#define MCD212_RC_WF 0x00fc00 // Weight position
-#define MCD212_RC_WF_SHIFT 10
-#define MCD212_RC_RF 0x010000 // Region flag
-#define MCD212_RC_RF_SHIFT 16
-#define MCD212_RC_OP 0xf00000 // Operation
-#define MCD212_RC_OP_SHIFT 20
-
-#define MCD212_CSR1W_ST 0x0002 // Standard
-#define MCD212_CSR1W_BE 0x0001 // Bus Error
-
-#define MCD212_CSR2R_IT1 0x0004 // Interrupt 1
-#define MCD212_CSR2R_IT2 0x0002 // Interrupt 2
-#define MCD212_CSR2R_BE 0x0001 // Bus Error
-
-#define MCD212_DCR_DE 0x8000 // Display Enable
-#define MCD212_DCR_CF 0x4000 // Crystal Frequency
-#define MCD212_DCR_FD 0x2000 // Frame Duration
-#define MCD212_DCR_SM 0x1000 // Scan Mode
-#define MCD212_DCR_CM 0x0800 // Color Mode Ch.1/2
-#define MCD212_DCR_ICA 0x0200 // ICA Enable Ch.1/2
-#define MCD212_DCR_DCA 0x0100 // DCA Enable Ch.1/2
-
-#define MCD212_DDR_FT 0x0300 // Display File Type
-#define MCD212_DDR_FT_BMP 0x0000 // Bitmap
-#define MCD212_DDR_FT_BMP2 0x0100 // Bitmap (alt.)
-#define MCD212_DDR_FT_RLE 0x0200 // Run-Length Encoded
-#define MCD212_DDR_FT_MOSAIC 0x0300 // Mosaic
-#define MCD212_DDR_MT 0x0c00 // Mosaic File Type
-#define MCD212_DDR_MT_2 0x0000 // 2x1
-#define MCD212_DDR_MT_4 0x0400 // 4x1
-#define MCD212_DDR_MT_8 0x0800 // 8x1
-#define MCD212_DDR_MT_16 0x0c00 // 16x1
-#define MCD212_DDR_MT_SHIFT 10
-
-typedef uint8_t BYTE68K;
-typedef uint16_t WORD68K;
-typedef int16_t SWORD68K;
-
-#define BYTE68K_MAX 255
-
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-// ======================> mcd212_device
-
class mcd212_device : public device_t,
- public device_video_interface
+ public device_video_interface
{
public:
- typedef device_delegate<void (int)> scanline_callback_delegate;
-
- // construction/destruction
mcd212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto int_callback() { return m_int_callback.bind(); }
- template <typename... T> void set_scanline_callback(T &&... args) { m_scanline_callback.set(std::forward<T>(args)...); }
-
- // device members
- uint16_t regs_r(offs_t offset, uint16_t mem_mask = ~0);
- void regs_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
- TIMER_CALLBACK_MEMBER( perform_scan );
-
- bitmap_rgb32& get_bitmap() { return m_bitmap; }
-
+ DECLARE_WRITE_LINE_MEMBER(screen_vblank);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
- struct channel_t
- {
- uint8_t csrr;
- uint16_t csrw;
- uint16_t dcr;
- uint16_t vsr;
- uint16_t ddr;
- uint16_t dcp;
- uint32_t dca;
- uint8_t clut_r[256];
- uint8_t clut_g[256];
- uint8_t clut_b[256];
- uint32_t image_coding_method;
- uint32_t transparency_control;
- uint32_t plane_order;
- uint32_t clut_bank;
- uint32_t transparent_color_a;
- uint32_t reserved0;
- uint32_t transparent_color_b;
- uint32_t mask_color_a;
- uint32_t reserved1;
- uint32_t mask_color_b;
- uint32_t dyuv_abs_start_a;
- uint32_t dyuv_abs_start_b;
- uint32_t reserved2;
- uint32_t cursor_position;
- uint32_t cursor_control;
- uint32_t cursor_pattern[16];
- uint32_t region_control[8];
- uint32_t backdrop_color;
- uint32_t mosaic_hold_a;
- uint32_t mosaic_hold_b;
- uint8_t weight_factor_a[768];
- uint8_t weight_factor_b[768];
- };
-
- struct ab_t
- {
- //* Color limit array.
- BYTE68K limit[3 * BYTE68K_MAX];
-
- //* Color clamp array.
- BYTE68K clamp[3 * BYTE68K_MAX];
-
- //* U-to-B matrix array.
- SWORD68K matrixUB[BYTE68K_MAX + 1];
-
- //* U-to-G matrix array.
- SWORD68K matrixUG[BYTE68K_MAX + 1];
-
- //* V-to-G matrix array.
- SWORD68K matrixVG[BYTE68K_MAX + 1];
-
- //* V-to-R matrix array.
- SWORD68K matrixVR[BYTE68K_MAX + 1];
-
- //* Delta-Y decoding array.
- BYTE68K deltaY[BYTE68K_MAX + 1];
-
- //* Delta-U/V decoding array.
- BYTE68K deltaUV[BYTE68K_MAX + 1];
- };
+ void map(address_map &map);
protected:
// device-level overrides
@@ -206,51 +50,196 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
-private:
+ uint8_t csr1_r();
+ void csr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t dcr1_r(offs_t offset, uint16_t mem_mask = ~0);
+ void dcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t vsr1_r(offs_t offset, uint16_t mem_mask = ~0);
+ void vsr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t ddr1_r(offs_t offset, uint16_t mem_mask = ~0);
+ void ddr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t dca1_r(offs_t offset, uint16_t mem_mask = ~0);
+ void dca1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+
+ uint8_t csr2_r();
+ void csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t dcr2_r(offs_t offset, uint16_t mem_mask = ~0);
+ void dcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t vsr2_r(offs_t offset, uint16_t mem_mask = ~0);
+ void vsr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t ddr2_r(offs_t offset, uint16_t mem_mask = ~0);
+ void ddr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+ uint16_t dca2_r(offs_t offset, uint16_t mem_mask = ~0);
+ void dca2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
+
+ enum : uint32_t
+ {
+ CURCNT_COLOR = 0x00000f, // Cursor color
+ CURCNT_CUW = 0x008000, // Cursor width
+ CURCNT_COF = 0x070000, // Cursor off time
+ CURCNT_COF_SHIFT = 16,
+ CURCNT_CON = 0x280000, // Cursor on time
+ CURCNT_CON_SHIFT = 19,
+ CURCNT_BLKC = 0x400000, // Blink type
+ CURCNT_EN = 0x800000, // Cursor enable
+
+ ICM_CS = 0x400000, // CLUT select
+ ICM_NR = 0x080000, // Number of region flags
+ ICM_NR_BIT = 19,
+ ICM_EV = 0x040000, // External video
+ ICM_MODE2 = 0x000f00, // Plane 2
+ ICM_MODE2_SHIFT = 8,
+ ICM_MODE1 = 0x00000f, // Plane 1
+ ICM_MODE1_SHIFT = 0,
+
+ TCR_DISABLE_MX = 0x800000, // Mix disable
+ TCR_TB = 0x000f00, // Plane B
+ TCR_TB_SHIFT = 8,
+ TCR_TA = 0x00000f, // Plane A
+ TCR_COND_1 = 0x0, // Transparent if: Always (Plane Disabled)
+ TCR_COND_KEY_1 = 0x1, // Transparent if: Color Key = True
+ TCR_COND_XLU_1 = 0x2, // Transparent if: Transparency Bit = 1
+ TCR_COND_RF0_1 = 0x3, // Transparent if: Region Flag 0 = True
+ TCR_COND_RF1_1 = 0x4, // Transparent if: Region Flag 1 = True
+ TCR_COND_RF0KEY_1 = 0x5, // Transparent if: Region Flag 0 = True || Color Key = True
+ TCR_COND_RF1KEY_1 = 0x6, // Transparent if: Region Flag 1 = True || Color Key = True
+ TCR_COND_UNUSED0 = 0x7, // Unused
+ TCR_COND_0 = 0x8, // Transparent if: Never (No Transparent Area)
+ TCR_COND_KEY_0 = 0x9, // Transparent if: Color Key = False
+ TCR_COND_XLU_0 = 0xa, // Transparent if: Transparency Bit = 0
+ TCR_COND_RF0_0 = 0xb, // Transparent if: Region Flag 0 = False
+ TCR_COND_RF1_0 = 0xc, // Transparent if: Region Flag 1 = False
+ TCR_COND_RF0KEY_0 = 0xd, // Transparent if: Region Flag 0 = False && Color Key = False
+ TCR_COND_RF1KEY_0 = 0xe, // Transparent if: Region Flag 1 = False && Color Key = False
+ TCR_COND_UNUSED1 = 0xf, // Unused
+
+ POR_AB = 0, // Plane A in front of Plane B
+ POR_BA = 1, // Plane B in front of Plane A
+
+ RC_X = 0x0003ff, // X position
+ RC_WF = 0x00fc00, // Weight position
+ RC_WF_SHIFT = 10,
+ RC_RF_BIT = 16, // Region flag bit
+ RC_OP = 0xf00000, // Operation
+ RC_OP_SHIFT = 20,
+
+ CSR1W_ST = 0x0002, // Standard
+ CSR1W_BE = 0x0001, // Bus Error
+
+ CSR2R_IT1 = 0x0004, // Interrupt 1
+ CSR2R_IT2 = 0x0002, // Interrupt 2
+ CSR2R_BE = 0x0001, // Bus Error
+
+ DCR_DE = 0x8000, // Display Enable
+ DCR_CF = 0x4000, // Crystal Frequency
+ DCR_FD = 0x2000, // Frame Duration
+ DCR_SM = 0x1000, // Scan Mode
+ DCR_CM = 0x0800, // Color Mode Ch.1/2
+ DCR_ICA = 0x0200, // ICA Enable Ch.1/2
+ DCR_DCA = 0x0100, // DCA Enable Ch.1/2
+
+ DDR_FT = 0x0300, // Display File Type
+ DDR_FT_BMP = 0x0000, // Bitmap
+ DDR_FT_BMP2 = 0x0100, // Bitmap (alt.)
+ DDR_FT_RLE = 0x0200, // Run-Length Encoded
+ DDR_FT_MOSAIC = 0x0300, // Mosaic
+ DDR_MT = 0x0c00, // Mosaic File Type
+ DDR_MT_2 = 0x0000, // 2x1
+ DDR_MT_4 = 0x0400, // 4x1
+ DDR_MT_8 = 0x0800, // 8x1
+ DDR_MT_16 = 0x0c00, // 16x1
+ DDR_MT_SHIFT = 10
+ };
+
+ uint8_t m_csrr[2];
+ uint16_t m_csrw[2];
+ uint16_t m_dcr[2];
+ uint16_t m_vsr[2];
+ uint16_t m_ddr[2];
+ uint16_t m_dcp[2];
+ uint32_t m_dca[2];
+ uint32_t m_clut[256];
+ uint32_t m_image_coding_method;
+ uint32_t m_transparency_control;
+ uint32_t m_plane_order;
+ uint32_t m_clut_bank[2];
+ uint32_t m_transparent_color[2];
+ uint32_t m_mask_color[2];
+ uint32_t m_dyuv_abs_start[2];
+ uint32_t m_cursor_position;
+ uint32_t m_cursor_control;
+ uint32_t m_cursor_pattern[16];
+ uint32_t m_region_control[8];
+ uint32_t m_backdrop_color;
+ uint32_t m_mosaic_hold[2];
+ uint8_t m_weight_factor[2][768];
+
+ // DYUV color limit arrays.
+ uint32_t m_dyuv_limit_r_lut[3 * 0xff];
+ uint32_t m_dyuv_limit_g_lut[3 * 0xff];
+ uint32_t m_dyuv_limit_b_lut[3 * 0xff];
+
+ // DYUV delta-Y decoding array
+ uint8_t m_delta_y_lut[0x100];
+
+ // DYUV delta-UV decoding array
+ uint8_t m_delta_uv_lut[0x100];
+
+ // DYUV U-to-B decoding array
+ int16_t m_dyuv_u_to_b[0x100];
+
+ // U-to-G decoding array
+ int16_t m_dyuv_u_to_g[0x100];
+
+ // V-to-G decoding array
+ int16_t m_dyuv_v_to_g[0x100];
+
+ // V-to-R decoding array
+ int16_t m_dyuv_v_to_r[0x100];
+
// interrupt callbacks
devcb_write_line m_int_callback;
- scanline_callback_delegate m_scanline_callback;
-
required_shared_ptr<uint16_t> m_planea;
required_shared_ptr<uint16_t> m_planeb;
// internal state
- channel_t m_channel[2];
- emu_timer *m_scan_timer;
- uint8_t m_region_flag_0[768];
- uint8_t m_region_flag_1[768];
-
- bitmap_rgb32 m_bitmap;
+ bool m_region_flag[2][768];
+ int m_ica_height;
+ int m_total_height;
static const uint32_t s_4bpp_color[16];
- ab_t m_ab;
-
+ uint8_t get_weight_factor(const uint32_t region_idx);
+ uint8_t get_region_op(const uint32_t region_idx);
void update_region_arrays();
- void set_vsr(int channel, uint32_t value);
- uint32_t get_vsr(int channel);
-
- void set_dcp(int channel, uint32_t value);
- uint32_t get_dcp(int channel);
-
- void set_display_parameters(int channel, uint8_t value);
void update_visible_area();
uint32_t get_screen_width();
- void process_ica(int channel);
- void process_dca(int channel);
- void process_vsr(int channel, uint8_t *pixels_r, uint8_t *pixels_g, uint8_t *pixels_b);
+ template <int Channel> void set_vsr(uint32_t value);
+ template <int Channel> uint32_t get_vsr();
+
+ template <int Channel> void set_dcp(uint32_t value);
+ template <int Channel> uint32_t get_dcp();
+
+ template <int Channel> void set_display_parameters(uint8_t value);
+
+ template <int Channel> void process_ica();
+ template <int Channel> void process_dca();
- void set_register(int channel, uint8_t reg, uint32_t value);
+ template <int Channel> uint8_t get_transparency_control();
+ template <int Channel> uint8_t get_icm();
+ template <int Channel> bool get_mosaic_enable();
+ template <int Channel> uint8_t get_mosaic_factor();
+ template <int Channel> void process_vsr(uint32_t *pixels, bool *transparent);
- void mix_lines(uint8_t *plane_a_r, uint8_t *plane_a_g, uint8_t *plane_a_b, uint8_t *plane_b_r, uint8_t *plane_b_g, uint8_t *plane_b_b, uint32_t *out);
+ template <int Channel> void set_register(uint8_t reg, uint32_t value);
- void draw_cursor(uint32_t *scanline, int y);
- void draw_scanline(int y);
+ template <bool MosaicA, bool MosaicB, bool OrderAB> void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out);
- void ab_init();
+ void draw_cursor(uint32_t *scanline);
+ void draw_scanline(bitmap_rgb32 &bitmap);
};
// device type definition