From a3cc6df3495d4fd390c51170acaeaafe267ad964 Mon Sep 17 00:00:00 2001 From: MooglyGuy Date: Fri, 7 Jan 2022 16:32:21 +0100 Subject: -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. --- hash/cdi.xml | 2 +- src/lib/util/cdrom.cpp | 5 + src/mame/drivers/cdi.cpp | 151 +--- src/mame/includes/cdi.h | 11 +- src/mame/machine/cdicdic.cpp | 378 ++++++++- src/mame/machine/cdicdic.h | 9 +- src/mame/video/mcd212.cpp | 1824 ++++++++++++++++++++---------------------- src/mame/video/mcd212.h | 359 ++++----- 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 The Vision Factory - + 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 m_maincpu; + optional_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 m_servo; optional_device m_slave; optional_device m_cdic; - required_device m_cdda; required_device m_mcd212; - optional_device m_lcd; required_device_array 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 m_dmadac; required_device m_scc; - required_device m_cdda; optional_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 +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 +inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr() +{ + return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel]; +} + +template +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 +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 +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 +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 +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(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(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(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(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(cmd >> 24, cmd & 0x00ffffff); break; } - if(stop) - { - break; - } } } -void mcd212_device::process_dca(int channel) +template +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(); + } + + 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(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(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(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(cmd & 0x1f); break; default: - set_register(channel, cmd >> 24, cmd & 0x00ffffff); + set_register(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 +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 +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control() { - uint8_t *data = reinterpret_cast(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 +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 +inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable() +{ + return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC; +} + +template +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() +{ + return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); +} + +template +void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) +{ + const uint8_t *data = reinterpret_cast(Channel ? m_planeb.target() : m_planea.target()); + const uint8_t icm = get_icm(); + const uint32_t width = get_screen_width(); + const uint8_t transp_ctrl = get_transparency_control(); - //printf( "vsr before: %08x: ", vsr ); - //fflush(stdout); + uint32_t vsr = get_vsr(); - 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(); + const uint8_t mosaic_factor = get_mosaic_factor(); + + 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(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(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(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(icm, byte >> 4)]; + const uint32_t odd_entry = m_clut[BYTE_TO_CLUT(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(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(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(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(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(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(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 +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(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 1: // Mosaic A, No Mosaic B, A->B->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 2: // No Mosaic A, Mosaic B, A->B->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 3: // Mosaic A/B, A->B->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 4: // No Mosaic A/B, B->A->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 5: // Mosaic A, No Mosaic B, B->A->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 6: // No Mosaic A, Mosaic B, B->A->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 7: // Mosaic A/B, B->A->Backdrop plane ordering + mix_lines(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 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 void set_scanline_callback(T &&... args) { m_scanline_callback.set(std::forward(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 m_planea; required_shared_ptr 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 void set_vsr(uint32_t value); + template uint32_t get_vsr(); + + template void set_dcp(uint32_t value); + template uint32_t get_dcp(); + + template void set_display_parameters(uint8_t value); + + template void process_ica(); + template void process_dca(); - void set_register(int channel, uint8_t reg, uint32_t value); + template uint8_t get_transparency_control(); + template uint8_t get_icm(); + template bool get_mosaic_enable(); + template uint8_t get_mosaic_factor(); + template 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 void set_register(uint8_t reg, uint32_t value); - void draw_cursor(uint32_t *scanline, int y); - void draw_scanline(int y); + template 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 -- cgit v1.2.3