From 8d5734ba26f532bab27a304b8ae95eb3c9d05979 Mon Sep 17 00:00:00 2001 From: Vincent-Halver Date: Sat, 21 Mar 2026 05:22:05 -0700 Subject: [PATCH 01/47] Cherry-pick from recent CD-i driver changes. --- src/mame/drivers/cdi.cpp | 1 + src/mame/machine/cdicdic.cpp | 72 +++++++++++++++++++++++--------- src/mame/machine/cdicdic.h | 5 ++- src/mame/machine/cdislavehle.cpp | 45 ++++++++------------ 4 files changed, 75 insertions(+), 48 deletions(-) diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp index ee057381..f42aeb84 100644 --- a/src/mame/drivers/cdi.cpp +++ b/src/mame/drivers/cdi.cpp @@ -435,6 +435,7 @@ void cdi_state::cdimono1_base(machine_config &config) CDI_SLAVE_HLE(config, m_slave_hle, 0); m_slave_hle->int_callback().set(m_maincpu, FUNC(scc68070_device::in2_w)); + m_slave_hle->atten_callback().set(m_cdic, FUNC(cdicdic_device::atten_w)); /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp index 1aea9112..81c417a9 100644 --- a/src/mame/machine/cdicdic.cpp +++ b/src/mame/machine/cdicdic.cpp @@ -28,15 +28,15 @@ #include "romload.h" #include "sound/cdda.h" -#define LOG_DECODES (1 << 1) -#define LOG_SAMPLES (1 << 2) -#define LOG_COMMANDS (1 << 3) -#define LOG_SECTORS (1 << 4) -#define LOG_IRQS (1 << 5) -#define LOG_READS (1 << 6) -#define LOG_WRITES (1 << 7) -#define LOG_UNKNOWNS (1 << 8) -#define LOG_RAM (1 << 9) +#define LOG_DECODES (1U << 1) +#define LOG_SAMPLES (1U << 2) +#define LOG_COMMANDS (1U << 3) +#define LOG_SECTORS (1U << 4) +#define LOG_IRQS (1U << 5) +#define LOG_READS (1U << 6) +#define LOG_WRITES (1U << 7) +#define LOG_UNKNOWNS (1U << 8) +#define LOG_RAM (1U << 9) #define LOG_ALL (LOG_DECODES | LOG_SAMPLES | LOG_COMMANDS | LOG_SECTORS | LOG_IRQS | LOG_READS | LOG_WRITES | LOG_UNKNOWNS | LOG_RAM) #define VERBOSE (0) @@ -515,14 +515,14 @@ void cdicdic_device::play_raw_group(const uint8_t *data) m_dmadac[1]->transfer(0, 1, 1, 28, samples); } -void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data) +void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data, const uint16_t idx) { static const uint16_t s_4bit_header_offsets[8] = { 0, 1, 2, 3, 8, 9, 10, 11 }; static const uint16_t s_8bit_header_offsets[4] = { 0, 1, 2, 3 }; static const uint16_t s_4bit_data_offsets[8] = { 16, 16, 17, 17, 18, 18, 19, 19 }; static const uint16_t s_8bit_data_offsets[4] = { 16, 17, 18, 19 }; - int16_t samples[28]; + const uint8_t num_samples = coding & CODING_8BPS ? 4 : 8; switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) { @@ -569,15 +569,15 @@ void cdicdic_device::play_cdda_sector(const uint8_t *data) 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++) + const uint16_t NUM_SAMPLES = SECTOR_SIZE / 4; + for (uint16_t i = 0; i < NUM_SAMPLES; 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_samples[0][i] = (int16_t)((data[(i * 4) + 1] << 8) | data[(i * 4) + 0]); + m_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]); + m_dmadac[0]->transfer(0, 1, 1, NUM_SAMPLES, &m_samples[0][0]); + m_dmadac[1]->transfer(0, 1, 1, NUM_SAMPLES, &m_samples[1][0]); } void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data) @@ -631,6 +631,10 @@ void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data m_dmadac[0]->set_volume(0x100); m_dmadac[1]->set_volume(0x100); + const uint16_t bps = ((coding & CODING_BPS_MASK) == CODING_8BPS); + const uint16_t chan = ((coding & CODING_CHAN_MASK) == CODING_STEREO); + const uint16_t num_samples = 8 >> (bps + chan); + if (bits == 16 && channels == 2) { for (uint16_t i = 0; i < SECTOR_AUDIO_SIZE; i += 112, data += 112) @@ -640,9 +644,29 @@ void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data } else { + uint16_t offset = 0; for (uint16_t i = 0; i < SECTOR_AUDIO_SIZE; i += 128, data += 128) { - play_xa_group(coding, data); + play_xa_group(coding, data, offset); + offset += 28 * num_samples; + } + + int16_t sampleL = 0, sampleR = 0, outL = 0, outR = 0; + // Attenuation is logarithmic (decibels). + // Floats are not chip accurate, but the formula is correct. + float scaleLL = powf(10.0f, -m_atten[0] / 20.0f); + float scaleLR = powf(10.0f, -m_atten[1] / 20.0f); + float scaleRR = powf(10.0f, -m_atten[2] / 20.0f); + float scaleRL = powf(10.0f, -m_atten[3] / 20.0f); + for (uint16_t i = 0; i < 18 * 28 * num_samples; i++) + { + sampleL = m_samples[0][i]; + sampleR = m_samples[coding & CODING_STEREO][i]; + + outL = (sampleL * scaleLL + sampleR * scaleRL) * 0.25; + outR = (sampleL * scaleLR + sampleR * scaleRR) * 0.25; + m_dmadac[0]->transfer(0, 1, 1, 1, &outL); + m_dmadac[1]->transfer(0, 1, 1, 1, &outR); } } } @@ -1278,6 +1302,14 @@ void cdicdic_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask) } } + +void cdicdic_device::atten_w(uint32_t state) { + m_atten[0] = (state & 0xFF000000) >> 24; + m_atten[1] = (state & 0x00FF0000) >> 16; + m_atten[2] = (state & 0x0000FF00) >> 8; + m_atten[3] = (state & 0x000000FF); +} + void cdicdic_device::init_disc_read(uint8_t disc_mode) { m_disc_command = m_command; @@ -1425,6 +1457,7 @@ void cdicdic_device::device_start() save_item(NAME(m_decoding_audio_map)); save_item(NAME(m_decode_addr)); + save_item(NAME(m_atten)); save_item(NAME(m_xa_last)); m_audio_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::audio_tick), this)); @@ -1483,7 +1516,8 @@ void cdicdic_device::device_reset() m_dmadac[0]->enable(1); m_dmadac[1]->enable(1); - std::fill_n(&m_xa_last[0], 4, 0); + std::fill_n(m_atten, 4, 0); + std::fill_n(m_xa_last, 4, 0); } void cdicdic_device::ram_w(offs_t offset, uint16_t data, uint16_t mem_mask) diff --git a/src/mame/machine/cdicdic.h b/src/mame/machine/cdicdic.h index 9075b77c..5f377577 100644 --- a/src/mame/machine/cdicdic.h +++ b/src/mame/machine/cdicdic.h @@ -59,6 +59,7 @@ class cdicdic_device : public device_t void ram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); uint8_t intack_r(); + void atten_w(uint32_t state); protected: // device-level overrides @@ -189,6 +190,8 @@ class cdicdic_device : public device_t bool m_decoding_audio_map; uint16_t m_decode_addr; + // Audio Attenuation (L->L, L->R, R->R, R->L) + uint8_t m_atten[4]; int16_t m_xa_last[4]; std::unique_ptr m_ram; std::unique_ptr m_samples[2]; @@ -196,7 +199,7 @@ class cdicdic_device : public device_t void decode_8bit_xa_unit(int channel, uint8_t param, const uint8_t *data, int16_t *out_buffer); void decode_4bit_xa_unit(int channel, uint8_t param, const uint8_t *data, uint8_t shift, int16_t *out_buffer); void play_raw_group(const uint8_t *data); - void play_xa_group(const uint8_t coding, const uint8_t *data); + void play_xa_group(const uint8_t coding, const uint8_t *data, const uint16_t idx); void play_audio_sector(const uint8_t coding, const uint8_t *data); void play_cdda_sector(const uint8_t *data); void process_audio_map(); diff --git a/src/mame/machine/cdislavehle.cpp b/src/mame/machine/cdislavehle.cpp index 769f9df2..ae6c1629 100644 --- a/src/mame/machine/cdislavehle.cpp +++ b/src/mame/machine/cdislavehle.cpp @@ -205,24 +205,16 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } break; case 1: - if (m_in_index) + if (m_in_index > 1) { - m_in_buf[m_in_index] = data & 0x00ff; - m_in_index++; if (m_in_index == m_in_count) { switch (m_in_buf[0]) { case 0xf0: // Set Front Panel LCD memcpy(m_lcd_state, m_in_buf + 1, 16); - memset(m_in_buf, 0, 17); - m_in_index = 0; - m_in_count = 0; break; default: - memset(m_in_buf, 0, 17); - m_in_index = 0; - m_in_count = 0; break; } } @@ -240,14 +232,18 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } break; case 2: - if (m_in_index) + if (m_in_index > 1) { - m_in_buf[m_in_index] = data & 0x00ff; - m_in_index++; if (m_in_index == m_in_count) { switch (m_in_buf[0]) { + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + m_atten_w((((u32)m_in_buf[1]) << 24) | (((u32)m_in_buf[2]) << 16) | (((u32)m_in_buf[3]) << 8) | (((u32)m_in_buf[4]))); + m_in_index = 0; + m_in_count = 0; + break; case 0xf0: // Set Front Panel LCD memset(m_in_buf + 1, 0, 16); m_in_count = 17; @@ -262,8 +258,6 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } else { - m_in_buf[m_in_index] = data & 0x00ff; - m_in_index++; switch (data & 0x00ff) { case 0x82: // Mute Audio @@ -283,6 +277,11 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) m_in_count = 0; break; } + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Set Attenuation Audio\n", offset); + m_in_count = 5; + break; case 0xf0: // Set Front Panel LCD m_in_count = 17; break; @@ -295,38 +294,28 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } break; case 3: - if (m_in_index) + if (m_in_index > 1) { - m_in_buf[m_in_index] = data & 0x00ff; - m_in_index++; if (m_in_index == m_in_count) { switch (m_in_buf[0]) { case 0xb0: // Request Disc Status - memset(m_in_buf, 0, 17); - m_in_index = 0; - m_in_count = 0; prepare_readback(attotime::from_hz(4), 3, 4, 0xb0, 0x00, 0x02, 0x15, 0xb0); break; //case 0xb1: // Request Disc Base - //memset(m_in_buf, 0, 17); - //m_in_index = 0; - //m_in_count = 0; //prepare_readback(attotime::from_hz(10000), 3, 4, 0xb1, 0x00, 0x00, 0x00, 0xb1); //break; default: - memset(m_in_buf, 0, 17); - m_in_index = 0; - m_in_count = 0; break; } + memset(m_in_buf, 0, 17); + m_in_index = 0; + m_in_count = 0; } } else { - m_in_buf[m_in_index] = data & 0x00ff; - m_in_index++; switch (data & 0x00ff) { case 0xb0: // Request Disc Status From da78df04ee3c5a31f95321cfb5e67bc0d30cfd31 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Sun, 5 Jul 2026 16:27:37 -0600 Subject: [PATCH 02/47] Move over CD-i changes to new branch. --- src/mame/drivers/cdi.cpp | 365 +------------------------------ src/mame/includes/cdi.h | 89 ++------ src/mame/machine/cdicdic.cpp | 41 ++-- src/mame/machine/cdicdic.h | 2 + src/mame/machine/cdislavehle.cpp | 24 +- src/mame/machine/cdislavehle.h | 3 + src/mame/mame.lst | 14 -- 7 files changed, 60 insertions(+), 478 deletions(-) diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp index f42aeb84..887a44f4 100644 --- a/src/mame/drivers/cdi.cpp +++ b/src/mame/drivers/cdi.cpp @@ -68,9 +68,6 @@ #define CLOCK_A 30_MHz_XTAL #define LOG_DVC (1 << 1) -#define LOG_QUIZARD_READS (1 << 2) -#define LOG_QUIZARD_WRITES (1 << 3) -#define LOG_QUIZARD_OTHER (1 << 4) #define LOG_UART (1 << 5) #define VERBOSE (0) @@ -139,38 +136,6 @@ INPUT_PORTS_END static INPUT_PORTS_START( cdimono2 ) INPUT_PORTS_END -static INPUT_PORTS_START( quizard ) - PORT_START("P0") - PORT_DIPNAME( 0x07, 0x05, "Settings" ) - PORT_DIPSETTING( 0x00, "1 Coin, 0 Bonus Limit, 0 Bonus Number" ) - PORT_DIPSETTING( 0x01, "2 Coins, 0 Bonus Limit, 0 Bonus Number" ) - PORT_DIPSETTING( 0x02, "1 Coin, 2 Bonus Limit, 1 Bonus Number" ) - PORT_DIPSETTING( 0x03, "1 Coin, 3 Bonus Limit, 1 Bonus Number" ) - PORT_DIPSETTING( 0x04, "1 Coin, 5 Bonus Limit, 1 Bonus Number" ) - PORT_DIPSETTING( 0x05, "1 Coin, 5 Bonus Limit, 2 Bonus Number" ) - PORT_DIPSETTING( 0x06, "1 Coin, 10 Bonus Limit, 2 Bonus Number" ) - PORT_DIPSETTING( 0x07, "2 Coins, 4 Bonus Limit, 1 Bonus Number" ) - PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN1 ) - PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_COIN2 ) - PORT_BIT( 0xc8, IP_ACTIVE_LOW, IPT_UNUSED ) - - PORT_START("P1") - PORT_BIT( 0x1f, IP_ACTIVE_LOW, IPT_UNUSED ) - PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START1 ) - PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START2 ) - PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SERVICE1 ) - - PORT_START("P2") - PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Player 1 A") - PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Player 1 B") - PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Player 1 C") - PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Player 2 A") - PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Player 2 B") - PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Player 2 C") - PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) -INPUT_PORTS_END - - /*************************** * Machine Initialization * ***************************/ @@ -182,21 +147,6 @@ void cdi_state::machine_reset() memcpy(dst, src, 0x8); } -void quizard_state::machine_start() -{ - save_item(NAME(m_mcu_rx_from_cpu)); - save_item(NAME(m_mcu_initial_byte)); -} - -void quizard_state::machine_reset() -{ - cdi_state::machine_reset(); - - m_mcu_rx_from_cpu = 0x00; - m_mcu_initial_byte = true; -} - - /*************************** * Wait-State Handling * ***************************/ @@ -221,7 +171,6 @@ uint16_t cdi_state::main_rom_r(offs_t offset) return m_main_rom[offset]; } - /********************** * BERR Handling * **********************/ @@ -247,82 +196,6 @@ void cdi_state::bus_error_w(offs_t offset, uint16_t data) } } - -/********************** -* Quizard Protection * -**********************/ - -void quizard_state::mcu_rtsn_from_cpu(int state) -{ -} - -void quizard_state::mcu_rx_from_cpu(uint8_t data) -{ - if (m_mcu_initial_byte) - { - m_mcu_initial_byte = false; - return; - } - - m_mcu_rx_from_cpu = data; - - m_mcu->set_input_line(MCS51_RX_LINE, ASSERT_LINE); - m_mcu->set_input_line(MCS51_RX_LINE, CLEAR_LINE); -} - -uint8_t quizard_state::mcu_p0_r() -{ - const uint8_t data = m_inputs[0]->read(); - return data; -} - -uint8_t quizard_state::mcu_p1_r() -{ - uint8_t data = m_inputs[1]->read(); - if (BIT(~m_inputs[0]->read(), 4)) - data &= ~(1 << 4); - return data; -} - -uint8_t quizard_state::mcu_p2_r() -{ - const uint8_t data = m_inputs[2]->read(); - return data; -} - -uint8_t quizard_state::mcu_p3_r() -{ - return 0x04; -} - -void quizard_state::mcu_p0_w(uint8_t data) -{ -} - -void quizard_state::mcu_p1_w(uint8_t data) -{ -} - -void quizard_state::mcu_p2_w(uint8_t data) -{ -} - -void quizard_state::mcu_p3_w(uint8_t data) -{ - m_maincpu->uart_ctsn(BIT(data, 6)); -} - -void quizard_state::mcu_tx(uint8_t data) -{ - m_maincpu->uart_rx(data); -} - -uint8_t quizard_state::mcu_rx() -{ - uint8_t data = m_mcu_rx_from_cpu; - return data; -} - /************************* * DVC cartridge * *************************/ @@ -437,6 +310,9 @@ void cdi_state::cdimono1_base(machine_config &config) m_slave_hle->int_callback().set(m_maincpu, FUNC(scc68070_device::in2_w)); m_slave_hle->atten_callback().set(m_cdic, FUNC(cdicdic_device::atten_w)); + CDROM(config, m_cdrom); + m_cdrom->set_interface("cdrom"); + /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); @@ -548,26 +424,6 @@ void cdi_state::cdimono1(machine_config &config) SOFTWARE_LIST(config, "cd_list").set_original("cdi").set_filter("!DVC"); } -void quizard_state::quizard(machine_config &config) -{ - cdimono1_base(config); - m_maincpu->set_addrmap(AS_PROGRAM, &quizard_state::cdimono1_mem); - m_maincpu->uart_rtsn_callback().set(FUNC(quizard_state::mcu_rtsn_from_cpu)); - m_maincpu->uart_tx_callback().set(FUNC(quizard_state::mcu_rx_from_cpu)); - - I8751(config, m_mcu, 8000000); - m_mcu->port_in_cb<0>().set(FUNC(quizard_state::mcu_p0_r)); - m_mcu->port_in_cb<1>().set(FUNC(quizard_state::mcu_p1_r)); - m_mcu->port_in_cb<2>().set(FUNC(quizard_state::mcu_p2_r)); - m_mcu->port_in_cb<3>().set(FUNC(quizard_state::mcu_p3_r)); - m_mcu->port_out_cb<0>().set(FUNC(quizard_state::mcu_p0_w)); - m_mcu->port_out_cb<1>().set(FUNC(quizard_state::mcu_p1_w)); - m_mcu->port_out_cb<2>().set(FUNC(quizard_state::mcu_p2_w)); - m_mcu->port_out_cb<3>().set(FUNC(quizard_state::mcu_p3_w)); - m_mcu->serial_tx_cb().set(FUNC(quizard_state::mcu_tx)); - m_mcu->serial_rx_cb().set(FUNC(quizard_state::mcu_rx)); -} - /************************* * Rom Load * *************************/ @@ -628,199 +484,6 @@ ROM_START( cdi490a ) ROM_LOAD( "vmpega.rom", 0x0000, 0x40000, CRC(db264e8b) SHA1(be407fbc102f1731a0862554855e963e5a47c17b) ) ROM_END -ROM_START( cdibios ) // for the quizard sets - ROM_REGION(0x80000, "maincpu", 0) - ROM_SYSTEM_BIOS( 0, "mcdi200", "Magnavox CD-i 200" ) - ROMX_LOAD( "cdi200.rom", 0x000000, 0x80000, CRC(40c4e6b9) SHA1(d961de803c89b3d1902d656ceb9ce7c02dccb40a), ROM_BIOS(0) ) - ROM_SYSTEM_BIOS( 1, "pcdi220", "Philips CD-i 220 F2" ) - ROMX_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e), ROM_BIOS(1) ) - - // The MCU dump below is taken from the cdi910. We still need a dump from a Mono-I board SLAVE MCU in case the revisions are different. - ROM_REGION(0x2000, "slave", 0) - ROM_LOAD( "zx405042p__cdi_slave_2.0__b43t__zzmk9213.mc68hc705c8a_withtestrom.7206", 0x0000, 0x2000, CRC(688cda63) SHA1(56d0acd7caad51c7de703247cd6d842b36173079) BAD_DUMP ) -ROM_END - -/* Quizard notes - - The MCU controls the protection sequence, which in turn controls the game display language. - Each Quizard game (1,2,3,4) requires its own MCU, you can upgrade between revisions by changing - just the CD, but not between games as a new MCU is required. - - MCU Notes: - i8751 MCU dumps confirmed good on original hardware - German language MCUs for Quizard 1 through 4 are dumped - Czech language MCU for Quizard 4 is dumped - Italian language MCU for Quizard 1 is known to exist (IT 11 L2, not dumped) - Alt. German language MCU for Quizard 2 is known to exist (DE 122 D3, not dumped) - -*/ - - -//******************************************************** -// Quizard (1) -//******************************************************** - -ROM_START( quizard ) /* CD-ROM printed ??/?? */ - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard18", 0, BAD_DUMP SHA1(ede873b22957f2a707bbd3039e962ef2ca5aedbd) ) - - ROM_REGION(0x1000, "mcu", 0) - ROM_LOAD( "de_11_d3.bin", 0x0000, 0x1000, CRC(95f45b6b) SHA1(51b34956539b1e2cf0306f243a970750f1e18d01) ) // German language -ROM_END - -ROM_START( quizard_17 ) - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard17", 0, BAD_DUMP SHA1(4bd698f076505b4e17be978481bce027eb47123b) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_11_d3.bin", 0x0000, 0x1000, CRC(95f45b6b) SHA1(51b34956539b1e2cf0306f243a970750f1e18d01) ) // German language -ROM_END - -ROM_START( quizard_12 ) /* CD-ROM printed 01/95 */ - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard12", 0, BAD_DUMP SHA1(6e41683b96b74e903040842aeb18437ad7813c82) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_11_d3.bin", 0x0000, 0x1000, CRC(95f45b6b) SHA1(51b34956539b1e2cf0306f243a970750f1e18d01) ) // German language -ROM_END - -ROM_START( quizard_10 ) - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - // software: BurnAtOnce 0.99.5 / CHDMAN 0.163 - // Drive: TS-L633R - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard10", 0, SHA1(5715db50f0d5ffe06f47c0943f4bf0481ab6048e) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_11_d3.bin", 0x0000, 0x1000, CRC(95f45b6b) SHA1(51b34956539b1e2cf0306f243a970750f1e18d01) ) // German language -ROM_END - - -//******************************************************** -// Quizard 2 -//******************************************************** - -ROM_START( quizard2 ) /* CD-ROM printed ??/?? */ - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard23", 0, BAD_DUMP SHA1(cd909d9a54275d6f2d36e03e83eea996e781b4d3) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "dn_122_d3.bin", 0x0000, 0x1000, CRC(d48063ea) SHA1(b512fa5e53f296a180340e09b53613dd1c0d38bc) ) // German language - DE 122 D3 known to exist -ROM_END - -ROM_START( quizard2_22 ) - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard22", 0, BAD_DUMP SHA1(03c8fdcf27ead6e221691111e8c679b551099543) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "dn_122_d3.bin", 0x0000, 0x1000, CRC(d48063ea) SHA1(b512fa5e53f296a180340e09b53613dd1c0d38bc) ) // German language - DE 122 D3 known to exist -ROM_END - - -//******************************************************** -// Quizard 3 -//******************************************************** - -ROM_START( quizard3 ) /* CD-ROM printed ??/?? */ - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard34", 0, BAD_DUMP SHA1(37ad49b72b5175afbb87141d57bc8604347fe032) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_132_d3.bin", 0x0000, 0x1000, CRC(8858251e) SHA1(2c1005a74bb6f0c2918dff4ab6326528eea48e1f) ) // German language -ROM_END - -ROM_START( quizard3a ) /* CD-ROM printed ??/?? */ - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard34", 0, BAD_DUMP SHA1(37ad49b72b5175afbb87141d57bc8604347fe032) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_132_a1.bin", 0x0000, 0x1000, CRC(313ac673) SHA1(cb0ee7e9a6eaa5f4d000f5ea99b7ee4c440b31d1) ) // German language - earlier version of MCU code -ROM_END - -ROM_START( quizard3_32 ) - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard32", 0, BAD_DUMP SHA1(31e9fa2169aa44d799c37170b238134ab738e1a1) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_132_d3.bin", 0x0000, 0x1000, CRC(8858251e) SHA1(2c1005a74bb6f0c2918dff4ab6326528eea48e1f) ) // German language -ROM_END - - -//******************************************************** -// Quizard 4 -//******************************************************** - -ROM_START( quizard4 ) /* CD-ROM printed 09/98 */ - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard4r42", 0, BAD_DUMP SHA1(a5d5c8950b4650b8753f9119dc7f1ccaa2aa5442) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_142_d3.bin", 0x0000, 0x1000, CRC(77be0b40) SHA1(113b5c239480a2259f55e411ba8fb3972e6d4301) ) // German language -ROM_END - -ROM_START( quizard4cz ) /* CD-ROM printed 09/98 */ - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard4r42", 0, BAD_DUMP SHA1(a5d5c8950b4650b8753f9119dc7f1ccaa2aa5442) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "ts142_cz1.bin", 0x0000, 0x1000, CRC(fdc1f457) SHA1(5169c4d2ea4073a854c3f619205161386c9af8af) ) // Czech language - works with all Quizard 4 versions -ROM_END - -ROM_START( quizard4_41 ) - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard4r41", 0, BAD_DUMP SHA1(2c0484c6545aac8e00b318328c6edce6f5dde43d) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_142_d3.bin", 0x0000, 0x1000, CRC(77be0b40) SHA1(113b5c239480a2259f55e411ba8fb3972e6d4301) ) // German language -ROM_END - -ROM_START( quizard4_40 ) /* CD-ROM printed 07/97 */ - ROM_REGION(0x80000, "maincpu", 0) - ROM_LOAD( "cdi220b.rom", 0x000000, 0x80000, CRC(279683ca) SHA1(53360a1f21ddac952e95306ced64186a3fc0b93e) ) - - DISK_REGION( "cdrom" ) - DISK_IMAGE_READONLY( "quizard4r40", 0, BAD_DUMP SHA1(288cc37a994e4f1cbd47aa8c92342879c6fc0b87) ) - - ROM_REGION(0x1000, "mcu", 0) // Intel D8751H MCU - ROM_LOAD( "de_142_d3.bin", 0x0000, 0x1000, CRC(77be0b40) SHA1(113b5c239480a2259f55e411ba8fb3972e6d4301) ) // German language -ROM_END - - /************************* * Game driver(s) * *************************/ @@ -831,25 +494,3 @@ CONS( 1991, cdimono1, 0, 0, cdimono1, cdi, cdi_state, empty_init, CONS( 1991, cdimono2, 0, 0, cdimono2, cdimono2, cdi_state, empty_init, "Philips", "CD-i (Mono-II) (NTSC)", MACHINE_NOT_WORKING ) CONS( 1991, cdi910, 0, 0, cdi910, cdimono2, cdi_state, empty_init, "Philips", "CD-i 910-17P Mini-MMC (PAL)", MACHINE_NOT_WORKING ) CONS( 1991, cdi490a, 0, 0, cdimono1, cdi, cdi_state, empty_init, "Philips", "CD-i 490", MACHINE_NOT_WORKING ) - -// The Quizard games are retail CD-i units in a cabinet, with an additional JAMMA adapter and dongle for protection, hence being clones of the system. -/* YEAR NAME PARENT MACHINE INPUT DEVICE INIT MONITOR COMPANY FULLNAME */ -GAME( 1995, cdibios, 0, cdimono1, quizard, cdi_state, empty_init, ROT0, "Philips", "CD-i (Mono-I) (PAL) BIOS", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IS_BIOS_ROOT ) - -GAME( 1995, quizard, cdibios, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.8, German, i8751 DE 11 D3)", MACHINE_IMPERFECT_SOUND ) -GAME( 1995, quizard_17, quizard, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.7, German, i8751 DE 11 D3)", MACHINE_IMPERFECT_SOUND ) -GAME( 1995, quizard_12, quizard, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.2, German, i8751 DE 11 D3)", MACHINE_IMPERFECT_SOUND ) -GAME( 1995, quizard_10, quizard, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard (v1.0, German, i8751 DE 11 D3)", MACHINE_IMPERFECT_SOUND ) - -GAME( 1995, quizard2, cdibios, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 2 (v2.3, German, i8751 DN 122 D3)", MACHINE_IMPERFECT_SOUND ) -GAME( 1995, quizard2_22, quizard2, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 2 (v2.2, German, i8751 DN 122 D3)", MACHINE_IMPERFECT_SOUND ) - -// Quizard 3 and 4 will hang after starting a game (CDIC issues?) -GAME( 1995, quizard3, cdibios, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.4, German, i8751 DE 132 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) -GAME( 1995, quizard3a, quizard3, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.4, German, i8751 DE 132 A1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) -GAME( 1996, quizard3_32, quizard3, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 3 (v3.2, German, i8751 DE 132 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) - -GAME( 1998, quizard4, cdibios, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.2, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) -GAME( 1998, quizard4cz, quizard4, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.2, Czech, i8751 TS142 CZ1)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) -GAME( 1998, quizard4_41, quizard4, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.1, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) -GAME( 1997, quizard4_40, quizard4, quizard, quizard, quizard_state, empty_init, ROT0, "TAB Austria", "Quizard 4 Rainbow (v4.0, German, i8751 DE 142 D3)", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND ) diff --git a/src/mame/includes/cdi.h b/src/mame/includes/cdi.h index 69e8a862..60ec6c76 100644 --- a/src/mame/includes/cdi.h +++ b/src/mame/includes/cdi.h @@ -1,8 +1,8 @@ // license:BSD-3-Clause // copyright-holders:Ryan Holtz -#ifndef MAME_INCLUDES_CDI_H -#define MAME_INCLUDES_CDI_H +#ifndef MAME_PHILIPS_CDI_H +#define MAME_PHILIPS_CDI_H #include "machine/scc68070.h" #include "machine/cdislavehle.h" @@ -11,6 +11,7 @@ #include "video/mcd212.h" #include "cpu/mcs51/mcs51.h" #include "cpu/m6805/m68hc05.h" +#include "diserial.h" #include "screen.h" /*----------- driver state -----------*/ @@ -23,11 +24,12 @@ class cdi_state : public driver_device , m_maincpu(*this, "maincpu") , m_main_rom(*this, "maincpu") , m_lcd(*this, "lcd") - , m_plane_ram(*this, "plane%u", 0U) , m_slave_hle(*this, "slave_hle") + , m_plane_ram(*this, "plane%u", 0U) , m_servo(*this, "servo") , m_slave(*this, "slave") , m_cdic(*this, "cdic") + , m_cdrom(*this, "cdrom") , m_mcd212(*this, "mcd212") , m_dmadac(*this, "dac%u", 1U) { } @@ -38,15 +40,6 @@ class cdi_state : public driver_device void cdi910(machine_config &config); protected: - virtual void machine_reset() override; - - void cdimono1_mem(address_map &map); - - required_device m_maincpu; - required_region_ptr m_main_rom; - optional_device m_lcd; - -private: enum servo_portc_bit_t { INV_JUC_OUT = (1 << 2), @@ -54,72 +47,38 @@ class cdi_state : public driver_device INV_CADDYSWITCH_IN = (1 << 7) }; - uint32_t screen_update_cdimono1_lcd(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - - void cdi910_mem(address_map &map); - void cdimono2_mem(address_map &map); - void cdi070_cpuspace(address_map &map); - - template uint16_t plane_r(offs_t offset, uint16_t mem_mask = ~0); - template void plane_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - - uint16_t main_rom_r(offs_t offset); - - uint16_t dvc_r(offs_t offset, uint16_t mem_mask = ~0); - void dvc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - - uint16_t bus_error_r(offs_t offset); - void bus_error_w(offs_t offset, uint16_t data); - - required_shared_ptr_array m_plane_ram; + required_device m_maincpu; + required_region_ptr m_main_rom; + optional_device m_lcd; optional_device m_slave_hle; + required_shared_ptr_array m_plane_ram; optional_device m_servo; optional_device m_slave; optional_device m_cdic; + required_device m_cdrom; required_device m_mcd212; required_device_array m_dmadac; -}; -class quizard_state : public cdi_state -{ -public: - quizard_state(const machine_config &mconfig, device_type type, const char *tag) - : cdi_state(mconfig, type, tag) - , m_mcu(*this, "mcu") - , m_inputs(*this, "P%u", 0U) - { } + uint32_t screen_update_cdimono1_lcd(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); + virtual void machine_reset() override ATTR_COLD; - void quizard(machine_config &config); + void cdimono1_mem(address_map &map) ATTR_COLD; -private: - virtual void machine_start() override; - virtual void machine_reset() override; + void cdi910_mem(address_map &map) ATTR_COLD; + void cdimono2_mem(address_map &map) ATTR_COLD; + void cdi070_cpuspace(address_map &map) ATTR_COLD; - uint8_t mcu_p0_r(); - uint8_t mcu_p1_r(); - uint8_t mcu_p2_r(); - uint8_t mcu_p3_r(); - void mcu_p0_w(uint8_t data); - void mcu_p1_w(uint8_t data); - void mcu_p2_w(uint8_t data); - void mcu_p3_w(uint8_t data); - void mcu_tx(uint8_t data); - uint8_t mcu_rx(); + template uint16_t plane_r(offs_t offset, uint16_t mem_mask = ~0); + template void plane_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - void mcu_rx_from_cpu(uint8_t data); - void mcu_rtsn_from_cpu(int state); + uint16_t main_rom_r(offs_t offset); - required_device m_mcu; - required_ioport_array<3> m_inputs; + uint16_t dvc_r(offs_t offset, uint16_t mem_mask = ~0); + void dvc_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); - uint8_t m_mcu_rx_from_cpu; - bool m_mcu_initial_byte; + uint16_t bus_error_r(offs_t offset); + void bus_error_w(offs_t offset, uint16_t data); }; -// Quizard 2 language values: -// 0x2b1: Italian -// 0x001: French -// 0x188: German - -#endif // MAME_INCLUDES_CDI_H +#endif // MAME_PHILIPS_CDI_H diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp index 81c417a9..82fb990e 100644 --- a/src/mame/machine/cdicdic.cpp +++ b/src/mame/machine/cdicdic.cpp @@ -517,48 +517,33 @@ void cdicdic_device::play_raw_group(const uint8_t *data) void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data, const uint16_t idx) { - static const uint16_t s_4bit_header_offsets[8] = { 0, 1, 2, 3, 8, 9, 10, 11 }; - static const uint16_t s_8bit_header_offsets[4] = { 0, 1, 2, 3 }; + static const uint16_t s_4bit_header_offsets[8] = { 4, 5, 6, 7, 12, 13, 14, 15 }; + static const uint16_t s_8bit_header_offsets[4] = { 4, 5, 6, 7 }; static const uint16_t s_4bit_data_offsets[8] = { 16, 16, 17, 17, 18, 18, 19, 19 }; static const uint16_t s_8bit_data_offsets[4] = { 16, 17, 18, 19 }; const uint8_t num_samples = coding & CODING_8BPS ? 4 : 8; + for (uint8_t i = 0; i < num_samples; i++) + { switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) { case CODING_4BPS | CODING_MONO: - for (uint8_t i = 0; i < 8; i++) - { - decode_4bit_xa_unit(0, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); - m_dmadac[0]->transfer(0, 1, 1, 28, samples); - m_dmadac[1]->transfer(0, 1, 1, 28, samples); - } - return; + decode_4bit_xa_unit(0, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, &m_samples[0][idx + i * 28]); + break; case CODING_4BPS | CODING_STEREO: - for (uint8_t i = 0; i < 8; i++) - { - decode_4bit_xa_unit(i & 1, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); - m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); - } - return; + decode_4bit_xa_unit(i & 1, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, &m_samples[i & 1][idx + (i >> 1) * 28]); + break; case CODING_8BPS | CODING_MONO: - for (uint8_t i = 0; i < 4; i++) - { - decode_8bit_xa_unit(0, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); - m_dmadac[0]->transfer(0, 1, 1, 28, samples); - m_dmadac[1]->transfer(0, 1, 1, 28, samples); - } - return; + decode_8bit_xa_unit(0, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], &m_samples[0][idx + i * 28]); + break; case CODING_8BPS | CODING_STEREO: - for (uint8_t i = 0; i < 4; i++) - { - decode_8bit_xa_unit(i & 1, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); - m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); - } - return; + decode_8bit_xa_unit(i & 1, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], &m_samples[i & 1][idx + (i >> 1) * 28]); + break; + } } } diff --git a/src/mame/machine/cdicdic.h b/src/mame/machine/cdicdic.h index 5f377577..f959c697 100644 --- a/src/mame/machine/cdicdic.h +++ b/src/mame/machine/cdicdic.h @@ -31,6 +31,7 @@ #include "sound/cdda.h" #include "sound/dmadac.h" #include "cdrom.h" +#include //************************************************************************** // TYPE DEFINITIONS @@ -204,6 +205,7 @@ class cdicdic_device : public device_t 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); diff --git a/src/mame/machine/cdislavehle.cpp b/src/mame/machine/cdislavehle.cpp index ae6c1629..8c5c57f5 100644 --- a/src/mame/machine/cdislavehle.cpp +++ b/src/mame/machine/cdislavehle.cpp @@ -20,6 +20,8 @@ #include +#include + #define LOG_IRQS (1 << 0) #define LOG_COMMANDS (1 << 1) #define LOG_READS (1 << 2) @@ -160,8 +162,6 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) case 0: if (m_in_index) { - m_in_buf[m_in_index] = data & 0x00ff; - m_in_index++; if (m_in_index == m_in_count) { switch (m_in_buf[0]) @@ -262,6 +262,7 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) { case 0x82: // Mute Audio { + LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Mute Audio (0x82)\n", offset); m_dmadac[0]->set_volume(0); m_dmadac[1]->set_volume(0); m_in_index = 0; @@ -271,6 +272,7 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } case 0x83: // Unmute Audio { + LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Unmute Audio (0x83)\n", offset); m_dmadac[0]->set_volume(0x100); m_dmadac[1]->set_volume(0x100); m_in_index = 0; @@ -283,9 +285,11 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) m_in_count = 5; break; case 0xf0: // Set Front Panel LCD + LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Set Front Panel LCD (0xf0)\n", offset); m_in_count = 17; break; default: + LOGMASKED(LOG_COMMANDS | LOG_UNKNOWNS, "slave_w: Channel %d: Unknown register: %02x\n", offset, data & 0x00ff); memset(m_in_buf, 0, 17); m_in_index = 0; m_in_count = 0; @@ -293,14 +297,15 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } } break; + case 3: - if (m_in_index > 1) - { - if (m_in_index == m_in_count) - { - switch (m_in_buf[0]) - { - case 0xb0: // Request Disc Status + if (m_in_index > 1) + { + if (m_in_index == m_in_count) + { + switch (m_in_buf[0]) + { + case 0xb0: // Request Disc Status prepare_readback(attotime::from_hz(4), 3, 4, 0xb0, 0x00, 0x02, 0x15, 0xb0); break; //case 0xb1: // Request Disc Base @@ -371,6 +376,7 @@ cdislave_hle_device::cdislave_hle_device(const machine_config &mconfig, const ch : device_t(mconfig, CDI_SLAVE_HLE, tag, owner, clock) , m_int_callback(*this) , m_dmadac(*this, ":dac%u", 1U) + , m_atten_w(*this) , m_mousex(*this, "MOUSEX") , m_mousey(*this, "MOUSEY") , m_mousebtn(*this, "MOUSEBTN") diff --git a/src/mame/machine/cdislavehle.h b/src/mame/machine/cdislavehle.h index f4e31d7d..85589a00 100644 --- a/src/mame/machine/cdislavehle.h +++ b/src/mame/machine/cdislavehle.h @@ -21,6 +21,7 @@ #pragma once #include "sound/dmadac.h" +#include //************************************************************************** // TYPE DEFINITIONS @@ -35,6 +36,7 @@ class cdislave_hle_device : public device_t cdislave_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); auto int_callback() { return m_int_callback.bind(); } + auto atten_callback() { return m_atten_w.bind(); } // external callbacks DECLARE_INPUT_CHANGED_MEMBER( mouse_update ); @@ -61,6 +63,7 @@ class cdislave_hle_device : public device_t devcb_write_line m_int_callback; required_device_array m_dmadac; + devcb_write32 m_atten_w; required_ioport m_mousex; required_ioport m_mousey; diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 023c1e8c..527054af 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -12,19 +12,5 @@ @source:cdi.cpp cdi490a // cdi910 // -cdibios // Base unit cdimono1 // Philips CD-i model 200 (Mono-I board, PAL) cdimono2 // Philips CD-i model 220 (Mono-II board, NTSC) -quizard // (c) TAB Austria 199? -quizard_10 // (c) TAB Austria 1996 -quizard_12 // (c) TAB Austria 1996 -quizard_17 // (c) TAB Austria 1996 -quizard2 // (c) TAB Austria 1995 -quizard2_22 // (c) TAB Austria 199? -quizard3 // (c) TAB Austria 1996 -quizard3_32 // (c) TAB Austria 1996 -quizard3a // (c) TAB Austria 1996 -quizard4 // (c) TAB Austria 1998 -quizard4_40 // (c) TAB Austria 1997 -quizard4_41 // (c) TAB Austria 1998 -quizard4cz // (c) TAB Austria 1998 From 64d754fb60c392a240ff34e38a62ee9a03a968bd Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:31:23 -0600 Subject: [PATCH 03/47] Revert cdicdic and cdislavehle to original state. --- src/mame/machine/cdicdic.cpp | 113 +++++++++++++------------------ src/mame/machine/cdicdic.h | 7 +- src/mame/machine/cdislavehle.cpp | 67 +++++++++--------- src/mame/machine/cdislavehle.h | 3 - 4 files changed, 84 insertions(+), 106 deletions(-) diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp index 82fb990e..1aea9112 100644 --- a/src/mame/machine/cdicdic.cpp +++ b/src/mame/machine/cdicdic.cpp @@ -28,15 +28,15 @@ #include "romload.h" #include "sound/cdda.h" -#define LOG_DECODES (1U << 1) -#define LOG_SAMPLES (1U << 2) -#define LOG_COMMANDS (1U << 3) -#define LOG_SECTORS (1U << 4) -#define LOG_IRQS (1U << 5) -#define LOG_READS (1U << 6) -#define LOG_WRITES (1U << 7) -#define LOG_UNKNOWNS (1U << 8) -#define LOG_RAM (1U << 9) +#define LOG_DECODES (1 << 1) +#define LOG_SAMPLES (1 << 2) +#define LOG_COMMANDS (1 << 3) +#define LOG_SECTORS (1 << 4) +#define LOG_IRQS (1 << 5) +#define LOG_READS (1 << 6) +#define LOG_WRITES (1 << 7) +#define LOG_UNKNOWNS (1 << 8) +#define LOG_RAM (1 << 9) #define LOG_ALL (LOG_DECODES | LOG_SAMPLES | LOG_COMMANDS | LOG_SECTORS | LOG_IRQS | LOG_READS | LOG_WRITES | LOG_UNKNOWNS | LOG_RAM) #define VERBOSE (0) @@ -515,35 +515,50 @@ void cdicdic_device::play_raw_group(const uint8_t *data) m_dmadac[1]->transfer(0, 1, 1, 28, samples); } -void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data, const uint16_t idx) +void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data) { - static const uint16_t s_4bit_header_offsets[8] = { 4, 5, 6, 7, 12, 13, 14, 15 }; - static const uint16_t s_8bit_header_offsets[4] = { 4, 5, 6, 7 }; + static const uint16_t s_4bit_header_offsets[8] = { 0, 1, 2, 3, 8, 9, 10, 11 }; + static const uint16_t s_8bit_header_offsets[4] = { 0, 1, 2, 3 }; static const uint16_t s_4bit_data_offsets[8] = { 16, 16, 17, 17, 18, 18, 19, 19 }; static const uint16_t s_8bit_data_offsets[4] = { 16, 17, 18, 19 }; - const uint8_t num_samples = coding & CODING_8BPS ? 4 : 8; + int16_t samples[28]; - for (uint8_t i = 0; i < num_samples; i++) - { switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) { case CODING_4BPS | CODING_MONO: - decode_4bit_xa_unit(0, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, &m_samples[0][idx + i * 28]); - break; + for (uint8_t i = 0; i < 8; i++) + { + decode_4bit_xa_unit(0, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); + m_dmadac[0]->transfer(0, 1, 1, 28, samples); + m_dmadac[1]->transfer(0, 1, 1, 28, samples); + } + return; case CODING_4BPS | CODING_STEREO: - decode_4bit_xa_unit(i & 1, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, &m_samples[i & 1][idx + (i >> 1) * 28]); - break; + for (uint8_t i = 0; i < 8; i++) + { + decode_4bit_xa_unit(i & 1, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); + m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); + } + return; case CODING_8BPS | CODING_MONO: - decode_8bit_xa_unit(0, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], &m_samples[0][idx + i * 28]); - break; + for (uint8_t i = 0; i < 4; i++) + { + decode_8bit_xa_unit(0, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); + m_dmadac[0]->transfer(0, 1, 1, 28, samples); + m_dmadac[1]->transfer(0, 1, 1, 28, samples); + } + return; case CODING_8BPS | CODING_STEREO: - decode_8bit_xa_unit(i & 1, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], &m_samples[i & 1][idx + (i >> 1) * 28]); - break; - } + for (uint8_t i = 0; i < 4; i++) + { + decode_8bit_xa_unit(i & 1, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); + m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); + } + return; } } @@ -554,15 +569,15 @@ void cdicdic_device::play_cdda_sector(const uint8_t *data) m_dmadac[0]->set_volume(0x100); m_dmadac[1]->set_volume(0x100); - const uint16_t NUM_SAMPLES = SECTOR_SIZE / 4; - for (uint16_t i = 0; i < NUM_SAMPLES; i++) + int16_t samples[2][2352/4]; + for (uint16_t i = 0; i < 2352/4; i++) { - m_samples[0][i] = (int16_t)((data[(i * 4) + 1] << 8) | data[(i * 4) + 0]); - m_samples[1][i] = (int16_t)((data[(i * 4) + 3] << 8) | data[(i * 4) + 2]); + 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, NUM_SAMPLES, &m_samples[0][0]); - m_dmadac[1]->transfer(0, 1, 1, NUM_SAMPLES, &m_samples[1][0]); + 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) @@ -616,10 +631,6 @@ void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data m_dmadac[0]->set_volume(0x100); m_dmadac[1]->set_volume(0x100); - const uint16_t bps = ((coding & CODING_BPS_MASK) == CODING_8BPS); - const uint16_t chan = ((coding & CODING_CHAN_MASK) == CODING_STEREO); - const uint16_t num_samples = 8 >> (bps + chan); - if (bits == 16 && channels == 2) { for (uint16_t i = 0; i < SECTOR_AUDIO_SIZE; i += 112, data += 112) @@ -629,29 +640,9 @@ void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data } else { - uint16_t offset = 0; for (uint16_t i = 0; i < SECTOR_AUDIO_SIZE; i += 128, data += 128) { - play_xa_group(coding, data, offset); - offset += 28 * num_samples; - } - - int16_t sampleL = 0, sampleR = 0, outL = 0, outR = 0; - // Attenuation is logarithmic (decibels). - // Floats are not chip accurate, but the formula is correct. - float scaleLL = powf(10.0f, -m_atten[0] / 20.0f); - float scaleLR = powf(10.0f, -m_atten[1] / 20.0f); - float scaleRR = powf(10.0f, -m_atten[2] / 20.0f); - float scaleRL = powf(10.0f, -m_atten[3] / 20.0f); - for (uint16_t i = 0; i < 18 * 28 * num_samples; i++) - { - sampleL = m_samples[0][i]; - sampleR = m_samples[coding & CODING_STEREO][i]; - - outL = (sampleL * scaleLL + sampleR * scaleRL) * 0.25; - outR = (sampleL * scaleLR + sampleR * scaleRR) * 0.25; - m_dmadac[0]->transfer(0, 1, 1, 1, &outL); - m_dmadac[1]->transfer(0, 1, 1, 1, &outR); + play_xa_group(coding, data); } } } @@ -1287,14 +1278,6 @@ void cdicdic_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask) } } - -void cdicdic_device::atten_w(uint32_t state) { - m_atten[0] = (state & 0xFF000000) >> 24; - m_atten[1] = (state & 0x00FF0000) >> 16; - m_atten[2] = (state & 0x0000FF00) >> 8; - m_atten[3] = (state & 0x000000FF); -} - void cdicdic_device::init_disc_read(uint8_t disc_mode) { m_disc_command = m_command; @@ -1442,7 +1425,6 @@ void cdicdic_device::device_start() save_item(NAME(m_decoding_audio_map)); save_item(NAME(m_decode_addr)); - save_item(NAME(m_atten)); save_item(NAME(m_xa_last)); m_audio_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdicdic_device::audio_tick), this)); @@ -1501,8 +1483,7 @@ void cdicdic_device::device_reset() m_dmadac[0]->enable(1); m_dmadac[1]->enable(1); - std::fill_n(m_atten, 4, 0); - std::fill_n(m_xa_last, 4, 0); + std::fill_n(&m_xa_last[0], 4, 0); } void cdicdic_device::ram_w(offs_t offset, uint16_t data, uint16_t mem_mask) diff --git a/src/mame/machine/cdicdic.h b/src/mame/machine/cdicdic.h index f959c697..9075b77c 100644 --- a/src/mame/machine/cdicdic.h +++ b/src/mame/machine/cdicdic.h @@ -31,7 +31,6 @@ #include "sound/cdda.h" #include "sound/dmadac.h" #include "cdrom.h" -#include //************************************************************************** // TYPE DEFINITIONS @@ -60,7 +59,6 @@ class cdicdic_device : public device_t void ram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); uint8_t intack_r(); - void atten_w(uint32_t state); protected: // device-level overrides @@ -191,8 +189,6 @@ class cdicdic_device : public device_t bool m_decoding_audio_map; uint16_t m_decode_addr; - // Audio Attenuation (L->L, L->R, R->R, R->L) - uint8_t m_atten[4]; int16_t m_xa_last[4]; std::unique_ptr m_ram; std::unique_ptr m_samples[2]; @@ -200,12 +196,11 @@ class cdicdic_device : public device_t void decode_8bit_xa_unit(int channel, uint8_t param, const uint8_t *data, int16_t *out_buffer); void decode_4bit_xa_unit(int channel, uint8_t param, const uint8_t *data, uint8_t shift, int16_t *out_buffer); void play_raw_group(const uint8_t *data); - void play_xa_group(const uint8_t coding, const uint8_t *data, const uint16_t idx); + 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); diff --git a/src/mame/machine/cdislavehle.cpp b/src/mame/machine/cdislavehle.cpp index 8c5c57f5..769f9df2 100644 --- a/src/mame/machine/cdislavehle.cpp +++ b/src/mame/machine/cdislavehle.cpp @@ -20,8 +20,6 @@ #include -#include - #define LOG_IRQS (1 << 0) #define LOG_COMMANDS (1 << 1) #define LOG_READS (1 << 2) @@ -162,6 +160,8 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) case 0: if (m_in_index) { + m_in_buf[m_in_index] = data & 0x00ff; + m_in_index++; if (m_in_index == m_in_count) { switch (m_in_buf[0]) @@ -205,16 +205,24 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } break; case 1: - if (m_in_index > 1) + if (m_in_index) { + m_in_buf[m_in_index] = data & 0x00ff; + m_in_index++; if (m_in_index == m_in_count) { switch (m_in_buf[0]) { case 0xf0: // Set Front Panel LCD memcpy(m_lcd_state, m_in_buf + 1, 16); + memset(m_in_buf, 0, 17); + m_in_index = 0; + m_in_count = 0; break; default: + memset(m_in_buf, 0, 17); + m_in_index = 0; + m_in_count = 0; break; } } @@ -232,18 +240,14 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } break; case 2: - if (m_in_index > 1) + if (m_in_index) { + m_in_buf[m_in_index] = data & 0x00ff; + m_in_index++; if (m_in_index == m_in_count) { switch (m_in_buf[0]) { - case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: - m_atten_w((((u32)m_in_buf[1]) << 24) | (((u32)m_in_buf[2]) << 16) | (((u32)m_in_buf[3]) << 8) | (((u32)m_in_buf[4]))); - m_in_index = 0; - m_in_count = 0; - break; case 0xf0: // Set Front Panel LCD memset(m_in_buf + 1, 0, 16); m_in_count = 17; @@ -258,11 +262,12 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } else { + m_in_buf[m_in_index] = data & 0x00ff; + m_in_index++; switch (data & 0x00ff) { case 0x82: // Mute Audio { - LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Mute Audio (0x82)\n", offset); m_dmadac[0]->set_volume(0); m_dmadac[1]->set_volume(0); m_in_index = 0; @@ -272,24 +277,16 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } case 0x83: // Unmute Audio { - LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Unmute Audio (0x83)\n", offset); m_dmadac[0]->set_volume(0x100); m_dmadac[1]->set_volume(0x100); m_in_index = 0; m_in_count = 0; break; } - case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: - case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: - LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Set Attenuation Audio\n", offset); - m_in_count = 5; - break; case 0xf0: // Set Front Panel LCD - LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Set Front Panel LCD (0xf0)\n", offset); m_in_count = 17; break; default: - LOGMASKED(LOG_COMMANDS | LOG_UNKNOWNS, "slave_w: Channel %d: Unknown register: %02x\n", offset, data & 0x00ff); memset(m_in_buf, 0, 17); m_in_index = 0; m_in_count = 0; @@ -297,30 +294,39 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) } } break; - case 3: - if (m_in_index > 1) - { - if (m_in_index == m_in_count) - { - switch (m_in_buf[0]) - { - case 0xb0: // Request Disc Status + if (m_in_index) + { + m_in_buf[m_in_index] = data & 0x00ff; + m_in_index++; + if (m_in_index == m_in_count) + { + switch (m_in_buf[0]) + { + case 0xb0: // Request Disc Status + memset(m_in_buf, 0, 17); + m_in_index = 0; + m_in_count = 0; prepare_readback(attotime::from_hz(4), 3, 4, 0xb0, 0x00, 0x02, 0x15, 0xb0); break; //case 0xb1: // Request Disc Base + //memset(m_in_buf, 0, 17); + //m_in_index = 0; + //m_in_count = 0; //prepare_readback(attotime::from_hz(10000), 3, 4, 0xb1, 0x00, 0x00, 0x00, 0xb1); //break; default: + memset(m_in_buf, 0, 17); + m_in_index = 0; + m_in_count = 0; break; } - memset(m_in_buf, 0, 17); - m_in_index = 0; - m_in_count = 0; } } else { + m_in_buf[m_in_index] = data & 0x00ff; + m_in_index++; switch (data & 0x00ff) { case 0xb0: // Request Disc Status @@ -376,7 +382,6 @@ cdislave_hle_device::cdislave_hle_device(const machine_config &mconfig, const ch : device_t(mconfig, CDI_SLAVE_HLE, tag, owner, clock) , m_int_callback(*this) , m_dmadac(*this, ":dac%u", 1U) - , m_atten_w(*this) , m_mousex(*this, "MOUSEX") , m_mousey(*this, "MOUSEY") , m_mousebtn(*this, "MOUSEBTN") diff --git a/src/mame/machine/cdislavehle.h b/src/mame/machine/cdislavehle.h index 85589a00..f4e31d7d 100644 --- a/src/mame/machine/cdislavehle.h +++ b/src/mame/machine/cdislavehle.h @@ -21,7 +21,6 @@ #pragma once #include "sound/dmadac.h" -#include //************************************************************************** // TYPE DEFINITIONS @@ -36,7 +35,6 @@ class cdislave_hle_device : public device_t cdislave_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); auto int_callback() { return m_int_callback.bind(); } - auto atten_callback() { return m_atten_w.bind(); } // external callbacks DECLARE_INPUT_CHANGED_MEMBER( mouse_update ); @@ -63,7 +61,6 @@ class cdislave_hle_device : public device_t devcb_write_line m_int_callback; required_device_array m_dmadac; - devcb_write32 m_atten_w; required_ioport m_mousex; required_ioport m_mousey; From 65a19e584e6a9a7db7405c78251b1f6c82103c46 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:32:25 -0600 Subject: [PATCH 04/47] Backport fix for Hotel Mario. --- src/mame/machine/cdicdic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp index 1aea9112..4b8fbc99 100644 --- a/src/mame/machine/cdicdic.cpp +++ b/src/mame/machine/cdicdic.cpp @@ -695,7 +695,7 @@ void cdicdic_device::process_audio_map() else { m_decode_addr = 0xffff; - m_audio_sector_counter = m_audio_format_sectors; + m_audio_sector_counter = 0; } if (was_decoding) From 25b4ef5deccb4663ecc0b4d82e3da8534dde8657 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:35:57 -0600 Subject: [PATCH 05/47] Backport reworked play_xa_group. --- src/mame/machine/cdicdic.cpp | 70 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp index 4b8fbc99..8df448bc 100644 --- a/src/mame/machine/cdicdic.cpp +++ b/src/mame/machine/cdicdic.cpp @@ -517,48 +517,40 @@ void cdicdic_device::play_raw_group(const uint8_t *data) void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data) { - static const uint16_t s_4bit_header_offsets[8] = { 0, 1, 2, 3, 8, 9, 10, 11 }; - static const uint16_t s_8bit_header_offsets[4] = { 0, 1, 2, 3 }; - static const uint16_t s_4bit_data_offsets[8] = { 16, 16, 17, 17, 18, 18, 19, 19 }; - static const uint16_t s_8bit_data_offsets[4] = { 16, 17, 18, 19 }; + static const uint16_t HEADER_OFFSET_4BIT[8] = { 4, 5, 6, 7, 12, 13, 14, 15 }; + static const uint16_t HEADER_OFFSET_8BIT[4] = { 4, 5, 6, 7 }; + static const uint16_t DATA_OFFSET_4BIT[8] = { 16, 16, 17, 17, 18, 18, 19, 19 }; + static const uint16_t DATA_OFFSET_8BIT[4] = { 16, 17, 18, 19 }; int16_t samples[28]; + uint8_t num_samples = coding & CODING_8BPS ? 4 : 8; - switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) + for (uint8_t i = 0; i < num_samples; i++) { + switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) + { case CODING_4BPS | CODING_MONO: - for (uint8_t i = 0; i < 8; i++) - { - decode_4bit_xa_unit(0, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); - m_dmadac[0]->transfer(0, 1, 1, 28, samples); - m_dmadac[1]->transfer(0, 1, 1, 28, samples); - } - return; + decode_4bit_xa_unit(0, data[HEADER_OFFSET_4BIT[i]], data + DATA_OFFSET_4BIT[i], (i & 1) ? 4 : 0, samples); + m_dmadac[0]->transfer(0, 1, 1, 28, samples); + m_dmadac[1]->transfer(0, 1, 1, 28, samples); + break; case CODING_4BPS | CODING_STEREO: - for (uint8_t i = 0; i < 8; i++) - { - decode_4bit_xa_unit(i & 1, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); - m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); - } - return; + decode_4bit_xa_unit(i & 1, data[HEADER_OFFSET_4BIT[i]], data + DATA_OFFSET_4BIT[i], (i & 1) ? 4 : 0, samples); + m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); + break; case CODING_8BPS | CODING_MONO: - for (uint8_t i = 0; i < 4; i++) - { - decode_8bit_xa_unit(0, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); - m_dmadac[0]->transfer(0, 1, 1, 28, samples); - m_dmadac[1]->transfer(0, 1, 1, 28, samples); - } - return; + decode_8bit_xa_unit(0, data[HEADER_OFFSET_8BIT[i]], data + DATA_OFFSET_8BIT[i], samples); + m_dmadac[0]->transfer(0, 1, 1, 28, samples); + m_dmadac[1]->transfer(0, 1, 1, 28, samples); + break; case CODING_8BPS | CODING_STEREO: - for (uint8_t i = 0; i < 4; i++) - { - decode_8bit_xa_unit(i & 1, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); - m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); - } - return; + decode_8bit_xa_unit(i & 1, data[HEADER_OFFSET_8BIT[i]], data + DATA_OFFSET_8BIT[i], samples); + m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); + break; + } } } @@ -569,21 +561,27 @@ void cdicdic_device::play_cdda_sector(const uint8_t *data) 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++) + const int16_t NUM_SAMPLES = SECTOR_SIZE / 4; + int16_t samples[2][NUM_SAMPLES]; + for (uint16_t i = 0; i < NUM_SAMPLES; 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]); + m_dmadac[0]->transfer(0, 1, 1, NUM_SAMPLES, samples[0]); + m_dmadac[1]->transfer(0, 1, 1, NUM_SAMPLES, 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) - return; + { + } + + if (coding & 0x40) + { + } int channels = 2; //offs_t buffer_length = 1; From db7a2ae11d8faf5c53b6edfae47e5327491e4241 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:38:15 -0600 Subject: [PATCH 06/47] Increment disc_spinup_counter from 1 to 6, reworked m_xa_last. --- src/mame/machine/cdicdic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp index 8df448bc..1fac7fb8 100644 --- a/src/mame/machine/cdicdic.cpp +++ b/src/mame/machine/cdicdic.cpp @@ -1281,7 +1281,7 @@ void cdicdic_device::init_disc_read(uint8_t disc_mode) m_disc_command = m_command; m_disc_mode = disc_mode; m_curr_lba = lba_from_time(); - m_disc_spinup_counter = 1; + m_disc_spinup_counter = 6; } void cdicdic_device::cancel_disc_read() From bb21d44199226b9c95f836ba3c7cac0c4d4f9992 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:38:29 -0600 Subject: [PATCH 07/47] Reworked m_xa_last. --- src/mame/machine/cdicdic.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mame/machine/cdicdic.cpp b/src/mame/machine/cdicdic.cpp index 1fac7fb8..7c8cfd92 100644 --- a/src/mame/machine/cdicdic.cpp +++ b/src/mame/machine/cdicdic.cpp @@ -1250,7 +1250,7 @@ void cdicdic_device::regs_w(offs_t offset, uint16_t data, uint16_t mem_mask) m_audio_format_sectors = 0; m_audio_sector_counter = 1; m_decoding_audio_map = true; - std::fill_n(&m_xa_last[0], 4, 0); + std::fill_n(m_xa_last, 4, 0); } break; From c547220f6300b93cff9e448ae484302f9e466576 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:52:48 -0600 Subject: [PATCH 08/47] Remove references to audio attenuation. --- src/mame/drivers/cdi.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp index 887a44f4..ea59656a 100644 --- a/src/mame/drivers/cdi.cpp +++ b/src/mame/drivers/cdi.cpp @@ -308,7 +308,6 @@ void cdi_state::cdimono1_base(machine_config &config) CDI_SLAVE_HLE(config, m_slave_hle, 0); m_slave_hle->int_callback().set(m_maincpu, FUNC(scc68070_device::in2_w)); - m_slave_hle->atten_callback().set(m_cdic, FUNC(cdicdic_device::atten_w)); CDROM(config, m_cdrom); m_cdrom->set_interface("cdrom"); From 695dc69548990491c8fd1aa2334b0c34828443e9 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:53:56 -0600 Subject: [PATCH 09/47] Include cstdint in osdlib.h --- src/osd/modules/lib/osdlib.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/osd/modules/lib/osdlib.h b/src/osd/modules/lib/osdlib.h index 4a06b705..361da9b4 100644 --- a/src/osd/modules/lib/osdlib.h +++ b/src/osd/modules/lib/osdlib.h @@ -21,6 +21,7 @@ #include #include #include +#include /*----------------------------------------------------------------------------- osd_process_kill: kill the current process From 2d176c8e678c67540dedb5955ff6c95d0516ee16 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:56:25 -0600 Subject: [PATCH 10/47] Set interface to cdrom in cdimono1 --- src/mame/drivers/cdi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp index ea59656a..1ae5075d 100644 --- a/src/mame/drivers/cdi.cpp +++ b/src/mame/drivers/cdi.cpp @@ -309,8 +309,8 @@ void cdi_state::cdimono1_base(machine_config &config) CDI_SLAVE_HLE(config, m_slave_hle, 0); m_slave_hle->int_callback().set(m_maincpu, FUNC(scc68070_device::in2_w)); - CDROM(config, m_cdrom); - m_cdrom->set_interface("cdrom"); + CDROM(config, "cdrom").set_interface("cdi_cdrom"); + SOFTWARE_LIST(config, "cd_list").set_original("cdi").set_filter("!DVC"); /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); From 0d75bea60536aa7a9f6638bd6f5d8f866ed61710 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 12:59:51 -0600 Subject: [PATCH 11/47] Revert CD-i driver to previous state, without Quizard references. --- src/mame/drivers/cdi.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp index 1ae5075d..2d220fd2 100644 --- a/src/mame/drivers/cdi.cpp +++ b/src/mame/drivers/cdi.cpp @@ -171,6 +171,7 @@ uint16_t cdi_state::main_rom_r(offs_t offset) return m_main_rom[offset]; } + /********************** * BERR Handling * **********************/ @@ -309,9 +310,6 @@ void cdi_state::cdimono1_base(machine_config &config) CDI_SLAVE_HLE(config, m_slave_hle, 0); m_slave_hle->int_callback().set(m_maincpu, FUNC(scc68070_device::in2_w)); - CDROM(config, "cdrom").set_interface("cdi_cdrom"); - SOFTWARE_LIST(config, "cd_list").set_original("cdi").set_filter("!DVC"); - /* sound hardware */ SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); @@ -483,6 +481,7 @@ ROM_START( cdi490a ) ROM_LOAD( "vmpega.rom", 0x0000, 0x40000, CRC(db264e8b) SHA1(be407fbc102f1731a0862554855e963e5a47c17b) ) ROM_END + /************************* * Game driver(s) * *************************/ From 3ed064eddacbe34df18b7860a7d803369ad2d2f9 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 13:06:39 -0600 Subject: [PATCH 12/47] New mcd212 driver. --- src/emu/device.h | 2 +- src/mame/video/mcd212.cpp | 1113 +++++++++++++++---------------------- src/mame/video/mcd212.h | 169 +++--- 3 files changed, 552 insertions(+), 732 deletions(-) diff --git a/src/emu/device.h b/src/emu/device.h index 77c12cb2..90725311 100644 --- a/src/emu/device.h +++ b/src/emu/device.h @@ -705,7 +705,7 @@ class device_t : public delegate_late_bind u64 attotime_to_clocks(const attotime &duration) const noexcept; // timer interfaces - emu_timer *timer_alloc(device_timer_id id = 0, void *ptr = nullptr); + template emu_timer *timer_alloc(T &&... args); void timer_set(const attotime &duration, device_timer_id id = 0, int param = 0, void *ptr = nullptr); void synchronize(device_timer_id id = 0, int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, id, param, ptr); } void timer_expired(emu_timer &timer, device_timer_id id, int param, void *ptr) { device_timer(timer, id, param, ptr); } diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index bf1436bb..2101a6d1 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -6,7 +6,7 @@ CD-i MCD212 Video Decoder and System Controller emulation ------------------- - written by Ryan Holtz + written by Ryan Holtz, Vincent.Halver ******************************************************************************* @@ -17,12 +17,12 @@ TODO: -- Unknown yet. +- QHY DYUV Image Decoder *******************************************************************************/ #include "emu.h" -#include "video/mcd212.h" +#include "mcd212.h" #include "screen.h" #define LOG_UNKNOWNS (1U << 1) @@ -42,178 +42,71 @@ // device type definition DEFINE_DEVICE_TYPE(MCD212, mcd212_device, "mcd212", "MCD212 VDSC") -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t region_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t matte_idx) { - return (uint8_t)((m_region_control[region_idx] & RC_WF) >> RC_WF_SHIFT); + return (uint8_t)((m_matte_control[matte_idx] & MC_WF) >> MC_WF_SHIFT); } -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_region_op(const uint32_t region_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_matte_op(const uint32_t matte_idx) { - return (m_region_control[region_idx] & RC_OP) >> RC_OP_SHIFT; + return (m_matte_control[matte_idx] & MC_OP) >> MC_OP_SHIFT; } -void mcd212_device::update_region_arrays() +void mcd212_device::update_matte_arrays() { - bool latched_rf[2] { false, false }; - uint8_t latched_wfa = m_weight_factor[0][0]; - uint8_t latched_wfb = m_weight_factor[1][0]; const int width = get_screen_width(); + const int num_mattes = BIT(m_image_coding_method, ICM_NM_BIT) ? 2 : 1; - if (BIT(m_image_coding_method, ICM_NR_BIT)) - { - if (get_region_op(0) == 0 && get_region_op(4) == 0) - { - 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; - } + bool latched_mf[2]{ false, false }; + uint8_t latched_wf[2] = { m_weight_factor[0][0], m_weight_factor[1][0] }; + int matte_idx[2] = { 0, 4 }; - for (int x = 0; x < width; x++) + for (int x = 0; x < width; x++) + { + for (int matte = 0; matte < num_mattes; matte++) { - for (int flag = 0; flag < 2; flag++) + const int max_matte_id = ((num_mattes == 2) ? 4 : 8) + (matte ? 4 : 0); + if (matte_idx[matte] >= max_matte_id) { - for (int region = 0; region < 4; region++) - { - 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 == (region_ctrl & RC_X)) - { - switch (region_op) - { - case 0: // End of region control for line - break; - case 1: - case 2: - case 3: // Not used - break; - case 4: // Change weight of plane A - latched_wfa = get_weight_factor(region_idx); - break; - case 5: // Not used - break; - case 6: // Change weight of plane B - latched_wfb = get_weight_factor(region_idx); - break; - case 7: // Not used - break; - case 8: // Reset region flag - latched_rf[flag] = false; - break; - case 9: // Set region flag - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 13: // Set region flag and change weight of plane A - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 15: // Set region flag and change weight of plane B - latched_wfb = get_weight_factor(region_idx); - latched_rf[flag] = true; - break; - } - } - } + continue; } - 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 - { - int region_idx = 0; - for (int x = 0; x < width; x++) - { - if (region_idx < 8) + const uint32_t matte_ctrl = m_matte_control[matte_idx[matte]]; + + if (x == (matte_ctrl & MC_X)) { - 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) + const uint32_t matte_op = get_matte_op(matte_idx[matte]); + const int flag = (num_mattes == 2) ? matte : BIT(m_matte_control[matte_idx[matte]], MC_MF_BIT); + // See 5.10.2 Matte Commands. Changing the MF-bit inside a line is undefined. Greenbook says don't do it. + // Console validation shows the 220 reads and uses this value anyway. + switch (matte_op) { - 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, latched_rf[0]); - std::fill_n(m_region_flag[1] + x, std::size(m_region_flag[1]) - x, latched_rf[1]); - return; - } - if (x == (region_ctrl & RC_X)) - { - switch (region_op) - { - case 0: // End of region control for line - break; - case 1: - case 2: - case 3: // Not used - break; - case 4: // Change weight of plane A - latched_wfa = get_weight_factor(region_idx); - break; - case 5: // Not used - break; - case 6: // Change weight of plane B - latched_wfb = get_weight_factor(region_idx); - break; - case 7: // Not used - break; - case 8: // Reset region flag - latched_rf[flag] = false; - break; - case 9: // Set region flag - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 13: // Set region flag and change weight of plane A - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 15: // Set region flag and change weight of plane B - latched_wfb = get_weight_factor(region_idx); - latched_rf[flag] = true; - break; - } - region_idx++; + case 0: // Disregard all commands in higher registers. See 5.10.2 + matte_idx[matte] = 8; + break; + case 1: case 2: case 3: case 5: case 7: case 10: case 11: // Not used + break; + case 4: case 6: // Change weight of plane (A or B) + latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); + break; + case 8: case 9: // (Reset or Set) matte flag + latched_mf[flag] = BIT(matte_op, 0); + break; + case 12: case 13: case 14: case 15: // Change weight of plane (A or B) and (Reset or Set) matte flag + latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); + latched_mf[flag] = BIT(matte_op, 0); + break; } + matte_idx[matte]++; } - 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_weight_factor[0][x] = latched_wf[0]; + m_weight_factor[1][x] = latched_wf[1]; + m_matte_flag[0][x] = latched_mf[0]; + m_matte_flag[1][x] = latched_mf[1]; } } -template +template void mcd212_device::set_register(uint8_t reg, uint32_t value) { switch (reg) @@ -227,86 +120,100 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) 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: { - const uint8_t clut_index = m_clut_bank[Channel] * 0x40 + (reg - 0x80); + const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); + LOGMASKED(LOG_CLUT, "%s: Path %d: CLUT[%d] = %08x\n", machine().describe_context(), Path, clut_index, value); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Path 0: Image Coding Method = %08x\n", machine().describe_context(), value); m_image_coding_method = value; } break; case 0xc1: // Transparency Control - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Transparency Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_transparency_control = value; } break; case 0xc2: // Plane Order - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Plane Order = %08x\n", machine().describe_context(), screen().vpos(), value & 7); m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register - m_clut_bank[Channel] = Channel ? (2 | (value & 0x00000001)) : (value & 0x00000003); + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: CLUT Bank Register = %08x\n", machine().describe_context(), screen().vpos(), Path, value & 3); + m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Position = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_position = value; } break; case 0xce: // Cursor Control - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_control = value; } break; case 0xcf: // Cursor Pattern - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 + case 0xd0: // matte Control 0-7 case 0xd1: case 0xd2: case 0xd3: @@ -314,79 +221,85 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xd5: case 0xd6: case 0xd7: - m_region_control[reg & 7] = value; - update_region_arrays(); + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: matte Control %d = %08x\n", machine().describe_context(), screen().vpos(), Path, reg & 7, value); + m_matte_control[reg & 7] = value; + update_matte_arrays(); break; case 0xd8: // Backdrop Color - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Weight Factor A = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[0][0] = (uint8_t)value; - update_region_arrays(); + update_matte_arrays(); } break; case 0xdc: // Weight Factor B - if (Channel == 1) + if (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 1: Weight Factor B = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[1][0] = (uint8_t)value; - update_region_arrays(); + update_matte_arrays(); } break; } } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr() { - return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel]; + return ((m_dcr[Path] & 0x3f) << 16) | m_vsr[Path]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_vsr(uint32_t value) { - m_vsr[Channel] = value & 0x0000ffff; - m_dcr[Channel] &= 0xffc0; - m_dcr[Channel] |= (value >> 16) & 0x003f; + m_vsr[Path] = value & 0x0000ffff; + m_dcr[Path] &= 0xffc0; + m_dcr[Path] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_dcp(uint32_t value) { - m_dcp[Channel] = value & 0x0000ffff; - m_ddr[Channel] &= 0xffc0; - m_ddr[Channel] |= (value >> 16) & 0x003f; + m_dcp[Path] = value & 0x0000ffff; + m_ddr[Path] &= 0xffc0; + m_ddr[Path] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_dcp() { - return ((m_ddr[Channel] & 0x3f) << 16) | m_dcp[Channel]; + return ((m_ddr[Path] & 0x3f) << 16) | m_dcp[Path]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t value) { - m_ddr[Channel] &= 0xf0ff; - m_ddr[Channel] |= (value & 0x0f) << 8; - m_dcr[Channel] &= 0xf7ff; - m_dcr[Channel] |= (value & 0x10) << 7; + m_ddr[Path] &= 0xf0ff; + m_ddr[Path] |= (value & 0x0f) << 8; + m_dcr[Path] &= 0xf7ff; + m_dcr[Path] |= (value & 0x10) << 7; } int mcd212_device::get_screen_width() @@ -405,69 +318,88 @@ int mcd212_device::get_border_width() return width; } -template -void mcd212_device::process_ica() +uint32_t mcd212_device::get_backdrop_plane() { - uint16_t *ica = Channel ? m_planeb.target() : m_planea.target(); - uint32_t addr = 0x200; - uint32_t cmd = 0; + if (BIT(m_image_coding_method, ICM_EV_BIT)) + return 0; // External Video Background. Default to Black since there is no DVC. + else + return s_4bpp_color[m_backdrop_color]; +} +template +void mcd212_device::process_ica() +{ + uint16_t *ica = Path ? m_planeb.target() : m_planea.target(); const int max_to_process = m_ica_height * 120; + // LCT depends on the current frame parity + uint32_t addr = !BIT(m_csrr[0], CSR1R_PA_BIT) ? 0x200 : 0x202; + for (int i = 0; i < max_to_process; i++) { - cmd = ica[addr++] << 16; + uint32_t cmd = ica[addr++] << 16; cmd |= ica[addr++]; 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - set_dcp(cmd & 0x003ffffc); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x003fffff); + 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: - set_dcp(cmd & 0x003ffffc); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x003fffff); + 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x003fffff); 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: - set_vsr(cmd & 0x003fffff); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR and STOP: VSR = %05x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Channel); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + m_csrr[1] |= 1 << (2 - Path); 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 - set_display_parameters(cmd & 0x1f); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: SET REGISTER %02x = %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } } -template +template void mcd212_device::process_dca() { - uint16_t *dca = Channel ? m_planeb.target() : m_planea.target(); - uint32_t addr = (m_dca[Channel] & 0x0007ffff) / 2; + uint16_t *dca = Path ? m_planeb.target() : m_planea.target(); + uint32_t addr = (m_dca[Path] & 0x0007ffff) / 2; uint32_t cmd = 0; uint32_t count = 0; uint32_t max = 64; bool addr_changed = false; bool processing = true; + LOGMASKED(LOG_DCA, "Scanline %d: Processing DCA %d\n", screen().vpos(), Path); + while (processing && count < max) { cmd = dca[addr++] << 16; @@ -477,38 +409,47 @@ void mcd212_device::process_dca() { 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP (NOP)\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - set_dcp(cmd & 0x003ffffc); - m_dca[Channel] = cmd & 0x0007fffc; + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP and STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + set_dcp(cmd & 0x003ffffc); + m_dca[Path] = 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: - set_vsr(cmd & 0x003fffff); + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - set_vsr(cmd & 0x003fffff); + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - m_csrr[1] |= 1 << (2 - Channel); + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + m_csrr[1] |= 1 << (2 - Path); 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 - set_display_parameters(cmd & 0x1f); + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } @@ -518,323 +459,186 @@ void mcd212_device::process_dca() addr += (max - count) >> 1; } - m_dca[Channel] = addr * 2; + m_dca[Path] = addr * 2; } -template -static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) +template +static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) { switch (icm) { - case 1: - return byte; - case 3: - if (Channel == 1) - { - return 0x80 + (byte & 0x7f); - } - else - { - return byte & 0x7f; - } - case 4: - if (Channel == 0) - { - return byte & 0x7f; - } - break; - case 11: - if (Channel == 1) - { - return 0x80 + (byte & 0x0f); - } - else - { - return byte & 0x0f; - } - default: - break; + case 1: + return byte; + case 3: + return (Path ? 0x80 : 0) | (byte & 0x7f); + case 4: + if (Path == 0) + { + return (clut_select ? 0x80 : 0) | (byte & 0x7f); + } + break; + case 11: + return (Path ? 0x80 : 0) | (byte & 0x0f); + default: + break; } return 0; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control() { - return (m_transparency_control >> (Channel ? 8 : 0)) & 0x0f; + return (m_transparency_control >> (Path ? 8 : 0)) & 0x0f; } -template +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; + const uint32_t mask = Path ? ICM_MODE2 : ICM_MODE1; + const uint32_t shift = Path ? ICM_MODE2_SHIFT : ICM_MODE1_SHIFT; return (m_image_coding_method & mask) >> shift; } -template +template inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable() { - return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC; + return (m_ddr[Path] & DDR_FT) == DDR_FT_MOSAIC; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() { - return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); + return 1 << (((m_ddr[Path] & DDR_MT) >> DDR_MT_SHIFT) + 1); } -template -int mcd212_device::get_plane_width() -{ - const int width = get_screen_width(); - const uint8_t icm = get_icm(); - if (icm == ICM_CLUT4) - return width; - return width >> 1; -} - -template +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 uint8_t transp_ctrl = get_transparency_control(); - const int width = get_plane_width(); + const uint8_t *data = reinterpret_cast(Path ? m_planeb.target() : m_planea.target()); + const uint8_t *data2 = reinterpret_cast(!Path ? m_planeb.target() : m_planea.target()); + const uint8_t icm = get_icm(); + const uint8_t tp_ctrl = get_transparency_control(); + const int width = get_screen_width(); - uint32_t vsr = get_vsr(); + uint32_t vsr = get_vsr(); + uint32_t vsr2 = get_vsr(); - if (transp_ctrl == TCR_COND_1) + if (tp_ctrl == TCR_ALWAYS || !icm || !vsr) { - std::fill_n(pixels, get_screen_width(), 0x00101010); - std::fill_n(transparent, get_screen_width(), true); + std::fill_n(pixels, get_screen_width(), s_4bpp_color[0]); + std::fill_n(transparent, get_screen_width(), (tp_ctrl == TCR_ALWAYS)); return; } - if (!icm || !vsr) - { - std::fill_n(pixels, get_screen_width(), 0x00101010); - return; - } + const uint32_t decodingMode = m_ddr[Path] & DDR_FT; - const uint8_t mosaic_enable = get_mosaic_enable(); - const uint8_t mosaic_factor = get_mosaic_factor(); + 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 dyuv_abs_start = m_dyuv_abs_start[Path]; + uint8_t y = (dyuv_abs_start >> 16) & 0x000000ff; + uint8_t u = (dyuv_abs_start >> 8) & 0x000000ff; + uint8_t 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); + const uint32_t mask_bits = (~m_mask_color[Path]) & 0x00fcfcfc; + const uint32_t tp_color_match = m_transparent_color[Path] & mask_bits; + const uint8_t tp_ctrl_type = tp_ctrl & 0x07; - bool done = false; - int x = 0; + const bool use_rgb_tp_bit = (tp_ctrl_type == TCR_RGB); + const bool tp_check_parity = !BIT(tp_ctrl, 3); + const bool tp_always = ((tp_ctrl_type == TCR_ALWAYS) && tp_check_parity); + const int matte_flag_index = BIT(~tp_ctrl_type, 0); + const bool *const matte_flags = m_matte_flag[matte_flag_index]; + const bool use_matte_flag = (tp_ctrl_type >= TCR_MF0 && tp_ctrl_type <= TCR_MF1_KEY1); + const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. + const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); - while (!done) + LOGMASKED(LOG_VSR, "Scanline %d: VSR Path %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Path, icm, vsr); + + for (uint32_t x = 0; x < width; ) { - uint8_t byte = data[(vsr & 0x0007ffff) ^ 1]; - vsr++; - switch (m_ddr[Channel] & DDR_FT) + const uint8_t byte = data[(vsr++ & 0x0007ffff) ^ 1]; + uint32_t color0 = 0; + uint32_t color1 = 0; + bool rgb_tp_bit = false; + if (icm == ICM_DYUV) { - case DDR_FT_BMP: - case DDR_FT_BMP2: - case DDR_FT_MOSAIC: - if (icm == ICM_DYUV) - { - use_color_key = false; - - uint8_t y = start_y; - uint8_t u = start_u; - uint8_t v = start_v; - for (; x < width; x++) - { - 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]; - - const uint8_t v1 = v + m_delta_uv_lut[byte1]; - const uint8_t y1 = y0 + m_delta_y_lut[byte1]; - - const uint8_t u0 = (u + u1) >> 1; - const uint8_t v0 = (v + v1) >> 1; - - 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; - - 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] = entry; - transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; - - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x << 1]; - } - x += mosaic_factor; - } - else - { - x++; - } - - 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; - - 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] = entry; - transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; - - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x]; - } - x += mosaic_factor - 1; - } - - byte = data[(vsr++ & 0x0007ffff) ^ 1]; - - y = y1; - u = u1; - v = v1; - } - set_vsr(vsr - 1); - } - else if (icm == ICM_CLUT8 || icm == ICM_CLUT7 || icm == ICM_CLUT77) - { - for (; x < width; x++) - { - uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; - pixels[x] = entry; - transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x]; - } - x += mosaic_factor - 1; - } - byte = data[(vsr & 0x0007ffff) ^ 1]; - vsr++; - } - set_vsr(vsr - 1); - } - else if (icm == ICM_CLUT4) - { - for (; x < width - 1; x += 2) - { - 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 (int mosaic_index = 0; mosaic_index < mosaic_factor && (x + mosaic_index) < (width - 1); mosaic_index += 2) - { - pixels[x + mosaic_index] = even_entry; - transparent[x + mosaic_index] = (even_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition; - pixels[x + mosaic_index + 1] = odd_entry; - transparent[x + mosaic_index + 1] = (odd_pre_transparent || (use_region_flag && region_flags[x + mosaic_index + 1])) != invert_transp_condition; - } - x += mosaic_factor - 2; - } - else - { - 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(vsr - 1); - } - else - { - std::fill_n(pixels + x, width - x, 0x00101010); - std::fill_n(transparent + x, width - x, true); - } - done = true; - break; - case DDR_FT_RLE: - if (byte & 0x80) - { - // Run length - uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1]; - 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) - { - // Go to the end of the line - std::fill_n(pixels + x, width - x, entry); - for (int transp_index = x; transp_index < width; transp_index++) - { - transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; - } - done = true; - set_vsr(vsr); - } - else - { - int end = std::min(width, x + length); - std::fill_n(pixels + x, end - x, entry); - for (int transp_index = x; transp_index < end; transp_index++) - { - transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; - } - x = end; - if (x >= width) - { - done = true; - set_vsr(vsr); - } - } - } - else - { - // Single pixel - 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 << 1])) != invert_transp_condition; - x++; - - if (x >= width) - { - done = true; - set_vsr(vsr); - } - } - break; + const uint8_t byte1 = data[(vsr++ & 0x0007ffff) ^ 1]; + const uint8_t y2 = y + m_delta_y_lut[byte]; + y = y2 + m_delta_y_lut[byte1]; + u += m_delta_uv_lut[byte]; + v += m_delta_uv_lut[byte1]; + + const uint32_t *limit_rgb = m_dyuv_limit_lut + y2 + 0x100; + const uint32_t *limit_rgb2 = m_dyuv_limit_lut + y + 0x100; + + color0 = (limit_rgb[m_dyuv_v_to_r[v]] << 16) | (limit_rgb[m_dyuv_u_to_g[u] + m_dyuv_v_to_g[v]] << 8) | limit_rgb[m_dyuv_u_to_b[u]]; + + const uint8_t byte2 = data[(vsr & 0x0007ffff) ^ 1]; // Peek ahead, for calculating the half-step. + const uint8_t byte3 = data[((vsr + 1) & 0x0007ffff) ^ 1]; + const uint8_t u8 = u + m_delta_uv_lut[byte2]; + const uint8_t v8 = v + m_delta_uv_lut[byte3]; + const uint8_t u6 = (u >> 1) + (u8 >> 1) + (u & u8 & 1); + const uint8_t v6 = (v >> 1) + (v8 >> 1) + (v & v8 & 1); + + color1 = (limit_rgb2[m_dyuv_v_to_r[v6]] << 16) | (limit_rgb2[m_dyuv_u_to_g[u6] + m_dyuv_v_to_g[v6]] << 8) | limit_rgb2[m_dyuv_u_to_b[u6]]; + + // TODO: Does not support QHY + pixels[x] = color0; + pixels[x + 1] = color0; + pixels[x + 2] = color1; + pixels[x + 3] = color1; + transparent[x ] = tp_always || (use_matte_flag && (matte_flags[x ] == tp_check_parity)); + transparent[x + 1] = tp_always || (use_matte_flag && (matte_flags[x + 1] == tp_check_parity)); + transparent[x + 2] = tp_always || (use_matte_flag && (matte_flags[x + 2] == tp_check_parity)); + transparent[x + 3] = tp_always || (use_matte_flag && (matte_flags[x + 3] == tp_check_parity)); + x += 4; } - } - - if (icm != ICM_CLUT4) - { - for (int i = width - 1; i >= 0; i--) + else { - pixels[i * 2] = pixels[i * 2 + 1] = pixels[i]; - transparent[i * 2] = transparent[i * 2 + 1] = transparent[i]; + bool clut_select = BIT(m_image_coding_method, ICM_CS_BIT); + if (icm == ICM_RGB555 && Path == 1) + { + const uint8_t byte1 = data2[(vsr2++ & 0x0007ffff) ^ 1]; + const uint8_t blue = (byte & 0b11111) << 3; + const uint8_t green = ((byte & 0b11100000) >> 2) + ((byte1 & 0b11) << 6); + const uint8_t red = (byte1 & 0b01111100) << 1; + rgb_tp_bit = (use_rgb_tp_bit && (BIT(byte1,7) == tp_check_parity)); + color1 = color0 = (uint32_t(red) << 16) | (uint32_t(green) << 8) | blue; + } + else if (icm == ICM_CLUT4) + { + const uint8_t mask = (decodingMode == DDR_FT_RLE) ? 0x7 : 0xf; + color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; + color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; + } + else + { + color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; + } + + int length_m = mosaic_enable ? (mosaic_factor * 2) : 2; + if (decodingMode == DDR_FT_RLE) + { + const uint16_t length = (byte & 0x80) ? data[((vsr++) & 0x0007ffff) ^ 1] : 1; + length_m = length ? (length * 2) : width; + } + + const bool color_match0 = ((mask_bits & color0) == tp_color_match) == tp_check_parity; + const bool color_match1 = ((mask_bits & color1) == tp_color_match) == tp_check_parity; + const int end = std::min(width, x + length_m); + for (int rl_index = x; rl_index < end; rl_index += 2) + { + pixels[rl_index ] = color0; + pixels[rl_index + 1] = color1; + transparent[rl_index ] = tp_always || rgb_tp_bit || (use_color_key && color_match0) || (use_matte_flag && (matte_flags[rl_index ] == tp_check_parity)); + transparent[rl_index + 1] = tp_always || rgb_tp_bit || (use_color_key && color_match1) || (use_matte_flag && (matte_flags[rl_index + 1] == tp_check_parity)); + } + x = end; } } + set_vsr(vsr); + set_vsr(vsr2); } const uint32_t mcd212_device::s_4bpp_color[16] = @@ -846,152 +650,115 @@ const uint32_t mcd212_device::s_4bpp_color[16] = template void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out) { - 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; + const uint8_t icmA = get_icm<0>(); + const uint8_t icmB = get_icm<1>(); + uint16_t mosaic_count_a = (m_mosaic_hold[0] & 0x0000ff) << 1; + uint16_t mosaic_count_b = (m_mosaic_hold[1] & 0x0000ff) << 1; const int width = get_screen_width(); const int border_width = get_border_width(); 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)) + // Console Verified. CLUT4 pixels are drawn in pairs during VSR. So the mosaic here is halved. + if (icmA == ICM_CLUT4) + mosaic_count_a >>= 1; + if (icmB == ICM_CLUT4) + mosaic_count_b >>= 1; + + // If PAL and 'Standard' bit set, insert a 24px border on the left/right + uint32_t offset = (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) ? 24 : 0; + std::fill_n(out, offset, s_4bpp_color[0]); + out += offset; + + for (int x = 0; x < width; x++) { - for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) + if (transparent_a[x] && transparent_b[x]) { - 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++ = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; + out[x] = get_backdrop_plane(); + continue; } - } - else - { - for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) + uint32_t plane_a_cur = MosaicA ? plane_a[x - (x % mosaic_count_a)] : plane_a[x]; + uint32_t plane_b_cur = MosaicB ? plane_b[x - (x % mosaic_count_b)] : plane_b[x]; + + if (transparent_a[x]) { - if (OrderAB) - { - 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; - } - else - { - *out++ = backdrop; - } - } - 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; - } - else - { - *out++ = backdrop; - } - } + plane_a_cur = 0; + } + else if (OrderAB && (m_transparency_control & TCR_DISABLE_MX)) + { + plane_b_cur = 0; } + + if (transparent_b[x]) + { + plane_b_cur = 0; + } + else if (!OrderAB && (m_transparency_control & TCR_DISABLE_MX)) + { + plane_a_cur = 0; + } + + const int32_t plane_a_r = 0xff & (plane_a_cur >> 16); + const int32_t plane_a_g = 0xff & (plane_a_cur >> 8); + const int32_t plane_a_b = 0xff & plane_a_cur; + const int32_t plane_b_r = 0xff & (plane_b_cur >> 16); + const int32_t plane_b_g = 0xff & (plane_b_cur >> 8); + const int32_t plane_b_b = 0xff & plane_b_cur; + + const int32_t weighted_a_r = std::clamp((std::clamp(plane_a_r - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + const int32_t weighted_a_g = std::clamp((std::clamp(plane_a_g - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + const int32_t weighted_a_b = std::clamp((std::clamp(plane_a_b - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + + const int32_t weighted_b_r = std::clamp((std::clamp(plane_b_r - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + const int32_t weighted_b_g = std::clamp((std::clamp(plane_b_g - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + const int32_t weighted_b_b = std::clamp((std::clamp(plane_b_b - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + + const uint8_t out_r = std::clamp(weighted_a_r + weighted_b_r + 16, 0, 255); + const uint8_t out_g = std::clamp(weighted_a_g + weighted_b_g + 16, 0, 255); + const uint8_t out_b = std::clamp(weighted_a_b + weighted_b_b + 16, 0, 255); + out[x] = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; } if (border_width) { - std::fill_n(out, border_width, 0xff101010); + std::fill_n(&out[width], border_width, s_4bpp_color[0]); } } void mcd212_device::draw_cursor(uint32_t *scanline) { - if (m_cursor_control & CURCNT_EN) + if (!(m_cursor_control & CURCNT_EN)) + return; // Cursor is Disabled + + uint8_t color_index = m_cursor_control & CURCNT_COLOR; + if (m_blink_active) { - 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)) + const bool invert = BIT(m_cursor_control, CURCNT_BLKC_SHIFT); + if (!invert) + return; // Normal Blink + else + color_index = color_index ^ 0x7; // Inverted Color Blink. MCD212 Section 7.5 + } + + const uint16_t cursor_x = m_cursor_position & 0x3ff; + const uint16_t cursor_y = ((m_cursor_position >> 12) & 0x3ff) + m_ica_height; + const int32_t y = screen().vpos() - cursor_y; + const int width = get_screen_width(); + + if ((0 <= y) && (y < 16)) + { + const uint32_t color = s_4bpp_color[color_index]; + const uint8_t resolution = (m_cursor_control & CURCNT_CUW) ? 1 : 2; + for (int x = 0; x < 16; x++) { - const int width = get_screen_width(); - uint32_t color = s_4bpp_color[m_cursor_control & CURCNT_COLOR]; - y -= cursor_y; - if (m_cursor_control & CURCNT_CUW) - { - for (int x = cursor_x; x < cursor_x + 64 && x < width; x++) - { - if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 2)))) - { - scanline[x++] = color; - scanline[x++] = color; - scanline[x++] = color; - scanline[x] = color; - } - } - } - else + if (BIT(m_cursor_pattern[y], 15 - x)) { - for (int x = cursor_x; x < cursor_x + 32 && x < width; x++) + for (uint32_t j = 0; j < resolution; j++) { - if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 1)))) - { - scanline[x++] = color; - scanline[x] = color; - } + const uint32_t index = cursor_x + x * resolution + j; + if (index < width) + scanline[index] = color; } } } @@ -1017,51 +784,61 @@ void mcd212_device::map(address_map &map) 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_MAIN_REG_WRITES, "%s: Control/Status Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_csrw[0]); } uint16_t mcd212_device::dcr1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[0]); } uint16_t mcd212_device::vsr1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Decoder Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_ddr[0]); } uint16_t mcd212_device::dca1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%s: DCA Pointer 1 Read: %04x & %08x\n", machine().describe_context(), m_dca[0], mem_mask); return m_dca[0]; } void mcd212_device::dca1_w(offs_t offset, uint16_t data, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_WRITES, "%s: DCA Pointer 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[0]); } @@ -1073,6 +850,7 @@ uint8_t mcd212_device::csr2_r() } 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)) @@ -1083,46 +861,55 @@ uint8_t mcd212_device::csr2_r() void mcd212_device::csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[1]); } uint16_t mcd212_device::vsr2_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: DCA Pointer 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[1]); } @@ -1142,6 +929,21 @@ TIMER_CALLBACK_MEMBER(mcd212_device::ica_tick) m_dca[1] = get_dcp<1>(); m_ica_timer->adjust(screen().time_until_pos(0, 0)); + + // Cursor Blink + m_blink_time += 5 + BIT(m_dcr[0], DCR_FD_BIT); // FD bit * 8... Page 4-3 MCD + // Adjust the blink time once per frame + if (!m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_CON) >> CURCNT_CON_SHIFT) * 60)) + { + m_blink_active = true; + m_blink_time = 0; + } + // If blink off time is 0, immediately turn back on. + if (m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_COF) >> CURCNT_COF_SHIFT) * 60)) + { + m_blink_active = false; + m_blink_time = 0; + } } TIMER_CALLBACK_MEMBER(mcd212_device::dca_tick) @@ -1166,12 +968,20 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma bool transparent_a[768]; bool transparent_b[768]; + if (screen.vpos() >= m_total_height) + { + return 0; // Do nothing on the extended rows. + } + + // FIXME this should use the clipping rectangle to determine which lines need drawing int scanline = screen.vpos(); // Process VSR and mix if we're in the visible region if (scanline >= m_ica_height) { - uint32_t *out = &bitmap.pix(scanline); + uint32_t const bitmap_line = ((scanline - m_ica_height) << 1) + m_ica_height; + uint32_t *const out = &bitmap.pix(bitmap_line + BIT(~m_csrr[0], CSR1R_PA_BIT)); + uint32_t *const out2 = &bitmap.pix(bitmap_line + BIT(m_csrr[0], CSR1R_PA_BIT)); bool draw_line = true; if (!BIT(m_dcr[0], DCR_FD_BIT) && BIT(m_csrw[0], CSR1W_ST_BIT)) @@ -1179,7 +989,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma // If PAL and 'Standard' bit set, insert a 20-line border on the top/bottom if ((scanline - m_ica_height < 20) || (scanline >= (m_total_height - 20))) { - std::fill_n(out, 768, 0xff101010); + std::fill_n(out, 768, s_4bpp_color[0]); draw_line = false; } } @@ -1188,12 +998,6 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma if (draw_line) { - // If PAL and 'Standard' bit set, insert a 24px border on the left/right - if (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) - { - std::fill_n(out, 24, 0xff101010); - out += 24; - } process_vsr<0>(plane_a, transparent_a); process_vsr<1>(plane_b, transparent_b); @@ -1231,6 +1035,18 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma draw_cursor(out); } + + if (BIT(m_dcr[0], DCR_SM_BIT)) + { + // Interlace Output + std::copy_n(m_interlace_field[scanline], 768, out2); + std::copy_n(out, 768, m_interlace_field[scanline]); + } + else + { + // Single Field Output (duplicate lines) + std::copy_n(out, 768, out2); + } } // Toggle frame parity at the end of the visible frame (even in non-interlaced mode). @@ -1245,7 +1061,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma template int mcd212_device::ram_dtack_cycle_count<0>(); template int mcd212_device::ram_dtack_cycle_count<1>(); -template +template int mcd212_device::ram_dtack_cycle_count() { // Per MCD-212 documentation, it takes 4 CLKs (2 SCC68070 clocks) for a VRAM access during the System timing slot. @@ -1254,8 +1070,8 @@ int mcd212_device::ram_dtack_cycle_count() if (!BIT(m_dcr[0], DCR_DE_BIT)) return 2; - // No contending for Ch.1/Ch.2 timing slots if a relevant channel is disabled - if (!BIT(m_dcr[Channel], DCR_ICA_BIT)) + // No contending for Ch.1/Ch.2 timing slots if a relevant Path is disabled + if (!BIT(m_dcr[Path], DCR_ICA_BIT)) return 2; const int x = screen().hpos(); @@ -1271,11 +1087,11 @@ int mcd212_device::ram_dtack_cycle_count() return 2; // No contending for Ch.1/Ch.2 timing slots during the free-run area of DCA lines if DCA is disabled - if (!BIT(m_dcr[Channel], DCR_DCA_BIT) && x_outside_active_display) + if (!BIT(m_dcr[Path], DCR_DCA_BIT) && x_outside_active_display) return 2; // System access is restricted to the last 5 out of every 16 CLKs. - const int slot_cycle = (int)(machine().time().as_ticks(clock()) & 0xf); + const int slot_cycle = int(machine().time().as_ticks(clock()) & 0xf); if (slot_cycle >= 11) return 2; @@ -1310,16 +1126,21 @@ void mcd212_device::device_reset() 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); + std::fill_n(m_matte_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); + std::fill_n(m_matte_flag[0], std::size(m_matte_flag[0]), false); + std::fill_n(m_matte_flag[1], std::size(m_matte_flag[1]), false); m_ica_height = 32; m_total_height = 312; + m_blink_time = 0; + for (int i = 0; i < m_total_height; i++) + { + std::fill_n(m_interlace_field[i], 768, 0); + } m_int_callback(CLEAR_LINE); @@ -1340,17 +1161,6 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev { } -//------------------------------------------------- -// device_resolve_objects - resolve objects that -// may be needed for other devices to set -// initial conditions at start time -//------------------------------------------------- - -void mcd212_device::device_resolve_objects() -{ - m_int_callback.resolve_safe(); -} - //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -1365,12 +1175,10 @@ void mcd212_device::device_start() m_delta_uv_lut[d] = s_dyuv_deltas[d >> 4]; } - for (uint16_t w = 0; w < 3 * 0xff; w++) + for (uint16_t w = 0; w < 0x300; w++) { - 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; + const uint8_t limit = (w < 0x100) ? 0 : (w < 0x200) ? (w - 0x100) : 0xff; + m_dyuv_limit_lut[w] = limit; } for (int16_t sw = 0; sw < 0x100; sw++) @@ -1381,10 +1189,6 @@ void mcd212_device::device_start() m_dyuv_v_to_r[sw] = (351 * (sw - 128)) / 256; } - 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)); @@ -1403,15 +1207,24 @@ void mcd212_device::device_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_matte_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])); - m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::dca_tick), this)); + save_item(NAME(m_matte_flag)); + save_item(NAME(m_ica_height)); + save_item(NAME(m_total_height)); + + save_item(NAME(m_blink_time)); + save_item(NAME(m_blink_active)); + + save_item(NAME(m_interlace_field)); + + m_dca_timer = timer_alloc(FUNC(mcd212_device::dca_tick), this); m_dca_timer->adjust(attotime::never); - m_ica_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::ica_tick), this)); + m_ica_timer = timer_alloc(FUNC(mcd212_device::ica_tick), this); m_ica_timer->adjust(attotime::never); } diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index 521207ef..0158c64c 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -21,8 +21,8 @@ *******************************************************************************/ -#ifndef MAME_VIDEO_MCD212_H -#define MAME_VIDEO_MCD212_H +#ifndef MAME_PHILIPS_MCD212_H +#define MAME_PHILIPS_MCD212_H #pragma once @@ -49,16 +49,15 @@ class mcd212_device : public device_t, uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - void map(address_map &map); + void map(address_map &map) ATTR_COLD; - template int ram_dtack_cycle_count(); + template int ram_dtack_cycle_count(); int rom_dtack_cycle_count(); protected: - // device-level overrides - virtual void device_resolve_objects() override; - virtual void device_start() override; - virtual void device_reset() override; + // device_t implementation + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; TIMER_CALLBACK_MEMBER(ica_tick); TIMER_CALLBACK_MEMBER(dca_tick); @@ -89,10 +88,11 @@ class mcd212_device : public device_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_COF = 0b111 << CURCNT_COF_SHIFT, // Cursor off time CURCNT_CON_SHIFT = 19, + CURCNT_CON = 0b111 << CURCNT_CON_SHIFT, // Cursor on time + CURCNT_BLKC_SHIFT = 22, CURCNT_BLKC = 0x400000, // Blink type CURCNT_EN = 0x800000, // Cursor enable @@ -101,42 +101,45 @@ class mcd212_device : public device_t, ICM_MODE2 = 0x000f00, // Plane 2 ICM_MODE2_SHIFT = 8, ICM_EV = 0x040000, // External video - ICM_NR = 0x080000, // Number of region flags - ICM_NR_BIT = 19, + ICM_EV_BIT = 18, + ICM_NM = 0x080000, // Number of Matte flags + ICM_NM_BIT = 19, ICM_CS = 0x400000, // CLUT select + ICM_CS_BIT = 22, TCR_TA = 0x00000f, // Plane A TCR_TB = 0x000f00, // Plane B TCR_TB_SHIFT = 8, - 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_ALWAYS = 0x0, // Transparent if: Always (Plane Disabled) + TCR_KEY = 0x1, // Transparent if: Color Key = True + TCR_RGB = 0x2, // Transparent if: Transparency Bit = 1 (RGB Only) + TCR_MF0 = 0x3, // Transparent if: Matte Flag 0 = True + TCR_MF1 = 0x4, // Transparent if: Matte Flag 1 = True + TCR_MF0_KEY1 = 0x5, // Transparent if: Matte Flag 0 = True || Color Key = True + TCR_MF1_KEY1 = 0x6, // Transparent if: Matte 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_NEVER = 0x8, // Transparent if: Never (No Transparent Area) + TCR_NOT_KEY = 0x9, // Transparent if: Color Key = False + TCR_NOT_RGB = 0xa, // Transparent if: Transparency Bit = 0 (RGB Only) + TCR_NOT_MF0 = 0xb, // Transparent if: Matte Flag 0 = False + TCR_NOT_MF1 = 0xc, // Transparent if: Matte Flag 1 = False + TCR_NOT_MF0_KEY = 0xd, // Transparent if: Matte Flag 0 = False || Color Key = False + TCR_NOT_MF1_KEY = 0xe, // Transparent if: Matte Flag 1 = False || Color Key = False TCR_COND_UNUSED1 = 0xf, // Unused TCR_DISABLE_MX = 0x800000, // Mix disable 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, + MC_X = 0x0003ff, // X position + MC_WF = 0x00fc00, // Weight position + MC_WF_SHIFT = 10, + MC_MF_BIT = 16, // Matte flag bit + MC_OP = 0xf00000, // Operation + MC_OP_SHIFT = 20, CSR1R_PA = 0x20, // Parity + CSR1R_PA_BIT = 5, CSR1R_DA = 0x80, // Display Active CSR1W_BE = 0x0001, // Bus Error @@ -172,40 +175,38 @@ class mcd212_device : public device_t, ICM_OFF = 0x0, ICM_CLUT8 = 0x1, - ICM_RGB555 = 0x2, + ICM_RGB555 = 0x1, ICM_CLUT7 = 0x3, ICM_CLUT77 = 0x4, ICM_DYUV = 0x5, ICM_CLUT4 = 0xb }; - 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]; + 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 = 0; + uint32_t m_transparency_control = 0; + uint32_t m_plane_order = 0; + 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 = 0; + uint32_t m_cursor_control = 0; + uint32_t m_cursor_pattern[16]{}; + uint32_t m_matte_control[8]{}; + uint32_t m_backdrop_color = 0; + 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]; + uint32_t m_dyuv_limit_lut[0x300]; // DYUV delta-Y decoding array uint8_t m_delta_y_lut[0x100]; @@ -231,41 +232,47 @@ class mcd212_device : public device_t, required_shared_ptr m_planea; required_shared_ptr m_planeb; + uint32_t m_interlace_field[312][768]; + // internal state - bool m_region_flag[2][768]; - int m_ica_height; - int m_total_height; - emu_timer *m_ica_timer; - emu_timer *m_dca_timer; + bool m_matte_flag[2][768]{}; + int m_ica_height = 0; + int m_total_height = 0; + emu_timer *m_ica_timer = nullptr; + emu_timer *m_dca_timer = nullptr; + + // Cursor State + uint16_t m_blink_time; // Counter that tracks how long since the last m_blink_active last changed. + bool m_blink_active = false; static const uint32_t s_4bpp_color[16]; - uint8_t get_weight_factor(const uint32_t region_idx); - uint8_t get_region_op(const uint32_t region_idx); - void update_region_arrays(); + uint8_t get_weight_factor(const uint32_t Matte_idx); + uint8_t get_matte_op(const uint32_t Matte_idx); + void update_matte_arrays(); int get_screen_width(); int get_border_width(); - template int get_plane_width(); + uint32_t get_backdrop_plane(); - template void set_vsr(uint32_t value); - template uint32_t get_vsr(); + 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_dcp(uint32_t value); + template uint32_t get_dcp(); - template void set_display_parameters(uint8_t value); + template void set_display_parameters(uint8_t value); - template void process_ica(); - template void process_dca(); + template void process_ica(); + template void process_dca(); - 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); + 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); - template void set_register(uint8_t reg, uint32_t value); + template void set_register(uint8_t reg, uint32_t value); template void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out); @@ -275,4 +282,4 @@ class mcd212_device : public device_t, // device type definition DECLARE_DEVICE_TYPE(MCD212, mcd212_device) -#endif // MAME_VIDEO_MCD212_H +#endif // MAME_PHILIPS_MCD212_H From e2763c81930486da33f9fe76897a9118698bbf07 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 13:11:07 -0600 Subject: [PATCH 13/47] Use older timer function for mcd212 + revert update to device.h --- src/emu/device.h | 2 +- src/mame/video/mcd212.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/emu/device.h b/src/emu/device.h index 90725311..77c12cb2 100644 --- a/src/emu/device.h +++ b/src/emu/device.h @@ -705,7 +705,7 @@ class device_t : public delegate_late_bind u64 attotime_to_clocks(const attotime &duration) const noexcept; // timer interfaces - template emu_timer *timer_alloc(T &&... args); + emu_timer *timer_alloc(device_timer_id id = 0, void *ptr = nullptr); void timer_set(const attotime &duration, device_timer_id id = 0, int param = 0, void *ptr = nullptr); void synchronize(device_timer_id id = 0, int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, id, param, ptr); } void timer_expired(emu_timer &timer, device_timer_id id, int param, void *ptr) { device_timer(timer, id, param, ptr); } diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 2101a6d1..abf1f5c6 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -1222,9 +1222,9 @@ void mcd212_device::device_start() save_item(NAME(m_interlace_field)); - m_dca_timer = timer_alloc(FUNC(mcd212_device::dca_tick), this); + m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::dca_tick), this)); m_dca_timer->adjust(attotime::never); - m_ica_timer = timer_alloc(FUNC(mcd212_device::ica_tick), this); + m_ica_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::ica_tick), this)); m_ica_timer->adjust(attotime::never); } From 3803e7f7a4a07ce69df7f6f780a7fe1935b371a6 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Tue, 7 Jul 2026 13:35:36 -0600 Subject: [PATCH 14/47] Revert back to old mcd212 driver, as that makes RetroArch crash. --- src/mame/video/mcd212.cpp | 1109 ++++++++++++++++++++++--------------- src/mame/video/mcd212.h | 169 +++--- 2 files changed, 729 insertions(+), 549 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index abf1f5c6..bf1436bb 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -6,7 +6,7 @@ CD-i MCD212 Video Decoder and System Controller emulation ------------------- - written by Ryan Holtz, Vincent.Halver + written by Ryan Holtz ******************************************************************************* @@ -17,12 +17,12 @@ TODO: -- QHY DYUV Image Decoder +- Unknown yet. *******************************************************************************/ #include "emu.h" -#include "mcd212.h" +#include "video/mcd212.h" #include "screen.h" #define LOG_UNKNOWNS (1U << 1) @@ -42,71 +42,178 @@ // device type definition DEFINE_DEVICE_TYPE(MCD212, mcd212_device, "mcd212", "MCD212 VDSC") -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t matte_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t region_idx) { - return (uint8_t)((m_matte_control[matte_idx] & MC_WF) >> MC_WF_SHIFT); + return (uint8_t)((m_region_control[region_idx] & RC_WF) >> RC_WF_SHIFT); } -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_matte_op(const uint32_t matte_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_region_op(const uint32_t region_idx) { - return (m_matte_control[matte_idx] & MC_OP) >> MC_OP_SHIFT; + return (m_region_control[region_idx] & RC_OP) >> RC_OP_SHIFT; } -void mcd212_device::update_matte_arrays() +void mcd212_device::update_region_arrays() { + bool latched_rf[2] { false, false }; + uint8_t latched_wfa = m_weight_factor[0][0]; + uint8_t latched_wfb = m_weight_factor[1][0]; const int width = get_screen_width(); - const int num_mattes = BIT(m_image_coding_method, ICM_NM_BIT) ? 2 : 1; - bool latched_mf[2]{ false, false }; - uint8_t latched_wf[2] = { m_weight_factor[0][0], m_weight_factor[1][0] }; - int matte_idx[2] = { 0, 4 }; - - for (int x = 0; x < width; x++) + if (BIT(m_image_coding_method, ICM_NR_BIT)) { - for (int matte = 0; matte < num_mattes; matte++) + if (get_region_op(0) == 0 && get_region_op(4) == 0) { - const int max_matte_id = ((num_mattes == 2) ? 4 : 8) + (matte ? 4 : 0); - if (matte_idx[matte] >= max_matte_id) + 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 < width; x++) + { + for (int flag = 0; flag < 2; flag++) { - continue; + for (int region = 0; region < 4; region++) + { + 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 == (region_ctrl & RC_X)) + { + switch (region_op) + { + case 0: // End of region control for line + break; + case 1: + case 2: + case 3: // Not used + break; + case 4: // Change weight of plane A + latched_wfa = get_weight_factor(region_idx); + break; + case 5: // Not used + break; + case 6: // Change weight of plane B + latched_wfb = get_weight_factor(region_idx); + break; + case 7: // Not used + break; + case 8: // Reset region flag + latched_rf[flag] = false; + break; + case 9: // Set region flag + 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 = get_weight_factor(region_idx); + latched_rf[flag] = false; + break; + case 13: // Set region flag and change weight of plane A + 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 = get_weight_factor(region_idx); + latched_rf[flag] = false; + break; + case 15: // Set region flag and change weight of plane B + latched_wfb = get_weight_factor(region_idx); + latched_rf[flag] = true; + break; + } + } + } } - const uint32_t matte_ctrl = m_matte_control[matte_idx[matte]]; - - if (x == (matte_ctrl & MC_X)) + 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 + { + int region_idx = 0; + for (int x = 0; x < width; x++) + { + if (region_idx < 8) { - const uint32_t matte_op = get_matte_op(matte_idx[matte]); - const int flag = (num_mattes == 2) ? matte : BIT(m_matte_control[matte_idx[matte]], MC_MF_BIT); - // See 5.10.2 Matte Commands. Changing the MF-bit inside a line is undefined. Greenbook says don't do it. - // Console validation shows the 220 reads and uses this value anyway. - switch (matte_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) { - case 0: // Disregard all commands in higher registers. See 5.10.2 - matte_idx[matte] = 8; - break; - case 1: case 2: case 3: case 5: case 7: case 10: case 11: // Not used - break; - case 4: case 6: // Change weight of plane (A or B) - latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); - break; - case 8: case 9: // (Reset or Set) matte flag - latched_mf[flag] = BIT(matte_op, 0); - break; - case 12: case 13: case 14: case 15: // Change weight of plane (A or B) and (Reset or Set) matte flag - latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); - latched_mf[flag] = BIT(matte_op, 0); - 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, latched_rf[0]); + std::fill_n(m_region_flag[1] + x, std::size(m_region_flag[1]) - x, latched_rf[1]); + return; + } + if (x == (region_ctrl & RC_X)) + { + switch (region_op) + { + case 0: // End of region control for line + break; + case 1: + case 2: + case 3: // Not used + break; + case 4: // Change weight of plane A + latched_wfa = get_weight_factor(region_idx); + break; + case 5: // Not used + break; + case 6: // Change weight of plane B + latched_wfb = get_weight_factor(region_idx); + break; + case 7: // Not used + break; + case 8: // Reset region flag + latched_rf[flag] = false; + break; + case 9: // Set region flag + 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 = get_weight_factor(region_idx); + latched_rf[flag] = false; + break; + case 13: // Set region flag and change weight of plane A + 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 = get_weight_factor(region_idx); + latched_rf[flag] = false; + break; + case 15: // Set region flag and change weight of plane B + latched_wfb = get_weight_factor(region_idx); + latched_rf[flag] = true; + break; + } + region_idx++; } - matte_idx[matte]++; } + 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_weight_factor[0][x] = latched_wf[0]; - m_weight_factor[1][x] = latched_wf[1]; - m_matte_flag[0][x] = latched_mf[0]; - m_matte_flag[1][x] = latched_mf[1]; } } -template +template void mcd212_device::set_register(uint8_t reg, uint32_t value) { switch (reg) @@ -120,100 +227,86 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) 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: { - const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); - LOGMASKED(LOG_CLUT, "%s: Path %d: CLUT[%d] = %08x\n", machine().describe_context(), Path, clut_index, value); + const uint8_t clut_index = m_clut_bank[Channel] * 0x40 + (reg - 0x80); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method - if (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Path 0: Image Coding Method = %08x\n", machine().describe_context(), value); m_image_coding_method = value; } break; case 0xc1: // Transparency Control - if (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Transparency Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_transparency_control = value; } break; case 0xc2: // Plane Order - if (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Plane Order = %08x\n", machine().describe_context(), screen().vpos(), value & 7); m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: CLUT Bank Register = %08x\n", machine().describe_context(), screen().vpos(), Path, value & 3); - m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); + m_clut_bank[Channel] = Channel ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A - if (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) + if (Channel == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) + if (Channel == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) + if (Channel == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Position = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_position = value; } break; case 0xce: // Cursor Control - if (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_control = value; } break; case 0xcf: // Cursor Pattern - if (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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: // matte Control 0-7 + case 0xd0: // Region Control 0-7 case 0xd1: case 0xd2: case 0xd3: @@ -221,85 +314,79 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xd5: case 0xd6: case 0xd7: - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: matte Control %d = %08x\n", machine().describe_context(), screen().vpos(), Path, reg & 7, value); - m_matte_control[reg & 7] = value; - update_matte_arrays(); + m_region_control[reg & 7] = value; + update_region_arrays(); break; case 0xd8: // Backdrop Color - if (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Backdrop Color = %08x\n", machine().describe_context(), screen().vpos(), value); m_backdrop_color = value; } break; case 0xd9: // Mosaic Pixel Hold Factor A - if (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) + if (Channel == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) + if (Channel == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Weight Factor A = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[0][0] = (uint8_t)value; - update_matte_arrays(); + update_region_arrays(); } break; case 0xdc: // Weight Factor B - if (Path == 1) + if (Channel == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 1: Weight Factor B = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[1][0] = (uint8_t)value; - update_matte_arrays(); + update_region_arrays(); } break; } } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr() { - return ((m_dcr[Path] & 0x3f) << 16) | m_vsr[Path]; + return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_vsr(uint32_t value) { - m_vsr[Path] = value & 0x0000ffff; - m_dcr[Path] &= 0xffc0; - m_dcr[Path] |= (value >> 16) & 0x003f; + m_vsr[Channel] = value & 0x0000ffff; + m_dcr[Channel] &= 0xffc0; + m_dcr[Channel] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_dcp(uint32_t value) { - m_dcp[Path] = value & 0x0000ffff; - m_ddr[Path] &= 0xffc0; - m_ddr[Path] |= (value >> 16) & 0x003f; + m_dcp[Channel] = value & 0x0000ffff; + m_ddr[Channel] &= 0xffc0; + m_ddr[Channel] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_dcp() { - return ((m_ddr[Path] & 0x3f) << 16) | m_dcp[Path]; + return ((m_ddr[Channel] & 0x3f) << 16) | m_dcp[Channel]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t value) { - m_ddr[Path] &= 0xf0ff; - m_ddr[Path] |= (value & 0x0f) << 8; - m_dcr[Path] &= 0xf7ff; - m_dcr[Path] |= (value & 0x10) << 7; + m_ddr[Channel] &= 0xf0ff; + m_ddr[Channel] |= (value & 0x0f) << 8; + m_dcr[Channel] &= 0xf7ff; + m_dcr[Channel] |= (value & 0x10) << 7; } int mcd212_device::get_screen_width() @@ -318,88 +405,69 @@ int mcd212_device::get_border_width() return width; } -uint32_t mcd212_device::get_backdrop_plane() -{ - if (BIT(m_image_coding_method, ICM_EV_BIT)) - return 0; // External Video Background. Default to Black since there is no DVC. - else - return s_4bpp_color[m_backdrop_color]; -} - -template +template void mcd212_device::process_ica() { - uint16_t *ica = Path ? m_planeb.target() : m_planea.target(); - const int max_to_process = m_ica_height * 120; - // LCT depends on the current frame parity - uint32_t addr = !BIT(m_csrr[0], CSR1R_PA_BIT) ? 0x200 : 0x202; + uint16_t *ica = Channel ? m_planeb.target() : m_planea.target(); + uint32_t addr = 0x200; + uint32_t cmd = 0; + const int max_to_process = m_ica_height * 120; for (int i = 0; i < max_to_process; i++) { - uint32_t cmd = ica[addr++] << 16; + cmd = ica[addr++] << 16; cmd |= ica[addr++]; 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x003fffff); - set_dcp(cmd & 0x003ffffc); + 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x003fffff); - set_dcp(cmd & 0x003ffffc); + 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x003fffff); 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR and STOP: VSR = %05x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x003fffff); - set_vsr(cmd & 0x003fffff); + 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); - m_csrr[1] |= 1 << (2 - Path); + 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 - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: SET REGISTER %02x = %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd >> 24, cmd & 0x00ffffff); - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } } -template +template void mcd212_device::process_dca() { - uint16_t *dca = Path ? m_planeb.target() : m_planea.target(); - uint32_t addr = (m_dca[Path] & 0x0007ffff) / 2; + 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; bool addr_changed = false; bool processing = true; - LOGMASKED(LOG_DCA, "Scanline %d: Processing DCA %d\n", screen().vpos(), Path); - while (processing && count < max) { cmd = dca[addr++] << 16; @@ -409,47 +477,38 @@ void mcd212_device::process_dca() { 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); - 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP (NOP)\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP and STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); - set_dcp(cmd & 0x003ffffc); - m_dca[Path] = cmd & 0x0007fffc; + 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x001fffff); - set_vsr(cmd & 0x003fffff); + 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd & 0x001fffff); - set_vsr(cmd & 0x003fffff); + 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); - m_csrr[1] |= 1 << (2 - Path); + 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 - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } @@ -459,186 +518,323 @@ void mcd212_device::process_dca() addr += (max - count) >> 1; } - m_dca[Path] = addr * 2; + m_dca[Channel] = addr * 2; } -template -static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) +template +static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) { switch (icm) { - case 1: - return byte; - case 3: - return (Path ? 0x80 : 0) | (byte & 0x7f); - case 4: - if (Path == 0) - { - return (clut_select ? 0x80 : 0) | (byte & 0x7f); - } - break; - case 11: - return (Path ? 0x80 : 0) | (byte & 0x0f); - default: - break; + case 1: + return byte; + case 3: + if (Channel == 1) + { + return 0x80 + (byte & 0x7f); + } + else + { + return byte & 0x7f; + } + case 4: + if (Channel == 0) + { + return byte & 0x7f; + } + break; + case 11: + if (Channel == 1) + { + return 0x80 + (byte & 0x0f); + } + else + { + return byte & 0x0f; + } + default: + break; } return 0; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control() { - return (m_transparency_control >> (Path ? 8 : 0)) & 0x0f; + return (m_transparency_control >> (Channel ? 8 : 0)) & 0x0f; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_icm() { - const uint32_t mask = Path ? ICM_MODE2 : ICM_MODE1; - const uint32_t shift = Path ? ICM_MODE2_SHIFT : ICM_MODE1_SHIFT; + 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 +template inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable() { - return (m_ddr[Path] & DDR_FT) == DDR_FT_MOSAIC; + return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() { - return 1 << (((m_ddr[Path] & DDR_MT) >> DDR_MT_SHIFT) + 1); + return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); } -template -void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) +template +int mcd212_device::get_plane_width() { - const uint8_t *data = reinterpret_cast(Path ? m_planeb.target() : m_planea.target()); - const uint8_t *data2 = reinterpret_cast(!Path ? m_planeb.target() : m_planea.target()); - const uint8_t icm = get_icm(); - const uint8_t tp_ctrl = get_transparency_control(); const int width = get_screen_width(); + const uint8_t icm = get_icm(); + if (icm == ICM_CLUT4) + return width; + return width >> 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 uint8_t transp_ctrl = get_transparency_control(); + const int width = get_plane_width(); - uint32_t vsr = get_vsr(); - uint32_t vsr2 = get_vsr(); + uint32_t vsr = get_vsr(); - if (tp_ctrl == TCR_ALWAYS || !icm || !vsr) + if (transp_ctrl == TCR_COND_1) { - std::fill_n(pixels, get_screen_width(), s_4bpp_color[0]); - std::fill_n(transparent, get_screen_width(), (tp_ctrl == TCR_ALWAYS)); + std::fill_n(pixels, get_screen_width(), 0x00101010); + std::fill_n(transparent, get_screen_width(), true); return; } - const uint32_t decodingMode = m_ddr[Path] & DDR_FT; - - const uint8_t mosaic_enable = get_mosaic_enable(); - const uint8_t mosaic_factor = get_mosaic_factor(); + if (!icm || !vsr) + { + std::fill_n(pixels, get_screen_width(), 0x00101010); + return; + } - const uint32_t dyuv_abs_start = m_dyuv_abs_start[Path]; - uint8_t y = (dyuv_abs_start >> 16) & 0x000000ff; - uint8_t u = (dyuv_abs_start >> 8) & 0x000000ff; - uint8_t v = (dyuv_abs_start >> 0) & 0x000000ff; + const uint8_t mosaic_enable = get_mosaic_enable(); + const uint8_t mosaic_factor = get_mosaic_factor(); - const uint32_t mask_bits = (~m_mask_color[Path]) & 0x00fcfcfc; - const uint32_t tp_color_match = m_transparent_color[Path] & mask_bits; - const uint8_t tp_ctrl_type = tp_ctrl & 0x07; + 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 bool use_rgb_tp_bit = (tp_ctrl_type == TCR_RGB); - const bool tp_check_parity = !BIT(tp_ctrl, 3); - const bool tp_always = ((tp_ctrl_type == TCR_ALWAYS) && tp_check_parity); - const int matte_flag_index = BIT(~tp_ctrl_type, 0); - const bool *const matte_flags = m_matte_flag[matte_flag_index]; - const bool use_matte_flag = (tp_ctrl_type >= TCR_MF0 && tp_ctrl_type <= TCR_MF1_KEY1); - const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. - const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); + 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); - LOGMASKED(LOG_VSR, "Scanline %d: VSR Path %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Path, icm, vsr); + bool done = false; + int x = 0; - for (uint32_t x = 0; x < width; ) + while (!done) { - const uint8_t byte = data[(vsr++ & 0x0007ffff) ^ 1]; - uint32_t color0 = 0; - uint32_t color1 = 0; - bool rgb_tp_bit = false; - if (icm == ICM_DYUV) + uint8_t byte = data[(vsr & 0x0007ffff) ^ 1]; + vsr++; + switch (m_ddr[Channel] & DDR_FT) { - const uint8_t byte1 = data[(vsr++ & 0x0007ffff) ^ 1]; - const uint8_t y2 = y + m_delta_y_lut[byte]; - y = y2 + m_delta_y_lut[byte1]; - u += m_delta_uv_lut[byte]; - v += m_delta_uv_lut[byte1]; - - const uint32_t *limit_rgb = m_dyuv_limit_lut + y2 + 0x100; - const uint32_t *limit_rgb2 = m_dyuv_limit_lut + y + 0x100; - - color0 = (limit_rgb[m_dyuv_v_to_r[v]] << 16) | (limit_rgb[m_dyuv_u_to_g[u] + m_dyuv_v_to_g[v]] << 8) | limit_rgb[m_dyuv_u_to_b[u]]; - - const uint8_t byte2 = data[(vsr & 0x0007ffff) ^ 1]; // Peek ahead, for calculating the half-step. - const uint8_t byte3 = data[((vsr + 1) & 0x0007ffff) ^ 1]; - const uint8_t u8 = u + m_delta_uv_lut[byte2]; - const uint8_t v8 = v + m_delta_uv_lut[byte3]; - const uint8_t u6 = (u >> 1) + (u8 >> 1) + (u & u8 & 1); - const uint8_t v6 = (v >> 1) + (v8 >> 1) + (v & v8 & 1); - - color1 = (limit_rgb2[m_dyuv_v_to_r[v6]] << 16) | (limit_rgb2[m_dyuv_u_to_g[u6] + m_dyuv_v_to_g[v6]] << 8) | limit_rgb2[m_dyuv_u_to_b[u6]]; - - // TODO: Does not support QHY - pixels[x] = color0; - pixels[x + 1] = color0; - pixels[x + 2] = color1; - pixels[x + 3] = color1; - transparent[x ] = tp_always || (use_matte_flag && (matte_flags[x ] == tp_check_parity)); - transparent[x + 1] = tp_always || (use_matte_flag && (matte_flags[x + 1] == tp_check_parity)); - transparent[x + 2] = tp_always || (use_matte_flag && (matte_flags[x + 2] == tp_check_parity)); - transparent[x + 3] = tp_always || (use_matte_flag && (matte_flags[x + 3] == tp_check_parity)); - x += 4; + case DDR_FT_BMP: + case DDR_FT_BMP2: + case DDR_FT_MOSAIC: + if (icm == ICM_DYUV) + { + use_color_key = false; + + uint8_t y = start_y; + uint8_t u = start_u; + uint8_t v = start_v; + for (; x < width; x++) + { + 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]; + + const uint8_t v1 = v + m_delta_uv_lut[byte1]; + const uint8_t y1 = y0 + m_delta_y_lut[byte1]; + + const uint8_t u0 = (u + u1) >> 1; + const uint8_t v0 = (v + v1) >> 1; + + 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; + + 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] = entry; + transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + + if (mosaic_enable) + { + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) + { + pixels[x + mosaic_index] = pixels[x]; + transparent[x + mosaic_index] = transparent[x << 1]; + } + x += mosaic_factor; + } + else + { + x++; + } + + 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; + + 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] = entry; + transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + + if (mosaic_enable) + { + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) + { + pixels[x + mosaic_index] = pixels[x]; + transparent[x + mosaic_index] = transparent[x]; + } + x += mosaic_factor - 1; + } + + byte = data[(vsr++ & 0x0007ffff) ^ 1]; + + y = y1; + u = u1; + v = v1; + } + set_vsr(vsr - 1); + } + else if (icm == ICM_CLUT8 || icm == ICM_CLUT7 || icm == ICM_CLUT77) + { + for (; x < width; x++) + { + uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; + pixels[x] = entry; + transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + if (mosaic_enable) + { + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) + { + pixels[x + mosaic_index] = pixels[x]; + transparent[x + mosaic_index] = transparent[x]; + } + x += mosaic_factor - 1; + } + byte = data[(vsr & 0x0007ffff) ^ 1]; + vsr++; + } + set_vsr(vsr - 1); + } + else if (icm == ICM_CLUT4) + { + for (; x < width - 1; x += 2) + { + 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 (int mosaic_index = 0; mosaic_index < mosaic_factor && (x + mosaic_index) < (width - 1); mosaic_index += 2) + { + pixels[x + mosaic_index] = even_entry; + transparent[x + mosaic_index] = (even_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition; + pixels[x + mosaic_index + 1] = odd_entry; + transparent[x + mosaic_index + 1] = (odd_pre_transparent || (use_region_flag && region_flags[x + mosaic_index + 1])) != invert_transp_condition; + } + x += mosaic_factor - 2; + } + else + { + 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(vsr - 1); + } + else + { + std::fill_n(pixels + x, width - x, 0x00101010); + std::fill_n(transparent + x, width - x, true); + } + done = true; + break; + case DDR_FT_RLE: + if (byte & 0x80) + { + // Run length + uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1]; + 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) + { + // Go to the end of the line + std::fill_n(pixels + x, width - x, entry); + for (int transp_index = x; transp_index < width; transp_index++) + { + transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; + } + done = true; + set_vsr(vsr); + } + else + { + int end = std::min(width, x + length); + std::fill_n(pixels + x, end - x, entry); + for (int transp_index = x; transp_index < end; transp_index++) + { + transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; + } + x = end; + if (x >= width) + { + done = true; + set_vsr(vsr); + } + } + } + else + { + // Single pixel + 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 << 1])) != invert_transp_condition; + x++; + + if (x >= width) + { + done = true; + set_vsr(vsr); + } + } + break; } - else - { - bool clut_select = BIT(m_image_coding_method, ICM_CS_BIT); - if (icm == ICM_RGB555 && Path == 1) - { - const uint8_t byte1 = data2[(vsr2++ & 0x0007ffff) ^ 1]; - const uint8_t blue = (byte & 0b11111) << 3; - const uint8_t green = ((byte & 0b11100000) >> 2) + ((byte1 & 0b11) << 6); - const uint8_t red = (byte1 & 0b01111100) << 1; - rgb_tp_bit = (use_rgb_tp_bit && (BIT(byte1,7) == tp_check_parity)); - color1 = color0 = (uint32_t(red) << 16) | (uint32_t(green) << 8) | blue; - } - else if (icm == ICM_CLUT4) - { - const uint8_t mask = (decodingMode == DDR_FT_RLE) ? 0x7 : 0xf; - color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; - color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; - } - else - { - color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; - } - - int length_m = mosaic_enable ? (mosaic_factor * 2) : 2; - if (decodingMode == DDR_FT_RLE) - { - const uint16_t length = (byte & 0x80) ? data[((vsr++) & 0x0007ffff) ^ 1] : 1; - length_m = length ? (length * 2) : width; - } + } - const bool color_match0 = ((mask_bits & color0) == tp_color_match) == tp_check_parity; - const bool color_match1 = ((mask_bits & color1) == tp_color_match) == tp_check_parity; - const int end = std::min(width, x + length_m); - for (int rl_index = x; rl_index < end; rl_index += 2) - { - pixels[rl_index ] = color0; - pixels[rl_index + 1] = color1; - transparent[rl_index ] = tp_always || rgb_tp_bit || (use_color_key && color_match0) || (use_matte_flag && (matte_flags[rl_index ] == tp_check_parity)); - transparent[rl_index + 1] = tp_always || rgb_tp_bit || (use_color_key && color_match1) || (use_matte_flag && (matte_flags[rl_index + 1] == tp_check_parity)); - } - x = end; + if (icm != ICM_CLUT4) + { + for (int i = width - 1; i >= 0; i--) + { + pixels[i * 2] = pixels[i * 2 + 1] = pixels[i]; + transparent[i * 2] = transparent[i * 2 + 1] = transparent[i]; } } - set_vsr(vsr); - set_vsr(vsr2); } const uint32_t mcd212_device::s_4bpp_color[16] = @@ -650,115 +846,152 @@ const uint32_t mcd212_device::s_4bpp_color[16] = template void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out) { - const uint8_t icmA = get_icm<0>(); - const uint8_t icmB = get_icm<1>(); - uint16_t mosaic_count_a = (m_mosaic_hold[0] & 0x0000ff) << 1; - uint16_t mosaic_count_b = (m_mosaic_hold[1] & 0x0000ff) << 1; + 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; const int width = get_screen_width(); const int border_width = get_border_width(); uint8_t *weight_a = &m_weight_factor[0][0]; uint8_t *weight_b = &m_weight_factor[1][0]; - // Console Verified. CLUT4 pixels are drawn in pairs during VSR. So the mosaic here is halved. - if (icmA == ICM_CLUT4) - mosaic_count_a >>= 1; - if (icmB == ICM_CLUT4) - mosaic_count_b >>= 1; - - // If PAL and 'Standard' bit set, insert a 24px border on the left/right - uint32_t offset = (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) ? 24 : 0; - std::fill_n(out, offset, s_4bpp_color[0]); - out += offset; - - for (int x = 0; x < width; x++) + if (!(m_transparency_control & TCR_DISABLE_MX)) { - if (transparent_a[x] && transparent_b[x]) - { - out[x] = get_backdrop_plane(); - continue; - } - uint32_t plane_a_cur = MosaicA ? plane_a[x - (x % mosaic_count_a)] : plane_a[x]; - uint32_t plane_b_cur = MosaicB ? plane_b[x - (x % mosaic_count_b)] : plane_b[x]; - - if (transparent_a[x]) + for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) { - plane_a_cur = 0; + 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++ = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; } - else if (OrderAB && (m_transparency_control & TCR_DISABLE_MX)) - { - plane_b_cur = 0; - } - - if (transparent_b[x]) - { - plane_b_cur = 0; - } - else if (!OrderAB && (m_transparency_control & TCR_DISABLE_MX)) + } + else + { + for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) { - plane_a_cur = 0; + if (OrderAB) + { + 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; + } + else + { + *out++ = backdrop; + } + } + 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; + } + else + { + *out++ = backdrop; + } + } } - - const int32_t plane_a_r = 0xff & (plane_a_cur >> 16); - const int32_t plane_a_g = 0xff & (plane_a_cur >> 8); - const int32_t plane_a_b = 0xff & plane_a_cur; - const int32_t plane_b_r = 0xff & (plane_b_cur >> 16); - const int32_t plane_b_g = 0xff & (plane_b_cur >> 8); - const int32_t plane_b_b = 0xff & plane_b_cur; - - const int32_t weighted_a_r = std::clamp((std::clamp(plane_a_r - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); - const int32_t weighted_a_g = std::clamp((std::clamp(plane_a_g - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); - const int32_t weighted_a_b = std::clamp((std::clamp(plane_a_b - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); - - const int32_t weighted_b_r = std::clamp((std::clamp(plane_b_r - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); - const int32_t weighted_b_g = std::clamp((std::clamp(plane_b_g - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); - const int32_t weighted_b_b = std::clamp((std::clamp(plane_b_b - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); - - const uint8_t out_r = std::clamp(weighted_a_r + weighted_b_r + 16, 0, 255); - const uint8_t out_g = std::clamp(weighted_a_g + weighted_b_g + 16, 0, 255); - const uint8_t out_b = std::clamp(weighted_a_b + weighted_b_b + 16, 0, 255); - out[x] = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; } if (border_width) { - std::fill_n(&out[width], border_width, s_4bpp_color[0]); + std::fill_n(out, border_width, 0xff101010); } } void mcd212_device::draw_cursor(uint32_t *scanline) { - if (!(m_cursor_control & CURCNT_EN)) - return; // Cursor is Disabled - - uint8_t color_index = m_cursor_control & CURCNT_COLOR; - if (m_blink_active) + if (m_cursor_control & CURCNT_EN) { - const bool invert = BIT(m_cursor_control, CURCNT_BLKC_SHIFT); - if (!invert) - return; // Normal Blink - else - color_index = color_index ^ 0x7; // Inverted Color Blink. MCD212 Section 7.5 - } - - const uint16_t cursor_x = m_cursor_position & 0x3ff; - const uint16_t cursor_y = ((m_cursor_position >> 12) & 0x3ff) + m_ica_height; - const int32_t y = screen().vpos() - cursor_y; - const int width = get_screen_width(); - - if ((0 <= y) && (y < 16)) - { - const uint32_t color = s_4bpp_color[color_index]; - const uint8_t resolution = (m_cursor_control & CURCNT_CUW) ? 1 : 2; - for (int x = 0; x < 16; x++) + 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)) { - if (BIT(m_cursor_pattern[y], 15 - x)) + const int width = get_screen_width(); + uint32_t color = s_4bpp_color[m_cursor_control & CURCNT_COLOR]; + y -= cursor_y; + if (m_cursor_control & CURCNT_CUW) + { + for (int x = cursor_x; x < cursor_x + 64 && x < width; x++) + { + if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 2)))) + { + scanline[x++] = color; + scanline[x++] = color; + scanline[x++] = color; + scanline[x] = color; + } + } + } + else { - for (uint32_t j = 0; j < resolution; j++) + for (int x = cursor_x; x < cursor_x + 32 && x < width; x++) { - const uint32_t index = cursor_x + x * resolution + j; - if (index < width) - scanline[index] = color; + if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 1)))) + { + scanline[x++] = color; + scanline[x] = color; + } } } } @@ -784,61 +1017,51 @@ void mcd212_device::map(address_map &map) 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_MAIN_REG_WRITES, "%s: Control/Status Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_csrw[0]); } uint16_t mcd212_device::dcr1_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[0]); } uint16_t mcd212_device::vsr1_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Decoder Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_ddr[0]); } uint16_t mcd212_device::dca1_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_READS, "%s: DCA Pointer 1 Read: %04x & %08x\n", machine().describe_context(), m_dca[0], mem_mask); return m_dca[0]; } void mcd212_device::dca1_w(offs_t offset, uint16_t data, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_WRITES, "%s: DCA Pointer 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[0]); } @@ -850,7 +1073,6 @@ uint8_t mcd212_device::csr2_r() } 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)) @@ -861,55 +1083,46 @@ uint8_t mcd212_device::csr2_r() void mcd212_device::csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[1]); } uint16_t mcd212_device::vsr2_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: DCA Pointer 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[1]); } @@ -929,21 +1142,6 @@ TIMER_CALLBACK_MEMBER(mcd212_device::ica_tick) m_dca[1] = get_dcp<1>(); m_ica_timer->adjust(screen().time_until_pos(0, 0)); - - // Cursor Blink - m_blink_time += 5 + BIT(m_dcr[0], DCR_FD_BIT); // FD bit * 8... Page 4-3 MCD - // Adjust the blink time once per frame - if (!m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_CON) >> CURCNT_CON_SHIFT) * 60)) - { - m_blink_active = true; - m_blink_time = 0; - } - // If blink off time is 0, immediately turn back on. - if (m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_COF) >> CURCNT_COF_SHIFT) * 60)) - { - m_blink_active = false; - m_blink_time = 0; - } } TIMER_CALLBACK_MEMBER(mcd212_device::dca_tick) @@ -968,20 +1166,12 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma bool transparent_a[768]; bool transparent_b[768]; - if (screen.vpos() >= m_total_height) - { - return 0; // Do nothing on the extended rows. - } - - // FIXME this should use the clipping rectangle to determine which lines need drawing int scanline = screen.vpos(); // Process VSR and mix if we're in the visible region if (scanline >= m_ica_height) { - uint32_t const bitmap_line = ((scanline - m_ica_height) << 1) + m_ica_height; - uint32_t *const out = &bitmap.pix(bitmap_line + BIT(~m_csrr[0], CSR1R_PA_BIT)); - uint32_t *const out2 = &bitmap.pix(bitmap_line + BIT(m_csrr[0], CSR1R_PA_BIT)); + uint32_t *out = &bitmap.pix(scanline); bool draw_line = true; if (!BIT(m_dcr[0], DCR_FD_BIT) && BIT(m_csrw[0], CSR1W_ST_BIT)) @@ -989,7 +1179,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma // If PAL and 'Standard' bit set, insert a 20-line border on the top/bottom if ((scanline - m_ica_height < 20) || (scanline >= (m_total_height - 20))) { - std::fill_n(out, 768, s_4bpp_color[0]); + std::fill_n(out, 768, 0xff101010); draw_line = false; } } @@ -998,6 +1188,12 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma if (draw_line) { + // If PAL and 'Standard' bit set, insert a 24px border on the left/right + if (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) + { + std::fill_n(out, 24, 0xff101010); + out += 24; + } process_vsr<0>(plane_a, transparent_a); process_vsr<1>(plane_b, transparent_b); @@ -1035,18 +1231,6 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma draw_cursor(out); } - - if (BIT(m_dcr[0], DCR_SM_BIT)) - { - // Interlace Output - std::copy_n(m_interlace_field[scanline], 768, out2); - std::copy_n(out, 768, m_interlace_field[scanline]); - } - else - { - // Single Field Output (duplicate lines) - std::copy_n(out, 768, out2); - } } // Toggle frame parity at the end of the visible frame (even in non-interlaced mode). @@ -1061,7 +1245,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma template int mcd212_device::ram_dtack_cycle_count<0>(); template int mcd212_device::ram_dtack_cycle_count<1>(); -template +template int mcd212_device::ram_dtack_cycle_count() { // Per MCD-212 documentation, it takes 4 CLKs (2 SCC68070 clocks) for a VRAM access during the System timing slot. @@ -1070,8 +1254,8 @@ int mcd212_device::ram_dtack_cycle_count() if (!BIT(m_dcr[0], DCR_DE_BIT)) return 2; - // No contending for Ch.1/Ch.2 timing slots if a relevant Path is disabled - if (!BIT(m_dcr[Path], DCR_ICA_BIT)) + // No contending for Ch.1/Ch.2 timing slots if a relevant channel is disabled + if (!BIT(m_dcr[Channel], DCR_ICA_BIT)) return 2; const int x = screen().hpos(); @@ -1087,11 +1271,11 @@ int mcd212_device::ram_dtack_cycle_count() return 2; // No contending for Ch.1/Ch.2 timing slots during the free-run area of DCA lines if DCA is disabled - if (!BIT(m_dcr[Path], DCR_DCA_BIT) && x_outside_active_display) + if (!BIT(m_dcr[Channel], DCR_DCA_BIT) && x_outside_active_display) return 2; // System access is restricted to the last 5 out of every 16 CLKs. - const int slot_cycle = int(machine().time().as_ticks(clock()) & 0xf); + const int slot_cycle = (int)(machine().time().as_ticks(clock()) & 0xf); if (slot_cycle >= 11) return 2; @@ -1126,21 +1310,16 @@ void mcd212_device::device_reset() m_cursor_position = 0; m_cursor_control = 0; std::fill_n(m_cursor_pattern, std::size(m_cursor_pattern), 0); - std::fill_n(m_matte_control, 8, 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_matte_flag[0], std::size(m_matte_flag[0]), false); - std::fill_n(m_matte_flag[1], std::size(m_matte_flag[1]), false); + 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_blink_time = 0; - for (int i = 0; i < m_total_height; i++) - { - std::fill_n(m_interlace_field[i], 768, 0); - } m_int_callback(CLEAR_LINE); @@ -1161,6 +1340,17 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev { } +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void mcd212_device::device_resolve_objects() +{ + m_int_callback.resolve_safe(); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -1175,10 +1365,12 @@ void mcd212_device::device_start() m_delta_uv_lut[d] = s_dyuv_deltas[d >> 4]; } - for (uint16_t w = 0; w < 0x300; w++) + for (uint16_t w = 0; w < 3 * 0xff; w++) { - const uint8_t limit = (w < 0x100) ? 0 : (w < 0x200) ? (w - 0x100) : 0xff; - m_dyuv_limit_lut[w] = limit; + 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 (int16_t sw = 0; sw < 0x100; sw++) @@ -1189,6 +1381,10 @@ void mcd212_device::device_start() m_dyuv_v_to_r[sw] = (351 * (sw - 128)) / 256; } + 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)); @@ -1207,21 +1403,12 @@ void mcd212_device::device_start() save_item(NAME(m_cursor_position)); save_item(NAME(m_cursor_control)); save_item(NAME(m_cursor_pattern)); - save_item(NAME(m_matte_control)); + 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])); - save_item(NAME(m_matte_flag)); - save_item(NAME(m_ica_height)); - save_item(NAME(m_total_height)); - - save_item(NAME(m_blink_time)); - save_item(NAME(m_blink_active)); - - save_item(NAME(m_interlace_field)); - m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::dca_tick), this)); m_dca_timer->adjust(attotime::never); diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index 0158c64c..521207ef 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -21,8 +21,8 @@ *******************************************************************************/ -#ifndef MAME_PHILIPS_MCD212_H -#define MAME_PHILIPS_MCD212_H +#ifndef MAME_VIDEO_MCD212_H +#define MAME_VIDEO_MCD212_H #pragma once @@ -49,15 +49,16 @@ class mcd212_device : public device_t, uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - void map(address_map &map) ATTR_COLD; + void map(address_map &map); - template int ram_dtack_cycle_count(); + template int ram_dtack_cycle_count(); int rom_dtack_cycle_count(); protected: - // device_t implementation - virtual void device_start() override ATTR_COLD; - virtual void device_reset() override ATTR_COLD; + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; TIMER_CALLBACK_MEMBER(ica_tick); TIMER_CALLBACK_MEMBER(dca_tick); @@ -88,11 +89,10 @@ class mcd212_device : public device_t, { CURCNT_COLOR = 0x00000f, // Cursor color CURCNT_CUW = 0x008000, // Cursor width + CURCNT_COF = 0x070000, // Cursor off time CURCNT_COF_SHIFT = 16, - CURCNT_COF = 0b111 << CURCNT_COF_SHIFT, // Cursor off time + CURCNT_CON = 0x280000, // Cursor on time CURCNT_CON_SHIFT = 19, - CURCNT_CON = 0b111 << CURCNT_CON_SHIFT, // Cursor on time - CURCNT_BLKC_SHIFT = 22, CURCNT_BLKC = 0x400000, // Blink type CURCNT_EN = 0x800000, // Cursor enable @@ -101,45 +101,42 @@ class mcd212_device : public device_t, ICM_MODE2 = 0x000f00, // Plane 2 ICM_MODE2_SHIFT = 8, ICM_EV = 0x040000, // External video - ICM_EV_BIT = 18, - ICM_NM = 0x080000, // Number of Matte flags - ICM_NM_BIT = 19, + ICM_NR = 0x080000, // Number of region flags + ICM_NR_BIT = 19, ICM_CS = 0x400000, // CLUT select - ICM_CS_BIT = 22, TCR_TA = 0x00000f, // Plane A TCR_TB = 0x000f00, // Plane B TCR_TB_SHIFT = 8, - TCR_ALWAYS = 0x0, // Transparent if: Always (Plane Disabled) - TCR_KEY = 0x1, // Transparent if: Color Key = True - TCR_RGB = 0x2, // Transparent if: Transparency Bit = 1 (RGB Only) - TCR_MF0 = 0x3, // Transparent if: Matte Flag 0 = True - TCR_MF1 = 0x4, // Transparent if: Matte Flag 1 = True - TCR_MF0_KEY1 = 0x5, // Transparent if: Matte Flag 0 = True || Color Key = True - TCR_MF1_KEY1 = 0x6, // Transparent if: Matte Flag 1 = True || Color Key = True + 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_NEVER = 0x8, // Transparent if: Never (No Transparent Area) - TCR_NOT_KEY = 0x9, // Transparent if: Color Key = False - TCR_NOT_RGB = 0xa, // Transparent if: Transparency Bit = 0 (RGB Only) - TCR_NOT_MF0 = 0xb, // Transparent if: Matte Flag 0 = False - TCR_NOT_MF1 = 0xc, // Transparent if: Matte Flag 1 = False - TCR_NOT_MF0_KEY = 0xd, // Transparent if: Matte Flag 0 = False || Color Key = False - TCR_NOT_MF1_KEY = 0xe, // Transparent if: Matte Flag 1 = False || Color Key = False + 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 TCR_DISABLE_MX = 0x800000, // Mix disable POR_AB = 0, // Plane A in front of Plane B POR_BA = 1, // Plane B in front of Plane A - MC_X = 0x0003ff, // X position - MC_WF = 0x00fc00, // Weight position - MC_WF_SHIFT = 10, - MC_MF_BIT = 16, // Matte flag bit - MC_OP = 0xf00000, // Operation - MC_OP_SHIFT = 20, + 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, CSR1R_PA = 0x20, // Parity - CSR1R_PA_BIT = 5, CSR1R_DA = 0x80, // Display Active CSR1W_BE = 0x0001, // Bus Error @@ -175,38 +172,40 @@ class mcd212_device : public device_t, ICM_OFF = 0x0, ICM_CLUT8 = 0x1, - ICM_RGB555 = 0x1, + ICM_RGB555 = 0x2, ICM_CLUT7 = 0x3, ICM_CLUT77 = 0x4, ICM_DYUV = 0x5, ICM_CLUT4 = 0xb }; - 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 = 0; - uint32_t m_transparency_control = 0; - uint32_t m_plane_order = 0; - 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 = 0; - uint32_t m_cursor_control = 0; - uint32_t m_cursor_pattern[16]{}; - uint32_t m_matte_control[8]{}; - uint32_t m_backdrop_color = 0; - uint32_t m_mosaic_hold[2]{}; - uint8_t m_weight_factor[2][768]{}; + 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_lut[0x300]; + 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]; @@ -232,47 +231,41 @@ class mcd212_device : public device_t, required_shared_ptr m_planea; required_shared_ptr m_planeb; - uint32_t m_interlace_field[312][768]; - // internal state - bool m_matte_flag[2][768]{}; - int m_ica_height = 0; - int m_total_height = 0; - emu_timer *m_ica_timer = nullptr; - emu_timer *m_dca_timer = nullptr; - - // Cursor State - uint16_t m_blink_time; // Counter that tracks how long since the last m_blink_active last changed. - bool m_blink_active = false; + bool m_region_flag[2][768]; + int m_ica_height; + int m_total_height; + emu_timer *m_ica_timer; + emu_timer *m_dca_timer; static const uint32_t s_4bpp_color[16]; - uint8_t get_weight_factor(const uint32_t Matte_idx); - uint8_t get_matte_op(const uint32_t Matte_idx); - void update_matte_arrays(); + uint8_t get_weight_factor(const uint32_t region_idx); + uint8_t get_region_op(const uint32_t region_idx); + void update_region_arrays(); int get_screen_width(); int get_border_width(); - uint32_t get_backdrop_plane(); + template int get_plane_width(); - template void set_vsr(uint32_t value); - template uint32_t get_vsr(); + 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_dcp(uint32_t value); + template uint32_t get_dcp(); - template void set_display_parameters(uint8_t value); + template void set_display_parameters(uint8_t value); - template void process_ica(); - template void process_dca(); + template void process_ica(); + template void process_dca(); - 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); + 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); - template void set_register(uint8_t reg, uint32_t value); + template void set_register(uint8_t reg, uint32_t value); template void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out); @@ -282,4 +275,4 @@ class mcd212_device : public device_t, // device type definition DECLARE_DEVICE_TYPE(MCD212, mcd212_device) -#endif // MAME_PHILIPS_MCD212_H +#endif // MAME_VIDEO_MCD212_H From 9fbe907b95b0fd76e8dbe0483dfe4f9ee6cff7bf Mon Sep 17 00:00:00 2001 From: OM3GAZX <120065710+OM3GAZX@users.noreply.github.com> Date: Tue, 7 Jul 2026 15:32:42 -0600 Subject: [PATCH 15/47] Add workflow to core0287-v5 branch. --- .github/workflows/main.yml | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..a8a56619 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,47 @@ +name: Build SAME_CDi iOS dylib + +on: + workflow_dispatch: + +jobs: + build: + runs-on: macos-latest + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up Xcode + run: | + sudo xcode-select -s /Applications/Xcode.app + xcodebuild -version + + - name: Install Dependencies + run: | + brew install coreutils + # MAME requires Python for build scripts (GENie) + echo "PYTHON_EXECUTABLE=python3" >> $GITHUB_ENV + + - name: Compile SAME_CDi Libretro Core (iOS arm64) + run: | + # Get iOS SDK path dynamically + IOS_SDK_PATH=$(xcrun --sdk iphoneos --show-sdk-path) + + # Run the Libretro Makefile with explicit iOS overrides + # Using SUBTARGET=arcade keeps compilation faster and prevents GitHub runner timeouts + make -f Makefile.libretro -j$(sysctl -n hw.ncpu) \ + platform=ios-arm64 \ + IOS_SDK_PATH="$IOS_SDK_PATH" + + - name: Locate and Rename Artifact + run: | + mkdir -p output/ + # Libretro cores traditionally output as mame_libretro_ios.dylib or similar + find . -name "*.dylib" -exec cp {} output/ \; + ls -la output/ + + - name: Upload Built Binaries + uses: actions/upload-artifact@v4 + with: + name: samecdi-libretro-ios + path: output/ From b6e53085e3f469e645480261ac64a665152d5e71 Mon Sep 17 00:00:00 2001 From: OM3GAZX <120065710+OM3GAZX@users.noreply.github.com> Date: Wed, 8 Jul 2026 11:16:59 -0600 Subject: [PATCH 16/47] Use macos-14 instead of macos-latest for workflow. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a8a56619..6891ccad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,7 @@ on: jobs: build: - runs-on: macos-latest + runs-on: macos-14 steps: - name: Checkout Code From d7ede24a6260d757387a3c9ed45dd4ccc08576c6 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 13:01:26 -0600 Subject: [PATCH 17/47] mcd212 updates. --- src/mame/video/mcd212.cpp | 1065 +++++++++++++++---------------------- src/mame/video/mcd212.h | 166 +++--- 2 files changed, 514 insertions(+), 717 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index bf1436bb..89592e5c 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -17,12 +17,12 @@ TODO: -- Unknown yet. +- QHY DYUV Image Decoder *******************************************************************************/ #include "emu.h" -#include "video/mcd212.h" +#include "mcd212.h" #include "screen.h" #define LOG_UNKNOWNS (1U << 1) @@ -42,178 +42,71 @@ // device type definition DEFINE_DEVICE_TYPE(MCD212, mcd212_device, "mcd212", "MCD212 VDSC") -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t region_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t matte_idx) { - return (uint8_t)((m_region_control[region_idx] & RC_WF) >> RC_WF_SHIFT); + return (uint8_t)((m_matte_control[matte_idx] & MC_WF) >> MC_WF_SHIFT); } -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_region_op(const uint32_t region_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_matte_op(const uint32_t matte_idx) { - return (m_region_control[region_idx] & RC_OP) >> RC_OP_SHIFT; + return (m_matte_control[matte_idx] & MC_OP) >> MC_OP_SHIFT; } -void mcd212_device::update_region_arrays() +void mcd212_device::update_matte_arrays() { - bool latched_rf[2] { false, false }; - uint8_t latched_wfa = m_weight_factor[0][0]; - uint8_t latched_wfb = m_weight_factor[1][0]; const int width = get_screen_width(); + const int num_mattes = BIT(m_image_coding_method, ICM_NM_BIT) ? 2 : 1; - if (BIT(m_image_coding_method, ICM_NR_BIT)) - { - if (get_region_op(0) == 0 && get_region_op(4) == 0) - { - 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; - } + bool latched_mf[2]{ false, false }; + uint8_t latched_wf[2] = { m_weight_factor[0][0], m_weight_factor[1][0] }; + int matte_idx[2] = { 0, 4 }; - for (int x = 0; x < width; x++) + for (int x = 0; x < width; x++) + { + for (int matte = 0; matte < num_mattes; matte++) { - for (int flag = 0; flag < 2; flag++) + const int max_matte_id = ((num_mattes == 2) ? 4 : 8) + (matte ? 4 : 0); + if (matte_idx[matte] >= max_matte_id) { - for (int region = 0; region < 4; region++) - { - 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 == (region_ctrl & RC_X)) - { - switch (region_op) - { - case 0: // End of region control for line - break; - case 1: - case 2: - case 3: // Not used - break; - case 4: // Change weight of plane A - latched_wfa = get_weight_factor(region_idx); - break; - case 5: // Not used - break; - case 6: // Change weight of plane B - latched_wfb = get_weight_factor(region_idx); - break; - case 7: // Not used - break; - case 8: // Reset region flag - latched_rf[flag] = false; - break; - case 9: // Set region flag - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 13: // Set region flag and change weight of plane A - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 15: // Set region flag and change weight of plane B - latched_wfb = get_weight_factor(region_idx); - latched_rf[flag] = true; - break; - } - } - } + continue; } - 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 - { - int region_idx = 0; - for (int x = 0; x < width; x++) - { - if (region_idx < 8) + const uint32_t matte_ctrl = m_matte_control[matte_idx[matte]]; + + if (x == (matte_ctrl & MC_X)) { - 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) - { - 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, latched_rf[0]); - std::fill_n(m_region_flag[1] + x, std::size(m_region_flag[1]) - x, latched_rf[1]); - return; - } - if (x == (region_ctrl & RC_X)) + const uint32_t matte_op = get_matte_op(matte_idx[matte]); + const int flag = (num_mattes == 2) ? matte : BIT(m_matte_control[matte_idx[matte]], MC_MF_BIT); + // See 5.10.2 Matte Commands. Changing the MF-bit inside a line is undefined. Greenbook says don't do it. + // Console validation shows the 220 reads and uses this value anyway. + switch (matte_op) { - switch (region_op) - { - case 0: // End of region control for line - break; - case 1: - case 2: - case 3: // Not used - break; - case 4: // Change weight of plane A - latched_wfa = get_weight_factor(region_idx); - break; - case 5: // Not used - break; - case 6: // Change weight of plane B - latched_wfb = get_weight_factor(region_idx); - break; - case 7: // Not used - break; - case 8: // Reset region flag - latched_rf[flag] = false; - break; - case 9: // Set region flag - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 13: // Set region flag and change weight of plane A - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 15: // Set region flag and change weight of plane B - latched_wfb = get_weight_factor(region_idx); - latched_rf[flag] = true; - break; - } - region_idx++; + case 0: // Disregard all commands in higher registers. See 5.10.2 + matte_idx[matte] = 8; + break; + case 1: case 2: case 3: case 5: case 7: case 10: case 11: // Not used + break; + case 4: case 6: // Change weight of plane (A or B) + latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); + break; + case 8: case 9: // (Reset or Set) matte flag + latched_mf[flag] = BIT(matte_op, 0); + break; + case 12: case 13: case 14: case 15: // Change weight of plane (A or B) and (Reset or Set) matte flag + latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); + latched_mf[flag] = BIT(matte_op, 0); + break; } + matte_idx[matte]++; } - 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_weight_factor[0][x] = latched_wf[0]; + m_weight_factor[1][x] = latched_wf[1]; + m_matte_flag[0][x] = latched_mf[0]; + m_matte_flag[1][x] = latched_mf[1]; } } -template +template void mcd212_device::set_register(uint8_t reg, uint32_t value) { switch (reg) @@ -227,86 +120,100 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) 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: { - const uint8_t clut_index = m_clut_bank[Channel] * 0x40 + (reg - 0x80); + const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); + LOGMASKED(LOG_CLUT, "%s: Path %d: CLUT[%d] = %08x\n", machine().describe_context(), Path, clut_index, value); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Path 0: Image Coding Method = %08x\n", machine().describe_context(), value); m_image_coding_method = value; } break; case 0xc1: // Transparency Control - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Transparency Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_transparency_control = value; } break; case 0xc2: // Plane Order - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Plane Order = %08x\n", machine().describe_context(), screen().vpos(), value & 7); m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register - m_clut_bank[Channel] = Channel ? (2 | (value & 0x00000001)) : (value & 0x00000003); + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: CLUT Bank Register = %08x\n", machine().describe_context(), screen().vpos(), Path, value & 3); + m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Position = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_position = value; } break; case 0xce: // Cursor Control - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_control = value; } break; case 0xcf: // Cursor Pattern - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 + case 0xd0: // matte Control 0-7 case 0xd1: case 0xd2: case 0xd3: @@ -314,79 +221,85 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xd5: case 0xd6: case 0xd7: - m_region_control[reg & 7] = value; - update_region_arrays(); + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: matte Control %d = %08x\n", machine().describe_context(), screen().vpos(), Path, reg & 7, value); + m_matte_control[reg & 7] = value; + update_matte_arrays(); break; case 0xd8: // Backdrop Color - if (Channel == 0) + if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Weight Factor A = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[0][0] = (uint8_t)value; - update_region_arrays(); + update_matte_arrays(); } break; case 0xdc: // Weight Factor B - if (Channel == 1) + if (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 1: Weight Factor B = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[1][0] = (uint8_t)value; - update_region_arrays(); + update_matte_arrays(); } break; } } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr() { - return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel]; + return ((m_dcr[Path] & 0x3f) << 16) | m_vsr[Path]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_vsr(uint32_t value) { - m_vsr[Channel] = value & 0x0000ffff; - m_dcr[Channel] &= 0xffc0; - m_dcr[Channel] |= (value >> 16) & 0x003f; + m_vsr[Path] = value & 0x0000ffff; + m_dcr[Path] &= 0xffc0; + m_dcr[Path] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_dcp(uint32_t value) { - m_dcp[Channel] = value & 0x0000ffff; - m_ddr[Channel] &= 0xffc0; - m_ddr[Channel] |= (value >> 16) & 0x003f; + m_dcp[Path] = value & 0x0000ffff; + m_ddr[Path] &= 0xffc0; + m_ddr[Path] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_dcp() { - return ((m_ddr[Channel] & 0x3f) << 16) | m_dcp[Channel]; + return ((m_ddr[Path] & 0x3f) << 16) | m_dcp[Path]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t value) { - m_ddr[Channel] &= 0xf0ff; - m_ddr[Channel] |= (value & 0x0f) << 8; - m_dcr[Channel] &= 0xf7ff; - m_dcr[Channel] |= (value & 0x10) << 7; + m_ddr[Path] &= 0xf0ff; + m_ddr[Path] |= (value & 0x0f) << 8; + m_dcr[Path] &= 0xf7ff; + m_dcr[Path] |= (value & 0x10) << 7; } int mcd212_device::get_screen_width() @@ -405,10 +318,21 @@ int mcd212_device::get_border_width() return width; } -template +uint32_t mcd212_device::get_backdrop_plane() { + if (BIT(m_image_coding_method, ICM_EV_BIT)) + { + return 0; // External Video Background. Default to Black since there is no DVC. + } + else + { + return s_4bpp_color[m_backdrop_color]; + } +} + +template void mcd212_device::process_ica() { - uint16_t *ica = Channel ? m_planeb.target() : m_planea.target(); + uint16_t *ica = Path ? m_planeb.target() : m_planea.target(); uint32_t addr = 0x200; uint32_t cmd = 0; @@ -421,53 +345,64 @@ void mcd212_device::process_ica() { 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - set_dcp(cmd & 0x003ffffc); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - set_dcp(cmd & 0x003ffffc); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - set_vsr(cmd & 0x003fffff); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR and STOP: VSR = %05x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - m_csrr[1] |= 1 << (2 - Channel); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + m_csrr[1] |= 1 << (2 - Path); 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 - set_display_parameters(cmd & 0x1f); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: SET REGISTER %02x = %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } } -template +template void mcd212_device::process_dca() { - uint16_t *dca = Channel ? m_planeb.target() : m_planea.target(); - uint32_t addr = (m_dca[Channel] & 0x0007ffff) / 2; + uint16_t *dca = Path ? m_planeb.target() : m_planea.target(); + uint32_t addr = (m_dca[Path] & 0x0007ffff) / 2; uint32_t cmd = 0; uint32_t count = 0; uint32_t max = 64; bool addr_changed = false; bool processing = true; + LOGMASKED(LOG_DCA, "Scanline %d: Processing DCA %d\n", screen().vpos(), Path); + while (processing && count < max) { cmd = dca[addr++] << 16; @@ -477,38 +412,47 @@ void mcd212_device::process_dca() { 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP (NOP)\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - set_dcp(cmd & 0x003ffffc); - m_dca[Channel] = cmd & 0x0007fffc; + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP and STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + set_dcp(cmd & 0x003ffffc); + m_dca[Path] = 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: - set_vsr(cmd & 0x003fffff); + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - set_vsr(cmd & 0x003fffff); + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - m_csrr[1] |= 1 << (2 - Channel); + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + m_csrr[1] |= 1 << (2 - Path); 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 - set_display_parameters(cmd & 0x1f); + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } @@ -518,323 +462,186 @@ void mcd212_device::process_dca() addr += (max - count) >> 1; } - m_dca[Channel] = addr * 2; + m_dca[Path] = addr * 2; } -template -static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) +template +static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) { switch (icm) { - case 1: - return byte; - case 3: - if (Channel == 1) - { - return 0x80 + (byte & 0x7f); - } - else - { - return byte & 0x7f; - } - case 4: - if (Channel == 0) - { - return byte & 0x7f; - } - break; - case 11: - if (Channel == 1) - { - return 0x80 + (byte & 0x0f); - } - else - { - return byte & 0x0f; - } - default: - break; + case 1: + return byte; + case 3: + return (Path ? 0x80 : 0) | (byte & 0x7f); + case 4: + if (Path == 0) + { + return (clut_select ? 0x80 : 0) | (byte & 0x7f); + } + break; + case 11: + return (Path ? 0x80 : 0) | (byte & 0x0f); + default: + break; } return 0; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control() { - return (m_transparency_control >> (Channel ? 8 : 0)) & 0x0f; + return (m_transparency_control >> (Path ? 8 : 0)) & 0x0f; } -template +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; + const uint32_t mask = Path ? ICM_MODE2 : ICM_MODE1; + const uint32_t shift = Path ? ICM_MODE2_SHIFT : ICM_MODE1_SHIFT; return (m_image_coding_method & mask) >> shift; } -template +template inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable() { - return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC; + return (m_ddr[Path] & DDR_FT) == DDR_FT_MOSAIC; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() { - return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); -} - -template -int mcd212_device::get_plane_width() -{ - const int width = get_screen_width(); - const uint8_t icm = get_icm(); - if (icm == ICM_CLUT4) - return width; - return width >> 1; + return 1 << (((m_ddr[Path] & DDR_MT) >> DDR_MT_SHIFT) + 1); } -template +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 uint8_t transp_ctrl = get_transparency_control(); - const int width = get_plane_width(); + const uint8_t *data = reinterpret_cast(Path ? m_planeb.target() : m_planea.target()); + const uint8_t *data2 = reinterpret_cast(!Path ? m_planeb.target() : m_planea.target()); + const uint8_t icm = get_icm(); + const uint8_t tp_ctrl = get_transparency_control(); + const int width = get_screen_width(); - uint32_t vsr = get_vsr(); + uint32_t vsr = get_vsr(); + uint32_t vsr2 = get_vsr(); - if (transp_ctrl == TCR_COND_1) + if (tp_ctrl == TCR_ALWAYS || !icm || !vsr) { - std::fill_n(pixels, get_screen_width(), 0x00101010); + std::fill_n(pixels, get_screen_width(), s_4bpp_color[0]); std::fill_n(transparent, get_screen_width(), true); return; } - if (!icm || !vsr) - { - std::fill_n(pixels, get_screen_width(), 0x00101010); - return; - } + const uint32_t decodingMode = m_ddr[Path] & DDR_FT; - const uint8_t mosaic_enable = get_mosaic_enable(); - const uint8_t mosaic_factor = get_mosaic_factor(); + 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 dyuv_abs_start = m_dyuv_abs_start[Path]; + uint8_t y = (dyuv_abs_start >> 16) & 0x000000ff; + uint8_t u = (dyuv_abs_start >> 8) & 0x000000ff; + uint8_t 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); + const uint32_t mask_bits = (~m_mask_color[Path]) & 0x00fcfcfc; + const uint32_t tp_color_match = m_transparent_color[Path] & mask_bits; + const uint8_t tp_ctrl_type = tp_ctrl & 0x07; - bool done = false; - int x = 0; + const bool use_rgb_tp_bit = (tp_ctrl_type == TCR_RGB); + const bool tp_check_parity = !BIT(tp_ctrl, 3); + const bool tp_always = ((tp_ctrl_type == TCR_ALWAYS) && tp_check_parity); + const int matte_flag_index = BIT(~tp_ctrl_type, 0); + const bool *const matte_flags = m_matte_flag[matte_flag_index]; + const bool use_matte_flag = (tp_ctrl_type >= TCR_MF0 && tp_ctrl_type <= TCR_MF1_KEY1); + const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. + const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); - while (!done) + LOGMASKED(LOG_VSR, "Scanline %d: VSR Path %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Path, icm, vsr); + + for (uint32_t x = 0; x < width; ) { - uint8_t byte = data[(vsr & 0x0007ffff) ^ 1]; - vsr++; - switch (m_ddr[Channel] & DDR_FT) + const uint8_t byte = data[(vsr++ & 0x0007ffff) ^ 1]; + uint32_t color0 = 0; + uint32_t color1 = 0; + bool rgb_tp_bit = false; + if (icm == ICM_DYUV) { - case DDR_FT_BMP: - case DDR_FT_BMP2: - case DDR_FT_MOSAIC: - if (icm == ICM_DYUV) - { - use_color_key = false; - - uint8_t y = start_y; - uint8_t u = start_u; - uint8_t v = start_v; - for (; x < width; x++) - { - 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]; - - const uint8_t v1 = v + m_delta_uv_lut[byte1]; - const uint8_t y1 = y0 + m_delta_y_lut[byte1]; - - const uint8_t u0 = (u + u1) >> 1; - const uint8_t v0 = (v + v1) >> 1; - - 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; - - 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] = entry; - transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; - - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x << 1]; - } - x += mosaic_factor; - } - else - { - x++; - } - - 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; - - 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] = entry; - transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; - - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x]; - } - x += mosaic_factor - 1; - } - - byte = data[(vsr++ & 0x0007ffff) ^ 1]; - - y = y1; - u = u1; - v = v1; - } - set_vsr(vsr - 1); - } - else if (icm == ICM_CLUT8 || icm == ICM_CLUT7 || icm == ICM_CLUT77) - { - for (; x < width; x++) - { - uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; - pixels[x] = entry; - transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x]; - } - x += mosaic_factor - 1; - } - byte = data[(vsr & 0x0007ffff) ^ 1]; - vsr++; - } - set_vsr(vsr - 1); - } - else if (icm == ICM_CLUT4) - { - for (; x < width - 1; x += 2) - { - 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 (int mosaic_index = 0; mosaic_index < mosaic_factor && (x + mosaic_index) < (width - 1); mosaic_index += 2) - { - pixels[x + mosaic_index] = even_entry; - transparent[x + mosaic_index] = (even_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition; - pixels[x + mosaic_index + 1] = odd_entry; - transparent[x + mosaic_index + 1] = (odd_pre_transparent || (use_region_flag && region_flags[x + mosaic_index + 1])) != invert_transp_condition; - } - x += mosaic_factor - 2; - } - else - { - 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(vsr - 1); - } - else - { - std::fill_n(pixels + x, width - x, 0x00101010); - std::fill_n(transparent + x, width - x, true); - } - done = true; - break; - case DDR_FT_RLE: - if (byte & 0x80) - { - // Run length - uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1]; - 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) - { - // Go to the end of the line - std::fill_n(pixels + x, width - x, entry); - for (int transp_index = x; transp_index < width; transp_index++) - { - transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; - } - done = true; - set_vsr(vsr); - } - else - { - int end = std::min(width, x + length); - std::fill_n(pixels + x, end - x, entry); - for (int transp_index = x; transp_index < end; transp_index++) - { - transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; - } - x = end; - if (x >= width) - { - done = true; - set_vsr(vsr); - } - } - } - else - { - // Single pixel - 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 << 1])) != invert_transp_condition; - x++; - - if (x >= width) - { - done = true; - set_vsr(vsr); - } - } - break; + const uint8_t byte1 = data[(vsr++ & 0x0007ffff) ^ 1]; + const uint8_t y2 = y + m_delta_y_lut[byte]; + y = y2 + m_delta_y_lut[byte1]; + u += m_delta_uv_lut[byte]; + v += m_delta_uv_lut[byte1]; + + const uint32_t *limit_rgb = m_dyuv_limit_lut + y2 + 0x100; + const uint32_t *limit_rgb2 = m_dyuv_limit_lut + y + 0x100; + + color0 = (limit_rgb[m_dyuv_v_to_r[v]] << 16) | (limit_rgb[m_dyuv_u_to_g[u] + m_dyuv_v_to_g[v]] << 8) | limit_rgb[m_dyuv_u_to_b[u]]; + + const uint8_t byte2 = data[(vsr & 0x0007ffff) ^ 1]; // Peek ahead, for calculating the half-step. + const uint8_t byte3 = data[((vsr + 1) & 0x0007ffff) ^ 1]; + const uint8_t u8 = u + m_delta_uv_lut[byte2]; + const uint8_t v8 = v + m_delta_uv_lut[byte3]; + const uint8_t u6 = (u >> 1) + (u8 >> 1) + (u & u8 & 1); + const uint8_t v6 = (v >> 1) + (v8 >> 1) + (v & v8 & 1); + + color1 = (limit_rgb2[m_dyuv_v_to_r[v6]] << 16) | (limit_rgb2[m_dyuv_u_to_g[u6] + m_dyuv_v_to_g[v6]] << 8) | limit_rgb2[m_dyuv_u_to_b[u6]]; + + // TODO: Does not support QHY + pixels[x] = color0; + pixels[x + 1] = color0; + pixels[x + 2] = color1; + pixels[x + 3] = color1; + transparent[x ] = tp_always || (use_matte_flag && (matte_flags[x ] == tp_check_parity)); + transparent[x + 1] = tp_always || (use_matte_flag && (matte_flags[x + 1] == tp_check_parity)); + transparent[x + 2] = tp_always || (use_matte_flag && (matte_flags[x + 2] == tp_check_parity)); + transparent[x + 3] = tp_always || (use_matte_flag && (matte_flags[x + 3] == tp_check_parity)); + x += 4; } - } - - if (icm != ICM_CLUT4) - { - for (int i = width - 1; i >= 0; i--) + else { - pixels[i * 2] = pixels[i * 2 + 1] = pixels[i]; - transparent[i * 2] = transparent[i * 2 + 1] = transparent[i]; + bool clut_select = BIT(m_image_coding_method, ICM_CS_BIT); + if (icm == ICM_RGB555 && Path == 1) + { + const uint8_t byte1 = data2[(vsr2++ & 0x0007ffff) ^ 1]; + const uint8_t blue = (byte & 0b11111) << 3; + const uint8_t green = ((byte & 0b11100000) >> 2) + ((byte1 & 0b11) << 6); + const uint8_t red = (byte1 & 0b01111100) << 1; + rgb_tp_bit = (use_rgb_tp_bit && (BIT(byte1,7) == tp_check_parity)); + color1 = color0 = (uint32_t(red) << 16) | (uint32_t(green) << 8) | blue; + } + else if (icm == ICM_CLUT4) + { + const uint8_t mask = (decodingMode == DDR_FT_RLE) ? 0x7 : 0xf; + color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; + color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; + } + else + { + color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; + } + + int length_m = mosaic_enable ? (mosaic_factor * 2) : 2; + if (decodingMode == DDR_FT_RLE) + { + const uint16_t length = (byte & 0x80) ? data[((vsr++) & 0x0007ffff) ^ 1] : 1; + length_m = length ? (length * 2) : width; + } + + const bool color_match0 = ((mask_bits & color0) == tp_color_match) == tp_check_parity; + const bool color_match1 = ((mask_bits & color1) == tp_color_match) == tp_check_parity; + const int end = std::min(width, x + length_m); + for (int rl_index = x; rl_index < end; rl_index += 2) + { + pixels[rl_index ] = color0; + pixels[rl_index + 1] = color1; + transparent[rl_index ] = tp_always || rgb_tp_bit || (use_color_key && color_match0) || (use_matte_flag && (matte_flags[rl_index ] == tp_check_parity)); + transparent[rl_index + 1] = tp_always || rgb_tp_bit || (use_color_key && color_match1) || (use_matte_flag && (matte_flags[rl_index + 1] == tp_check_parity)); + } + x = end; } } + set_vsr(vsr); + set_vsr(vsr2); } const uint32_t mcd212_device::s_4bpp_color[16] = @@ -846,152 +653,112 @@ const uint32_t mcd212_device::s_4bpp_color[16] = template void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out) { - 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; + const uint8_t icmA = get_icm<0>(); + const uint8_t icmB = get_icm<1>(); + uint16_t mosaic_count_a = (m_mosaic_hold[0] & 0x0000ff) << 1; + uint16_t mosaic_count_b = (m_mosaic_hold[1] & 0x0000ff) << 1; const int width = get_screen_width(); const int border_width = get_border_width(); 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)) + // Console Verified. CLUT4 pixels are drawn in pairs during VSR. So the mosaic here is halved. + if (icmA == ICM_CLUT4) { + mosaic_count_a >>= 1; + } + if (icmB == ICM_CLUT4) { + mosaic_count_b >>= 1; + } + + for (int x = 0; x < width; x++) { - for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) + if (transparent_a[x] && transparent_b[x]) { - 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++ = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; + out[x] = get_backdrop_plane(); + continue; } - } - else - { - for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) + uint32_t plane_a_cur = MosaicA ? plane_a[x - (x % mosaic_count_a)] : plane_a[x]; + uint32_t plane_b_cur = MosaicB ? plane_b[x - (x % mosaic_count_b)] : plane_b[x]; + + if (transparent_a[x]) { - if (OrderAB) - { - 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; - } - else - { - *out++ = backdrop; - } - } - 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; - } - else - { - *out++ = backdrop; - } - } + plane_a_cur = 0; } + else if (OrderAB && (m_transparency_control & TCR_DISABLE_MX)) + { + plane_b_cur = 0; + } + + if (transparent_b[x]) + { + plane_b_cur = 0; + } + else if (!OrderAB && (m_transparency_control & TCR_DISABLE_MX)) + { + plane_a_cur = 0; + } + + const int32_t plane_a_r = 0xff & (plane_a_cur >> 16); + const int32_t plane_a_g = 0xff & (plane_a_cur >> 8); + const int32_t plane_a_b = 0xff & plane_a_cur; + const int32_t plane_b_r = 0xff & (plane_b_cur >> 16); + const int32_t plane_b_g = 0xff & (plane_b_cur >> 8); + const int32_t plane_b_b = 0xff & plane_b_cur; + + const int32_t weighted_a_r = std::clamp((std::clamp(plane_a_r - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + const int32_t weighted_a_g = std::clamp((std::clamp(plane_a_g - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + const int32_t weighted_a_b = std::clamp((std::clamp(plane_a_b - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + + const int32_t weighted_b_r = std::clamp((std::clamp(plane_b_r - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + const int32_t weighted_b_g = std::clamp((std::clamp(plane_b_g - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + const int32_t weighted_b_b = std::clamp((std::clamp(plane_b_b - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + + const uint8_t out_r = std::clamp(weighted_a_r + weighted_b_r + 16, 0, 255); + const uint8_t out_g = std::clamp(weighted_a_g + weighted_b_g + 16, 0, 255); + const uint8_t out_b = std::clamp(weighted_a_b + weighted_b_b + 16, 0, 255); + out[x] = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; } if (border_width) { - std::fill_n(out, border_width, 0xff101010); + std::fill_n(&out[width], border_width, s_4bpp_color[0]); } } void mcd212_device::draw_cursor(uint32_t *scanline) { - if (m_cursor_control & CURCNT_EN) + if (!(m_cursor_control & CURCNT_EN)) + return; // Cursor is Disabled + + uint8_t color_index = m_cursor_control & CURCNT_COLOR; + if (m_blink_active) + { + const bool invert = BIT(m_cursor_control, CURCNT_BLKC_SHIFT); + if (!invert) + return; // Normal Blink + else + color_index = color_index ^ 0x7; // Inverted Color Blink. MCD212 Section 7.5 + } + + const uint16_t cursor_x = m_cursor_position & 0x3ff; + const uint16_t cursor_y = ((m_cursor_position >> 12) & 0x3ff) + m_ica_height; + const int32_t y = screen().vpos() - cursor_y; + const int width = get_screen_width(); + + if ((0 <= y) && (y < 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)) + const uint32_t color = s_4bpp_color[color_index]; + const uint8_t resolution = (m_cursor_control & CURCNT_CUW) ? 1 : 2; + for (int x = 0; x < 16; x++) { - const int width = get_screen_width(); - uint32_t color = s_4bpp_color[m_cursor_control & CURCNT_COLOR]; - y -= cursor_y; - if (m_cursor_control & CURCNT_CUW) - { - for (int x = cursor_x; x < cursor_x + 64 && x < width; x++) - { - if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 2)))) - { - scanline[x++] = color; - scanline[x++] = color; - scanline[x++] = color; - scanline[x] = color; - } - } - } - else + if (BIT(m_cursor_pattern[y], 15 - x)) { - for (int x = cursor_x; x < cursor_x + 32 && x < width; x++) + for (uint32_t j = 0; j < resolution; j++) { - if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 1)))) - { - scanline[x++] = color; - scanline[x] = color; - } + const uint32_t index = cursor_x + x * resolution + j; + if (index < width) + scanline[index] = color; } } } @@ -1017,51 +784,61 @@ void mcd212_device::map(address_map &map) 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_MAIN_REG_WRITES, "%s: Control/Status Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_csrw[0]); } uint16_t mcd212_device::dcr1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[0]); } uint16_t mcd212_device::vsr1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Decoder Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_ddr[0]); } uint16_t mcd212_device::dca1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%s: DCA Pointer 1 Read: %04x & %08x\n", machine().describe_context(), m_dca[0], mem_mask); return m_dca[0]; } void mcd212_device::dca1_w(offs_t offset, uint16_t data, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_WRITES, "%s: DCA Pointer 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[0]); } @@ -1073,6 +850,7 @@ uint8_t mcd212_device::csr2_r() } 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)) @@ -1083,46 +861,55 @@ uint8_t mcd212_device::csr2_r() void mcd212_device::csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[1]); } uint16_t mcd212_device::vsr2_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: DCA Pointer 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[1]); } @@ -1142,6 +929,21 @@ TIMER_CALLBACK_MEMBER(mcd212_device::ica_tick) m_dca[1] = get_dcp<1>(); m_ica_timer->adjust(screen().time_until_pos(0, 0)); + + // Cursor Blink + m_blink_time += 5 + BIT(m_dcr[0], DCR_FD_BIT); // FD bit * 8... Page 4-3 MCD + // Adjust the blink time once per frame + if (!m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_CON) >> CURCNT_CON_SHIFT) * 60)) + { + m_blink_active = true; + m_blink_time = 0; + } + // If blink off time is 0, immediately turn back on. + if (m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_COF) >> CURCNT_COF_SHIFT) * 60)) + { + m_blink_active = false; + m_blink_time = 0; + } } TIMER_CALLBACK_MEMBER(mcd212_device::dca_tick) @@ -1179,7 +981,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma // If PAL and 'Standard' bit set, insert a 20-line border on the top/bottom if ((scanline - m_ica_height < 20) || (scanline >= (m_total_height - 20))) { - std::fill_n(out, 768, 0xff101010); + std::fill_n(out, 768, s_4bpp_color[0]); draw_line = false; } } @@ -1191,7 +993,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma // If PAL and 'Standard' bit set, insert a 24px border on the left/right if (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) { - std::fill_n(out, 24, 0xff101010); + std::fill_n(out, 24, s_4bpp_color[0]); out += 24; } @@ -1245,7 +1047,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma template int mcd212_device::ram_dtack_cycle_count<0>(); template int mcd212_device::ram_dtack_cycle_count<1>(); -template +template int mcd212_device::ram_dtack_cycle_count() { // Per MCD-212 documentation, it takes 4 CLKs (2 SCC68070 clocks) for a VRAM access during the System timing slot. @@ -1254,8 +1056,8 @@ int mcd212_device::ram_dtack_cycle_count() if (!BIT(m_dcr[0], DCR_DE_BIT)) return 2; - // No contending for Ch.1/Ch.2 timing slots if a relevant channel is disabled - if (!BIT(m_dcr[Channel], DCR_ICA_BIT)) + // No contending for Ch.1/Ch.2 timing slots if a relevant Path is disabled + if (!BIT(m_dcr[Path], DCR_ICA_BIT)) return 2; const int x = screen().hpos(); @@ -1271,11 +1073,11 @@ int mcd212_device::ram_dtack_cycle_count() return 2; // No contending for Ch.1/Ch.2 timing slots during the free-run area of DCA lines if DCA is disabled - if (!BIT(m_dcr[Channel], DCR_DCA_BIT) && x_outside_active_display) + if (!BIT(m_dcr[Path], DCR_DCA_BIT) && x_outside_active_display) return 2; // System access is restricted to the last 5 out of every 16 CLKs. - const int slot_cycle = (int)(machine().time().as_ticks(clock()) & 0xf); + const int slot_cycle = int(machine().time().as_ticks(clock()) & 0xf); if (slot_cycle >= 11) return 2; @@ -1310,16 +1112,17 @@ void mcd212_device::device_reset() 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); + std::fill_n(m_matte_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); + std::fill_n(m_matte_flag[0], std::size(m_matte_flag[0]), false); + std::fill_n(m_matte_flag[1], std::size(m_matte_flag[1]), false); m_ica_height = 32; m_total_height = 312; + m_blink_time = 0; m_int_callback(CLEAR_LINE); @@ -1340,17 +1143,6 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev { } -//------------------------------------------------- -// device_resolve_objects - resolve objects that -// may be needed for other devices to set -// initial conditions at start time -//------------------------------------------------- - -void mcd212_device::device_resolve_objects() -{ - m_int_callback.resolve_safe(); -} - //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -1365,12 +1157,10 @@ void mcd212_device::device_start() m_delta_uv_lut[d] = s_dyuv_deltas[d >> 4]; } - for (uint16_t w = 0; w < 3 * 0xff; w++) + for (uint16_t w = 0; w < 0x300; w++) { - 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; + const uint8_t limit = (w < 0x100) ? 0 : (w < 0x200) ? (w - 0x100) : 0xff; + m_dyuv_limit_lut[w] = limit; } for (int16_t sw = 0; sw < 0x100; sw++) @@ -1381,10 +1171,6 @@ void mcd212_device::device_start() m_dyuv_v_to_r[sw] = (351 * (sw - 128)) / 256; } - 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)); @@ -1403,12 +1189,19 @@ void mcd212_device::device_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_matte_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])); + save_item(NAME(m_matte_flag)); + save_item(NAME(m_ica_height)); + save_item(NAME(m_total_height)); + + save_item(NAME(m_blink_time)); + save_item(NAME(m_blink_active)); + m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::dca_tick), this)); m_dca_timer->adjust(attotime::never); diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index 521207ef..fe81045a 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -21,8 +21,8 @@ *******************************************************************************/ -#ifndef MAME_VIDEO_MCD212_H -#define MAME_VIDEO_MCD212_H +#ifndef MAME_PHILIPS_MCD212_H +#define MAME_PHILIPS_MCD212_H #pragma once @@ -49,16 +49,15 @@ class mcd212_device : public device_t, uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - void map(address_map &map); + void map(address_map &map) ATTR_COLD; - template int ram_dtack_cycle_count(); + template int ram_dtack_cycle_count(); int rom_dtack_cycle_count(); protected: - // device-level overrides - virtual void device_resolve_objects() override; - virtual void device_start() override; - virtual void device_reset() override; + // device_t implementation + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; TIMER_CALLBACK_MEMBER(ica_tick); TIMER_CALLBACK_MEMBER(dca_tick); @@ -89,10 +88,11 @@ class mcd212_device : public device_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_COF = 0b111 << CURCNT_COF_SHIFT, // Cursor off time CURCNT_CON_SHIFT = 19, + CURCNT_CON = 0b111 << CURCNT_CON_SHIFT, // Cursor on time + CURCNT_BLKC_SHIFT = 22, CURCNT_BLKC = 0x400000, // Blink type CURCNT_EN = 0x800000, // Cursor enable @@ -101,40 +101,42 @@ class mcd212_device : public device_t, ICM_MODE2 = 0x000f00, // Plane 2 ICM_MODE2_SHIFT = 8, ICM_EV = 0x040000, // External video - ICM_NR = 0x080000, // Number of region flags - ICM_NR_BIT = 19, + ICM_EV_BIT = 18, + ICM_NM = 0x080000, // Number of Matte flags + ICM_NM_BIT = 19, ICM_CS = 0x400000, // CLUT select + ICM_CS_BIT = 22, TCR_TA = 0x00000f, // Plane A TCR_TB = 0x000f00, // Plane B TCR_TB_SHIFT = 8, - 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_ALWAYS = 0x0, // Transparent if: Always (Plane Disabled) + TCR_KEY = 0x1, // Transparent if: Color Key = True + TCR_RGB = 0x2, // Transparent if: Transparency Bit = 1 (RGB Only) + TCR_MF0 = 0x3, // Transparent if: Matte Flag 0 = True + TCR_MF1 = 0x4, // Transparent if: Matte Flag 1 = True + TCR_MF0_KEY1 = 0x5, // Transparent if: Matte Flag 0 = True || Color Key = True + TCR_MF1_KEY1 = 0x6, // Transparent if: Matte 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_NEVER = 0x8, // Transparent if: Never (No Transparent Area) + TCR_NOT_KEY = 0x9, // Transparent if: Color Key = False + TCR_NOT_RGB = 0xa, // Transparent if: Transparency Bit = 0 (RGB Only) + TCR_NOT_MF0 = 0xb, // Transparent if: Matte Flag 0 = False + TCR_NOT_MF1 = 0xc, // Transparent if: Matte Flag 1 = False + TCR_NOT_MF0_KEY = 0xd, // Transparent if: Matte Flag 0 = False || Color Key = False + TCR_NOT_MF1_KEY = 0xe, // Transparent if: Matte Flag 1 = False || Color Key = False TCR_COND_UNUSED1 = 0xf, // Unused TCR_DISABLE_MX = 0x800000, // Mix disable 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, + MC_X = 0x0003ff, // X position + MC_WF = 0x00fc00, // Weight position + MC_WF_SHIFT = 10, + MC_MF_BIT = 16, // Matte flag bit + MC_OP = 0xf00000, // Operation + MC_OP_SHIFT = 20, CSR1R_PA = 0x20, // Parity CSR1R_DA = 0x80, // Display Active @@ -172,40 +174,38 @@ class mcd212_device : public device_t, ICM_OFF = 0x0, ICM_CLUT8 = 0x1, - ICM_RGB555 = 0x2, + ICM_RGB555 = 0x1, ICM_CLUT7 = 0x3, ICM_CLUT77 = 0x4, ICM_DYUV = 0x5, ICM_CLUT4 = 0xb }; - 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]; + 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 = 0; + uint32_t m_transparency_control = 0; + uint32_t m_plane_order = 0; + 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 = 0; + uint32_t m_cursor_control = 0; + uint32_t m_cursor_pattern[16]{}; + uint32_t m_matte_control[8]{}; + uint32_t m_backdrop_color = 0; + 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]; + uint32_t m_dyuv_limit_lut[0x300]; // DYUV delta-Y decoding array uint8_t m_delta_y_lut[0x100]; @@ -232,40 +232,44 @@ class mcd212_device : public device_t, required_shared_ptr m_planeb; // internal state - bool m_region_flag[2][768]; - int m_ica_height; - int m_total_height; - emu_timer *m_ica_timer; - emu_timer *m_dca_timer; + bool m_matte_flag[2][768]{}; + int m_ica_height = 0; + int m_total_height = 0; + emu_timer *m_ica_timer = nullptr; + emu_timer *m_dca_timer = nullptr; + + // Cursor State + uint16_t m_blink_time; // Counter that tracks how long since the last m_blink_active last changed. + bool m_blink_active = false; static const uint32_t s_4bpp_color[16]; - uint8_t get_weight_factor(const uint32_t region_idx); - uint8_t get_region_op(const uint32_t region_idx); - void update_region_arrays(); + uint8_t get_weight_factor(const uint32_t Matte_idx); + uint8_t get_matte_op(const uint32_t Matte_idx); + void update_matte_arrays(); int get_screen_width(); int get_border_width(); - template int get_plane_width(); + uint32_t get_backdrop_plane(); - template void set_vsr(uint32_t value); - template uint32_t get_vsr(); + 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_dcp(uint32_t value); + template uint32_t get_dcp(); - template void set_display_parameters(uint8_t value); + template void set_display_parameters(uint8_t value); - template void process_ica(); - template void process_dca(); + template void process_ica(); + template void process_dca(); - 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); + 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); - template void set_register(uint8_t reg, uint32_t value); + template void set_register(uint8_t reg, uint32_t value); template void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out); @@ -275,4 +279,4 @@ class mcd212_device : public device_t, // device type definition DECLARE_DEVICE_TYPE(MCD212, mcd212_device) -#endif // MAME_VIDEO_MCD212_H +#endif // MAME_PHILIPS_MCD212_H From 964e582c459aeaf822ceec29fafad1310dc6042e Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 13:15:49 -0600 Subject: [PATCH 18/47] mcd212 updates. --- src/mame/video/mcd212.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 89592e5c..19c0f243 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -1202,9 +1202,9 @@ void mcd212_device::device_start() save_item(NAME(m_blink_time)); save_item(NAME(m_blink_active)); - m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::dca_tick), this)); + m_dca_timer = timer_alloc(FUNC(mcd212_device::dca_tick), this); m_dca_timer->adjust(attotime::never); - m_ica_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::ica_tick), this)); + m_ica_timer = timer_alloc(FUNC(mcd212_device::ica_tick), this); m_ica_timer->adjust(attotime::never); } From a94861476fd2af739005dea8ebad95d5afec1525 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 13:17:44 -0600 Subject: [PATCH 19/47] mcd212 updates. --- src/mame/video/mcd212.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 19c0f243..89592e5c 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -1202,9 +1202,9 @@ void mcd212_device::device_start() save_item(NAME(m_blink_time)); save_item(NAME(m_blink_active)); - m_dca_timer = timer_alloc(FUNC(mcd212_device::dca_tick), this); + m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::dca_tick), this)); m_dca_timer->adjust(attotime::never); - m_ica_timer = timer_alloc(FUNC(mcd212_device::ica_tick), this); + m_ica_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::ica_tick), this)); m_ica_timer->adjust(attotime::never); } From 083bb93695478e5c8d24f7c29b97074d6bfc8900 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 13:31:35 -0600 Subject: [PATCH 20/47] Change define from MAME_PHILIPS_MCD212_H to MAME_VIDEO_MCD212_H. --- src/mame/video/mcd212.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index fe81045a..5921b9f4 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -21,8 +21,8 @@ *******************************************************************************/ -#ifndef MAME_PHILIPS_MCD212_H -#define MAME_PHILIPS_MCD212_H +#ifndef MAME_VIDEO_MCD212_H +#define MAME_VIDEO_MCD212_H #pragma once From b5b3a060c11e987c32695763a8a469fd08712778 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:14:13 -0600 Subject: [PATCH 21/47] Update mcd212 driver again. No interlacing involved. --- src/mame/video/mcd212.cpp | 15 +++++---------- src/mame/video/mcd212.h | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 89592e5c..140cc164 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -83,7 +83,7 @@ void mcd212_device::update_matte_arrays() case 0: // Disregard all commands in higher registers. See 5.10.2 matte_idx[matte] = 8; break; - case 1: case 2: case 3: case 5: case 7: case 10: case 11: // Not used + case 1: case 2: case 3: case 5: case 7: case 10: case 11: // Not used break; case 4: case 6: // Change weight of plane (A or B) latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); @@ -318,15 +318,12 @@ int mcd212_device::get_border_width() return width; } -uint32_t mcd212_device::get_backdrop_plane() { +uint32_t mcd212_device::get_backdrop_plane() +{ if (BIT(m_image_coding_method, ICM_EV_BIT)) - { return 0; // External Video Background. Default to Black since there is no DVC. - } else - { return s_4bpp_color[m_backdrop_color]; - } } template @@ -664,12 +661,10 @@ void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t * uint8_t *weight_b = &m_weight_factor[1][0]; // Console Verified. CLUT4 pixels are drawn in pairs during VSR. So the mosaic here is halved. - if (icmA == ICM_CLUT4) { + if (icmA == ICM_CLUT4) mosaic_count_a >>= 1; - } - if (icmB == ICM_CLUT4) { + if (icmB == ICM_CLUT4) mosaic_count_b >>= 1; - } for (int x = 0; x < width; x++) { diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index 5921b9f4..fe81045a 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -21,8 +21,8 @@ *******************************************************************************/ -#ifndef MAME_VIDEO_MCD212_H -#define MAME_VIDEO_MCD212_H +#ifndef MAME_PHILIPS_MCD212_H +#define MAME_PHILIPS_MCD212_H #pragma once From 051f4b03b5c29152b4fccc5f16651db5291fcebe Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:26:23 -0600 Subject: [PATCH 22/47] Remove all logging references. Not used here, it seems. --- src/mame/video/mcd212.cpp | 72 --------------------------------------- 1 file changed, 72 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 140cc164..f69e5786 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -25,17 +25,6 @@ #include "mcd212.h" #include "screen.h" -#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" @@ -121,95 +110,81 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: { const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); - LOGMASKED(LOG_CLUT, "%s: Path %d: CLUT[%d] = %08x\n", machine().describe_context(), Path, clut_index, value); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method if (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Path 0: Image Coding Method = %08x\n", machine().describe_context(), value); m_image_coding_method = value; } break; case 0xc1: // Transparency Control if (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Transparency Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_transparency_control = value; } break; case 0xc2: // Plane Order if (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Plane Order = %08x\n", machine().describe_context(), screen().vpos(), value & 7); m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: CLUT Bank Register = %08x\n", machine().describe_context(), screen().vpos(), Path, value & 3); m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A if (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Position = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_position = value; } break; case 0xce: // Cursor Control if (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_control = value; } break; case 0xcf: // Cursor Pattern if (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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; @@ -221,35 +196,30 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xd5: case 0xd6: case 0xd7: - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: matte Control %d = %08x\n", machine().describe_context(), screen().vpos(), Path, reg & 7, value); m_matte_control[reg & 7] = value; update_matte_arrays(); break; case 0xd8: // Backdrop Color if (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Backdrop Color = %08x\n", machine().describe_context(), screen().vpos(), value); m_backdrop_color = value; } break; case 0xd9: // Mosaic Pixel Hold Factor A if (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Weight Factor A = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[0][0] = (uint8_t)value; update_matte_arrays(); } @@ -257,7 +227,6 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xdc: // Weight Factor B if (Path == 1) { - LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 1: Weight Factor B = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[1][0] = (uint8_t)value; update_matte_arrays(); } @@ -342,45 +311,36 @@ void mcd212_device::process_ica() { 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR and STOP: VSR = %05x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); m_csrr[1] |= 1 << (2 - Path); 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 - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); set_display_parameters(cmd & 0x1f); break; default: - LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: SET REGISTER %02x = %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd >> 24, cmd & 0x00ffffff); set_register(cmd >> 24, cmd & 0x00ffffff); break; } @@ -398,7 +358,6 @@ void mcd212_device::process_dca() bool addr_changed = false; bool processing = true; - LOGMASKED(LOG_DCA, "Scanline %d: Processing DCA %d\n", screen().vpos(), Path); while (processing && count < max) { @@ -409,43 +368,34 @@ void mcd212_device::process_dca() { 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP (NOP)\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP and STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); set_dcp(cmd & 0x003ffffc); m_dca[Path] = 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); m_csrr[1] |= 1 << (2 - Path); 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 - LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); set_display_parameters(cmd & 0x1f); break; default: @@ -553,8 +503,6 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); - LOGMASKED(LOG_VSR, "Scanline %d: VSR Path %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Path, icm, vsr); - for (uint32_t x = 0; x < width; ) { const uint8_t byte = data[(vsr++ & 0x0007ffff) ^ 1]; @@ -779,61 +727,51 @@ void mcd212_device::map(address_map &map) 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_MAIN_REG_WRITES, "%s: Control/Status Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_csrw[0]); } uint16_t mcd212_device::dcr1_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[0]); } uint16_t mcd212_device::vsr1_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Decoder Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_ddr[0]); } uint16_t mcd212_device::dca1_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_READS, "%s: DCA Pointer 1 Read: %04x & %08x\n", machine().describe_context(), m_dca[0], mem_mask); return m_dca[0]; } void mcd212_device::dca1_w(offs_t offset, uint16_t data, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_WRITES, "%s: DCA Pointer 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[0]); } @@ -845,7 +783,6 @@ uint8_t mcd212_device::csr2_r() } 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)) @@ -856,55 +793,46 @@ uint8_t mcd212_device::csr2_r() void mcd212_device::csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[1]); } uint16_t mcd212_device::vsr2_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: DCA Pointer 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[1]); } From bf2d3c85a97139bb63676b009b11c79dff3de465 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:30:35 -0600 Subject: [PATCH 23/47] Update monitor_retro.cpp --- src/osd/modules/monitor/monitor_retro.cpp | 53 +++++------------------ 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/src/osd/modules/monitor/monitor_retro.cpp b/src/osd/modules/monitor/monitor_retro.cpp index da880532..4b35d7ac 100644 --- a/src/osd/modules/monitor/monitor_retro.cpp +++ b/src/osd/modules/monitor/monitor_retro.cpp @@ -2,12 +2,12 @@ * monitor_retro.cpp * */ -#include "emu.h" #include "modules/osdmodule.h" #include "monitor_module.h" #include "modules/osdwindow.h" #include "monitor_common.h" +#include "osdcore.h" #include "libretro/libretro-internal/libretro_shared.h" @@ -27,16 +27,10 @@ class retro_monitor_info : public osd_monitor_info private: void refresh() override { - m_pos_size = osd_rect(0,0, fb_width, fb_height); m_usuable_pos_size = osd_rect(0,0, fb_width, fb_height); m_is_primary = (oshandle() == 0); - - if(alternate_renderer==false) - set_aspect(retro_aspect); - //printf("refreshmonitor (%d x %d) a:%f\n", fb_width, fb_height,retro_aspect); } - }; //============================================================ @@ -88,52 +82,29 @@ class retro_monitor_module : public monitor_module_base protected: int init_internal(const osd_options& options) override { - // make a list of monitors - { - int i; - - osd_printf_verbose("Enter init_monitors\n"); + int i; - for (i = 0; i < 1; i++) - { - char temp[64]; - snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); - - // allocate a new monitor info - std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); + for (i = 0; i < 1; i++) + { + char temp[64]; + snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); - osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename().c_str(), - monitor->position_size().width(), monitor->position_size().height()); + // allocate a new monitor info + std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); - // guess the aspect ratio assuming square pixels - monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); -printf("Adding monitor %s (%d x %d) a:%f\n", monitor->devicename().c_str(), - monitor->position_size().width(), monitor->position_size().height(),(float)monitor->position_size().width()/(float) monitor->position_size().height()); + // guess the aspect ratio assuming square pixels + monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); - // hook us into the list - add_monitor(monitor); - } + // hook us into the list + add_monitor(monitor); } - osd_printf_verbose("Leave init_monitors\n"); return 0; } private: -/* - sdl.h = osd.height(); - sdl.w = osd.width(); - sdl.x = osd.left(); - sdl.y = osd.top(); - -*/ static int compute_intersection(const osd_rect &rect1, const osd_rect &rect2) { -/* - SDL_Rect intersection; - if (SDL_IntersectRect(&sdl1, &sdl2, &intersection)) - return intersection.w + intersection.h; -*/ return 0; } }; From 45d64b0804d49e68500c53c97a2895fe69c081a5 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:32:20 -0600 Subject: [PATCH 24/47] Update screen driver --- src/emu/screen.cpp | 337 +++++++++++++++++++++++++++++---------------- src/emu/screen.h | 60 ++++---- 2 files changed, 240 insertions(+), 157 deletions(-) diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp index 3ef25676..cd8c2012 100644 --- a/src/emu/screen.cpp +++ b/src/emu/screen.cpp @@ -12,6 +12,8 @@ #include "screen.h" #include "emuopts.h" +#include "fileio.h" +#include "main.h" #include "render.h" #include "rendutil.h" @@ -20,6 +22,19 @@ #include +#ifdef __LIBRETRO__ +#include "libretro/osdretro.h" +#endif + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define VERBOSE (0) +#define LOG_PARTIAL_UPDATES(x) do { if (VERBOSE) logerror x; } while (0) + + + //************************************************************************** // GLOBAL VARIABLES //************************************************************************** @@ -543,8 +558,9 @@ screen_device::screen_device(const machine_config &mconfig, const char *tag, dev , m_curbitmap(0) , m_curtexture(0) , m_changed(true) + , m_last_partial_reset(attotime::zero) , m_last_partial_scan(0) - , m_partial_scan_hpos(-1) + , m_partial_scan_hpos(0) , m_color(rgb_t(0xff, 0xff, 0xff, 0xff)) , m_brightness(0xff) , m_frame_period(DEFAULT_FRAME_PERIOD.as_attoseconds()) @@ -760,8 +776,6 @@ void screen_device::device_resolve_objects() // bind our handlers m_screen_update_ind16.resolve(); m_screen_update_rgb32.resolve(); - m_screen_vblank.resolve_safe(); - m_scanline_cb.resolve(); // assign our format to the palette before it starts if (m_palette) @@ -824,15 +838,19 @@ void screen_device::device_start() m_container->set_user_settings(settings); // allocate the VBLANK timers - m_vblank_begin_timer = timer_alloc(TID_VBLANK_START); - m_vblank_end_timer = timer_alloc(TID_VBLANK_END); + m_vblank_begin_timer = timer_alloc(FUNC(screen_device::vblank_begin), this); + m_vblank_end_timer = timer_alloc(FUNC(screen_device::vblank_end), this); // allocate a timer to reset partial updates - m_scanline0_timer = timer_alloc(TID_SCANLINE0); + m_scanline0_timer = timer_alloc(FUNC(screen_device::first_scanline_tick), this); // allocate a timer to generate per-scanline updates - if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb) - m_scanline_timer = timer_alloc(TID_SCANLINE); + if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset()) + m_scanline_timer = timer_alloc(FUNC(screen_device::scanline_tick), this); + +#ifdef __LIBRETRO__ + screen_configured = 0; +#endif // configure the screen with the default parameters configure(m_width, m_height, m_visarea, m_refresh); @@ -842,7 +860,7 @@ void screen_device::device_start() m_vblank_end_time = attotime(0, m_vblank_period); // start the timer to generate per-scanline updates - if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb) + if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset()) m_scanline_timer->adjust(time_until_pos(0)); // create burn-in bitmap @@ -867,6 +885,7 @@ void screen_device::device_start() save_item(NAME(m_visarea.min_y)); save_item(NAME(m_visarea.max_x)); save_item(NAME(m_visarea.max_y)); + save_item(NAME(m_last_partial_reset)); save_item(NAME(m_last_partial_scan)); save_item(NAME(m_frame_period)); save_item(NAME(m_brightness)); @@ -876,6 +895,9 @@ void screen_device::device_start() save_item(NAME(m_vblank_start_time)); save_item(NAME(m_vblank_end_time)); save_item(NAME(m_frame_number)); + if (m_oldstyle_vblank_supplied) + logerror("%s: Deprecated legacy Old Style screen configured (set_vblank_time), please use set_raw instead.\n",this->tag()); + m_is_primary_screen = (this == screen_device_enumerator(machine().root_device()).first()); } @@ -917,54 +939,39 @@ void screen_device::device_post_load() //------------------------------------------------- -// device_timer - called whenever a device timer -// fires +// timer events //------------------------------------------------- -void screen_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(screen_device::first_scanline_tick) { - switch (id) + // first scanline + reset_partial_updates(); + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - // signal VBLANK start - case TID_VBLANK_START: - vblank_begin(); - break; - - // signal VBLANK end - case TID_VBLANK_END: - vblank_end(); - break; - - // first scanline - case TID_SCANLINE0: - reset_partial_updates(); - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) - { - pre_update_scanline(0); - } - break; + pre_update_scanline(0); + } +} - // subsequent scanlines when scanline updates are enabled - case TID_SCANLINE: - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) - { - pre_update_scanline(param); - } - if (m_video_attributes & VIDEO_UPDATE_SCANLINE) - { - // force a partial update to the current scanline - update_partial(param); - } - if (m_scanline_cb) - m_scanline_cb(param); - - // compute the next visible scanline - param++; - if (param > m_visarea.bottom()) - param = m_visarea.top(); - m_scanline_timer->adjust(time_until_pos(param), param); - break; +TIMER_CALLBACK_MEMBER(screen_device::scanline_tick) +{ + // subsequent scanlines when scanline updates are enabled + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + { + pre_update_scanline(param); + } + if (m_video_attributes & VIDEO_UPDATE_SCANLINE) + { + // force a partial update to the current scanline + update_partial(param); } + if (!m_scanline_cb.isunset()) + m_scanline_cb(param); + + // compute the next visible scanline + param++; + if (param > m_visarea.bottom()) + param = m_visarea.top(); + m_scanline_timer->adjust(time_until_pos(param), param); } @@ -1006,6 +1013,15 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a else m_vblank_period = m_scantime * (height - visarea.height()); +#ifdef __LIBRETRO__ + /* Performance hack fix for "pong" and "breakout" */ + if (screen_configured > 10 + && width == m_width + && height == m_height + && floorf(ATTOSECONDS_TO_HZ(frame_period)) == floorf(ATTOSECONDS_TO_HZ(m_frame_period))) + return; +#endif + // we are now fully configured with the new parameters // and can safely call time_until_pos(), etc. @@ -1013,7 +1029,7 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a // call the VBLANK start timer now; otherwise, adjust it for the future attoseconds_t delta = (machine().time() - m_vblank_start_time).as_attoseconds(); if (delta >= m_frame_period) - vblank_begin(); + vblank_begin(0); else m_vblank_begin_timer->adjust(time_until_vblank_start()); @@ -1026,6 +1042,17 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a // adjust speed if necessary machine().video().update_refresh_speed(); + +#ifdef __LIBRETRO__ + float retro_fps_new = ATTOSECONDS_TO_HZ(m_frame_period); + if (!screen_configured + && retro_fps_new != retro_fps + && retro_fps_new <= 120.0f + && retro_fps_new >= 40.0f) + retro_fps = retro_fps_new; + + screen_configured++; +#endif } @@ -1041,19 +1068,19 @@ void screen_device::reset_origin(int beamy, int beamx) m_vblank_end_time = curtime - attotime(0, beamy * m_scantime + beamx * m_pixeltime); m_vblank_start_time = m_vblank_end_time - attotime(0, m_vblank_period); + // if we are resetting relative to (visarea.bottom() + 1, 0) == VBLANK start, + // call the VBLANK start timer now; otherwise, adjust it for the future + if (beamy == ((m_visarea.bottom() + 1) % m_height) && beamx == 0) + vblank_begin(0); + else + m_vblank_begin_timer->adjust(time_until_vblank_start()); + // if we are resetting relative to (0,0) == VBLANK end, call the // scanline 0 timer by hand now; otherwise, adjust it for the future if (beamy == 0 && beamx == 0) reset_partial_updates(); else m_scanline0_timer->adjust(time_until_pos(0)); - - // if we are resetting relative to (visarea.bottom() + 1, 0) == VBLANK start, - // call the VBLANK start timer now; otherwise, adjust it for the future - if (beamy == ((m_visarea.bottom() + 1) % m_height) && beamx == 0) - vblank_begin(); - else - m_vblank_begin_timer->adjust(time_until_vblank_start()); } @@ -1143,21 +1170,40 @@ void screen_device::set_visible_area(int min_x, int max_x, int min_y, int max_y) bool screen_device::update_partial(int scanline) { + LOG_PARTIAL_UPDATES(("Partial: update_partial(%s, %d): ", tag(), scanline)); + // these two checks only apply if we're allowed to skip frames if (!(m_video_attributes & VIDEO_ALWAYS_UPDATE)) { // if skipping this frame, bail if (machine().video().skip_this_frame()) + { + LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n")); return false; + } // skip if this screen is not visible anywhere if (!machine().render().is_live(*this)) + { + LOG_PARTIAL_UPDATES(("skipped because screen not live\n")); return false; + } } // skip if we already rendered this line if (scanline < m_last_partial_scan) + { + LOG_PARTIAL_UPDATES(("skipped because line was already rendered\n")); return false; + } + + // skip if we already rendered this frame + // this can happen if a cpu timeslice that called update_partial is in the previous frame while scanline 0 already started + if (m_last_partial_scan == 0 && m_last_partial_reset > machine().time()) + { + LOG_PARTIAL_UPDATES(("skipped because frame was already rendered\n")); + return false; + } // set the range of scanlines to render rectangle clip(m_visarea); @@ -1165,46 +1211,61 @@ bool screen_device::update_partial(int scanline) // skip if entirely outside of visible area if (clip.top() > clip.bottom()) + { + LOG_PARTIAL_UPDATES(("skipped because outside of visible area\n")); return false; + } // otherwise, render + LOG_PARTIAL_UPDATES(("updating %d-%d\n", clip.top(), clip.bottom())); + u32 flags = 0; - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - rectangle scan_clip(clip); - for (int y = clip.top(); y <= clip.bottom(); y++) + auto profile = g_profiler.start(PROFILER_VIDEO); + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - scan_clip.sety(y, y); - pre_update_scanline(y); - - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - switch (curbitmap.format()) + rectangle scan_clip(clip); + for (int y = clip.top(); y <= clip.bottom(); y++) { - default: - case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; - case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; - } + scan_clip.sety(y, y); + pre_update_scanline(y); - m_partial_updates_this_frame++; - } - } - else - { - if (m_type != SCREEN_TYPE_SVG) - { - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - switch (curbitmap.format()) - { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; + case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; + } + + m_partial_updates_this_frame++; } } else { - flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); + if (m_type != SCREEN_TYPE_SVG) + { + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + } + } + else + { + // optional screen_update callback before rendering svg (eg. for preparing outputs used by the svg) + // bitmap can be considered read-only, as it gets overwritten later + if (!m_screen_update_rgb32.isnull()) + flags = m_screen_update_rgb32(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); + + if (~flags & UPDATE_HAS_NOT_CHANGED) + flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); + } + m_partial_updates_this_frame++; } - m_partial_updates_this_frame++; + // stop profiling } // if we modified the bitmap, we have to commit @@ -1212,7 +1273,7 @@ bool screen_device::update_partial(int scanline) // remember where we left off m_last_partial_scan = scanline + 1; - m_partial_scan_hpos = -1; + m_partial_scan_hpos = 0; return true; } @@ -1229,11 +1290,17 @@ void screen_device::update_now() { // if skipping this frame, bail if (machine().video().skip_this_frame()) + { + LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n")); return; + } // skip if this screen is not visible anywhere if (!machine().render().is_live(*this)) + { + LOG_PARTIAL_UPDATES(("skipped because screen not live\n")); return; + } } int current_vpos = vpos(); @@ -1242,20 +1309,36 @@ void screen_device::update_now() // skip if we already rendered this line if (current_vpos < m_last_partial_scan) + { + LOG_PARTIAL_UPDATES(("skipped because line was already rendered\n")); return; + } // if beam position is the same, there's nothing to update if (current_vpos == m_last_partial_scan && current_hpos == m_partial_scan_hpos) + { + LOG_PARTIAL_UPDATES(("skipped because beam position is unchanged\n")); return; + } + + // skip if we already rendered this frame + // this can happen if a cpu timeslice that called update_now is in the previous frame while scanline 0 already started + if (m_last_partial_scan == 0 && m_partial_scan_hpos == 0 && m_last_partial_reset > machine().time()) + { + LOG_PARTIAL_UPDATES(("skipped because frame was already rendered\n")); + return; + } + + LOG_PARTIAL_UPDATES(("update_now(): Y=%d, X=%d, last partial %d, partial hpos %d (vis %d %d)\n", current_vpos, current_hpos, m_last_partial_scan, m_partial_scan_hpos, m_visarea.right(), m_visarea.bottom())); // start off by doing a partial update up to the line before us, in case that was necessary if (current_vpos > m_last_partial_scan) { // if the line before us was incomplete, we must do it in two pieces - if (m_partial_scan_hpos >= 0) + if (m_partial_scan_hpos > 0) { // now finish the previous partial scanline - clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1), + clip.set((std::max)(clip.left(), m_partial_scan_hpos), clip.right(), (std::max)(clip.top(), m_last_partial_scan), (std::min)(clip.bottom(), m_last_partial_scan)); @@ -1263,6 +1346,8 @@ void screen_device::update_now() // if there's something to draw, do it if (!clip.empty()) { + auto profile = g_profiler.start(PROFILER_VIDEO); + u32 flags = 0; screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; if (m_video_attributes & VIDEO_VARIABLE_WIDTH) @@ -1291,7 +1376,7 @@ void screen_device::update_now() m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; } - m_partial_scan_hpos = -1; + m_partial_scan_hpos = 0; m_last_partial_scan++; } if (current_vpos > m_last_partial_scan) @@ -1301,42 +1386,49 @@ void screen_device::update_now() } // now draw this partial scanline - clip = m_visarea; + if (current_hpos > 0) + { + clip = m_visarea; - clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1), - (std::min)(clip.right(), current_hpos), - (std::max)(clip.top(), current_vpos), - (std::min)(clip.bottom(), current_vpos)); + clip.set((std::max)(clip.left(), m_partial_scan_hpos), + (std::min)(clip.right(), current_hpos - 1), + (std::max)(clip.top(), current_vpos), + (std::min)(clip.bottom(), current_vpos)); - // and if there's something to draw, do it - if (!clip.empty()) - { - u32 flags = 0; - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + // and if there's something to draw, do it + if (!clip.empty()) { - pre_update_scanline(current_vpos); - switch (curbitmap.format()) + auto profile = g_profiler.start(PROFILER_VIDEO); + + LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.bottom(), clip.left(), clip.right())); + + u32 flags = 0; + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; + pre_update_scanline(current_vpos); + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; + } } - } - else - { - switch (curbitmap.format()) + else { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; + } } - } - m_partial_updates_this_frame++; + m_partial_updates_this_frame++; - // if we modified the bitmap, we have to commit - m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; + // if we modified the bitmap, we have to commit + m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; + } } // remember where we left off @@ -1352,8 +1444,9 @@ void screen_device::update_now() void screen_device::reset_partial_updates() { + m_last_partial_reset = machine().time(); m_last_partial_scan = 0; - m_partial_scan_hpos = -1; + m_partial_scan_hpos = 0; m_partial_updates_this_frame = 0; m_scanline0_timer->adjust(time_until_pos(0)); } @@ -1592,7 +1685,7 @@ void screen_device::register_screen_bitmap(bitmap_t &bitmap) // signal the VBLANK period has begun //------------------------------------------------- -void screen_device::vblank_begin() +TIMER_CALLBACK_MEMBER(screen_device::vblank_begin) { // reset the starting VBLANK time m_vblank_start_time = machine().time(); @@ -1612,7 +1705,7 @@ void screen_device::vblank_begin() // if no VBLANK period, call the VBLANK end callback immediately, otherwise reset the timer if (m_vblank_period == 0) - vblank_end(); + vblank_end(0); else m_vblank_end_timer->adjust(time_until_vblank_end()); } @@ -1623,7 +1716,7 @@ void screen_device::vblank_begin() // signal the VBLANK period has ended //------------------------------------------------- -void screen_device::vblank_end() +TIMER_CALLBACK_MEMBER(screen_device::vblank_end) { // call the screen specific callbacks for (auto &item : m_callback_list) @@ -1873,7 +1966,7 @@ void screen_device::finalize_burnin() //------------------------------------------------- -// finalize_burnin - finalize the burnin bitmap +// load_effect_overlay - //------------------------------------------------- void screen_device::load_effect_overlay(const char *filename) diff --git a/src/emu/screen.h b/src/emu/screen.h index b909c25c..31451d9b 100644 --- a/src/emu/screen.h +++ b/src/emu/screen.h @@ -13,6 +13,8 @@ #pragma once +#include "rendertypes.h" + #include #include @@ -31,28 +33,18 @@ enum screen_type_enum SCREEN_TYPE_SVG }; -// texture formats -enum texture_format -{ - TEXFORMAT_UNDEFINED = 0, // require a format to be specified - TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha - TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB - TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB - TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence -}; - // screen_update callback flags -constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed +constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed /*! @defgroup flags for video_attributes @{ @def VIDEO_UPDATE_BEFORE_VBLANK - update_video called at the start of the VBLANK period + update_video called at the start of the VBLANK period, this is the default @todo hack, remove me @def VIDEO_UPDATE_AFTER_VBLANK - update_video called at the end of the VBLANK period + update_video called at the end of the VBLANK period (in other words: before active display) @todo hack, remove me @def VIDEO_SELF_RENDER @@ -233,9 +225,10 @@ class screen_device : public device_t screen_device &set_raw(u32 pixclock, u16 htotal, u16 hbend, u16 hbstart, u16 vtotal, u16 vbend, u16 vbstart) { assert(pixclock != 0); - m_clock = pixclock; + set_clock(pixclock); m_refresh = HZ_TO_ATTOSECONDS(pixclock) * htotal * vtotal; m_vblank = m_refresh / vtotal * (vtotal - (vbstart - vbend)); + m_oldstyle_vblank_supplied = false; m_width = htotal; m_height = vtotal; m_visarea.set(hbend, hbstart ? hbstart - 1 : htotal - 1, vbend, vbstart - 1); @@ -246,6 +239,10 @@ class screen_device : public device_t xtal.validate(std::string("Configuring screen ") + tag()); return set_raw(xtal.value(), htotal, hbend, hbstart, vtotal, vbend, vbstart); } + screen_device &set_raw(const XTAL &xtal, u16 htotal, u16 vtotal, rectangle visarea) + { + return set_raw(xtal, htotal, visarea.left(), visarea.right() + 1, vtotal, visarea.top(), visarea.bottom() + 1); + } void set_refresh(attoseconds_t rate) { m_refresh = rate; } /// \brief Set refresh rate in Hertz @@ -389,8 +386,8 @@ class screen_device : public device_t // beam positioning and state int vpos() const; int hpos() const; - DECLARE_READ_LINE_MEMBER(vblank) const { return (machine().time() < m_vblank_end_time) ? 1 : 0; } - DECLARE_READ_LINE_MEMBER(hblank) const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; } + int vblank() const { return (machine().time() < m_vblank_end_time) ? 1 : 0; } + int hblank() const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; } // timing attotime time_until_pos(int vpos, int hpos = 0) const; @@ -428,30 +425,22 @@ class screen_device : public device_t private: class svg_renderer; - // timer IDs - enum - { - TID_VBLANK_START, - TID_VBLANK_END, - TID_SCANLINE0, - TID_SCANLINE - }; - // device-level overrides virtual void device_validity_check(validity_checker &valid) const override; virtual void device_config_complete() override; - virtual void device_resolve_objects() override; - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_stop() override; + virtual void device_resolve_objects() override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual void device_stop() override ATTR_COLD; virtual void device_post_load() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; // internal helpers void set_container(render_container &container) { m_container = &container; } void realloc_screen_bitmaps(); - void vblank_begin(); - void vblank_end(); + TIMER_CALLBACK_MEMBER(vblank_begin); + TIMER_CALLBACK_MEMBER(vblank_end); + TIMER_CALLBACK_MEMBER(first_scanline_tick); + TIMER_CALLBACK_MEMBER(scanline_tick); void finalize_burnin(); void load_effect_overlay(const char *filename); void update_scan_bitmap_size(int y); @@ -473,7 +462,7 @@ class screen_device : public device_t screen_update_rgb32_delegate m_screen_update_rgb32; // screen update callback (32-bit RGB) devcb_write_line m_screen_vblank; // screen vblank line callback devcb_write32 m_scanline_cb; // screen scanline callback - optional_device m_palette; // our palette + optional_device m_palette; // our palette u32 m_video_attributes; // flags describing the video system optional_memory_region m_svg_region; // the region in which the svg data is in @@ -497,6 +486,7 @@ class screen_device : public device_t u8 m_curbitmap; // current bitmap index u8 m_curtexture; // current texture index bool m_changed; // has this bitmap changed? + attotime m_last_partial_reset; // last time partial updates were reset s32 m_last_partial_scan; // scanline of last partial update s32 m_partial_scan_hpos; // horizontal pixel last rendered on this partial scanline bitmap_argb32 m_screen_overlay_bitmap; // screen overlay bitmap @@ -516,7 +506,7 @@ class screen_device : public device_t emu_timer * m_scanline0_timer; // scanline 0 timer emu_timer * m_scanline_timer; // scanline timer u64 m_frame_number; // the current frame number - u32 m_partial_updates_this_frame;// partial update counter this frame + u32 m_partial_updates_this_frame; // partial update counter this frame bool m_is_primary_screen; @@ -529,7 +519,7 @@ class screen_device : public device_t vblank_state_delegate m_callback; }; - std::vector> m_callback_list; // list of VBLANK callbacks + std::vector> m_callback_list; // list of VBLANK callbacks // auto-sizing bitmaps class auto_bitmap_item From 27bfc22efdc18a519be9d3d191bbbfd25ddfc49f Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:43:48 -0600 Subject: [PATCH 25/47] Update rendering. --- src/emu/render.cpp | 434 ++++++++++++++++++++++------------------- src/emu/render.h | 59 +++--- src/emu/rendertypes.h | 10 + src/emu/rendutil.h | 19 +- src/lib/util/ioprocs.h | 127 +++++++++++- 5 files changed, 406 insertions(+), 243 deletions(-) diff --git a/src/emu/render.cpp b/src/emu/render.cpp index d1fe139c..19f99955 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -41,6 +41,7 @@ #include "corestr.h" #include "emuopts.h" +#include "fileio.h" #include "rendfont.h" #include "rendlay.h" #include "rendutil.h" @@ -56,6 +57,7 @@ #include "util/xmlfile.h" #include +#include @@ -98,6 +100,20 @@ struct render_target::object_transform }; +struct render_target::hit_test +{ + hit_test() noexcept + : inbounds(0U, 0U) + , hit(0U) + { + } + + std::pair inbounds; + u64 hit; +}; + + + //************************************************************************** // GLOBAL VARIABLES @@ -300,7 +316,8 @@ render_texture::render_texture() m_curseq(0) { m_sbounds.set(0, -1, 0, -1); - memset(m_scaled, 0, sizeof(m_scaled)); + for (auto &elem : m_scaled) + elem.seqid = 0; } @@ -352,6 +369,7 @@ void render_texture::release() m_bitmap = nullptr; m_sbounds.set(0, -1, 0, -1); m_format = TEXFORMAT_ARGB32; + m_scaler = nullptr; m_curseq = 0; } @@ -430,6 +448,7 @@ void render_texture::get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo texinfo.base = m_bitmap->raw_pixptr(m_sbounds.top(), m_sbounds.left()); texinfo.rowpixels = m_bitmap->rowpixels(); texinfo.width = swidth; + texinfo.width_margin = m_sbounds.left(); texinfo.height = sheight; // palette will be set later texinfo.seqid = ++m_curseq; @@ -690,7 +709,7 @@ const rgb_t *render_container::bcg_lookup_table(int texformat, u32 &out_length, m_bcglookup.resize(palette->max_index()); recompute_lookups(); } - assert (palette == &m_palclient->palette()); + assert(palette == &m_palclient->palette()); out_length = palette->max_index(); return &m_bcglookup[0]; @@ -880,19 +899,21 @@ render_container::user_settings::user_settings() // render_target - constructor //------------------------------------------------- -render_target::render_target(render_manager &manager, const internal_layout *layoutfile, u32 flags) - : render_target(manager, layoutfile, flags, CONSTRUCTOR_IMPL) +render_target::render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags) + : render_target(manager, ui, layoutfile, flags, CONSTRUCTOR_IMPL) { } -render_target::render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags) - : render_target(manager, layout, flags, CONSTRUCTOR_IMPL) +render_target::render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags) + : render_target(manager, ui, layout, flags, CONSTRUCTOR_IMPL) { } -template render_target::render_target(render_manager &manager, T &&layout, u32 flags, constructor_impl_t) +template +render_target::render_target(render_manager &manager, render_container *ui, T &&layout, u32 flags, constructor_impl_t) : m_next(nullptr) , m_manager(manager) + , m_ui_container(ui) , m_curview(0U) , m_flags(flags) , m_listindex(0) @@ -1012,9 +1033,9 @@ void render_target::set_bounds(s32 width, s32 height, float pixel_aspect) m_width = width; m_height = height; m_bounds.x0 = m_bounds.y0 = 0; - m_bounds.x1 = (float)width; - m_bounds.y1 = (float)height; - m_pixel_aspect = pixel_aspect != 0.0? pixel_aspect : 1.0; + m_bounds.x1 = float(width); + m_bounds.y1 = float(height); + m_pixel_aspect = pixel_aspect != 0.0F ? pixel_aspect : 1.0F; } @@ -1030,6 +1051,8 @@ void render_target::set_view(unsigned viewindex) m_curview = viewindex; current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); current_view().preload(); + m_clickable_items.clear(); + m_clickable_items.resize(current_view().interactive_items().size()); } } @@ -1058,7 +1081,7 @@ void render_target::set_visibility_toggle(unsigned index, bool enable) m_views[m_curview].second |= u32(1) << index; else m_views[m_curview].second &= ~(u32(1) << index); - current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); + update_layer_config(); current_view().preload(); } @@ -1070,28 +1093,29 @@ void render_target::set_visibility_toggle(unsigned index, bool enable) unsigned render_target::configured_view(const char *viewname, int targetindex, int numtargets) { - layout_view *view = nullptr; - // if it isn't "auto" or an empty string, try to match it as a view name prefix if (viewname && *viewname && strcmp(viewname, "auto")) { // scan for a matching view name size_t const viewlen = strlen(viewname); - for (unsigned i = 0; !view && (m_views.size() > i); ++i) + for (unsigned i = 0; m_views.size() > i; ++i) + { if (!core_strnicmp(m_views[i].first.name().c_str(), viewname, viewlen)) - view = &m_views[i].first; + return i; + } } // if we don't have a match, default to the nth view std::vector > screens; for (screen_device &screen : screen_device_enumerator(m_manager.machine().root_device())) screens.push_back(screen); - if (!view && !screens.empty()) + if (!screens.empty()) { // if we have enough targets to be one per screen, assign in order if (numtargets >= screens.size()) { // find the first view with this screen and this screen only + layout_view *view = nullptr; screen_device const &screen = screens[index() % screens.size()]; for (unsigned i = 0; !view && (m_views.size() > i); ++i) { @@ -1109,22 +1133,21 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i } } } + if (view) + return view_index(*view); } // otherwise, find the first view that has all the screens - if (!view) + for (unsigned i = 0; m_views.size() > i; ++i) { - for (unsigned i = 0; !view && (m_views.size() > i); ++i) - { - layout_view &curview = m_views[i].first; - if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end()) - view = &curview; - } + layout_view &curview = m_views[i].first; + if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end()) + return i; } } - // make sure it's a valid view - return view ? view_index(*view) : 0; + // default to the first view + return 0; } @@ -1197,63 +1220,103 @@ void render_target::compute_visible_area(s32 target_width, s32 target_height, fl // apply orientation if required if (target_orientation & ORIENTATION_SWAP_XY) - src_aspect = 1.0 / src_aspect; + src_aspect = 1.0f / src_aspect; + + // we need the ratio of target to source aspect + float aspect_ratio = m_keepaspect ? (float)target_width / (float)target_height * target_pixel_aspect / src_aspect : 1.0f; - // get target aspect - float target_aspect = (float)target_width / (float)target_height * target_pixel_aspect; + // first compute (a, b) scale factors to fit the screen + float a = (float)target_width / src_width; + float b = (float)target_height / src_height; // apply automatic axial stretching if required int scale_mode = m_scale_mode; - if (m_scale_mode == SCALE_FRACTIONAL_AUTO) - { - bool is_rotated = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY); - scale_mode = is_rotated ? SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X; - } + if (scale_mode == SCALE_FRACTIONAL_AUTO) + scale_mode = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY) ? + SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X; - // first compute scale factors to fit the screen - float xscale = (float)target_width / src_width; - float yscale = (float)target_height / src_height; + // determine the scaling method for each axis + bool a_is_fract = (scale_mode == SCALE_FRACTIONAL_X || scale_mode == SCALE_FRACTIONAL); + bool b_is_fract = (scale_mode == SCALE_FRACTIONAL_Y || scale_mode == SCALE_FRACTIONAL); - // apply aspect correction - if (m_keepaspect) - { - if (target_aspect > src_aspect) - xscale *= src_aspect / target_aspect; - else - yscale *= target_aspect / src_aspect; - } + // check if we have user defined scale factors, if so use them instead, but only on integer axes + int a_user = a_is_fract ? 0 : m_int_scale_x; + int b_user = b_is_fract ? 0 : m_int_scale_y; - bool x_fits = render_round_nearest(xscale) * src_width <= target_width; - bool y_fits = render_round_nearest(yscale) * src_height <= target_height; + // we allow overscan either explicitely or if integer scale factors are forced by user + bool int_overscan = m_int_overscan || (m_keepaspect && (a_user != 0 || b_user != 0)); + float a_max = std::max(a, (float)a_user); + float b_max = std::max(b, (float)b_user); - // compute integer scale factors - float integer_x = std::max(1.0f, float(m_int_overscan || x_fits ? render_round_nearest(xscale) : floor(xscale))); - float integer_y = std::max(1.0f, float(m_int_overscan || y_fits ? render_round_nearest(yscale) : floor(yscale))); - // check if we have user defined scale factors, if so use them instead - integer_x = m_int_scale_x > 0 ? m_int_scale_x : integer_x; - integer_y = m_int_scale_y > 0 ? m_int_scale_y : integer_y; + // get the usable bounding box considering the type of scaling for each axis + float usable_aspect = (a_is_fract ? a : std::max(1.0f, floorf(a))) * src_width / + ((b_is_fract ? b : std::max(1.0f, floorf(b))) * src_height) * target_pixel_aspect; - // now apply desired scale mode - if (scale_mode == SCALE_FRACTIONAL_X) + // depending on the relative shape between target and source, let's define 'a' and 'b' so that: + // * a is the leader axis (first to hit a boundary) + // * b is the follower axis + if (usable_aspect > src_aspect) { - if (m_keepaspect) xscale *= integer_y / yscale; - yscale = integer_y; + std::swap(a, b); + std::swap(a_user, b_user); + std::swap(a_is_fract, b_is_fract); + std::swap(a_max, b_max); + aspect_ratio = 1.0f / aspect_ratio; } - else if (scale_mode == SCALE_FRACTIONAL_Y) - { - if (m_keepaspect) yscale *= integer_x / xscale; - xscale = integer_x; - } - else + + // now find an (a, b) pair that best fits our boundaries and scale options + float a_best = 1.0f, b_best = 1.0f; + float diff = 1000; + + // fill (a0, a1) range + float u = a_user == 0 ? a : (float)a_user; + float a_range[] = {a_is_fract ? u : std::max(1.0f, floorf(u)), a_is_fract ? u : std::max(1.0f, roundf(u))}; + + for (float aa : a_range) { - xscale = integer_x; - yscale = integer_y; + // apply aspect correction to 'b' axis if needed, considering resulting 'a' borders + float ba = b * (m_keepaspect ? aspect_ratio * (aa / a) : 1.0f); + + // fill (b0, b1) range + float v = b_user == 0 ? ba : (float)b_user; + float b_range[] = {b_is_fract ? v : std::max(1.0f, floorf(v)), b_is_fract ? v : std::max(1.0f, roundf(v))}; + + for (float bb : b_range) + { + // we may need to propagate proportions back to 'a' axis + float ab = aa; + if (m_keepaspect && a_user == 0) + { + if (a_is_fract) ab *= (bb / ba); + else if (b_user != 0) ab = std::max(1.0f, roundf(ab * (bb / ba))); + } + + // if overscan isn't allowed, discard values that exceed the usable bounding box, except a minimum of 1.0f + if (!int_overscan && ((ab > a_max && bb > 1.0f) || (bb > b_max && ab > 1.0f))) + continue; + + // score the result + float new_diff = fabsf(aspect_ratio * (a / b) - (ab / bb)); + + if (new_diff <= diff) + { + diff = new_diff; + a_best = ab; + b_best = bb; + } + } } + a = a_best; + b = b_best; + + // restore orientation + if (usable_aspect > src_aspect) + std::swap(a, b); // set the final width/height - visible_width = render_round_nearest(src_width * xscale); - visible_height = render_round_nearest(src_height * yscale); + visible_width = render_round_nearest(src_width * a); + visible_height = render_round_nearest(src_height * b); break; } } @@ -1411,8 +1474,8 @@ render_primitive_list &render_target::get_primitives() } } - // process the UI if we are the UI target - if (is_ui_target()) + // process UI elements if applicable + if (m_ui_container) { // compute the transform for the UI object_transform ui_xform; @@ -1425,7 +1488,7 @@ render_primitive_list &render_target::get_primitives() ui_xform.no_center = false; // add UI elements - add_container_primitives(list, root_xform, ui_xform, m_manager.ui_container(), BLENDMODE_ALPHA); + add_container_primitives(list, root_xform, ui_xform, *m_ui_container, BLENDMODE_ALPHA); } // optimize the list before handing it off @@ -1446,16 +1509,12 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta std::pair target_f(map_point_internal(target_x, target_y)); // explicitly check for the UI container - if (&container == &m_manager.ui_container()) + if (&container == m_ui_container) { // this hit test went against the UI container - if ((target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f)) - { - // this point was successfully mapped - container_x = float(target_x) / m_width; - container_y = float(target_y) / m_height; - return true; - } + container_x = float(target_x) / m_width; + container_y = float(target_y) / m_height; + return (target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f); } else { @@ -1474,15 +1533,12 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta [&container] (layout_view_item &item) { return &item.screen()->container() == &container; })); if (items.end() != found) { + // point successfully mapped layout_view_item &item(*found); render_bounds const bounds(item.bounds()); - if (bounds.includes(target_f.first, target_f.second)) - { - // point successfully mapped - container_x = (target_f.first - bounds.x0) / bounds.width(); - container_y = (target_f.second - bounds.y0) / bounds.height(); - return true; - } + container_x = (target_f.first - bounds.x0) / bounds.width(); + container_y = (target_f.second - bounds.y0) / bounds.height(); + return bounds.includes(target_f.first, target_f.second); } } @@ -1492,74 +1548,6 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta } -//------------------------------------------------- -// map_point_input - attempts to map a point on -// the specified render_target to an input port -// field, if possible -//------------------------------------------------- - -bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y) -{ - std::pair target_f(map_point_internal(target_x, target_y)); - if (m_orientation & ORIENTATION_FLIP_X) - target_f.first = 1.0f - target_f.first; - if (m_orientation & ORIENTATION_FLIP_Y) - target_f.second = 1.0f - target_f.second; - if (m_orientation & ORIENTATION_SWAP_XY) - std::swap(target_f.first, target_f.second); - - auto const &items(current_view().interactive_items()); - m_hit_test.resize(items.size() * 2); - std::fill(m_hit_test.begin(), m_hit_test.end(), false); - - for (auto const &edge : current_view().interactive_edges_x()) - { - if ((edge.position() > target_f.first) || ((edge.position() == target_f.first) && edge.trailing())) - break; - else - m_hit_test[edge.index()] = !edge.trailing(); - } - - for (auto const &edge : current_view().interactive_edges_y()) - { - if ((edge.position() > target_f.second) || ((edge.position() == target_f.second) && edge.trailing())) - break; - else - m_hit_test[items.size() + edge.index()] = !edge.trailing(); - } - - for (unsigned i = 0; items.size() > i; ++i) - { - if (m_hit_test[i] && m_hit_test[items.size() + i]) - { - layout_view_item &item(items[i]); - render_bounds const bounds(item.bounds()); - if (bounds.includes(target_f.first, target_f.second)) - { - if (item.has_input()) - { - // point successfully mapped - std::tie(input_port, input_mask) = item.input_tag_and_mask(); - input_x = (target_f.first - bounds.x0) / bounds.width(); - input_y = (target_f.second - bounds.y0) / bounds.height(); - return true; - } - else - { - break; - } - } - } - } - - // default to point not mapped - input_port = nullptr; - input_mask = 0; - input_x = input_y = -1.0f; - return false; -} - - //------------------------------------------------- // invalidate_all - if any of our primitive lists // contain a reference to the given pointer, @@ -1589,7 +1577,7 @@ void render_target::resolve_tags() for (layout_file &file : m_filelist) file.resolve_tags(); - current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); + update_layer_config(); current_view().preload(); } @@ -1602,6 +1590,8 @@ void render_target::resolve_tags() void render_target::update_layer_config() { current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); + m_clickable_items.clear(); + m_clickable_items.resize(current_view().interactive_items().size()); } @@ -1664,14 +1654,6 @@ void render_target::load_additional_layout_files(const char *basename, bool have else m_external_artwork = true; - // if a default view has been specified, use that as a fallback - bool have_default = false; - if (system.default_layout) - have_default |= load_layout_file(nullptr, *system.default_layout); - m_manager.machine().config().apply_default_layouts( - [this, &have_default] (device_t &dev, internal_layout const &layout) - { have_default |= load_layout_file(nullptr, layout, &dev); }); - // try to load another file based on the parent driver name int cloneof = driver_list::clone(system); while (0 <= cloneof) @@ -1689,6 +1671,14 @@ void render_target::load_additional_layout_files(const char *basename, bool have cloneof = driver_list::clone(parent); } + // if a default view has been specified, use that as a fallback + bool have_default = false; + if (system.default_layout) + have_default |= load_layout_file(nullptr, *system.default_layout); + m_manager.machine().config().apply_default_layouts( + [this, &have_default] (device_t &dev, internal_layout const &layout) + { have_default |= load_layout_file(nullptr, layout, &dev); }); + have_artwork |= m_external_artwork; // Use fallback artwork if defined and no artwork has been found yet @@ -2076,11 +2066,10 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout size_t decompressed = 0; do { - size_t actual; - std::error_condition const err = inflater->read( + auto const [err, actual] = read( + *inflater, &tempout[decompressed], - layout_data.decompressed_size - decompressed, - actual); + layout_data.decompressed_size - decompressed); decompressed += actual; if (err) { @@ -2173,7 +2162,7 @@ bool render_target::load_layout_file(device_t &device, util::xml::data_node cons { m_filelist.emplace_back(device, rootnode, searchpath, dirname); } - catch (emu_fatalerror &err) + catch (emu_fatalerror const &err) { osd_printf_warning("%s\n", err.what()); return false; @@ -2309,11 +2298,11 @@ void render_target::add_container_primitives(render_primitive_list &list, const // clip the primitive if (!m_transform_container && PRIMFLAG_GET_VECTOR(curitem.flags())) { - clipped = render_clip_line(&prim->bounds, &root_cliprect); + clipped = render_clip_line(prim->bounds, root_cliprect); } else { - clipped = render_clip_line(&prim->bounds, &cliprect); + clipped = render_clip_line(prim->bounds, cliprect); } break; @@ -2346,7 +2335,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const prim->texcoords = oriented_texcoords[finalorient]; // apply clipping - clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); + clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); // apply the final orientation from the quad flags and then build up the final flags prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) @@ -2406,7 +2395,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const prim->texcoords = oriented_texcoords[finalorient]; // apply clipping - clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); + clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); // apply the final orientation from the quad flags and then build up the final flags prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) @@ -2422,7 +2411,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); // apply clipping - clipped = render_clip_quad(&prim->bounds, &cliprect, nullptr); + clipped = render_clip_quad(prim->bounds, cliprect, nullptr); } } break; @@ -2547,7 +2536,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob } // add to the list or free if we're clipped out - bool const clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); + bool const clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); list.append_or_return(*prim, clipped); } } @@ -2577,6 +2566,25 @@ std::pair render_target::map_point_internal(s32 target_x, s32 targ } +//------------------------------------------------- +// map_point_layout - map point from screen +// coordinates to layout coordinates +//------------------------------------------------- + +std::pair render_target::map_point_layout(s32 target_x, s32 target_y) +{ + using std::swap; + std::pair result(map_point_internal(target_x, target_y)); + if (m_orientation & ORIENTATION_FLIP_X) + result.first = 1.0f - result.first; + if (m_orientation & ORIENTATION_FLIP_Y) + result.second = 1.0f - result.second; + if (m_orientation & ORIENTATION_SWAP_XY) + swap(result.first, result.second); + return result; +} + + //------------------------------------------------- // view_name - return the name of the indexed // view, or nullptr if it doesn't exist @@ -2619,20 +2627,22 @@ void render_target::config_load(util::xml::data_node const *targetnode) if (!targetnode) return; + // TODO: consider option priority - command line should take precedence over CFG + // not practical at the moment because view selection options are in the OSD layer + // find the view const char *viewname = targetnode->get_attribute_string("view", nullptr); - if (viewname != nullptr) - for (int viewnum = 0; viewnum < 1000; viewnum++) + if (viewname) + { + for (unsigned viewnum = 0; m_views.size() > viewnum; viewnum++) { - const char *testname = view_name(viewnum); - if (testname == nullptr) - break; - if (!strcmp(viewname, testname)) + if (!strcmp(viewname, view_name(viewnum))) { set_view(viewnum); break; } } + } // modify the artwork config int const zoom = targetnode->get_attribute_int("zoom", -1); @@ -2654,12 +2664,11 @@ void render_target::config_load(util::xml::data_node const *targetnode) set_orientation(orientation_add(rotate, orientation())); // apply the opposite orientation to the UI - if (is_ui_target()) + if (m_ui_container) { - render_container &ui_container = m_manager.ui_container(); - render_container::user_settings settings = ui_container.get_user_settings(); + render_container::user_settings settings = m_ui_container->get_user_settings(); settings.m_orientation = orientation_add(orientation_reverse(rotate), settings.m_orientation); - ui_container.set_user_settings(settings); + m_ui_container->set_user_settings(settings); } } @@ -2699,6 +2708,8 @@ void render_target::config_load(util::xml::data_node const *targetnode) { current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); current_view().preload(); + m_clickable_items.clear(); + m_clickable_items.resize(current_view().interactive_items().size()); } } } @@ -3060,7 +3071,6 @@ render_manager::render_manager(running_machine &machine) , m_ui_target(nullptr) , m_live_textures(0) , m_texture_id(0) - , m_ui_container(std::make_unique(*this)) { // register callbacks machine.configuration().config_register( @@ -3081,7 +3091,7 @@ render_manager::render_manager(running_machine &machine) render_manager::~render_manager() { // free all the containers since they may own textures - m_ui_container.reset(); + m_ui_containers.clear(); m_screen_container_list.clear(); // better not be any outstanding textures when we die @@ -3137,12 +3147,14 @@ float render_manager::max_update_rate() const render_target *render_manager::target_alloc(const internal_layout *layoutfile, u32 flags) { - return &m_targetlist.append(*new render_target(*this, layoutfile, flags)); + render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this); + return &m_targetlist.append(*new render_target(*this, ui, layoutfile, flags)); } render_target *render_manager::target_alloc(util::xml::data_node const &layout, u32 flags) { - return &m_targetlist.append(*new render_target(*this, layout, flags)); + render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this); + return &m_targetlist.append(*new render_target(*this, ui, layout, flags)); } @@ -3179,35 +3191,56 @@ render_target *render_manager::target_by_index(int index) const float render_manager::ui_aspect(render_container *rc) { - int orient; + // work out if this is a UI container + render_target *target = nullptr; + if (!rc) + { + target = &ui_target(); + rc = target->ui_container(); + assert(rc); + } + else + { + for (render_target &t : m_targetlist) + { + if (t.ui_container() == rc) + { + target = &t; + break; + } + } + } + float aspect; - if (rc == m_ui_container.get() || rc == nullptr) { - // ui container, aggregated multi-screen target + if (target) + { + // UI container, aggregated multi-screen target - orient = orientation_add(m_ui_target->orientation(), m_ui_container->orientation()); // based on the orientation of the target, compute height/width or width/height + int const orient = orientation_add(target->orientation(), rc->orientation()); if (!(orient & ORIENTATION_SWAP_XY)) - aspect = (float)m_ui_target->height() / (float)m_ui_target->width(); + aspect = float(target->height()) / float(target->width()); else - aspect = (float)m_ui_target->width() / (float)m_ui_target->height(); + aspect = float(target->width()) / float(target->height()); // if we have a valid pixel aspect, apply that and return - if (m_ui_target->pixel_aspect() != 0.0f) + if (target->pixel_aspect() != 0.0f) { - float pixel_aspect = m_ui_target->pixel_aspect(); + float pixel_aspect = target->pixel_aspect(); if (orient & ORIENTATION_SWAP_XY) pixel_aspect = 1.0f / pixel_aspect; return aspect /= pixel_aspect; } - - } else { + } + else + { // single screen container - orient = rc->orientation(); // based on the orientation of the target, compute height/width or width/height + int const orient = rc->orientation(); if (!(orient & ORIENTATION_SWAP_XY)) aspect = (float)rc->screen()->visible_area().height() / (float)rc->screen()->visible_area().width(); else @@ -3215,12 +3248,7 @@ float render_manager::ui_aspect(render_container *rc) } // clamp for extreme proportions - if (aspect < 0.66f) - aspect = 0.66f; - if (aspect > 1.5f) - aspect = 1.5f; - - return aspect; + return std::clamp(aspect, 0.66f, 1.5f); } diff --git a/src/emu/render.h b/src/emu/render.h index d7158340..7834cbae 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -47,18 +47,12 @@ #define MAME_EMU_RENDER_H #include "rendertypes.h" -#include "screen.h" -#include + #include -#include -#include +#include #include #include -#include -#include -#include -#include #include #include @@ -164,6 +158,7 @@ struct render_texinfo void * base; // base of the data u32 rowpixels; // pixels per row u32 width; // width of the image + u32 width_margin; // left margin of the scaled bounds, if applicable u32 height; // height of the image u32 seqid; // sequence ID u64 unique_id; // unique identifier to pass to osd @@ -346,7 +341,7 @@ class render_texture void get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo, render_primitive_list &primlist, u32 flags = 0); const rgb_t *get_adjusted_palette(render_container &container, u32 &out_length); - static constexpr int MAX_TEXTURE_SCALES = 20; + static constexpr int MAX_TEXTURE_SCALES = 100; // a scaled_texture contains a single scaled entry for a texture struct scaled_texture @@ -498,14 +493,15 @@ class render_target friend class render_manager; // construction/destruction - render_target(render_manager &manager, const internal_layout *layoutfile = nullptr, u32 flags = 0); - render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags = 0); + render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags); + render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags); ~render_target(); public: // getters render_target *next() const { return m_next; } render_manager &manager() const { return m_manager; } + render_container *ui_container() const { return m_ui_container; } u32 width() const { return m_width; } u32 height() const { return m_height; } float pixel_aspect() const { return m_pixel_aspect; } @@ -556,7 +552,6 @@ class render_target // hit testing bool map_point_container(s32 target_x, s32 target_y, render_container &container, float &container_x, float &container_y); - bool map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y); // reference tracking void invalidate_all(void *refptr); @@ -565,15 +560,24 @@ class render_target void resolve_tags(); private: + // constants + static inline constexpr int NUM_PRIMLISTS = 3; + static inline constexpr int MAX_CLEAR_EXTENTS = 1000; + using view_mask_pair = std::pair; using view_mask_vector = std::vector; // private classes declared in render.cpp struct object_transform; + struct pointer_info; + struct hit_test; + + using pointer_info_vector = std::vector; + using hit_test_vector = std::vector; // internal helpers enum constructor_impl_t { CONSTRUCTOR_IMPL }; - template render_target(render_manager &manager, T&& layout, u32 flags, constructor_impl_t); + template render_target(render_manager &manager, render_container *ui, T&& layout, u32 flags, constructor_impl_t); void update_layer_config(); void load_layout_files(const internal_layout *layoutfile, bool singlefile); void load_layout_files(util::xml::data_node const &rootnode, bool singlefile); @@ -584,6 +588,7 @@ class render_target void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode); void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item); std::pair map_point_internal(s32 target_x, s32 target_y); + std::pair map_point_layout(s32 target_x, s32 target_y); // config callbacks void config_load(util::xml::data_node const *targetnode); @@ -599,13 +604,10 @@ class render_target void add_clear_extents(render_primitive_list &list); void add_clear_and_optimize_primitive_list(render_primitive_list &list); - // constants - static constexpr int NUM_PRIMLISTS = 3; - static constexpr int MAX_CLEAR_EXTENTS = 1000; - // internal state render_target * m_next; // link to next target render_manager & m_manager; // reference to our owning manager + render_container *const m_ui_container; // container for drawing UI elements std::list m_filelist; // list of layout files view_mask_vector m_views; // views we consider unsigned m_curview; // current view index @@ -624,7 +626,8 @@ class render_target float m_max_refresh; // maximum refresh rate, 0 or if none int m_orientation; // orientation render_layer_config m_layerconfig; // layer configuration - std::vector m_hit_test; // used when mapping points to inputs + pointer_info_vector m_pointers; // state of pointers over this target + hit_test_vector m_clickable_items; // for tracking clicked elements layout_view * m_base_view; // the view at the time of first frame int m_base_orientation; // the orientation at the time of first frame render_layer_config m_base_layerconfig; // the layer configuration at the time of first frame @@ -671,7 +674,7 @@ class render_manager float ui_aspect(render_container *rc = nullptr); // UI containers - render_container &ui_container() const { assert(m_ui_container != nullptr); return *m_ui_container; } + render_container &ui_container() const { assert(ui_target().ui_container()); return *ui_target().ui_container(); } // textures render_texture *texture_alloc(texture_scaler_func scaler = nullptr, void *param = nullptr); @@ -692,20 +695,20 @@ class render_manager void config_save(config_type cfg_type, util::xml::data_node *parentnode); // internal state - running_machine & m_machine; // reference back to the machine + running_machine & m_machine; // reference back to the machine // array of live targets - simple_list m_targetlist; // list of targets - render_target * m_ui_target; // current UI target + simple_list m_targetlist; // list of targets + render_target * m_ui_target; // current UI target // texture lists - u32 m_live_textures; // number of live textures - u64 m_texture_id; // rolling texture ID counter - fixed_allocator m_texture_allocator;// texture allocator + u32 m_live_textures; // number of live textures + u64 m_texture_id; // rolling texture ID counter + fixed_allocator m_texture_allocator; // texture allocator - // containers for the UI and for screens - std::unique_ptr m_ui_container; // UI container - std::list m_screen_container_list; // list of containers for the screen + // containers for UI elements and for screens + std::list m_ui_containers; // containers for drawing UI elements + std::list m_screen_container_list; // list of containers for the screen }; #endif // MAME_EMU_RENDER_H diff --git a/src/emu/rendertypes.h b/src/emu/rendertypes.h index 43f2ebb8..b3eed6ad 100644 --- a/src/emu/rendertypes.h +++ b/src/emu/rendertypes.h @@ -20,6 +20,16 @@ //************************************************************************** +// texture formats +enum texture_format +{ + TEXFORMAT_UNDEFINED = 0, // require a format to be specified + TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha + TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB + TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB + TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence +}; + // blending modes enum { diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h index 4d2b8956..71e5bdc9 100644 --- a/src/emu/rendutil.h +++ b/src/emu/rendutil.h @@ -15,8 +15,11 @@ #include "rendertypes.h" +#include "utilfwd.h" + #include #include +#include /* ----- image formats ----- */ @@ -39,14 +42,14 @@ enum ru_imgformat /* ----- render utilities ----- */ -void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false); -bool render_clip_line(render_bounds *bounds, const render_bounds *clip); -bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords); -void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1); -void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file); -void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file); -bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false); -ru_imgformat render_detect_image(util::random_read &file); +void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false) noexcept; +bool render_clip_line(render_bounds &bounds, const render_bounds &clip); +bool render_clip_quad(render_bounds &bounds, const render_bounds &clip, render_quad_texuv *texcoords); +std::pair render_line_to_quad(const render_bounds &bounds, float width, float length_extension); +void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) noexcept; +void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) noexcept; +bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false) noexcept; +ru_imgformat render_detect_image(util::random_read &file) noexcept; diff --git a/src/lib/util/ioprocs.h b/src/lib/util/ioprocs.h index efe0a231..9e2c29d2 100644 --- a/src/lib/util/ioprocs.h +++ b/src/lib/util/ioprocs.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include // FIXME: make a proper place for OSD forward declarations @@ -56,7 +58,7 @@ class read_stream /// \param [out] actual Number of bytes actually read. Will always /// be less than or equal to the requested length. /// \return An error condition if reading stopped due to an error. - virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -100,7 +102,7 @@ class write_stream /// \param [out] actual Number of bytes actually written. Will /// always be less than or equal to the requested length. /// \return An error condition if writing stopped due to an error. - virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -184,7 +186,7 @@ class random_read : public virtual read_stream, public virtual random_access /// be less than or equal to the requested length. /// \return An error condition if seeking failed or reading stopped /// due to an error. - virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -214,7 +216,7 @@ class random_write : public virtual write_stream, public virtual random_access /// always be less than or equal to the requested length. /// \return An error condition if seeking failed or writing stopped /// due to an error. - virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -229,6 +231,123 @@ class random_read_write : public read_write_stream, public virtual random_read, using ptr = std::unique_ptr; }; + +/// \brief Read from the current position in the stream +/// +/// Reads up to the specified number of bytes from the stream into the +/// supplied buffer, continuing if interrupted by asynchronous signals. +/// May read less than the requested number of bytes if the end of the +/// stream is reached or an error occurs. If the stream supports +/// seeking, reading starts at the current position in the stream, and +/// the current position is incremented by the number of bytes read. +/// The operation may not be atomic if it is interrupted before the +/// requested number of bytes is read. +/// \param [in] stream The stream to read from. +/// \param [out] buffer Destination buffer. Must be large enough to +/// hold the requested number of bytes. +/// \param [in] length Maximum number of bytes to read. +/// \return A pair containing an error condition if reading stopped due +/// to an error, and the actual number of bytes read. +std::pair read(read_stream &stream, void *buffer, std::size_t length) noexcept; + +/// \brief Allocate memory and read from the current position in the +/// stream +/// +/// Allocates the specified number of bytes and then reads up to that +/// number of bytes from the stream into the newly allocated buffer, +/// continuing if interrupted by asynchronous signals. May read less +/// than the requested number of bytes if the end of the stream is +/// reached or an error occurs. If the stream supports seeking, +/// reading starts at the current position in the stream, and the +/// current position is incremented by the number of bytes read. The +/// operation may not be atomic if it is interrupted before the +/// requested number of bytes is read. No data will be read if +/// allocation fails. +/// \param [in] stream The stream to read from. +/// hold the requested number of bytes. +/// \param [in] length Maximum number of bytes to read. +/// \return A tuple containing an error condition if allocation failed +/// or reading stopped due to an error, the allocated buffer, and the +/// actual number of bytes read. +std::tuple, std::size_t> read(read_stream &stream, std::size_t length) noexcept; + +/// \brief Read from the specified position +/// +/// Reads up to the specified number of bytes from the stream into the +/// supplied buffer, continuing if interrupted by asynchronous signals. +/// May read less than the requested number of bytes if the end of the +/// stream is reached or an error occurs. If seeking is supported, +/// reading starts at the specified position and the current position is +/// unaffected. The operation may not be atomic if it is interrupted +/// before the requested number of bytes is read. +/// \param [in] stream The stream to read from. +/// \param [in] offset The position to start reading from, specified as +/// a number of bytes from the beginning of the stream. +/// \param [out] buffer Destination buffer. Must be large enough to +/// hold the requested number of bytes. +/// \param [in] length Maximum number of bytes to read. +/// \return A pair containing an error condition if reading stopped due +/// to an error, and the actual number of bytes read. +std::pair read_at(random_read &stream, std::uint64_t offset, void *buffer, std::size_t length) noexcept; + +/// \brief Allocate memory and read from the specified position +/// +/// Allocates the specified number of bytes and then reads up to that +/// number of bytes from the stream into the newly allocated buffer, +/// continuing if interrupted by asynchronous signals. May read less +/// than the requested number of bytes if the end of the stream is +/// reached or an error occurs. If seeking is supported, reading +/// starts at the specified position and the current position is +/// unaffected. The operation may not be atomic if it is interrupted +/// before the requested number of bytes is read. No data will be read +/// if allocation fails. +/// \param [in] stream The stream to read from. +/// \param [in] offset The position to start reading from, specified as +/// a number of bytes from the beginning of the stream. +/// \param [out] buffer Destination buffer. Must be large enough to +/// hold the requested number of bytes. +/// \param [in] length Maximum number of bytes to read. +/// \return A tuple containing an error condition if allocation failed +/// or reading stopped due to an error, the allocated buffer, and the +/// actual number of bytes read. +std::tuple, std::size_t> read_at(random_read &stream, std::uint64_t offset, std::size_t length) noexcept; + +/// \brief Write at the current position in the stream +/// +/// Writes up to the specified number of bytes from the supplied +/// buffer to the stream, continuing if interrupted by asynchronous +/// signals. May write less than the requested number of bytes if an +/// error occurs. If the stream supports seeking, writing starts at the +/// current position in the stream, and the current position is +/// incremented by the number of bytes written. The operation may not +/// be atomic if it is interrupted before the requested number of bytes +/// is written. +/// \param [in] stream The stream to write to. +/// \param [in] buffer Buffer containing the data to write. Must +/// contain at least the specified number of bytes. +/// \param [in] length Number of bytes to write. +/// \return A pair containing an error condition if writing stopped due +/// to an error, and the actual number of bytes written. +std::pair write(write_stream &stream, void const *buffer, std::size_t length) noexcept; + +/// \brief Write at specified position +/// +/// Writes up to the specified number of bytes from the supplied buffer, +/// continuing if interrupted by asynchronous signals. If seeking is +/// supported, writing starts at the specified position and the current +/// position is unaffected. May write less than the requested number +/// of bytes if an error occurs. The operation may not be atomic if it +/// is interrupted before the requested number of bytes is written. +/// \param [in] stream The stream to write to. +/// \param [in] offset The position to start writing at, specified as a +/// number of bytes from the beginning of the stream. +/// \param [in] buffer Buffer containing the data to write. Must +/// contain at least the specified number of bytes. +/// \param [in] length Number of bytes to write. +/// \return A pair containing an error condition if writing stopped due +/// to an error, and the actual number of bytes written. +std::pair write_at(random_write &stream, std::uint64_t offset, void const *buffer, std::size_t length) noexcept; + /// \} From cf04e0fd88eee6248d728ac1da70626c1e5e79ec Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:44:50 -0600 Subject: [PATCH 26/47] Update diimage. --- src/emu/diimage.cpp | 677 ++++++++++++++++++++++---------------------- src/emu/diimage.h | 224 ++++++--------- 2 files changed, 420 insertions(+), 481 deletions(-) diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 031ed46e..7ad94fb6 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -11,49 +11,20 @@ #include "emu.h" #include "emuopts.h" +#include "fileio.h" #include "romload.h" #include "softlist.h" #include "softlist_dev.h" -#include "ui/uimain.h" - #include "corestr.h" #include "opresolv.h" +#include "path.h" #include "zippath.h" #include -#include #include #include - - -//************************************************************************** -// DEVICE CONFIG IMAGE INTERFACE -//************************************************************************** -const image_device_type_info device_image_interface::m_device_info_array[] = - { - { IO_UNKNOWN, "unknown", "unkn" }, /* 0 */ - { IO_CARTSLOT, "cartridge", "cart" }, /* 1 */ - { IO_FLOPPY, "floppydisk", "flop" }, /* 2 */ - { IO_HARDDISK, "harddisk", "hard" }, /* 3 */ - { IO_CYLINDER, "cylinder", "cyln" }, /* 4 */ - { IO_CASSETTE, "cassette", "cass" }, /* 5 */ - { IO_PUNCHCARD, "punchcard", "pcrd" }, /* 6 */ - { IO_PUNCHTAPE, "punchtape", "ptap" }, /* 7 */ - { IO_PRINTER, "printout", "prin" }, /* 8 */ - { IO_SERIAL, "serial", "serl" }, /* 9 */ - { IO_PARALLEL, "parallel", "parl" }, /* 10 */ - { IO_SNAPSHOT, "snapshot", "dump" }, /* 11 */ - { IO_QUICKLOAD, "quickload", "quik" }, /* 12 */ - { IO_MEMCARD, "memcard", "memc" }, /* 13 */ - { IO_CDROM, "cdrom", "cdrm" }, /* 14 */ - { IO_MAGTAPE, "magtape", "magt" }, /* 15 */ - { IO_ROM, "romimage", "rom" }, /* 16 */ - { IO_MIDIIN, "midiin", "min" }, /* 17 */ - { IO_MIDIOUT, "midiout", "mout" }, /* 18 */ - { IO_PICTURE, "picture", "pic" }, /* 19 */ - { IO_VIDEO, "vidfile", "vid" } /* 20 */ - }; +#include //************************************************************************** @@ -94,15 +65,18 @@ image_device_format::~image_device_format() device_image_interface::device_image_interface(const machine_config &mconfig, device_t &device) : device_interface(device, "image") - , m_err() , m_file() , m_mame_file() + , m_default_region(-1) + , m_current_region(-1) , m_software_part_ptr(nullptr) + , m_sequence_counter(0) , m_readonly(false) , m_created(false) , m_create_format(0) , m_create_args(nullptr) , m_user_loadable(true) + , m_must_be_loaded(false) , m_is_loading(false) , m_is_reset_and_loading(false) { @@ -117,6 +91,17 @@ device_image_interface::~device_image_interface() { } +//------------------------------------------------- +// add_region - register a region that may +// have a chd image +//------------------------------------------------- +void device_image_interface::add_region(std::string name, bool is_default) +{ + if (is_default) + m_default_region = m_possible_preset_regions.size(); + m_possible_preset_regions.push_back(name); +} + //------------------------------------------------- // interface_config_complete - perform any @@ -130,57 +115,143 @@ void device_image_interface::interface_config_complete() update_names(); } - //------------------------------------------------- -// find_device_type - search through list of -// device types to extract data +// check_preset_images - lookup the CHDs from the +// region(s), if any //------------------------------------------------- -const image_device_type_info *device_image_interface::find_device_type(iodevice_t type) +void device_image_interface::check_preset_images() { - for (const image_device_type_info &info : m_device_info_array) + if (!m_possible_preset_regions.empty()) { - if (info.m_type == type) - return &info; + for(const auto &r : m_possible_preset_regions) + m_preset_images.push_back(device().machine().rom_load().get_disk_handle(":" + r)); + if (m_default_region != -1 && m_preset_images[m_default_region]) + m_current_region = m_default_region; + else + { + for (m_current_region = 0; m_current_region != int(m_preset_images.size()) && !m_preset_images[m_current_region]; m_current_region++); + if (m_current_region == int(m_preset_images.size())) + fatalerror("%s: No configured region has an image\n", device().tag()); + } + set_image_tag(); + set_user_loadable(false); + } + else + { + std::string tag = device().owner()->tag(); + auto *const chd = device().machine().rom_load().get_disk_handle(tag); + if (chd) + { + m_possible_preset_regions.emplace_back(std::move(tag)); + m_preset_images.push_back(chd); + m_current_region = 0; + set_image_tag(); + set_user_loadable(false); + } } - return nullptr; } //------------------------------------------------- -// device_typename - retrieves device type name +// has_preset_images - does the device have an +// image to retrieve through current_image_* //------------------------------------------------- -const char *device_image_interface::device_typename(iodevice_t type) +bool device_image_interface::has_preset_images() const { - const image_device_type_info *info = find_device_type(type); - return (info != nullptr) ? info->m_name : "unknown"; + return !m_possible_preset_regions.empty(); } //------------------------------------------------- -// device_brieftypename - retrieves device -// brief type name +// has_preset_images - does the device have +// multiple preset images with user selection //------------------------------------------------- -const char *device_image_interface::device_brieftypename(iodevice_t type) +bool device_image_interface::has_preset_images_selection() const { - const image_device_type_info *info = find_device_type(type); - return (info != nullptr) ? info->m_shortname : "unk"; + int icount = 0; + for (const auto *f : m_preset_images) + if (f) + icount ++; + return icount > 1; } + //------------------------------------------------- -// device_typeid - retrieves device type id +// preset_images_list -- generate the list of +// available image names //------------------------------------------------- -iodevice_t device_image_interface::device_typeid(const char *name) +std::vector device_image_interface::preset_images_list() const { - for (const image_device_type_info &info : m_device_info_array) + std::vector result; + for (unsigned int i = 0; i != m_preset_images.size(); i++) + if (m_preset_images[i]) + result.push_back(m_possible_preset_regions[i]); + return result; +} + +//------------------------------------------------- +// current_preset_image_id -- current image id, +// recomputed to ignore non-present images. +// returns -1 if not in preset mode +//------------------------------------------------- + +int device_image_interface::current_preset_image_id() const +{ + if (m_current_region == -1) + return -1; + int id = 0; + for (int i = 0; i != m_current_region; i++) + if (m_preset_images[i]) + id++; + return id; +} + +//------------------------------------------------- +// current_preset_image_chd -- return the chd of +// the current active image, nullptr if non +//------------------------------------------------- + +chd_file *device_image_interface::current_preset_image_chd() const +{ + if (m_current_region == -1) + return nullptr; + return m_preset_images[m_current_region]; +} + +//------------------------------------------------- +// switch_preset_image -- change of preset image +//------------------------------------------------- + +void device_image_interface::switch_preset_image(int id) +{ + for (unsigned i = 0; i != m_preset_images.size(); i++) { - if (!core_stricmp(name, info.m_name) || !core_stricmp(name, info.m_shortname)) - return info.m_type; + if (m_preset_images[i]) + { + if (!id) + { + if (is_loaded() || loaded_through_softlist()) + { + call_unload(); + clear(); + m_media_change_notifier(media_change_event::UNLOADED); + } + m_current_region = i; + auto const err = call_load(); + if (!err.first) + m_media_change_notifier(media_change_event::LOADED); + break; + } + id--; + } } - return (iodevice_t)-1; + + return; } + //------------------------------------------------- // set_image_filename - specifies the filename of // an image @@ -194,9 +265,9 @@ void device_image_interface::set_image_filename(std::string_view filename) // find the last "path separator" auto iter = std::find_if( - m_image_name.rbegin(), - m_image_name.rend(), - [](char c) { return (c == '\\') || (c == '/') || (c == ':'); }); + m_image_name.rbegin(), + m_image_name.rend(), + [] (char c) { return (c == '\\') || (c == '/') || (c == ':'); }); if (iter != m_image_name.rend()) m_basename.assign(iter.base(), m_image_name.end()); @@ -209,6 +280,20 @@ void device_image_interface::set_image_filename(std::string_view filename) m_filetype = core_filename_extract_extension(m_basename, true); } +//------------------------------------------------- +// set_image_tag - specifies the filename of +// an image as the device tag +//------------------------------------------------- + +void device_image_interface::set_image_tag() +{ + m_image_name = device().owner()->tag(); + m_working_directory = ""; + m_basename = ""; + m_basename_noext = ""; + m_filetype = ""; +} + //------------------------------------------------- // is_filetype - check if the filetype matches @@ -216,14 +301,24 @@ void device_image_interface::set_image_filename(std::string_view filename) bool device_image_interface::is_filetype(std::string_view candidate_filetype) const { - return std::equal(m_filetype.begin(), m_filetype.end(), candidate_filetype.begin(), candidate_filetype.end(), - [] (unsigned char c1, unsigned char c2) { return std::tolower(c1) == c2; }); + return util::streqlower(m_filetype, candidate_filetype); } -/**************************************************************************** - CREATION FORMATS -****************************************************************************/ +//------------------------------------------------- +// add_media_change_notifier - subscribe for +// media change notifications +//------------------------------------------------- + +util::notifier_subscription device_image_interface::add_media_change_notifier(delegate &&n) +{ + return m_media_change_notifier.subscribe(std::move(n)); +} + + +//*************************************************************************** +// CREATION FORMATS +//*************************************************************************** //------------------------------------------------- // device_get_named_creatable_format - @@ -231,10 +326,10 @@ bool device_image_interface::is_filetype(std::string_view candidate_filetype) co // image creation by name //------------------------------------------------- -const image_device_format *device_image_interface::device_get_named_creatable_format(const std::string &format_name) noexcept +const image_device_format *device_image_interface::device_get_named_creatable_format(std::string_view format_name) const noexcept { - for (auto &format : m_formatlist) - if (format->name() == format_name) + for (const auto &format : m_formatlist) + if (std::string_view(format->name()) == format_name) return format.get(); return nullptr; } @@ -261,22 +356,9 @@ void device_image_interface::add_format(std::string &&name, std::string &&descri } -/**************************************************************************** - ERROR HANDLING -****************************************************************************/ - -//------------------------------------------------- -// image_clear_error - clear out any specified -// error -//------------------------------------------------- - -void device_image_interface::clear_error() -{ - m_err.clear(); - m_err_message.clear(); -} - - +//*************************************************************************** +// ERROR HANDLING +//*************************************************************************** //------------------------------------------------- // error - returns the error text for an image @@ -298,7 +380,10 @@ std::error_category const &image_category() noexcept "Internal error"sv, "Unsupported operation"sv, "Invalid image"sv, + "Invalid image length"sv, "File already open"sv, + "Unrecognized software item"sv, + "Invalid software item"sv, "Unspecified error"sv }; if ((0 <= condition) && (std::size(s_messages) > condition)) return std::string(s_messages[condition]); @@ -310,50 +395,6 @@ std::error_category const &image_category() noexcept return s_image_category_instance; } -std::string_view device_image_interface::error() -{ - if (m_err && m_err_message.empty()) - m_err_message = m_err.message(); - return m_err_message; -} - - - -//------------------------------------------------- -// seterror - specifies an error on an image -//------------------------------------------------- - -void device_image_interface::seterror(std::error_condition err, const char *message) -{ - clear_error(); - m_err = err; - if (message) - m_err_message = message; -} - - - -//------------------------------------------------- -// message - used to display a message while -// loading -//------------------------------------------------- - -void device_image_interface::message(const char *format, ...) -{ - va_list args; - char buffer[256]; - - /* format the message */ - va_start(args, format); - vsnprintf(buffer, std::size(buffer), format, args); - va_end(args); - - /* display the popup for a standard amount of time */ - device().machine().ui().popup_time(5, "%s: %s", - basename(), - buffer); -} - //------------------------------------------------- // software_entry - return a pointer to the @@ -370,14 +411,13 @@ const software_info *device_image_interface::software_entry() const noexcept // get_software_region //------------------------------------------------- -u8 *device_image_interface::get_software_region(const char *tag) +u8 *device_image_interface::get_software_region(std::string_view tag) { if (!loaded_through_softlist()) return nullptr; - std::string full_tag = util::string_format("%s:%s", device().tag(), tag); - memory_region *region = device().machine().root_device().memregion(full_tag); - return region != nullptr ? region->base() : nullptr; + memory_region *const region = device().memregion(tag); + return region ? region->base() : nullptr; } @@ -385,11 +425,13 @@ u8 *device_image_interface::get_software_region(const char *tag) // image_get_software_region_length //------------------------------------------------- -u32 device_image_interface::get_software_region_length(const char *tag) +u32 device_image_interface::get_software_region_length(std::string_view tag) { - std::string full_tag = util::string_format("%s:%s", device().tag(), tag); - memory_region *region = device().machine().root_device().memregion(full_tag); - return region != nullptr ? region->bytes() : 0; + if (!loaded_through_softlist()) + return 0; + + memory_region *const region = device().memregion(tag); + return region ? region->bytes() : 0; } @@ -397,7 +439,7 @@ u32 device_image_interface::get_software_region_length(const char *tag) // image_get_feature //------------------------------------------------- -const char *device_image_interface::get_feature(const char *feature_name) const +const char *device_image_interface::get_feature(std::string_view feature_name) const { return !m_software_part_ptr ? nullptr : m_software_part_ptr->feature(feature_name); } @@ -407,7 +449,7 @@ const char *device_image_interface::get_feature(const char *feature_name) const // load_software_region - //------------------------------------------------- -bool device_image_interface::load_software_region(const char *tag, std::unique_ptr &ptr) +std::error_condition device_image_interface::load_software_region(std::string_view tag, std::unique_ptr &ptr) { size_t size = get_software_region_length(tag); @@ -415,9 +457,10 @@ bool device_image_interface::load_software_region(const char *tag, std::unique_p { ptr = std::make_unique(size); memcpy(ptr.get(), get_software_region(tag), size); + return std::error_condition(); } - - return size > 0; + else + return image_error::UNSUPPORTED; } @@ -428,75 +471,61 @@ bool device_image_interface::load_software_region(const char *tag, std::unique_p // to be loaded // **************************************************************************** -bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) +std::error_condition device_image_interface::run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) { // reset the hash; we want to override existing data hashes.reset(); // figure out the size, and "cap" the skip bytes u64 size; - if (file.length(size)) - return false; + std::error_condition filerr = file.length(size); + if (filerr) + return filerr; skip_bytes = u32(std::min(skip_bytes, size)); - // seek to the beginning - file.seek(skip_bytes, SEEK_SET); // TODO: check error return - u64 position = skip_bytes; - - // keep on reading hashes - hashes.begin(types); - while (position < size) - { - uint8_t buffer[8192]; - - // read bytes - const size_t count = size_t(std::min(size - position, sizeof(buffer))); - size_t actual_count; - const std::error_condition filerr = file.read(buffer, count, actual_count); - if (filerr || !actual_count) - return false; - position += actual_count; - - // and compute the hashes - hashes.buffer(buffer, actual_count); - } - hashes.end(); + // and compute the hashes + size_t actual_count; + filerr = hashes.compute(file, skip_bytes, size - skip_bytes, actual_count, types); + if (filerr) + return filerr; - // cleanup - file.seek(0, SEEK_SET); // TODO: check error return - return true; + return std::error_condition(); } -bool device_image_interface::image_checkhash() +std::error_condition device_image_interface::image_checkhash() { // only calculate CRC if it hasn't been calculated, and the open_mode is read only u32 crcval; if (!m_hash.crc(crcval) && is_readonly() && !m_created) { +#ifdef __LIBRETRO__ + // because 'image_is_chd_type()' below does not actually work + if (core_filename_ends_with(m_image_name.c_str(), "chd")) + return std::error_condition(); +#endif // do not cause a linear read of 600 megs please // TODO: use SHA1 in the CHD header as the hash - if (image_type() == IO_CDROM) - return true; + if (image_is_chd_type()) + return std::error_condition(); // Skip calculating the hash when we have an image mounted through a software list if (loaded_through_softlist()) - return true; + return std::error_condition(); // run the hash - if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL)) - return false; + return run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL); } - return true; + return std::error_condition(); } -util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const +util::hash_collection device_image_interface::calculate_hash_on_file(util::random_read &file) const { // calculate the hash util::hash_collection hash; - if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) + if (run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) hash.reset(); return hash; } @@ -514,33 +543,6 @@ u32 device_image_interface::crc() } -//------------------------------------------------- -// support_command_line_image_creation - do we -// want to support image creation from the front -// end command line? -//------------------------------------------------- - -bool device_image_interface::support_command_line_image_creation() const noexcept -{ - bool result; - switch (image_type()) - { - case IO_PRINTER: - case IO_SERIAL: - case IO_PARALLEL: - // going by the assumption that these device image types should support this - // behavior; ideally we'd get rid of IO_* and just push this to the specific - // devices - result = true; - break; - default: - result = false; - break; - } - return result; -} - - // **************************************************************************** // Battery functions // @@ -619,34 +621,6 @@ void device_image_interface::battery_save(const void *buffer, int length) } -//------------------------------------------------- -// uses_file_extension - update configuration -// based on completed device setup -//------------------------------------------------- - -bool device_image_interface::uses_file_extension(const char *file_extension) const -{ - bool result = false; - - if (file_extension[0] == '.') - file_extension++; - - /* find the extensions */ - std::string extensions(file_extensions()); - char *ext = strtok((char*)extensions.c_str(),","); - while (ext != nullptr) - { - if (!core_stricmp(ext, file_extension)) - { - result = true; - break; - } - ext = strtok (nullptr, ","); - } - return result; -} - - // *************************************************************************** // IMAGE LOADING // *************************************************************************** @@ -712,15 +686,20 @@ std::vector device_image_interface::determine_open_plan(bool is_create) { std::vector open_plan; - // emit flags into a vector - if (!is_create && is_readable() && is_writeable()) - open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE); - if (!is_create && !is_readable() && is_writeable()) - open_plan.push_back(OPEN_FLAG_WRITE); - if (!is_create && is_readable()) - open_plan.push_back(OPEN_FLAG_READ); - if (is_create && is_writeable() && is_creatable()) - open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + if (!is_create) + { + if (is_writeable()) + open_plan.push_back(is_readable() ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_WRITE); + if (is_readable()) + open_plan.push_back(OPEN_FLAG_READ); + } + else if (is_writeable() && is_creatable()) + { + if (is_readable()) + open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + else + open_plan.push_back(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + } return open_plan; } @@ -772,9 +751,9 @@ static int verify_length_and_hash(emu_file *file, std::string_view name, u32 exp // load_software - software image loading //------------------------------------------------- -bool device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) +std::error_condition device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) { - bool retval = false; + std::error_condition retval; int warningcount = 0; for (const rom_entry *region = start; region; region = rom_next_region(region)) { @@ -786,7 +765,7 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st { const software_info *const swinfo = swlist.find(std::string(swname)); if (!swinfo) - return false; + return image_error::NOSOFTWARE; if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED) osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()); @@ -816,14 +795,31 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st else filerr = m_mame_file->open(romp->name()); if (filerr) + { m_mame_file.reset(); + std::ostringstream msg; + util::stream_format(msg, + "%s: error opening image file %s: %s (%s:%d)", + device().tag(), romp->name(), + filerr.message(), + filerr.category().name(), + filerr.value()); + if (!searchpath.empty()) + { + msg << " (tried in"; + for (auto const &path : searchpath) + msg << ' ' << path; + msg << ')'; + } + osd_printf_error("%s\n", std::move(msg).str()); + } warningcount += verify_length_and_hash(m_mame_file.get(), romp->name(), romp->get_length(), util::hash_collection(romp->hashdata())); if (!filerr) filerr = util::core_file::open_proxy(*m_mame_file, m_file); - if (!filerr) - retval = true; + if (filerr) + retval = filerr; break; // load first item for start } @@ -841,16 +837,16 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st // load_internal - core image loading //------------------------------------------------- -image_init_result device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) +std::pair device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) { + std::pair err; + // first unload the image unload(); - // clear any possible error messages - clear_error(); - // we are now loading m_is_loading = true; + m_sequence_counter++; // record the filename set_image_filename(path); @@ -858,50 +854,47 @@ image_init_result device_image_interface::load_internal(std::string_view path, b if (core_opens_image_file()) { // determine open plan - std::vector open_plan = determine_open_plan(is_create); + std::vector const open_plan = determine_open_plan(is_create); // attempt to open the file in various ways for (auto iter = open_plan.cbegin(); !m_file && iter != open_plan.cend(); iter++) { // open the file - m_err = load_image_by_path(*iter, path); - if (m_err && (m_err != std::errc::no_such_file_or_directory) && (m_err != std::errc::permission_denied)) - goto done; + err.first = load_image_by_path(*iter, path); + if (err.first && (err.first != std::errc::no_such_file_or_directory) && (err.first != std::errc::permission_denied)) + break; } // did we fail to find the file? - if (!m_file) - { - m_err = std::errc::no_such_file_or_directory; - goto done; - } + if (!err.first && !m_file) + err.first = std::errc::no_such_file_or_directory; } - // call device load or create - m_create_format = create_format; - m_create_args = create_args; - - if (!init_phase()) + if (!err.first) { - m_err = (finish_load() == image_init_result::PASS) ? std::error_condition() : image_error::INTERNAL; - if (m_err) - goto done; + // call device load or create + m_create_format = create_format; + m_create_args = create_args; + + if (!init_phase()) + err = finish_load(); } - // success! -done: - if (m_err) + if (err.first) { - if (!init_phase()) - { - if (device().machine().phase() == machine_phase::RUNNING) - device().popmessage("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error()); - else - osd_printf_error("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path, error()); - } + osd_printf_error( + !err.second.empty() + ? (is_create ? "Unable to create image '%1$s': %2$s (%3$s:%4$d %5$s)\n" : "Unable to load image '%1$s': %2$s (%3$s:%4$d %5$s)\n") + : (is_create ? "Unable to create image '%1$s': %5$s (%3$s:%4$d)\n" : "Unable to load image '%1$s': %5$s (%3$s:%4$d)\n"), + path, + err.second, + err.first.category().name(), + err.first.value(), + err.first.message()); clear(); } - return m_err ? image_init_result::FAIL : image_init_result::PASS; + + return err; } @@ -909,13 +902,13 @@ image_init_result device_image_interface::load_internal(std::string_view path, b // load - load an image into MAME //------------------------------------------------- -image_init_result device_image_interface::load(std::string_view path) +std::pair device_image_interface::load(std::string_view path) { // is this a reset on load item? if (is_reset_on_load() && !init_phase()) { reset_and_load(path); - return image_init_result::PASS; + return std::make_pair(std::error_condition(), std::string()); } return load_internal(path, false, 0, nullptr); @@ -926,26 +919,26 @@ image_init_result device_image_interface::load(std::string_view path) // load_software - loads a softlist item by name //------------------------------------------------- -image_init_result device_image_interface::load_software(std::string_view software_identifier) +std::pair device_image_interface::load_software(std::string_view software_identifier) { // Is this a software part that forces a reset and we're at runtime? If so, get this loaded through reset_and_load if (is_reset_on_load() && !init_phase()) { reset_and_load(software_identifier); - return image_init_result::PASS; + return std::make_pair(std::error_condition(), std::string()); } // Prepare to load unload(); - clear_error(); m_is_loading = true; // Check if there's a software list defined for this device and use that if we're not creating an image - bool softload = load_software_part(software_identifier); - if (!softload) + std::pair err; + err.first = load_software_part(software_identifier); + if (err.first) { m_is_loading = false; - return image_init_result::FAIL; + return err; } // set up softlist stuff @@ -955,9 +948,10 @@ image_init_result device_image_interface::load_software(std::string_view softwar m_image_name = m_full_software_name; m_basename = m_full_software_name; m_basename_noext = m_full_software_name; - m_filetype = use_software_list_file_extension_for_filetype() && m_mame_file != nullptr - ? std::string(core_filename_extract_extension(m_mame_file->filename(), true)) - : ""; + if (use_software_list_file_extension_for_filetype() && m_mame_file) + m_filetype = core_filename_extract_extension(m_mame_file->filename(), true); + else + m_filetype.clear(); // Copy some image information when we have been loaded through a software list software_info &swinfo = m_software_part_ptr->info(); @@ -967,16 +961,31 @@ image_init_result device_image_interface::load_software(std::string_view softwar fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n"); // set file type - std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr) + std::string filename = (m_mame_file && m_mame_file->filename()) ? m_mame_file->filename() : ""; m_filetype = core_filename_extract_extension(filename, true); // call finish_load if necessary - if (init_phase() == false && (finish_load() != image_init_result::PASS)) - return image_init_result::FAIL; + if (!init_phase()) + { + err = finish_load(); + if (err.first) + { + osd_printf_error( + !err.second.empty() + ? "Unable to load software item '%1$s': %2$s (%3$s:%4$d %5$s)\n" + : "Unable to load software item '%1$s': %5$s (%3$s:%4$d)\n", + software_identifier, + err.second, + err.first.category().name(), + err.first.value(), + err.first.message()); + clear(); + } + } - return image_init_result::PASS; + return err; } @@ -985,53 +994,38 @@ image_init_result device_image_interface::load_software(std::string_view softwar // from core //------------------------------------------------- -image_init_result device_image_interface::finish_load() +std::pair device_image_interface::finish_load() { - image_init_result err = image_init_result::PASS; + std::pair err; if (m_is_loading) { - if (!image_checkhash()) - { - m_err = image_error::INVALIDIMAGE; - err = image_init_result::FAIL; - } + err.first = image_checkhash(); - if (err == image_init_result::PASS) + if (!err.first) { if (m_created) - { err = call_create(m_create_format, m_create_args); - if (err != image_init_result::PASS) - { - if (!m_err) - m_err = image_error::UNSPECIFIED; - } - } else - { - // using device load - err = call_load(); - if (err != image_init_result::PASS) - { - if (!m_err) - m_err = image_error::UNSPECIFIED; - } - } + err = call_load(); // using device load } } + m_is_loading = false; m_create_format = 0; m_create_args = nullptr; + if (!err.first) + m_media_change_notifier(media_change_event::LOADED); + return err; } //------------------------------------------------- -// create - create a image +// create - create an image //------------------------------------------------- -image_init_result device_image_interface::create(std::string_view path) +std::pair device_image_interface::create(std::string_view path) { return create(path, nullptr, nullptr); } @@ -1041,13 +1035,14 @@ image_init_result device_image_interface::create(std::string_view path) // create - create a image //------------------------------------------------- -image_init_result device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) +std::pair device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) { int format_index = 0; int cnt = 0; for (auto &format : m_formatlist) { - if (create_format == format.get()) { + if (create_format == format.get()) + { format_index = cnt; break; } @@ -1081,7 +1076,7 @@ void device_image_interface::reset_and_load(std::string_view path) // to an image //------------------------------------------------- -void device_image_interface::clear() +void device_image_interface::clear() noexcept { m_mame_file.reset(); m_file.reset(); @@ -1101,6 +1096,8 @@ void device_image_interface::clear() m_software_list_name.clear(); m_hash.reset(); + + m_sequence_counter++; } @@ -1113,9 +1110,13 @@ void device_image_interface::unload() if (is_loaded() || loaded_through_softlist()) { call_unload(); + clear(); + m_media_change_notifier(media_change_event::UNLOADED); + } + else + { + clear(); // just to make sure everything is reset } - clear(); - clear_error(); } @@ -1137,12 +1138,10 @@ const util::option_guide &device_image_interface::create_option_guide() const void device_image_interface::update_names() { - const char *inst_name = custom_instance_name(); - const char *brief_name = custom_brief_instance_name(); - if (inst_name == nullptr) - inst_name = device_typename(image_type()); - if (brief_name == nullptr) - brief_name = device_brieftypename(image_type()); + const char *inst_name = image_type_name(); + const char *brief_name = image_brief_type_name(); + assert(inst_name != nullptr); + assert(brief_name != nullptr); // count instances of the general image type, or device type if custom int count = 0; @@ -1151,19 +1150,21 @@ void device_image_interface::update_names() { if (this == &image) index = count; - const char *other_name = image.custom_instance_name(); - if (!other_name) - other_name = device_typename(image.image_type()); + const char *other_name = image.image_type_name(); + const char *other_brief_name = image.image_brief_type_name(); + assert(other_name != nullptr); + assert(other_brief_name != nullptr); - if (other_name == inst_name || !strcmp(other_name, inst_name)) + if (other_name == inst_name || !strcmp(other_name, inst_name) || + other_brief_name == brief_name || !strcmp(other_brief_name, brief_name)) count++; } - m_canonical_instance_name = string_format("%s%d", inst_name, index + 1); + m_canonical_instance_name = util::string_format("%s%d", inst_name, index + 1); if (count > 1) { m_instance_name = m_canonical_instance_name; - m_brief_instance_name = string_format("%s%d", brief_name, index + 1); + m_brief_instance_name = util::string_format("%s%d", brief_name, index + 1); } else { @@ -1256,7 +1257,7 @@ const software_list_loader &device_image_interface::get_software_list_loader() c // sw_info and sw_part are also set. //------------------------------------------------- -bool device_image_interface::load_software_part(std::string_view identifier) +std::error_condition device_image_interface::load_software_part(std::string_view identifier) { // if no match has been found, we suggest similar shortnames software_list_device *swlist; @@ -1264,14 +1265,14 @@ bool device_image_interface::load_software_part(std::string_view identifier) if (m_software_part_ptr == nullptr) { software_list_device::display_matches(device().machine().config(), image_interface(), identifier); - return false; + return image_error::NOSOFTWARE; } // Load the software part const std::string &swname = m_software_part_ptr->info().shortname(); const rom_entry *start_entry = m_software_part_ptr->romdata().data(); const software_list_loader &loader = get_software_list_loader(); - bool result = loader.load_software(*this, *swlist, swname, start_entry); + std::error_condition result = loader.load_software(*this, *swlist, swname, start_entry); // check compatibility switch (swlist->is_compatible(*m_software_part_ptr)) diff --git a/src/emu/diimage.h b/src/emu/diimage.h index 67d20c43..aa9c991c 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -17,11 +17,13 @@ #ifndef MAME_EMU_DIIMAGE_H #define MAME_EMU_DIIMAGE_H +#include "notifier.h" #include "utilfwd.h" #include #include #include +#include #include @@ -29,39 +31,15 @@ // TYPE DEFINITIONS //************************************************************************** -enum iodevice_t -{ - /* List of all supported devices. Refer to the device by these names only */ - IO_UNKNOWN, - IO_CARTSLOT, /* 1 - Cartridge Port, as found on most console and on some computers */ - IO_FLOPPY, /* 2 - Floppy Disk unit */ - IO_HARDDISK, /* 3 - Hard Disk unit */ - IO_CYLINDER, /* 4 - Magnetically-Coated Cylinder */ - IO_CASSETTE, /* 5 - Cassette Recorder (common on early home computers) */ - IO_PUNCHCARD, /* 6 - Card Puncher/Reader */ - IO_PUNCHTAPE, /* 7 - Tape Puncher/Reader (reels instead of punchcards) */ - IO_PRINTER, /* 8 - Printer device */ - IO_SERIAL, /* 9 - Generic Serial Port */ - IO_PARALLEL, /* 10 - Generic Parallel Port */ - IO_SNAPSHOT, /* 11 - Complete 'snapshot' of the state of the computer */ - IO_QUICKLOAD, /* 12 - Allow to load program/data into memory, without matching any actual device */ - IO_MEMCARD, /* 13 - Memory card */ - IO_CDROM, /* 14 - optical CD-ROM disc */ - IO_MAGTAPE, /* 15 - Magnetic tape */ - IO_ROM, /* 16 - Individual ROM image - the Amstrad CPC has a few applications that were sold on 16kB ROMs */ - IO_MIDIIN, /* 17 - MIDI In port */ - IO_MIDIOUT, /* 18 - MIDI Out port */ - IO_PICTURE, /* 19 - A single-frame image */ - IO_VIDEO, /* 20 - A video file */ - IO_COUNT /* 21 - Total Number of IO_devices for searching */ -}; - enum class image_error : int { INTERNAL = 1, UNSUPPORTED, INVALIDIMAGE, + INVALIDLENGTH, ALREADYOPEN, + NOSOFTWARE, + BADSOFTWARE, UNSPECIFIED }; @@ -69,13 +47,6 @@ const std::error_category &image_category() noexcept; inline std::error_condition make_error_condition(image_error e) noexcept { return std::error_condition(int(e), image_category()); } namespace std { template <> struct is_error_condition_enum : public std::true_type { }; } -struct image_device_type_info -{ - iodevice_t m_type; - const char *m_name; - const char *m_shortname; -}; - class image_device_format { public: @@ -95,66 +66,56 @@ class image_device_format }; -enum class image_init_result { PASS, FAIL }; -enum class image_verify_result { PASS, FAIL }; - -//************************************************************************** -// MACROS -//************************************************************************** - -#define DEVICE_IMAGE_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image) -#define DECLARE_DEVICE_IMAGE_LOAD_MEMBER(_name) DEVICE_IMAGE_LOAD_MEMBER(_name) - -#define DEVICE_IMAGE_UNLOAD_MEMBER(_name) void _name(device_image_interface &image) -#define DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(_name) DEVICE_IMAGE_UNLOAD_MEMBER(_name) - - // ======================> device_image_interface // class representing interface-specific live image class device_image_interface : public device_interface { public: - typedef device_delegate load_delegate; - typedef device_delegate unload_delegate; + enum class media_change_event + { + LOADED, + UNLOADED + }; - typedef std::vector> formatlist_type; + using formatlist_type = std::vector >; // construction/destruction device_image_interface(const machine_config &mconfig, device_t &device); virtual ~device_image_interface(); - static const char *device_typename(iodevice_t type); - static const char *device_brieftypename(iodevice_t type); - static iodevice_t device_typeid(const char *name); - - virtual image_init_result call_load() { return image_init_result::PASS; } - virtual image_init_result call_create(int format_type, util::option_resolution *format_options) { return image_init_result::PASS; } + virtual std::pair call_load() { return std::make_pair(std::error_condition(), std::string()); } + virtual std::pair call_create(int format_type, util::option_resolution *format_options) { return std::make_pair(std::error_condition(), std::string()); } virtual void call_unload() { } virtual std::string call_display() { return std::string(); } virtual u32 unhashed_header_length() const noexcept { return 0; } virtual bool core_opens_image_file() const noexcept { return true; } - virtual iodevice_t image_type() const noexcept = 0; + virtual bool image_is_chd_type() const noexcept { return false; } virtual bool is_readable() const noexcept = 0; virtual bool is_writeable() const noexcept = 0; virtual bool is_creatable() const noexcept = 0; - virtual bool must_be_loaded() const noexcept = 0; virtual bool is_reset_on_load() const noexcept = 0; - virtual bool support_command_line_image_creation() const noexcept; + virtual bool support_command_line_image_creation() const noexcept { return false; } virtual const char *image_interface() const noexcept { return nullptr; } virtual const char *file_extensions() const noexcept = 0; virtual const util::option_guide &create_option_guide() const; - virtual const char *custom_instance_name() const noexcept { return nullptr; } - virtual const char *custom_brief_instance_name() const noexcept { return nullptr; } + virtual const char *image_type_name() const noexcept = 0; + virtual const char *image_brief_type_name() const noexcept = 0; + + // Set block device image regions for arcade systems + void add_region(std::string name, bool is_default = false); + bool has_preset_images() const; + bool has_preset_images_selection() const; + std::vector preset_images_list() const; + int current_preset_image_id() const; + void switch_preset_image(int id); + chd_file *current_preset_image_chd() const; + void check_preset_images(); const image_device_format *device_get_indexed_creatable_format(int index) const noexcept { return (index < m_formatlist.size()) ? m_formatlist.at(index).get() : nullptr; } - const image_device_format *device_get_named_creatable_format(const std::string &format_name) noexcept; + const image_device_format *device_get_named_creatable_format(std::string_view format_name) const noexcept; const util::option_guide &device_get_creation_option_guide() const { return create_option_guide(); } - std::string_view error(); - void seterror(std::error_condition err, const char *message); - void message(const char *format, ...) ATTR_PRINTF(2,3); - bool exists() const noexcept { return !m_image_name.empty(); } // get image file path/name @@ -165,9 +126,15 @@ class device_image_interface : public device_interface bool is_filetype(std::string_view candidate_filetype) const; bool is_open() const noexcept { return bool(m_file); } - util::core_file &image_core_file() const noexcept { return *m_file; } + util::core_file &image_core_file() const noexcept { assert(is_open()); return *m_file; } bool is_readonly() const noexcept { return m_readonly; } + u32 sequence_counter() const { return m_sequence_counter; } // Increments on media load/unload/etc + util::notifier_subscription add_media_change_notifier(delegate &&n); + template + util::notifier_subscription add_media_change_notifier(T &&n) + { return add_media_change_notifier(delegate(std::forward(n))); } + // image file I/O wrappers // TODO: move away from using these and let implementations use the I/O interface directly // FIXME: don't swallow errors @@ -181,15 +148,13 @@ class device_image_interface : public device_interface u32 fread(void *buffer, u32 length) { check_for_file(); - size_t actual; - m_file->read(buffer, length, actual); + auto const [err, actual] = read(*m_file, buffer, length); return actual; } u32 fwrite(const void *buffer, u32 length) { check_for_file(); - size_t actual; - m_file->write(buffer, length, actual); + auto const [err, actual] = write(*m_file, buffer, length); return actual; } std::error_condition fseek(s64 offset, int whence) @@ -204,32 +169,6 @@ class device_image_interface : public device_interface m_file->tell(result); return result; } - int fgetc() - { - char ch; - if (fread(&ch, 1) != 1) - ch = '\0'; - return ch; - } - char *fgets(char *buffer, u32 length) - { - check_for_file(); - return m_file->gets(buffer, length); - } - bool image_feof() - { - check_for_file(); - return m_file->eof(); - } - const void *ptr() - { - check_for_file(); - return m_file->buffer(); - } - - // allocate and read into buffers - u32 fread(std::unique_ptr &ptr, u32 length) { ptr = std::make_unique(length); return fread(ptr.get(), length); } - u32 fread(std::unique_ptr &ptr, u32 length, offs_t offset) { ptr = std::make_unique(length); return fread(ptr.get() + offset, length - offset); } // access to software list item information const software_info *software_entry() const noexcept; @@ -243,67 +182,62 @@ class device_image_interface : public device_interface const std::string &working_directory() const { return m_working_directory; } // access to software list properties and ROM data areas - u8 *get_software_region(const char *tag); - u32 get_software_region_length(const char *tag); - const char *get_feature(const char *feature_name) const; - bool load_software_region(const char *tag, std::unique_ptr &ptr); + u8 *get_software_region(std::string_view tag); + u32 get_software_region_length(std::string_view tag); + const char *get_feature(std::string_view feature_name) const; + std::error_condition load_software_region(std::string_view tag, std::unique_ptr &ptr); u32 crc(); - util::hash_collection& hash() { return m_hash; } - util::hash_collection calculate_hash_on_file(util::core_file &file) const; + util::hash_collection &hash() { return m_hash; } + util::hash_collection calculate_hash_on_file(util::random_read &file) const; void battery_load(void *buffer, int length, int fill); void battery_load(void *buffer, int length, const void *def_buffer); void battery_save(const void *buffer, int length); - const char *image_type_name() const { return device_typename(image_type()); } - const std::string &instance_name() const { return m_instance_name; } const std::string &brief_instance_name() const { return m_brief_instance_name; } const std::string &canonical_instance_name() const { return m_canonical_instance_name; } - bool uses_file_extension(const char *file_extension) const; const formatlist_type &formatlist() const { return m_formatlist; } // loads an image file - image_init_result load(std::string_view path); + std::pair load(std::string_view path); // loads a softlist item by name - image_init_result load_software(std::string_view software_identifier); + std::pair load_software(std::string_view software_identifier); - image_init_result finish_load(); + std::pair finish_load(); void unload(); - image_init_result create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); - image_init_result create(std::string_view path); - bool load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); + std::pair create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); + std::pair create(std::string_view path); + std::error_condition load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); std::error_condition reopen_for_write(std::string_view path); - void set_user_loadable(bool user_loadable) { m_user_loadable = user_loadable; } + void set_user_loadable(bool user_loadable) noexcept { m_user_loadable = user_loadable; } + void set_must_be_loaded(bool must_be_loaded) noexcept { m_must_be_loaded = must_be_loaded; } bool user_loadable() const noexcept { return m_user_loadable; } + bool must_be_loaded() const noexcept { return m_must_be_loaded; } bool is_reset_and_loading() const noexcept { return m_is_reset_and_loading; } const std::string &full_software_name() const noexcept { return m_full_software_name; } protected: - // interface-level overrides + // device_interface implementation virtual void interface_config_complete() override; virtual const software_list_loader &get_software_list_loader() const; - virtual const bool use_software_list_file_extension_for_filetype() const { return false; } + virtual bool use_software_list_file_extension_for_filetype() const noexcept { return false; } - image_init_result load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); std::error_condition load_image_by_path(u32 open_flags, std::string_view path); - void clear(); - bool is_loaded() const { return m_file != nullptr; } + bool is_loaded() const noexcept { return m_file != nullptr; } - void set_image_filename(std::string_view filename); - - void clear_error(); + void set_image_tag(); void check_for_file() const { if (!m_file) throw emu_fatalerror("%s(%s): Illegal operation on unmounted image", device().shortname(), device().tag()); } void make_readonly() noexcept { m_readonly = true; } - bool image_checkhash(); + std::error_condition image_checkhash(); const software_part *find_software_item(std::string_view identifier, bool restrict_to_interface, software_list_device **device = nullptr) const; std::string software_get_default_slot(std::string_view default_card_slot) const; @@ -311,17 +245,21 @@ class device_image_interface : public device_interface void add_format(std::unique_ptr &&format); void add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec); - // derived class overrides +private: + std::vector determine_open_plan(bool is_create); + void update_names(); + void set_image_filename(std::string_view filename); + void clear() noexcept; + std::pair load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); + std::error_condition load_software_part(std::string_view identifier); - // configuration - static const image_device_type_info *find_device_type(iodevice_t type); - static const image_device_type_info m_device_info_array[]; + bool init_phase() const; + static std::error_condition run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); - // error related info - std::error_condition m_err; - std::string m_err_message; + // loads an image or software items and resets - called internally when we + // load an is_reset_on_load() item + void reset_and_load(std::string_view path); -private: // variables that are only non-zero when an image is mounted util::core_file::ptr m_file; std::unique_ptr m_mame_file; @@ -330,29 +268,27 @@ class device_image_interface : public device_interface std::string m_basename_noext; std::string m_filetype; + // preset images regions + std::vector m_possible_preset_regions; + std::vector m_preset_images; + int m_default_region, m_current_region; + // Software information std::string m_full_software_name; const software_part *m_software_part_ptr; std::string m_software_list_name; - std::vector determine_open_plan(bool is_create); - void update_names(); - bool load_software_part(std::string_view identifier); - - bool init_phase() const; - static bool run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); - - // loads an image or software items and resets - called internally when we - // load an is_reset_on_load() item - void reset_and_load(std::string_view path); - // creation info formatlist_type m_formatlist; // working directory; persists across mounts std::string m_working_directory; + // to notify interested parties when media changes + util::notifier m_media_change_notifier; + // flags + u32 m_sequence_counter; bool m_readonly; bool m_created; @@ -370,6 +306,8 @@ class device_image_interface : public device_interface // we want to disable command line cart loading... bool m_user_loadable; + bool m_must_be_loaded; + bool m_is_loading; bool m_is_reset_and_loading; @@ -378,4 +316,4 @@ class device_image_interface : public device_interface // iterator typedef device_interface_enumerator image_interface_enumerator; -#endif /* MAME_EMU_DIIMAGE_H */ +#endif // MAME_EMU_DIIMAGE_H From c10901b10c64e6048dadb63ea63a95d774f57d77 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:46:18 -0600 Subject: [PATCH 27/47] Revert update to diimage. --- src/emu/diimage.cpp | 677 ++++++++++++++++++++++---------------------- src/emu/diimage.h | 224 +++++++++------ 2 files changed, 481 insertions(+), 420 deletions(-) diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 7ad94fb6..031ed46e 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -11,20 +11,49 @@ #include "emu.h" #include "emuopts.h" -#include "fileio.h" #include "romload.h" #include "softlist.h" #include "softlist_dev.h" +#include "ui/uimain.h" + #include "corestr.h" #include "opresolv.h" -#include "path.h" #include "zippath.h" #include +#include #include #include -#include + + +//************************************************************************** +// DEVICE CONFIG IMAGE INTERFACE +//************************************************************************** +const image_device_type_info device_image_interface::m_device_info_array[] = + { + { IO_UNKNOWN, "unknown", "unkn" }, /* 0 */ + { IO_CARTSLOT, "cartridge", "cart" }, /* 1 */ + { IO_FLOPPY, "floppydisk", "flop" }, /* 2 */ + { IO_HARDDISK, "harddisk", "hard" }, /* 3 */ + { IO_CYLINDER, "cylinder", "cyln" }, /* 4 */ + { IO_CASSETTE, "cassette", "cass" }, /* 5 */ + { IO_PUNCHCARD, "punchcard", "pcrd" }, /* 6 */ + { IO_PUNCHTAPE, "punchtape", "ptap" }, /* 7 */ + { IO_PRINTER, "printout", "prin" }, /* 8 */ + { IO_SERIAL, "serial", "serl" }, /* 9 */ + { IO_PARALLEL, "parallel", "parl" }, /* 10 */ + { IO_SNAPSHOT, "snapshot", "dump" }, /* 11 */ + { IO_QUICKLOAD, "quickload", "quik" }, /* 12 */ + { IO_MEMCARD, "memcard", "memc" }, /* 13 */ + { IO_CDROM, "cdrom", "cdrm" }, /* 14 */ + { IO_MAGTAPE, "magtape", "magt" }, /* 15 */ + { IO_ROM, "romimage", "rom" }, /* 16 */ + { IO_MIDIIN, "midiin", "min" }, /* 17 */ + { IO_MIDIOUT, "midiout", "mout" }, /* 18 */ + { IO_PICTURE, "picture", "pic" }, /* 19 */ + { IO_VIDEO, "vidfile", "vid" } /* 20 */ + }; //************************************************************************** @@ -65,18 +94,15 @@ image_device_format::~image_device_format() device_image_interface::device_image_interface(const machine_config &mconfig, device_t &device) : device_interface(device, "image") + , m_err() , m_file() , m_mame_file() - , m_default_region(-1) - , m_current_region(-1) , m_software_part_ptr(nullptr) - , m_sequence_counter(0) , m_readonly(false) , m_created(false) , m_create_format(0) , m_create_args(nullptr) , m_user_loadable(true) - , m_must_be_loaded(false) , m_is_loading(false) , m_is_reset_and_loading(false) { @@ -91,17 +117,6 @@ device_image_interface::~device_image_interface() { } -//------------------------------------------------- -// add_region - register a region that may -// have a chd image -//------------------------------------------------- -void device_image_interface::add_region(std::string name, bool is_default) -{ - if (is_default) - m_default_region = m_possible_preset_regions.size(); - m_possible_preset_regions.push_back(name); -} - //------------------------------------------------- // interface_config_complete - perform any @@ -115,143 +130,57 @@ void device_image_interface::interface_config_complete() update_names(); } + //------------------------------------------------- -// check_preset_images - lookup the CHDs from the -// region(s), if any +// find_device_type - search through list of +// device types to extract data //------------------------------------------------- -void device_image_interface::check_preset_images() +const image_device_type_info *device_image_interface::find_device_type(iodevice_t type) { - if (!m_possible_preset_regions.empty()) + for (const image_device_type_info &info : m_device_info_array) { - for(const auto &r : m_possible_preset_regions) - m_preset_images.push_back(device().machine().rom_load().get_disk_handle(":" + r)); - if (m_default_region != -1 && m_preset_images[m_default_region]) - m_current_region = m_default_region; - else - { - for (m_current_region = 0; m_current_region != int(m_preset_images.size()) && !m_preset_images[m_current_region]; m_current_region++); - if (m_current_region == int(m_preset_images.size())) - fatalerror("%s: No configured region has an image\n", device().tag()); - } - set_image_tag(); - set_user_loadable(false); + if (info.m_type == type) + return &info; } - else - { - std::string tag = device().owner()->tag(); - auto *const chd = device().machine().rom_load().get_disk_handle(tag); - if (chd) - { - m_possible_preset_regions.emplace_back(std::move(tag)); - m_preset_images.push_back(chd); - m_current_region = 0; - set_image_tag(); - set_user_loadable(false); - } - } -} - -//------------------------------------------------- -// has_preset_images - does the device have an -// image to retrieve through current_image_* -//------------------------------------------------- - -bool device_image_interface::has_preset_images() const -{ - return !m_possible_preset_regions.empty(); -} - -//------------------------------------------------- -// has_preset_images - does the device have -// multiple preset images with user selection -//------------------------------------------------- - -bool device_image_interface::has_preset_images_selection() const -{ - int icount = 0; - for (const auto *f : m_preset_images) - if (f) - icount ++; - return icount > 1; -} - - -//------------------------------------------------- -// preset_images_list -- generate the list of -// available image names -//------------------------------------------------- - -std::vector device_image_interface::preset_images_list() const -{ - std::vector result; - for (unsigned int i = 0; i != m_preset_images.size(); i++) - if (m_preset_images[i]) - result.push_back(m_possible_preset_regions[i]); - return result; + return nullptr; } //------------------------------------------------- -// current_preset_image_id -- current image id, -// recomputed to ignore non-present images. -// returns -1 if not in preset mode +// device_typename - retrieves device type name //------------------------------------------------- -int device_image_interface::current_preset_image_id() const +const char *device_image_interface::device_typename(iodevice_t type) { - if (m_current_region == -1) - return -1; - int id = 0; - for (int i = 0; i != m_current_region; i++) - if (m_preset_images[i]) - id++; - return id; + const image_device_type_info *info = find_device_type(type); + return (info != nullptr) ? info->m_name : "unknown"; } //------------------------------------------------- -// current_preset_image_chd -- return the chd of -// the current active image, nullptr if non +// device_brieftypename - retrieves device +// brief type name //------------------------------------------------- -chd_file *device_image_interface::current_preset_image_chd() const +const char *device_image_interface::device_brieftypename(iodevice_t type) { - if (m_current_region == -1) - return nullptr; - return m_preset_images[m_current_region]; + const image_device_type_info *info = find_device_type(type); + return (info != nullptr) ? info->m_shortname : "unk"; } //------------------------------------------------- -// switch_preset_image -- change of preset image +// device_typeid - retrieves device type id //------------------------------------------------- -void device_image_interface::switch_preset_image(int id) +iodevice_t device_image_interface::device_typeid(const char *name) { - for (unsigned i = 0; i != m_preset_images.size(); i++) + for (const image_device_type_info &info : m_device_info_array) { - if (m_preset_images[i]) - { - if (!id) - { - if (is_loaded() || loaded_through_softlist()) - { - call_unload(); - clear(); - m_media_change_notifier(media_change_event::UNLOADED); - } - m_current_region = i; - auto const err = call_load(); - if (!err.first) - m_media_change_notifier(media_change_event::LOADED); - break; - } - id--; - } + if (!core_stricmp(name, info.m_name) || !core_stricmp(name, info.m_shortname)) + return info.m_type; } - - return; + return (iodevice_t)-1; } - //------------------------------------------------- // set_image_filename - specifies the filename of // an image @@ -265,9 +194,9 @@ void device_image_interface::set_image_filename(std::string_view filename) // find the last "path separator" auto iter = std::find_if( - m_image_name.rbegin(), - m_image_name.rend(), - [] (char c) { return (c == '\\') || (c == '/') || (c == ':'); }); + m_image_name.rbegin(), + m_image_name.rend(), + [](char c) { return (c == '\\') || (c == '/') || (c == ':'); }); if (iter != m_image_name.rend()) m_basename.assign(iter.base(), m_image_name.end()); @@ -280,20 +209,6 @@ void device_image_interface::set_image_filename(std::string_view filename) m_filetype = core_filename_extract_extension(m_basename, true); } -//------------------------------------------------- -// set_image_tag - specifies the filename of -// an image as the device tag -//------------------------------------------------- - -void device_image_interface::set_image_tag() -{ - m_image_name = device().owner()->tag(); - m_working_directory = ""; - m_basename = ""; - m_basename_noext = ""; - m_filetype = ""; -} - //------------------------------------------------- // is_filetype - check if the filetype matches @@ -301,24 +216,14 @@ void device_image_interface::set_image_tag() bool device_image_interface::is_filetype(std::string_view candidate_filetype) const { - return util::streqlower(m_filetype, candidate_filetype); + return std::equal(m_filetype.begin(), m_filetype.end(), candidate_filetype.begin(), candidate_filetype.end(), + [] (unsigned char c1, unsigned char c2) { return std::tolower(c1) == c2; }); } -//------------------------------------------------- -// add_media_change_notifier - subscribe for -// media change notifications -//------------------------------------------------- - -util::notifier_subscription device_image_interface::add_media_change_notifier(delegate &&n) -{ - return m_media_change_notifier.subscribe(std::move(n)); -} - - -//*************************************************************************** -// CREATION FORMATS -//*************************************************************************** +/**************************************************************************** + CREATION FORMATS +****************************************************************************/ //------------------------------------------------- // device_get_named_creatable_format - @@ -326,10 +231,10 @@ util::notifier_subscription device_image_interface::add_media_change_notifier(de // image creation by name //------------------------------------------------- -const image_device_format *device_image_interface::device_get_named_creatable_format(std::string_view format_name) const noexcept +const image_device_format *device_image_interface::device_get_named_creatable_format(const std::string &format_name) noexcept { - for (const auto &format : m_formatlist) - if (std::string_view(format->name()) == format_name) + for (auto &format : m_formatlist) + if (format->name() == format_name) return format.get(); return nullptr; } @@ -356,9 +261,22 @@ void device_image_interface::add_format(std::string &&name, std::string &&descri } -//*************************************************************************** -// ERROR HANDLING -//*************************************************************************** +/**************************************************************************** + ERROR HANDLING +****************************************************************************/ + +//------------------------------------------------- +// image_clear_error - clear out any specified +// error +//------------------------------------------------- + +void device_image_interface::clear_error() +{ + m_err.clear(); + m_err_message.clear(); +} + + //------------------------------------------------- // error - returns the error text for an image @@ -380,10 +298,7 @@ std::error_category const &image_category() noexcept "Internal error"sv, "Unsupported operation"sv, "Invalid image"sv, - "Invalid image length"sv, "File already open"sv, - "Unrecognized software item"sv, - "Invalid software item"sv, "Unspecified error"sv }; if ((0 <= condition) && (std::size(s_messages) > condition)) return std::string(s_messages[condition]); @@ -395,6 +310,50 @@ std::error_category const &image_category() noexcept return s_image_category_instance; } +std::string_view device_image_interface::error() +{ + if (m_err && m_err_message.empty()) + m_err_message = m_err.message(); + return m_err_message; +} + + + +//------------------------------------------------- +// seterror - specifies an error on an image +//------------------------------------------------- + +void device_image_interface::seterror(std::error_condition err, const char *message) +{ + clear_error(); + m_err = err; + if (message) + m_err_message = message; +} + + + +//------------------------------------------------- +// message - used to display a message while +// loading +//------------------------------------------------- + +void device_image_interface::message(const char *format, ...) +{ + va_list args; + char buffer[256]; + + /* format the message */ + va_start(args, format); + vsnprintf(buffer, std::size(buffer), format, args); + va_end(args); + + /* display the popup for a standard amount of time */ + device().machine().ui().popup_time(5, "%s: %s", + basename(), + buffer); +} + //------------------------------------------------- // software_entry - return a pointer to the @@ -411,13 +370,14 @@ const software_info *device_image_interface::software_entry() const noexcept // get_software_region //------------------------------------------------- -u8 *device_image_interface::get_software_region(std::string_view tag) +u8 *device_image_interface::get_software_region(const char *tag) { if (!loaded_through_softlist()) return nullptr; - memory_region *const region = device().memregion(tag); - return region ? region->base() : nullptr; + std::string full_tag = util::string_format("%s:%s", device().tag(), tag); + memory_region *region = device().machine().root_device().memregion(full_tag); + return region != nullptr ? region->base() : nullptr; } @@ -425,13 +385,11 @@ u8 *device_image_interface::get_software_region(std::string_view tag) // image_get_software_region_length //------------------------------------------------- -u32 device_image_interface::get_software_region_length(std::string_view tag) +u32 device_image_interface::get_software_region_length(const char *tag) { - if (!loaded_through_softlist()) - return 0; - - memory_region *const region = device().memregion(tag); - return region ? region->bytes() : 0; + std::string full_tag = util::string_format("%s:%s", device().tag(), tag); + memory_region *region = device().machine().root_device().memregion(full_tag); + return region != nullptr ? region->bytes() : 0; } @@ -439,7 +397,7 @@ u32 device_image_interface::get_software_region_length(std::string_view tag) // image_get_feature //------------------------------------------------- -const char *device_image_interface::get_feature(std::string_view feature_name) const +const char *device_image_interface::get_feature(const char *feature_name) const { return !m_software_part_ptr ? nullptr : m_software_part_ptr->feature(feature_name); } @@ -449,7 +407,7 @@ const char *device_image_interface::get_feature(std::string_view feature_name) c // load_software_region - //------------------------------------------------- -std::error_condition device_image_interface::load_software_region(std::string_view tag, std::unique_ptr &ptr) +bool device_image_interface::load_software_region(const char *tag, std::unique_ptr &ptr) { size_t size = get_software_region_length(tag); @@ -457,10 +415,9 @@ std::error_condition device_image_interface::load_software_region(std::string_vi { ptr = std::make_unique(size); memcpy(ptr.get(), get_software_region(tag), size); - return std::error_condition(); } - else - return image_error::UNSUPPORTED; + + return size > 0; } @@ -471,61 +428,75 @@ std::error_condition device_image_interface::load_software_region(std::string_vi // to be loaded // **************************************************************************** -std::error_condition device_image_interface::run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) +bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) { // reset the hash; we want to override existing data hashes.reset(); // figure out the size, and "cap" the skip bytes u64 size; - std::error_condition filerr = file.length(size); - if (filerr) - return filerr; + if (file.length(size)) + return false; skip_bytes = u32(std::min(skip_bytes, size)); - // and compute the hashes - size_t actual_count; - filerr = hashes.compute(file, skip_bytes, size - skip_bytes, actual_count, types); - if (filerr) - return filerr; + // seek to the beginning + file.seek(skip_bytes, SEEK_SET); // TODO: check error return + u64 position = skip_bytes; - return std::error_condition(); + // keep on reading hashes + hashes.begin(types); + while (position < size) + { + uint8_t buffer[8192]; + + // read bytes + const size_t count = size_t(std::min(size - position, sizeof(buffer))); + size_t actual_count; + const std::error_condition filerr = file.read(buffer, count, actual_count); + if (filerr || !actual_count) + return false; + position += actual_count; + + // and compute the hashes + hashes.buffer(buffer, actual_count); + } + hashes.end(); + + // cleanup + file.seek(0, SEEK_SET); // TODO: check error return + return true; } -std::error_condition device_image_interface::image_checkhash() +bool device_image_interface::image_checkhash() { // only calculate CRC if it hasn't been calculated, and the open_mode is read only u32 crcval; if (!m_hash.crc(crcval) && is_readonly() && !m_created) { -#ifdef __LIBRETRO__ - // because 'image_is_chd_type()' below does not actually work - if (core_filename_ends_with(m_image_name.c_str(), "chd")) - return std::error_condition(); -#endif // do not cause a linear read of 600 megs please // TODO: use SHA1 in the CHD header as the hash - if (image_is_chd_type()) - return std::error_condition(); + if (image_type() == IO_CDROM) + return true; // Skip calculating the hash when we have an image mounted through a software list if (loaded_through_softlist()) - return std::error_condition(); + return true; // run the hash - return run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL); + if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL)) + return false; } - return std::error_condition(); + return true; } -util::hash_collection device_image_interface::calculate_hash_on_file(util::random_read &file) const +util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const { // calculate the hash util::hash_collection hash; - if (run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) + if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) hash.reset(); return hash; } @@ -543,6 +514,33 @@ u32 device_image_interface::crc() } +//------------------------------------------------- +// support_command_line_image_creation - do we +// want to support image creation from the front +// end command line? +//------------------------------------------------- + +bool device_image_interface::support_command_line_image_creation() const noexcept +{ + bool result; + switch (image_type()) + { + case IO_PRINTER: + case IO_SERIAL: + case IO_PARALLEL: + // going by the assumption that these device image types should support this + // behavior; ideally we'd get rid of IO_* and just push this to the specific + // devices + result = true; + break; + default: + result = false; + break; + } + return result; +} + + // **************************************************************************** // Battery functions // @@ -621,6 +619,34 @@ void device_image_interface::battery_save(const void *buffer, int length) } +//------------------------------------------------- +// uses_file_extension - update configuration +// based on completed device setup +//------------------------------------------------- + +bool device_image_interface::uses_file_extension(const char *file_extension) const +{ + bool result = false; + + if (file_extension[0] == '.') + file_extension++; + + /* find the extensions */ + std::string extensions(file_extensions()); + char *ext = strtok((char*)extensions.c_str(),","); + while (ext != nullptr) + { + if (!core_stricmp(ext, file_extension)) + { + result = true; + break; + } + ext = strtok (nullptr, ","); + } + return result; +} + + // *************************************************************************** // IMAGE LOADING // *************************************************************************** @@ -686,20 +712,15 @@ std::vector device_image_interface::determine_open_plan(bool is_create) { std::vector open_plan; - if (!is_create) - { - if (is_writeable()) - open_plan.push_back(is_readable() ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_WRITE); - if (is_readable()) - open_plan.push_back(OPEN_FLAG_READ); - } - else if (is_writeable() && is_creatable()) - { - if (is_readable()) - open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - else - open_plan.push_back(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - } + // emit flags into a vector + if (!is_create && is_readable() && is_writeable()) + open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE); + if (!is_create && !is_readable() && is_writeable()) + open_plan.push_back(OPEN_FLAG_WRITE); + if (!is_create && is_readable()) + open_plan.push_back(OPEN_FLAG_READ); + if (is_create && is_writeable() && is_creatable()) + open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); return open_plan; } @@ -751,9 +772,9 @@ static int verify_length_and_hash(emu_file *file, std::string_view name, u32 exp // load_software - software image loading //------------------------------------------------- -std::error_condition device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) +bool device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) { - std::error_condition retval; + bool retval = false; int warningcount = 0; for (const rom_entry *region = start; region; region = rom_next_region(region)) { @@ -765,7 +786,7 @@ std::error_condition device_image_interface::load_software(software_list_device { const software_info *const swinfo = swlist.find(std::string(swname)); if (!swinfo) - return image_error::NOSOFTWARE; + return false; if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED) osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()); @@ -795,31 +816,14 @@ std::error_condition device_image_interface::load_software(software_list_device else filerr = m_mame_file->open(romp->name()); if (filerr) - { m_mame_file.reset(); - std::ostringstream msg; - util::stream_format(msg, - "%s: error opening image file %s: %s (%s:%d)", - device().tag(), romp->name(), - filerr.message(), - filerr.category().name(), - filerr.value()); - if (!searchpath.empty()) - { - msg << " (tried in"; - for (auto const &path : searchpath) - msg << ' ' << path; - msg << ')'; - } - osd_printf_error("%s\n", std::move(msg).str()); - } warningcount += verify_length_and_hash(m_mame_file.get(), romp->name(), romp->get_length(), util::hash_collection(romp->hashdata())); if (!filerr) filerr = util::core_file::open_proxy(*m_mame_file, m_file); - if (filerr) - retval = filerr; + if (!filerr) + retval = true; break; // load first item for start } @@ -837,16 +841,16 @@ std::error_condition device_image_interface::load_software(software_list_device // load_internal - core image loading //------------------------------------------------- -std::pair device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) +image_init_result device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) { - std::pair err; - // first unload the image unload(); + // clear any possible error messages + clear_error(); + // we are now loading m_is_loading = true; - m_sequence_counter++; // record the filename set_image_filename(path); @@ -854,47 +858,50 @@ std::pair device_image_interface::load_intern if (core_opens_image_file()) { // determine open plan - std::vector const open_plan = determine_open_plan(is_create); + std::vector open_plan = determine_open_plan(is_create); // attempt to open the file in various ways for (auto iter = open_plan.cbegin(); !m_file && iter != open_plan.cend(); iter++) { // open the file - err.first = load_image_by_path(*iter, path); - if (err.first && (err.first != std::errc::no_such_file_or_directory) && (err.first != std::errc::permission_denied)) - break; + m_err = load_image_by_path(*iter, path); + if (m_err && (m_err != std::errc::no_such_file_or_directory) && (m_err != std::errc::permission_denied)) + goto done; } // did we fail to find the file? - if (!err.first && !m_file) - err.first = std::errc::no_such_file_or_directory; + if (!m_file) + { + m_err = std::errc::no_such_file_or_directory; + goto done; + } } - if (!err.first) - { - // call device load or create - m_create_format = create_format; - m_create_args = create_args; + // call device load or create + m_create_format = create_format; + m_create_args = create_args; - if (!init_phase()) - err = finish_load(); + if (!init_phase()) + { + m_err = (finish_load() == image_init_result::PASS) ? std::error_condition() : image_error::INTERNAL; + if (m_err) + goto done; } + // success! - if (err.first) +done: + if (m_err) { - osd_printf_error( - !err.second.empty() - ? (is_create ? "Unable to create image '%1$s': %2$s (%3$s:%4$d %5$s)\n" : "Unable to load image '%1$s': %2$s (%3$s:%4$d %5$s)\n") - : (is_create ? "Unable to create image '%1$s': %5$s (%3$s:%4$d)\n" : "Unable to load image '%1$s': %5$s (%3$s:%4$d)\n"), - path, - err.second, - err.first.category().name(), - err.first.value(), - err.first.message()); + if (!init_phase()) + { + if (device().machine().phase() == machine_phase::RUNNING) + device().popmessage("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error()); + else + osd_printf_error("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path, error()); + } clear(); } - - return err; + return m_err ? image_init_result::FAIL : image_init_result::PASS; } @@ -902,13 +909,13 @@ std::pair device_image_interface::load_intern // load - load an image into MAME //------------------------------------------------- -std::pair device_image_interface::load(std::string_view path) +image_init_result device_image_interface::load(std::string_view path) { // is this a reset on load item? if (is_reset_on_load() && !init_phase()) { reset_and_load(path); - return std::make_pair(std::error_condition(), std::string()); + return image_init_result::PASS; } return load_internal(path, false, 0, nullptr); @@ -919,26 +926,26 @@ std::pair device_image_interface::load(std::s // load_software - loads a softlist item by name //------------------------------------------------- -std::pair device_image_interface::load_software(std::string_view software_identifier) +image_init_result device_image_interface::load_software(std::string_view software_identifier) { // Is this a software part that forces a reset and we're at runtime? If so, get this loaded through reset_and_load if (is_reset_on_load() && !init_phase()) { reset_and_load(software_identifier); - return std::make_pair(std::error_condition(), std::string()); + return image_init_result::PASS; } // Prepare to load unload(); + clear_error(); m_is_loading = true; // Check if there's a software list defined for this device and use that if we're not creating an image - std::pair err; - err.first = load_software_part(software_identifier); - if (err.first) + bool softload = load_software_part(software_identifier); + if (!softload) { m_is_loading = false; - return err; + return image_init_result::FAIL; } // set up softlist stuff @@ -948,10 +955,9 @@ std::pair device_image_interface::load_softwa m_image_name = m_full_software_name; m_basename = m_full_software_name; m_basename_noext = m_full_software_name; - if (use_software_list_file_extension_for_filetype() && m_mame_file) - m_filetype = core_filename_extract_extension(m_mame_file->filename(), true); - else - m_filetype.clear(); + m_filetype = use_software_list_file_extension_for_filetype() && m_mame_file != nullptr + ? std::string(core_filename_extract_extension(m_mame_file->filename(), true)) + : ""; // Copy some image information when we have been loaded through a software list software_info &swinfo = m_software_part_ptr->info(); @@ -961,31 +967,16 @@ std::pair device_image_interface::load_softwa fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n"); // set file type - std::string filename = (m_mame_file && m_mame_file->filename()) + std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr) ? m_mame_file->filename() : ""; m_filetype = core_filename_extract_extension(filename, true); // call finish_load if necessary - if (!init_phase()) - { - err = finish_load(); - if (err.first) - { - osd_printf_error( - !err.second.empty() - ? "Unable to load software item '%1$s': %2$s (%3$s:%4$d %5$s)\n" - : "Unable to load software item '%1$s': %5$s (%3$s:%4$d)\n", - software_identifier, - err.second, - err.first.category().name(), - err.first.value(), - err.first.message()); - clear(); - } - } + if (init_phase() == false && (finish_load() != image_init_result::PASS)) + return image_init_result::FAIL; - return err; + return image_init_result::PASS; } @@ -994,38 +985,53 @@ std::pair device_image_interface::load_softwa // from core //------------------------------------------------- -std::pair device_image_interface::finish_load() +image_init_result device_image_interface::finish_load() { - std::pair err; + image_init_result err = image_init_result::PASS; if (m_is_loading) { - err.first = image_checkhash(); + if (!image_checkhash()) + { + m_err = image_error::INVALIDIMAGE; + err = image_init_result::FAIL; + } - if (!err.first) + if (err == image_init_result::PASS) { if (m_created) + { err = call_create(m_create_format, m_create_args); + if (err != image_init_result::PASS) + { + if (!m_err) + m_err = image_error::UNSPECIFIED; + } + } else - err = call_load(); // using device load + { + // using device load + err = call_load(); + if (err != image_init_result::PASS) + { + if (!m_err) + m_err = image_error::UNSPECIFIED; + } + } } } - m_is_loading = false; m_create_format = 0; m_create_args = nullptr; - if (!err.first) - m_media_change_notifier(media_change_event::LOADED); - return err; } //------------------------------------------------- -// create - create an image +// create - create a image //------------------------------------------------- -std::pair device_image_interface::create(std::string_view path) +image_init_result device_image_interface::create(std::string_view path) { return create(path, nullptr, nullptr); } @@ -1035,14 +1041,13 @@ std::pair device_image_interface::create(std: // create - create a image //------------------------------------------------- -std::pair device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) +image_init_result device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) { int format_index = 0; int cnt = 0; for (auto &format : m_formatlist) { - if (create_format == format.get()) - { + if (create_format == format.get()) { format_index = cnt; break; } @@ -1076,7 +1081,7 @@ void device_image_interface::reset_and_load(std::string_view path) // to an image //------------------------------------------------- -void device_image_interface::clear() noexcept +void device_image_interface::clear() { m_mame_file.reset(); m_file.reset(); @@ -1096,8 +1101,6 @@ void device_image_interface::clear() noexcept m_software_list_name.clear(); m_hash.reset(); - - m_sequence_counter++; } @@ -1110,13 +1113,9 @@ void device_image_interface::unload() if (is_loaded() || loaded_through_softlist()) { call_unload(); - clear(); - m_media_change_notifier(media_change_event::UNLOADED); - } - else - { - clear(); // just to make sure everything is reset } + clear(); + clear_error(); } @@ -1138,10 +1137,12 @@ const util::option_guide &device_image_interface::create_option_guide() const void device_image_interface::update_names() { - const char *inst_name = image_type_name(); - const char *brief_name = image_brief_type_name(); - assert(inst_name != nullptr); - assert(brief_name != nullptr); + const char *inst_name = custom_instance_name(); + const char *brief_name = custom_brief_instance_name(); + if (inst_name == nullptr) + inst_name = device_typename(image_type()); + if (brief_name == nullptr) + brief_name = device_brieftypename(image_type()); // count instances of the general image type, or device type if custom int count = 0; @@ -1150,21 +1151,19 @@ void device_image_interface::update_names() { if (this == &image) index = count; - const char *other_name = image.image_type_name(); - const char *other_brief_name = image.image_brief_type_name(); - assert(other_name != nullptr); - assert(other_brief_name != nullptr); + const char *other_name = image.custom_instance_name(); + if (!other_name) + other_name = device_typename(image.image_type()); - if (other_name == inst_name || !strcmp(other_name, inst_name) || - other_brief_name == brief_name || !strcmp(other_brief_name, brief_name)) + if (other_name == inst_name || !strcmp(other_name, inst_name)) count++; } - m_canonical_instance_name = util::string_format("%s%d", inst_name, index + 1); + m_canonical_instance_name = string_format("%s%d", inst_name, index + 1); if (count > 1) { m_instance_name = m_canonical_instance_name; - m_brief_instance_name = util::string_format("%s%d", brief_name, index + 1); + m_brief_instance_name = string_format("%s%d", brief_name, index + 1); } else { @@ -1257,7 +1256,7 @@ const software_list_loader &device_image_interface::get_software_list_loader() c // sw_info and sw_part are also set. //------------------------------------------------- -std::error_condition device_image_interface::load_software_part(std::string_view identifier) +bool device_image_interface::load_software_part(std::string_view identifier) { // if no match has been found, we suggest similar shortnames software_list_device *swlist; @@ -1265,14 +1264,14 @@ std::error_condition device_image_interface::load_software_part(std::string_view if (m_software_part_ptr == nullptr) { software_list_device::display_matches(device().machine().config(), image_interface(), identifier); - return image_error::NOSOFTWARE; + return false; } // Load the software part const std::string &swname = m_software_part_ptr->info().shortname(); const rom_entry *start_entry = m_software_part_ptr->romdata().data(); const software_list_loader &loader = get_software_list_loader(); - std::error_condition result = loader.load_software(*this, *swlist, swname, start_entry); + bool result = loader.load_software(*this, *swlist, swname, start_entry); // check compatibility switch (swlist->is_compatible(*m_software_part_ptr)) diff --git a/src/emu/diimage.h b/src/emu/diimage.h index aa9c991c..67d20c43 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -17,13 +17,11 @@ #ifndef MAME_EMU_DIIMAGE_H #define MAME_EMU_DIIMAGE_H -#include "notifier.h" #include "utilfwd.h" #include #include #include -#include #include @@ -31,15 +29,39 @@ // TYPE DEFINITIONS //************************************************************************** +enum iodevice_t +{ + /* List of all supported devices. Refer to the device by these names only */ + IO_UNKNOWN, + IO_CARTSLOT, /* 1 - Cartridge Port, as found on most console and on some computers */ + IO_FLOPPY, /* 2 - Floppy Disk unit */ + IO_HARDDISK, /* 3 - Hard Disk unit */ + IO_CYLINDER, /* 4 - Magnetically-Coated Cylinder */ + IO_CASSETTE, /* 5 - Cassette Recorder (common on early home computers) */ + IO_PUNCHCARD, /* 6 - Card Puncher/Reader */ + IO_PUNCHTAPE, /* 7 - Tape Puncher/Reader (reels instead of punchcards) */ + IO_PRINTER, /* 8 - Printer device */ + IO_SERIAL, /* 9 - Generic Serial Port */ + IO_PARALLEL, /* 10 - Generic Parallel Port */ + IO_SNAPSHOT, /* 11 - Complete 'snapshot' of the state of the computer */ + IO_QUICKLOAD, /* 12 - Allow to load program/data into memory, without matching any actual device */ + IO_MEMCARD, /* 13 - Memory card */ + IO_CDROM, /* 14 - optical CD-ROM disc */ + IO_MAGTAPE, /* 15 - Magnetic tape */ + IO_ROM, /* 16 - Individual ROM image - the Amstrad CPC has a few applications that were sold on 16kB ROMs */ + IO_MIDIIN, /* 17 - MIDI In port */ + IO_MIDIOUT, /* 18 - MIDI Out port */ + IO_PICTURE, /* 19 - A single-frame image */ + IO_VIDEO, /* 20 - A video file */ + IO_COUNT /* 21 - Total Number of IO_devices for searching */ +}; + enum class image_error : int { INTERNAL = 1, UNSUPPORTED, INVALIDIMAGE, - INVALIDLENGTH, ALREADYOPEN, - NOSOFTWARE, - BADSOFTWARE, UNSPECIFIED }; @@ -47,6 +69,13 @@ const std::error_category &image_category() noexcept; inline std::error_condition make_error_condition(image_error e) noexcept { return std::error_condition(int(e), image_category()); } namespace std { template <> struct is_error_condition_enum : public std::true_type { }; } +struct image_device_type_info +{ + iodevice_t m_type; + const char *m_name; + const char *m_shortname; +}; + class image_device_format { public: @@ -66,56 +95,66 @@ class image_device_format }; +enum class image_init_result { PASS, FAIL }; +enum class image_verify_result { PASS, FAIL }; + +//************************************************************************** +// MACROS +//************************************************************************** + +#define DEVICE_IMAGE_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image) +#define DECLARE_DEVICE_IMAGE_LOAD_MEMBER(_name) DEVICE_IMAGE_LOAD_MEMBER(_name) + +#define DEVICE_IMAGE_UNLOAD_MEMBER(_name) void _name(device_image_interface &image) +#define DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(_name) DEVICE_IMAGE_UNLOAD_MEMBER(_name) + + // ======================> device_image_interface // class representing interface-specific live image class device_image_interface : public device_interface { public: - enum class media_change_event - { - LOADED, - UNLOADED - }; + typedef device_delegate load_delegate; + typedef device_delegate unload_delegate; - using formatlist_type = std::vector >; + typedef std::vector> formatlist_type; // construction/destruction device_image_interface(const machine_config &mconfig, device_t &device); virtual ~device_image_interface(); - virtual std::pair call_load() { return std::make_pair(std::error_condition(), std::string()); } - virtual std::pair call_create(int format_type, util::option_resolution *format_options) { return std::make_pair(std::error_condition(), std::string()); } + static const char *device_typename(iodevice_t type); + static const char *device_brieftypename(iodevice_t type); + static iodevice_t device_typeid(const char *name); + + virtual image_init_result call_load() { return image_init_result::PASS; } + virtual image_init_result call_create(int format_type, util::option_resolution *format_options) { return image_init_result::PASS; } virtual void call_unload() { } virtual std::string call_display() { return std::string(); } virtual u32 unhashed_header_length() const noexcept { return 0; } virtual bool core_opens_image_file() const noexcept { return true; } - virtual bool image_is_chd_type() const noexcept { return false; } + virtual iodevice_t image_type() const noexcept = 0; virtual bool is_readable() const noexcept = 0; virtual bool is_writeable() const noexcept = 0; virtual bool is_creatable() const noexcept = 0; + virtual bool must_be_loaded() const noexcept = 0; virtual bool is_reset_on_load() const noexcept = 0; - virtual bool support_command_line_image_creation() const noexcept { return false; } + virtual bool support_command_line_image_creation() const noexcept; virtual const char *image_interface() const noexcept { return nullptr; } virtual const char *file_extensions() const noexcept = 0; virtual const util::option_guide &create_option_guide() const; - virtual const char *image_type_name() const noexcept = 0; - virtual const char *image_brief_type_name() const noexcept = 0; - - // Set block device image regions for arcade systems - void add_region(std::string name, bool is_default = false); - bool has_preset_images() const; - bool has_preset_images_selection() const; - std::vector preset_images_list() const; - int current_preset_image_id() const; - void switch_preset_image(int id); - chd_file *current_preset_image_chd() const; - void check_preset_images(); + virtual const char *custom_instance_name() const noexcept { return nullptr; } + virtual const char *custom_brief_instance_name() const noexcept { return nullptr; } const image_device_format *device_get_indexed_creatable_format(int index) const noexcept { return (index < m_formatlist.size()) ? m_formatlist.at(index).get() : nullptr; } - const image_device_format *device_get_named_creatable_format(std::string_view format_name) const noexcept; + const image_device_format *device_get_named_creatable_format(const std::string &format_name) noexcept; const util::option_guide &device_get_creation_option_guide() const { return create_option_guide(); } + std::string_view error(); + void seterror(std::error_condition err, const char *message); + void message(const char *format, ...) ATTR_PRINTF(2,3); + bool exists() const noexcept { return !m_image_name.empty(); } // get image file path/name @@ -126,15 +165,9 @@ class device_image_interface : public device_interface bool is_filetype(std::string_view candidate_filetype) const; bool is_open() const noexcept { return bool(m_file); } - util::core_file &image_core_file() const noexcept { assert(is_open()); return *m_file; } + util::core_file &image_core_file() const noexcept { return *m_file; } bool is_readonly() const noexcept { return m_readonly; } - u32 sequence_counter() const { return m_sequence_counter; } // Increments on media load/unload/etc - util::notifier_subscription add_media_change_notifier(delegate &&n); - template - util::notifier_subscription add_media_change_notifier(T &&n) - { return add_media_change_notifier(delegate(std::forward(n))); } - // image file I/O wrappers // TODO: move away from using these and let implementations use the I/O interface directly // FIXME: don't swallow errors @@ -148,13 +181,15 @@ class device_image_interface : public device_interface u32 fread(void *buffer, u32 length) { check_for_file(); - auto const [err, actual] = read(*m_file, buffer, length); + size_t actual; + m_file->read(buffer, length, actual); return actual; } u32 fwrite(const void *buffer, u32 length) { check_for_file(); - auto const [err, actual] = write(*m_file, buffer, length); + size_t actual; + m_file->write(buffer, length, actual); return actual; } std::error_condition fseek(s64 offset, int whence) @@ -169,6 +204,32 @@ class device_image_interface : public device_interface m_file->tell(result); return result; } + int fgetc() + { + char ch; + if (fread(&ch, 1) != 1) + ch = '\0'; + return ch; + } + char *fgets(char *buffer, u32 length) + { + check_for_file(); + return m_file->gets(buffer, length); + } + bool image_feof() + { + check_for_file(); + return m_file->eof(); + } + const void *ptr() + { + check_for_file(); + return m_file->buffer(); + } + + // allocate and read into buffers + u32 fread(std::unique_ptr &ptr, u32 length) { ptr = std::make_unique(length); return fread(ptr.get(), length); } + u32 fread(std::unique_ptr &ptr, u32 length, offs_t offset) { ptr = std::make_unique(length); return fread(ptr.get() + offset, length - offset); } // access to software list item information const software_info *software_entry() const noexcept; @@ -182,62 +243,67 @@ class device_image_interface : public device_interface const std::string &working_directory() const { return m_working_directory; } // access to software list properties and ROM data areas - u8 *get_software_region(std::string_view tag); - u32 get_software_region_length(std::string_view tag); - const char *get_feature(std::string_view feature_name) const; - std::error_condition load_software_region(std::string_view tag, std::unique_ptr &ptr); + u8 *get_software_region(const char *tag); + u32 get_software_region_length(const char *tag); + const char *get_feature(const char *feature_name) const; + bool load_software_region(const char *tag, std::unique_ptr &ptr); u32 crc(); - util::hash_collection &hash() { return m_hash; } - util::hash_collection calculate_hash_on_file(util::random_read &file) const; + util::hash_collection& hash() { return m_hash; } + util::hash_collection calculate_hash_on_file(util::core_file &file) const; void battery_load(void *buffer, int length, int fill); void battery_load(void *buffer, int length, const void *def_buffer); void battery_save(const void *buffer, int length); + const char *image_type_name() const { return device_typename(image_type()); } + const std::string &instance_name() const { return m_instance_name; } const std::string &brief_instance_name() const { return m_brief_instance_name; } const std::string &canonical_instance_name() const { return m_canonical_instance_name; } + bool uses_file_extension(const char *file_extension) const; const formatlist_type &formatlist() const { return m_formatlist; } // loads an image file - std::pair load(std::string_view path); + image_init_result load(std::string_view path); // loads a softlist item by name - std::pair load_software(std::string_view software_identifier); + image_init_result load_software(std::string_view software_identifier); - std::pair finish_load(); + image_init_result finish_load(); void unload(); - std::pair create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); - std::pair create(std::string_view path); - std::error_condition load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); + image_init_result create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); + image_init_result create(std::string_view path); + bool load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); std::error_condition reopen_for_write(std::string_view path); - void set_user_loadable(bool user_loadable) noexcept { m_user_loadable = user_loadable; } - void set_must_be_loaded(bool must_be_loaded) noexcept { m_must_be_loaded = must_be_loaded; } + void set_user_loadable(bool user_loadable) { m_user_loadable = user_loadable; } bool user_loadable() const noexcept { return m_user_loadable; } - bool must_be_loaded() const noexcept { return m_must_be_loaded; } bool is_reset_and_loading() const noexcept { return m_is_reset_and_loading; } const std::string &full_software_name() const noexcept { return m_full_software_name; } protected: - // device_interface implementation + // interface-level overrides virtual void interface_config_complete() override; virtual const software_list_loader &get_software_list_loader() const; - virtual bool use_software_list_file_extension_for_filetype() const noexcept { return false; } + virtual const bool use_software_list_file_extension_for_filetype() const { return false; } + image_init_result load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); std::error_condition load_image_by_path(u32 open_flags, std::string_view path); - bool is_loaded() const noexcept { return m_file != nullptr; } + void clear(); + bool is_loaded() const { return m_file != nullptr; } - void set_image_tag(); + void set_image_filename(std::string_view filename); + + void clear_error(); void check_for_file() const { if (!m_file) throw emu_fatalerror("%s(%s): Illegal operation on unmounted image", device().shortname(), device().tag()); } void make_readonly() noexcept { m_readonly = true; } - std::error_condition image_checkhash(); + bool image_checkhash(); const software_part *find_software_item(std::string_view identifier, bool restrict_to_interface, software_list_device **device = nullptr) const; std::string software_get_default_slot(std::string_view default_card_slot) const; @@ -245,21 +311,17 @@ class device_image_interface : public device_interface void add_format(std::unique_ptr &&format); void add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec); -private: - std::vector determine_open_plan(bool is_create); - void update_names(); - void set_image_filename(std::string_view filename); - void clear() noexcept; - std::pair load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); - std::error_condition load_software_part(std::string_view identifier); + // derived class overrides - bool init_phase() const; - static std::error_condition run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); + // configuration + static const image_device_type_info *find_device_type(iodevice_t type); + static const image_device_type_info m_device_info_array[]; - // loads an image or software items and resets - called internally when we - // load an is_reset_on_load() item - void reset_and_load(std::string_view path); + // error related info + std::error_condition m_err; + std::string m_err_message; +private: // variables that are only non-zero when an image is mounted util::core_file::ptr m_file; std::unique_ptr m_mame_file; @@ -268,27 +330,29 @@ class device_image_interface : public device_interface std::string m_basename_noext; std::string m_filetype; - // preset images regions - std::vector m_possible_preset_regions; - std::vector m_preset_images; - int m_default_region, m_current_region; - // Software information std::string m_full_software_name; const software_part *m_software_part_ptr; std::string m_software_list_name; + std::vector determine_open_plan(bool is_create); + void update_names(); + bool load_software_part(std::string_view identifier); + + bool init_phase() const; + static bool run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); + + // loads an image or software items and resets - called internally when we + // load an is_reset_on_load() item + void reset_and_load(std::string_view path); + // creation info formatlist_type m_formatlist; // working directory; persists across mounts std::string m_working_directory; - // to notify interested parties when media changes - util::notifier m_media_change_notifier; - // flags - u32 m_sequence_counter; bool m_readonly; bool m_created; @@ -306,8 +370,6 @@ class device_image_interface : public device_interface // we want to disable command line cart loading... bool m_user_loadable; - bool m_must_be_loaded; - bool m_is_loading; bool m_is_reset_and_loading; @@ -316,4 +378,4 @@ class device_image_interface : public device_interface // iterator typedef device_interface_enumerator image_interface_enumerator; -#endif // MAME_EMU_DIIMAGE_H +#endif /* MAME_EMU_DIIMAGE_H */ From c0bd27fd5475546d7a0ff96b5efea760f080bb03 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:48:10 -0600 Subject: [PATCH 28/47] Revert updates. --- src/emu/diimage.cpp | 677 ++++++++++++++++++++++---------------------- src/emu/diimage.h | 224 ++++++--------- 2 files changed, 420 insertions(+), 481 deletions(-) diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 031ed46e..7ad94fb6 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -11,49 +11,20 @@ #include "emu.h" #include "emuopts.h" +#include "fileio.h" #include "romload.h" #include "softlist.h" #include "softlist_dev.h" -#include "ui/uimain.h" - #include "corestr.h" #include "opresolv.h" +#include "path.h" #include "zippath.h" #include -#include #include #include - - -//************************************************************************** -// DEVICE CONFIG IMAGE INTERFACE -//************************************************************************** -const image_device_type_info device_image_interface::m_device_info_array[] = - { - { IO_UNKNOWN, "unknown", "unkn" }, /* 0 */ - { IO_CARTSLOT, "cartridge", "cart" }, /* 1 */ - { IO_FLOPPY, "floppydisk", "flop" }, /* 2 */ - { IO_HARDDISK, "harddisk", "hard" }, /* 3 */ - { IO_CYLINDER, "cylinder", "cyln" }, /* 4 */ - { IO_CASSETTE, "cassette", "cass" }, /* 5 */ - { IO_PUNCHCARD, "punchcard", "pcrd" }, /* 6 */ - { IO_PUNCHTAPE, "punchtape", "ptap" }, /* 7 */ - { IO_PRINTER, "printout", "prin" }, /* 8 */ - { IO_SERIAL, "serial", "serl" }, /* 9 */ - { IO_PARALLEL, "parallel", "parl" }, /* 10 */ - { IO_SNAPSHOT, "snapshot", "dump" }, /* 11 */ - { IO_QUICKLOAD, "quickload", "quik" }, /* 12 */ - { IO_MEMCARD, "memcard", "memc" }, /* 13 */ - { IO_CDROM, "cdrom", "cdrm" }, /* 14 */ - { IO_MAGTAPE, "magtape", "magt" }, /* 15 */ - { IO_ROM, "romimage", "rom" }, /* 16 */ - { IO_MIDIIN, "midiin", "min" }, /* 17 */ - { IO_MIDIOUT, "midiout", "mout" }, /* 18 */ - { IO_PICTURE, "picture", "pic" }, /* 19 */ - { IO_VIDEO, "vidfile", "vid" } /* 20 */ - }; +#include //************************************************************************** @@ -94,15 +65,18 @@ image_device_format::~image_device_format() device_image_interface::device_image_interface(const machine_config &mconfig, device_t &device) : device_interface(device, "image") - , m_err() , m_file() , m_mame_file() + , m_default_region(-1) + , m_current_region(-1) , m_software_part_ptr(nullptr) + , m_sequence_counter(0) , m_readonly(false) , m_created(false) , m_create_format(0) , m_create_args(nullptr) , m_user_loadable(true) + , m_must_be_loaded(false) , m_is_loading(false) , m_is_reset_and_loading(false) { @@ -117,6 +91,17 @@ device_image_interface::~device_image_interface() { } +//------------------------------------------------- +// add_region - register a region that may +// have a chd image +//------------------------------------------------- +void device_image_interface::add_region(std::string name, bool is_default) +{ + if (is_default) + m_default_region = m_possible_preset_regions.size(); + m_possible_preset_regions.push_back(name); +} + //------------------------------------------------- // interface_config_complete - perform any @@ -130,57 +115,143 @@ void device_image_interface::interface_config_complete() update_names(); } - //------------------------------------------------- -// find_device_type - search through list of -// device types to extract data +// check_preset_images - lookup the CHDs from the +// region(s), if any //------------------------------------------------- -const image_device_type_info *device_image_interface::find_device_type(iodevice_t type) +void device_image_interface::check_preset_images() { - for (const image_device_type_info &info : m_device_info_array) + if (!m_possible_preset_regions.empty()) { - if (info.m_type == type) - return &info; + for(const auto &r : m_possible_preset_regions) + m_preset_images.push_back(device().machine().rom_load().get_disk_handle(":" + r)); + if (m_default_region != -1 && m_preset_images[m_default_region]) + m_current_region = m_default_region; + else + { + for (m_current_region = 0; m_current_region != int(m_preset_images.size()) && !m_preset_images[m_current_region]; m_current_region++); + if (m_current_region == int(m_preset_images.size())) + fatalerror("%s: No configured region has an image\n", device().tag()); + } + set_image_tag(); + set_user_loadable(false); + } + else + { + std::string tag = device().owner()->tag(); + auto *const chd = device().machine().rom_load().get_disk_handle(tag); + if (chd) + { + m_possible_preset_regions.emplace_back(std::move(tag)); + m_preset_images.push_back(chd); + m_current_region = 0; + set_image_tag(); + set_user_loadable(false); + } } - return nullptr; } //------------------------------------------------- -// device_typename - retrieves device type name +// has_preset_images - does the device have an +// image to retrieve through current_image_* //------------------------------------------------- -const char *device_image_interface::device_typename(iodevice_t type) +bool device_image_interface::has_preset_images() const { - const image_device_type_info *info = find_device_type(type); - return (info != nullptr) ? info->m_name : "unknown"; + return !m_possible_preset_regions.empty(); } //------------------------------------------------- -// device_brieftypename - retrieves device -// brief type name +// has_preset_images - does the device have +// multiple preset images with user selection //------------------------------------------------- -const char *device_image_interface::device_brieftypename(iodevice_t type) +bool device_image_interface::has_preset_images_selection() const { - const image_device_type_info *info = find_device_type(type); - return (info != nullptr) ? info->m_shortname : "unk"; + int icount = 0; + for (const auto *f : m_preset_images) + if (f) + icount ++; + return icount > 1; } + //------------------------------------------------- -// device_typeid - retrieves device type id +// preset_images_list -- generate the list of +// available image names //------------------------------------------------- -iodevice_t device_image_interface::device_typeid(const char *name) +std::vector device_image_interface::preset_images_list() const { - for (const image_device_type_info &info : m_device_info_array) + std::vector result; + for (unsigned int i = 0; i != m_preset_images.size(); i++) + if (m_preset_images[i]) + result.push_back(m_possible_preset_regions[i]); + return result; +} + +//------------------------------------------------- +// current_preset_image_id -- current image id, +// recomputed to ignore non-present images. +// returns -1 if not in preset mode +//------------------------------------------------- + +int device_image_interface::current_preset_image_id() const +{ + if (m_current_region == -1) + return -1; + int id = 0; + for (int i = 0; i != m_current_region; i++) + if (m_preset_images[i]) + id++; + return id; +} + +//------------------------------------------------- +// current_preset_image_chd -- return the chd of +// the current active image, nullptr if non +//------------------------------------------------- + +chd_file *device_image_interface::current_preset_image_chd() const +{ + if (m_current_region == -1) + return nullptr; + return m_preset_images[m_current_region]; +} + +//------------------------------------------------- +// switch_preset_image -- change of preset image +//------------------------------------------------- + +void device_image_interface::switch_preset_image(int id) +{ + for (unsigned i = 0; i != m_preset_images.size(); i++) { - if (!core_stricmp(name, info.m_name) || !core_stricmp(name, info.m_shortname)) - return info.m_type; + if (m_preset_images[i]) + { + if (!id) + { + if (is_loaded() || loaded_through_softlist()) + { + call_unload(); + clear(); + m_media_change_notifier(media_change_event::UNLOADED); + } + m_current_region = i; + auto const err = call_load(); + if (!err.first) + m_media_change_notifier(media_change_event::LOADED); + break; + } + id--; + } } - return (iodevice_t)-1; + + return; } + //------------------------------------------------- // set_image_filename - specifies the filename of // an image @@ -194,9 +265,9 @@ void device_image_interface::set_image_filename(std::string_view filename) // find the last "path separator" auto iter = std::find_if( - m_image_name.rbegin(), - m_image_name.rend(), - [](char c) { return (c == '\\') || (c == '/') || (c == ':'); }); + m_image_name.rbegin(), + m_image_name.rend(), + [] (char c) { return (c == '\\') || (c == '/') || (c == ':'); }); if (iter != m_image_name.rend()) m_basename.assign(iter.base(), m_image_name.end()); @@ -209,6 +280,20 @@ void device_image_interface::set_image_filename(std::string_view filename) m_filetype = core_filename_extract_extension(m_basename, true); } +//------------------------------------------------- +// set_image_tag - specifies the filename of +// an image as the device tag +//------------------------------------------------- + +void device_image_interface::set_image_tag() +{ + m_image_name = device().owner()->tag(); + m_working_directory = ""; + m_basename = ""; + m_basename_noext = ""; + m_filetype = ""; +} + //------------------------------------------------- // is_filetype - check if the filetype matches @@ -216,14 +301,24 @@ void device_image_interface::set_image_filename(std::string_view filename) bool device_image_interface::is_filetype(std::string_view candidate_filetype) const { - return std::equal(m_filetype.begin(), m_filetype.end(), candidate_filetype.begin(), candidate_filetype.end(), - [] (unsigned char c1, unsigned char c2) { return std::tolower(c1) == c2; }); + return util::streqlower(m_filetype, candidate_filetype); } -/**************************************************************************** - CREATION FORMATS -****************************************************************************/ +//------------------------------------------------- +// add_media_change_notifier - subscribe for +// media change notifications +//------------------------------------------------- + +util::notifier_subscription device_image_interface::add_media_change_notifier(delegate &&n) +{ + return m_media_change_notifier.subscribe(std::move(n)); +} + + +//*************************************************************************** +// CREATION FORMATS +//*************************************************************************** //------------------------------------------------- // device_get_named_creatable_format - @@ -231,10 +326,10 @@ bool device_image_interface::is_filetype(std::string_view candidate_filetype) co // image creation by name //------------------------------------------------- -const image_device_format *device_image_interface::device_get_named_creatable_format(const std::string &format_name) noexcept +const image_device_format *device_image_interface::device_get_named_creatable_format(std::string_view format_name) const noexcept { - for (auto &format : m_formatlist) - if (format->name() == format_name) + for (const auto &format : m_formatlist) + if (std::string_view(format->name()) == format_name) return format.get(); return nullptr; } @@ -261,22 +356,9 @@ void device_image_interface::add_format(std::string &&name, std::string &&descri } -/**************************************************************************** - ERROR HANDLING -****************************************************************************/ - -//------------------------------------------------- -// image_clear_error - clear out any specified -// error -//------------------------------------------------- - -void device_image_interface::clear_error() -{ - m_err.clear(); - m_err_message.clear(); -} - - +//*************************************************************************** +// ERROR HANDLING +//*************************************************************************** //------------------------------------------------- // error - returns the error text for an image @@ -298,7 +380,10 @@ std::error_category const &image_category() noexcept "Internal error"sv, "Unsupported operation"sv, "Invalid image"sv, + "Invalid image length"sv, "File already open"sv, + "Unrecognized software item"sv, + "Invalid software item"sv, "Unspecified error"sv }; if ((0 <= condition) && (std::size(s_messages) > condition)) return std::string(s_messages[condition]); @@ -310,50 +395,6 @@ std::error_category const &image_category() noexcept return s_image_category_instance; } -std::string_view device_image_interface::error() -{ - if (m_err && m_err_message.empty()) - m_err_message = m_err.message(); - return m_err_message; -} - - - -//------------------------------------------------- -// seterror - specifies an error on an image -//------------------------------------------------- - -void device_image_interface::seterror(std::error_condition err, const char *message) -{ - clear_error(); - m_err = err; - if (message) - m_err_message = message; -} - - - -//------------------------------------------------- -// message - used to display a message while -// loading -//------------------------------------------------- - -void device_image_interface::message(const char *format, ...) -{ - va_list args; - char buffer[256]; - - /* format the message */ - va_start(args, format); - vsnprintf(buffer, std::size(buffer), format, args); - va_end(args); - - /* display the popup for a standard amount of time */ - device().machine().ui().popup_time(5, "%s: %s", - basename(), - buffer); -} - //------------------------------------------------- // software_entry - return a pointer to the @@ -370,14 +411,13 @@ const software_info *device_image_interface::software_entry() const noexcept // get_software_region //------------------------------------------------- -u8 *device_image_interface::get_software_region(const char *tag) +u8 *device_image_interface::get_software_region(std::string_view tag) { if (!loaded_through_softlist()) return nullptr; - std::string full_tag = util::string_format("%s:%s", device().tag(), tag); - memory_region *region = device().machine().root_device().memregion(full_tag); - return region != nullptr ? region->base() : nullptr; + memory_region *const region = device().memregion(tag); + return region ? region->base() : nullptr; } @@ -385,11 +425,13 @@ u8 *device_image_interface::get_software_region(const char *tag) // image_get_software_region_length //------------------------------------------------- -u32 device_image_interface::get_software_region_length(const char *tag) +u32 device_image_interface::get_software_region_length(std::string_view tag) { - std::string full_tag = util::string_format("%s:%s", device().tag(), tag); - memory_region *region = device().machine().root_device().memregion(full_tag); - return region != nullptr ? region->bytes() : 0; + if (!loaded_through_softlist()) + return 0; + + memory_region *const region = device().memregion(tag); + return region ? region->bytes() : 0; } @@ -397,7 +439,7 @@ u32 device_image_interface::get_software_region_length(const char *tag) // image_get_feature //------------------------------------------------- -const char *device_image_interface::get_feature(const char *feature_name) const +const char *device_image_interface::get_feature(std::string_view feature_name) const { return !m_software_part_ptr ? nullptr : m_software_part_ptr->feature(feature_name); } @@ -407,7 +449,7 @@ const char *device_image_interface::get_feature(const char *feature_name) const // load_software_region - //------------------------------------------------- -bool device_image_interface::load_software_region(const char *tag, std::unique_ptr &ptr) +std::error_condition device_image_interface::load_software_region(std::string_view tag, std::unique_ptr &ptr) { size_t size = get_software_region_length(tag); @@ -415,9 +457,10 @@ bool device_image_interface::load_software_region(const char *tag, std::unique_p { ptr = std::make_unique(size); memcpy(ptr.get(), get_software_region(tag), size); + return std::error_condition(); } - - return size > 0; + else + return image_error::UNSUPPORTED; } @@ -428,75 +471,61 @@ bool device_image_interface::load_software_region(const char *tag, std::unique_p // to be loaded // **************************************************************************** -bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) +std::error_condition device_image_interface::run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) { // reset the hash; we want to override existing data hashes.reset(); // figure out the size, and "cap" the skip bytes u64 size; - if (file.length(size)) - return false; + std::error_condition filerr = file.length(size); + if (filerr) + return filerr; skip_bytes = u32(std::min(skip_bytes, size)); - // seek to the beginning - file.seek(skip_bytes, SEEK_SET); // TODO: check error return - u64 position = skip_bytes; - - // keep on reading hashes - hashes.begin(types); - while (position < size) - { - uint8_t buffer[8192]; - - // read bytes - const size_t count = size_t(std::min(size - position, sizeof(buffer))); - size_t actual_count; - const std::error_condition filerr = file.read(buffer, count, actual_count); - if (filerr || !actual_count) - return false; - position += actual_count; - - // and compute the hashes - hashes.buffer(buffer, actual_count); - } - hashes.end(); + // and compute the hashes + size_t actual_count; + filerr = hashes.compute(file, skip_bytes, size - skip_bytes, actual_count, types); + if (filerr) + return filerr; - // cleanup - file.seek(0, SEEK_SET); // TODO: check error return - return true; + return std::error_condition(); } -bool device_image_interface::image_checkhash() +std::error_condition device_image_interface::image_checkhash() { // only calculate CRC if it hasn't been calculated, and the open_mode is read only u32 crcval; if (!m_hash.crc(crcval) && is_readonly() && !m_created) { +#ifdef __LIBRETRO__ + // because 'image_is_chd_type()' below does not actually work + if (core_filename_ends_with(m_image_name.c_str(), "chd")) + return std::error_condition(); +#endif // do not cause a linear read of 600 megs please // TODO: use SHA1 in the CHD header as the hash - if (image_type() == IO_CDROM) - return true; + if (image_is_chd_type()) + return std::error_condition(); // Skip calculating the hash when we have an image mounted through a software list if (loaded_through_softlist()) - return true; + return std::error_condition(); // run the hash - if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL)) - return false; + return run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL); } - return true; + return std::error_condition(); } -util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const +util::hash_collection device_image_interface::calculate_hash_on_file(util::random_read &file) const { // calculate the hash util::hash_collection hash; - if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) + if (run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) hash.reset(); return hash; } @@ -514,33 +543,6 @@ u32 device_image_interface::crc() } -//------------------------------------------------- -// support_command_line_image_creation - do we -// want to support image creation from the front -// end command line? -//------------------------------------------------- - -bool device_image_interface::support_command_line_image_creation() const noexcept -{ - bool result; - switch (image_type()) - { - case IO_PRINTER: - case IO_SERIAL: - case IO_PARALLEL: - // going by the assumption that these device image types should support this - // behavior; ideally we'd get rid of IO_* and just push this to the specific - // devices - result = true; - break; - default: - result = false; - break; - } - return result; -} - - // **************************************************************************** // Battery functions // @@ -619,34 +621,6 @@ void device_image_interface::battery_save(const void *buffer, int length) } -//------------------------------------------------- -// uses_file_extension - update configuration -// based on completed device setup -//------------------------------------------------- - -bool device_image_interface::uses_file_extension(const char *file_extension) const -{ - bool result = false; - - if (file_extension[0] == '.') - file_extension++; - - /* find the extensions */ - std::string extensions(file_extensions()); - char *ext = strtok((char*)extensions.c_str(),","); - while (ext != nullptr) - { - if (!core_stricmp(ext, file_extension)) - { - result = true; - break; - } - ext = strtok (nullptr, ","); - } - return result; -} - - // *************************************************************************** // IMAGE LOADING // *************************************************************************** @@ -712,15 +686,20 @@ std::vector device_image_interface::determine_open_plan(bool is_create) { std::vector open_plan; - // emit flags into a vector - if (!is_create && is_readable() && is_writeable()) - open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE); - if (!is_create && !is_readable() && is_writeable()) - open_plan.push_back(OPEN_FLAG_WRITE); - if (!is_create && is_readable()) - open_plan.push_back(OPEN_FLAG_READ); - if (is_create && is_writeable() && is_creatable()) - open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + if (!is_create) + { + if (is_writeable()) + open_plan.push_back(is_readable() ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_WRITE); + if (is_readable()) + open_plan.push_back(OPEN_FLAG_READ); + } + else if (is_writeable() && is_creatable()) + { + if (is_readable()) + open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + else + open_plan.push_back(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); + } return open_plan; } @@ -772,9 +751,9 @@ static int verify_length_and_hash(emu_file *file, std::string_view name, u32 exp // load_software - software image loading //------------------------------------------------- -bool device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) +std::error_condition device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) { - bool retval = false; + std::error_condition retval; int warningcount = 0; for (const rom_entry *region = start; region; region = rom_next_region(region)) { @@ -786,7 +765,7 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st { const software_info *const swinfo = swlist.find(std::string(swname)); if (!swinfo) - return false; + return image_error::NOSOFTWARE; if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED) osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()); @@ -816,14 +795,31 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st else filerr = m_mame_file->open(romp->name()); if (filerr) + { m_mame_file.reset(); + std::ostringstream msg; + util::stream_format(msg, + "%s: error opening image file %s: %s (%s:%d)", + device().tag(), romp->name(), + filerr.message(), + filerr.category().name(), + filerr.value()); + if (!searchpath.empty()) + { + msg << " (tried in"; + for (auto const &path : searchpath) + msg << ' ' << path; + msg << ')'; + } + osd_printf_error("%s\n", std::move(msg).str()); + } warningcount += verify_length_and_hash(m_mame_file.get(), romp->name(), romp->get_length(), util::hash_collection(romp->hashdata())); if (!filerr) filerr = util::core_file::open_proxy(*m_mame_file, m_file); - if (!filerr) - retval = true; + if (filerr) + retval = filerr; break; // load first item for start } @@ -841,16 +837,16 @@ bool device_image_interface::load_software(software_list_device &swlist, std::st // load_internal - core image loading //------------------------------------------------- -image_init_result device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) +std::pair device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) { + std::pair err; + // first unload the image unload(); - // clear any possible error messages - clear_error(); - // we are now loading m_is_loading = true; + m_sequence_counter++; // record the filename set_image_filename(path); @@ -858,50 +854,47 @@ image_init_result device_image_interface::load_internal(std::string_view path, b if (core_opens_image_file()) { // determine open plan - std::vector open_plan = determine_open_plan(is_create); + std::vector const open_plan = determine_open_plan(is_create); // attempt to open the file in various ways for (auto iter = open_plan.cbegin(); !m_file && iter != open_plan.cend(); iter++) { // open the file - m_err = load_image_by_path(*iter, path); - if (m_err && (m_err != std::errc::no_such_file_or_directory) && (m_err != std::errc::permission_denied)) - goto done; + err.first = load_image_by_path(*iter, path); + if (err.first && (err.first != std::errc::no_such_file_or_directory) && (err.first != std::errc::permission_denied)) + break; } // did we fail to find the file? - if (!m_file) - { - m_err = std::errc::no_such_file_or_directory; - goto done; - } + if (!err.first && !m_file) + err.first = std::errc::no_such_file_or_directory; } - // call device load or create - m_create_format = create_format; - m_create_args = create_args; - - if (!init_phase()) + if (!err.first) { - m_err = (finish_load() == image_init_result::PASS) ? std::error_condition() : image_error::INTERNAL; - if (m_err) - goto done; + // call device load or create + m_create_format = create_format; + m_create_args = create_args; + + if (!init_phase()) + err = finish_load(); } - // success! -done: - if (m_err) + if (err.first) { - if (!init_phase()) - { - if (device().machine().phase() == machine_phase::RUNNING) - device().popmessage("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error()); - else - osd_printf_error("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path, error()); - } + osd_printf_error( + !err.second.empty() + ? (is_create ? "Unable to create image '%1$s': %2$s (%3$s:%4$d %5$s)\n" : "Unable to load image '%1$s': %2$s (%3$s:%4$d %5$s)\n") + : (is_create ? "Unable to create image '%1$s': %5$s (%3$s:%4$d)\n" : "Unable to load image '%1$s': %5$s (%3$s:%4$d)\n"), + path, + err.second, + err.first.category().name(), + err.first.value(), + err.first.message()); clear(); } - return m_err ? image_init_result::FAIL : image_init_result::PASS; + + return err; } @@ -909,13 +902,13 @@ image_init_result device_image_interface::load_internal(std::string_view path, b // load - load an image into MAME //------------------------------------------------- -image_init_result device_image_interface::load(std::string_view path) +std::pair device_image_interface::load(std::string_view path) { // is this a reset on load item? if (is_reset_on_load() && !init_phase()) { reset_and_load(path); - return image_init_result::PASS; + return std::make_pair(std::error_condition(), std::string()); } return load_internal(path, false, 0, nullptr); @@ -926,26 +919,26 @@ image_init_result device_image_interface::load(std::string_view path) // load_software - loads a softlist item by name //------------------------------------------------- -image_init_result device_image_interface::load_software(std::string_view software_identifier) +std::pair device_image_interface::load_software(std::string_view software_identifier) { // Is this a software part that forces a reset and we're at runtime? If so, get this loaded through reset_and_load if (is_reset_on_load() && !init_phase()) { reset_and_load(software_identifier); - return image_init_result::PASS; + return std::make_pair(std::error_condition(), std::string()); } // Prepare to load unload(); - clear_error(); m_is_loading = true; // Check if there's a software list defined for this device and use that if we're not creating an image - bool softload = load_software_part(software_identifier); - if (!softload) + std::pair err; + err.first = load_software_part(software_identifier); + if (err.first) { m_is_loading = false; - return image_init_result::FAIL; + return err; } // set up softlist stuff @@ -955,9 +948,10 @@ image_init_result device_image_interface::load_software(std::string_view softwar m_image_name = m_full_software_name; m_basename = m_full_software_name; m_basename_noext = m_full_software_name; - m_filetype = use_software_list_file_extension_for_filetype() && m_mame_file != nullptr - ? std::string(core_filename_extract_extension(m_mame_file->filename(), true)) - : ""; + if (use_software_list_file_extension_for_filetype() && m_mame_file) + m_filetype = core_filename_extract_extension(m_mame_file->filename(), true); + else + m_filetype.clear(); // Copy some image information when we have been loaded through a software list software_info &swinfo = m_software_part_ptr->info(); @@ -967,16 +961,31 @@ image_init_result device_image_interface::load_software(std::string_view softwar fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n"); // set file type - std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr) + std::string filename = (m_mame_file && m_mame_file->filename()) ? m_mame_file->filename() : ""; m_filetype = core_filename_extract_extension(filename, true); // call finish_load if necessary - if (init_phase() == false && (finish_load() != image_init_result::PASS)) - return image_init_result::FAIL; + if (!init_phase()) + { + err = finish_load(); + if (err.first) + { + osd_printf_error( + !err.second.empty() + ? "Unable to load software item '%1$s': %2$s (%3$s:%4$d %5$s)\n" + : "Unable to load software item '%1$s': %5$s (%3$s:%4$d)\n", + software_identifier, + err.second, + err.first.category().name(), + err.first.value(), + err.first.message()); + clear(); + } + } - return image_init_result::PASS; + return err; } @@ -985,53 +994,38 @@ image_init_result device_image_interface::load_software(std::string_view softwar // from core //------------------------------------------------- -image_init_result device_image_interface::finish_load() +std::pair device_image_interface::finish_load() { - image_init_result err = image_init_result::PASS; + std::pair err; if (m_is_loading) { - if (!image_checkhash()) - { - m_err = image_error::INVALIDIMAGE; - err = image_init_result::FAIL; - } + err.first = image_checkhash(); - if (err == image_init_result::PASS) + if (!err.first) { if (m_created) - { err = call_create(m_create_format, m_create_args); - if (err != image_init_result::PASS) - { - if (!m_err) - m_err = image_error::UNSPECIFIED; - } - } else - { - // using device load - err = call_load(); - if (err != image_init_result::PASS) - { - if (!m_err) - m_err = image_error::UNSPECIFIED; - } - } + err = call_load(); // using device load } } + m_is_loading = false; m_create_format = 0; m_create_args = nullptr; + if (!err.first) + m_media_change_notifier(media_change_event::LOADED); + return err; } //------------------------------------------------- -// create - create a image +// create - create an image //------------------------------------------------- -image_init_result device_image_interface::create(std::string_view path) +std::pair device_image_interface::create(std::string_view path) { return create(path, nullptr, nullptr); } @@ -1041,13 +1035,14 @@ image_init_result device_image_interface::create(std::string_view path) // create - create a image //------------------------------------------------- -image_init_result device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) +std::pair device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) { int format_index = 0; int cnt = 0; for (auto &format : m_formatlist) { - if (create_format == format.get()) { + if (create_format == format.get()) + { format_index = cnt; break; } @@ -1081,7 +1076,7 @@ void device_image_interface::reset_and_load(std::string_view path) // to an image //------------------------------------------------- -void device_image_interface::clear() +void device_image_interface::clear() noexcept { m_mame_file.reset(); m_file.reset(); @@ -1101,6 +1096,8 @@ void device_image_interface::clear() m_software_list_name.clear(); m_hash.reset(); + + m_sequence_counter++; } @@ -1113,9 +1110,13 @@ void device_image_interface::unload() if (is_loaded() || loaded_through_softlist()) { call_unload(); + clear(); + m_media_change_notifier(media_change_event::UNLOADED); + } + else + { + clear(); // just to make sure everything is reset } - clear(); - clear_error(); } @@ -1137,12 +1138,10 @@ const util::option_guide &device_image_interface::create_option_guide() const void device_image_interface::update_names() { - const char *inst_name = custom_instance_name(); - const char *brief_name = custom_brief_instance_name(); - if (inst_name == nullptr) - inst_name = device_typename(image_type()); - if (brief_name == nullptr) - brief_name = device_brieftypename(image_type()); + const char *inst_name = image_type_name(); + const char *brief_name = image_brief_type_name(); + assert(inst_name != nullptr); + assert(brief_name != nullptr); // count instances of the general image type, or device type if custom int count = 0; @@ -1151,19 +1150,21 @@ void device_image_interface::update_names() { if (this == &image) index = count; - const char *other_name = image.custom_instance_name(); - if (!other_name) - other_name = device_typename(image.image_type()); + const char *other_name = image.image_type_name(); + const char *other_brief_name = image.image_brief_type_name(); + assert(other_name != nullptr); + assert(other_brief_name != nullptr); - if (other_name == inst_name || !strcmp(other_name, inst_name)) + if (other_name == inst_name || !strcmp(other_name, inst_name) || + other_brief_name == brief_name || !strcmp(other_brief_name, brief_name)) count++; } - m_canonical_instance_name = string_format("%s%d", inst_name, index + 1); + m_canonical_instance_name = util::string_format("%s%d", inst_name, index + 1); if (count > 1) { m_instance_name = m_canonical_instance_name; - m_brief_instance_name = string_format("%s%d", brief_name, index + 1); + m_brief_instance_name = util::string_format("%s%d", brief_name, index + 1); } else { @@ -1256,7 +1257,7 @@ const software_list_loader &device_image_interface::get_software_list_loader() c // sw_info and sw_part are also set. //------------------------------------------------- -bool device_image_interface::load_software_part(std::string_view identifier) +std::error_condition device_image_interface::load_software_part(std::string_view identifier) { // if no match has been found, we suggest similar shortnames software_list_device *swlist; @@ -1264,14 +1265,14 @@ bool device_image_interface::load_software_part(std::string_view identifier) if (m_software_part_ptr == nullptr) { software_list_device::display_matches(device().machine().config(), image_interface(), identifier); - return false; + return image_error::NOSOFTWARE; } // Load the software part const std::string &swname = m_software_part_ptr->info().shortname(); const rom_entry *start_entry = m_software_part_ptr->romdata().data(); const software_list_loader &loader = get_software_list_loader(); - bool result = loader.load_software(*this, *swlist, swname, start_entry); + std::error_condition result = loader.load_software(*this, *swlist, swname, start_entry); // check compatibility switch (swlist->is_compatible(*m_software_part_ptr)) diff --git a/src/emu/diimage.h b/src/emu/diimage.h index 67d20c43..aa9c991c 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -17,11 +17,13 @@ #ifndef MAME_EMU_DIIMAGE_H #define MAME_EMU_DIIMAGE_H +#include "notifier.h" #include "utilfwd.h" #include #include #include +#include #include @@ -29,39 +31,15 @@ // TYPE DEFINITIONS //************************************************************************** -enum iodevice_t -{ - /* List of all supported devices. Refer to the device by these names only */ - IO_UNKNOWN, - IO_CARTSLOT, /* 1 - Cartridge Port, as found on most console and on some computers */ - IO_FLOPPY, /* 2 - Floppy Disk unit */ - IO_HARDDISK, /* 3 - Hard Disk unit */ - IO_CYLINDER, /* 4 - Magnetically-Coated Cylinder */ - IO_CASSETTE, /* 5 - Cassette Recorder (common on early home computers) */ - IO_PUNCHCARD, /* 6 - Card Puncher/Reader */ - IO_PUNCHTAPE, /* 7 - Tape Puncher/Reader (reels instead of punchcards) */ - IO_PRINTER, /* 8 - Printer device */ - IO_SERIAL, /* 9 - Generic Serial Port */ - IO_PARALLEL, /* 10 - Generic Parallel Port */ - IO_SNAPSHOT, /* 11 - Complete 'snapshot' of the state of the computer */ - IO_QUICKLOAD, /* 12 - Allow to load program/data into memory, without matching any actual device */ - IO_MEMCARD, /* 13 - Memory card */ - IO_CDROM, /* 14 - optical CD-ROM disc */ - IO_MAGTAPE, /* 15 - Magnetic tape */ - IO_ROM, /* 16 - Individual ROM image - the Amstrad CPC has a few applications that were sold on 16kB ROMs */ - IO_MIDIIN, /* 17 - MIDI In port */ - IO_MIDIOUT, /* 18 - MIDI Out port */ - IO_PICTURE, /* 19 - A single-frame image */ - IO_VIDEO, /* 20 - A video file */ - IO_COUNT /* 21 - Total Number of IO_devices for searching */ -}; - enum class image_error : int { INTERNAL = 1, UNSUPPORTED, INVALIDIMAGE, + INVALIDLENGTH, ALREADYOPEN, + NOSOFTWARE, + BADSOFTWARE, UNSPECIFIED }; @@ -69,13 +47,6 @@ const std::error_category &image_category() noexcept; inline std::error_condition make_error_condition(image_error e) noexcept { return std::error_condition(int(e), image_category()); } namespace std { template <> struct is_error_condition_enum : public std::true_type { }; } -struct image_device_type_info -{ - iodevice_t m_type; - const char *m_name; - const char *m_shortname; -}; - class image_device_format { public: @@ -95,66 +66,56 @@ class image_device_format }; -enum class image_init_result { PASS, FAIL }; -enum class image_verify_result { PASS, FAIL }; - -//************************************************************************** -// MACROS -//************************************************************************** - -#define DEVICE_IMAGE_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image) -#define DECLARE_DEVICE_IMAGE_LOAD_MEMBER(_name) DEVICE_IMAGE_LOAD_MEMBER(_name) - -#define DEVICE_IMAGE_UNLOAD_MEMBER(_name) void _name(device_image_interface &image) -#define DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(_name) DEVICE_IMAGE_UNLOAD_MEMBER(_name) - - // ======================> device_image_interface // class representing interface-specific live image class device_image_interface : public device_interface { public: - typedef device_delegate load_delegate; - typedef device_delegate unload_delegate; + enum class media_change_event + { + LOADED, + UNLOADED + }; - typedef std::vector> formatlist_type; + using formatlist_type = std::vector >; // construction/destruction device_image_interface(const machine_config &mconfig, device_t &device); virtual ~device_image_interface(); - static const char *device_typename(iodevice_t type); - static const char *device_brieftypename(iodevice_t type); - static iodevice_t device_typeid(const char *name); - - virtual image_init_result call_load() { return image_init_result::PASS; } - virtual image_init_result call_create(int format_type, util::option_resolution *format_options) { return image_init_result::PASS; } + virtual std::pair call_load() { return std::make_pair(std::error_condition(), std::string()); } + virtual std::pair call_create(int format_type, util::option_resolution *format_options) { return std::make_pair(std::error_condition(), std::string()); } virtual void call_unload() { } virtual std::string call_display() { return std::string(); } virtual u32 unhashed_header_length() const noexcept { return 0; } virtual bool core_opens_image_file() const noexcept { return true; } - virtual iodevice_t image_type() const noexcept = 0; + virtual bool image_is_chd_type() const noexcept { return false; } virtual bool is_readable() const noexcept = 0; virtual bool is_writeable() const noexcept = 0; virtual bool is_creatable() const noexcept = 0; - virtual bool must_be_loaded() const noexcept = 0; virtual bool is_reset_on_load() const noexcept = 0; - virtual bool support_command_line_image_creation() const noexcept; + virtual bool support_command_line_image_creation() const noexcept { return false; } virtual const char *image_interface() const noexcept { return nullptr; } virtual const char *file_extensions() const noexcept = 0; virtual const util::option_guide &create_option_guide() const; - virtual const char *custom_instance_name() const noexcept { return nullptr; } - virtual const char *custom_brief_instance_name() const noexcept { return nullptr; } + virtual const char *image_type_name() const noexcept = 0; + virtual const char *image_brief_type_name() const noexcept = 0; + + // Set block device image regions for arcade systems + void add_region(std::string name, bool is_default = false); + bool has_preset_images() const; + bool has_preset_images_selection() const; + std::vector preset_images_list() const; + int current_preset_image_id() const; + void switch_preset_image(int id); + chd_file *current_preset_image_chd() const; + void check_preset_images(); const image_device_format *device_get_indexed_creatable_format(int index) const noexcept { return (index < m_formatlist.size()) ? m_formatlist.at(index).get() : nullptr; } - const image_device_format *device_get_named_creatable_format(const std::string &format_name) noexcept; + const image_device_format *device_get_named_creatable_format(std::string_view format_name) const noexcept; const util::option_guide &device_get_creation_option_guide() const { return create_option_guide(); } - std::string_view error(); - void seterror(std::error_condition err, const char *message); - void message(const char *format, ...) ATTR_PRINTF(2,3); - bool exists() const noexcept { return !m_image_name.empty(); } // get image file path/name @@ -165,9 +126,15 @@ class device_image_interface : public device_interface bool is_filetype(std::string_view candidate_filetype) const; bool is_open() const noexcept { return bool(m_file); } - util::core_file &image_core_file() const noexcept { return *m_file; } + util::core_file &image_core_file() const noexcept { assert(is_open()); return *m_file; } bool is_readonly() const noexcept { return m_readonly; } + u32 sequence_counter() const { return m_sequence_counter; } // Increments on media load/unload/etc + util::notifier_subscription add_media_change_notifier(delegate &&n); + template + util::notifier_subscription add_media_change_notifier(T &&n) + { return add_media_change_notifier(delegate(std::forward(n))); } + // image file I/O wrappers // TODO: move away from using these and let implementations use the I/O interface directly // FIXME: don't swallow errors @@ -181,15 +148,13 @@ class device_image_interface : public device_interface u32 fread(void *buffer, u32 length) { check_for_file(); - size_t actual; - m_file->read(buffer, length, actual); + auto const [err, actual] = read(*m_file, buffer, length); return actual; } u32 fwrite(const void *buffer, u32 length) { check_for_file(); - size_t actual; - m_file->write(buffer, length, actual); + auto const [err, actual] = write(*m_file, buffer, length); return actual; } std::error_condition fseek(s64 offset, int whence) @@ -204,32 +169,6 @@ class device_image_interface : public device_interface m_file->tell(result); return result; } - int fgetc() - { - char ch; - if (fread(&ch, 1) != 1) - ch = '\0'; - return ch; - } - char *fgets(char *buffer, u32 length) - { - check_for_file(); - return m_file->gets(buffer, length); - } - bool image_feof() - { - check_for_file(); - return m_file->eof(); - } - const void *ptr() - { - check_for_file(); - return m_file->buffer(); - } - - // allocate and read into buffers - u32 fread(std::unique_ptr &ptr, u32 length) { ptr = std::make_unique(length); return fread(ptr.get(), length); } - u32 fread(std::unique_ptr &ptr, u32 length, offs_t offset) { ptr = std::make_unique(length); return fread(ptr.get() + offset, length - offset); } // access to software list item information const software_info *software_entry() const noexcept; @@ -243,67 +182,62 @@ class device_image_interface : public device_interface const std::string &working_directory() const { return m_working_directory; } // access to software list properties and ROM data areas - u8 *get_software_region(const char *tag); - u32 get_software_region_length(const char *tag); - const char *get_feature(const char *feature_name) const; - bool load_software_region(const char *tag, std::unique_ptr &ptr); + u8 *get_software_region(std::string_view tag); + u32 get_software_region_length(std::string_view tag); + const char *get_feature(std::string_view feature_name) const; + std::error_condition load_software_region(std::string_view tag, std::unique_ptr &ptr); u32 crc(); - util::hash_collection& hash() { return m_hash; } - util::hash_collection calculate_hash_on_file(util::core_file &file) const; + util::hash_collection &hash() { return m_hash; } + util::hash_collection calculate_hash_on_file(util::random_read &file) const; void battery_load(void *buffer, int length, int fill); void battery_load(void *buffer, int length, const void *def_buffer); void battery_save(const void *buffer, int length); - const char *image_type_name() const { return device_typename(image_type()); } - const std::string &instance_name() const { return m_instance_name; } const std::string &brief_instance_name() const { return m_brief_instance_name; } const std::string &canonical_instance_name() const { return m_canonical_instance_name; } - bool uses_file_extension(const char *file_extension) const; const formatlist_type &formatlist() const { return m_formatlist; } // loads an image file - image_init_result load(std::string_view path); + std::pair load(std::string_view path); // loads a softlist item by name - image_init_result load_software(std::string_view software_identifier); + std::pair load_software(std::string_view software_identifier); - image_init_result finish_load(); + std::pair finish_load(); void unload(); - image_init_result create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); - image_init_result create(std::string_view path); - bool load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); + std::pair create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); + std::pair create(std::string_view path); + std::error_condition load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); std::error_condition reopen_for_write(std::string_view path); - void set_user_loadable(bool user_loadable) { m_user_loadable = user_loadable; } + void set_user_loadable(bool user_loadable) noexcept { m_user_loadable = user_loadable; } + void set_must_be_loaded(bool must_be_loaded) noexcept { m_must_be_loaded = must_be_loaded; } bool user_loadable() const noexcept { return m_user_loadable; } + bool must_be_loaded() const noexcept { return m_must_be_loaded; } bool is_reset_and_loading() const noexcept { return m_is_reset_and_loading; } const std::string &full_software_name() const noexcept { return m_full_software_name; } protected: - // interface-level overrides + // device_interface implementation virtual void interface_config_complete() override; virtual const software_list_loader &get_software_list_loader() const; - virtual const bool use_software_list_file_extension_for_filetype() const { return false; } + virtual bool use_software_list_file_extension_for_filetype() const noexcept { return false; } - image_init_result load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); std::error_condition load_image_by_path(u32 open_flags, std::string_view path); - void clear(); - bool is_loaded() const { return m_file != nullptr; } + bool is_loaded() const noexcept { return m_file != nullptr; } - void set_image_filename(std::string_view filename); - - void clear_error(); + void set_image_tag(); void check_for_file() const { if (!m_file) throw emu_fatalerror("%s(%s): Illegal operation on unmounted image", device().shortname(), device().tag()); } void make_readonly() noexcept { m_readonly = true; } - bool image_checkhash(); + std::error_condition image_checkhash(); const software_part *find_software_item(std::string_view identifier, bool restrict_to_interface, software_list_device **device = nullptr) const; std::string software_get_default_slot(std::string_view default_card_slot) const; @@ -311,17 +245,21 @@ class device_image_interface : public device_interface void add_format(std::unique_ptr &&format); void add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec); - // derived class overrides +private: + std::vector determine_open_plan(bool is_create); + void update_names(); + void set_image_filename(std::string_view filename); + void clear() noexcept; + std::pair load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); + std::error_condition load_software_part(std::string_view identifier); - // configuration - static const image_device_type_info *find_device_type(iodevice_t type); - static const image_device_type_info m_device_info_array[]; + bool init_phase() const; + static std::error_condition run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); - // error related info - std::error_condition m_err; - std::string m_err_message; + // loads an image or software items and resets - called internally when we + // load an is_reset_on_load() item + void reset_and_load(std::string_view path); -private: // variables that are only non-zero when an image is mounted util::core_file::ptr m_file; std::unique_ptr m_mame_file; @@ -330,29 +268,27 @@ class device_image_interface : public device_interface std::string m_basename_noext; std::string m_filetype; + // preset images regions + std::vector m_possible_preset_regions; + std::vector m_preset_images; + int m_default_region, m_current_region; + // Software information std::string m_full_software_name; const software_part *m_software_part_ptr; std::string m_software_list_name; - std::vector determine_open_plan(bool is_create); - void update_names(); - bool load_software_part(std::string_view identifier); - - bool init_phase() const; - static bool run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); - - // loads an image or software items and resets - called internally when we - // load an is_reset_on_load() item - void reset_and_load(std::string_view path); - // creation info formatlist_type m_formatlist; // working directory; persists across mounts std::string m_working_directory; + // to notify interested parties when media changes + util::notifier m_media_change_notifier; + // flags + u32 m_sequence_counter; bool m_readonly; bool m_created; @@ -370,6 +306,8 @@ class device_image_interface : public device_interface // we want to disable command line cart loading... bool m_user_loadable; + bool m_must_be_loaded; + bool m_is_loading; bool m_is_reset_and_loading; @@ -378,4 +316,4 @@ class device_image_interface : public device_interface // iterator typedef device_interface_enumerator image_interface_enumerator; -#endif /* MAME_EMU_DIIMAGE_H */ +#endif // MAME_EMU_DIIMAGE_H From 125e0439f0b08be9862bbd686e64f6e1ec32029e Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:48:23 -0600 Subject: [PATCH 29/47] Revert updates. This reverts commit cf04e0fd88eee6248d728ac1da70626c1e5e79ec. --- src/emu/diimage.cpp | 677 ++++++++++++++++++++++---------------------- src/emu/diimage.h | 224 +++++++++------ 2 files changed, 481 insertions(+), 420 deletions(-) diff --git a/src/emu/diimage.cpp b/src/emu/diimage.cpp index 7ad94fb6..031ed46e 100644 --- a/src/emu/diimage.cpp +++ b/src/emu/diimage.cpp @@ -11,20 +11,49 @@ #include "emu.h" #include "emuopts.h" -#include "fileio.h" #include "romload.h" #include "softlist.h" #include "softlist_dev.h" +#include "ui/uimain.h" + #include "corestr.h" #include "opresolv.h" -#include "path.h" #include "zippath.h" #include +#include #include #include -#include + + +//************************************************************************** +// DEVICE CONFIG IMAGE INTERFACE +//************************************************************************** +const image_device_type_info device_image_interface::m_device_info_array[] = + { + { IO_UNKNOWN, "unknown", "unkn" }, /* 0 */ + { IO_CARTSLOT, "cartridge", "cart" }, /* 1 */ + { IO_FLOPPY, "floppydisk", "flop" }, /* 2 */ + { IO_HARDDISK, "harddisk", "hard" }, /* 3 */ + { IO_CYLINDER, "cylinder", "cyln" }, /* 4 */ + { IO_CASSETTE, "cassette", "cass" }, /* 5 */ + { IO_PUNCHCARD, "punchcard", "pcrd" }, /* 6 */ + { IO_PUNCHTAPE, "punchtape", "ptap" }, /* 7 */ + { IO_PRINTER, "printout", "prin" }, /* 8 */ + { IO_SERIAL, "serial", "serl" }, /* 9 */ + { IO_PARALLEL, "parallel", "parl" }, /* 10 */ + { IO_SNAPSHOT, "snapshot", "dump" }, /* 11 */ + { IO_QUICKLOAD, "quickload", "quik" }, /* 12 */ + { IO_MEMCARD, "memcard", "memc" }, /* 13 */ + { IO_CDROM, "cdrom", "cdrm" }, /* 14 */ + { IO_MAGTAPE, "magtape", "magt" }, /* 15 */ + { IO_ROM, "romimage", "rom" }, /* 16 */ + { IO_MIDIIN, "midiin", "min" }, /* 17 */ + { IO_MIDIOUT, "midiout", "mout" }, /* 18 */ + { IO_PICTURE, "picture", "pic" }, /* 19 */ + { IO_VIDEO, "vidfile", "vid" } /* 20 */ + }; //************************************************************************** @@ -65,18 +94,15 @@ image_device_format::~image_device_format() device_image_interface::device_image_interface(const machine_config &mconfig, device_t &device) : device_interface(device, "image") + , m_err() , m_file() , m_mame_file() - , m_default_region(-1) - , m_current_region(-1) , m_software_part_ptr(nullptr) - , m_sequence_counter(0) , m_readonly(false) , m_created(false) , m_create_format(0) , m_create_args(nullptr) , m_user_loadable(true) - , m_must_be_loaded(false) , m_is_loading(false) , m_is_reset_and_loading(false) { @@ -91,17 +117,6 @@ device_image_interface::~device_image_interface() { } -//------------------------------------------------- -// add_region - register a region that may -// have a chd image -//------------------------------------------------- -void device_image_interface::add_region(std::string name, bool is_default) -{ - if (is_default) - m_default_region = m_possible_preset_regions.size(); - m_possible_preset_regions.push_back(name); -} - //------------------------------------------------- // interface_config_complete - perform any @@ -115,143 +130,57 @@ void device_image_interface::interface_config_complete() update_names(); } + //------------------------------------------------- -// check_preset_images - lookup the CHDs from the -// region(s), if any +// find_device_type - search through list of +// device types to extract data //------------------------------------------------- -void device_image_interface::check_preset_images() +const image_device_type_info *device_image_interface::find_device_type(iodevice_t type) { - if (!m_possible_preset_regions.empty()) + for (const image_device_type_info &info : m_device_info_array) { - for(const auto &r : m_possible_preset_regions) - m_preset_images.push_back(device().machine().rom_load().get_disk_handle(":" + r)); - if (m_default_region != -1 && m_preset_images[m_default_region]) - m_current_region = m_default_region; - else - { - for (m_current_region = 0; m_current_region != int(m_preset_images.size()) && !m_preset_images[m_current_region]; m_current_region++); - if (m_current_region == int(m_preset_images.size())) - fatalerror("%s: No configured region has an image\n", device().tag()); - } - set_image_tag(); - set_user_loadable(false); + if (info.m_type == type) + return &info; } - else - { - std::string tag = device().owner()->tag(); - auto *const chd = device().machine().rom_load().get_disk_handle(tag); - if (chd) - { - m_possible_preset_regions.emplace_back(std::move(tag)); - m_preset_images.push_back(chd); - m_current_region = 0; - set_image_tag(); - set_user_loadable(false); - } - } -} - -//------------------------------------------------- -// has_preset_images - does the device have an -// image to retrieve through current_image_* -//------------------------------------------------- - -bool device_image_interface::has_preset_images() const -{ - return !m_possible_preset_regions.empty(); -} - -//------------------------------------------------- -// has_preset_images - does the device have -// multiple preset images with user selection -//------------------------------------------------- - -bool device_image_interface::has_preset_images_selection() const -{ - int icount = 0; - for (const auto *f : m_preset_images) - if (f) - icount ++; - return icount > 1; -} - - -//------------------------------------------------- -// preset_images_list -- generate the list of -// available image names -//------------------------------------------------- - -std::vector device_image_interface::preset_images_list() const -{ - std::vector result; - for (unsigned int i = 0; i != m_preset_images.size(); i++) - if (m_preset_images[i]) - result.push_back(m_possible_preset_regions[i]); - return result; + return nullptr; } //------------------------------------------------- -// current_preset_image_id -- current image id, -// recomputed to ignore non-present images. -// returns -1 if not in preset mode +// device_typename - retrieves device type name //------------------------------------------------- -int device_image_interface::current_preset_image_id() const +const char *device_image_interface::device_typename(iodevice_t type) { - if (m_current_region == -1) - return -1; - int id = 0; - for (int i = 0; i != m_current_region; i++) - if (m_preset_images[i]) - id++; - return id; + const image_device_type_info *info = find_device_type(type); + return (info != nullptr) ? info->m_name : "unknown"; } //------------------------------------------------- -// current_preset_image_chd -- return the chd of -// the current active image, nullptr if non +// device_brieftypename - retrieves device +// brief type name //------------------------------------------------- -chd_file *device_image_interface::current_preset_image_chd() const +const char *device_image_interface::device_brieftypename(iodevice_t type) { - if (m_current_region == -1) - return nullptr; - return m_preset_images[m_current_region]; + const image_device_type_info *info = find_device_type(type); + return (info != nullptr) ? info->m_shortname : "unk"; } //------------------------------------------------- -// switch_preset_image -- change of preset image +// device_typeid - retrieves device type id //------------------------------------------------- -void device_image_interface::switch_preset_image(int id) +iodevice_t device_image_interface::device_typeid(const char *name) { - for (unsigned i = 0; i != m_preset_images.size(); i++) + for (const image_device_type_info &info : m_device_info_array) { - if (m_preset_images[i]) - { - if (!id) - { - if (is_loaded() || loaded_through_softlist()) - { - call_unload(); - clear(); - m_media_change_notifier(media_change_event::UNLOADED); - } - m_current_region = i; - auto const err = call_load(); - if (!err.first) - m_media_change_notifier(media_change_event::LOADED); - break; - } - id--; - } + if (!core_stricmp(name, info.m_name) || !core_stricmp(name, info.m_shortname)) + return info.m_type; } - - return; + return (iodevice_t)-1; } - //------------------------------------------------- // set_image_filename - specifies the filename of // an image @@ -265,9 +194,9 @@ void device_image_interface::set_image_filename(std::string_view filename) // find the last "path separator" auto iter = std::find_if( - m_image_name.rbegin(), - m_image_name.rend(), - [] (char c) { return (c == '\\') || (c == '/') || (c == ':'); }); + m_image_name.rbegin(), + m_image_name.rend(), + [](char c) { return (c == '\\') || (c == '/') || (c == ':'); }); if (iter != m_image_name.rend()) m_basename.assign(iter.base(), m_image_name.end()); @@ -280,20 +209,6 @@ void device_image_interface::set_image_filename(std::string_view filename) m_filetype = core_filename_extract_extension(m_basename, true); } -//------------------------------------------------- -// set_image_tag - specifies the filename of -// an image as the device tag -//------------------------------------------------- - -void device_image_interface::set_image_tag() -{ - m_image_name = device().owner()->tag(); - m_working_directory = ""; - m_basename = ""; - m_basename_noext = ""; - m_filetype = ""; -} - //------------------------------------------------- // is_filetype - check if the filetype matches @@ -301,24 +216,14 @@ void device_image_interface::set_image_tag() bool device_image_interface::is_filetype(std::string_view candidate_filetype) const { - return util::streqlower(m_filetype, candidate_filetype); + return std::equal(m_filetype.begin(), m_filetype.end(), candidate_filetype.begin(), candidate_filetype.end(), + [] (unsigned char c1, unsigned char c2) { return std::tolower(c1) == c2; }); } -//------------------------------------------------- -// add_media_change_notifier - subscribe for -// media change notifications -//------------------------------------------------- - -util::notifier_subscription device_image_interface::add_media_change_notifier(delegate &&n) -{ - return m_media_change_notifier.subscribe(std::move(n)); -} - - -//*************************************************************************** -// CREATION FORMATS -//*************************************************************************** +/**************************************************************************** + CREATION FORMATS +****************************************************************************/ //------------------------------------------------- // device_get_named_creatable_format - @@ -326,10 +231,10 @@ util::notifier_subscription device_image_interface::add_media_change_notifier(de // image creation by name //------------------------------------------------- -const image_device_format *device_image_interface::device_get_named_creatable_format(std::string_view format_name) const noexcept +const image_device_format *device_image_interface::device_get_named_creatable_format(const std::string &format_name) noexcept { - for (const auto &format : m_formatlist) - if (std::string_view(format->name()) == format_name) + for (auto &format : m_formatlist) + if (format->name() == format_name) return format.get(); return nullptr; } @@ -356,9 +261,22 @@ void device_image_interface::add_format(std::string &&name, std::string &&descri } -//*************************************************************************** -// ERROR HANDLING -//*************************************************************************** +/**************************************************************************** + ERROR HANDLING +****************************************************************************/ + +//------------------------------------------------- +// image_clear_error - clear out any specified +// error +//------------------------------------------------- + +void device_image_interface::clear_error() +{ + m_err.clear(); + m_err_message.clear(); +} + + //------------------------------------------------- // error - returns the error text for an image @@ -380,10 +298,7 @@ std::error_category const &image_category() noexcept "Internal error"sv, "Unsupported operation"sv, "Invalid image"sv, - "Invalid image length"sv, "File already open"sv, - "Unrecognized software item"sv, - "Invalid software item"sv, "Unspecified error"sv }; if ((0 <= condition) && (std::size(s_messages) > condition)) return std::string(s_messages[condition]); @@ -395,6 +310,50 @@ std::error_category const &image_category() noexcept return s_image_category_instance; } +std::string_view device_image_interface::error() +{ + if (m_err && m_err_message.empty()) + m_err_message = m_err.message(); + return m_err_message; +} + + + +//------------------------------------------------- +// seterror - specifies an error on an image +//------------------------------------------------- + +void device_image_interface::seterror(std::error_condition err, const char *message) +{ + clear_error(); + m_err = err; + if (message) + m_err_message = message; +} + + + +//------------------------------------------------- +// message - used to display a message while +// loading +//------------------------------------------------- + +void device_image_interface::message(const char *format, ...) +{ + va_list args; + char buffer[256]; + + /* format the message */ + va_start(args, format); + vsnprintf(buffer, std::size(buffer), format, args); + va_end(args); + + /* display the popup for a standard amount of time */ + device().machine().ui().popup_time(5, "%s: %s", + basename(), + buffer); +} + //------------------------------------------------- // software_entry - return a pointer to the @@ -411,13 +370,14 @@ const software_info *device_image_interface::software_entry() const noexcept // get_software_region //------------------------------------------------- -u8 *device_image_interface::get_software_region(std::string_view tag) +u8 *device_image_interface::get_software_region(const char *tag) { if (!loaded_through_softlist()) return nullptr; - memory_region *const region = device().memregion(tag); - return region ? region->base() : nullptr; + std::string full_tag = util::string_format("%s:%s", device().tag(), tag); + memory_region *region = device().machine().root_device().memregion(full_tag); + return region != nullptr ? region->base() : nullptr; } @@ -425,13 +385,11 @@ u8 *device_image_interface::get_software_region(std::string_view tag) // image_get_software_region_length //------------------------------------------------- -u32 device_image_interface::get_software_region_length(std::string_view tag) +u32 device_image_interface::get_software_region_length(const char *tag) { - if (!loaded_through_softlist()) - return 0; - - memory_region *const region = device().memregion(tag); - return region ? region->bytes() : 0; + std::string full_tag = util::string_format("%s:%s", device().tag(), tag); + memory_region *region = device().machine().root_device().memregion(full_tag); + return region != nullptr ? region->bytes() : 0; } @@ -439,7 +397,7 @@ u32 device_image_interface::get_software_region_length(std::string_view tag) // image_get_feature //------------------------------------------------- -const char *device_image_interface::get_feature(std::string_view feature_name) const +const char *device_image_interface::get_feature(const char *feature_name) const { return !m_software_part_ptr ? nullptr : m_software_part_ptr->feature(feature_name); } @@ -449,7 +407,7 @@ const char *device_image_interface::get_feature(std::string_view feature_name) c // load_software_region - //------------------------------------------------- -std::error_condition device_image_interface::load_software_region(std::string_view tag, std::unique_ptr &ptr) +bool device_image_interface::load_software_region(const char *tag, std::unique_ptr &ptr) { size_t size = get_software_region_length(tag); @@ -457,10 +415,9 @@ std::error_condition device_image_interface::load_software_region(std::string_vi { ptr = std::make_unique(size); memcpy(ptr.get(), get_software_region(tag), size); - return std::error_condition(); } - else - return image_error::UNSUPPORTED; + + return size > 0; } @@ -471,61 +428,75 @@ std::error_condition device_image_interface::load_software_region(std::string_vi // to be loaded // **************************************************************************** -std::error_condition device_image_interface::run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) +bool device_image_interface::run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types) { // reset the hash; we want to override existing data hashes.reset(); // figure out the size, and "cap" the skip bytes u64 size; - std::error_condition filerr = file.length(size); - if (filerr) - return filerr; + if (file.length(size)) + return false; skip_bytes = u32(std::min(skip_bytes, size)); - // and compute the hashes - size_t actual_count; - filerr = hashes.compute(file, skip_bytes, size - skip_bytes, actual_count, types); - if (filerr) - return filerr; + // seek to the beginning + file.seek(skip_bytes, SEEK_SET); // TODO: check error return + u64 position = skip_bytes; - return std::error_condition(); + // keep on reading hashes + hashes.begin(types); + while (position < size) + { + uint8_t buffer[8192]; + + // read bytes + const size_t count = size_t(std::min(size - position, sizeof(buffer))); + size_t actual_count; + const std::error_condition filerr = file.read(buffer, count, actual_count); + if (filerr || !actual_count) + return false; + position += actual_count; + + // and compute the hashes + hashes.buffer(buffer, actual_count); + } + hashes.end(); + + // cleanup + file.seek(0, SEEK_SET); // TODO: check error return + return true; } -std::error_condition device_image_interface::image_checkhash() +bool device_image_interface::image_checkhash() { // only calculate CRC if it hasn't been calculated, and the open_mode is read only u32 crcval; if (!m_hash.crc(crcval) && is_readonly() && !m_created) { -#ifdef __LIBRETRO__ - // because 'image_is_chd_type()' below does not actually work - if (core_filename_ends_with(m_image_name.c_str(), "chd")) - return std::error_condition(); -#endif // do not cause a linear read of 600 megs please // TODO: use SHA1 in the CHD header as the hash - if (image_is_chd_type()) - return std::error_condition(); + if (image_type() == IO_CDROM) + return true; // Skip calculating the hash when we have an image mounted through a software list if (loaded_through_softlist()) - return std::error_condition(); + return true; // run the hash - return run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL); + if (!run_hash(*m_file, unhashed_header_length(), m_hash, util::hash_collection::HASH_TYPES_ALL)) + return false; } - return std::error_condition(); + return true; } -util::hash_collection device_image_interface::calculate_hash_on_file(util::random_read &file) const +util::hash_collection device_image_interface::calculate_hash_on_file(util::core_file &file) const { // calculate the hash util::hash_collection hash; - if (run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) + if (!run_hash(file, unhashed_header_length(), hash, util::hash_collection::HASH_TYPES_ALL)) hash.reset(); return hash; } @@ -543,6 +514,33 @@ u32 device_image_interface::crc() } +//------------------------------------------------- +// support_command_line_image_creation - do we +// want to support image creation from the front +// end command line? +//------------------------------------------------- + +bool device_image_interface::support_command_line_image_creation() const noexcept +{ + bool result; + switch (image_type()) + { + case IO_PRINTER: + case IO_SERIAL: + case IO_PARALLEL: + // going by the assumption that these device image types should support this + // behavior; ideally we'd get rid of IO_* and just push this to the specific + // devices + result = true; + break; + default: + result = false; + break; + } + return result; +} + + // **************************************************************************** // Battery functions // @@ -621,6 +619,34 @@ void device_image_interface::battery_save(const void *buffer, int length) } +//------------------------------------------------- +// uses_file_extension - update configuration +// based on completed device setup +//------------------------------------------------- + +bool device_image_interface::uses_file_extension(const char *file_extension) const +{ + bool result = false; + + if (file_extension[0] == '.') + file_extension++; + + /* find the extensions */ + std::string extensions(file_extensions()); + char *ext = strtok((char*)extensions.c_str(),","); + while (ext != nullptr) + { + if (!core_stricmp(ext, file_extension)) + { + result = true; + break; + } + ext = strtok (nullptr, ","); + } + return result; +} + + // *************************************************************************** // IMAGE LOADING // *************************************************************************** @@ -686,20 +712,15 @@ std::vector device_image_interface::determine_open_plan(bool is_create) { std::vector open_plan; - if (!is_create) - { - if (is_writeable()) - open_plan.push_back(is_readable() ? (OPEN_FLAG_READ | OPEN_FLAG_WRITE) : OPEN_FLAG_WRITE); - if (is_readable()) - open_plan.push_back(OPEN_FLAG_READ); - } - else if (is_writeable() && is_creatable()) - { - if (is_readable()) - open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - else - open_plan.push_back(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); - } + // emit flags into a vector + if (!is_create && is_readable() && is_writeable()) + open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE); + if (!is_create && !is_readable() && is_writeable()) + open_plan.push_back(OPEN_FLAG_WRITE); + if (!is_create && is_readable()) + open_plan.push_back(OPEN_FLAG_READ); + if (is_create && is_writeable() && is_creatable()) + open_plan.push_back(OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE); return open_plan; } @@ -751,9 +772,9 @@ static int verify_length_and_hash(emu_file *file, std::string_view name, u32 exp // load_software - software image loading //------------------------------------------------- -std::error_condition device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) +bool device_image_interface::load_software(software_list_device &swlist, std::string_view swname, const rom_entry *start) { - std::error_condition retval; + bool retval = false; int warningcount = 0; for (const rom_entry *region = start; region; region = rom_next_region(region)) { @@ -765,7 +786,7 @@ std::error_condition device_image_interface::load_software(software_list_device { const software_info *const swinfo = swlist.find(std::string(swname)); if (!swinfo) - return image_error::NOSOFTWARE; + return false; if (swinfo->supported() == software_support::PARTIALLY_SUPPORTED) osd_printf_error("WARNING: support for software %s (in list %s) is only partial\n", swname, swlist.list_name()); @@ -795,31 +816,14 @@ std::error_condition device_image_interface::load_software(software_list_device else filerr = m_mame_file->open(romp->name()); if (filerr) - { m_mame_file.reset(); - std::ostringstream msg; - util::stream_format(msg, - "%s: error opening image file %s: %s (%s:%d)", - device().tag(), romp->name(), - filerr.message(), - filerr.category().name(), - filerr.value()); - if (!searchpath.empty()) - { - msg << " (tried in"; - for (auto const &path : searchpath) - msg << ' ' << path; - msg << ')'; - } - osd_printf_error("%s\n", std::move(msg).str()); - } warningcount += verify_length_and_hash(m_mame_file.get(), romp->name(), romp->get_length(), util::hash_collection(romp->hashdata())); if (!filerr) filerr = util::core_file::open_proxy(*m_mame_file, m_file); - if (filerr) - retval = filerr; + if (!filerr) + retval = true; break; // load first item for start } @@ -837,16 +841,16 @@ std::error_condition device_image_interface::load_software(software_list_device // load_internal - core image loading //------------------------------------------------- -std::pair device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) +image_init_result device_image_interface::load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args) { - std::pair err; - // first unload the image unload(); + // clear any possible error messages + clear_error(); + // we are now loading m_is_loading = true; - m_sequence_counter++; // record the filename set_image_filename(path); @@ -854,47 +858,50 @@ std::pair device_image_interface::load_intern if (core_opens_image_file()) { // determine open plan - std::vector const open_plan = determine_open_plan(is_create); + std::vector open_plan = determine_open_plan(is_create); // attempt to open the file in various ways for (auto iter = open_plan.cbegin(); !m_file && iter != open_plan.cend(); iter++) { // open the file - err.first = load_image_by_path(*iter, path); - if (err.first && (err.first != std::errc::no_such_file_or_directory) && (err.first != std::errc::permission_denied)) - break; + m_err = load_image_by_path(*iter, path); + if (m_err && (m_err != std::errc::no_such_file_or_directory) && (m_err != std::errc::permission_denied)) + goto done; } // did we fail to find the file? - if (!err.first && !m_file) - err.first = std::errc::no_such_file_or_directory; + if (!m_file) + { + m_err = std::errc::no_such_file_or_directory; + goto done; + } } - if (!err.first) - { - // call device load or create - m_create_format = create_format; - m_create_args = create_args; + // call device load or create + m_create_format = create_format; + m_create_args = create_args; - if (!init_phase()) - err = finish_load(); + if (!init_phase()) + { + m_err = (finish_load() == image_init_result::PASS) ? std::error_condition() : image_error::INTERNAL; + if (m_err) + goto done; } + // success! - if (err.first) +done: + if (m_err) { - osd_printf_error( - !err.second.empty() - ? (is_create ? "Unable to create image '%1$s': %2$s (%3$s:%4$d %5$s)\n" : "Unable to load image '%1$s': %2$s (%3$s:%4$d %5$s)\n") - : (is_create ? "Unable to create image '%1$s': %5$s (%3$s:%4$d)\n" : "Unable to load image '%1$s': %5$s (%3$s:%4$d)\n"), - path, - err.second, - err.first.category().name(), - err.first.value(), - err.first.message()); + if (!init_phase()) + { + if (device().machine().phase() == machine_phase::RUNNING) + device().popmessage("Error: Unable to %s image '%s': %s", is_create ? "create" : "load", path, error()); + else + osd_printf_error("Error: Unable to %s image '%s': %s\n", is_create ? "create" : "load", path, error()); + } clear(); } - - return err; + return m_err ? image_init_result::FAIL : image_init_result::PASS; } @@ -902,13 +909,13 @@ std::pair device_image_interface::load_intern // load - load an image into MAME //------------------------------------------------- -std::pair device_image_interface::load(std::string_view path) +image_init_result device_image_interface::load(std::string_view path) { // is this a reset on load item? if (is_reset_on_load() && !init_phase()) { reset_and_load(path); - return std::make_pair(std::error_condition(), std::string()); + return image_init_result::PASS; } return load_internal(path, false, 0, nullptr); @@ -919,26 +926,26 @@ std::pair device_image_interface::load(std::s // load_software - loads a softlist item by name //------------------------------------------------- -std::pair device_image_interface::load_software(std::string_view software_identifier) +image_init_result device_image_interface::load_software(std::string_view software_identifier) { // Is this a software part that forces a reset and we're at runtime? If so, get this loaded through reset_and_load if (is_reset_on_load() && !init_phase()) { reset_and_load(software_identifier); - return std::make_pair(std::error_condition(), std::string()); + return image_init_result::PASS; } // Prepare to load unload(); + clear_error(); m_is_loading = true; // Check if there's a software list defined for this device and use that if we're not creating an image - std::pair err; - err.first = load_software_part(software_identifier); - if (err.first) + bool softload = load_software_part(software_identifier); + if (!softload) { m_is_loading = false; - return err; + return image_init_result::FAIL; } // set up softlist stuff @@ -948,10 +955,9 @@ std::pair device_image_interface::load_softwa m_image_name = m_full_software_name; m_basename = m_full_software_name; m_basename_noext = m_full_software_name; - if (use_software_list_file_extension_for_filetype() && m_mame_file) - m_filetype = core_filename_extract_extension(m_mame_file->filename(), true); - else - m_filetype.clear(); + m_filetype = use_software_list_file_extension_for_filetype() && m_mame_file != nullptr + ? std::string(core_filename_extract_extension(m_mame_file->filename(), true)) + : ""; // Copy some image information when we have been loaded through a software list software_info &swinfo = m_software_part_ptr->info(); @@ -961,31 +967,16 @@ std::pair device_image_interface::load_softwa fatalerror("Each entry in an XML list must have all of the following fields: description, publisher, year!\n"); // set file type - std::string filename = (m_mame_file && m_mame_file->filename()) + std::string filename = (m_mame_file != nullptr) && (m_mame_file->filename() != nullptr) ? m_mame_file->filename() : ""; m_filetype = core_filename_extract_extension(filename, true); // call finish_load if necessary - if (!init_phase()) - { - err = finish_load(); - if (err.first) - { - osd_printf_error( - !err.second.empty() - ? "Unable to load software item '%1$s': %2$s (%3$s:%4$d %5$s)\n" - : "Unable to load software item '%1$s': %5$s (%3$s:%4$d)\n", - software_identifier, - err.second, - err.first.category().name(), - err.first.value(), - err.first.message()); - clear(); - } - } + if (init_phase() == false && (finish_load() != image_init_result::PASS)) + return image_init_result::FAIL; - return err; + return image_init_result::PASS; } @@ -994,38 +985,53 @@ std::pair device_image_interface::load_softwa // from core //------------------------------------------------- -std::pair device_image_interface::finish_load() +image_init_result device_image_interface::finish_load() { - std::pair err; + image_init_result err = image_init_result::PASS; if (m_is_loading) { - err.first = image_checkhash(); + if (!image_checkhash()) + { + m_err = image_error::INVALIDIMAGE; + err = image_init_result::FAIL; + } - if (!err.first) + if (err == image_init_result::PASS) { if (m_created) + { err = call_create(m_create_format, m_create_args); + if (err != image_init_result::PASS) + { + if (!m_err) + m_err = image_error::UNSPECIFIED; + } + } else - err = call_load(); // using device load + { + // using device load + err = call_load(); + if (err != image_init_result::PASS) + { + if (!m_err) + m_err = image_error::UNSPECIFIED; + } + } } } - m_is_loading = false; m_create_format = 0; m_create_args = nullptr; - if (!err.first) - m_media_change_notifier(media_change_event::LOADED); - return err; } //------------------------------------------------- -// create - create an image +// create - create a image //------------------------------------------------- -std::pair device_image_interface::create(std::string_view path) +image_init_result device_image_interface::create(std::string_view path) { return create(path, nullptr, nullptr); } @@ -1035,14 +1041,13 @@ std::pair device_image_interface::create(std: // create - create a image //------------------------------------------------- -std::pair device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) +image_init_result device_image_interface::create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args) { int format_index = 0; int cnt = 0; for (auto &format : m_formatlist) { - if (create_format == format.get()) - { + if (create_format == format.get()) { format_index = cnt; break; } @@ -1076,7 +1081,7 @@ void device_image_interface::reset_and_load(std::string_view path) // to an image //------------------------------------------------- -void device_image_interface::clear() noexcept +void device_image_interface::clear() { m_mame_file.reset(); m_file.reset(); @@ -1096,8 +1101,6 @@ void device_image_interface::clear() noexcept m_software_list_name.clear(); m_hash.reset(); - - m_sequence_counter++; } @@ -1110,13 +1113,9 @@ void device_image_interface::unload() if (is_loaded() || loaded_through_softlist()) { call_unload(); - clear(); - m_media_change_notifier(media_change_event::UNLOADED); - } - else - { - clear(); // just to make sure everything is reset } + clear(); + clear_error(); } @@ -1138,10 +1137,12 @@ const util::option_guide &device_image_interface::create_option_guide() const void device_image_interface::update_names() { - const char *inst_name = image_type_name(); - const char *brief_name = image_brief_type_name(); - assert(inst_name != nullptr); - assert(brief_name != nullptr); + const char *inst_name = custom_instance_name(); + const char *brief_name = custom_brief_instance_name(); + if (inst_name == nullptr) + inst_name = device_typename(image_type()); + if (brief_name == nullptr) + brief_name = device_brieftypename(image_type()); // count instances of the general image type, or device type if custom int count = 0; @@ -1150,21 +1151,19 @@ void device_image_interface::update_names() { if (this == &image) index = count; - const char *other_name = image.image_type_name(); - const char *other_brief_name = image.image_brief_type_name(); - assert(other_name != nullptr); - assert(other_brief_name != nullptr); + const char *other_name = image.custom_instance_name(); + if (!other_name) + other_name = device_typename(image.image_type()); - if (other_name == inst_name || !strcmp(other_name, inst_name) || - other_brief_name == brief_name || !strcmp(other_brief_name, brief_name)) + if (other_name == inst_name || !strcmp(other_name, inst_name)) count++; } - m_canonical_instance_name = util::string_format("%s%d", inst_name, index + 1); + m_canonical_instance_name = string_format("%s%d", inst_name, index + 1); if (count > 1) { m_instance_name = m_canonical_instance_name; - m_brief_instance_name = util::string_format("%s%d", brief_name, index + 1); + m_brief_instance_name = string_format("%s%d", brief_name, index + 1); } else { @@ -1257,7 +1256,7 @@ const software_list_loader &device_image_interface::get_software_list_loader() c // sw_info and sw_part are also set. //------------------------------------------------- -std::error_condition device_image_interface::load_software_part(std::string_view identifier) +bool device_image_interface::load_software_part(std::string_view identifier) { // if no match has been found, we suggest similar shortnames software_list_device *swlist; @@ -1265,14 +1264,14 @@ std::error_condition device_image_interface::load_software_part(std::string_view if (m_software_part_ptr == nullptr) { software_list_device::display_matches(device().machine().config(), image_interface(), identifier); - return image_error::NOSOFTWARE; + return false; } // Load the software part const std::string &swname = m_software_part_ptr->info().shortname(); const rom_entry *start_entry = m_software_part_ptr->romdata().data(); const software_list_loader &loader = get_software_list_loader(); - std::error_condition result = loader.load_software(*this, *swlist, swname, start_entry); + bool result = loader.load_software(*this, *swlist, swname, start_entry); // check compatibility switch (swlist->is_compatible(*m_software_part_ptr)) diff --git a/src/emu/diimage.h b/src/emu/diimage.h index aa9c991c..67d20c43 100644 --- a/src/emu/diimage.h +++ b/src/emu/diimage.h @@ -17,13 +17,11 @@ #ifndef MAME_EMU_DIIMAGE_H #define MAME_EMU_DIIMAGE_H -#include "notifier.h" #include "utilfwd.h" #include #include #include -#include #include @@ -31,15 +29,39 @@ // TYPE DEFINITIONS //************************************************************************** +enum iodevice_t +{ + /* List of all supported devices. Refer to the device by these names only */ + IO_UNKNOWN, + IO_CARTSLOT, /* 1 - Cartridge Port, as found on most console and on some computers */ + IO_FLOPPY, /* 2 - Floppy Disk unit */ + IO_HARDDISK, /* 3 - Hard Disk unit */ + IO_CYLINDER, /* 4 - Magnetically-Coated Cylinder */ + IO_CASSETTE, /* 5 - Cassette Recorder (common on early home computers) */ + IO_PUNCHCARD, /* 6 - Card Puncher/Reader */ + IO_PUNCHTAPE, /* 7 - Tape Puncher/Reader (reels instead of punchcards) */ + IO_PRINTER, /* 8 - Printer device */ + IO_SERIAL, /* 9 - Generic Serial Port */ + IO_PARALLEL, /* 10 - Generic Parallel Port */ + IO_SNAPSHOT, /* 11 - Complete 'snapshot' of the state of the computer */ + IO_QUICKLOAD, /* 12 - Allow to load program/data into memory, without matching any actual device */ + IO_MEMCARD, /* 13 - Memory card */ + IO_CDROM, /* 14 - optical CD-ROM disc */ + IO_MAGTAPE, /* 15 - Magnetic tape */ + IO_ROM, /* 16 - Individual ROM image - the Amstrad CPC has a few applications that were sold on 16kB ROMs */ + IO_MIDIIN, /* 17 - MIDI In port */ + IO_MIDIOUT, /* 18 - MIDI Out port */ + IO_PICTURE, /* 19 - A single-frame image */ + IO_VIDEO, /* 20 - A video file */ + IO_COUNT /* 21 - Total Number of IO_devices for searching */ +}; + enum class image_error : int { INTERNAL = 1, UNSUPPORTED, INVALIDIMAGE, - INVALIDLENGTH, ALREADYOPEN, - NOSOFTWARE, - BADSOFTWARE, UNSPECIFIED }; @@ -47,6 +69,13 @@ const std::error_category &image_category() noexcept; inline std::error_condition make_error_condition(image_error e) noexcept { return std::error_condition(int(e), image_category()); } namespace std { template <> struct is_error_condition_enum : public std::true_type { }; } +struct image_device_type_info +{ + iodevice_t m_type; + const char *m_name; + const char *m_shortname; +}; + class image_device_format { public: @@ -66,56 +95,66 @@ class image_device_format }; +enum class image_init_result { PASS, FAIL }; +enum class image_verify_result { PASS, FAIL }; + +//************************************************************************** +// MACROS +//************************************************************************** + +#define DEVICE_IMAGE_LOAD_MEMBER(_name) image_init_result _name(device_image_interface &image) +#define DECLARE_DEVICE_IMAGE_LOAD_MEMBER(_name) DEVICE_IMAGE_LOAD_MEMBER(_name) + +#define DEVICE_IMAGE_UNLOAD_MEMBER(_name) void _name(device_image_interface &image) +#define DECLARE_DEVICE_IMAGE_UNLOAD_MEMBER(_name) DEVICE_IMAGE_UNLOAD_MEMBER(_name) + + // ======================> device_image_interface // class representing interface-specific live image class device_image_interface : public device_interface { public: - enum class media_change_event - { - LOADED, - UNLOADED - }; + typedef device_delegate load_delegate; + typedef device_delegate unload_delegate; - using formatlist_type = std::vector >; + typedef std::vector> formatlist_type; // construction/destruction device_image_interface(const machine_config &mconfig, device_t &device); virtual ~device_image_interface(); - virtual std::pair call_load() { return std::make_pair(std::error_condition(), std::string()); } - virtual std::pair call_create(int format_type, util::option_resolution *format_options) { return std::make_pair(std::error_condition(), std::string()); } + static const char *device_typename(iodevice_t type); + static const char *device_brieftypename(iodevice_t type); + static iodevice_t device_typeid(const char *name); + + virtual image_init_result call_load() { return image_init_result::PASS; } + virtual image_init_result call_create(int format_type, util::option_resolution *format_options) { return image_init_result::PASS; } virtual void call_unload() { } virtual std::string call_display() { return std::string(); } virtual u32 unhashed_header_length() const noexcept { return 0; } virtual bool core_opens_image_file() const noexcept { return true; } - virtual bool image_is_chd_type() const noexcept { return false; } + virtual iodevice_t image_type() const noexcept = 0; virtual bool is_readable() const noexcept = 0; virtual bool is_writeable() const noexcept = 0; virtual bool is_creatable() const noexcept = 0; + virtual bool must_be_loaded() const noexcept = 0; virtual bool is_reset_on_load() const noexcept = 0; - virtual bool support_command_line_image_creation() const noexcept { return false; } + virtual bool support_command_line_image_creation() const noexcept; virtual const char *image_interface() const noexcept { return nullptr; } virtual const char *file_extensions() const noexcept = 0; virtual const util::option_guide &create_option_guide() const; - virtual const char *image_type_name() const noexcept = 0; - virtual const char *image_brief_type_name() const noexcept = 0; - - // Set block device image regions for arcade systems - void add_region(std::string name, bool is_default = false); - bool has_preset_images() const; - bool has_preset_images_selection() const; - std::vector preset_images_list() const; - int current_preset_image_id() const; - void switch_preset_image(int id); - chd_file *current_preset_image_chd() const; - void check_preset_images(); + virtual const char *custom_instance_name() const noexcept { return nullptr; } + virtual const char *custom_brief_instance_name() const noexcept { return nullptr; } const image_device_format *device_get_indexed_creatable_format(int index) const noexcept { return (index < m_formatlist.size()) ? m_formatlist.at(index).get() : nullptr; } - const image_device_format *device_get_named_creatable_format(std::string_view format_name) const noexcept; + const image_device_format *device_get_named_creatable_format(const std::string &format_name) noexcept; const util::option_guide &device_get_creation_option_guide() const { return create_option_guide(); } + std::string_view error(); + void seterror(std::error_condition err, const char *message); + void message(const char *format, ...) ATTR_PRINTF(2,3); + bool exists() const noexcept { return !m_image_name.empty(); } // get image file path/name @@ -126,15 +165,9 @@ class device_image_interface : public device_interface bool is_filetype(std::string_view candidate_filetype) const; bool is_open() const noexcept { return bool(m_file); } - util::core_file &image_core_file() const noexcept { assert(is_open()); return *m_file; } + util::core_file &image_core_file() const noexcept { return *m_file; } bool is_readonly() const noexcept { return m_readonly; } - u32 sequence_counter() const { return m_sequence_counter; } // Increments on media load/unload/etc - util::notifier_subscription add_media_change_notifier(delegate &&n); - template - util::notifier_subscription add_media_change_notifier(T &&n) - { return add_media_change_notifier(delegate(std::forward(n))); } - // image file I/O wrappers // TODO: move away from using these and let implementations use the I/O interface directly // FIXME: don't swallow errors @@ -148,13 +181,15 @@ class device_image_interface : public device_interface u32 fread(void *buffer, u32 length) { check_for_file(); - auto const [err, actual] = read(*m_file, buffer, length); + size_t actual; + m_file->read(buffer, length, actual); return actual; } u32 fwrite(const void *buffer, u32 length) { check_for_file(); - auto const [err, actual] = write(*m_file, buffer, length); + size_t actual; + m_file->write(buffer, length, actual); return actual; } std::error_condition fseek(s64 offset, int whence) @@ -169,6 +204,32 @@ class device_image_interface : public device_interface m_file->tell(result); return result; } + int fgetc() + { + char ch; + if (fread(&ch, 1) != 1) + ch = '\0'; + return ch; + } + char *fgets(char *buffer, u32 length) + { + check_for_file(); + return m_file->gets(buffer, length); + } + bool image_feof() + { + check_for_file(); + return m_file->eof(); + } + const void *ptr() + { + check_for_file(); + return m_file->buffer(); + } + + // allocate and read into buffers + u32 fread(std::unique_ptr &ptr, u32 length) { ptr = std::make_unique(length); return fread(ptr.get(), length); } + u32 fread(std::unique_ptr &ptr, u32 length, offs_t offset) { ptr = std::make_unique(length); return fread(ptr.get() + offset, length - offset); } // access to software list item information const software_info *software_entry() const noexcept; @@ -182,62 +243,67 @@ class device_image_interface : public device_interface const std::string &working_directory() const { return m_working_directory; } // access to software list properties and ROM data areas - u8 *get_software_region(std::string_view tag); - u32 get_software_region_length(std::string_view tag); - const char *get_feature(std::string_view feature_name) const; - std::error_condition load_software_region(std::string_view tag, std::unique_ptr &ptr); + u8 *get_software_region(const char *tag); + u32 get_software_region_length(const char *tag); + const char *get_feature(const char *feature_name) const; + bool load_software_region(const char *tag, std::unique_ptr &ptr); u32 crc(); - util::hash_collection &hash() { return m_hash; } - util::hash_collection calculate_hash_on_file(util::random_read &file) const; + util::hash_collection& hash() { return m_hash; } + util::hash_collection calculate_hash_on_file(util::core_file &file) const; void battery_load(void *buffer, int length, int fill); void battery_load(void *buffer, int length, const void *def_buffer); void battery_save(const void *buffer, int length); + const char *image_type_name() const { return device_typename(image_type()); } + const std::string &instance_name() const { return m_instance_name; } const std::string &brief_instance_name() const { return m_brief_instance_name; } const std::string &canonical_instance_name() const { return m_canonical_instance_name; } + bool uses_file_extension(const char *file_extension) const; const formatlist_type &formatlist() const { return m_formatlist; } // loads an image file - std::pair load(std::string_view path); + image_init_result load(std::string_view path); // loads a softlist item by name - std::pair load_software(std::string_view software_identifier); + image_init_result load_software(std::string_view software_identifier); - std::pair finish_load(); + image_init_result finish_load(); void unload(); - std::pair create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); - std::pair create(std::string_view path); - std::error_condition load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); + image_init_result create(std::string_view path, const image_device_format *create_format, util::option_resolution *create_args); + image_init_result create(std::string_view path); + bool load_software(software_list_device &swlist, std::string_view swname, const rom_entry *entry); std::error_condition reopen_for_write(std::string_view path); - void set_user_loadable(bool user_loadable) noexcept { m_user_loadable = user_loadable; } - void set_must_be_loaded(bool must_be_loaded) noexcept { m_must_be_loaded = must_be_loaded; } + void set_user_loadable(bool user_loadable) { m_user_loadable = user_loadable; } bool user_loadable() const noexcept { return m_user_loadable; } - bool must_be_loaded() const noexcept { return m_must_be_loaded; } bool is_reset_and_loading() const noexcept { return m_is_reset_and_loading; } const std::string &full_software_name() const noexcept { return m_full_software_name; } protected: - // device_interface implementation + // interface-level overrides virtual void interface_config_complete() override; virtual const software_list_loader &get_software_list_loader() const; - virtual bool use_software_list_file_extension_for_filetype() const noexcept { return false; } + virtual const bool use_software_list_file_extension_for_filetype() const { return false; } + image_init_result load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); std::error_condition load_image_by_path(u32 open_flags, std::string_view path); - bool is_loaded() const noexcept { return m_file != nullptr; } + void clear(); + bool is_loaded() const { return m_file != nullptr; } - void set_image_tag(); + void set_image_filename(std::string_view filename); + + void clear_error(); void check_for_file() const { if (!m_file) throw emu_fatalerror("%s(%s): Illegal operation on unmounted image", device().shortname(), device().tag()); } void make_readonly() noexcept { m_readonly = true; } - std::error_condition image_checkhash(); + bool image_checkhash(); const software_part *find_software_item(std::string_view identifier, bool restrict_to_interface, software_list_device **device = nullptr) const; std::string software_get_default_slot(std::string_view default_card_slot) const; @@ -245,21 +311,17 @@ class device_image_interface : public device_interface void add_format(std::unique_ptr &&format); void add_format(std::string &&name, std::string &&description, std::string &&extensions, std::string &&optspec); -private: - std::vector determine_open_plan(bool is_create); - void update_names(); - void set_image_filename(std::string_view filename); - void clear() noexcept; - std::pair load_internal(std::string_view path, bool is_create, int create_format, util::option_resolution *create_args); - std::error_condition load_software_part(std::string_view identifier); + // derived class overrides - bool init_phase() const; - static std::error_condition run_hash(util::random_read &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); + // configuration + static const image_device_type_info *find_device_type(iodevice_t type); + static const image_device_type_info m_device_info_array[]; - // loads an image or software items and resets - called internally when we - // load an is_reset_on_load() item - void reset_and_load(std::string_view path); + // error related info + std::error_condition m_err; + std::string m_err_message; +private: // variables that are only non-zero when an image is mounted util::core_file::ptr m_file; std::unique_ptr m_mame_file; @@ -268,27 +330,29 @@ class device_image_interface : public device_interface std::string m_basename_noext; std::string m_filetype; - // preset images regions - std::vector m_possible_preset_regions; - std::vector m_preset_images; - int m_default_region, m_current_region; - // Software information std::string m_full_software_name; const software_part *m_software_part_ptr; std::string m_software_list_name; + std::vector determine_open_plan(bool is_create); + void update_names(); + bool load_software_part(std::string_view identifier); + + bool init_phase() const; + static bool run_hash(util::core_file &file, u32 skip_bytes, util::hash_collection &hashes, const char *types); + + // loads an image or software items and resets - called internally when we + // load an is_reset_on_load() item + void reset_and_load(std::string_view path); + // creation info formatlist_type m_formatlist; // working directory; persists across mounts std::string m_working_directory; - // to notify interested parties when media changes - util::notifier m_media_change_notifier; - // flags - u32 m_sequence_counter; bool m_readonly; bool m_created; @@ -306,8 +370,6 @@ class device_image_interface : public device_interface // we want to disable command line cart loading... bool m_user_loadable; - bool m_must_be_loaded; - bool m_is_loading; bool m_is_reset_and_loading; @@ -316,4 +378,4 @@ class device_image_interface : public device_interface // iterator typedef device_interface_enumerator image_interface_enumerator; -#endif // MAME_EMU_DIIMAGE_H +#endif /* MAME_EMU_DIIMAGE_H */ From d1a704f39c386f20dbec32a44e7677a4d7b02549 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:48:35 -0600 Subject: [PATCH 30/47] Revert updates. This reverts commit 27bfc22efdc18a519be9d3d191bbbfd25ddfc49f. --- src/emu/render.cpp | 434 +++++++++++++++++++---------------------- src/emu/render.h | 59 +++--- src/emu/rendertypes.h | 10 - src/emu/rendutil.h | 19 +- src/lib/util/ioprocs.h | 127 +----------- 5 files changed, 243 insertions(+), 406 deletions(-) diff --git a/src/emu/render.cpp b/src/emu/render.cpp index 19f99955..d1fe139c 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -41,7 +41,6 @@ #include "corestr.h" #include "emuopts.h" -#include "fileio.h" #include "rendfont.h" #include "rendlay.h" #include "rendutil.h" @@ -57,7 +56,6 @@ #include "util/xmlfile.h" #include -#include @@ -100,20 +98,6 @@ struct render_target::object_transform }; -struct render_target::hit_test -{ - hit_test() noexcept - : inbounds(0U, 0U) - , hit(0U) - { - } - - std::pair inbounds; - u64 hit; -}; - - - //************************************************************************** // GLOBAL VARIABLES @@ -316,8 +300,7 @@ render_texture::render_texture() m_curseq(0) { m_sbounds.set(0, -1, 0, -1); - for (auto &elem : m_scaled) - elem.seqid = 0; + memset(m_scaled, 0, sizeof(m_scaled)); } @@ -369,7 +352,6 @@ void render_texture::release() m_bitmap = nullptr; m_sbounds.set(0, -1, 0, -1); m_format = TEXFORMAT_ARGB32; - m_scaler = nullptr; m_curseq = 0; } @@ -448,7 +430,6 @@ void render_texture::get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo texinfo.base = m_bitmap->raw_pixptr(m_sbounds.top(), m_sbounds.left()); texinfo.rowpixels = m_bitmap->rowpixels(); texinfo.width = swidth; - texinfo.width_margin = m_sbounds.left(); texinfo.height = sheight; // palette will be set later texinfo.seqid = ++m_curseq; @@ -709,7 +690,7 @@ const rgb_t *render_container::bcg_lookup_table(int texformat, u32 &out_length, m_bcglookup.resize(palette->max_index()); recompute_lookups(); } - assert(palette == &m_palclient->palette()); + assert (palette == &m_palclient->palette()); out_length = palette->max_index(); return &m_bcglookup[0]; @@ -899,21 +880,19 @@ render_container::user_settings::user_settings() // render_target - constructor //------------------------------------------------- -render_target::render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags) - : render_target(manager, ui, layoutfile, flags, CONSTRUCTOR_IMPL) +render_target::render_target(render_manager &manager, const internal_layout *layoutfile, u32 flags) + : render_target(manager, layoutfile, flags, CONSTRUCTOR_IMPL) { } -render_target::render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags) - : render_target(manager, ui, layout, flags, CONSTRUCTOR_IMPL) +render_target::render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags) + : render_target(manager, layout, flags, CONSTRUCTOR_IMPL) { } -template -render_target::render_target(render_manager &manager, render_container *ui, T &&layout, u32 flags, constructor_impl_t) +template render_target::render_target(render_manager &manager, T &&layout, u32 flags, constructor_impl_t) : m_next(nullptr) , m_manager(manager) - , m_ui_container(ui) , m_curview(0U) , m_flags(flags) , m_listindex(0) @@ -1033,9 +1012,9 @@ void render_target::set_bounds(s32 width, s32 height, float pixel_aspect) m_width = width; m_height = height; m_bounds.x0 = m_bounds.y0 = 0; - m_bounds.x1 = float(width); - m_bounds.y1 = float(height); - m_pixel_aspect = pixel_aspect != 0.0F ? pixel_aspect : 1.0F; + m_bounds.x1 = (float)width; + m_bounds.y1 = (float)height; + m_pixel_aspect = pixel_aspect != 0.0? pixel_aspect : 1.0; } @@ -1051,8 +1030,6 @@ void render_target::set_view(unsigned viewindex) m_curview = viewindex; current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); current_view().preload(); - m_clickable_items.clear(); - m_clickable_items.resize(current_view().interactive_items().size()); } } @@ -1081,7 +1058,7 @@ void render_target::set_visibility_toggle(unsigned index, bool enable) m_views[m_curview].second |= u32(1) << index; else m_views[m_curview].second &= ~(u32(1) << index); - update_layer_config(); + current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); current_view().preload(); } @@ -1093,29 +1070,28 @@ void render_target::set_visibility_toggle(unsigned index, bool enable) unsigned render_target::configured_view(const char *viewname, int targetindex, int numtargets) { + layout_view *view = nullptr; + // if it isn't "auto" or an empty string, try to match it as a view name prefix if (viewname && *viewname && strcmp(viewname, "auto")) { // scan for a matching view name size_t const viewlen = strlen(viewname); - for (unsigned i = 0; m_views.size() > i; ++i) - { + for (unsigned i = 0; !view && (m_views.size() > i); ++i) if (!core_strnicmp(m_views[i].first.name().c_str(), viewname, viewlen)) - return i; - } + view = &m_views[i].first; } // if we don't have a match, default to the nth view std::vector > screens; for (screen_device &screen : screen_device_enumerator(m_manager.machine().root_device())) screens.push_back(screen); - if (!screens.empty()) + if (!view && !screens.empty()) { // if we have enough targets to be one per screen, assign in order if (numtargets >= screens.size()) { // find the first view with this screen and this screen only - layout_view *view = nullptr; screen_device const &screen = screens[index() % screens.size()]; for (unsigned i = 0; !view && (m_views.size() > i); ++i) { @@ -1133,21 +1109,22 @@ unsigned render_target::configured_view(const char *viewname, int targetindex, i } } } - if (view) - return view_index(*view); } // otherwise, find the first view that has all the screens - for (unsigned i = 0; m_views.size() > i; ++i) + if (!view) { - layout_view &curview = m_views[i].first; - if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end()) - return i; + for (unsigned i = 0; !view && (m_views.size() > i); ++i) + { + layout_view &curview = m_views[i].first; + if (std::find_if(screens.begin(), screens.end(), [&curview] (screen_device &screen) { return !curview.has_screen(screen); }) == screens.end()) + view = &curview; + } } } - // default to the first view - return 0; + // make sure it's a valid view + return view ? view_index(*view) : 0; } @@ -1220,103 +1197,63 @@ void render_target::compute_visible_area(s32 target_width, s32 target_height, fl // apply orientation if required if (target_orientation & ORIENTATION_SWAP_XY) - src_aspect = 1.0f / src_aspect; - - // we need the ratio of target to source aspect - float aspect_ratio = m_keepaspect ? (float)target_width / (float)target_height * target_pixel_aspect / src_aspect : 1.0f; + src_aspect = 1.0 / src_aspect; - // first compute (a, b) scale factors to fit the screen - float a = (float)target_width / src_width; - float b = (float)target_height / src_height; + // get target aspect + float target_aspect = (float)target_width / (float)target_height * target_pixel_aspect; // apply automatic axial stretching if required int scale_mode = m_scale_mode; - if (scale_mode == SCALE_FRACTIONAL_AUTO) - scale_mode = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY) ? - SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X; - - // determine the scaling method for each axis - bool a_is_fract = (scale_mode == SCALE_FRACTIONAL_X || scale_mode == SCALE_FRACTIONAL); - bool b_is_fract = (scale_mode == SCALE_FRACTIONAL_Y || scale_mode == SCALE_FRACTIONAL); - - // check if we have user defined scale factors, if so use them instead, but only on integer axes - int a_user = a_is_fract ? 0 : m_int_scale_x; - int b_user = b_is_fract ? 0 : m_int_scale_y; - - // we allow overscan either explicitely or if integer scale factors are forced by user - bool int_overscan = m_int_overscan || (m_keepaspect && (a_user != 0 || b_user != 0)); - float a_max = std::max(a, (float)a_user); - float b_max = std::max(b, (float)b_user); - - - // get the usable bounding box considering the type of scaling for each axis - float usable_aspect = (a_is_fract ? a : std::max(1.0f, floorf(a))) * src_width / - ((b_is_fract ? b : std::max(1.0f, floorf(b))) * src_height) * target_pixel_aspect; - - // depending on the relative shape between target and source, let's define 'a' and 'b' so that: - // * a is the leader axis (first to hit a boundary) - // * b is the follower axis - if (usable_aspect > src_aspect) + if (m_scale_mode == SCALE_FRACTIONAL_AUTO) { - std::swap(a, b); - std::swap(a_user, b_user); - std::swap(a_is_fract, b_is_fract); - std::swap(a_max, b_max); - aspect_ratio = 1.0f / aspect_ratio; + bool is_rotated = (m_manager.machine().system().flags & ORIENTATION_SWAP_XY) ^ (target_orientation & ORIENTATION_SWAP_XY); + scale_mode = is_rotated ? SCALE_FRACTIONAL_Y : SCALE_FRACTIONAL_X; } - // now find an (a, b) pair that best fits our boundaries and scale options - float a_best = 1.0f, b_best = 1.0f; - float diff = 1000; - - // fill (a0, a1) range - float u = a_user == 0 ? a : (float)a_user; - float a_range[] = {a_is_fract ? u : std::max(1.0f, floorf(u)), a_is_fract ? u : std::max(1.0f, roundf(u))}; + // first compute scale factors to fit the screen + float xscale = (float)target_width / src_width; + float yscale = (float)target_height / src_height; - for (float aa : a_range) + // apply aspect correction + if (m_keepaspect) { - // apply aspect correction to 'b' axis if needed, considering resulting 'a' borders - float ba = b * (m_keepaspect ? aspect_ratio * (aa / a) : 1.0f); - - // fill (b0, b1) range - float v = b_user == 0 ? ba : (float)b_user; - float b_range[] = {b_is_fract ? v : std::max(1.0f, floorf(v)), b_is_fract ? v : std::max(1.0f, roundf(v))}; + if (target_aspect > src_aspect) + xscale *= src_aspect / target_aspect; + else + yscale *= target_aspect / src_aspect; + } - for (float bb : b_range) - { - // we may need to propagate proportions back to 'a' axis - float ab = aa; - if (m_keepaspect && a_user == 0) - { - if (a_is_fract) ab *= (bb / ba); - else if (b_user != 0) ab = std::max(1.0f, roundf(ab * (bb / ba))); - } + bool x_fits = render_round_nearest(xscale) * src_width <= target_width; + bool y_fits = render_round_nearest(yscale) * src_height <= target_height; - // if overscan isn't allowed, discard values that exceed the usable bounding box, except a minimum of 1.0f - if (!int_overscan && ((ab > a_max && bb > 1.0f) || (bb > b_max && ab > 1.0f))) - continue; + // compute integer scale factors + float integer_x = std::max(1.0f, float(m_int_overscan || x_fits ? render_round_nearest(xscale) : floor(xscale))); + float integer_y = std::max(1.0f, float(m_int_overscan || y_fits ? render_round_nearest(yscale) : floor(yscale))); - // score the result - float new_diff = fabsf(aspect_ratio * (a / b) - (ab / bb)); + // check if we have user defined scale factors, if so use them instead + integer_x = m_int_scale_x > 0 ? m_int_scale_x : integer_x; + integer_y = m_int_scale_y > 0 ? m_int_scale_y : integer_y; - if (new_diff <= diff) - { - diff = new_diff; - a_best = ab; - b_best = bb; - } - } + // now apply desired scale mode + if (scale_mode == SCALE_FRACTIONAL_X) + { + if (m_keepaspect) xscale *= integer_y / yscale; + yscale = integer_y; + } + else if (scale_mode == SCALE_FRACTIONAL_Y) + { + if (m_keepaspect) yscale *= integer_x / xscale; + xscale = integer_x; + } + else + { + xscale = integer_x; + yscale = integer_y; } - a = a_best; - b = b_best; - - // restore orientation - if (usable_aspect > src_aspect) - std::swap(a, b); // set the final width/height - visible_width = render_round_nearest(src_width * a); - visible_height = render_round_nearest(src_height * b); + visible_width = render_round_nearest(src_width * xscale); + visible_height = render_round_nearest(src_height * yscale); break; } } @@ -1474,8 +1411,8 @@ render_primitive_list &render_target::get_primitives() } } - // process UI elements if applicable - if (m_ui_container) + // process the UI if we are the UI target + if (is_ui_target()) { // compute the transform for the UI object_transform ui_xform; @@ -1488,7 +1425,7 @@ render_primitive_list &render_target::get_primitives() ui_xform.no_center = false; // add UI elements - add_container_primitives(list, root_xform, ui_xform, *m_ui_container, BLENDMODE_ALPHA); + add_container_primitives(list, root_xform, ui_xform, m_manager.ui_container(), BLENDMODE_ALPHA); } // optimize the list before handing it off @@ -1509,12 +1446,16 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta std::pair target_f(map_point_internal(target_x, target_y)); // explicitly check for the UI container - if (&container == m_ui_container) + if (&container == &m_manager.ui_container()) { // this hit test went against the UI container - container_x = float(target_x) / m_width; - container_y = float(target_y) / m_height; - return (target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f); + if ((target_f.first >= 0.0f) && (target_f.first < 1.0f) && (target_f.second >= 0.0f) && (target_f.second < 1.0f)) + { + // this point was successfully mapped + container_x = float(target_x) / m_width; + container_y = float(target_y) / m_height; + return true; + } } else { @@ -1533,12 +1474,15 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta [&container] (layout_view_item &item) { return &item.screen()->container() == &container; })); if (items.end() != found) { - // point successfully mapped layout_view_item &item(*found); render_bounds const bounds(item.bounds()); - container_x = (target_f.first - bounds.x0) / bounds.width(); - container_y = (target_f.second - bounds.y0) / bounds.height(); - return bounds.includes(target_f.first, target_f.second); + if (bounds.includes(target_f.first, target_f.second)) + { + // point successfully mapped + container_x = (target_f.first - bounds.x0) / bounds.width(); + container_y = (target_f.second - bounds.y0) / bounds.height(); + return true; + } } } @@ -1548,6 +1492,74 @@ bool render_target::map_point_container(s32 target_x, s32 target_y, render_conta } +//------------------------------------------------- +// map_point_input - attempts to map a point on +// the specified render_target to an input port +// field, if possible +//------------------------------------------------- + +bool render_target::map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y) +{ + std::pair target_f(map_point_internal(target_x, target_y)); + if (m_orientation & ORIENTATION_FLIP_X) + target_f.first = 1.0f - target_f.first; + if (m_orientation & ORIENTATION_FLIP_Y) + target_f.second = 1.0f - target_f.second; + if (m_orientation & ORIENTATION_SWAP_XY) + std::swap(target_f.first, target_f.second); + + auto const &items(current_view().interactive_items()); + m_hit_test.resize(items.size() * 2); + std::fill(m_hit_test.begin(), m_hit_test.end(), false); + + for (auto const &edge : current_view().interactive_edges_x()) + { + if ((edge.position() > target_f.first) || ((edge.position() == target_f.first) && edge.trailing())) + break; + else + m_hit_test[edge.index()] = !edge.trailing(); + } + + for (auto const &edge : current_view().interactive_edges_y()) + { + if ((edge.position() > target_f.second) || ((edge.position() == target_f.second) && edge.trailing())) + break; + else + m_hit_test[items.size() + edge.index()] = !edge.trailing(); + } + + for (unsigned i = 0; items.size() > i; ++i) + { + if (m_hit_test[i] && m_hit_test[items.size() + i]) + { + layout_view_item &item(items[i]); + render_bounds const bounds(item.bounds()); + if (bounds.includes(target_f.first, target_f.second)) + { + if (item.has_input()) + { + // point successfully mapped + std::tie(input_port, input_mask) = item.input_tag_and_mask(); + input_x = (target_f.first - bounds.x0) / bounds.width(); + input_y = (target_f.second - bounds.y0) / bounds.height(); + return true; + } + else + { + break; + } + } + } + } + + // default to point not mapped + input_port = nullptr; + input_mask = 0; + input_x = input_y = -1.0f; + return false; +} + + //------------------------------------------------- // invalidate_all - if any of our primitive lists // contain a reference to the given pointer, @@ -1577,7 +1589,7 @@ void render_target::resolve_tags() for (layout_file &file : m_filelist) file.resolve_tags(); - update_layer_config(); + current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); current_view().preload(); } @@ -1590,8 +1602,6 @@ void render_target::resolve_tags() void render_target::update_layer_config() { current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); - m_clickable_items.clear(); - m_clickable_items.resize(current_view().interactive_items().size()); } @@ -1654,6 +1664,14 @@ void render_target::load_additional_layout_files(const char *basename, bool have else m_external_artwork = true; + // if a default view has been specified, use that as a fallback + bool have_default = false; + if (system.default_layout) + have_default |= load_layout_file(nullptr, *system.default_layout); + m_manager.machine().config().apply_default_layouts( + [this, &have_default] (device_t &dev, internal_layout const &layout) + { have_default |= load_layout_file(nullptr, layout, &dev); }); + // try to load another file based on the parent driver name int cloneof = driver_list::clone(system); while (0 <= cloneof) @@ -1671,14 +1689,6 @@ void render_target::load_additional_layout_files(const char *basename, bool have cloneof = driver_list::clone(parent); } - // if a default view has been specified, use that as a fallback - bool have_default = false; - if (system.default_layout) - have_default |= load_layout_file(nullptr, *system.default_layout); - m_manager.machine().config().apply_default_layouts( - [this, &have_default] (device_t &dev, internal_layout const &layout) - { have_default |= load_layout_file(nullptr, layout, &dev); }); - have_artwork |= m_external_artwork; // Use fallback artwork if defined and no artwork has been found yet @@ -2066,10 +2076,11 @@ bool render_target::load_layout_file(const char *dirname, const internal_layout size_t decompressed = 0; do { - auto const [err, actual] = read( - *inflater, + size_t actual; + std::error_condition const err = inflater->read( &tempout[decompressed], - layout_data.decompressed_size - decompressed); + layout_data.decompressed_size - decompressed, + actual); decompressed += actual; if (err) { @@ -2162,7 +2173,7 @@ bool render_target::load_layout_file(device_t &device, util::xml::data_node cons { m_filelist.emplace_back(device, rootnode, searchpath, dirname); } - catch (emu_fatalerror const &err) + catch (emu_fatalerror &err) { osd_printf_warning("%s\n", err.what()); return false; @@ -2298,11 +2309,11 @@ void render_target::add_container_primitives(render_primitive_list &list, const // clip the primitive if (!m_transform_container && PRIMFLAG_GET_VECTOR(curitem.flags())) { - clipped = render_clip_line(prim->bounds, root_cliprect); + clipped = render_clip_line(&prim->bounds, &root_cliprect); } else { - clipped = render_clip_line(prim->bounds, cliprect); + clipped = render_clip_line(&prim->bounds, &cliprect); } break; @@ -2335,7 +2346,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const prim->texcoords = oriented_texcoords[finalorient]; // apply clipping - clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); + clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); // apply the final orientation from the quad flags and then build up the final flags prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) @@ -2395,7 +2406,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const prim->texcoords = oriented_texcoords[finalorient]; // apply clipping - clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); + clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); // apply the final orientation from the quad flags and then build up the final flags prim->flags |= (curitem.flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) @@ -2411,7 +2422,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); // apply clipping - clipped = render_clip_quad(prim->bounds, cliprect, nullptr); + clipped = render_clip_quad(&prim->bounds, &cliprect, nullptr); } } break; @@ -2536,7 +2547,7 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob } // add to the list or free if we're clipped out - bool const clipped = render_clip_quad(prim->bounds, cliprect, &prim->texcoords); + bool const clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); list.append_or_return(*prim, clipped); } } @@ -2566,25 +2577,6 @@ std::pair render_target::map_point_internal(s32 target_x, s32 targ } -//------------------------------------------------- -// map_point_layout - map point from screen -// coordinates to layout coordinates -//------------------------------------------------- - -std::pair render_target::map_point_layout(s32 target_x, s32 target_y) -{ - using std::swap; - std::pair result(map_point_internal(target_x, target_y)); - if (m_orientation & ORIENTATION_FLIP_X) - result.first = 1.0f - result.first; - if (m_orientation & ORIENTATION_FLIP_Y) - result.second = 1.0f - result.second; - if (m_orientation & ORIENTATION_SWAP_XY) - swap(result.first, result.second); - return result; -} - - //------------------------------------------------- // view_name - return the name of the indexed // view, or nullptr if it doesn't exist @@ -2627,22 +2619,20 @@ void render_target::config_load(util::xml::data_node const *targetnode) if (!targetnode) return; - // TODO: consider option priority - command line should take precedence over CFG - // not practical at the moment because view selection options are in the OSD layer - // find the view const char *viewname = targetnode->get_attribute_string("view", nullptr); - if (viewname) - { - for (unsigned viewnum = 0; m_views.size() > viewnum; viewnum++) + if (viewname != nullptr) + for (int viewnum = 0; viewnum < 1000; viewnum++) { - if (!strcmp(viewname, view_name(viewnum))) + const char *testname = view_name(viewnum); + if (testname == nullptr) + break; + if (!strcmp(viewname, testname)) { set_view(viewnum); break; } } - } // modify the artwork config int const zoom = targetnode->get_attribute_int("zoom", -1); @@ -2664,11 +2654,12 @@ void render_target::config_load(util::xml::data_node const *targetnode) set_orientation(orientation_add(rotate, orientation())); // apply the opposite orientation to the UI - if (m_ui_container) + if (is_ui_target()) { - render_container::user_settings settings = m_ui_container->get_user_settings(); + render_container &ui_container = m_manager.ui_container(); + render_container::user_settings settings = ui_container.get_user_settings(); settings.m_orientation = orientation_add(orientation_reverse(rotate), settings.m_orientation); - m_ui_container->set_user_settings(settings); + ui_container.set_user_settings(settings); } } @@ -2708,8 +2699,6 @@ void render_target::config_load(util::xml::data_node const *targetnode) { current_view().recompute(visibility_mask(), m_layerconfig.zoom_to_screen()); current_view().preload(); - m_clickable_items.clear(); - m_clickable_items.resize(current_view().interactive_items().size()); } } } @@ -3071,6 +3060,7 @@ render_manager::render_manager(running_machine &machine) , m_ui_target(nullptr) , m_live_textures(0) , m_texture_id(0) + , m_ui_container(std::make_unique(*this)) { // register callbacks machine.configuration().config_register( @@ -3091,7 +3081,7 @@ render_manager::render_manager(running_machine &machine) render_manager::~render_manager() { // free all the containers since they may own textures - m_ui_containers.clear(); + m_ui_container.reset(); m_screen_container_list.clear(); // better not be any outstanding textures when we die @@ -3147,14 +3137,12 @@ float render_manager::max_update_rate() const render_target *render_manager::target_alloc(const internal_layout *layoutfile, u32 flags) { - render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this); - return &m_targetlist.append(*new render_target(*this, ui, layoutfile, flags)); + return &m_targetlist.append(*new render_target(*this, layoutfile, flags)); } render_target *render_manager::target_alloc(util::xml::data_node const &layout, u32 flags) { - render_container *const ui = (flags & RENDER_CREATE_HIDDEN) ? nullptr : &m_ui_containers.emplace_back(*this); - return &m_targetlist.append(*new render_target(*this, ui, layout, flags)); + return &m_targetlist.append(*new render_target(*this, layout, flags)); } @@ -3191,56 +3179,35 @@ render_target *render_manager::target_by_index(int index) const float render_manager::ui_aspect(render_container *rc) { - // work out if this is a UI container - render_target *target = nullptr; - if (!rc) - { - target = &ui_target(); - rc = target->ui_container(); - assert(rc); - } - else - { - for (render_target &t : m_targetlist) - { - if (t.ui_container() == rc) - { - target = &t; - break; - } - } - } - + int orient; float aspect; - if (target) - { - // UI container, aggregated multi-screen target + if (rc == m_ui_container.get() || rc == nullptr) { + // ui container, aggregated multi-screen target + orient = orientation_add(m_ui_target->orientation(), m_ui_container->orientation()); // based on the orientation of the target, compute height/width or width/height - int const orient = orientation_add(target->orientation(), rc->orientation()); if (!(orient & ORIENTATION_SWAP_XY)) - aspect = float(target->height()) / float(target->width()); + aspect = (float)m_ui_target->height() / (float)m_ui_target->width(); else - aspect = float(target->width()) / float(target->height()); + aspect = (float)m_ui_target->width() / (float)m_ui_target->height(); // if we have a valid pixel aspect, apply that and return - if (target->pixel_aspect() != 0.0f) + if (m_ui_target->pixel_aspect() != 0.0f) { - float pixel_aspect = target->pixel_aspect(); + float pixel_aspect = m_ui_target->pixel_aspect(); if (orient & ORIENTATION_SWAP_XY) pixel_aspect = 1.0f / pixel_aspect; return aspect /= pixel_aspect; } - } - else - { + + } else { // single screen container + orient = rc->orientation(); // based on the orientation of the target, compute height/width or width/height - int const orient = rc->orientation(); if (!(orient & ORIENTATION_SWAP_XY)) aspect = (float)rc->screen()->visible_area().height() / (float)rc->screen()->visible_area().width(); else @@ -3248,7 +3215,12 @@ float render_manager::ui_aspect(render_container *rc) } // clamp for extreme proportions - return std::clamp(aspect, 0.66f, 1.5f); + if (aspect < 0.66f) + aspect = 0.66f; + if (aspect > 1.5f) + aspect = 1.5f; + + return aspect; } diff --git a/src/emu/render.h b/src/emu/render.h index 7834cbae..d7158340 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -47,12 +47,18 @@ #define MAME_EMU_RENDER_H #include "rendertypes.h" +#include "screen.h" - +#include #include -#include +#include +#include #include #include +#include +#include +#include +#include #include #include @@ -158,7 +164,6 @@ struct render_texinfo void * base; // base of the data u32 rowpixels; // pixels per row u32 width; // width of the image - u32 width_margin; // left margin of the scaled bounds, if applicable u32 height; // height of the image u32 seqid; // sequence ID u64 unique_id; // unique identifier to pass to osd @@ -341,7 +346,7 @@ class render_texture void get_scaled(u32 dwidth, u32 dheight, render_texinfo &texinfo, render_primitive_list &primlist, u32 flags = 0); const rgb_t *get_adjusted_palette(render_container &container, u32 &out_length); - static constexpr int MAX_TEXTURE_SCALES = 100; + static constexpr int MAX_TEXTURE_SCALES = 20; // a scaled_texture contains a single scaled entry for a texture struct scaled_texture @@ -493,15 +498,14 @@ class render_target friend class render_manager; // construction/destruction - render_target(render_manager &manager, render_container *ui, const internal_layout *layoutfile, u32 flags); - render_target(render_manager &manager, render_container *ui, util::xml::data_node const &layout, u32 flags); + render_target(render_manager &manager, const internal_layout *layoutfile = nullptr, u32 flags = 0); + render_target(render_manager &manager, util::xml::data_node const &layout, u32 flags = 0); ~render_target(); public: // getters render_target *next() const { return m_next; } render_manager &manager() const { return m_manager; } - render_container *ui_container() const { return m_ui_container; } u32 width() const { return m_width; } u32 height() const { return m_height; } float pixel_aspect() const { return m_pixel_aspect; } @@ -552,6 +556,7 @@ class render_target // hit testing bool map_point_container(s32 target_x, s32 target_y, render_container &container, float &container_x, float &container_y); + bool map_point_input(s32 target_x, s32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y); // reference tracking void invalidate_all(void *refptr); @@ -560,24 +565,15 @@ class render_target void resolve_tags(); private: - // constants - static inline constexpr int NUM_PRIMLISTS = 3; - static inline constexpr int MAX_CLEAR_EXTENTS = 1000; - using view_mask_pair = std::pair; using view_mask_vector = std::vector; // private classes declared in render.cpp struct object_transform; - struct pointer_info; - struct hit_test; - - using pointer_info_vector = std::vector; - using hit_test_vector = std::vector; // internal helpers enum constructor_impl_t { CONSTRUCTOR_IMPL }; - template render_target(render_manager &manager, render_container *ui, T&& layout, u32 flags, constructor_impl_t); + template render_target(render_manager &manager, T&& layout, u32 flags, constructor_impl_t); void update_layer_config(); void load_layout_files(const internal_layout *layoutfile, bool singlefile); void load_layout_files(util::xml::data_node const &rootnode, bool singlefile); @@ -588,7 +584,6 @@ class render_target void add_container_primitives(render_primitive_list &list, const object_transform &root_xform, const object_transform &xform, render_container &container, int blendmode); void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_view_item &item); std::pair map_point_internal(s32 target_x, s32 target_y); - std::pair map_point_layout(s32 target_x, s32 target_y); // config callbacks void config_load(util::xml::data_node const *targetnode); @@ -604,10 +599,13 @@ class render_target void add_clear_extents(render_primitive_list &list); void add_clear_and_optimize_primitive_list(render_primitive_list &list); + // constants + static constexpr int NUM_PRIMLISTS = 3; + static constexpr int MAX_CLEAR_EXTENTS = 1000; + // internal state render_target * m_next; // link to next target render_manager & m_manager; // reference to our owning manager - render_container *const m_ui_container; // container for drawing UI elements std::list m_filelist; // list of layout files view_mask_vector m_views; // views we consider unsigned m_curview; // current view index @@ -626,8 +624,7 @@ class render_target float m_max_refresh; // maximum refresh rate, 0 or if none int m_orientation; // orientation render_layer_config m_layerconfig; // layer configuration - pointer_info_vector m_pointers; // state of pointers over this target - hit_test_vector m_clickable_items; // for tracking clicked elements + std::vector m_hit_test; // used when mapping points to inputs layout_view * m_base_view; // the view at the time of first frame int m_base_orientation; // the orientation at the time of first frame render_layer_config m_base_layerconfig; // the layer configuration at the time of first frame @@ -674,7 +671,7 @@ class render_manager float ui_aspect(render_container *rc = nullptr); // UI containers - render_container &ui_container() const { assert(ui_target().ui_container()); return *ui_target().ui_container(); } + render_container &ui_container() const { assert(m_ui_container != nullptr); return *m_ui_container; } // textures render_texture *texture_alloc(texture_scaler_func scaler = nullptr, void *param = nullptr); @@ -695,20 +692,20 @@ class render_manager void config_save(config_type cfg_type, util::xml::data_node *parentnode); // internal state - running_machine & m_machine; // reference back to the machine + running_machine & m_machine; // reference back to the machine // array of live targets - simple_list m_targetlist; // list of targets - render_target * m_ui_target; // current UI target + simple_list m_targetlist; // list of targets + render_target * m_ui_target; // current UI target // texture lists - u32 m_live_textures; // number of live textures - u64 m_texture_id; // rolling texture ID counter - fixed_allocator m_texture_allocator; // texture allocator + u32 m_live_textures; // number of live textures + u64 m_texture_id; // rolling texture ID counter + fixed_allocator m_texture_allocator;// texture allocator - // containers for UI elements and for screens - std::list m_ui_containers; // containers for drawing UI elements - std::list m_screen_container_list; // list of containers for the screen + // containers for the UI and for screens + std::unique_ptr m_ui_container; // UI container + std::list m_screen_container_list; // list of containers for the screen }; #endif // MAME_EMU_RENDER_H diff --git a/src/emu/rendertypes.h b/src/emu/rendertypes.h index b3eed6ad..43f2ebb8 100644 --- a/src/emu/rendertypes.h +++ b/src/emu/rendertypes.h @@ -20,16 +20,6 @@ //************************************************************************** -// texture formats -enum texture_format -{ - TEXFORMAT_UNDEFINED = 0, // require a format to be specified - TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha - TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB - TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB - TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence -}; - // blending modes enum { diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h index 71e5bdc9..4d2b8956 100644 --- a/src/emu/rendutil.h +++ b/src/emu/rendutil.h @@ -15,11 +15,8 @@ #include "rendertypes.h" -#include "utilfwd.h" - #include #include -#include /* ----- image formats ----- */ @@ -42,14 +39,14 @@ enum ru_imgformat /* ----- render utilities ----- */ -void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false) noexcept; -bool render_clip_line(render_bounds &bounds, const render_bounds &clip); -bool render_clip_quad(render_bounds &bounds, const render_bounds &clip, render_quad_texuv *texcoords); -std::pair render_line_to_quad(const render_bounds &bounds, float width, float length_extension); -void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file) noexcept; -void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file) noexcept; -bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false) noexcept; -ru_imgformat render_detect_image(util::random_read &file) noexcept; +void render_resample_argb_bitmap_hq(bitmap_argb32 &dest, bitmap_argb32 &source, const render_color &color, bool force = false); +bool render_clip_line(render_bounds *bounds, const render_bounds *clip); +bool render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords); +void render_line_to_quad(const render_bounds *bounds, float width, float length_extension, render_bounds *bounds0, render_bounds *bounds1); +void render_load_msdib(bitmap_argb32 &bitmap, util::random_read &file); +void render_load_jpeg(bitmap_argb32 &bitmap, util::random_read &file); +bool render_load_png(bitmap_argb32 &bitmap, util::random_read &file, bool load_as_alpha_to_existing = false); +ru_imgformat render_detect_image(util::random_read &file); diff --git a/src/lib/util/ioprocs.h b/src/lib/util/ioprocs.h index 9e2c29d2..efe0a231 100644 --- a/src/lib/util/ioprocs.h +++ b/src/lib/util/ioprocs.h @@ -19,8 +19,6 @@ #include #include #include -#include -#include // FIXME: make a proper place for OSD forward declarations @@ -58,7 +56,7 @@ class read_stream /// \param [out] actual Number of bytes actually read. Will always /// be less than or equal to the requested length. /// \return An error condition if reading stopped due to an error. - virtual std::error_condition read_some(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition read(void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -102,7 +100,7 @@ class write_stream /// \param [out] actual Number of bytes actually written. Will /// always be less than or equal to the requested length. /// \return An error condition if writing stopped due to an error. - virtual std::error_condition write_some(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition write(void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -186,7 +184,7 @@ class random_read : public virtual read_stream, public virtual random_access /// be less than or equal to the requested length. /// \return An error condition if seeking failed or reading stopped /// due to an error. - virtual std::error_condition read_some_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition read_at(std::uint64_t offset, void *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -216,7 +214,7 @@ class random_write : public virtual write_stream, public virtual random_access /// always be less than or equal to the requested length. /// \return An error condition if seeking failed or writing stopped /// due to an error. - virtual std::error_condition write_some_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; + virtual std::error_condition write_at(std::uint64_t offset, void const *buffer, std::size_t length, std::size_t &actual) noexcept = 0; }; @@ -231,123 +229,6 @@ class random_read_write : public read_write_stream, public virtual random_read, using ptr = std::unique_ptr; }; - -/// \brief Read from the current position in the stream -/// -/// Reads up to the specified number of bytes from the stream into the -/// supplied buffer, continuing if interrupted by asynchronous signals. -/// May read less than the requested number of bytes if the end of the -/// stream is reached or an error occurs. If the stream supports -/// seeking, reading starts at the current position in the stream, and -/// the current position is incremented by the number of bytes read. -/// The operation may not be atomic if it is interrupted before the -/// requested number of bytes is read. -/// \param [in] stream The stream to read from. -/// \param [out] buffer Destination buffer. Must be large enough to -/// hold the requested number of bytes. -/// \param [in] length Maximum number of bytes to read. -/// \return A pair containing an error condition if reading stopped due -/// to an error, and the actual number of bytes read. -std::pair read(read_stream &stream, void *buffer, std::size_t length) noexcept; - -/// \brief Allocate memory and read from the current position in the -/// stream -/// -/// Allocates the specified number of bytes and then reads up to that -/// number of bytes from the stream into the newly allocated buffer, -/// continuing if interrupted by asynchronous signals. May read less -/// than the requested number of bytes if the end of the stream is -/// reached or an error occurs. If the stream supports seeking, -/// reading starts at the current position in the stream, and the -/// current position is incremented by the number of bytes read. The -/// operation may not be atomic if it is interrupted before the -/// requested number of bytes is read. No data will be read if -/// allocation fails. -/// \param [in] stream The stream to read from. -/// hold the requested number of bytes. -/// \param [in] length Maximum number of bytes to read. -/// \return A tuple containing an error condition if allocation failed -/// or reading stopped due to an error, the allocated buffer, and the -/// actual number of bytes read. -std::tuple, std::size_t> read(read_stream &stream, std::size_t length) noexcept; - -/// \brief Read from the specified position -/// -/// Reads up to the specified number of bytes from the stream into the -/// supplied buffer, continuing if interrupted by asynchronous signals. -/// May read less than the requested number of bytes if the end of the -/// stream is reached or an error occurs. If seeking is supported, -/// reading starts at the specified position and the current position is -/// unaffected. The operation may not be atomic if it is interrupted -/// before the requested number of bytes is read. -/// \param [in] stream The stream to read from. -/// \param [in] offset The position to start reading from, specified as -/// a number of bytes from the beginning of the stream. -/// \param [out] buffer Destination buffer. Must be large enough to -/// hold the requested number of bytes. -/// \param [in] length Maximum number of bytes to read. -/// \return A pair containing an error condition if reading stopped due -/// to an error, and the actual number of bytes read. -std::pair read_at(random_read &stream, std::uint64_t offset, void *buffer, std::size_t length) noexcept; - -/// \brief Allocate memory and read from the specified position -/// -/// Allocates the specified number of bytes and then reads up to that -/// number of bytes from the stream into the newly allocated buffer, -/// continuing if interrupted by asynchronous signals. May read less -/// than the requested number of bytes if the end of the stream is -/// reached or an error occurs. If seeking is supported, reading -/// starts at the specified position and the current position is -/// unaffected. The operation may not be atomic if it is interrupted -/// before the requested number of bytes is read. No data will be read -/// if allocation fails. -/// \param [in] stream The stream to read from. -/// \param [in] offset The position to start reading from, specified as -/// a number of bytes from the beginning of the stream. -/// \param [out] buffer Destination buffer. Must be large enough to -/// hold the requested number of bytes. -/// \param [in] length Maximum number of bytes to read. -/// \return A tuple containing an error condition if allocation failed -/// or reading stopped due to an error, the allocated buffer, and the -/// actual number of bytes read. -std::tuple, std::size_t> read_at(random_read &stream, std::uint64_t offset, std::size_t length) noexcept; - -/// \brief Write at the current position in the stream -/// -/// Writes up to the specified number of bytes from the supplied -/// buffer to the stream, continuing if interrupted by asynchronous -/// signals. May write less than the requested number of bytes if an -/// error occurs. If the stream supports seeking, writing starts at the -/// current position in the stream, and the current position is -/// incremented by the number of bytes written. The operation may not -/// be atomic if it is interrupted before the requested number of bytes -/// is written. -/// \param [in] stream The stream to write to. -/// \param [in] buffer Buffer containing the data to write. Must -/// contain at least the specified number of bytes. -/// \param [in] length Number of bytes to write. -/// \return A pair containing an error condition if writing stopped due -/// to an error, and the actual number of bytes written. -std::pair write(write_stream &stream, void const *buffer, std::size_t length) noexcept; - -/// \brief Write at specified position -/// -/// Writes up to the specified number of bytes from the supplied buffer, -/// continuing if interrupted by asynchronous signals. If seeking is -/// supported, writing starts at the specified position and the current -/// position is unaffected. May write less than the requested number -/// of bytes if an error occurs. The operation may not be atomic if it -/// is interrupted before the requested number of bytes is written. -/// \param [in] stream The stream to write to. -/// \param [in] offset The position to start writing at, specified as a -/// number of bytes from the beginning of the stream. -/// \param [in] buffer Buffer containing the data to write. Must -/// contain at least the specified number of bytes. -/// \param [in] length Number of bytes to write. -/// \return A pair containing an error condition if writing stopped due -/// to an error, and the actual number of bytes written. -std::pair write_at(random_write &stream, std::uint64_t offset, void const *buffer, std::size_t length) noexcept; - /// \} From 5ea60eb206bad3baf53af0b24d417b8eb7370440 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:48:50 -0600 Subject: [PATCH 31/47] Revert updates. This reverts commit 45d64b0804d49e68500c53c97a2895fe69c081a5. --- src/emu/screen.cpp | 337 ++++++++++++++++----------------------------- src/emu/screen.h | 60 ++++---- 2 files changed, 157 insertions(+), 240 deletions(-) diff --git a/src/emu/screen.cpp b/src/emu/screen.cpp index cd8c2012..3ef25676 100644 --- a/src/emu/screen.cpp +++ b/src/emu/screen.cpp @@ -12,8 +12,6 @@ #include "screen.h" #include "emuopts.h" -#include "fileio.h" -#include "main.h" #include "render.h" #include "rendutil.h" @@ -22,19 +20,6 @@ #include -#ifdef __LIBRETRO__ -#include "libretro/osdretro.h" -#endif - -//************************************************************************** -// DEBUGGING -//************************************************************************** - -#define VERBOSE (0) -#define LOG_PARTIAL_UPDATES(x) do { if (VERBOSE) logerror x; } while (0) - - - //************************************************************************** // GLOBAL VARIABLES //************************************************************************** @@ -558,9 +543,8 @@ screen_device::screen_device(const machine_config &mconfig, const char *tag, dev , m_curbitmap(0) , m_curtexture(0) , m_changed(true) - , m_last_partial_reset(attotime::zero) , m_last_partial_scan(0) - , m_partial_scan_hpos(0) + , m_partial_scan_hpos(-1) , m_color(rgb_t(0xff, 0xff, 0xff, 0xff)) , m_brightness(0xff) , m_frame_period(DEFAULT_FRAME_PERIOD.as_attoseconds()) @@ -776,6 +760,8 @@ void screen_device::device_resolve_objects() // bind our handlers m_screen_update_ind16.resolve(); m_screen_update_rgb32.resolve(); + m_screen_vblank.resolve_safe(); + m_scanline_cb.resolve(); // assign our format to the palette before it starts if (m_palette) @@ -838,19 +824,15 @@ void screen_device::device_start() m_container->set_user_settings(settings); // allocate the VBLANK timers - m_vblank_begin_timer = timer_alloc(FUNC(screen_device::vblank_begin), this); - m_vblank_end_timer = timer_alloc(FUNC(screen_device::vblank_end), this); + m_vblank_begin_timer = timer_alloc(TID_VBLANK_START); + m_vblank_end_timer = timer_alloc(TID_VBLANK_END); // allocate a timer to reset partial updates - m_scanline0_timer = timer_alloc(FUNC(screen_device::first_scanline_tick), this); + m_scanline0_timer = timer_alloc(TID_SCANLINE0); // allocate a timer to generate per-scanline updates - if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset()) - m_scanline_timer = timer_alloc(FUNC(screen_device::scanline_tick), this); - -#ifdef __LIBRETRO__ - screen_configured = 0; -#endif + if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb) + m_scanline_timer = timer_alloc(TID_SCANLINE); // configure the screen with the default parameters configure(m_width, m_height, m_visarea, m_refresh); @@ -860,7 +842,7 @@ void screen_device::device_start() m_vblank_end_time = attotime(0, m_vblank_period); // start the timer to generate per-scanline updates - if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || !m_scanline_cb.isunset()) + if ((m_video_attributes & VIDEO_UPDATE_SCANLINE) != 0 || m_scanline_cb) m_scanline_timer->adjust(time_until_pos(0)); // create burn-in bitmap @@ -885,7 +867,6 @@ void screen_device::device_start() save_item(NAME(m_visarea.min_y)); save_item(NAME(m_visarea.max_x)); save_item(NAME(m_visarea.max_y)); - save_item(NAME(m_last_partial_reset)); save_item(NAME(m_last_partial_scan)); save_item(NAME(m_frame_period)); save_item(NAME(m_brightness)); @@ -895,9 +876,6 @@ void screen_device::device_start() save_item(NAME(m_vblank_start_time)); save_item(NAME(m_vblank_end_time)); save_item(NAME(m_frame_number)); - if (m_oldstyle_vblank_supplied) - logerror("%s: Deprecated legacy Old Style screen configured (set_vblank_time), please use set_raw instead.\n",this->tag()); - m_is_primary_screen = (this == screen_device_enumerator(machine().root_device()).first()); } @@ -939,39 +917,54 @@ void screen_device::device_post_load() //------------------------------------------------- -// timer events +// device_timer - called whenever a device timer +// fires //------------------------------------------------- -TIMER_CALLBACK_MEMBER(screen_device::first_scanline_tick) +void screen_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { - // first scanline - reset_partial_updates(); - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + switch (id) { - pre_update_scanline(0); - } -} + // signal VBLANK start + case TID_VBLANK_START: + vblank_begin(); + break; -TIMER_CALLBACK_MEMBER(screen_device::scanline_tick) -{ - // subsequent scanlines when scanline updates are enabled - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) - { - pre_update_scanline(param); - } - if (m_video_attributes & VIDEO_UPDATE_SCANLINE) - { - // force a partial update to the current scanline - update_partial(param); + // signal VBLANK end + case TID_VBLANK_END: + vblank_end(); + break; + + // first scanline + case TID_SCANLINE0: + reset_partial_updates(); + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + { + pre_update_scanline(0); + } + break; + + // subsequent scanlines when scanline updates are enabled + case TID_SCANLINE: + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + { + pre_update_scanline(param); + } + if (m_video_attributes & VIDEO_UPDATE_SCANLINE) + { + // force a partial update to the current scanline + update_partial(param); + } + if (m_scanline_cb) + m_scanline_cb(param); + + // compute the next visible scanline + param++; + if (param > m_visarea.bottom()) + param = m_visarea.top(); + m_scanline_timer->adjust(time_until_pos(param), param); + break; } - if (!m_scanline_cb.isunset()) - m_scanline_cb(param); - - // compute the next visible scanline - param++; - if (param > m_visarea.bottom()) - param = m_visarea.top(); - m_scanline_timer->adjust(time_until_pos(param), param); } @@ -1013,15 +1006,6 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a else m_vblank_period = m_scantime * (height - visarea.height()); -#ifdef __LIBRETRO__ - /* Performance hack fix for "pong" and "breakout" */ - if (screen_configured > 10 - && width == m_width - && height == m_height - && floorf(ATTOSECONDS_TO_HZ(frame_period)) == floorf(ATTOSECONDS_TO_HZ(m_frame_period))) - return; -#endif - // we are now fully configured with the new parameters // and can safely call time_until_pos(), etc. @@ -1029,7 +1013,7 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a // call the VBLANK start timer now; otherwise, adjust it for the future attoseconds_t delta = (machine().time() - m_vblank_start_time).as_attoseconds(); if (delta >= m_frame_period) - vblank_begin(0); + vblank_begin(); else m_vblank_begin_timer->adjust(time_until_vblank_start()); @@ -1042,17 +1026,6 @@ void screen_device::configure(int width, int height, const rectangle &visarea, a // adjust speed if necessary machine().video().update_refresh_speed(); - -#ifdef __LIBRETRO__ - float retro_fps_new = ATTOSECONDS_TO_HZ(m_frame_period); - if (!screen_configured - && retro_fps_new != retro_fps - && retro_fps_new <= 120.0f - && retro_fps_new >= 40.0f) - retro_fps = retro_fps_new; - - screen_configured++; -#endif } @@ -1068,19 +1041,19 @@ void screen_device::reset_origin(int beamy, int beamx) m_vblank_end_time = curtime - attotime(0, beamy * m_scantime + beamx * m_pixeltime); m_vblank_start_time = m_vblank_end_time - attotime(0, m_vblank_period); - // if we are resetting relative to (visarea.bottom() + 1, 0) == VBLANK start, - // call the VBLANK start timer now; otherwise, adjust it for the future - if (beamy == ((m_visarea.bottom() + 1) % m_height) && beamx == 0) - vblank_begin(0); - else - m_vblank_begin_timer->adjust(time_until_vblank_start()); - // if we are resetting relative to (0,0) == VBLANK end, call the // scanline 0 timer by hand now; otherwise, adjust it for the future if (beamy == 0 && beamx == 0) reset_partial_updates(); else m_scanline0_timer->adjust(time_until_pos(0)); + + // if we are resetting relative to (visarea.bottom() + 1, 0) == VBLANK start, + // call the VBLANK start timer now; otherwise, adjust it for the future + if (beamy == ((m_visarea.bottom() + 1) % m_height) && beamx == 0) + vblank_begin(); + else + m_vblank_begin_timer->adjust(time_until_vblank_start()); } @@ -1170,40 +1143,21 @@ void screen_device::set_visible_area(int min_x, int max_x, int min_y, int max_y) bool screen_device::update_partial(int scanline) { - LOG_PARTIAL_UPDATES(("Partial: update_partial(%s, %d): ", tag(), scanline)); - // these two checks only apply if we're allowed to skip frames if (!(m_video_attributes & VIDEO_ALWAYS_UPDATE)) { // if skipping this frame, bail if (machine().video().skip_this_frame()) - { - LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n")); return false; - } // skip if this screen is not visible anywhere if (!machine().render().is_live(*this)) - { - LOG_PARTIAL_UPDATES(("skipped because screen not live\n")); return false; - } } // skip if we already rendered this line if (scanline < m_last_partial_scan) - { - LOG_PARTIAL_UPDATES(("skipped because line was already rendered\n")); return false; - } - - // skip if we already rendered this frame - // this can happen if a cpu timeslice that called update_partial is in the previous frame while scanline 0 already started - if (m_last_partial_scan == 0 && m_last_partial_reset > machine().time()) - { - LOG_PARTIAL_UPDATES(("skipped because frame was already rendered\n")); - return false; - } // set the range of scanlines to render rectangle clip(m_visarea); @@ -1211,61 +1165,46 @@ bool screen_device::update_partial(int scanline) // skip if entirely outside of visible area if (clip.top() > clip.bottom()) - { - LOG_PARTIAL_UPDATES(("skipped because outside of visible area\n")); return false; - } // otherwise, render - LOG_PARTIAL_UPDATES(("updating %d-%d\n", clip.top(), clip.bottom())); - u32 flags = 0; + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - auto profile = g_profiler.start(PROFILER_VIDEO); - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + rectangle scan_clip(clip); + for (int y = clip.top(); y <= clip.bottom(); y++) { - rectangle scan_clip(clip); - for (int y = clip.top(); y <= clip.bottom(); y++) - { - scan_clip.sety(y, y); - pre_update_scanline(y); - - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - switch (curbitmap.format()) - { - default: - case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; - case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; - } + scan_clip.sety(y, y); + pre_update_scanline(y); - m_partial_updates_this_frame++; + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) + { + default: + case BITMAP_FORMAT_IND16: flags |= m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; + case BITMAP_FORMAT_RGB32: flags |= m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][y], scan_clip); break; } + + m_partial_updates_this_frame++; } - else + } + else + { + if (m_type != SCREEN_TYPE_SVG) { - if (m_type != SCREEN_TYPE_SVG) - { - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - switch (curbitmap.format()) - { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; - } - } - else + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + switch (curbitmap.format()) { - // optional screen_update callback before rendering svg (eg. for preparing outputs used by the svg) - // bitmap can be considered read-only, as it gets overwritten later - if (!m_screen_update_rgb32.isnull()) - flags = m_screen_update_rgb32(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); - - if (~flags & UPDATE_HAS_NOT_CHANGED) - flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; } - m_partial_updates_this_frame++; } - // stop profiling + else + { + flags = m_svg->render(*this, m_bitmap[m_curbitmap].as_rgb32(), clip); + } + m_partial_updates_this_frame++; } // if we modified the bitmap, we have to commit @@ -1273,7 +1212,7 @@ bool screen_device::update_partial(int scanline) // remember where we left off m_last_partial_scan = scanline + 1; - m_partial_scan_hpos = 0; + m_partial_scan_hpos = -1; return true; } @@ -1290,17 +1229,11 @@ void screen_device::update_now() { // if skipping this frame, bail if (machine().video().skip_this_frame()) - { - LOG_PARTIAL_UPDATES(("skipped due to frameskipping\n")); return; - } // skip if this screen is not visible anywhere if (!machine().render().is_live(*this)) - { - LOG_PARTIAL_UPDATES(("skipped because screen not live\n")); return; - } } int current_vpos = vpos(); @@ -1309,36 +1242,20 @@ void screen_device::update_now() // skip if we already rendered this line if (current_vpos < m_last_partial_scan) - { - LOG_PARTIAL_UPDATES(("skipped because line was already rendered\n")); return; - } // if beam position is the same, there's nothing to update if (current_vpos == m_last_partial_scan && current_hpos == m_partial_scan_hpos) - { - LOG_PARTIAL_UPDATES(("skipped because beam position is unchanged\n")); return; - } - - // skip if we already rendered this frame - // this can happen if a cpu timeslice that called update_now is in the previous frame while scanline 0 already started - if (m_last_partial_scan == 0 && m_partial_scan_hpos == 0 && m_last_partial_reset > machine().time()) - { - LOG_PARTIAL_UPDATES(("skipped because frame was already rendered\n")); - return; - } - - LOG_PARTIAL_UPDATES(("update_now(): Y=%d, X=%d, last partial %d, partial hpos %d (vis %d %d)\n", current_vpos, current_hpos, m_last_partial_scan, m_partial_scan_hpos, m_visarea.right(), m_visarea.bottom())); // start off by doing a partial update up to the line before us, in case that was necessary if (current_vpos > m_last_partial_scan) { // if the line before us was incomplete, we must do it in two pieces - if (m_partial_scan_hpos > 0) + if (m_partial_scan_hpos >= 0) { // now finish the previous partial scanline - clip.set((std::max)(clip.left(), m_partial_scan_hpos), + clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1), clip.right(), (std::max)(clip.top(), m_last_partial_scan), (std::min)(clip.bottom(), m_last_partial_scan)); @@ -1346,8 +1263,6 @@ void screen_device::update_now() // if there's something to draw, do it if (!clip.empty()) { - auto profile = g_profiler.start(PROFILER_VIDEO); - u32 flags = 0; screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; if (m_video_attributes & VIDEO_VARIABLE_WIDTH) @@ -1376,7 +1291,7 @@ void screen_device::update_now() m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; } - m_partial_scan_hpos = 0; + m_partial_scan_hpos = -1; m_last_partial_scan++; } if (current_vpos > m_last_partial_scan) @@ -1386,49 +1301,42 @@ void screen_device::update_now() } // now draw this partial scanline - if (current_hpos > 0) - { - clip = m_visarea; + clip = m_visarea; - clip.set((std::max)(clip.left(), m_partial_scan_hpos), - (std::min)(clip.right(), current_hpos - 1), - (std::max)(clip.top(), current_vpos), - (std::min)(clip.bottom(), current_vpos)); + clip.set((std::max)(clip.left(), m_partial_scan_hpos + 1), + (std::min)(clip.right(), current_hpos), + (std::max)(clip.top(), current_vpos), + (std::min)(clip.bottom(), current_vpos)); - // and if there's something to draw, do it - if (!clip.empty()) + // and if there's something to draw, do it + if (!clip.empty()) + { + u32 flags = 0; + screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; + if (m_video_attributes & VIDEO_VARIABLE_WIDTH) { - auto profile = g_profiler.start(PROFILER_VIDEO); - - LOG_PARTIAL_UPDATES(("doing scanline partial draw: Y %d X %d-%d\n", clip.bottom(), clip.left(), clip.right())); - - u32 flags = 0; - screen_bitmap &curbitmap = m_bitmap[m_curbitmap]; - if (m_video_attributes & VIDEO_VARIABLE_WIDTH) + pre_update_scanline(current_vpos); + switch (curbitmap.format()) { - pre_update_scanline(current_vpos); - switch (curbitmap.format()) - { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; - } + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, *(bitmap_ind16 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, *(bitmap_rgb32 *)m_scan_bitmaps[m_curbitmap][current_vpos], clip); break; } - else + } + else + { + switch (curbitmap.format()) { - switch (curbitmap.format()) - { - default: - case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; - case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; - } + default: + case BITMAP_FORMAT_IND16: flags = m_screen_update_ind16(*this, curbitmap.as_ind16(), clip); break; + case BITMAP_FORMAT_RGB32: flags = m_screen_update_rgb32(*this, curbitmap.as_rgb32(), clip); break; } + } - m_partial_updates_this_frame++; + m_partial_updates_this_frame++; - // if we modified the bitmap, we have to commit - m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; - } + // if we modified the bitmap, we have to commit + m_changed |= ~flags & UPDATE_HAS_NOT_CHANGED; } // remember where we left off @@ -1444,9 +1352,8 @@ void screen_device::update_now() void screen_device::reset_partial_updates() { - m_last_partial_reset = machine().time(); m_last_partial_scan = 0; - m_partial_scan_hpos = 0; + m_partial_scan_hpos = -1; m_partial_updates_this_frame = 0; m_scanline0_timer->adjust(time_until_pos(0)); } @@ -1685,7 +1592,7 @@ void screen_device::register_screen_bitmap(bitmap_t &bitmap) // signal the VBLANK period has begun //------------------------------------------------- -TIMER_CALLBACK_MEMBER(screen_device::vblank_begin) +void screen_device::vblank_begin() { // reset the starting VBLANK time m_vblank_start_time = machine().time(); @@ -1705,7 +1612,7 @@ TIMER_CALLBACK_MEMBER(screen_device::vblank_begin) // if no VBLANK period, call the VBLANK end callback immediately, otherwise reset the timer if (m_vblank_period == 0) - vblank_end(0); + vblank_end(); else m_vblank_end_timer->adjust(time_until_vblank_end()); } @@ -1716,7 +1623,7 @@ TIMER_CALLBACK_MEMBER(screen_device::vblank_begin) // signal the VBLANK period has ended //------------------------------------------------- -TIMER_CALLBACK_MEMBER(screen_device::vblank_end) +void screen_device::vblank_end() { // call the screen specific callbacks for (auto &item : m_callback_list) @@ -1966,7 +1873,7 @@ void screen_device::finalize_burnin() //------------------------------------------------- -// load_effect_overlay - +// finalize_burnin - finalize the burnin bitmap //------------------------------------------------- void screen_device::load_effect_overlay(const char *filename) diff --git a/src/emu/screen.h b/src/emu/screen.h index 31451d9b..b909c25c 100644 --- a/src/emu/screen.h +++ b/src/emu/screen.h @@ -13,8 +13,6 @@ #pragma once -#include "rendertypes.h" - #include #include @@ -33,18 +31,28 @@ enum screen_type_enum SCREEN_TYPE_SVG }; +// texture formats +enum texture_format +{ + TEXFORMAT_UNDEFINED = 0, // require a format to be specified + TEXFORMAT_PALETTE16, // 16bpp palettized, no alpha + TEXFORMAT_RGB32, // 32bpp 8-8-8 RGB + TEXFORMAT_ARGB32, // 32bpp 8-8-8-8 ARGB + TEXFORMAT_YUY16 // 16bpp 8-8 Y/Cb, Y/Cr in sequence +}; + // screen_update callback flags -constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed +constexpr u32 UPDATE_HAS_NOT_CHANGED = 0x0001; // the video has not changed /*! @defgroup flags for video_attributes @{ @def VIDEO_UPDATE_BEFORE_VBLANK - update_video called at the start of the VBLANK period, this is the default + update_video called at the start of the VBLANK period @todo hack, remove me @def VIDEO_UPDATE_AFTER_VBLANK - update_video called at the end of the VBLANK period (in other words: before active display) + update_video called at the end of the VBLANK period @todo hack, remove me @def VIDEO_SELF_RENDER @@ -225,10 +233,9 @@ class screen_device : public device_t screen_device &set_raw(u32 pixclock, u16 htotal, u16 hbend, u16 hbstart, u16 vtotal, u16 vbend, u16 vbstart) { assert(pixclock != 0); - set_clock(pixclock); + m_clock = pixclock; m_refresh = HZ_TO_ATTOSECONDS(pixclock) * htotal * vtotal; m_vblank = m_refresh / vtotal * (vtotal - (vbstart - vbend)); - m_oldstyle_vblank_supplied = false; m_width = htotal; m_height = vtotal; m_visarea.set(hbend, hbstart ? hbstart - 1 : htotal - 1, vbend, vbstart - 1); @@ -239,10 +246,6 @@ class screen_device : public device_t xtal.validate(std::string("Configuring screen ") + tag()); return set_raw(xtal.value(), htotal, hbend, hbstart, vtotal, vbend, vbstart); } - screen_device &set_raw(const XTAL &xtal, u16 htotal, u16 vtotal, rectangle visarea) - { - return set_raw(xtal, htotal, visarea.left(), visarea.right() + 1, vtotal, visarea.top(), visarea.bottom() + 1); - } void set_refresh(attoseconds_t rate) { m_refresh = rate; } /// \brief Set refresh rate in Hertz @@ -386,8 +389,8 @@ class screen_device : public device_t // beam positioning and state int vpos() const; int hpos() const; - int vblank() const { return (machine().time() < m_vblank_end_time) ? 1 : 0; } - int hblank() const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER(vblank) const { return (machine().time() < m_vblank_end_time) ? 1 : 0; } + DECLARE_READ_LINE_MEMBER(hblank) const { int const curpos = hpos(); return (curpos < m_visarea.left() || curpos > m_visarea.right()) ? 1 : 0; } // timing attotime time_until_pos(int vpos, int hpos = 0) const; @@ -425,22 +428,30 @@ class screen_device : public device_t private: class svg_renderer; + // timer IDs + enum + { + TID_VBLANK_START, + TID_VBLANK_END, + TID_SCANLINE0, + TID_SCANLINE + }; + // device-level overrides virtual void device_validity_check(validity_checker &valid) const override; virtual void device_config_complete() override; - virtual void device_resolve_objects() override ATTR_COLD; - virtual void device_start() override ATTR_COLD; - virtual void device_reset() override ATTR_COLD; - virtual void device_stop() override ATTR_COLD; + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_stop() override; virtual void device_post_load() override; + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; // internal helpers void set_container(render_container &container) { m_container = &container; } void realloc_screen_bitmaps(); - TIMER_CALLBACK_MEMBER(vblank_begin); - TIMER_CALLBACK_MEMBER(vblank_end); - TIMER_CALLBACK_MEMBER(first_scanline_tick); - TIMER_CALLBACK_MEMBER(scanline_tick); + void vblank_begin(); + void vblank_end(); void finalize_burnin(); void load_effect_overlay(const char *filename); void update_scan_bitmap_size(int y); @@ -462,7 +473,7 @@ class screen_device : public device_t screen_update_rgb32_delegate m_screen_update_rgb32; // screen update callback (32-bit RGB) devcb_write_line m_screen_vblank; // screen vblank line callback devcb_write32 m_scanline_cb; // screen scanline callback - optional_device m_palette; // our palette + optional_device m_palette; // our palette u32 m_video_attributes; // flags describing the video system optional_memory_region m_svg_region; // the region in which the svg data is in @@ -486,7 +497,6 @@ class screen_device : public device_t u8 m_curbitmap; // current bitmap index u8 m_curtexture; // current texture index bool m_changed; // has this bitmap changed? - attotime m_last_partial_reset; // last time partial updates were reset s32 m_last_partial_scan; // scanline of last partial update s32 m_partial_scan_hpos; // horizontal pixel last rendered on this partial scanline bitmap_argb32 m_screen_overlay_bitmap; // screen overlay bitmap @@ -506,7 +516,7 @@ class screen_device : public device_t emu_timer * m_scanline0_timer; // scanline 0 timer emu_timer * m_scanline_timer; // scanline timer u64 m_frame_number; // the current frame number - u32 m_partial_updates_this_frame; // partial update counter this frame + u32 m_partial_updates_this_frame;// partial update counter this frame bool m_is_primary_screen; @@ -519,7 +529,7 @@ class screen_device : public device_t vblank_state_delegate m_callback; }; - std::vector> m_callback_list; // list of VBLANK callbacks + std::vector> m_callback_list; // list of VBLANK callbacks // auto-sizing bitmaps class auto_bitmap_item From eafd9df770e6befeff63b37a146b2d28025caea7 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:51:33 -0600 Subject: [PATCH 32/47] Revert updates. This reverts commit bf2d3c85a97139bb63676b009b11c79dff3de465. --- src/osd/modules/monitor/monitor_retro.cpp | 53 ++++++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/src/osd/modules/monitor/monitor_retro.cpp b/src/osd/modules/monitor/monitor_retro.cpp index 4b35d7ac..da880532 100644 --- a/src/osd/modules/monitor/monitor_retro.cpp +++ b/src/osd/modules/monitor/monitor_retro.cpp @@ -2,12 +2,12 @@ * monitor_retro.cpp * */ +#include "emu.h" #include "modules/osdmodule.h" #include "monitor_module.h" #include "modules/osdwindow.h" #include "monitor_common.h" -#include "osdcore.h" #include "libretro/libretro-internal/libretro_shared.h" @@ -27,10 +27,16 @@ class retro_monitor_info : public osd_monitor_info private: void refresh() override { + m_pos_size = osd_rect(0,0, fb_width, fb_height); m_usuable_pos_size = osd_rect(0,0, fb_width, fb_height); m_is_primary = (oshandle() == 0); + + if(alternate_renderer==false) + set_aspect(retro_aspect); + //printf("refreshmonitor (%d x %d) a:%f\n", fb_width, fb_height,retro_aspect); } + }; //============================================================ @@ -82,29 +88,52 @@ class retro_monitor_module : public monitor_module_base protected: int init_internal(const osd_options& options) override { - int i; - - for (i = 0; i < 1; i++) + // make a list of monitors { - char temp[64]; - snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); + int i; + + osd_printf_verbose("Enter init_monitors\n"); - // allocate a new monitor info - std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); + for (i = 0; i < 1; i++) + { + char temp[64]; + snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); - // guess the aspect ratio assuming square pixels - monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); + // allocate a new monitor info + std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); - // hook us into the list - add_monitor(monitor); + osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename().c_str(), + monitor->position_size().width(), monitor->position_size().height()); + + // guess the aspect ratio assuming square pixels + monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); +printf("Adding monitor %s (%d x %d) a:%f\n", monitor->devicename().c_str(), + monitor->position_size().width(), monitor->position_size().height(),(float)monitor->position_size().width()/(float) monitor->position_size().height()); + + // hook us into the list + add_monitor(monitor); + } } + osd_printf_verbose("Leave init_monitors\n"); return 0; } private: +/* + sdl.h = osd.height(); + sdl.w = osd.width(); + sdl.x = osd.left(); + sdl.y = osd.top(); + +*/ static int compute_intersection(const osd_rect &rect1, const osd_rect &rect2) { +/* + SDL_Rect intersection; + if (SDL_IntersectRect(&sdl1, &sdl2, &intersection)) + return intersection.w + intersection.h; +*/ return 0; } }; From 0ef0f64bf54d4eae26b7dedff3ee8e943a37da8a Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 14:59:55 -0600 Subject: [PATCH 33/47] Update monitor_retro.cpp --- src/osd/modules/monitor/monitor_retro.cpp | 53 +++++------------------ 1 file changed, 12 insertions(+), 41 deletions(-) diff --git a/src/osd/modules/monitor/monitor_retro.cpp b/src/osd/modules/monitor/monitor_retro.cpp index da880532..4b35d7ac 100644 --- a/src/osd/modules/monitor/monitor_retro.cpp +++ b/src/osd/modules/monitor/monitor_retro.cpp @@ -2,12 +2,12 @@ * monitor_retro.cpp * */ -#include "emu.h" #include "modules/osdmodule.h" #include "monitor_module.h" #include "modules/osdwindow.h" #include "monitor_common.h" +#include "osdcore.h" #include "libretro/libretro-internal/libretro_shared.h" @@ -27,16 +27,10 @@ class retro_monitor_info : public osd_monitor_info private: void refresh() override { - m_pos_size = osd_rect(0,0, fb_width, fb_height); m_usuable_pos_size = osd_rect(0,0, fb_width, fb_height); m_is_primary = (oshandle() == 0); - - if(alternate_renderer==false) - set_aspect(retro_aspect); - //printf("refreshmonitor (%d x %d) a:%f\n", fb_width, fb_height,retro_aspect); } - }; //============================================================ @@ -88,52 +82,29 @@ class retro_monitor_module : public monitor_module_base protected: int init_internal(const osd_options& options) override { - // make a list of monitors - { - int i; - - osd_printf_verbose("Enter init_monitors\n"); + int i; - for (i = 0; i < 1; i++) - { - char temp[64]; - snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); - - // allocate a new monitor info - std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); + for (i = 0; i < 1; i++) + { + char temp[64]; + snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); - osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename().c_str(), - monitor->position_size().width(), monitor->position_size().height()); + // allocate a new monitor info + std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); - // guess the aspect ratio assuming square pixels - monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); -printf("Adding monitor %s (%d x %d) a:%f\n", monitor->devicename().c_str(), - monitor->position_size().width(), monitor->position_size().height(),(float)monitor->position_size().width()/(float) monitor->position_size().height()); + // guess the aspect ratio assuming square pixels + monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); - // hook us into the list - add_monitor(monitor); - } + // hook us into the list + add_monitor(monitor); } - osd_printf_verbose("Leave init_monitors\n"); return 0; } private: -/* - sdl.h = osd.height(); - sdl.w = osd.width(); - sdl.x = osd.left(); - sdl.y = osd.top(); - -*/ static int compute_intersection(const osd_rect &rect1, const osd_rect &rect2) { -/* - SDL_Rect intersection; - if (SDL_IntersectRect(&sdl1, &sdl2, &intersection)) - return intersection.w + intersection.h; -*/ return 0; } }; From 3eaafc91f921d24d85817395ff37809fd2d5d45c Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 15:06:09 -0600 Subject: [PATCH 34/47] Update monitor_retro.cpp --- src/osd/modules/monitor/monitor_retro.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/osd/modules/monitor/monitor_retro.cpp b/src/osd/modules/monitor/monitor_retro.cpp index 4b35d7ac..cd2bbaf5 100644 --- a/src/osd/modules/monitor/monitor_retro.cpp +++ b/src/osd/modules/monitor/monitor_retro.cpp @@ -2,12 +2,12 @@ * monitor_retro.cpp * */ +#include "emu.h" #include "modules/osdmodule.h" #include "monitor_module.h" #include "modules/osdwindow.h" #include "monitor_common.h" -#include "osdcore.h" #include "libretro/libretro-internal/libretro_shared.h" From b951581e2f2b0b5522bdf1161a0038e1f3326f72 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 15:34:50 -0600 Subject: [PATCH 35/47] Revert mcd212 driver update. Will pick changes by hand. --- src/mame/video/mcd212.cpp | 1008 ++++++++++++++++++++++++------------- src/mame/video/mcd212.h | 166 +++--- 2 files changed, 727 insertions(+), 447 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index f69e5786..4de847dd 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -17,7 +17,7 @@ TODO: -- QHY DYUV Image Decoder +- Unknown yet. *******************************************************************************/ @@ -25,77 +25,195 @@ #include "mcd212.h" #include "screen.h" +#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") -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t matte_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t region_idx) { - return (uint8_t)((m_matte_control[matte_idx] & MC_WF) >> MC_WF_SHIFT); + return (uint8_t)((m_region_control[region_idx] & RC_WF) >> RC_WF_SHIFT); } -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_matte_op(const uint32_t matte_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_region_op(const uint32_t region_idx) { - return (m_matte_control[matte_idx] & MC_OP) >> MC_OP_SHIFT; + return (m_region_control[region_idx] & RC_OP) >> RC_OP_SHIFT; } -void mcd212_device::update_matte_arrays() +void mcd212_device::update_region_arrays() { + bool latched_rf[2] { false, false }; + uint8_t latched_wfa = m_weight_factor[0][0]; + uint8_t latched_wfb = m_weight_factor[1][0]; const int width = get_screen_width(); - const int num_mattes = BIT(m_image_coding_method, ICM_NM_BIT) ? 2 : 1; - - bool latched_mf[2]{ false, false }; - uint8_t latched_wf[2] = { m_weight_factor[0][0], m_weight_factor[1][0] }; - int matte_idx[2] = { 0, 4 }; - for (int x = 0; x < width; x++) + if (BIT(m_image_coding_method, ICM_NR_BIT)) { - for (int matte = 0; matte < num_mattes; matte++) + if (get_region_op(0) == 0 && get_region_op(4) == 0) + { + 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 < width; x++) { - const int max_matte_id = ((num_mattes == 2) ? 4 : 8) + (matte ? 4 : 0); - if (matte_idx[matte] >= max_matte_id) + for (int flag = 0; flag < 2; flag++) { - continue; + for (int region = 0; region < 4; region++) + { + 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 == (region_ctrl & RC_X)) + { + switch (region_op) + { + case 0: // End of region control for line + break; + case 1: + case 2: + case 3: // Not used + break; + case 4: // Change weight of plane A + latched_wfa = get_weight_factor(region_idx); + break; + case 5: // Not used + break; + case 6: // Change weight of plane B + latched_wfb = get_weight_factor(region_idx); + break; + case 7: // Not used + break; + case 8: // Reset region flag + latched_rf[flag] = false; + break; + case 9: // Set region flag + 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 = get_weight_factor(region_idx); + latched_rf[flag] = false; + break; + case 13: // Set region flag and change weight of plane A + 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 = get_weight_factor(region_idx); + latched_rf[flag] = false; + break; + case 15: // Set region flag and change weight of plane B + latched_wfb = get_weight_factor(region_idx); + latched_rf[flag] = true; + break; + } + } + } } - const uint32_t matte_ctrl = m_matte_control[matte_idx[matte]]; - - if (x == (matte_ctrl & MC_X)) + 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 + { + int region_idx = 0; + for (int x = 0; x < width; x++) + { + if (region_idx < 8) { - const uint32_t matte_op = get_matte_op(matte_idx[matte]); - const int flag = (num_mattes == 2) ? matte : BIT(m_matte_control[matte_idx[matte]], MC_MF_BIT); - // See 5.10.2 Matte Commands. Changing the MF-bit inside a line is undefined. Greenbook says don't do it. - // Console validation shows the 220 reads and uses this value anyway. - switch (matte_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) { - case 0: // Disregard all commands in higher registers. See 5.10.2 - matte_idx[matte] = 8; - break; - case 1: case 2: case 3: case 5: case 7: case 10: case 11: // Not used - break; - case 4: case 6: // Change weight of plane (A or B) - latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); - break; - case 8: case 9: // (Reset or Set) matte flag - latched_mf[flag] = BIT(matte_op, 0); - break; - case 12: case 13: case 14: case 15: // Change weight of plane (A or B) and (Reset or Set) matte flag - latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); - latched_mf[flag] = BIT(matte_op, 0); - 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, latched_rf[0]); + std::fill_n(m_region_flag[1] + x, std::size(m_region_flag[1]) - x, latched_rf[1]); + return; + } + if (x == (region_ctrl & RC_X)) + { + switch (region_op) + { + case 0: // End of region control for line + break; + case 1: + case 2: + case 3: // Not used + break; + case 4: // Change weight of plane A + latched_wfa = get_weight_factor(region_idx); + break; + case 5: // Not used + break; + case 6: // Change weight of plane B + latched_wfb = get_weight_factor(region_idx); + break; + case 7: // Not used + break; + case 8: // Reset region flag + latched_rf[flag] = false; + break; + case 9: // Set region flag + 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 = get_weight_factor(region_idx); + latched_rf[flag] = false; + break; + case 13: // Set region flag and change weight of plane A + 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 = get_weight_factor(region_idx); + latched_rf[flag] = false; + break; + case 15: // Set region flag and change weight of plane B + latched_wfb = get_weight_factor(region_idx); + latched_rf[flag] = true; + break; + } + region_idx++; } - matte_idx[matte]++; } + 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_weight_factor[0][x] = latched_wf[0]; - m_weight_factor[1][x] = latched_wf[1]; - m_matte_flag[0][x] = latched_mf[0]; - m_matte_flag[1][x] = latched_mf[1]; } } -template +template void mcd212_device::set_register(uint8_t reg, uint32_t value) { switch (reg) @@ -109,86 +227,86 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) 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: { - const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); + const uint8_t clut_index = m_clut_bank[Channel] * 0x40 + (reg - 0x80); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method - if (Path == 0) + if (Channel == 0) { m_image_coding_method = value; } break; case 0xc1: // Transparency Control - if (Path == 0) + if (Channel == 0) { m_transparency_control = value; } break; case 0xc2: // Plane Order - if (Path == 0) + if (Channel == 0) { m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register - m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); + m_clut_bank[Channel] = Channel ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A - if (Path == 0) + if (Channel == 0) { m_transparent_color[0] = value & 0x00fcfcfc; } break; case 0xc6: // Transparent Color B - if (Path == 1) + if (Channel == 1) { m_transparent_color[1] = value & 0x00fcfcfc; } break; case 0xc7: // Mask Color A - if (Path == 0) + if (Channel == 0) { m_mask_color[0] = value & 0x00fcfcfc; } break; case 0xc9: // Mask Color B - if (Path == 1) + if (Channel == 1) { m_mask_color[1] = value & 0x00fcfcfc; } break; case 0xca: // Delta YUV Absolute Start Value A - if (Path == 0) + if (Channel == 0) { m_dyuv_abs_start[0] = value; } break; case 0xcb: // Delta YUV Absolute Start Value B - if (Path == 1) + if (Channel == 1) { m_dyuv_abs_start[1] = value; } break; case 0xcd: // Cursor Position - if (Path == 0) + if (Channel == 0) { m_cursor_position = value; } break; case 0xce: // Cursor Control - if (Path == 0) + if (Channel == 0) { m_cursor_control = value; } break; case 0xcf: // Cursor Pattern - if (Path == 0) + if (Channel == 0) { m_cursor_pattern[(value >> 16) & 0x000f] = value & 0x0000ffff; } break; - case 0xd0: // matte Control 0-7 + case 0xd0: // Region Control 0-7 case 0xd1: case 0xd2: case 0xd3: @@ -196,79 +314,79 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xd5: case 0xd6: case 0xd7: - m_matte_control[reg & 7] = value; - update_matte_arrays(); + m_region_control[reg & 7] = value; + update_region_arrays(); break; case 0xd8: // Backdrop Color - if (Path == 0) + if (Channel == 0) { m_backdrop_color = value; } break; case 0xd9: // Mosaic Pixel Hold Factor A - if (Path == 0) + if (Channel == 0) { m_mosaic_hold[0] = value; } break; case 0xda: // Mosaic Pixel Hold Factor B - if (Path == 1) + if (Channel == 1) { m_mosaic_hold[1] = value; } break; case 0xdb: // Weight Factor A - if (Path == 0) + if (Channel == 0) { m_weight_factor[0][0] = (uint8_t)value; - update_matte_arrays(); + update_region_arrays(); } break; case 0xdc: // Weight Factor B - if (Path == 1) + if (Channel == 1) { m_weight_factor[1][0] = (uint8_t)value; - update_matte_arrays(); + update_region_arrays(); } break; } } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr() { - return ((m_dcr[Path] & 0x3f) << 16) | m_vsr[Path]; + return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_vsr(uint32_t value) { - m_vsr[Path] = value & 0x0000ffff; - m_dcr[Path] &= 0xffc0; - m_dcr[Path] |= (value >> 16) & 0x003f; + m_vsr[Channel] = value & 0x0000ffff; + m_dcr[Channel] &= 0xffc0; + m_dcr[Channel] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_dcp(uint32_t value) { - m_dcp[Path] = value & 0x0000ffff; - m_ddr[Path] &= 0xffc0; - m_ddr[Path] |= (value >> 16) & 0x003f; + m_dcp[Channel] = value & 0x0000ffff; + m_ddr[Channel] &= 0xffc0; + m_ddr[Channel] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_dcp() { - return ((m_ddr[Path] & 0x3f) << 16) | m_dcp[Path]; + return ((m_ddr[Channel] & 0x3f) << 16) | m_dcp[Channel]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t value) { - m_ddr[Path] &= 0xf0ff; - m_ddr[Path] |= (value & 0x0f) << 8; - m_dcr[Path] &= 0xf7ff; - m_dcr[Path] |= (value & 0x10) << 7; + m_ddr[Channel] &= 0xf0ff; + m_ddr[Channel] |= (value & 0x0f) << 8; + m_dcr[Channel] &= 0xf7ff; + m_dcr[Channel] |= (value & 0x10) << 7; } int mcd212_device::get_screen_width() @@ -287,18 +405,10 @@ int mcd212_device::get_border_width() return width; } -uint32_t mcd212_device::get_backdrop_plane() -{ - if (BIT(m_image_coding_method, ICM_EV_BIT)) - return 0; // External Video Background. Default to Black since there is no DVC. - else - return s_4bpp_color[m_backdrop_color]; -} - -template +template void mcd212_device::process_ica() { - uint16_t *ica = Path ? m_planeb.target() : m_planea.target(); + uint16_t *ica = Channel ? m_planeb.target() : m_planea.target(); uint32_t addr = 0x200; uint32_t cmd = 0; @@ -317,11 +427,11 @@ void mcd212_device::process_ica() 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: - set_dcp(cmd & 0x003ffffc); + 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: - set_dcp(cmd & 0x003ffffc); + 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: @@ -329,36 +439,35 @@ void mcd212_device::process_ica() 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: - set_vsr(cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Path); + 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 - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } } -template +template void mcd212_device::process_dca() { - uint16_t *dca = Path ? m_planeb.target() : m_planea.target(); - uint32_t addr = (m_dca[Path] & 0x0007ffff) / 2; + 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; bool addr_changed = false; bool processing = true; - while (processing && count < max) { cmd = dca[addr++] << 16; @@ -372,34 +481,34 @@ void mcd212_device::process_dca() 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: - 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: 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: - set_dcp(cmd & 0x003ffffc); - m_dca[Path] = cmd & 0x0007fffc; + 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: + 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: - set_vsr(cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Path); + 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 - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } @@ -409,184 +518,323 @@ void mcd212_device::process_dca() addr += (max - count) >> 1; } - m_dca[Path] = addr * 2; + m_dca[Channel] = addr * 2; } -template -static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) +template +static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) { switch (icm) { - case 1: - return byte; - case 3: - return (Path ? 0x80 : 0) | (byte & 0x7f); - case 4: - if (Path == 0) - { - return (clut_select ? 0x80 : 0) | (byte & 0x7f); - } - break; - case 11: - return (Path ? 0x80 : 0) | (byte & 0x0f); - default: - break; + case 1: + return byte; + case 3: + if (Channel == 1) + { + return 0x80 + (byte & 0x7f); + } + else + { + return byte & 0x7f; + } + case 4: + if (Channel == 0) + { + return byte & 0x7f; + } + break; + case 11: + if (Channel == 1) + { + return 0x80 + (byte & 0x0f); + } + else + { + return byte & 0x0f; + } + default: + break; } return 0; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control() { - return (m_transparency_control >> (Path ? 8 : 0)) & 0x0f; + return (m_transparency_control >> (Channel ? 8 : 0)) & 0x0f; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_icm() { - const uint32_t mask = Path ? ICM_MODE2 : ICM_MODE1; - const uint32_t shift = Path ? ICM_MODE2_SHIFT : ICM_MODE1_SHIFT; + 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 +template inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable() { - return (m_ddr[Path] & DDR_FT) == DDR_FT_MOSAIC; + return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() { - return 1 << (((m_ddr[Path] & DDR_MT) >> DDR_MT_SHIFT) + 1); + return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); } -template -void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) +template +int mcd212_device::get_plane_width() { - const uint8_t *data = reinterpret_cast(Path ? m_planeb.target() : m_planea.target()); - const uint8_t *data2 = reinterpret_cast(!Path ? m_planeb.target() : m_planea.target()); - const uint8_t icm = get_icm(); - const uint8_t tp_ctrl = get_transparency_control(); const int width = get_screen_width(); + const uint8_t icm = get_icm(); + if (icm == ICM_CLUT4) + return width; + return width >> 1; +} - uint32_t vsr = get_vsr(); - uint32_t vsr2 = get_vsr(); +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 uint8_t transp_ctrl = get_transparency_control(); + const int width = get_plane_width(); - if (tp_ctrl == TCR_ALWAYS || !icm || !vsr) + uint32_t vsr = get_vsr(); + + if (transp_ctrl == TCR_COND_1) { - std::fill_n(pixels, get_screen_width(), s_4bpp_color[0]); + std::fill_n(pixels, get_screen_width(), 0x00101010); std::fill_n(transparent, get_screen_width(), true); return; } - const uint32_t decodingMode = m_ddr[Path] & DDR_FT; + if (!icm || !vsr) + { + std::fill_n(pixels, get_screen_width(), 0x00101010); + return; + } - const uint8_t mosaic_enable = get_mosaic_enable(); - const uint8_t mosaic_factor = get_mosaic_factor(); + 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[Path]; - uint8_t y = (dyuv_abs_start >> 16) & 0x000000ff; - uint8_t u = (dyuv_abs_start >> 8) & 0x000000ff; - uint8_t v = (dyuv_abs_start >> 0) & 0x000000ff; + 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 mask_bits = (~m_mask_color[Path]) & 0x00fcfcfc; - const uint32_t tp_color_match = m_transparent_color[Path] & mask_bits; - const uint8_t tp_ctrl_type = tp_ctrl & 0x07; + 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); - const bool use_rgb_tp_bit = (tp_ctrl_type == TCR_RGB); - const bool tp_check_parity = !BIT(tp_ctrl, 3); - const bool tp_always = ((tp_ctrl_type == TCR_ALWAYS) && tp_check_parity); - const int matte_flag_index = BIT(~tp_ctrl_type, 0); - const bool *const matte_flags = m_matte_flag[matte_flag_index]; - const bool use_matte_flag = (tp_ctrl_type >= TCR_MF0 && tp_ctrl_type <= TCR_MF1_KEY1); - const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. - const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); + bool done = false; + int x = 0; - for (uint32_t x = 0; x < width; ) + while (!done) { - const uint8_t byte = data[(vsr++ & 0x0007ffff) ^ 1]; - uint32_t color0 = 0; - uint32_t color1 = 0; - bool rgb_tp_bit = false; - if (icm == ICM_DYUV) + uint8_t byte = data[(vsr & 0x0007ffff) ^ 1]; + vsr++; + switch (m_ddr[Channel] & DDR_FT) { - const uint8_t byte1 = data[(vsr++ & 0x0007ffff) ^ 1]; - const uint8_t y2 = y + m_delta_y_lut[byte]; - y = y2 + m_delta_y_lut[byte1]; - u += m_delta_uv_lut[byte]; - v += m_delta_uv_lut[byte1]; - - const uint32_t *limit_rgb = m_dyuv_limit_lut + y2 + 0x100; - const uint32_t *limit_rgb2 = m_dyuv_limit_lut + y + 0x100; - - color0 = (limit_rgb[m_dyuv_v_to_r[v]] << 16) | (limit_rgb[m_dyuv_u_to_g[u] + m_dyuv_v_to_g[v]] << 8) | limit_rgb[m_dyuv_u_to_b[u]]; - - const uint8_t byte2 = data[(vsr & 0x0007ffff) ^ 1]; // Peek ahead, for calculating the half-step. - const uint8_t byte3 = data[((vsr + 1) & 0x0007ffff) ^ 1]; - const uint8_t u8 = u + m_delta_uv_lut[byte2]; - const uint8_t v8 = v + m_delta_uv_lut[byte3]; - const uint8_t u6 = (u >> 1) + (u8 >> 1) + (u & u8 & 1); - const uint8_t v6 = (v >> 1) + (v8 >> 1) + (v & v8 & 1); - - color1 = (limit_rgb2[m_dyuv_v_to_r[v6]] << 16) | (limit_rgb2[m_dyuv_u_to_g[u6] + m_dyuv_v_to_g[v6]] << 8) | limit_rgb2[m_dyuv_u_to_b[u6]]; - - // TODO: Does not support QHY - pixels[x] = color0; - pixels[x + 1] = color0; - pixels[x + 2] = color1; - pixels[x + 3] = color1; - transparent[x ] = tp_always || (use_matte_flag && (matte_flags[x ] == tp_check_parity)); - transparent[x + 1] = tp_always || (use_matte_flag && (matte_flags[x + 1] == tp_check_parity)); - transparent[x + 2] = tp_always || (use_matte_flag && (matte_flags[x + 2] == tp_check_parity)); - transparent[x + 3] = tp_always || (use_matte_flag && (matte_flags[x + 3] == tp_check_parity)); - x += 4; + case DDR_FT_BMP: + case DDR_FT_BMP2: + case DDR_FT_MOSAIC: + if (icm == ICM_DYUV) + { + use_color_key = false; + + uint8_t y = start_y; + uint8_t u = start_u; + uint8_t v = start_v; + for (; x < width; x++) + { + 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]; + + const uint8_t v1 = v + m_delta_uv_lut[byte1]; + const uint8_t y1 = y0 + m_delta_y_lut[byte1]; + + const uint8_t u0 = (u + u1) >> 1; + const uint8_t v0 = (v + v1) >> 1; + + 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; + + 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] = entry; + transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + + if (mosaic_enable) + { + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) + { + pixels[x + mosaic_index] = pixels[x]; + transparent[x + mosaic_index] = transparent[x << 1]; + } + x += mosaic_factor; + } + else + { + x++; + } + + 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; + + 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] = entry; + transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + + if (mosaic_enable) + { + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) + { + pixels[x + mosaic_index] = pixels[x]; + transparent[x + mosaic_index] = transparent[x]; + } + x += mosaic_factor - 1; + } + + byte = data[(vsr++ & 0x0007ffff) ^ 1]; + + y = y1; + u = u1; + v = v1; + } + set_vsr(vsr - 1); + } + else if (icm == ICM_CLUT8 || icm == ICM_CLUT7 || icm == ICM_CLUT77) + { + for (; x < width; x++) + { + uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; + pixels[x] = entry; + transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + if (mosaic_enable) + { + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) + { + pixels[x + mosaic_index] = pixels[x]; + transparent[x + mosaic_index] = transparent[x]; + } + x += mosaic_factor - 1; + } + byte = data[(vsr & 0x0007ffff) ^ 1]; + vsr++; + } + set_vsr(vsr - 1); + } + else if (icm == ICM_CLUT4) + { + for (; x < width - 1; x += 2) + { + 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 (int mosaic_index = 0; mosaic_index < mosaic_factor && (x + mosaic_index) < (width - 1); mosaic_index += 2) + { + pixels[x + mosaic_index] = even_entry; + transparent[x + mosaic_index] = (even_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition; + pixels[x + mosaic_index + 1] = odd_entry; + transparent[x + mosaic_index + 1] = (odd_pre_transparent || (use_region_flag && region_flags[x + mosaic_index + 1])) != invert_transp_condition; + } + x += mosaic_factor - 2; + } + else + { + 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(vsr - 1); + } + else + { + std::fill_n(pixels + x, width - x, 0x00101010); + std::fill_n(transparent + x, width - x, true); + } + done = true; + break; + case DDR_FT_RLE: + if (byte & 0x80) + { + // Run length + uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1]; + 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) + { + // Go to the end of the line + std::fill_n(pixels + x, width - x, entry); + for (int transp_index = x; transp_index < width; transp_index++) + { + transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; + } + done = true; + set_vsr(vsr); + } + else + { + int end = std::min(width, x + length); + std::fill_n(pixels + x, end - x, entry); + for (int transp_index = x; transp_index < end; transp_index++) + { + transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; + } + x = end; + if (x >= width) + { + done = true; + set_vsr(vsr); + } + } + } + else + { + // Single pixel + 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 << 1])) != invert_transp_condition; + x++; + + if (x >= width) + { + done = true; + set_vsr(vsr); + } + } + break; } - else - { - bool clut_select = BIT(m_image_coding_method, ICM_CS_BIT); - if (icm == ICM_RGB555 && Path == 1) - { - const uint8_t byte1 = data2[(vsr2++ & 0x0007ffff) ^ 1]; - const uint8_t blue = (byte & 0b11111) << 3; - const uint8_t green = ((byte & 0b11100000) >> 2) + ((byte1 & 0b11) << 6); - const uint8_t red = (byte1 & 0b01111100) << 1; - rgb_tp_bit = (use_rgb_tp_bit && (BIT(byte1,7) == tp_check_parity)); - color1 = color0 = (uint32_t(red) << 16) | (uint32_t(green) << 8) | blue; - } - else if (icm == ICM_CLUT4) - { - const uint8_t mask = (decodingMode == DDR_FT_RLE) ? 0x7 : 0xf; - color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; - color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; - } - else - { - color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; - } - - int length_m = mosaic_enable ? (mosaic_factor * 2) : 2; - if (decodingMode == DDR_FT_RLE) - { - const uint16_t length = (byte & 0x80) ? data[((vsr++) & 0x0007ffff) ^ 1] : 1; - length_m = length ? (length * 2) : width; - } + } - const bool color_match0 = ((mask_bits & color0) == tp_color_match) == tp_check_parity; - const bool color_match1 = ((mask_bits & color1) == tp_color_match) == tp_check_parity; - const int end = std::min(width, x + length_m); - for (int rl_index = x; rl_index < end; rl_index += 2) - { - pixels[rl_index ] = color0; - pixels[rl_index + 1] = color1; - transparent[rl_index ] = tp_always || rgb_tp_bit || (use_color_key && color_match0) || (use_matte_flag && (matte_flags[rl_index ] == tp_check_parity)); - transparent[rl_index + 1] = tp_always || rgb_tp_bit || (use_color_key && color_match1) || (use_matte_flag && (matte_flags[rl_index + 1] == tp_check_parity)); - } - x = end; + if (icm != ICM_CLUT4) + { + for (int i = width - 1; i >= 0; i--) + { + pixels[i * 2] = pixels[i * 2 + 1] = pixels[i]; + transparent[i * 2] = transparent[i * 2 + 1] = transparent[i]; } } - set_vsr(vsr); - set_vsr(vsr2); } const uint32_t mcd212_device::s_4bpp_color[16] = @@ -598,110 +846,152 @@ const uint32_t mcd212_device::s_4bpp_color[16] = template void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out) { - const uint8_t icmA = get_icm<0>(); - const uint8_t icmB = get_icm<1>(); - uint16_t mosaic_count_a = (m_mosaic_hold[0] & 0x0000ff) << 1; - uint16_t mosaic_count_b = (m_mosaic_hold[1] & 0x0000ff) << 1; + 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; const int width = get_screen_width(); const int border_width = get_border_width(); uint8_t *weight_a = &m_weight_factor[0][0]; uint8_t *weight_b = &m_weight_factor[1][0]; - // Console Verified. CLUT4 pixels are drawn in pairs during VSR. So the mosaic here is halved. - if (icmA == ICM_CLUT4) - mosaic_count_a >>= 1; - if (icmB == ICM_CLUT4) - mosaic_count_b >>= 1; - - for (int x = 0; x < width; x++) + if (!(m_transparency_control & TCR_DISABLE_MX)) { - if (transparent_a[x] && transparent_b[x]) + for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) { - out[x] = get_backdrop_plane(); - continue; + 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++ = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; } - uint32_t plane_a_cur = MosaicA ? plane_a[x - (x % mosaic_count_a)] : plane_a[x]; - uint32_t plane_b_cur = MosaicB ? plane_b[x - (x % mosaic_count_b)] : plane_b[x]; - - if (transparent_a[x]) - { - plane_a_cur = 0; - } - else if (OrderAB && (m_transparency_control & TCR_DISABLE_MX)) - { - plane_b_cur = 0; - } - - if (transparent_b[x]) - { - plane_b_cur = 0; - } - else if (!OrderAB && (m_transparency_control & TCR_DISABLE_MX)) + } + else + { + for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) { - plane_a_cur = 0; + if (OrderAB) + { + 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; + } + else + { + *out++ = backdrop; + } + } + 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; + } + else + { + *out++ = backdrop; + } + } } - - const int32_t plane_a_r = 0xff & (plane_a_cur >> 16); - const int32_t plane_a_g = 0xff & (plane_a_cur >> 8); - const int32_t plane_a_b = 0xff & plane_a_cur; - const int32_t plane_b_r = 0xff & (plane_b_cur >> 16); - const int32_t plane_b_g = 0xff & (plane_b_cur >> 8); - const int32_t plane_b_b = 0xff & plane_b_cur; - - const int32_t weighted_a_r = std::clamp((std::clamp(plane_a_r - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); - const int32_t weighted_a_g = std::clamp((std::clamp(plane_a_g - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); - const int32_t weighted_a_b = std::clamp((std::clamp(plane_a_b - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); - - const int32_t weighted_b_r = std::clamp((std::clamp(plane_b_r - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); - const int32_t weighted_b_g = std::clamp((std::clamp(plane_b_g - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); - const int32_t weighted_b_b = std::clamp((std::clamp(plane_b_b - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); - - const uint8_t out_r = std::clamp(weighted_a_r + weighted_b_r + 16, 0, 255); - const uint8_t out_g = std::clamp(weighted_a_g + weighted_b_g + 16, 0, 255); - const uint8_t out_b = std::clamp(weighted_a_b + weighted_b_b + 16, 0, 255); - out[x] = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; } if (border_width) { - std::fill_n(&out[width], border_width, s_4bpp_color[0]); + std::fill_n(out, border_width, 0xff101010); } } void mcd212_device::draw_cursor(uint32_t *scanline) { - if (!(m_cursor_control & CURCNT_EN)) - return; // Cursor is Disabled - - uint8_t color_index = m_cursor_control & CURCNT_COLOR; - if (m_blink_active) + if (m_cursor_control & CURCNT_EN) { - const bool invert = BIT(m_cursor_control, CURCNT_BLKC_SHIFT); - if (!invert) - return; // Normal Blink - else - color_index = color_index ^ 0x7; // Inverted Color Blink. MCD212 Section 7.5 - } - - const uint16_t cursor_x = m_cursor_position & 0x3ff; - const uint16_t cursor_y = ((m_cursor_position >> 12) & 0x3ff) + m_ica_height; - const int32_t y = screen().vpos() - cursor_y; - const int width = get_screen_width(); - - if ((0 <= y) && (y < 16)) - { - const uint32_t color = s_4bpp_color[color_index]; - const uint8_t resolution = (m_cursor_control & CURCNT_CUW) ? 1 : 2; - for (int x = 0; x < 16; x++) + 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)) { - if (BIT(m_cursor_pattern[y], 15 - x)) + const int width = get_screen_width(); + uint32_t color = s_4bpp_color[m_cursor_control & CURCNT_COLOR]; + y -= cursor_y; + if (m_cursor_control & CURCNT_CUW) + { + for (int x = cursor_x; x < cursor_x + 64 && x < width; x++) + { + if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 2)))) + { + scanline[x++] = color; + scanline[x++] = color; + scanline[x++] = color; + scanline[x] = color; + } + } + } + else { - for (uint32_t j = 0; j < resolution; j++) + for (int x = cursor_x; x < cursor_x + 32 && x < width; x++) { - const uint32_t index = cursor_x + x * resolution + j; - if (index < width) - scanline[index] = color; + if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 1)))) + { + scanline[x++] = color; + scanline[x] = color; + } } } } @@ -852,21 +1142,6 @@ TIMER_CALLBACK_MEMBER(mcd212_device::ica_tick) m_dca[1] = get_dcp<1>(); m_ica_timer->adjust(screen().time_until_pos(0, 0)); - - // Cursor Blink - m_blink_time += 5 + BIT(m_dcr[0], DCR_FD_BIT); // FD bit * 8... Page 4-3 MCD - // Adjust the blink time once per frame - if (!m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_CON) >> CURCNT_CON_SHIFT) * 60)) - { - m_blink_active = true; - m_blink_time = 0; - } - // If blink off time is 0, immediately turn back on. - if (m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_COF) >> CURCNT_COF_SHIFT) * 60)) - { - m_blink_active = false; - m_blink_time = 0; - } } TIMER_CALLBACK_MEMBER(mcd212_device::dca_tick) @@ -904,7 +1179,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma // If PAL and 'Standard' bit set, insert a 20-line border on the top/bottom if ((scanline - m_ica_height < 20) || (scanline >= (m_total_height - 20))) { - std::fill_n(out, 768, s_4bpp_color[0]); + std::fill_n(out, 768, 0xff101010); draw_line = false; } } @@ -916,7 +1191,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma // If PAL and 'Standard' bit set, insert a 24px border on the left/right if (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) { - std::fill_n(out, 24, s_4bpp_color[0]); + std::fill_n(out, 24, 0xff101010); out += 24; } @@ -970,7 +1245,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma template int mcd212_device::ram_dtack_cycle_count<0>(); template int mcd212_device::ram_dtack_cycle_count<1>(); -template +template int mcd212_device::ram_dtack_cycle_count() { // Per MCD-212 documentation, it takes 4 CLKs (2 SCC68070 clocks) for a VRAM access during the System timing slot. @@ -979,8 +1254,8 @@ int mcd212_device::ram_dtack_cycle_count() if (!BIT(m_dcr[0], DCR_DE_BIT)) return 2; - // No contending for Ch.1/Ch.2 timing slots if a relevant Path is disabled - if (!BIT(m_dcr[Path], DCR_ICA_BIT)) + // No contending for Ch.1/Ch.2 timing slots if a relevant channel is disabled + if (!BIT(m_dcr[Channel], DCR_ICA_BIT)) return 2; const int x = screen().hpos(); @@ -996,11 +1271,11 @@ int mcd212_device::ram_dtack_cycle_count() return 2; // No contending for Ch.1/Ch.2 timing slots during the free-run area of DCA lines if DCA is disabled - if (!BIT(m_dcr[Path], DCR_DCA_BIT) && x_outside_active_display) + if (!BIT(m_dcr[Channel], DCR_DCA_BIT) && x_outside_active_display) return 2; // System access is restricted to the last 5 out of every 16 CLKs. - const int slot_cycle = int(machine().time().as_ticks(clock()) & 0xf); + const int slot_cycle = (int)(machine().time().as_ticks(clock()) & 0xf); if (slot_cycle >= 11) return 2; @@ -1035,17 +1310,16 @@ void mcd212_device::device_reset() m_cursor_position = 0; m_cursor_control = 0; std::fill_n(m_cursor_pattern, std::size(m_cursor_pattern), 0); - std::fill_n(m_matte_control, 8, 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_matte_flag[0], std::size(m_matte_flag[0]), false); - std::fill_n(m_matte_flag[1], std::size(m_matte_flag[1]), false); + 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_blink_time = 0; m_int_callback(CLEAR_LINE); @@ -1066,6 +1340,17 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev { } +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void mcd212_device::device_resolve_objects() +{ + m_int_callback.resolve_safe(); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -1080,10 +1365,12 @@ void mcd212_device::device_start() m_delta_uv_lut[d] = s_dyuv_deltas[d >> 4]; } - for (uint16_t w = 0; w < 0x300; w++) + for (uint16_t w = 0; w < 3 * 0xff; w++) { - const uint8_t limit = (w < 0x100) ? 0 : (w < 0x200) ? (w - 0x100) : 0xff; - m_dyuv_limit_lut[w] = limit; + 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 (int16_t sw = 0; sw < 0x100; sw++) @@ -1094,6 +1381,10 @@ void mcd212_device::device_start() m_dyuv_v_to_r[sw] = (351 * (sw - 128)) / 256; } + 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)); @@ -1112,19 +1403,12 @@ void mcd212_device::device_start() save_item(NAME(m_cursor_position)); save_item(NAME(m_cursor_control)); save_item(NAME(m_cursor_pattern)); - save_item(NAME(m_matte_control)); + 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])); - save_item(NAME(m_matte_flag)); - save_item(NAME(m_ica_height)); - save_item(NAME(m_total_height)); - - save_item(NAME(m_blink_time)); - save_item(NAME(m_blink_active)); - m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::dca_tick), this)); m_dca_timer->adjust(attotime::never); diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index fe81045a..521207ef 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -21,8 +21,8 @@ *******************************************************************************/ -#ifndef MAME_PHILIPS_MCD212_H -#define MAME_PHILIPS_MCD212_H +#ifndef MAME_VIDEO_MCD212_H +#define MAME_VIDEO_MCD212_H #pragma once @@ -49,15 +49,16 @@ class mcd212_device : public device_t, uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - void map(address_map &map) ATTR_COLD; + void map(address_map &map); - template int ram_dtack_cycle_count(); + template int ram_dtack_cycle_count(); int rom_dtack_cycle_count(); protected: - // device_t implementation - virtual void device_start() override ATTR_COLD; - virtual void device_reset() override ATTR_COLD; + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; TIMER_CALLBACK_MEMBER(ica_tick); TIMER_CALLBACK_MEMBER(dca_tick); @@ -88,11 +89,10 @@ class mcd212_device : public device_t, { CURCNT_COLOR = 0x00000f, // Cursor color CURCNT_CUW = 0x008000, // Cursor width + CURCNT_COF = 0x070000, // Cursor off time CURCNT_COF_SHIFT = 16, - CURCNT_COF = 0b111 << CURCNT_COF_SHIFT, // Cursor off time + CURCNT_CON = 0x280000, // Cursor on time CURCNT_CON_SHIFT = 19, - CURCNT_CON = 0b111 << CURCNT_CON_SHIFT, // Cursor on time - CURCNT_BLKC_SHIFT = 22, CURCNT_BLKC = 0x400000, // Blink type CURCNT_EN = 0x800000, // Cursor enable @@ -101,42 +101,40 @@ class mcd212_device : public device_t, ICM_MODE2 = 0x000f00, // Plane 2 ICM_MODE2_SHIFT = 8, ICM_EV = 0x040000, // External video - ICM_EV_BIT = 18, - ICM_NM = 0x080000, // Number of Matte flags - ICM_NM_BIT = 19, + ICM_NR = 0x080000, // Number of region flags + ICM_NR_BIT = 19, ICM_CS = 0x400000, // CLUT select - ICM_CS_BIT = 22, TCR_TA = 0x00000f, // Plane A TCR_TB = 0x000f00, // Plane B TCR_TB_SHIFT = 8, - TCR_ALWAYS = 0x0, // Transparent if: Always (Plane Disabled) - TCR_KEY = 0x1, // Transparent if: Color Key = True - TCR_RGB = 0x2, // Transparent if: Transparency Bit = 1 (RGB Only) - TCR_MF0 = 0x3, // Transparent if: Matte Flag 0 = True - TCR_MF1 = 0x4, // Transparent if: Matte Flag 1 = True - TCR_MF0_KEY1 = 0x5, // Transparent if: Matte Flag 0 = True || Color Key = True - TCR_MF1_KEY1 = 0x6, // Transparent if: Matte Flag 1 = True || Color Key = True + 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_NEVER = 0x8, // Transparent if: Never (No Transparent Area) - TCR_NOT_KEY = 0x9, // Transparent if: Color Key = False - TCR_NOT_RGB = 0xa, // Transparent if: Transparency Bit = 0 (RGB Only) - TCR_NOT_MF0 = 0xb, // Transparent if: Matte Flag 0 = False - TCR_NOT_MF1 = 0xc, // Transparent if: Matte Flag 1 = False - TCR_NOT_MF0_KEY = 0xd, // Transparent if: Matte Flag 0 = False || Color Key = False - TCR_NOT_MF1_KEY = 0xe, // Transparent if: Matte Flag 1 = False || Color Key = False + 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 TCR_DISABLE_MX = 0x800000, // Mix disable POR_AB = 0, // Plane A in front of Plane B POR_BA = 1, // Plane B in front of Plane A - MC_X = 0x0003ff, // X position - MC_WF = 0x00fc00, // Weight position - MC_WF_SHIFT = 10, - MC_MF_BIT = 16, // Matte flag bit - MC_OP = 0xf00000, // Operation - MC_OP_SHIFT = 20, + 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, CSR1R_PA = 0x20, // Parity CSR1R_DA = 0x80, // Display Active @@ -174,38 +172,40 @@ class mcd212_device : public device_t, ICM_OFF = 0x0, ICM_CLUT8 = 0x1, - ICM_RGB555 = 0x1, + ICM_RGB555 = 0x2, ICM_CLUT7 = 0x3, ICM_CLUT77 = 0x4, ICM_DYUV = 0x5, ICM_CLUT4 = 0xb }; - 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 = 0; - uint32_t m_transparency_control = 0; - uint32_t m_plane_order = 0; - 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 = 0; - uint32_t m_cursor_control = 0; - uint32_t m_cursor_pattern[16]{}; - uint32_t m_matte_control[8]{}; - uint32_t m_backdrop_color = 0; - uint32_t m_mosaic_hold[2]{}; - uint8_t m_weight_factor[2][768]{}; + 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_lut[0x300]; + 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]; @@ -232,44 +232,40 @@ class mcd212_device : public device_t, required_shared_ptr m_planeb; // internal state - bool m_matte_flag[2][768]{}; - int m_ica_height = 0; - int m_total_height = 0; - emu_timer *m_ica_timer = nullptr; - emu_timer *m_dca_timer = nullptr; - - // Cursor State - uint16_t m_blink_time; // Counter that tracks how long since the last m_blink_active last changed. - bool m_blink_active = false; + bool m_region_flag[2][768]; + int m_ica_height; + int m_total_height; + emu_timer *m_ica_timer; + emu_timer *m_dca_timer; static const uint32_t s_4bpp_color[16]; - uint8_t get_weight_factor(const uint32_t Matte_idx); - uint8_t get_matte_op(const uint32_t Matte_idx); - void update_matte_arrays(); + uint8_t get_weight_factor(const uint32_t region_idx); + uint8_t get_region_op(const uint32_t region_idx); + void update_region_arrays(); int get_screen_width(); int get_border_width(); - uint32_t get_backdrop_plane(); + template int get_plane_width(); - template void set_vsr(uint32_t value); - template uint32_t get_vsr(); + 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_dcp(uint32_t value); + template uint32_t get_dcp(); - template void set_display_parameters(uint8_t value); + template void set_display_parameters(uint8_t value); - template void process_ica(); - template void process_dca(); + template void process_ica(); + template void process_dca(); - 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); + 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); - template void set_register(uint8_t reg, uint32_t value); + template void set_register(uint8_t reg, uint32_t value); template void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out); @@ -279,4 +275,4 @@ class mcd212_device : public device_t, // device type definition DECLARE_DEVICE_TYPE(MCD212, mcd212_device) -#endif // MAME_PHILIPS_MCD212_H +#endif // MAME_VIDEO_MCD212_H From 7095bff8530d1de5b0ee9c44b2d809f965e5f7ae Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 15:41:34 -0600 Subject: [PATCH 36/47] Add mcd212 driver changes by hand instead of just checkout. --- src/mame/video/mcd212.cpp | 235 +++++++++----------------------------- src/mame/video/mcd212.h | 166 ++++++++++++++------------- 2 files changed, 141 insertions(+), 260 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 4de847dd..4234965b 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -42,174 +42,72 @@ // device type definition DEFINE_DEVICE_TYPE(MCD212, mcd212_device, "mcd212", "MCD212 VDSC") -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t region_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_weight_factor(const uint32_t matte_idx) { - return (uint8_t)((m_region_control[region_idx] & RC_WF) >> RC_WF_SHIFT); + return (uint8_t)((m_matte_control[matte_idx] & MC_WF) >> MC_WF_SHIFT); } -inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_region_op(const uint32_t region_idx) +inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_matte_op(const uint32_t matte_idx) { - return (m_region_control[region_idx] & RC_OP) >> RC_OP_SHIFT; + return (m_matte_control[matte_idx] & MC_OP) >> MC_OP_SHIFT; } -void mcd212_device::update_region_arrays() +void mcd212_device::update_matte_arrays() { bool latched_rf[2] { false, false }; uint8_t latched_wfa = m_weight_factor[0][0]; uint8_t latched_wfb = m_weight_factor[1][0]; const int width = get_screen_width(); - if (BIT(m_image_coding_method, ICM_NR_BIT)) - { - if (get_region_op(0) == 0 && get_region_op(4) == 0) - { - 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; - } + const int width = get_screen_width(); + const int num_mattes = BIT(m_image_coding_method, ICM_NM_BIT) ? 2 : 1; + + bool latched_mf[2]{ false, false }; + uint8_t latched_wf[2] = { m_weight_factor[0][0], m_weight_factor[1][0] }; + int matte_idx[2] = { 0, 4 }; - for (int x = 0; x < width; x++) + for (int x = 0; x < width; x++) + { + for (int matte = 0; matte < num_mattes; matte++) { - for (int flag = 0; flag < 2; flag++) + const int max_matte_id = ((num_mattes == 2) ? 4 : 8) + (matte ? 4 : 0); + if (matte_idx[matte] >= max_matte_id) { - for (int region = 0; region < 4; region++) - { - 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 == (region_ctrl & RC_X)) - { - switch (region_op) - { - case 0: // End of region control for line - break; - case 1: - case 2: - case 3: // Not used - break; - case 4: // Change weight of plane A - latched_wfa = get_weight_factor(region_idx); - break; - case 5: // Not used - break; - case 6: // Change weight of plane B - latched_wfb = get_weight_factor(region_idx); - break; - case 7: // Not used - break; - case 8: // Reset region flag - latched_rf[flag] = false; - break; - case 9: // Set region flag - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 13: // Set region flag and change weight of plane A - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 15: // Set region flag and change weight of plane B - latched_wfb = get_weight_factor(region_idx); - latched_rf[flag] = true; - break; - } - } - } + continue; } - 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 - { - int region_idx = 0; - for (int x = 0; x < width; x++) - { - if (region_idx < 8) + const uint32_t matte_ctrl = m_matte_control[matte_idx[matte]]; + + if (x == (matte_ctrl & MC_X)) { - 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) + const uint32_t matte_op = get_matte_op(matte_idx[matte]); + const int flag = (num_mattes == 2) ? matte : BIT(m_matte_control[matte_idx[matte]], MC_MF_BIT); + // See 5.10.2 Matte Commands. Changing the MF-bit inside a line is undefined. Greenbook says don't do it. + // Console validation shows the 220 reads and uses this value anyway. + switch (matte_op) { - 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, latched_rf[0]); - std::fill_n(m_region_flag[1] + x, std::size(m_region_flag[1]) - x, latched_rf[1]); - return; - } - if (x == (region_ctrl & RC_X)) - { - switch (region_op) - { - case 0: // End of region control for line - break; - case 1: - case 2: - case 3: // Not used - break; - case 4: // Change weight of plane A - latched_wfa = get_weight_factor(region_idx); - break; - case 5: // Not used - break; - case 6: // Change weight of plane B - latched_wfb = get_weight_factor(region_idx); - break; - case 7: // Not used - break; - case 8: // Reset region flag - latched_rf[flag] = false; - break; - case 9: // Set region flag - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 13: // Set region flag and change weight of plane A - 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 = get_weight_factor(region_idx); - latched_rf[flag] = false; - break; - case 15: // Set region flag and change weight of plane B - latched_wfb = get_weight_factor(region_idx); - latched_rf[flag] = true; - break; - } - region_idx++; + case 0: // Disregard all commands in higher registers. See 5.10.2 + matte_idx[matte] = 8; + break; + case 1: case 2: case 3: case 5: case 7: case 10: case 11: // Not used + break; + case 4: case 6: // Change weight of plane (A or B) + latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); + break; + case 8: case 9: // (Reset or Set) matte flag + latched_mf[flag] = BIT(matte_op, 0); + break; + case 12: case 13: case 14: case 15: // Change weight of plane (A or B) and (Reset or Set) matte flag + latched_wf[BIT(matte_op, 1)] = get_weight_factor(matte_idx[matte]); + latched_mf[flag] = BIT(matte_op, 0); + break; } + matte_idx[matte]++; } - 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_weight_factor[0][x] = latched_wf[0]; + m_weight_factor[1][x] = latched_wf[1]; + m_matte_flag[0][x] = latched_mf[0]; + m_matte_flag[1][x] = latched_mf[1]; } } @@ -584,16 +482,6 @@ inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); } -template -int mcd212_device::get_plane_width() -{ - const int width = get_screen_width(); - const uint8_t icm = get_icm(); - if (icm == ICM_CLUT4) - return width; - return width >> 1; -} - template void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) { @@ -1310,13 +1198,13 @@ void mcd212_device::device_reset() 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); + std::fill_n(m_matte_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); + std::fill_n(m_matte_flag[0], std::size(m_matte_flag[0]), false); + std::fill_n(m_matte_flag[1], std::size(m_matte_flag[1]), false); m_ica_height = 32; m_total_height = 312; @@ -1340,17 +1228,6 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev { } -//------------------------------------------------- -// device_resolve_objects - resolve objects that -// may be needed for other devices to set -// initial conditions at start time -//------------------------------------------------- - -void mcd212_device::device_resolve_objects() -{ - m_int_callback.resolve_safe(); -} - //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -1365,12 +1242,12 @@ void mcd212_device::device_start() m_delta_uv_lut[d] = s_dyuv_deltas[d >> 4]; } - for (uint16_t w = 0; w < 3 * 0xff; w++) + for (int16_t sw = 0; sw < 0x100; sw++) { - 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; + 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; } for (int16_t sw = 0; sw < 0x100; sw++) @@ -1381,8 +1258,8 @@ void mcd212_device::device_start() m_dyuv_v_to_r[sw] = (351 * (sw - 128)) / 256; } - save_item(NAME(m_region_flag[0])); - save_item(NAME(m_region_flag[1])); + save_item(NAME(m_matte_flag[0])); + save_item(NAME(m_matte_flag[1])); save_item(NAME(m_ica_height)); save_item(NAME(m_total_height)); save_item(NAME(m_csrr)); @@ -1403,7 +1280,7 @@ void mcd212_device::device_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_matte_control)); save_item(NAME(m_backdrop_color)); save_item(NAME(m_mosaic_hold)); save_item(NAME(m_weight_factor[0])); diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index 521207ef..fe81045a 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -21,8 +21,8 @@ *******************************************************************************/ -#ifndef MAME_VIDEO_MCD212_H -#define MAME_VIDEO_MCD212_H +#ifndef MAME_PHILIPS_MCD212_H +#define MAME_PHILIPS_MCD212_H #pragma once @@ -49,16 +49,15 @@ class mcd212_device : public device_t, uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - void map(address_map &map); + void map(address_map &map) ATTR_COLD; - template int ram_dtack_cycle_count(); + template int ram_dtack_cycle_count(); int rom_dtack_cycle_count(); protected: - // device-level overrides - virtual void device_resolve_objects() override; - virtual void device_start() override; - virtual void device_reset() override; + // device_t implementation + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; TIMER_CALLBACK_MEMBER(ica_tick); TIMER_CALLBACK_MEMBER(dca_tick); @@ -89,10 +88,11 @@ class mcd212_device : public device_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_COF = 0b111 << CURCNT_COF_SHIFT, // Cursor off time CURCNT_CON_SHIFT = 19, + CURCNT_CON = 0b111 << CURCNT_CON_SHIFT, // Cursor on time + CURCNT_BLKC_SHIFT = 22, CURCNT_BLKC = 0x400000, // Blink type CURCNT_EN = 0x800000, // Cursor enable @@ -101,40 +101,42 @@ class mcd212_device : public device_t, ICM_MODE2 = 0x000f00, // Plane 2 ICM_MODE2_SHIFT = 8, ICM_EV = 0x040000, // External video - ICM_NR = 0x080000, // Number of region flags - ICM_NR_BIT = 19, + ICM_EV_BIT = 18, + ICM_NM = 0x080000, // Number of Matte flags + ICM_NM_BIT = 19, ICM_CS = 0x400000, // CLUT select + ICM_CS_BIT = 22, TCR_TA = 0x00000f, // Plane A TCR_TB = 0x000f00, // Plane B TCR_TB_SHIFT = 8, - 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_ALWAYS = 0x0, // Transparent if: Always (Plane Disabled) + TCR_KEY = 0x1, // Transparent if: Color Key = True + TCR_RGB = 0x2, // Transparent if: Transparency Bit = 1 (RGB Only) + TCR_MF0 = 0x3, // Transparent if: Matte Flag 0 = True + TCR_MF1 = 0x4, // Transparent if: Matte Flag 1 = True + TCR_MF0_KEY1 = 0x5, // Transparent if: Matte Flag 0 = True || Color Key = True + TCR_MF1_KEY1 = 0x6, // Transparent if: Matte 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_NEVER = 0x8, // Transparent if: Never (No Transparent Area) + TCR_NOT_KEY = 0x9, // Transparent if: Color Key = False + TCR_NOT_RGB = 0xa, // Transparent if: Transparency Bit = 0 (RGB Only) + TCR_NOT_MF0 = 0xb, // Transparent if: Matte Flag 0 = False + TCR_NOT_MF1 = 0xc, // Transparent if: Matte Flag 1 = False + TCR_NOT_MF0_KEY = 0xd, // Transparent if: Matte Flag 0 = False || Color Key = False + TCR_NOT_MF1_KEY = 0xe, // Transparent if: Matte Flag 1 = False || Color Key = False TCR_COND_UNUSED1 = 0xf, // Unused TCR_DISABLE_MX = 0x800000, // Mix disable 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, + MC_X = 0x0003ff, // X position + MC_WF = 0x00fc00, // Weight position + MC_WF_SHIFT = 10, + MC_MF_BIT = 16, // Matte flag bit + MC_OP = 0xf00000, // Operation + MC_OP_SHIFT = 20, CSR1R_PA = 0x20, // Parity CSR1R_DA = 0x80, // Display Active @@ -172,40 +174,38 @@ class mcd212_device : public device_t, ICM_OFF = 0x0, ICM_CLUT8 = 0x1, - ICM_RGB555 = 0x2, + ICM_RGB555 = 0x1, ICM_CLUT7 = 0x3, ICM_CLUT77 = 0x4, ICM_DYUV = 0x5, ICM_CLUT4 = 0xb }; - 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]; + 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 = 0; + uint32_t m_transparency_control = 0; + uint32_t m_plane_order = 0; + 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 = 0; + uint32_t m_cursor_control = 0; + uint32_t m_cursor_pattern[16]{}; + uint32_t m_matte_control[8]{}; + uint32_t m_backdrop_color = 0; + 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]; + uint32_t m_dyuv_limit_lut[0x300]; // DYUV delta-Y decoding array uint8_t m_delta_y_lut[0x100]; @@ -232,40 +232,44 @@ class mcd212_device : public device_t, required_shared_ptr m_planeb; // internal state - bool m_region_flag[2][768]; - int m_ica_height; - int m_total_height; - emu_timer *m_ica_timer; - emu_timer *m_dca_timer; + bool m_matte_flag[2][768]{}; + int m_ica_height = 0; + int m_total_height = 0; + emu_timer *m_ica_timer = nullptr; + emu_timer *m_dca_timer = nullptr; + + // Cursor State + uint16_t m_blink_time; // Counter that tracks how long since the last m_blink_active last changed. + bool m_blink_active = false; static const uint32_t s_4bpp_color[16]; - uint8_t get_weight_factor(const uint32_t region_idx); - uint8_t get_region_op(const uint32_t region_idx); - void update_region_arrays(); + uint8_t get_weight_factor(const uint32_t Matte_idx); + uint8_t get_matte_op(const uint32_t Matte_idx); + void update_matte_arrays(); int get_screen_width(); int get_border_width(); - template int get_plane_width(); + uint32_t get_backdrop_plane(); - template void set_vsr(uint32_t value); - template uint32_t get_vsr(); + 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_dcp(uint32_t value); + template uint32_t get_dcp(); - template void set_display_parameters(uint8_t value); + template void set_display_parameters(uint8_t value); - template void process_ica(); - template void process_dca(); + template void process_ica(); + template void process_dca(); - 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); + 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); - template void set_register(uint8_t reg, uint32_t value); + template void set_register(uint8_t reg, uint32_t value); template void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out); @@ -275,4 +279,4 @@ class mcd212_device : public device_t, // device type definition DECLARE_DEVICE_TYPE(MCD212, mcd212_device) -#endif // MAME_VIDEO_MCD212_H +#endif // MAME_PHILIPS_MCD212_H From d2f73739957057d9e773916c7ed1a379b680b992 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 15:44:11 -0600 Subject: [PATCH 37/47] Various fixes. --- src/mame/video/mcd212.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 4234965b..f78eb8f8 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -54,10 +54,6 @@ inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_matte_op(const uint32_t matt void mcd212_device::update_matte_arrays() { - bool latched_rf[2] { false, false }; - uint8_t latched_wfa = m_weight_factor[0][0]; - uint8_t latched_wfb = m_weight_factor[1][0]; - const int width = get_screen_width(); const int width = get_screen_width(); const int num_mattes = BIT(m_image_coding_method, ICM_NM_BIT) ? 2 : 1; @@ -212,8 +208,8 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xd5: case 0xd6: case 0xd7: - m_region_control[reg & 7] = value; - update_region_arrays(); + m_matte_control[reg & 7] = value; + update_matte_arrays(); break; case 0xd8: // Backdrop Color if (Channel == 0) @@ -237,14 +233,14 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) if (Channel == 0) { m_weight_factor[0][0] = (uint8_t)value; - update_region_arrays(); + update_matte_arrays(); } break; case 0xdc: // Weight Factor B if (Channel == 1) { m_weight_factor[1][0] = (uint8_t)value; - update_region_arrays(); + update_matte_arrays(); } break; } From b1382432a1a884fd6a3256b86b8dc13c857183a8 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 15:55:59 -0600 Subject: [PATCH 38/47] Various fixes. --- src/mame/video/mcd212.cpp | 240 +++++++++++++++++++------------------- 1 file changed, 123 insertions(+), 117 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index f78eb8f8..f6a2f660 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -107,7 +107,7 @@ void mcd212_device::update_matte_arrays() } } -template +template void mcd212_device::set_register(uint8_t reg, uint32_t value) { switch (reg) @@ -121,86 +121,86 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) 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: { - const uint8_t clut_index = m_clut_bank[Channel] * 0x40 + (reg - 0x80); + const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method - if (Channel == 0) + if (Path == 0) { m_image_coding_method = value; } break; case 0xc1: // Transparency Control - if (Channel == 0) + if (Path == 0) { m_transparency_control = value; } break; case 0xc2: // Plane Order - if (Channel == 0) + if (Path == 0) { m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register - m_clut_bank[Channel] = Channel ? (2 | (value & 0x00000001)) : (value & 0x00000003); + m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A - if (Channel == 0) + if (Path == 0) { m_transparent_color[0] = value & 0x00fcfcfc; } break; case 0xc6: // Transparent Color B - if (Channel == 1) + if (Path == 1) { m_transparent_color[1] = value & 0x00fcfcfc; } break; case 0xc7: // Mask Color A - if (Channel == 0) + if (Path == 0) { m_mask_color[0] = value & 0x00fcfcfc; } break; case 0xc9: // Mask Color B - if (Channel == 1) + if (Path == 1) { m_mask_color[1] = value & 0x00fcfcfc; } break; case 0xca: // Delta YUV Absolute Start Value A - if (Channel == 0) + if (Path == 0) { m_dyuv_abs_start[0] = value; } break; case 0xcb: // Delta YUV Absolute Start Value B - if (Channel == 1) + if (Path == 1) { m_dyuv_abs_start[1] = value; } break; case 0xcd: // Cursor Position - if (Channel == 0) + if (Path == 0) { m_cursor_position = value; } break; case 0xce: // Cursor Control - if (Channel == 0) + if (Path == 0) { m_cursor_control = value; } break; case 0xcf: // Cursor Pattern - if (Channel == 0) + if (Path == 0) { m_cursor_pattern[(value >> 16) & 0x000f] = value & 0x0000ffff; } break; - case 0xd0: // Region Control 0-7 + case 0xd0: // matte Control 0-7 case 0xd1: case 0xd2: case 0xd3: @@ -212,32 +212,32 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) update_matte_arrays(); break; case 0xd8: // Backdrop Color - if (Channel == 0) + if (Path == 0) { m_backdrop_color = value; } break; case 0xd9: // Mosaic Pixel Hold Factor A - if (Channel == 0) + if (Path == 0) { m_mosaic_hold[0] = value; } break; case 0xda: // Mosaic Pixel Hold Factor B - if (Channel == 1) + if (Path == 1) { m_mosaic_hold[1] = value; } break; case 0xdb: // Weight Factor A - if (Channel == 0) + if (Path == 0) { m_weight_factor[0][0] = (uint8_t)value; update_matte_arrays(); } break; case 0xdc: // Weight Factor B - if (Channel == 1) + if (Path == 1) { m_weight_factor[1][0] = (uint8_t)value; update_matte_arrays(); @@ -246,41 +246,41 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) } } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr() { - return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel]; + return ((m_dcr[Path] & 0x3f) << 16) | m_vsr[Path]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_vsr(uint32_t value) { - m_vsr[Channel] = value & 0x0000ffff; - m_dcr[Channel] &= 0xffc0; - m_dcr[Channel] |= (value >> 16) & 0x003f; + m_vsr[Path] = value & 0x0000ffff; + m_dcr[Path] &= 0xffc0; + m_dcr[Path] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_dcp(uint32_t value) { - m_dcp[Channel] = value & 0x0000ffff; - m_ddr[Channel] &= 0xffc0; - m_ddr[Channel] |= (value >> 16) & 0x003f; + m_dcp[Path] = value & 0x0000ffff; + m_ddr[Path] &= 0xffc0; + m_ddr[Path] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_dcp() { - return ((m_ddr[Channel] & 0x3f) << 16) | m_dcp[Channel]; + return ((m_ddr[Path] & 0x3f) << 16) | m_dcp[Path]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t value) { - m_ddr[Channel] &= 0xf0ff; - m_ddr[Channel] |= (value & 0x0f) << 8; - m_dcr[Channel] &= 0xf7ff; - m_dcr[Channel] |= (value & 0x10) << 7; + m_ddr[Path] &= 0xf0ff; + m_ddr[Path] |= (value & 0x0f) << 8; + m_dcr[Path] &= 0xf7ff; + m_dcr[Path] |= (value & 0x10) << 7; } int mcd212_device::get_screen_width() @@ -299,10 +299,10 @@ int mcd212_device::get_border_width() return width; } -template +template void mcd212_device::process_ica() { - uint16_t *ica = Channel ? m_planeb.target() : m_planea.target(); + uint16_t *ica = Path ? m_planeb.target() : m_planea.target(); uint32_t addr = 0x200; uint32_t cmd = 0; @@ -321,11 +321,11 @@ void mcd212_device::process_ica() 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: - set_dcp(cmd & 0x003ffffc); + 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: - set_dcp(cmd & 0x003ffffc); + 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: @@ -333,29 +333,29 @@ void mcd212_device::process_ica() 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: - set_vsr(cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Channel); + m_csrr[1] |= 1 << (2 - Path); 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 - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } } -template +template void mcd212_device::process_dca() { - uint16_t *dca = Channel ? m_planeb.target() : m_planea.target(); - uint32_t addr = (m_dca[Channel] & 0x0007ffff) / 2; + uint16_t *dca = Path ? m_planeb.target() : m_planea.target(); + uint32_t addr = (m_dca[Path] & 0x0007ffff) / 2; uint32_t cmd = 0; uint32_t count = 0; uint32_t max = 64; @@ -380,29 +380,29 @@ void mcd212_device::process_dca() 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: - set_dcp(cmd & 0x003ffffc); - m_dca[Channel] = cmd & 0x0007fffc; + set_dcp(cmd & 0x003ffffc); + m_dca[Path] = 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: - set_vsr(cmd & 0x003fffff); + 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: - set_vsr(cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Channel); + m_csrr[1] |= 1 << (2 - Path); 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 - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } @@ -412,10 +412,10 @@ void mcd212_device::process_dca() addr += (max - count) >> 1; } - m_dca[Channel] = addr * 2; + m_dca[Path] = addr * 2; } -template +template static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) { switch (icm) @@ -423,7 +423,7 @@ static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) case 1: return byte; case 3: - if (Channel == 1) + if (Path == 1) { return 0x80 + (byte & 0x7f); } @@ -432,13 +432,13 @@ static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) return byte & 0x7f; } case 4: - if (Channel == 0) + if (Path == 0) { return byte & 0x7f; } break; case 11: - if (Channel == 1) + if (Path == 1) { return 0x80 + (byte & 0x0f); } @@ -452,41 +452,41 @@ static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) return 0; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control() { - return (m_transparency_control >> (Channel ? 8 : 0)) & 0x0f; + return (m_transparency_control >> (Path ? 8 : 0)) & 0x0f; } -template +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; + const uint32_t mask = Path ? ICM_MODE2 : ICM_MODE1; + const uint32_t shift = Path ? ICM_MODE2_SHIFT : ICM_MODE1_SHIFT; return (m_image_coding_method & mask) >> shift; } -template +template inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable() { - return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC; + return (m_ddr[Path] & DDR_FT) == DDR_FT_MOSAIC; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() { - return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); + return 1 << (((m_ddr[Path] & DDR_MT) >> DDR_MT_SHIFT) + 1); } -template +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 uint8_t transp_ctrl = get_transparency_control(); - const int width = get_plane_width(); + const uint8_t *data = reinterpret_cast(Path ? m_planeb.target() : m_planea.target()); + const uint8_t icm = get_icm(); + const uint8_t transp_ctrl = get_transparency_control(); + const int width = get_screen_width(); - uint32_t vsr = get_vsr(); + uint32_t vsr = get_vsr(); if (transp_ctrl == TCR_COND_1) { @@ -501,22 +501,28 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) return; } - const uint8_t mosaic_enable = get_mosaic_enable(); - const uint8_t mosaic_factor = get_mosaic_factor(); + const uint32_t decodingMode = m_ddr[Path] & DDR_FT; - 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 uint8_t mosaic_enable = get_mosaic_enable(); + const uint8_t mosaic_factor = get_mosaic_factor(); - 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); + const uint32_t dyuv_abs_start = m_dyuv_abs_start[Path]; + uint8_t y = (dyuv_abs_start >> 16) & 0x000000ff; + uint8_t u = (dyuv_abs_start >> 8) & 0x000000ff; + uint8_t v = (dyuv_abs_start >> 0) & 0x000000ff; + + const uint32_t mask_bits = (~m_mask_color[Path]) & 0x00fcfcfc; + const uint32_t tp_color_match = m_transparent_color[Path] & mask_bits; + const uint8_t tp_ctrl_type = tp_ctrl & 0x07; + + const bool use_rgb_tp_bit = (tp_ctrl_type == TCR_RGB); + const bool tp_check_parity = !BIT(tp_ctrl, 3); + const bool tp_always = ((tp_ctrl_type == TCR_ALWAYS) && tp_check_parity); + const int matte_flag_index = BIT(~tp_ctrl_type, 0); + const bool *const matte_flags = m_matte_flag[matte_flag_index]; + const bool use_matte_flag = (tp_ctrl_type >= TCR_MF0 && tp_ctrl_type <= TCR_MF1_KEY1); + const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. + const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); bool done = false; int x = 0; @@ -525,7 +531,7 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) { uint8_t byte = data[(vsr & 0x0007ffff) ^ 1]; vsr++; - switch (m_ddr[Channel] & DDR_FT) + switch (m_ddr[Path] & DDR_FT) { case DDR_FT_BMP: case DDR_FT_BMP2: @@ -555,7 +561,7 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) 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] = entry; - transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + transparent[x] = (transp_always || (use_matte_flag && matte_flags[x << 1])) != invert_transp_condition; if (mosaic_enable) { @@ -577,7 +583,7 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) 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] = entry; - transparent[x] = (transp_always || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + transparent[x] = (transp_always || (use_matte_flag && matte_flags[x << 1])) != invert_transp_condition; if (mosaic_enable) { @@ -595,15 +601,15 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) u = u1; v = v1; } - set_vsr(vsr - 1); + set_vsr(vsr - 1); } else if (icm == ICM_CLUT8 || icm == ICM_CLUT7 || icm == ICM_CLUT77) { for (; x < width; x++) { - uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; + uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; pixels[x] = entry; - transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x << 1])) != invert_transp_condition; + transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_matte_flag && matte_flags[x << 1])) != invert_transp_condition; if (mosaic_enable) { for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) @@ -616,14 +622,14 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) byte = data[(vsr & 0x0007ffff) ^ 1]; vsr++; } - set_vsr(vsr - 1); + set_vsr(vsr - 1); } else if (icm == ICM_CLUT4) { for (; x < width - 1; x += 2) { - 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 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) @@ -631,24 +637,24 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) for (int mosaic_index = 0; mosaic_index < mosaic_factor && (x + mosaic_index) < (width - 1); mosaic_index += 2) { pixels[x + mosaic_index] = even_entry; - transparent[x + mosaic_index] = (even_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition; + transparent[x + mosaic_index] = (even_pre_transparent || (use_matte_flag && matte_flags[x + mosaic_index])) != invert_transp_condition; pixels[x + mosaic_index + 1] = odd_entry; - transparent[x + mosaic_index + 1] = (odd_pre_transparent || (use_region_flag && region_flags[x + mosaic_index + 1])) != invert_transp_condition; + transparent[x + mosaic_index + 1] = (odd_pre_transparent || (use_matte_flag && matte_flags[x + mosaic_index + 1])) != invert_transp_condition; } x += mosaic_factor - 2; } else { pixels[x] = even_entry; - transparent[x] = (even_pre_transparent || (use_region_flag && region_flags[x])) != invert_transp_condition; + transparent[x] = (even_pre_transparent || (use_matte_flag && matte_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; + transparent[x + 1] = (odd_pre_transparent || (use_matte_flag && matte_flags[x + 1])) != invert_transp_condition; } byte = data[(vsr & 0x0007ffff) ^ 1]; vsr++; } - set_vsr(vsr - 1); + set_vsr(vsr - 1); } else { @@ -662,7 +668,7 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) { // Run length uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1]; - const uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte & 0x7f)]; + 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) { @@ -670,10 +676,10 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) std::fill_n(pixels + x, width - x, entry); for (int transp_index = x; transp_index < width; transp_index++) { - transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; + transparent[transp_index] = (pre_transparent || (use_matte_flag && matte_flags[transp_index << 1])) != invert_transp_condition; } done = true; - set_vsr(vsr); + set_vsr(vsr); } else { @@ -681,30 +687,30 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) std::fill_n(pixels + x, end - x, entry); for (int transp_index = x; transp_index < end; transp_index++) { - transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; + transparent[transp_index] = (pre_transparent || (use_matte_flag && matte_flags[transp_index << 1])) != invert_transp_condition; } x = end; if (x >= width) { done = true; - set_vsr(vsr); + set_vsr(vsr); } } } else { // Single pixel - const uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; + 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 << 1])) != invert_transp_condition; + transparent[x] = (pre_transparent || (use_matte_flag && matte_flags[x << 1])) != invert_transp_condition; x++; if (x >= width) { done = true; - set_vsr(vsr); + set_vsr(vsr); } } break; @@ -1052,7 +1058,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma int scanline = screen.vpos(); - // Process VSR and mix if we're in the visible region + // Process VSR and mix if we're in the visible matte if (scanline >= m_ica_height) { uint32_t *out = &bitmap.pix(scanline); @@ -1129,7 +1135,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma template int mcd212_device::ram_dtack_cycle_count<0>(); template int mcd212_device::ram_dtack_cycle_count<1>(); -template +template int mcd212_device::ram_dtack_cycle_count() { // Per MCD-212 documentation, it takes 4 CLKs (2 SCC68070 clocks) for a VRAM access during the System timing slot. @@ -1138,8 +1144,8 @@ int mcd212_device::ram_dtack_cycle_count() if (!BIT(m_dcr[0], DCR_DE_BIT)) return 2; - // No contending for Ch.1/Ch.2 timing slots if a relevant channel is disabled - if (!BIT(m_dcr[Channel], DCR_ICA_BIT)) + // No contending for Ch.1/Ch.2 timing slots if a relevant Path is disabled + if (!BIT(m_dcr[Path], DCR_ICA_BIT)) return 2; const int x = screen().hpos(); @@ -1155,7 +1161,7 @@ int mcd212_device::ram_dtack_cycle_count() return 2; // No contending for Ch.1/Ch.2 timing slots during the free-run area of DCA lines if DCA is disabled - if (!BIT(m_dcr[Channel], DCR_DCA_BIT) && x_outside_active_display) + if (!BIT(m_dcr[Path], DCR_DCA_BIT) && x_outside_active_display) return 2; // System access is restricted to the last 5 out of every 16 CLKs. From 9a12f27479080eabc46699ab78ad6879e05e50a5 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 15:58:50 -0600 Subject: [PATCH 39/47] Even more fixes. --- src/mame/video/mcd212.cpp | 291 +++++++++++--------------------------- 1 file changed, 86 insertions(+), 205 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index f6a2f660..1a919cb0 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -482,22 +482,18 @@ template void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) { const uint8_t *data = reinterpret_cast(Path ? m_planeb.target() : m_planea.target()); + const uint8_t *data2 = reinterpret_cast(!Path ? m_planeb.target() : m_planea.target()); const uint8_t icm = get_icm(); - const uint8_t transp_ctrl = get_transparency_control(); - const int width = get_screen_width(); + const uint8_t tp_ctrl = get_transparency_control(); + const int width = get_screen_width(); uint32_t vsr = get_vsr(); + uint32_t vsr2 = get_vsr(); - if (transp_ctrl == TCR_COND_1) + if (tp_ctrl == TCR_ALWAYS || !icm || !vsr) { - std::fill_n(pixels, get_screen_width(), 0x00101010); - std::fill_n(transparent, get_screen_width(), true); - return; - } - - if (!icm || !vsr) - { - std::fill_n(pixels, get_screen_width(), 0x00101010); + std::fill_n(pixels, get_screen_width(), s_4bpp_color[0]); + std::fill_n(transparent, get_screen_width(), (tp_ctrl == TCR_ALWAYS)); return; } @@ -524,207 +520,92 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); - bool done = false; - int x = 0; + LOGMASKED(LOG_VSR, "Scanline %d: VSR Path %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Path, icm, vsr); - while (!done) + for (uint32_t x = 0; x < width; ) { - uint8_t byte = data[(vsr & 0x0007ffff) ^ 1]; - vsr++; - switch (m_ddr[Path] & DDR_FT) + const uint8_t byte = data[(vsr++ & 0x0007ffff) ^ 1]; + uint32_t color0 = 0; + uint32_t color1 = 0; + bool rgb_tp_bit = false; + if (icm == ICM_DYUV) { - case DDR_FT_BMP: - case DDR_FT_BMP2: - case DDR_FT_MOSAIC: - if (icm == ICM_DYUV) - { - use_color_key = false; - - uint8_t y = start_y; - uint8_t u = start_u; - uint8_t v = start_v; - for (; x < width; x++) - { - 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]; - - const uint8_t v1 = v + m_delta_uv_lut[byte1]; - const uint8_t y1 = y0 + m_delta_y_lut[byte1]; - - const uint8_t u0 = (u + u1) >> 1; - const uint8_t v0 = (v + v1) >> 1; - - 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; - - 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] = entry; - transparent[x] = (transp_always || (use_matte_flag && matte_flags[x << 1])) != invert_transp_condition; - - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x << 1]; - } - x += mosaic_factor; - } - else - { - x++; - } - - 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; - - 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] = entry; - transparent[x] = (transp_always || (use_matte_flag && matte_flags[x << 1])) != invert_transp_condition; - - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x]; - } - x += mosaic_factor - 1; - } - - byte = data[(vsr++ & 0x0007ffff) ^ 1]; - - y = y1; - u = u1; - v = v1; - } - set_vsr(vsr - 1); - } - else if (icm == ICM_CLUT8 || icm == ICM_CLUT7 || icm == ICM_CLUT77) - { - for (; x < width; x++) - { - uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; - pixels[x] = entry; - transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_matte_flag && matte_flags[x << 1])) != invert_transp_condition; - if (mosaic_enable) - { - for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) - { - pixels[x + mosaic_index] = pixels[x]; - transparent[x + mosaic_index] = transparent[x]; - } - x += mosaic_factor - 1; - } - byte = data[(vsr & 0x0007ffff) ^ 1]; - vsr++; - } - set_vsr(vsr - 1); - } - else if (icm == ICM_CLUT4) - { - for (; x < width - 1; x += 2) - { - 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 (int mosaic_index = 0; mosaic_index < mosaic_factor && (x + mosaic_index) < (width - 1); mosaic_index += 2) - { - pixels[x + mosaic_index] = even_entry; - transparent[x + mosaic_index] = (even_pre_transparent || (use_matte_flag && matte_flags[x + mosaic_index])) != invert_transp_condition; - pixels[x + mosaic_index + 1] = odd_entry; - transparent[x + mosaic_index + 1] = (odd_pre_transparent || (use_matte_flag && matte_flags[x + mosaic_index + 1])) != invert_transp_condition; - } - x += mosaic_factor - 2; - } - else - { - pixels[x] = even_entry; - transparent[x] = (even_pre_transparent || (use_matte_flag && matte_flags[x])) != invert_transp_condition; - - pixels[x + 1] = odd_entry; - transparent[x + 1] = (odd_pre_transparent || (use_matte_flag && matte_flags[x + 1])) != invert_transp_condition; - } - byte = data[(vsr & 0x0007ffff) ^ 1]; - vsr++; - } - set_vsr(vsr - 1); - } - else - { - std::fill_n(pixels + x, width - x, 0x00101010); - std::fill_n(transparent + x, width - x, true); - } - done = true; - break; - case DDR_FT_RLE: - if (byte & 0x80) - { - // Run length - uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1]; - 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) - { - // Go to the end of the line - std::fill_n(pixels + x, width - x, entry); - for (int transp_index = x; transp_index < width; transp_index++) - { - transparent[transp_index] = (pre_transparent || (use_matte_flag && matte_flags[transp_index << 1])) != invert_transp_condition; - } - done = true; - set_vsr(vsr); - } - else - { - int end = std::min(width, x + length); - std::fill_n(pixels + x, end - x, entry); - for (int transp_index = x; transp_index < end; transp_index++) - { - transparent[transp_index] = (pre_transparent || (use_matte_flag && matte_flags[transp_index << 1])) != invert_transp_condition; - } - x = end; - if (x >= width) - { - done = true; - set_vsr(vsr); - } - } - } - else - { - // Single pixel - 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_matte_flag && matte_flags[x << 1])) != invert_transp_condition; - x++; - - if (x >= width) - { - done = true; - set_vsr(vsr); - } - } - break; + const uint8_t byte1 = data[(vsr++ & 0x0007ffff) ^ 1]; + const uint8_t y2 = y + m_delta_y_lut[byte]; + y = y2 + m_delta_y_lut[byte1]; + u += m_delta_uv_lut[byte]; + v += m_delta_uv_lut[byte1]; + + const uint32_t *limit_rgb = m_dyuv_limit_lut + y2 + 0x100; + const uint32_t *limit_rgb2 = m_dyuv_limit_lut + y + 0x100; + + color0 = (limit_rgb[m_dyuv_v_to_r[v]] << 16) | (limit_rgb[m_dyuv_u_to_g[u] + m_dyuv_v_to_g[v]] << 8) | limit_rgb[m_dyuv_u_to_b[u]]; + + const uint8_t byte2 = data[(vsr & 0x0007ffff) ^ 1]; // Peek ahead, for calculating the half-step. + const uint8_t byte3 = data[((vsr + 1) & 0x0007ffff) ^ 1]; + const uint8_t u8 = u + m_delta_uv_lut[byte2]; + const uint8_t v8 = v + m_delta_uv_lut[byte3]; + const uint8_t u6 = (u >> 1) + (u8 >> 1) + (u & u8 & 1); + const uint8_t v6 = (v >> 1) + (v8 >> 1) + (v & v8 & 1); + + color1 = (limit_rgb2[m_dyuv_v_to_r[v6]] << 16) | (limit_rgb2[m_dyuv_u_to_g[u6] + m_dyuv_v_to_g[v6]] << 8) | limit_rgb2[m_dyuv_u_to_b[u6]]; + + // TODO: Does not support QHY + pixels[x] = color0; + pixels[x + 1] = color0; + pixels[x + 2] = color1; + pixels[x + 3] = color1; + transparent[x ] = tp_always || (use_matte_flag && (matte_flags[x ] == tp_check_parity)); + transparent[x + 1] = tp_always || (use_matte_flag && (matte_flags[x + 1] == tp_check_parity)); + transparent[x + 2] = tp_always || (use_matte_flag && (matte_flags[x + 2] == tp_check_parity)); + transparent[x + 3] = tp_always || (use_matte_flag && (matte_flags[x + 3] == tp_check_parity)); + x += 4; } - } - - if (icm != ICM_CLUT4) - { - for (int i = width - 1; i >= 0; i--) + else { - pixels[i * 2] = pixels[i * 2 + 1] = pixels[i]; - transparent[i * 2] = transparent[i * 2 + 1] = transparent[i]; + bool clut_select = BIT(m_image_coding_method, ICM_CS_BIT); + if (icm == ICM_RGB555 && Path == 1) + { + const uint8_t byte1 = data2[(vsr2++ & 0x0007ffff) ^ 1]; + const uint8_t blue = (byte & 0b11111) << 3; + const uint8_t green = ((byte & 0b11100000) >> 2) + ((byte1 & 0b11) << 6); + const uint8_t red = (byte1 & 0b01111100) << 1; + rgb_tp_bit = (use_rgb_tp_bit && (BIT(byte1,7) == tp_check_parity)); + color1 = color0 = (uint32_t(red) << 16) | (uint32_t(green) << 8) | blue; + } + else if (icm == ICM_CLUT4) + { + const uint8_t mask = (decodingMode == DDR_FT_RLE) ? 0x7 : 0xf; + color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; + color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; + } + else + { + color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; + } + + int length_m = mosaic_enable ? (mosaic_factor * 2) : 2; + if (decodingMode == DDR_FT_RLE) + { + const uint16_t length = (byte & 0x80) ? data[((vsr++) & 0x0007ffff) ^ 1] : 1; + length_m = length ? (length * 2) : width; + } + + const bool color_match0 = ((mask_bits & color0) == tp_color_match) == tp_check_parity; + const bool color_match1 = ((mask_bits & color1) == tp_color_match) == tp_check_parity; + const int end = std::min(width, x + length_m); + for (int rl_index = x; rl_index < end; rl_index += 2) + { + pixels[rl_index ] = color0; + pixels[rl_index + 1] = color1; + transparent[rl_index ] = tp_always || rgb_tp_bit || (use_color_key && color_match0) || (use_matte_flag && (matte_flags[rl_index ] == tp_check_parity)); + transparent[rl_index + 1] = tp_always || rgb_tp_bit || (use_color_key && color_match1) || (use_matte_flag && (matte_flags[rl_index + 1] == tp_check_parity)); + } + x = end; } } + set_vsr(vsr); + set_vsr(vsr2); } const uint32_t mcd212_device::s_4bpp_color[16] = From 2fe714943d362312b853f406344083e72fa221a1 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 16:00:56 -0600 Subject: [PATCH 40/47] Fixes. --- src/mame/video/mcd212.cpp | 44 +++++++++++++-------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 1a919cb0..ebcc673d 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -416,38 +416,24 @@ void mcd212_device::process_dca() } template -static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte) +static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) { switch (icm) { - case 1: - return byte; - case 3: - if (Path == 1) - { - return 0x80 + (byte & 0x7f); - } - else - { - return byte & 0x7f; - } - case 4: - if (Path == 0) - { - return byte & 0x7f; - } - break; - case 11: - if (Path == 1) - { - return 0x80 + (byte & 0x0f); - } - else - { - return byte & 0x0f; - } - default: - break; + case 1: + return byte; + case 3: + return (Path ? 0x80 : 0) | (byte & 0x7f); + case 4: + if (Path == 0) + { + return (clut_select ? 0x80 : 0) | (byte & 0x7f); + } + break; + case 11: + return (Path ? 0x80 : 0) | (byte & 0x0f); + default: + break; } return 0; } From b3509eaf1db93d6452ab39f0f1d5a841ea1b1fc0 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 16:04:04 -0600 Subject: [PATCH 41/47] FIXES. --- src/mame/video/mcd212.cpp | 188 +++++++++++++++++++------------------- src/mame/video/mcd212.h | 28 +++--- 2 files changed, 108 insertions(+), 108 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index ebcc673d..682ff206 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -107,7 +107,7 @@ void mcd212_device::update_matte_arrays() } } -template +template void mcd212_device::set_register(uint8_t reg, uint32_t value) { switch (reg) @@ -121,81 +121,81 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) 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: { - const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); + const uint8_t clut_index = m_clut_bank[Channel] * 0x40 + (reg - 0x80); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method - if (Path == 0) + if (Channel == 0) { m_image_coding_method = value; } break; case 0xc1: // Transparency Control - if (Path == 0) + if (Channel == 0) { m_transparency_control = value; } break; case 0xc2: // Plane Order - if (Path == 0) + if (Channel == 0) { m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register - m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); + m_clut_bank[Channel] = Channel ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A - if (Path == 0) + if (Channel == 0) { m_transparent_color[0] = value & 0x00fcfcfc; } break; case 0xc6: // Transparent Color B - if (Path == 1) + if (Channel == 1) { m_transparent_color[1] = value & 0x00fcfcfc; } break; case 0xc7: // Mask Color A - if (Path == 0) + if (Channel == 0) { m_mask_color[0] = value & 0x00fcfcfc; } break; case 0xc9: // Mask Color B - if (Path == 1) + if (Channel == 1) { m_mask_color[1] = value & 0x00fcfcfc; } break; case 0xca: // Delta YUV Absolute Start Value A - if (Path == 0) + if (Channel == 0) { m_dyuv_abs_start[0] = value; } break; case 0xcb: // Delta YUV Absolute Start Value B - if (Path == 1) + if (Channel == 1) { m_dyuv_abs_start[1] = value; } break; case 0xcd: // Cursor Position - if (Path == 0) + if (Channel == 0) { m_cursor_position = value; } break; case 0xce: // Cursor Control - if (Path == 0) + if (Channel == 0) { m_cursor_control = value; } break; case 0xcf: // Cursor Pattern - if (Path == 0) + if (Channel == 0) { m_cursor_pattern[(value >> 16) & 0x000f] = value & 0x0000ffff; } @@ -212,32 +212,32 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) update_matte_arrays(); break; case 0xd8: // Backdrop Color - if (Path == 0) + if (Channel == 0) { m_backdrop_color = value; } break; case 0xd9: // Mosaic Pixel Hold Factor A - if (Path == 0) + if (Channel == 0) { m_mosaic_hold[0] = value; } break; case 0xda: // Mosaic Pixel Hold Factor B - if (Path == 1) + if (Channel == 1) { m_mosaic_hold[1] = value; } break; case 0xdb: // Weight Factor A - if (Path == 0) + if (Channel == 0) { m_weight_factor[0][0] = (uint8_t)value; update_matte_arrays(); } break; case 0xdc: // Weight Factor B - if (Path == 1) + if (Channel == 1) { m_weight_factor[1][0] = (uint8_t)value; update_matte_arrays(); @@ -246,41 +246,41 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) } } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr() { - return ((m_dcr[Path] & 0x3f) << 16) | m_vsr[Path]; + return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_vsr(uint32_t value) { - m_vsr[Path] = value & 0x0000ffff; - m_dcr[Path] &= 0xffc0; - m_dcr[Path] |= (value >> 16) & 0x003f; + m_vsr[Channel] = value & 0x0000ffff; + m_dcr[Channel] &= 0xffc0; + m_dcr[Channel] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_dcp(uint32_t value) { - m_dcp[Path] = value & 0x0000ffff; - m_ddr[Path] &= 0xffc0; - m_ddr[Path] |= (value >> 16) & 0x003f; + m_dcp[Channel] = value & 0x0000ffff; + m_ddr[Channel] &= 0xffc0; + m_ddr[Channel] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_dcp() { - return ((m_ddr[Path] & 0x3f) << 16) | m_dcp[Path]; + return ((m_ddr[Channel] & 0x3f) << 16) | m_dcp[Channel]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t value) { - m_ddr[Path] &= 0xf0ff; - m_ddr[Path] |= (value & 0x0f) << 8; - m_dcr[Path] &= 0xf7ff; - m_dcr[Path] |= (value & 0x10) << 7; + m_ddr[Channel] &= 0xf0ff; + m_ddr[Channel] |= (value & 0x0f) << 8; + m_dcr[Channel] &= 0xf7ff; + m_dcr[Channel] |= (value & 0x10) << 7; } int mcd212_device::get_screen_width() @@ -299,10 +299,10 @@ int mcd212_device::get_border_width() return width; } -template +template void mcd212_device::process_ica() { - uint16_t *ica = Path ? m_planeb.target() : m_planea.target(); + uint16_t *ica = Channel ? m_planeb.target() : m_planea.target(); uint32_t addr = 0x200; uint32_t cmd = 0; @@ -321,11 +321,11 @@ void mcd212_device::process_ica() 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: - set_dcp(cmd & 0x003ffffc); + 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: - set_dcp(cmd & 0x003ffffc); + 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: @@ -333,29 +333,29 @@ void mcd212_device::process_ica() 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: - set_vsr(cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Path); + 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 - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } } -template +template void mcd212_device::process_dca() { - uint16_t *dca = Path ? m_planeb.target() : m_planea.target(); - uint32_t addr = (m_dca[Path] & 0x0007ffff) / 2; + 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; @@ -380,29 +380,29 @@ void mcd212_device::process_dca() 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: - set_dcp(cmd & 0x003ffffc); - m_dca[Path] = cmd & 0x0007fffc; + 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: - set_vsr(cmd & 0x003fffff); + 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: - set_vsr(cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Path); + 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 - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } @@ -412,10 +412,10 @@ void mcd212_device::process_dca() addr += (max - count) >> 1; } - m_dca[Path] = addr * 2; + m_dca[Channel] = addr * 2; } -template +template static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) { switch (icm) @@ -423,58 +423,58 @@ static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) case 1: return byte; case 3: - return (Path ? 0x80 : 0) | (byte & 0x7f); + return (Channel ? 0x80 : 0) | (byte & 0x7f); case 4: - if (Path == 0) + if (Channel == 0) { return (clut_select ? 0x80 : 0) | (byte & 0x7f); } break; case 11: - return (Path ? 0x80 : 0) | (byte & 0x0f); + return (Channel ? 0x80 : 0) | (byte & 0x0f); default: break; } return 0; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control() { - return (m_transparency_control >> (Path ? 8 : 0)) & 0x0f; + return (m_transparency_control >> (Channel ? 8 : 0)) & 0x0f; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_icm() { - const uint32_t mask = Path ? ICM_MODE2 : ICM_MODE1; - const uint32_t shift = Path ? ICM_MODE2_SHIFT : ICM_MODE1_SHIFT; + 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 +template inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable() { - return (m_ddr[Path] & DDR_FT) == DDR_FT_MOSAIC; + return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() { - return 1 << (((m_ddr[Path] & DDR_MT) >> DDR_MT_SHIFT) + 1); + return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); } -template +template void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) { - const uint8_t *data = reinterpret_cast(Path ? m_planeb.target() : m_planea.target()); - const uint8_t *data2 = reinterpret_cast(!Path ? m_planeb.target() : m_planea.target()); - const uint8_t icm = get_icm(); - const uint8_t tp_ctrl = get_transparency_control(); + const uint8_t *data = reinterpret_cast(Channel ? m_planeb.target() : m_planea.target()); + const uint8_t *data2 = reinterpret_cast(!Channel ? m_planeb.target() : m_planea.target()); + const uint8_t icm = get_icm(); + const uint8_t tp_ctrl = get_transparency_control(); const int width = get_screen_width(); - uint32_t vsr = get_vsr(); - uint32_t vsr2 = get_vsr(); + uint32_t vsr = get_vsr(); + uint32_t vsr2 = get_vsr(); if (tp_ctrl == TCR_ALWAYS || !icm || !vsr) { @@ -483,18 +483,18 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) return; } - const uint32_t decodingMode = m_ddr[Path] & DDR_FT; + const uint32_t decodingMode = m_ddr[Channel] & DDR_FT; - const uint8_t mosaic_enable = get_mosaic_enable(); - const uint8_t mosaic_factor = get_mosaic_factor(); + 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[Path]; + const uint32_t dyuv_abs_start = m_dyuv_abs_start[Channel]; uint8_t y = (dyuv_abs_start >> 16) & 0x000000ff; uint8_t u = (dyuv_abs_start >> 8) & 0x000000ff; uint8_t v = (dyuv_abs_start >> 0) & 0x000000ff; - const uint32_t mask_bits = (~m_mask_color[Path]) & 0x00fcfcfc; - const uint32_t tp_color_match = m_transparent_color[Path] & mask_bits; + const uint32_t mask_bits = (~m_mask_color[Channel]) & 0x00fcfcfc; + const uint32_t tp_color_match = m_transparent_color[Channel] & mask_bits; const uint8_t tp_ctrl_type = tp_ctrl & 0x07; const bool use_rgb_tp_bit = (tp_ctrl_type == TCR_RGB); @@ -503,10 +503,10 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) const int matte_flag_index = BIT(~tp_ctrl_type, 0); const bool *const matte_flags = m_matte_flag[matte_flag_index]; const bool use_matte_flag = (tp_ctrl_type >= TCR_MF0 && tp_ctrl_type <= TCR_MF1_KEY1); - const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. + const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Channel == 1)); // DYUV and RGB do not have access to color key. const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); - LOGMASKED(LOG_VSR, "Scanline %d: VSR Path %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Path, icm, vsr); + LOGMASKED(LOG_VSR, "Scanline %d: VSR Channel %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Channel, icm, vsr); for (uint32_t x = 0; x < width; ) { @@ -550,7 +550,7 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) else { bool clut_select = BIT(m_image_coding_method, ICM_CS_BIT); - if (icm == ICM_RGB555 && Path == 1) + if (icm == ICM_RGB555 && Channel == 1) { const uint8_t byte1 = data2[(vsr2++ & 0x0007ffff) ^ 1]; const uint8_t blue = (byte & 0b11111) << 3; @@ -562,12 +562,12 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) else if (icm == ICM_CLUT4) { const uint8_t mask = (decodingMode == DDR_FT_RLE) ? 0x7 : 0xf; - color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; - color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; + color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; + color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; } else { - color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; + color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; } int length_m = mosaic_enable ? (mosaic_factor * 2) : 2; @@ -590,8 +590,8 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) x = end; } } - set_vsr(vsr); - set_vsr(vsr2); + set_vsr(vsr); + set_vsr(vsr2); } const uint32_t mcd212_device::s_4bpp_color[16] = @@ -1002,7 +1002,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma template int mcd212_device::ram_dtack_cycle_count<0>(); template int mcd212_device::ram_dtack_cycle_count<1>(); -template +template int mcd212_device::ram_dtack_cycle_count() { // Per MCD-212 documentation, it takes 4 CLKs (2 SCC68070 clocks) for a VRAM access during the System timing slot. @@ -1011,8 +1011,8 @@ int mcd212_device::ram_dtack_cycle_count() if (!BIT(m_dcr[0], DCR_DE_BIT)) return 2; - // No contending for Ch.1/Ch.2 timing slots if a relevant Path is disabled - if (!BIT(m_dcr[Path], DCR_ICA_BIT)) + // No contending for Ch.1/Ch.2 timing slots if a relevant Channel is disabled + if (!BIT(m_dcr[Channel], DCR_ICA_BIT)) return 2; const int x = screen().hpos(); @@ -1028,7 +1028,7 @@ int mcd212_device::ram_dtack_cycle_count() return 2; // No contending for Ch.1/Ch.2 timing slots during the free-run area of DCA lines if DCA is disabled - if (!BIT(m_dcr[Path], DCR_DCA_BIT) && x_outside_active_display) + if (!BIT(m_dcr[Channel], DCR_DCA_BIT) && x_outside_active_display) return 2; // System access is restricted to the last 5 out of every 16 CLKs. diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index fe81045a..6aed1eba 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -51,7 +51,7 @@ class mcd212_device : public device_t, void map(address_map &map) ATTR_COLD; - template int ram_dtack_cycle_count(); + template int ram_dtack_cycle_count(); int rom_dtack_cycle_count(); protected: @@ -252,24 +252,24 @@ class mcd212_device : public device_t, int get_border_width(); uint32_t get_backdrop_plane(); - template void set_vsr(uint32_t value); - template uint32_t get_vsr(); + 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_dcp(uint32_t value); + template uint32_t get_dcp(); - template void set_display_parameters(uint8_t value); + template void set_display_parameters(uint8_t value); - template void process_ica(); - template void process_dca(); + template void process_ica(); + template void process_dca(); - 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); + 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); - template void set_register(uint8_t reg, uint32_t value); + template void set_register(uint8_t reg, uint32_t value); template void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out); From 246e6c35b68d74e8fb2fe226a9740fabe5d979ba Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 16:04:53 -0600 Subject: [PATCH 42/47] No fixes? This reverts commit b3509eaf1db93d6452ab39f0f1d5a841ea1b1fc0. --- src/mame/video/mcd212.cpp | 188 +++++++++++++++++++------------------- src/mame/video/mcd212.h | 28 +++--- 2 files changed, 108 insertions(+), 108 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 682ff206..ebcc673d 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -107,7 +107,7 @@ void mcd212_device::update_matte_arrays() } } -template +template void mcd212_device::set_register(uint8_t reg, uint32_t value) { switch (reg) @@ -121,81 +121,81 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) 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: { - const uint8_t clut_index = m_clut_bank[Channel] * 0x40 + (reg - 0x80); + const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method - if (Channel == 0) + if (Path == 0) { m_image_coding_method = value; } break; case 0xc1: // Transparency Control - if (Channel == 0) + if (Path == 0) { m_transparency_control = value; } break; case 0xc2: // Plane Order - if (Channel == 0) + if (Path == 0) { m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register - m_clut_bank[Channel] = Channel ? (2 | (value & 0x00000001)) : (value & 0x00000003); + m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A - if (Channel == 0) + if (Path == 0) { m_transparent_color[0] = value & 0x00fcfcfc; } break; case 0xc6: // Transparent Color B - if (Channel == 1) + if (Path == 1) { m_transparent_color[1] = value & 0x00fcfcfc; } break; case 0xc7: // Mask Color A - if (Channel == 0) + if (Path == 0) { m_mask_color[0] = value & 0x00fcfcfc; } break; case 0xc9: // Mask Color B - if (Channel == 1) + if (Path == 1) { m_mask_color[1] = value & 0x00fcfcfc; } break; case 0xca: // Delta YUV Absolute Start Value A - if (Channel == 0) + if (Path == 0) { m_dyuv_abs_start[0] = value; } break; case 0xcb: // Delta YUV Absolute Start Value B - if (Channel == 1) + if (Path == 1) { m_dyuv_abs_start[1] = value; } break; case 0xcd: // Cursor Position - if (Channel == 0) + if (Path == 0) { m_cursor_position = value; } break; case 0xce: // Cursor Control - if (Channel == 0) + if (Path == 0) { m_cursor_control = value; } break; case 0xcf: // Cursor Pattern - if (Channel == 0) + if (Path == 0) { m_cursor_pattern[(value >> 16) & 0x000f] = value & 0x0000ffff; } @@ -212,32 +212,32 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) update_matte_arrays(); break; case 0xd8: // Backdrop Color - if (Channel == 0) + if (Path == 0) { m_backdrop_color = value; } break; case 0xd9: // Mosaic Pixel Hold Factor A - if (Channel == 0) + if (Path == 0) { m_mosaic_hold[0] = value; } break; case 0xda: // Mosaic Pixel Hold Factor B - if (Channel == 1) + if (Path == 1) { m_mosaic_hold[1] = value; } break; case 0xdb: // Weight Factor A - if (Channel == 0) + if (Path == 0) { m_weight_factor[0][0] = (uint8_t)value; update_matte_arrays(); } break; case 0xdc: // Weight Factor B - if (Channel == 1) + if (Path == 1) { m_weight_factor[1][0] = (uint8_t)value; update_matte_arrays(); @@ -246,41 +246,41 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) } } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_vsr() { - return ((m_dcr[Channel] & 0x3f) << 16) | m_vsr[Channel]; + return ((m_dcr[Path] & 0x3f) << 16) | m_vsr[Path]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_vsr(uint32_t value) { - m_vsr[Channel] = value & 0x0000ffff; - m_dcr[Channel] &= 0xffc0; - m_dcr[Channel] |= (value >> 16) & 0x003f; + m_vsr[Path] = value & 0x0000ffff; + m_dcr[Path] &= 0xffc0; + m_dcr[Path] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_dcp(uint32_t value) { - m_dcp[Channel] = value & 0x0000ffff; - m_ddr[Channel] &= 0xffc0; - m_ddr[Channel] |= (value >> 16) & 0x003f; + m_dcp[Path] = value & 0x0000ffff; + m_ddr[Path] &= 0xffc0; + m_ddr[Path] |= (value >> 16) & 0x003f; } -template +template inline ATTR_FORCE_INLINE uint32_t mcd212_device::get_dcp() { - return ((m_ddr[Channel] & 0x3f) << 16) | m_dcp[Channel]; + return ((m_ddr[Path] & 0x3f) << 16) | m_dcp[Path]; } -template +template inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t value) { - m_ddr[Channel] &= 0xf0ff; - m_ddr[Channel] |= (value & 0x0f) << 8; - m_dcr[Channel] &= 0xf7ff; - m_dcr[Channel] |= (value & 0x10) << 7; + m_ddr[Path] &= 0xf0ff; + m_ddr[Path] |= (value & 0x0f) << 8; + m_dcr[Path] &= 0xf7ff; + m_dcr[Path] |= (value & 0x10) << 7; } int mcd212_device::get_screen_width() @@ -299,10 +299,10 @@ int mcd212_device::get_border_width() return width; } -template +template void mcd212_device::process_ica() { - uint16_t *ica = Channel ? m_planeb.target() : m_planea.target(); + uint16_t *ica = Path ? m_planeb.target() : m_planea.target(); uint32_t addr = 0x200; uint32_t cmd = 0; @@ -321,11 +321,11 @@ void mcd212_device::process_ica() 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: - set_dcp(cmd & 0x003ffffc); + 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: - set_dcp(cmd & 0x003ffffc); + 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: @@ -333,29 +333,29 @@ void mcd212_device::process_ica() 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: - set_vsr(cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Channel); + m_csrr[1] |= 1 << (2 - Path); 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 - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } } -template +template void mcd212_device::process_dca() { - uint16_t *dca = Channel ? m_planeb.target() : m_planea.target(); - uint32_t addr = (m_dca[Channel] & 0x0007ffff) / 2; + uint16_t *dca = Path ? m_planeb.target() : m_planea.target(); + uint32_t addr = (m_dca[Path] & 0x0007ffff) / 2; uint32_t cmd = 0; uint32_t count = 0; uint32_t max = 64; @@ -380,29 +380,29 @@ void mcd212_device::process_dca() 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: - set_dcp(cmd & 0x003ffffc); - m_dca[Channel] = cmd & 0x0007fffc; + set_dcp(cmd & 0x003ffffc); + m_dca[Path] = 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: - set_vsr(cmd & 0x003fffff); + 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: - set_vsr(cmd & 0x003fffff); + 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: - m_csrr[1] |= 1 << (2 - Channel); + m_csrr[1] |= 1 << (2 - Path); 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 - set_display_parameters(cmd & 0x1f); + set_display_parameters(cmd & 0x1f); break; default: - set_register(cmd >> 24, cmd & 0x00ffffff); + set_register(cmd >> 24, cmd & 0x00ffffff); break; } } @@ -412,10 +412,10 @@ void mcd212_device::process_dca() addr += (max - count) >> 1; } - m_dca[Channel] = addr * 2; + m_dca[Path] = addr * 2; } -template +template static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) { switch (icm) @@ -423,58 +423,58 @@ static inline uint8_t BYTE_TO_CLUT(int icm, uint8_t byte, bool clut_select) case 1: return byte; case 3: - return (Channel ? 0x80 : 0) | (byte & 0x7f); + return (Path ? 0x80 : 0) | (byte & 0x7f); case 4: - if (Channel == 0) + if (Path == 0) { return (clut_select ? 0x80 : 0) | (byte & 0x7f); } break; case 11: - return (Channel ? 0x80 : 0) | (byte & 0x0f); + return (Path ? 0x80 : 0) | (byte & 0x0f); default: break; } return 0; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_transparency_control() { - return (m_transparency_control >> (Channel ? 8 : 0)) & 0x0f; + return (m_transparency_control >> (Path ? 8 : 0)) & 0x0f; } -template +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; + const uint32_t mask = Path ? ICM_MODE2 : ICM_MODE1; + const uint32_t shift = Path ? ICM_MODE2_SHIFT : ICM_MODE1_SHIFT; return (m_image_coding_method & mask) >> shift; } -template +template inline ATTR_FORCE_INLINE bool mcd212_device::get_mosaic_enable() { - return (m_ddr[Channel] & DDR_FT) == DDR_FT_MOSAIC; + return (m_ddr[Path] & DDR_FT) == DDR_FT_MOSAIC; } -template +template inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_mosaic_factor() { - return 1 << (((m_ddr[Channel] & DDR_MT) >> DDR_MT_SHIFT) + 1); + return 1 << (((m_ddr[Path] & DDR_MT) >> DDR_MT_SHIFT) + 1); } -template +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 *data2 = reinterpret_cast(!Channel ? m_planeb.target() : m_planea.target()); - const uint8_t icm = get_icm(); - const uint8_t tp_ctrl = get_transparency_control(); + const uint8_t *data = reinterpret_cast(Path ? m_planeb.target() : m_planea.target()); + const uint8_t *data2 = reinterpret_cast(!Path ? m_planeb.target() : m_planea.target()); + const uint8_t icm = get_icm(); + const uint8_t tp_ctrl = get_transparency_control(); const int width = get_screen_width(); - uint32_t vsr = get_vsr(); - uint32_t vsr2 = get_vsr(); + uint32_t vsr = get_vsr(); + uint32_t vsr2 = get_vsr(); if (tp_ctrl == TCR_ALWAYS || !icm || !vsr) { @@ -483,18 +483,18 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) return; } - const uint32_t decodingMode = m_ddr[Channel] & DDR_FT; + const uint32_t decodingMode = m_ddr[Path] & DDR_FT; - const uint8_t mosaic_enable = get_mosaic_enable(); - const uint8_t mosaic_factor = get_mosaic_factor(); + 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 uint32_t dyuv_abs_start = m_dyuv_abs_start[Path]; uint8_t y = (dyuv_abs_start >> 16) & 0x000000ff; uint8_t u = (dyuv_abs_start >> 8) & 0x000000ff; uint8_t v = (dyuv_abs_start >> 0) & 0x000000ff; - const uint32_t mask_bits = (~m_mask_color[Channel]) & 0x00fcfcfc; - const uint32_t tp_color_match = m_transparent_color[Channel] & mask_bits; + const uint32_t mask_bits = (~m_mask_color[Path]) & 0x00fcfcfc; + const uint32_t tp_color_match = m_transparent_color[Path] & mask_bits; const uint8_t tp_ctrl_type = tp_ctrl & 0x07; const bool use_rgb_tp_bit = (tp_ctrl_type == TCR_RGB); @@ -503,10 +503,10 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) const int matte_flag_index = BIT(~tp_ctrl_type, 0); const bool *const matte_flags = m_matte_flag[matte_flag_index]; const bool use_matte_flag = (tp_ctrl_type >= TCR_MF0 && tp_ctrl_type <= TCR_MF1_KEY1); - const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Channel == 1)); // DYUV and RGB do not have access to color key. + const bool is_dyuv_rgb = (icm == ICM_DYUV) || ((icm == ICM_RGB555) && (Path == 1)); // DYUV and RGB do not have access to color key. const bool use_color_key = !is_dyuv_rgb && ((tp_ctrl_type == TCR_KEY) || (tp_ctrl_type == TCR_MF0_KEY1) || (tp_ctrl_type == TCR_MF1_KEY1)); - LOGMASKED(LOG_VSR, "Scanline %d: VSR Channel %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Channel, icm, vsr); + LOGMASKED(LOG_VSR, "Scanline %d: VSR Path %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Path, icm, vsr); for (uint32_t x = 0; x < width; ) { @@ -550,7 +550,7 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) else { bool clut_select = BIT(m_image_coding_method, ICM_CS_BIT); - if (icm == ICM_RGB555 && Channel == 1) + if (icm == ICM_RGB555 && Path == 1) { const uint8_t byte1 = data2[(vsr2++ & 0x0007ffff) ^ 1]; const uint8_t blue = (byte & 0b11111) << 3; @@ -562,12 +562,12 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) else if (icm == ICM_CLUT4) { const uint8_t mask = (decodingMode == DDR_FT_RLE) ? 0x7 : 0xf; - color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; - color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; + color0 = m_clut[BYTE_TO_CLUT(icm, mask & (byte >> 4), clut_select)]; + color1 = m_clut[BYTE_TO_CLUT(icm, mask & byte, clut_select)]; } else { - color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; + color1 = color0 = m_clut[BYTE_TO_CLUT(icm, byte, clut_select)]; } int length_m = mosaic_enable ? (mosaic_factor * 2) : 2; @@ -590,8 +590,8 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) x = end; } } - set_vsr(vsr); - set_vsr(vsr2); + set_vsr(vsr); + set_vsr(vsr2); } const uint32_t mcd212_device::s_4bpp_color[16] = @@ -1002,7 +1002,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma template int mcd212_device::ram_dtack_cycle_count<0>(); template int mcd212_device::ram_dtack_cycle_count<1>(); -template +template int mcd212_device::ram_dtack_cycle_count() { // Per MCD-212 documentation, it takes 4 CLKs (2 SCC68070 clocks) for a VRAM access during the System timing slot. @@ -1011,8 +1011,8 @@ int mcd212_device::ram_dtack_cycle_count() if (!BIT(m_dcr[0], DCR_DE_BIT)) return 2; - // No contending for Ch.1/Ch.2 timing slots if a relevant Channel is disabled - if (!BIT(m_dcr[Channel], DCR_ICA_BIT)) + // No contending for Ch.1/Ch.2 timing slots if a relevant Path is disabled + if (!BIT(m_dcr[Path], DCR_ICA_BIT)) return 2; const int x = screen().hpos(); @@ -1028,7 +1028,7 @@ int mcd212_device::ram_dtack_cycle_count() return 2; // No contending for Ch.1/Ch.2 timing slots during the free-run area of DCA lines if DCA is disabled - if (!BIT(m_dcr[Channel], DCR_DCA_BIT) && x_outside_active_display) + if (!BIT(m_dcr[Path], DCR_DCA_BIT) && x_outside_active_display) return 2; // System access is restricted to the last 5 out of every 16 CLKs. diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index 6aed1eba..fe81045a 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -51,7 +51,7 @@ class mcd212_device : public device_t, void map(address_map &map) ATTR_COLD; - template int ram_dtack_cycle_count(); + template int ram_dtack_cycle_count(); int rom_dtack_cycle_count(); protected: @@ -252,24 +252,24 @@ class mcd212_device : public device_t, int get_border_width(); uint32_t get_backdrop_plane(); - template void set_vsr(uint32_t value); - template uint32_t get_vsr(); + 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_dcp(uint32_t value); + template uint32_t get_dcp(); - template void set_display_parameters(uint8_t value); + template void set_display_parameters(uint8_t value); - template void process_ica(); - template void process_dca(); + template void process_ica(); + template void process_dca(); - 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); + 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); - template void set_register(uint8_t reg, uint32_t value); + template void set_register(uint8_t reg, uint32_t value); template void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out); From 2efa252957488f08bfa684150bfa1f9381b2ce69 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 16:08:01 -0600 Subject: [PATCH 43/47] Update mcd212.cpp driver AGAIN. This is driving me insane... --- src/mame/video/mcd212.cpp | 318 +++++++++++++++++++++----------------- 1 file changed, 180 insertions(+), 138 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index ebcc673d..140cc164 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -17,7 +17,7 @@ TODO: -- Unknown yet. +- QHY DYUV Image Decoder *******************************************************************************/ @@ -54,7 +54,6 @@ inline ATTR_FORCE_INLINE uint8_t mcd212_device::get_matte_op(const uint32_t matt void mcd212_device::update_matte_arrays() { - const int width = get_screen_width(); const int num_mattes = BIT(m_image_coding_method, ICM_NM_BIT) ? 2 : 1; @@ -122,81 +121,95 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: { const uint8_t clut_index = m_clut_bank[Path] * 0x40 + (reg - 0x80); + LOGMASKED(LOG_CLUT, "%s: Path %d: CLUT[%d] = %08x\n", machine().describe_context(), Path, clut_index, value); m_clut[clut_index] = value & 0x00fcfcfc; } break; case 0xc0: // Image Coding Method if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Path 0: Image Coding Method = %08x\n", machine().describe_context(), value); m_image_coding_method = value; } break; case 0xc1: // Transparency Control if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Transparency Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_transparency_control = value; } break; case 0xc2: // Plane Order if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Plane Order = %08x\n", machine().describe_context(), screen().vpos(), value & 7); m_plane_order = value & 0x00000007; } break; case 0xc3: // CLUT Bank Register + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: CLUT Bank Register = %08x\n", machine().describe_context(), screen().vpos(), Path, value & 3); m_clut_bank[Path] = Path ? (2 | (value & 0x00000001)) : (value & 0x00000003); break; case 0xc4: // Transparent Color A if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Position = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_position = value; } break; case 0xce: // Cursor Control if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Cursor Control = %08x\n", machine().describe_context(), screen().vpos(), value); m_cursor_control = value; } break; case 0xcf: // Cursor Pattern if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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; @@ -208,30 +221,35 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xd5: case 0xd6: case 0xd7: + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path %d: matte Control %d = %08x\n", machine().describe_context(), screen().vpos(), Path, reg & 7, value); m_matte_control[reg & 7] = value; update_matte_arrays(); break; case 0xd8: // Backdrop Color if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Backdrop Color = %08x\n", machine().describe_context(), screen().vpos(), value); m_backdrop_color = value; } break; case 0xd9: // Mosaic Pixel Hold Factor A if (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 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 (Path == 0) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 0: Weight Factor A = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[0][0] = (uint8_t)value; update_matte_arrays(); } @@ -239,6 +257,7 @@ void mcd212_device::set_register(uint8_t reg, uint32_t value) case 0xdc: // Weight Factor B if (Path == 1) { + LOGMASKED(LOG_REGISTERS, "%s: Scanline %d, Path 1: Weight Factor B = %08x\n", machine().describe_context(), screen().vpos(), value); m_weight_factor[1][0] = (uint8_t)value; update_matte_arrays(); } @@ -299,6 +318,14 @@ int mcd212_device::get_border_width() return width; } +uint32_t mcd212_device::get_backdrop_plane() +{ + if (BIT(m_image_coding_method, ICM_EV_BIT)) + return 0; // External Video Background. Default to Black since there is no DVC. + else + return s_4bpp_color[m_backdrop_color]; +} + template void mcd212_device::process_ica() { @@ -315,36 +342,45 @@ void mcd212_device::process_ica() { 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DCP and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD VSR and STOP: VSR = %05x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); m_csrr[1] |= 1 << (2 - Path); 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 + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); set_display_parameters(cmd & 0x1f); break; default: + LOGMASKED(LOG_ICA, "%08x: %08x: ICA %d: SET REGISTER %02x = %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, cmd >> 24, cmd & 0x00ffffff); set_register(cmd >> 24, cmd & 0x00ffffff); break; } @@ -362,6 +398,8 @@ void mcd212_device::process_dca() bool addr_changed = false; bool processing = true; + LOGMASKED(LOG_DCA, "Scanline %d: Processing DCA %d\n", screen().vpos(), Path); + while (processing && count < max) { cmd = dca[addr++] << 16; @@ -371,34 +409,43 @@ void mcd212_device::process_dca() { 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: NOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); + 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP (NOP)\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DCP and STOP\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); set_dcp(cmd & 0x003ffffc); m_dca[Path] = 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD VSR and STOP: %06x\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path, 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: + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: INTERRUPT\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); m_csrr[1] |= 1 << (2 - Path); 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 + LOGMASKED(LOG_DCA, "%08x: %08x: DCA %d: RELOAD DISPLAY PARAMETERS\n", (addr - 2) * 2 + Path * 0x200000, cmd, Path); set_display_parameters(cmd & 0x1f); break; default: @@ -479,7 +526,7 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) if (tp_ctrl == TCR_ALWAYS || !icm || !vsr) { std::fill_n(pixels, get_screen_width(), s_4bpp_color[0]); - std::fill_n(transparent, get_screen_width(), (tp_ctrl == TCR_ALWAYS)); + std::fill_n(transparent, get_screen_width(), true); return; } @@ -603,152 +650,110 @@ const uint32_t mcd212_device::s_4bpp_color[16] = template void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out) { - 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; + const uint8_t icmA = get_icm<0>(); + const uint8_t icmB = get_icm<1>(); + uint16_t mosaic_count_a = (m_mosaic_hold[0] & 0x0000ff) << 1; + uint16_t mosaic_count_b = (m_mosaic_hold[1] & 0x0000ff) << 1; const int width = get_screen_width(); const int border_width = get_border_width(); 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)) + // Console Verified. CLUT4 pixels are drawn in pairs during VSR. So the mosaic here is halved. + if (icmA == ICM_CLUT4) + mosaic_count_a >>= 1; + if (icmB == ICM_CLUT4) + mosaic_count_b >>= 1; + + for (int x = 0; x < width; x++) { - for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) + if (transparent_a[x] && transparent_b[x]) { - 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++ = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; + out[x] = get_backdrop_plane(); + continue; } - } - else - { - for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) + uint32_t plane_a_cur = MosaicA ? plane_a[x - (x % mosaic_count_a)] : plane_a[x]; + uint32_t plane_b_cur = MosaicB ? plane_b[x - (x % mosaic_count_b)] : plane_b[x]; + + if (transparent_a[x]) { - if (OrderAB) - { - 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; - } - else - { - *out++ = backdrop; - } - } - 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++ = 0xff000000 | (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++ = 0xff000000 | (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; - } - else - { - *out++ = backdrop; - } - } + plane_a_cur = 0; + } + else if (OrderAB && (m_transparency_control & TCR_DISABLE_MX)) + { + plane_b_cur = 0; + } + + if (transparent_b[x]) + { + plane_b_cur = 0; } + else if (!OrderAB && (m_transparency_control & TCR_DISABLE_MX)) + { + plane_a_cur = 0; + } + + const int32_t plane_a_r = 0xff & (plane_a_cur >> 16); + const int32_t plane_a_g = 0xff & (plane_a_cur >> 8); + const int32_t plane_a_b = 0xff & plane_a_cur; + const int32_t plane_b_r = 0xff & (plane_b_cur >> 16); + const int32_t plane_b_g = 0xff & (plane_b_cur >> 8); + const int32_t plane_b_b = 0xff & plane_b_cur; + + const int32_t weighted_a_r = std::clamp((std::clamp(plane_a_r - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + const int32_t weighted_a_g = std::clamp((std::clamp(plane_a_g - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + const int32_t weighted_a_b = std::clamp((std::clamp(plane_a_b - 16, 0, 255) * weight_a[x]) >> 6, 0, 255); + + const int32_t weighted_b_r = std::clamp((std::clamp(plane_b_r - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + const int32_t weighted_b_g = std::clamp((std::clamp(plane_b_g - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + const int32_t weighted_b_b = std::clamp((std::clamp(plane_b_b - 16, 0, 255) * weight_b[x]) >> 6, 0, 255); + + const uint8_t out_r = std::clamp(weighted_a_r + weighted_b_r + 16, 0, 255); + const uint8_t out_g = std::clamp(weighted_a_g + weighted_b_g + 16, 0, 255); + const uint8_t out_b = std::clamp(weighted_a_b + weighted_b_b + 16, 0, 255); + out[x] = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; } if (border_width) { - std::fill_n(out, border_width, 0xff101010); + std::fill_n(&out[width], border_width, s_4bpp_color[0]); } } void mcd212_device::draw_cursor(uint32_t *scanline) { - if (m_cursor_control & CURCNT_EN) + if (!(m_cursor_control & CURCNT_EN)) + return; // Cursor is Disabled + + uint8_t color_index = m_cursor_control & CURCNT_COLOR; + if (m_blink_active) { - 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)) + const bool invert = BIT(m_cursor_control, CURCNT_BLKC_SHIFT); + if (!invert) + return; // Normal Blink + else + color_index = color_index ^ 0x7; // Inverted Color Blink. MCD212 Section 7.5 + } + + const uint16_t cursor_x = m_cursor_position & 0x3ff; + const uint16_t cursor_y = ((m_cursor_position >> 12) & 0x3ff) + m_ica_height; + const int32_t y = screen().vpos() - cursor_y; + const int width = get_screen_width(); + + if ((0 <= y) && (y < 16)) + { + const uint32_t color = s_4bpp_color[color_index]; + const uint8_t resolution = (m_cursor_control & CURCNT_CUW) ? 1 : 2; + for (int x = 0; x < 16; x++) { - const int width = get_screen_width(); - uint32_t color = s_4bpp_color[m_cursor_control & CURCNT_COLOR]; - y -= cursor_y; - if (m_cursor_control & CURCNT_CUW) - { - for (int x = cursor_x; x < cursor_x + 64 && x < width; x++) - { - if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 2)))) - { - scanline[x++] = color; - scanline[x++] = color; - scanline[x++] = color; - scanline[x] = color; - } - } - } - else + if (BIT(m_cursor_pattern[y], 15 - x)) { - for (int x = cursor_x; x < cursor_x + 32 && x < width; x++) + for (uint32_t j = 0; j < resolution; j++) { - if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 1)))) - { - scanline[x++] = color; - scanline[x] = color; - } + const uint32_t index = cursor_x + x * resolution + j; + if (index < width) + scanline[index] = color; } } } @@ -774,51 +779,61 @@ void mcd212_device::map(address_map &map) 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_MAIN_REG_WRITES, "%s: Control/Status Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_csrw[0]); } uint16_t mcd212_device::dcr1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[0]); } uint16_t mcd212_device::vsr1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Decoder Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_ddr[0]); } uint16_t mcd212_device::dca1_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%s: DCA Pointer 1 Read: %04x & %08x\n", machine().describe_context(), m_dca[0], mem_mask); return m_dca[0]; } void mcd212_device::dca1_w(offs_t offset, uint16_t data, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_WRITES, "%s: DCA Pointer 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[0]); } @@ -830,6 +845,7 @@ uint8_t mcd212_device::csr2_r() } 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)) @@ -840,46 +856,55 @@ uint8_t mcd212_device::csr2_r() void mcd212_device::csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: Display Command Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dcr[1]); } uint16_t mcd212_device::vsr2_r(offs_t offset, uint16_t mem_mask) { + LOGMASKED(LOG_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%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_MAIN_REG_READS, "%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_MAIN_REG_WRITES, "%s: DCA Pointer 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); COMBINE_DATA(&m_dca[1]); } @@ -899,6 +924,21 @@ TIMER_CALLBACK_MEMBER(mcd212_device::ica_tick) m_dca[1] = get_dcp<1>(); m_ica_timer->adjust(screen().time_until_pos(0, 0)); + + // Cursor Blink + m_blink_time += 5 + BIT(m_dcr[0], DCR_FD_BIT); // FD bit * 8... Page 4-3 MCD + // Adjust the blink time once per frame + if (!m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_CON) >> CURCNT_CON_SHIFT) * 60)) + { + m_blink_active = true; + m_blink_time = 0; + } + // If blink off time is 0, immediately turn back on. + if (m_blink_active && (m_blink_time >= ((m_cursor_control & CURCNT_COF) >> CURCNT_COF_SHIFT) * 60)) + { + m_blink_active = false; + m_blink_time = 0; + } } TIMER_CALLBACK_MEMBER(mcd212_device::dca_tick) @@ -925,7 +965,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma int scanline = screen.vpos(); - // Process VSR and mix if we're in the visible matte + // Process VSR and mix if we're in the visible region if (scanline >= m_ica_height) { uint32_t *out = &bitmap.pix(scanline); @@ -936,7 +976,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma // If PAL and 'Standard' bit set, insert a 20-line border on the top/bottom if ((scanline - m_ica_height < 20) || (scanline >= (m_total_height - 20))) { - std::fill_n(out, 768, 0xff101010); + std::fill_n(out, 768, s_4bpp_color[0]); draw_line = false; } } @@ -948,7 +988,7 @@ uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitma // If PAL and 'Standard' bit set, insert a 24px border on the left/right if (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) { - std::fill_n(out, 24, 0xff101010); + std::fill_n(out, 24, s_4bpp_color[0]); out += 24; } @@ -1032,7 +1072,7 @@ int mcd212_device::ram_dtack_cycle_count() return 2; // System access is restricted to the last 5 out of every 16 CLKs. - const int slot_cycle = (int)(machine().time().as_ticks(clock()) & 0xf); + const int slot_cycle = int(machine().time().as_ticks(clock()) & 0xf); if (slot_cycle >= 11) return 2; @@ -1077,6 +1117,7 @@ void mcd212_device::device_reset() m_ica_height = 32; m_total_height = 312; + m_blink_time = 0; m_int_callback(CLEAR_LINE); @@ -1111,12 +1152,10 @@ void mcd212_device::device_start() m_delta_uv_lut[d] = s_dyuv_deltas[d >> 4]; } - for (int16_t sw = 0; sw < 0x100; sw++) + for (uint16_t w = 0; w < 0x300; w++) { - 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; + const uint8_t limit = (w < 0x100) ? 0 : (w < 0x200) ? (w - 0x100) : 0xff; + m_dyuv_limit_lut[w] = limit; } for (int16_t sw = 0; sw < 0x100; sw++) @@ -1127,10 +1166,6 @@ void mcd212_device::device_start() m_dyuv_v_to_r[sw] = (351 * (sw - 128)) / 256; } - save_item(NAME(m_matte_flag[0])); - save_item(NAME(m_matte_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)); @@ -1155,6 +1190,13 @@ void mcd212_device::device_start() save_item(NAME(m_weight_factor[0])); save_item(NAME(m_weight_factor[1])); + save_item(NAME(m_matte_flag)); + save_item(NAME(m_ica_height)); + save_item(NAME(m_total_height)); + + save_item(NAME(m_blink_time)); + save_item(NAME(m_blink_active)); + m_dca_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mcd212_device::dca_tick), this)); m_dca_timer->adjust(attotime::never); From 4ef1a8754f8d1bbe62ed0925c23a7b45eb5c2e78 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 16:12:12 -0600 Subject: [PATCH 44/47] NO WAY THAT WORKED mcd212 driver updated by changing just three lines of code in the header. I'm so freaking baffled... --- src/mame/video/mcd212.cpp | 11 +++++++++++ src/mame/video/mcd212.h | 6 ++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index 140cc164..6d7ea671 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -1138,6 +1138,17 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev { } +//------------------------------------------------- +// device_resolve_objects - resolve objects that +// may be needed for other devices to set +// initial conditions at start time +//------------------------------------------------- + +void mcd212_device::device_resolve_objects() +{ + m_int_callback.resolve_safe(); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index fe81045a..b8c4ae99 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -56,8 +56,10 @@ class mcd212_device : public device_t, protected: // device_t implementation - virtual void device_start() override ATTR_COLD; - virtual void device_reset() override ATTR_COLD; + // device-level overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; TIMER_CALLBACK_MEMBER(ica_tick); TIMER_CALLBACK_MEMBER(dca_tick); From dc8bcfc538455eda47f97a56d07b6a52ddb07757 Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 16:26:58 -0600 Subject: [PATCH 45/47] Bump version to 0.287. --- android-project/app/src/main/AndroidManifest.xml | 2 +- makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android-project/app/src/main/AndroidManifest.xml b/android-project/app/src/main/AndroidManifest.xml index 3138a3c4..50871cca 100644 --- a/android-project/app/src/main/AndroidManifest.xml +++ b/android-project/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ diff --git a/makefile b/makefile index 25c9108a..73582913 100644 --- a/makefile +++ b/makefile @@ -1490,7 +1490,7 @@ endif ifeq (posix,$(SHELLTYPE)) $(GENDIR)/version.cpp: makefile $(GENDIR)/git_desc | $(GEN_FOLDERS) - @echo '#define BARE_BUILD_VERSION "0.239"' > $@ + @echo '#define BARE_BUILD_VERSION "0.287"' > $@ @echo '#define BARE_VCS_REVISION "$(NEW_GIT_VERSION)"' >> $@ @echo 'extern const char bare_build_version[];' >> $@ @echo 'extern const char bare_vcs_revision[];' >> $@ @@ -1500,7 +1500,7 @@ $(GENDIR)/version.cpp: makefile $(GENDIR)/git_desc | $(GEN_FOLDERS) @echo 'const char build_version[] = BARE_BUILD_VERSION " (" BARE_VCS_REVISION ")";' >> $@ else $(GENDIR)/version.cpp: makefile $(GENDIR)/git_desc | $(GEN_FOLDERS) - @echo #define BARE_BUILD_VERSION "0.239" > $@ + @echo #define BARE_BUILD_VERSION "0.287" > $@ @echo #define BARE_VCS_REVISION "$(NEW_GIT_VERSION)" >> $@ @echo extern const char bare_build_version[]; >> $@ @echo extern const char bare_vcs_revision[]; >> $@ From 5de268ef80d8a571d8b8adb9381185a1c192dc0f Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 16:34:43 -0600 Subject: [PATCH 46/47] Make the gameName variable store more data so the program doesn't crash on longer filenames (hopefully) --- src/osd/libretro/libretro-internal/retro_init.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/osd/libretro/libretro-internal/retro_init.cpp b/src/osd/libretro/libretro-internal/retro_init.cpp index eb7f65cf..af54aaa5 100644 --- a/src/osd/libretro/libretro-internal/retro_init.cpp +++ b/src/osd/libretro/libretro-internal/retro_init.cpp @@ -82,7 +82,7 @@ static char MgamePath[1024]; static char MparentPath[1024]; static char MgameName[512]; static char MsystemName[512]; -static char gameName[1024]; +static char gameName[4096]; static char forcedSystem[9] = "cdimono1"; // args for cores From fcba323f6cd0e9bb6c4ac27d0170bd4838dc811f Mon Sep 17 00:00:00 2001 From: OM3GAZX Date: Wed, 8 Jul 2026 19:04:52 -0600 Subject: [PATCH 47/47] Revert monitor_retro.cpp update. --- src/osd/modules/monitor/monitor_retro.cpp | 51 ++++++++++++++++++----- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/osd/modules/monitor/monitor_retro.cpp b/src/osd/modules/monitor/monitor_retro.cpp index cd2bbaf5..da880532 100644 --- a/src/osd/modules/monitor/monitor_retro.cpp +++ b/src/osd/modules/monitor/monitor_retro.cpp @@ -27,10 +27,16 @@ class retro_monitor_info : public osd_monitor_info private: void refresh() override { + m_pos_size = osd_rect(0,0, fb_width, fb_height); m_usuable_pos_size = osd_rect(0,0, fb_width, fb_height); m_is_primary = (oshandle() == 0); + + if(alternate_renderer==false) + set_aspect(retro_aspect); + //printf("refreshmonitor (%d x %d) a:%f\n", fb_width, fb_height,retro_aspect); } + }; //============================================================ @@ -82,29 +88,52 @@ class retro_monitor_module : public monitor_module_base protected: int init_internal(const osd_options& options) override { - int i; - - for (i = 0; i < 1; i++) + // make a list of monitors { - char temp[64]; - snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); + int i; + + osd_printf_verbose("Enter init_monitors\n"); - // allocate a new monitor info - std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); + for (i = 0; i < 1; i++) + { + char temp[64]; + snprintf(temp, sizeof(temp) - 1, "%s%d", OSDOPTION_SCREEN, i); - // guess the aspect ratio assuming square pixels - monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); + // allocate a new monitor info + std::shared_ptr monitor = std::make_shared(*this, i, temp, 1.0f); - // hook us into the list - add_monitor(monitor); + osd_printf_verbose("Adding monitor %s (%d x %d)\n", monitor->devicename().c_str(), + monitor->position_size().width(), monitor->position_size().height()); + + // guess the aspect ratio assuming square pixels + monitor->set_aspect(static_cast(monitor->position_size().width()) / static_cast(monitor->position_size().height())); +printf("Adding monitor %s (%d x %d) a:%f\n", monitor->devicename().c_str(), + monitor->position_size().width(), monitor->position_size().height(),(float)monitor->position_size().width()/(float) monitor->position_size().height()); + + // hook us into the list + add_monitor(monitor); + } } + osd_printf_verbose("Leave init_monitors\n"); return 0; } private: +/* + sdl.h = osd.height(); + sdl.w = osd.width(); + sdl.x = osd.left(); + sdl.y = osd.top(); + +*/ static int compute_intersection(const osd_rect &rect1, const osd_rect &rect2) { +/* + SDL_Rect intersection; + if (SDL_IntersectRect(&sdl1, &sdl2, &intersection)) + return intersection.w + intersection.h; +*/ return 0; } };