From 255e3d6f3f2796ec1ae5e724970465d938159c2e Mon Sep 17 00:00:00 2001 From: MooglyGuy Date: Thu, 13 Jan 2022 02:37:27 +0100 Subject: -mcd212: Various accuracy and timing improvements. [Ryan Holtz] (#9123) * Added wait states on ROM and VRAM accesses. * Simplified pixel-duplication in 360/384-width modes. * Fixed DCA to process after VSR. * Switched to use raw parameters for screens. * Fixed some transparency-fill issues with disabled ICM/VSR. --- src/mame/drivers/cdi.cpp | 86 +++--- src/mame/includes/cdi.h | 11 +- src/mame/video/mcd212.cpp | 701 +++++++++++++++++++++++++--------------------- src/mame/video/mcd212.h | 106 ++++--- 4 files changed, 507 insertions(+), 397 deletions(-) diff --git a/src/mame/drivers/cdi.cpp b/src/mame/drivers/cdi.cpp index 40cb2e4d876..2243e31af76 100644 --- a/src/mame/drivers/cdi.cpp +++ b/src/mame/drivers/cdi.cpp @@ -3,8 +3,8 @@ /****************************************************************************** - Philips CD-I-based games - ------------------------ + Philips CD-i consoles and games + ------------------------------- Preliminary MAME driver by Ryan Holtz Help provided by CD-i Fan @@ -30,14 +30,18 @@ STATUS: * Philips IMS66490, "CDIC" ADPCM decoder * PC85010 DSP - Quizard: -- Quizard 3 and 4 fail when going in-game, presumably due to CD-i emulation - faults. - TODO: +- Screen clocks are a hack right now; they should be exactly CLOCK_A/2. However, the + MCD-212 documentation states in both tables and timing diagrams that vertical retrace + has an additional half-line even in non-interlaced mode, which cannot be represented + in the current screen-timing framework. The input clock has been adjusted downward + to factor out this half-line, resulting in the expected 50Hz exactly in PAL mode. + - Proper abstraction of the 68070's internal devices (UART, DMA, Timers, etc.) + - Mono-I: Full emulation of the CDIC, as well as the SERVO and SLAVE MCUs + - Mono-II: SERVO and SLAVE I/O device hookup - Mono-II: DSP56k hookup @@ -81,8 +85,8 @@ TODO: void cdi_state::cdimono1_mem(address_map &map) { map(0x000000, 0xffffff).rw(FUNC(cdi_state::bus_error_r), FUNC(cdi_state::bus_error_w)); - map(0x000000, 0x07ffff).ram().share("mcd212:planea"); - map(0x200000, 0x27ffff).ram().share("mcd212:planeb"); + map(0x000000, 0x07ffff).rw(FUNC(cdi_state::plane_r<0>), FUNC(cdi_state::plane_w<0>)).share("plane0"); + map(0x200000, 0x27ffff).rw(FUNC(cdi_state::plane_r<1>), FUNC(cdi_state::plane_w<1>)).share("plane1"); map(0x300000, 0x303bff).rw(m_cdic, FUNC(cdicdic_device::ram_r), FUNC(cdicdic_device::ram_w)); #if ENABLE_UART_PRINTING map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); @@ -91,7 +95,7 @@ void cdi_state::cdimono1_mem(address_map &map) map(0x310000, 0x317fff).rw(m_slave_hle, FUNC(cdislave_hle_device::slave_r), FUNC(cdislave_hle_device::slave_w)); map(0x318000, 0x31ffff).noprw(); map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */ - map(0x400000, 0x47ffff).rom().region("maincpu", 0); + map(0x400000, 0x47ffff).r(FUNC(cdi_state::main_rom_r)); map(0x4fffe0, 0x4fffff).m(m_mcd212, FUNC(mcd212_device::map)); map(0x500000, 0x57ffff).ram(); map(0xd00000, 0xdfffff).ram(); // DVC RAM block 1 @@ -101,22 +105,21 @@ void cdi_state::cdimono1_mem(address_map &map) void cdi_state::cdimono2_mem(address_map &map) { - map(0x000000, 0x07ffff).ram().share("mcd212:planea"); - map(0x200000, 0x27ffff).ram().share("mcd212:planeb"); + map(0x000000, 0x07ffff).ram().share("plane0"); + map(0x200000, 0x27ffff).ram().share("plane1"); #if ENABLE_UART_PRINTING map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); #endif map(0x320000, 0x323fff).rw("mk48t08", FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)).umask16(0xff00); /* nvram (only low bytes used) */ - map(0x400000, 0x47ffff).rom().region("maincpu", 0); + map(0x400000, 0x47ffff).r(FUNC(cdi_state::main_rom_r)); map(0x4fffe0, 0x4fffff).m(m_mcd212, FUNC(mcd212_device::map)); } void cdi_state::cdi910_mem(address_map &map) { - map(0x000000, 0x07ffff).ram().share("mcd212:planea"); + map(0x000000, 0x07ffff).ram().share("plane0"); map(0x180000, 0x1fffff).rom().region("maincpu", 0); // boot vectors point here - - map(0x200000, 0x27ffff).ram().share("mcd212:planeb"); + map(0x200000, 0x27ffff).ram().share("plane1"); #if ENABLE_UART_PRINTING map(0x301400, 0x301403).r(m_maincpu, FUNC(scc68070_device::uart_loopback_enable)); #endif @@ -174,8 +177,8 @@ INPUT_PORTS_END void cdi_state::machine_reset() { - uint16_t *src = (uint16_t*)memregion("maincpu")->base(); - uint16_t *dst = m_planea; + uint16_t *src = &m_main_rom[0]; + uint16_t *dst = &m_plane_ram[0][0]; memcpy(dst, src, 0x8); } @@ -194,6 +197,31 @@ void quizard_state::machine_reset() } +/*************************** +* Wait-State Handling * +***************************/ + +template +uint16_t cdi_state::plane_r(offs_t offset, uint16_t mem_mask) +{ + m_maincpu->eat_cycles(m_mcd212->ram_dtack_cycle_count()); + return m_plane_ram[Channel][offset]; +} + +template +void cdi_state::plane_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + m_maincpu->eat_cycles(m_mcd212->ram_dtack_cycle_count()); + COMBINE_DATA(&m_plane_ram[Channel][offset]); +} + +uint16_t cdi_state::main_rom_r(offs_t offset) +{ + m_maincpu->eat_cycles(m_mcd212->rom_dtack_cycle_count()); + return m_main_rom[offset]; +} + + /********************** * BERR Handling * **********************/ @@ -393,18 +421,14 @@ void cdi_state::cdimono1_base(machine_config &config) m_maincpu->set_addrmap(AS_PROGRAM, &cdi_state::cdimono1_mem); m_maincpu->iack4_callback().set(m_cdic, FUNC(cdicdic_device::intack_r)); - MCD212(config, m_mcd212, CLOCK_A); + MCD212(config, m_mcd212, CLOCK_A, m_plane_ram[0], m_plane_ram[1]); m_mcd212->set_screen("screen"); m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w)); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(50); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); + screen.set_raw(14976000, 960, 0, 768, 312, 32, 312); screen.set_video_attributes(VIDEO_UPDATE_SCANLINE); - screen.set_size(384, 312); - screen.set_visarea(0, 384-1, 0, 312-1); // TODO: dynamic resolution screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update)); - screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank)); SCREEN(config, m_lcd, SCREEN_TYPE_RASTER); m_lcd->set_refresh_hz(50); @@ -445,18 +469,14 @@ void cdi_state::cdimono2(machine_config &config) SCC68070(config, m_maincpu, CLOCK_A); m_maincpu->set_addrmap(AS_PROGRAM, &cdi_state::cdimono2_mem); - MCD212(config, m_mcd212, CLOCK_A); + MCD212(config, m_mcd212, CLOCK_A, m_plane_ram[0], m_plane_ram[1]); m_mcd212->set_screen("screen"); m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w)); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(60); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); + screen.set_raw(14976000, 960, 0, 768, 312, 32, 312); screen.set_video_attributes(VIDEO_UPDATE_SCANLINE); - screen.set_size(384, 312); - screen.set_visarea(0, 384-1, 0, 312-1); // TODO: dynamic resolution screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update)); - screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank)); SCREEN(config, m_lcd, SCREEN_TYPE_RASTER); m_lcd->set_refresh_hz(60); @@ -493,18 +513,14 @@ void cdi_state::cdi910(machine_config &config) SCC68070(config, m_maincpu, CLOCK_A); m_maincpu->set_addrmap(AS_PROGRAM, &cdi_state::cdi910_mem); - MCD212(config, m_mcd212, CLOCK_A); + MCD212(config, m_mcd212, CLOCK_A, m_plane_ram[0], m_plane_ram[1]); m_mcd212->set_screen("screen"); m_mcd212->int_callback().set(m_maincpu, FUNC(scc68070_device::int1_w)); screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); - screen.set_refresh_hz(50); - screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); + screen.set_raw(14976000, 960, 0, 768, 312, 32, 312); screen.set_video_attributes(VIDEO_UPDATE_SCANLINE); - screen.set_size(384, 312); - screen.set_visarea(0, 384-1, 32, 312-1); // TODO: dynamic resolution screen.set_screen_update(m_mcd212, FUNC(mcd212_device::screen_update)); - screen.screen_vblank().set(m_mcd212, FUNC(mcd212_device::screen_vblank)); SCREEN(config, m_lcd, SCREEN_TYPE_RASTER); m_lcd->set_refresh_hz(60); diff --git a/src/mame/includes/cdi.h b/src/mame/includes/cdi.h index d3e7445087f..69e8a86241d 100644 --- a/src/mame/includes/cdi.h +++ b/src/mame/includes/cdi.h @@ -21,8 +21,9 @@ public: cdi_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") + , m_main_rom(*this, "maincpu") , m_lcd(*this, "lcd") - , m_planea(*this, "mcd212:planea") + , m_plane_ram(*this, "plane%u", 0U) , m_slave_hle(*this, "slave_hle") , m_servo(*this, "servo") , m_slave(*this, "slave") @@ -42,6 +43,7 @@ protected: void cdimono1_mem(address_map &map); required_device m_maincpu; + required_region_ptr m_main_rom; optional_device m_lcd; private: @@ -58,13 +60,18 @@ private: 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 m_planea; + required_shared_ptr_array m_plane_ram; optional_device m_slave_hle; optional_device m_servo; optional_device m_slave; diff --git a/src/mame/video/mcd212.cpp b/src/mame/video/mcd212.cpp index ba78e3affbf..4031385d70a 100644 --- a/src/mame/video/mcd212.cpp +++ b/src/mame/video/mcd212.cpp @@ -23,7 +23,6 @@ TODO: #include "emu.h" #include "video/mcd212.h" - #include "screen.h" #define LOG_UNKNOWNS (1U << 1) @@ -58,6 +57,7 @@ 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(); if (BIT(m_image_coding_method, ICM_NR_BIT)) { @@ -70,7 +70,7 @@ void mcd212_device::update_region_arrays() return; } - for (int x = 0; x < 768; x++) + for (int x = 0; x < width; x++) { for (int flag = 0; flag < 2; flag++) { @@ -141,7 +141,7 @@ void mcd212_device::update_region_arrays() else { int region_idx = 0; - for (int x = 0; x < 768; x++) + for (int x = 0; x < width; x++) { if (region_idx < 8) { @@ -408,42 +408,20 @@ inline ATTR_FORCE_INLINE void mcd212_device::set_display_parameters(uint8_t valu m_dcr[Channel] |= (value & 0x10) << 7; } -void mcd212_device::update_visible_area() +int mcd212_device::get_screen_width() { - rectangle visarea; - attoseconds_t period = screen().frame_period().attoseconds(); - - const bool st_set = (m_csrw[0] & CSR1W_ST) != 0; - const bool fd_set = (m_dcr[0] & (DCR_CF | DCR_FD)) != 0; - int total_width = 384; - if (fd_set && st_set) - total_width = 360; - - const bool pal = !(m_dcr[0] & DCR_FD); - const int total_height = (pal ? 312 : 262); - - int visible_height = 240; - if (pal && !st_set) - visible_height = 280; - - m_ica_height = total_height - visible_height; - m_total_height = total_height; - - visarea.min_y = m_ica_height; - visarea.max_y = total_height - 1; - visarea.min_x = 0; - visarea.max_x = total_width - 1; - - screen().configure(total_width, total_height, visarea, period); + int width = 768; + if (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) + width = 720; + return width; } -uint32_t mcd212_device::get_screen_width() +int mcd212_device::get_border_width() { - if ((m_dcr[0] & (DCR_CF | DCR_FD)) && (m_csrw[0] & CSR1W_ST)) - { - return 720; - } - return 768; + int width = 0; + if (!BIT(m_dcr[0], DCR_CF_BIT) || BIT(m_csrw[0], CSR1W_ST_BIT)) + width = 24; + return width; } template @@ -510,11 +488,6 @@ void mcd212_device::process_ica() template void mcd212_device::process_dca() { - if (screen().vpos() == m_ica_height) - { - m_dca[Channel] = get_dcp(); - } - uint16_t *dca = Channel ? m_planeb.target() : m_planea.target(); uint32_t addr = (m_dca[Channel] & 0x0007ffff) / 2; uint32_t cmd = 0; @@ -523,6 +496,8 @@ void mcd212_device::process_dca() bool addr_changed = false; bool processing = true; + LOGMASKED(LOG_DCA, "Scanline %d: Processing DCA %d\n", screen().vpos(), Channel ); + while (processing && count < max) { cmd = dca[addr++] << 16; @@ -648,20 +623,36 @@ 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) { const uint8_t *data = reinterpret_cast(Channel ? m_planeb.target() : m_planea.target()); const uint8_t icm = get_icm(); - const uint32_t width = get_screen_width(); const uint8_t transp_ctrl = get_transparency_control(); + const int width = get_plane_width(); uint32_t vsr = get_vsr(); - if (!icm || !vsr || (transp_ctrl == TCR_COND_1)) + if (transp_ctrl == TCR_COND_1) { - std::fill_n(pixels, width, 0x00101010); - std::fill_n(transparent, width, true); + 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); return; } @@ -682,9 +673,8 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) const bool use_region_flag = (transp_ctrl_masked >= TCR_COND_RF0_1 && transp_ctrl_masked <= TCR_COND_RF1KEY_1); bool use_color_key = (transp_ctrl_masked == TCR_COND_KEY_1 || transp_ctrl_masked == TCR_COND_RF0KEY_1 || transp_ctrl_masked == TCR_COND_RF1KEY_1); - int mosaic_index = 0; bool done = false; - uint32_t x = 0; + int x = 0; LOGMASKED(LOG_VSR, "Scanline %d: VSR Channel %d, ICM (%02x), VSR (%08x)\n", screen().vpos(), Channel, icm, vsr); @@ -710,213 +700,164 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) { LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: MOSAIC\n", screen().vpos(), Channel); } - if (m_dcr[Channel] & DCR_CM) - { - // 4-bit Bitmap - LOGMASKED(LOG_UNKNOWNS, "%s", "Unsupported display mode: 4-bit Bitmap\n" ); - } - else + + if (icm == ICM_DYUV) { - // 8-bit Bitmap - if (icm == 5) - { - use_color_key = false; + use_color_key = false; - LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: DYUV\n", screen().vpos(), Channel); - uint8_t y = start_y; - uint8_t u = start_u; - uint8_t v = start_v; - for (; x < width; x += 2) - { - const uint8_t byte1 = data[(vsr++ & 0x0007ffff) ^ 1]; - const uint8_t u1 = u + m_delta_uv_lut[byte]; - const uint8_t y0 = y + m_delta_y_lut[byte]; + LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: DYUV\n", screen().vpos(), Channel); + uint8_t y = start_y; + uint8_t u = start_u; + uint8_t v = start_v; + for (; x < width; x++) + { + 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 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; + 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 *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] = pixels[x + 1] = entry; - transparent[x] = (transp_always || (use_region_flag && region_flags[x])) != invert_transp_condition; - transparent[x + 1] = (transp_always || (use_region_flag && region_flags[x])) != invert_transp_condition; + 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 (mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) - { - pixels[x + 0 + mosaic_index*2] = pixels[x]; - pixels[x + 1 + mosaic_index*2] = pixels[x + 1]; - transparent[x + 0 + mosaic_index*2] = transparent[x]; - transparent[x + 1 + mosaic_index*2] = transparent[x + 1]; - } - x += mosaic_factor * 2; - } - else + if (mosaic_enable) + { + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) { - x += 2; + 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; + 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] = pixels[x + 1] = entry; - transparent[x] = (transp_always || (use_region_flag && region_flags[x])) != invert_transp_condition; - transparent[x + 1] = (transp_always || (use_region_flag && region_flags[x])) != invert_transp_condition; + 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) + if (mosaic_enable) + { + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) { - for (mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) - { - pixels[x + 0 + mosaic_index*2] = pixels[x]; - pixels[x + 1 + mosaic_index*2] = pixels[x + 1]; - transparent[x + 0 + mosaic_index*2] = transparent[x]; - transparent[x + 1 + mosaic_index*2] = transparent[x + 1]; - } - x += (mosaic_factor * 2) - 2; + pixels[x + mosaic_index] = pixels[x]; + transparent[x + mosaic_index] = transparent[x]; } + x += mosaic_factor - 1; + } - byte = data[(vsr++ & 0x0007ffff) ^ 1]; + byte = data[(vsr++ & 0x0007ffff) ^ 1]; - y = y1; - u = u1; - v = v1; - } - set_vsr(vsr - 1); + y = y1; + u = u1; + v = v1; } - else if (icm == 1 || icm == 3 || icm == 4) + set_vsr(vsr - 1); + } + else if (icm == ICM_CLUT8 || icm == ICM_CLUT7 || icm == ICM_CLUT77) + { + for (; x < width; x++) { - for (; x < width; x += 2) + 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) { - uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte)]; - pixels[x] = pixels[x + 1] = entry; - transparent[x] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x])) != invert_transp_condition; - transparent[x + 1] = (transp_always || (use_color_key && (entry == transparent_color)) || (use_region_flag && region_flags[x + 1])) != invert_transp_condition; - if (mosaic_enable) + for (int mosaic_index = 1; mosaic_index < mosaic_factor && (x + mosaic_index) < width; mosaic_index++) { - for (mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) - { - pixels[x + 0 + mosaic_index*2] = pixels[x]; - pixels[x + 1 + mosaic_index*2] = pixels[x + 1]; - transparent[x + 0 + mosaic_index*2] = transparent[x]; - transparent[x + 1 + mosaic_index*2] = transparent[x + 1]; - } - x += (mosaic_factor * 2) - 2; + pixels[x + mosaic_index] = pixels[x]; + transparent[x + mosaic_index] = transparent[x]; } - byte = data[(vsr & 0x0007ffff) ^ 1]; - vsr++; + x += mosaic_factor - 1; } - set_vsr(vsr - 1); + byte = data[(vsr & 0x0007ffff) ^ 1]; + vsr++; } - else if (icm == 11) + set_vsr(vsr - 1); + } + else if (icm == ICM_CLUT4) + { + for (; x < width - 1; x += 2) { - for (; x < width; 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) { - 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) { - for (int mosaic_index = 0; mosaic_index < mosaic_factor; mosaic_index++) - { - pixels[x + mosaic_index] = even_entry; - transparent[x + mosaic_index] = (even_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition; - } - for (int mosaic_index = mosaic_factor; mosaic_index < mosaic_factor * 2; mosaic_index++) - { - pixels[x + mosaic_index] = odd_entry; - transparent[x + mosaic_index] = (odd_pre_transparent || (use_region_flag && region_flags[x + mosaic_index])) != invert_transp_condition; - } - x += (mosaic_factor * 2) - 2; + 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; } - else - { - pixels[x] = even_entry; - transparent[x] = (even_pre_transparent || (use_region_flag && region_flags[x])) != 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++; + pixels[x + 1] = odd_entry; + transparent[x + 1] = (odd_pre_transparent || (use_region_flag && region_flags[x + 1])) != invert_transp_condition; } - set_vsr(vsr - 1); - } - else - { - std::fill_n(pixels + x, width - x, 0x00101010); - std::fill_n(transparent + x, width - x, true); + 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: LOGMASKED(LOG_VSR, "Scanline %d: Chan %d: RLE\n", screen().vpos(), Channel); - if (m_dcr[Channel] & DCR_CM) + if (byte & 0x80) { - LOGMASKED(LOG_UNKNOWNS, "%s", "Unsupported display mode: 4-bit RLE\n" ); - done = true; - } - else - { - if (byte & 0x80) + // Run length + uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1]; + LOGMASKED(LOG_VSR, "Byte %02x w/ run length %02x at %d\n", byte, length, x); + const uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte & 0x7f)]; + const bool pre_transparent = (transp_always || (use_color_key && entry == transparent_color)); + if (!length) { - // Run length - uint8_t length = data[((vsr++) & 0x0007ffff) ^ 1]; - LOGMASKED(LOG_VSR, "Byte %02x w/ run length %02x at %d\n", byte, length, x); - const uint32_t entry = m_clut[BYTE_TO_CLUT(icm, byte & 0x7f)]; - const bool pre_transparent = (transp_always || (use_color_key && entry == transparent_color)); - if (!length) + // 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++) { - // 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[x])) != invert_transp_condition; - } - done = true; - set_vsr(vsr); - } - else - { - int end = std::min(width, x + (length * 2)); - std::fill_n(pixels + x, end - x, entry); - for (int transp_index = x; transp_index < end; transp_index++) - { - transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[x])) != invert_transp_condition; - } - if (x >= width) - { - done = true; - set_vsr(vsr); - } - x = end; + transparent[transp_index] = (pre_transparent || (use_region_flag && region_flags[transp_index << 1])) != invert_transp_condition; } + done = true; + set_vsr(vsr); } else { - LOGMASKED(LOG_VSR, "Byte %02x, single at %d\n", byte, x); - // 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])) != invert_transp_condition; - x++; - - pixels[x] = entry; - transparent[x] = (pre_transparent || (use_region_flag && region_flags[x])) != invert_transp_condition; - x++; - + 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; @@ -924,15 +865,41 @@ void mcd212_device::process_vsr(uint32_t *pixels, bool *transparent) } } } + else + { + LOGMASKED(LOG_VSR, "Byte %02x, single at %d\n", byte, x); + // 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; } } + + 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]; + } + } } const uint32_t mcd212_device::s_4bpp_color[16] = { - 0x00101010, 0x0010107a, 0x00107a10, 0x00107a7a, 0x007a1010, 0x007a107a, 0x007a7a10, 0x007a7a7a, - 0x00101010, 0x001010e6, 0x0010e610, 0x0010e6e6, 0x00e61010, 0x00e610e6, 0x00e6e610, 0x00e6e6e6 + 0xff101010, 0xff10107a, 0xff107a10, 0xff107a7a, 0xff7a1010, 0xff7a107a, 0xff7a7a10, 0xff7a7a7a, + 0xff101010, 0xff1010e6, 0xff10e610, 0xff10e6e6, 0xffe61010, 0xffe610e6, 0xffe6e610, 0xffe6e6e6 }; template @@ -941,13 +908,15 @@ void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t * 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]; if (!(m_transparency_control & TCR_DISABLE_MX)) { - for (int x = 0; x < 768; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) + for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) { const uint8_t weight_a_cur = *weight_a; const uint8_t weight_b_cur = *weight_b; @@ -970,12 +939,12 @@ void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t * const uint8_t out_r = (weighted_b_r > 255) ? 255 : (uint8_t)weighted_b_r; const uint8_t out_g = (weighted_b_g > 255) ? 255 : (uint8_t)weighted_b_g; const uint8_t out_b = (weighted_b_b > 255) ? 255 : (uint8_t)weighted_b_b; - out[x] = (out_r << 16) | (out_g << 8) | out_b; + *out++ = 0xff000000 | (out_r << 16) | (out_g << 8) | out_b; } } else { - for (int x = 0; x < 768; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) + for (int x = 0; x < width; x++, weight_a++, transparent_a++, weight_b++, transparent_b++) { if (OrderAB) { @@ -989,7 +958,7 @@ void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t * const uint8_t weighted_a_r = std::clamp(((plane_a_r > 16) ? (((plane_a_r - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255); const uint8_t weighted_a_g = std::clamp(((plane_a_g > 16) ? (((plane_a_g - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255); const uint8_t weighted_a_b = std::clamp(((plane_a_b > 16) ? (((plane_a_b - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255); - out[x] = (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; + *out++ = 0xff000000 | (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; } else if (!(*transparent_b)) { @@ -1001,11 +970,11 @@ void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t * const uint8_t weighted_b_r = std::clamp(((plane_b_r > 16) ? (((plane_b_r - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255); const uint8_t weighted_b_g = std::clamp(((plane_b_g > 16) ? (((plane_b_g - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255); const uint8_t weighted_b_b = std::clamp(((plane_b_b > 16) ? (((plane_b_b - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255); - out[x] = (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; + *out++ = 0xff000000 | (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; } else { - out[x] = backdrop; + *out++ = backdrop; } } else @@ -1020,7 +989,7 @@ void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t * const uint8_t weighted_b_r = std::clamp(((plane_b_r > 16) ? (((plane_b_r - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255); const uint8_t weighted_b_g = std::clamp(((plane_b_g > 16) ? (((plane_b_g - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255); const uint8_t weighted_b_b = std::clamp(((plane_b_b > 16) ? (((plane_b_b - 16) * weight_b_cur) >> 6) : 0) + 16, 0, 255); - out[x] = (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; + *out++ = 0xff000000 | (weighted_b_r << 16) | (weighted_b_g << 8) | weighted_b_b; } else if (!(*transparent_a)) { @@ -1032,15 +1001,20 @@ void mcd212_device::mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t * const uint8_t weighted_a_r = std::clamp(((plane_a_r > 16) ? (((plane_a_r - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255); const uint8_t weighted_a_g = std::clamp(((plane_a_g > 16) ? (((plane_a_g - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255); const uint8_t weighted_a_b = std::clamp(((plane_a_b > 16) ? (((plane_a_b - 16) * weight_a_cur) >> 6) : 0) + 16, 0, 255); - out[x] = (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; + *out++ = 0xff000000 | (weighted_a_r << 16) | (weighted_a_g << 8) | weighted_a_b; } else { - out[x] = backdrop; + *out++ = backdrop; } } } } + + if (border_width) + { + std::fill_n(out, border_width, 0xff101010); + } } void mcd212_device::draw_cursor(uint32_t *scanline) @@ -1052,29 +1026,30 @@ void mcd212_device::draw_cursor(uint32_t *scanline) const uint16_t cursor_y = ((m_cursor_position >> 12) & 0x3ff) + m_ica_height; if (y >= cursor_y && y < (cursor_y + 16)) { + 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 < 768; x++) + 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++)/2] = color; - scanline[(x++)/2] = color; - scanline[(x++)/2] = color; - scanline[(x/2)] = color; + scanline[x++] = color; + scanline[x++] = color; + scanline[x++] = color; + scanline[x] = color; } } } else { - for (int x = cursor_x; x < cursor_x + 32 && x < 768; x++) + for (int x = cursor_x; x < cursor_x + 32 && x < width; x++) { if (m_cursor_pattern[y] & (1 << (15 - ((x - cursor_x) >> 1)))) { - scanline[(x++)/2] = color; - scanline[x/2] = color; + scanline[x++] = color; + scanline[x] = color; } } } @@ -1082,57 +1057,6 @@ void mcd212_device::draw_cursor(uint32_t *scanline) } } -void mcd212_device::draw_scanline(bitmap_rgb32 &bitmap) -{ - uint32_t plane_a[768]; - uint32_t plane_b[768]; - bool transparent_a[768]; - bool transparent_b[768]; - uint32_t out[768]; - - process_vsr<0>(plane_a, transparent_a); - process_vsr<1>(plane_b, transparent_b); - - const uint8_t mosaic_enable_a = (m_mosaic_hold[0] & 0x800000) >> 23; - const uint8_t mosaic_enable_b = (m_mosaic_hold[1] & 0x800000) >> 22; - const uint8_t mixing_mode = (mosaic_enable_a | mosaic_enable_b) | (BIT(m_plane_order, 0) << 2); - switch (mixing_mode & 7) - { - case 0: // No Mosaic A/B, A->B->Backdrop plane ordering - mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); - break; - case 1: // Mosaic A, No Mosaic B, A->B->Backdrop plane ordering - mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); - break; - case 2: // No Mosaic A, Mosaic B, A->B->Backdrop plane ordering - mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); - break; - case 3: // Mosaic A/B, A->B->Backdrop plane ordering - mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); - break; - case 4: // No Mosaic A/B, B->A->Backdrop plane ordering - mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); - break; - case 5: // Mosaic A, No Mosaic B, B->A->Backdrop plane ordering - mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); - break; - case 6: // No Mosaic A, Mosaic B, B->A->Backdrop plane ordering - mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); - break; - case 7: // Mosaic A/B, B->A->Backdrop plane ordering - mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); - break; - } - - uint32_t *const scanline = &bitmap.pix(screen().vpos()); - for (int x = 0; x < 384; x++) - { - scanline[x] = 0xff000000 | out[x*2]; - } - - draw_cursor(scanline); -} - void mcd212_device::map(address_map &map) { map(0x00, 0x01).w(FUNC(mcd212_device::csr2_w)); @@ -1158,57 +1082,55 @@ uint8_t mcd212_device::csr1_r() void mcd212_device::csr1_w(offs_t offset, uint16_t data, uint16_t mem_mask) { - LOGMASKED(LOG_STATUS, "%s: Control/Status Register 1 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); + 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]); - update_visible_area(); } uint16_t mcd212_device::dcr1_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_STATUS, "%s: Display Command Register 1 Read: %04x & %08x\n", machine().describe_context(), m_dcr[0], mem_mask); + 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_STATUS, "%s: Display Command Register 1 Write: %04x & %08x\n", machine().describe_context(), data, 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]); - update_visible_area(); } uint16_t mcd212_device::vsr1_r(offs_t offset, uint16_t mem_mask) { - LOGMASKED(LOG_STATUS, "%s: Video Start Register 1 Read: %04x & %08x\n", machine().describe_context(), m_vsr[0], mem_mask); + 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_STATUS, "%s: Video Start Register 1 Write: %04x & %08x\n", machine().describe_context(), data, 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_STATUS, "%s: Display Decoder Register 1 Read: %04x & %08x\n", machine().describe_context(), m_ddr[0], 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_STATUS, "%s: Display Decoder Register 1 Write: %04x & %08x\n", machine().describe_context(), data, 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_STATUS, "%s: DCA Pointer 1 Read: %04x & %08x\n", machine().describe_context(), m_dca[0], 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_STATUS, "%s: DCA Pointer 1 Write: %04x & %08x\n", machine().describe_context(), data, 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]); } @@ -1231,97 +1153,222 @@ uint8_t mcd212_device::csr2_r() void mcd212_device::csr2_w(offs_t offset, uint16_t data, uint16_t mem_mask) { - LOGMASKED(LOG_STATUS, "%s: Control/Status Register 2 Write: %04x & %08x\n", machine().describe_context(), data, mem_mask); + 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_STATUS, "%s: Display Command Register 2 Read: %04x & %08x\n", machine().describe_context(), m_dcr[1], 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_STATUS, "%s: Display Command Register 2 Write: %04x & %08x\n", machine().describe_context(), data, 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_STATUS, "%s: Video Start Register 2 Read: %04x & %08x\n", machine().describe_context(), m_vsr[1], 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_STATUS, "%s: Video Start Register 2 Write: %04x & %08x\n", machine().describe_context(), data, 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_STATUS, "%s: Display Decoder Register 2 Read: %04x & %08x\n", machine().describe_context(), m_ddr[1], 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_STATUS, "%s: Display Decoder Register 2 Write: %04x & %08x\n", machine().describe_context(), data, 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_STATUS, "%s: DCA Pointer 2 Read: %04x & %08x\n", machine().describe_context(), m_dca[1], 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_STATUS, "%s: DCA Pointer 2 Write: %04x & %08x\n", machine().describe_context(), data, 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]); } -WRITE_LINE_MEMBER(mcd212_device::screen_vblank) +TIMER_CALLBACK_MEMBER(mcd212_device::ica_tick) { - if (state) - { - // Process ICA - m_csrr[0] &= 0x7f; - if (m_dcr[0] & DCR_ICA) - process_ica<0>(); - if (m_dcr[1] & DCR_ICA) - process_ica<1>(); - } + m_csrr[0] &= ~CSR1R_DA; + + // Process ICA + if (BIT(m_dcr[0], DCR_ICA_BIT)) + process_ica<0>(); + if (BIT(m_dcr[1], DCR_ICA_BIT)) + process_ica<1>(); + + if (BIT(m_dcr[0], DCR_DCA_BIT)) + m_dca[0] = get_dcp<0>(); + if (BIT(m_dcr[1], DCR_DCA_BIT)) + m_dca[1] = get_dcp<1>(); + + m_ica_timer->adjust(screen().time_until_pos(0, 0)); +} + +TIMER_CALLBACK_MEMBER(mcd212_device::dca_tick) +{ + // Process DCA + if (BIT(m_dcr[0], DCR_DCA_BIT)) + process_dca<0>(); + if (BIT(m_dcr[1], DCR_DCA_BIT)) + process_dca<1>(); + + int scanline = screen().vpos(); + if (scanline == m_total_height - 1) + m_dca_timer->adjust(screen().time_until_pos(m_ica_height, 784)); + else + m_dca_timer->adjust(screen().time_until_pos(scanline + 1, 784)); } uint32_t mcd212_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { + uint32_t plane_a[768]; + uint32_t plane_b[768]; + bool transparent_a[768]; + bool transparent_b[768]; + int scanline = screen.vpos(); + // Process VSR and mix if we're in the visible region if (scanline >= m_ica_height) { - m_csrr[0] |= 0x80; + uint32_t *out = &bitmap.pix(scanline); - // Process DCA - if (m_dcr[0] & DCR_DCA) - process_dca<0>(); - if (m_dcr[1] & DCR_DCA) - process_dca<1>(); + bool draw_line = true; + if (!BIT(m_dcr[0], DCR_FD_BIT) && BIT(m_csrw[0], CSR1W_ST_BIT)) + { + // 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); + draw_line = false; + } + } - // Process VSR - draw_scanline(bitmap); + m_csrr[0] |= CSR1R_DA; + + 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); + + const uint8_t mosaic_enable_a = (m_mosaic_hold[0] & 0x800000) >> 23; + const uint8_t mosaic_enable_b = (m_mosaic_hold[1] & 0x800000) >> 22; + const uint8_t mixing_mode = (mosaic_enable_a | mosaic_enable_b) | (BIT(m_plane_order, 0) << 2); + switch (mixing_mode & 7) + { + case 0: // No Mosaic A/B, A->B->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 1: // Mosaic A, No Mosaic B, A->B->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 2: // No Mosaic A, Mosaic B, A->B->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 3: // Mosaic A/B, A->B->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 4: // No Mosaic A/B, B->A->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 5: // Mosaic A, No Mosaic B, B->A->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 6: // No Mosaic A, Mosaic B, B->A->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + case 7: // Mosaic A/B, B->A->Backdrop plane ordering + mix_lines(plane_a, transparent_a, plane_b, transparent_b, out); + break; + } + + draw_cursor(out); + } } + // Toggle frame parity at the end of the visible frame (even in non-interlaced mode). if (scanline == (m_total_height - 1)) { - m_csrr[0] ^= 0x20; + m_csrr[0] ^= CSR1R_PA; } return 0; } +template int mcd212_device::ram_dtack_cycle_count<0>(); +template int mcd212_device::ram_dtack_cycle_count<1>(); + +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. + + // No contending for Ch.1/Ch.2 timing slots if display is disabled + 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)) + return 2; + + const int x = screen().hpos(); + const int y = screen().vpos(); + const bool x_outside_active_display = (x >= 408); + + // No contending for Ch.1/Ch.2 timing slots during the final 8-pixel area on all lines + if (x >= 472) + return 2; + + // No contending for Ch.1/Ch.2 timing slots during the free-run area of ICA lines + if (y < m_ica_height && x_outside_active_display) + 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) + 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); + if (slot_cycle >= 11) + return 2; + + return 2 + std::max((11 - slot_cycle) >> 1, 1); +} + +int mcd212_device::rom_dtack_cycle_count() +{ + static const int s_dd_values[4] = { 2, 3, 4, 5 }; + if (!BIT(m_csrw[0], CSR1W_DD_BIT)) + return 7; + return s_dd_values[(m_csrw[0] & CSR1W_DD2) >> CSR1W_DD2_SHIFT]; +} + void mcd212_device::device_reset() { std::fill_n(m_csrr, 2, 0); @@ -1349,10 +1396,14 @@ void mcd212_device::device_reset() std::fill_n(m_weight_factor[1], std::size(m_weight_factor[1]), 0); std::fill_n(m_region_flag[0], std::size(m_region_flag[0]), false); std::fill_n(m_region_flag[1], std::size(m_region_flag[1]), false); + m_ica_height = 32; m_total_height = 312; m_int_callback(CLEAR_LINE); + + m_dca_timer->adjust(screen().time_until_pos(m_ica_height, 784)); + m_ica_timer->adjust(screen().time_until_pos(m_ica_height, 0)); } //------------------------------------------------- @@ -1363,8 +1414,8 @@ mcd212_device::mcd212_device(const machine_config &mconfig, const char *tag, dev : device_t(mconfig, MCD212, tag, owner, clock) , device_video_interface(mconfig, *this) , m_int_callback(*this) - , m_planea(*this, "planea") - , m_planeb(*this, "planeb") + , m_planea(*this, finder_base::DUMMY_TAG) + , m_planeb(*this, finder_base::DUMMY_TAG) { } @@ -1436,4 +1487,10 @@ void mcd212_device::device_start() 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)); + 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->adjust(attotime::never); } diff --git a/src/mame/video/mcd212.h b/src/mame/video/mcd212.h index 3b9a379c9ba..521207ef1ac 100644 --- a/src/mame/video/mcd212.h +++ b/src/mame/video/mcd212.h @@ -35,21 +35,34 @@ class mcd212_device : public device_t, public device_video_interface { public: + template + mcd212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&plane_a_tag, U &&plane_b_tag) + : mcd212_device(mconfig, tag, owner, clock) + { + m_planea.set_tag(std::forward(plane_a_tag)); + m_planeb.set_tag(std::forward(plane_b_tag)); + } + mcd212_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); auto int_callback() { return m_int_callback.bind(); } - DECLARE_WRITE_LINE_MEMBER(screen_vblank); uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); void map(address_map &map); + 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; + TIMER_CALLBACK_MEMBER(ica_tick); + TIMER_CALLBACK_MEMBER(dca_tick); + uint8_t csr1_r(); void csr1_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); uint16_t dcr1_r(offs_t offset, uint16_t mem_mask = ~0); @@ -83,19 +96,18 @@ protected: CURCNT_BLKC = 0x400000, // Blink type CURCNT_EN = 0x800000, // Cursor enable - ICM_CS = 0x400000, // CLUT select - ICM_NR = 0x080000, // Number of region flags - ICM_NR_BIT = 19, - ICM_EV = 0x040000, // External video - ICM_MODE2 = 0x000f00, // Plane 2 - ICM_MODE2_SHIFT = 8, ICM_MODE1 = 0x00000f, // Plane 1 ICM_MODE1_SHIFT = 0, + 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_CS = 0x400000, // CLUT select - TCR_DISABLE_MX = 0x800000, // Mix disable + TCR_TA = 0x00000f, // Plane A TCR_TB = 0x000f00, // Plane B TCR_TB_SHIFT = 8, - TCR_TA = 0x00000f, // Plane A TCR_COND_1 = 0x0, // Transparent if: Always (Plane Disabled) TCR_COND_KEY_1 = 0x1, // Transparent if: Color Key = True TCR_COND_XLU_1 = 0x2, // Transparent if: Transparency Bit = 1 @@ -112,6 +124,7 @@ protected: 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 @@ -123,32 +136,47 @@ protected: RC_OP = 0xf00000, // Operation RC_OP_SHIFT = 20, - CSR1W_ST = 0x0002, // Standard - CSR1W_BE = 0x0001, // Bus Error - - CSR2R_IT1 = 0x0004, // Interrupt 1 - CSR2R_IT2 = 0x0002, // Interrupt 2 - CSR2R_BE = 0x0001, // Bus Error - - DCR_DE = 0x8000, // Display Enable - DCR_CF = 0x4000, // Crystal Frequency - DCR_FD = 0x2000, // Frame Duration - DCR_SM = 0x1000, // Scan Mode - DCR_CM = 0x0800, // Color Mode Ch.1/2 - DCR_ICA = 0x0200, // ICA Enable Ch.1/2 - DCR_DCA = 0x0100, // DCA Enable Ch.1/2 - - DDR_FT = 0x0300, // Display File Type - DDR_FT_BMP = 0x0000, // Bitmap - DDR_FT_BMP2 = 0x0100, // Bitmap (alt.) - DDR_FT_RLE = 0x0200, // Run-Length Encoded - DDR_FT_MOSAIC = 0x0300, // Mosaic - DDR_MT = 0x0c00, // Mosaic File Type - DDR_MT_2 = 0x0000, // 2x1 - DDR_MT_4 = 0x0400, // 4x1 - DDR_MT_8 = 0x0800, // 8x1 - DDR_MT_16 = 0x0c00, // 16x1 - DDR_MT_SHIFT = 10 + CSR1R_PA = 0x20, // Parity + CSR1R_DA = 0x80, // Display Active + + CSR1W_BE = 0x0001, // Bus Error + CSR1W_ST_BIT = 1, // Standard + CSR1W_DD_BIT = 3, + CSR1W_DD2 = 0x0300, // /DTACK Delay + CSR1W_DD2_SHIFT = 8, + CSR1W_DI1_BIT = 15, + + CSR2R_BE = 0x0001, // Bus Error + CSR2R_IT2 = 0x0002, // Interrupt 2 + CSR2R_IT1 = 0x0004, // Interrupt 1 + + DCR_DCA_BIT = 8, // DCA Enable Ch.1/2 + DCR_ICA_BIT = 9, // ICA Enable Ch.1/2 + DCR_CM_BIT = 11, // Color Mode Ch.1/2 + DCR_SM_BIT = 12, // Scan Mode + DCR_FD_BIT = 13, // Frame Duration + DCR_CF_BIT = 14, // Crystal Frequency + DCR_DE_BIT = 15, // Display Enable + + DDR_MT = 0x0c00, // Mosaic File Type + DDR_MT_2 = 0x0000, // 2x1 + DDR_MT_4 = 0x0400, // 4x1 + DDR_MT_8 = 0x0800, // 8x1 + DDR_MT_16 = 0x0c00, // 16x1 + DDR_MT_SHIFT = 10, + DDR_FT = 0x0300, // Display File Type + DDR_FT_BMP = 0x0000, // Bitmap + DDR_FT_BMP2 = 0x0100, // Bitmap (alt.) + DDR_FT_RLE = 0x0200, // Run-Length Encoded + DDR_FT_MOSAIC = 0x0300, // Mosaic + + ICM_OFF = 0x0, + ICM_CLUT8 = 0x1, + ICM_RGB555 = 0x2, + ICM_CLUT7 = 0x3, + ICM_CLUT77 = 0x4, + ICM_DYUV = 0x5, + ICM_CLUT4 = 0xb }; uint8_t m_csrr[2]; @@ -207,6 +235,8 @@ protected: 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]; @@ -214,8 +244,9 @@ protected: uint8_t get_region_op(const uint32_t region_idx); void update_region_arrays(); - void update_visible_area(); - uint32_t get_screen_width(); + int get_screen_width(); + int get_border_width(); + template int get_plane_width(); template void set_vsr(uint32_t value); template uint32_t get_vsr(); @@ -239,7 +270,6 @@ protected: template void mix_lines(uint32_t *plane_a, bool *transparent_a, uint32_t *plane_b, bool *transparent_b, uint32_t *out); void draw_cursor(uint32_t *scanline); - void draw_scanline(bitmap_rgb32 &bitmap); }; // device type definition -- cgit v1.2.3