-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.
This commit is contained in:
MooglyGuy 2022-01-07 16:32:21 +01:00 committed by GitHub
parent 6cb03e6627
commit a3cc6df349
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1470 additions and 1307 deletions

View File

@ -10700,7 +10700,7 @@ license:CC0
<publisher>The Vision Factory</publisher>
<part name="cdrom" interface="cdi_cdrom">
<diskarea name="cdrom">
<disk name="the apprentice (cdi-ready)" sha1="7e1f612f1c36dabdc304abf2d17200b5faa4e180" status="baddump"/>
<disk name="the apprentice (cdi-ready)" sha1="3a66337c20b9157e64228847ee3d153f80c25e4e"/>
</diskarea>
</part>
</software>

View File

@ -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;

View File

@ -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;
if (!m_slave_hle.found())
return 0;
uint32_t *scanline = &m_lcdbitmap.pix(y);
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])
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::white();
}
else
{
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");
}

View File

@ -21,14 +21,13 @@ public:
cdi_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag)
, m_maincpu(*this, "maincpu")
, m_lcd(*this, "lcd")
, m_planea(*this, "mcd212:planea")
, m_slave_hle(*this, "slave_hle")
, m_servo(*this, "servo")
, m_slave(*this, "slave")
, m_cdic(*this, "cdic")
, m_cdda(*this, "cdda")
, m_mcd212(*this, "mcd212")
, m_lcd(*this, "lcd")
, m_dmadac(*this, "dac%u", 1U)
{ }
@ -43,10 +42,9 @@ protected:
void cdimono1_mem(address_map &map);
required_device<scc68070_device> m_maincpu;
optional_device<screen_device> m_lcd;
private:
virtual void video_start() override;
enum servo_portc_bit_t
{
INV_JUC_OUT = (1 << 2),
@ -54,7 +52,6 @@ private:
INV_CADDYSWITCH_IN = (1 << 7)
};
void draw_lcd(int y);
uint32_t screen_update_cdimono1_lcd(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
void cdi910_mem(address_map &map);
@ -72,13 +69,9 @@ private:
optional_device<m68hc05c8_device> m_servo;
optional_device<m68hc05c8_device> m_slave;
optional_device<cdicdic_device> m_cdic;
required_device<cdda_device> m_cdda;
required_device<mcd212_device> m_mcd212;
optional_device<screen_device> m_lcd;
required_device_array<dmadac_sound_device, 2> m_dmadac;
bitmap_rgb32 m_lcdbitmap;
};
class quizard_state : public cdi_state

View File

@ -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;
uint8_t *toc_data = &buffer[(m_curr_lba % entry_index) * 5];
// 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);
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));

View File

@ -86,6 +86,9 @@ private:
SECTOR_HEADER = 12,
SECTOR_MINUTES = 12,
SECTOR_SECONDS = 13,
SECTOR_FRACS = 14,
SECTOR_MODE = 15,
SECTOR_FILE1 = 16,
@ -153,7 +156,6 @@ private:
required_address_space m_memory_space;
required_device_array<dmadac_sound_device, 2> m_dmadac;
required_device<scc68070_device> m_scc;
required_device<cdda_device> m_cdda;
optional_device<cdrom_image_device> m_cdrom_dev;
uint32_t m_clock2;
@ -173,6 +175,7 @@ private:
uint16_t m_data_buffer; // CDIC Data Buffer Register (0x303ffe)
cdrom_file *m_cd;
bool m_cd_byteswap;
emu_timer *m_sector_timer;
uint8_t m_disc_command;
@ -195,8 +198,11 @@ private:
void play_raw_group(const uint8_t *data);
void play_xa_group(const uint8_t coding, const uint8_t *data);
void play_audio_sector(const uint8_t coding, const uint8_t *data);
void play_cdda_sector(const uint8_t *data);
void process_audio_map();
void descramble_sector(uint8_t *buffer);
bool is_valid_sector(const uint8_t *buffer);
bool is_mode2_sector_selected(const uint8_t *buffer);
bool is_mode2_audio_selected(const uint8_t *buffer);
@ -219,6 +225,7 @@ private:
static const int16_t s_xa_filter_coef[4][2];
static const int32_t s_samples_per_sector;
static const uint16_t s_crc_ccitt_table[256];
static const uint8_t s_sector_scramble[2448];
};
// device type definition

File diff suppressed because it is too large Load Diff

View File

@ -27,178 +27,22 @@ TODO:
#pragma once
#define MCD212_CURCNT_COLOR 0x00000f // Cursor color
#define MCD212_CURCNT_CUW 0x008000 // Cursor width
#define MCD212_CURCNT_COF 0x070000 // Cursor off time
#define MCD212_CURCNT_COF_SHIFT 16
#define MCD212_CURCNT_CON 0x280000 // Cursor on time
#define MCD212_CURCNT_CON_SHIFT 19
#define MCD212_CURCNT_BLKC 0x400000 // Blink type
#define MCD212_CURCNT_EN 0x800000 // Cursor enable
#define MCD212_ICM_CS 0x400000 // CLUT select
#define MCD212_ICM_NR 0x080000 // Number of region flags
#define MCD212_ICM_EV 0x040000 // External video
#define MCD212_ICM_MODE2 0x000f00 // Plane 2
#define MCD212_ICM_MODE2_SHIFT 8
#define MCD212_ICM_MODE1 0x00000f // Plane 1
#define MCD212_ICM_MODE1_SHIFT 0
#define MCD212_TCR_DISABLE_MX 0x800000 // Mix disable
#define MCD212_TCR_TB 0x000f00 // Plane B
#define MCD212_TCR_TB_SHIFT 8
#define MCD212_TCR_TA 0x00000f // Plane A
#define MCD212_TCR_COND_1 0x0 // Transparent if: Always (Plane Disabled)
#define MCD212_TCR_COND_KEY_1 0x1 // Transparent if: Color Key = True
#define MCD212_TCR_COND_XLU_1 0x2 // Transparent if: Transparency Bit = 1
#define MCD212_TCR_COND_RF0_1 0x3 // Transparent if: Region Flag 0 = True
#define MCD212_TCR_COND_RF1_1 0x4 // Transparent if: Region Flag 1 = True
#define MCD212_TCR_COND_RF0KEY_1 0x5 // Transparent if: Region Flag 0 = True || Color Key = True
#define MCD212_TCR_COND_RF1KEY_1 0x6 // Transparent if: Region Flag 1 = True || Color Key = True
#define MCD212_TCR_COND_UNUSED0 0x7 // Unused
#define MCD212_TCR_COND_0 0x8 // Transparent if: Never (No Transparent Area)
#define MCD212_TCR_COND_KEY_0 0x9 // Transparent if: Color Key = False
#define MCD212_TCR_COND_XLU_0 0xa // Transparent if: Transparency Bit = 0
#define MCD212_TCR_COND_RF0_0 0xb // Transparent if: Region Flag 0 = False
#define MCD212_TCR_COND_RF1_0 0xc // Transparent if: Region Flag 1 = False
#define MCD212_TCR_COND_RF0KEY_0 0xd // Transparent if: Region Flag 0 = False && Color Key = False
#define MCD212_TCR_COND_RF1KEY_0 0xe // Transparent if: Region Flag 1 = False && Color Key = False
#define MCD212_TCR_COND_UNUSED1 0xf // Unused
#define MCD212_POR_AB 0 // Plane A in front of Plane B
#define MCD212_POR_BA 1 // Plane B in front of Plane A
#define MCD212_RC_X 0x0003ff // X position
#define MCD212_RC_WF 0x00fc00 // Weight position
#define MCD212_RC_WF_SHIFT 10
#define MCD212_RC_RF 0x010000 // Region flag
#define MCD212_RC_RF_SHIFT 16
#define MCD212_RC_OP 0xf00000 // Operation
#define MCD212_RC_OP_SHIFT 20
#define MCD212_CSR1W_ST 0x0002 // Standard
#define MCD212_CSR1W_BE 0x0001 // Bus Error
#define MCD212_CSR2R_IT1 0x0004 // Interrupt 1
#define MCD212_CSR2R_IT2 0x0002 // Interrupt 2
#define MCD212_CSR2R_BE 0x0001 // Bus Error
#define MCD212_DCR_DE 0x8000 // Display Enable
#define MCD212_DCR_CF 0x4000 // Crystal Frequency
#define MCD212_DCR_FD 0x2000 // Frame Duration
#define MCD212_DCR_SM 0x1000 // Scan Mode
#define MCD212_DCR_CM 0x0800 // Color Mode Ch.1/2
#define MCD212_DCR_ICA 0x0200 // ICA Enable Ch.1/2
#define MCD212_DCR_DCA 0x0100 // DCA Enable Ch.1/2
#define MCD212_DDR_FT 0x0300 // Display File Type
#define MCD212_DDR_FT_BMP 0x0000 // Bitmap
#define MCD212_DDR_FT_BMP2 0x0100 // Bitmap (alt.)
#define MCD212_DDR_FT_RLE 0x0200 // Run-Length Encoded
#define MCD212_DDR_FT_MOSAIC 0x0300 // Mosaic
#define MCD212_DDR_MT 0x0c00 // Mosaic File Type
#define MCD212_DDR_MT_2 0x0000 // 2x1
#define MCD212_DDR_MT_4 0x0400 // 4x1
#define MCD212_DDR_MT_8 0x0800 // 8x1
#define MCD212_DDR_MT_16 0x0c00 // 16x1
#define MCD212_DDR_MT_SHIFT 10
typedef uint8_t BYTE68K;
typedef uint16_t WORD68K;
typedef int16_t SWORD68K;
#define BYTE68K_MAX 255
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> mcd212_device
class mcd212_device : public device_t,
public device_video_interface
public device_video_interface
{
public:
typedef device_delegate<void (int)> scanline_callback_delegate;
// construction/destruction
mcd212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto int_callback() { return m_int_callback.bind(); }
template <typename... T> void set_scanline_callback(T &&... args) { m_scanline_callback.set(std::forward<T>(args)...); }
// device members
uint16_t regs_r(offs_t offset, uint16_t mem_mask = ~0);
void regs_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
TIMER_CALLBACK_MEMBER( perform_scan );
bitmap_rgb32& get_bitmap() { return m_bitmap; }
DECLARE_WRITE_LINE_MEMBER(screen_vblank);
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
struct channel_t
{
uint8_t csrr;
uint16_t csrw;
uint16_t dcr;
uint16_t vsr;
uint16_t ddr;
uint16_t dcp;
uint32_t dca;
uint8_t clut_r[256];
uint8_t clut_g[256];
uint8_t clut_b[256];
uint32_t image_coding_method;
uint32_t transparency_control;
uint32_t plane_order;
uint32_t clut_bank;
uint32_t transparent_color_a;
uint32_t reserved0;
uint32_t transparent_color_b;
uint32_t mask_color_a;
uint32_t reserved1;
uint32_t mask_color_b;
uint32_t dyuv_abs_start_a;
uint32_t dyuv_abs_start_b;
uint32_t reserved2;
uint32_t cursor_position;
uint32_t cursor_control;
uint32_t cursor_pattern[16];
uint32_t region_control[8];
uint32_t backdrop_color;
uint32_t mosaic_hold_a;
uint32_t mosaic_hold_b;
uint8_t weight_factor_a[768];
uint8_t weight_factor_b[768];
};
struct ab_t
{
//* Color limit array.
BYTE68K limit[3 * BYTE68K_MAX];
//* Color clamp array.
BYTE68K clamp[3 * BYTE68K_MAX];
//* U-to-B matrix array.
SWORD68K matrixUB[BYTE68K_MAX + 1];
//* U-to-G matrix array.
SWORD68K matrixUG[BYTE68K_MAX + 1];
//* V-to-G matrix array.
SWORD68K matrixVG[BYTE68K_MAX + 1];
//* V-to-R matrix array.
SWORD68K matrixVR[BYTE68K_MAX + 1];
//* Delta-Y decoding array.
BYTE68K deltaY[BYTE68K_MAX + 1];
//* Delta-U/V decoding array.
BYTE68K deltaUV[BYTE68K_MAX + 1];
};
void map(address_map &map);
protected:
// device-level overrides
@ -206,51 +50,196 @@ protected:
virtual void device_start() override;
virtual void device_reset() override;
private:
uint8_t csr1_r();
void csr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t dcr1_r(offs_t offset, uint16_t mem_mask = ~0);
void dcr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t vsr1_r(offs_t offset, uint16_t mem_mask = ~0);
void vsr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t ddr1_r(offs_t offset, uint16_t mem_mask = ~0);
void ddr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t dca1_r(offs_t offset, uint16_t mem_mask = ~0);
void dca1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint8_t csr2_r();
void csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t dcr2_r(offs_t offset, uint16_t mem_mask = ~0);
void dcr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t vsr2_r(offs_t offset, uint16_t mem_mask = ~0);
void vsr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t ddr2_r(offs_t offset, uint16_t mem_mask = ~0);
void ddr2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
uint16_t dca2_r(offs_t offset, uint16_t mem_mask = ~0);
void dca2_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
enum : uint32_t
{
CURCNT_COLOR = 0x00000f, // Cursor color
CURCNT_CUW = 0x008000, // Cursor width
CURCNT_COF = 0x070000, // Cursor off time
CURCNT_COF_SHIFT = 16,
CURCNT_CON = 0x280000, // Cursor on time
CURCNT_CON_SHIFT = 19,
CURCNT_BLKC = 0x400000, // Blink type
CURCNT_EN = 0x800000, // Cursor enable
ICM_CS = 0x400000, // CLUT select
ICM_NR = 0x080000, // Number of region flags
ICM_NR_BIT = 19,
ICM_EV = 0x040000, // External video
ICM_MODE2 = 0x000f00, // Plane 2
ICM_MODE2_SHIFT = 8,
ICM_MODE1 = 0x00000f, // Plane 1
ICM_MODE1_SHIFT = 0,
TCR_DISABLE_MX = 0x800000, // Mix disable
TCR_TB = 0x000f00, // Plane B
TCR_TB_SHIFT = 8,
TCR_TA = 0x00000f, // Plane A
TCR_COND_1 = 0x0, // Transparent if: Always (Plane Disabled)
TCR_COND_KEY_1 = 0x1, // Transparent if: Color Key = True
TCR_COND_XLU_1 = 0x2, // Transparent if: Transparency Bit = 1
TCR_COND_RF0_1 = 0x3, // Transparent if: Region Flag 0 = True
TCR_COND_RF1_1 = 0x4, // Transparent if: Region Flag 1 = True
TCR_COND_RF0KEY_1 = 0x5, // Transparent if: Region Flag 0 = True || Color Key = True
TCR_COND_RF1KEY_1 = 0x6, // Transparent if: Region Flag 1 = True || Color Key = True
TCR_COND_UNUSED0 = 0x7, // Unused
TCR_COND_0 = 0x8, // Transparent if: Never (No Transparent Area)
TCR_COND_KEY_0 = 0x9, // Transparent if: Color Key = False
TCR_COND_XLU_0 = 0xa, // Transparent if: Transparency Bit = 0
TCR_COND_RF0_0 = 0xb, // Transparent if: Region Flag 0 = False
TCR_COND_RF1_0 = 0xc, // Transparent if: Region Flag 1 = False
TCR_COND_RF0KEY_0 = 0xd, // Transparent if: Region Flag 0 = False && Color Key = False
TCR_COND_RF1KEY_0 = 0xe, // Transparent if: Region Flag 1 = False && Color Key = False
TCR_COND_UNUSED1 = 0xf, // Unused
POR_AB = 0, // Plane A in front of Plane B
POR_BA = 1, // Plane B in front of Plane A
RC_X = 0x0003ff, // X position
RC_WF = 0x00fc00, // Weight position
RC_WF_SHIFT = 10,
RC_RF_BIT = 16, // Region flag bit
RC_OP = 0xf00000, // Operation
RC_OP_SHIFT = 20,
CSR1W_ST = 0x0002, // Standard
CSR1W_BE = 0x0001, // Bus Error
CSR2R_IT1 = 0x0004, // Interrupt 1
CSR2R_IT2 = 0x0002, // Interrupt 2
CSR2R_BE = 0x0001, // Bus Error
DCR_DE = 0x8000, // Display Enable
DCR_CF = 0x4000, // Crystal Frequency
DCR_FD = 0x2000, // Frame Duration
DCR_SM = 0x1000, // Scan Mode
DCR_CM = 0x0800, // Color Mode Ch.1/2
DCR_ICA = 0x0200, // ICA Enable Ch.1/2
DCR_DCA = 0x0100, // DCA Enable Ch.1/2
DDR_FT = 0x0300, // Display File Type
DDR_FT_BMP = 0x0000, // Bitmap
DDR_FT_BMP2 = 0x0100, // Bitmap (alt.)
DDR_FT_RLE = 0x0200, // Run-Length Encoded
DDR_FT_MOSAIC = 0x0300, // Mosaic
DDR_MT = 0x0c00, // Mosaic File Type
DDR_MT_2 = 0x0000, // 2x1
DDR_MT_4 = 0x0400, // 4x1
DDR_MT_8 = 0x0800, // 8x1
DDR_MT_16 = 0x0c00, // 16x1
DDR_MT_SHIFT = 10
};
uint8_t m_csrr[2];
uint16_t m_csrw[2];
uint16_t m_dcr[2];
uint16_t m_vsr[2];
uint16_t m_ddr[2];
uint16_t m_dcp[2];
uint32_t m_dca[2];
uint32_t m_clut[256];
uint32_t m_image_coding_method;
uint32_t m_transparency_control;
uint32_t m_plane_order;
uint32_t m_clut_bank[2];
uint32_t m_transparent_color[2];
uint32_t m_mask_color[2];
uint32_t m_dyuv_abs_start[2];
uint32_t m_cursor_position;
uint32_t m_cursor_control;
uint32_t m_cursor_pattern[16];
uint32_t m_region_control[8];
uint32_t m_backdrop_color;
uint32_t m_mosaic_hold[2];
uint8_t m_weight_factor[2][768];
// DYUV color limit arrays.
uint32_t m_dyuv_limit_r_lut[3 * 0xff];
uint32_t m_dyuv_limit_g_lut[3 * 0xff];
uint32_t m_dyuv_limit_b_lut[3 * 0xff];
// DYUV delta-Y decoding array
uint8_t m_delta_y_lut[0x100];
// DYUV delta-UV decoding array
uint8_t m_delta_uv_lut[0x100];
// DYUV U-to-B decoding array
int16_t m_dyuv_u_to_b[0x100];
// U-to-G decoding array
int16_t m_dyuv_u_to_g[0x100];
// V-to-G decoding array
int16_t m_dyuv_v_to_g[0x100];
// V-to-R decoding array
int16_t m_dyuv_v_to_r[0x100];
// interrupt callbacks
devcb_write_line m_int_callback;
scanline_callback_delegate m_scanline_callback;
required_shared_ptr<uint16_t> m_planea;
required_shared_ptr<uint16_t> m_planeb;
// internal state
channel_t m_channel[2];
emu_timer *m_scan_timer;
uint8_t m_region_flag_0[768];
uint8_t m_region_flag_1[768];
bitmap_rgb32 m_bitmap;
bool m_region_flag[2][768];
int m_ica_height;
int m_total_height;
static const uint32_t s_4bpp_color[16];
ab_t m_ab;
uint8_t get_weight_factor(const uint32_t region_idx);
uint8_t get_region_op(const uint32_t region_idx);
void update_region_arrays();
void set_vsr(int channel, uint32_t value);
uint32_t get_vsr(int channel);
void set_dcp(int channel, uint32_t value);
uint32_t get_dcp(int channel);
void set_display_parameters(int channel, uint8_t value);
void update_visible_area();
uint32_t get_screen_width();
void process_ica(int channel);
void process_dca(int channel);
void process_vsr(int channel, uint8_t *pixels_r, uint8_t *pixels_g, uint8_t *pixels_b);
template <int Channel> void set_vsr(uint32_t value);
template <int Channel> uint32_t get_vsr();
void set_register(int channel, uint8_t reg, uint32_t value);
template <int Channel> void set_dcp(uint32_t value);
template <int Channel> uint32_t get_dcp();
void mix_lines(uint8_t *plane_a_r, uint8_t *plane_a_g, uint8_t *plane_a_b, uint8_t *plane_b_r, uint8_t *plane_b_g, uint8_t *plane_b_b, uint32_t *out);
template <int Channel> void set_display_parameters(uint8_t value);
void draw_cursor(uint32_t *scanline, int y);
void draw_scanline(int y);
template <int Channel> void process_ica();
template <int Channel> void process_dca();
void ab_init();
template <int Channel> uint8_t get_transparency_control();
template <int Channel> uint8_t get_icm();
template <int Channel> bool get_mosaic_enable();
template <int Channel> uint8_t get_mosaic_factor();
template <int Channel> void process_vsr(uint32_t *pixels, bool *transparent);
template <int Channel> void set_register(uint8_t reg, uint32_t value);
template <bool MosaicA, bool MosaicB, bool OrderAB> void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out);
void draw_cursor(uint32_t *scanline);
void draw_scanline(bitmap_rgb32 &bitmap);
};
// device type definition