diff options
Diffstat (limited to 'src/devices/video/scn2674.cpp')
-rw-r--r-- | src/devices/video/scn2674.cpp | 303 |
1 files changed, 186 insertions, 117 deletions
diff --git a/src/devices/video/scn2674.cpp b/src/devices/video/scn2674.cpp index 9baae770f4c..8957171848f 100644 --- a/src/devices/video/scn2674.cpp +++ b/src/devices/video/scn2674.cpp @@ -44,12 +44,15 @@ scn2674_device::scn2674_device(const machine_config &mconfig, device_type type, , device_memory_interface(mconfig, *this) , m_intr_cb(*this) , m_breq_cb(*this) + , m_mbc_cb(*this) + , m_mbc_char_cb(*this) + , m_mbc_attr_cb(*this) , m_IR_pointer(0) , m_screen1_address(0), m_screen2_address(0) , m_cursor_address(0) , m_irq_register(0), m_status_register(0), m_irq_mask(0) , m_gfx_enabled(false) - , m_display_enabled(false), m_display_enabled_field(false), m_display_enabled_scanline(false) + , m_display_enabled(false), m_dadd_enabled(false), m_display_enabled_field(false), m_display_enabled_scanline(false) , m_cursor_enabled(false) , m_hpixels_per_column(0) , m_double_ht_wd(false) @@ -83,6 +86,8 @@ scn2674_device::scn2674_device(const machine_config &mconfig, device_type type, , m_char_buffer(0), m_attr_buffer(0) , m_linecounter(0), m_address(0), m_start1change(0) , m_scanline_timer(nullptr) + , m_breq_timer(nullptr) + , m_vblank_timer(nullptr) , m_char_space(nullptr), m_attr_space(nullptr) , m_char_space_config("charram", ENDIANNESS_LITTLE, 8, extend_addressing ? 16 : 14, 0, address_map_constructor(), address_map_constructor(FUNC(scn2674_device::scn2674_vram), this)) , m_attr_space_config("attrram", ENDIANNESS_LITTLE, 8, extend_addressing ? 16 : 14, 0, address_map_constructor(), address_map_constructor(FUNC(scn2674_device::scn2674_vram), this)) @@ -105,7 +110,12 @@ void scn2674_device::device_start() m_display_cb.bind_relative_to(*owner()); m_intr_cb.resolve_safe(); m_breq_cb.resolve_safe(); - m_scanline_timer = timer_alloc(TIMER_SCANLINE); + m_mbc_cb.resolve_safe(); + m_mbc_char_cb.resolve(); + m_mbc_attr_cb.resolve(); + m_scanline_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scn2674_device::scanline_timer), this)); + m_breq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scn2674_device::breq_timer), this)); + m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(scn2674_device::vblank_timer), this)); screen().register_screen_bitmap(m_bitmap); m_char_space = &space(0); @@ -123,6 +133,7 @@ void scn2674_device::device_start() save_item(NAME(m_irq_mask)); save_item(NAME(m_gfx_enabled)); save_item(NAME(m_display_enabled)); + save_item(NAME(m_dadd_enabled)); save_item(NAME(m_display_enabled_field)); save_item(NAME(m_display_enabled_scanline)); save_item(NAME(m_cursor_enabled)); @@ -174,6 +185,7 @@ void scn2674_device::device_reset() m_irq_mask = 0; m_gfx_enabled = false; m_display_enabled = false; + m_dadd_enabled = false; m_display_enabled_field = false; m_display_enabled_scanline = false; m_cursor_enabled = false; @@ -551,9 +563,15 @@ void scn2674_device::set_display_enabled(bool enabled, int n) m_display_enabled = false; if (n == 1) + { LOGMASKED(LOG_COMMAND, "%s: Display off - float DADD bus\n", machine().describe_context()); + m_dadd_enabled = false; + } else + { LOGMASKED(LOG_COMMAND, "%s: Display off - no float DADD bus\n", machine().describe_context()); + m_dadd_enabled = true; + } } else { @@ -766,6 +784,7 @@ void scn2674_device::write_command(uint8_t data) m_irq_mask = 0x00; m_gfx_enabled = false; m_display_enabled = false; + m_dadd_enabled = false; m_cursor_enabled = false; m_use_row_table = false; m_intr_cb(CLEAR_LINE); @@ -911,6 +930,8 @@ void scn2674_device::write(offs_t offset, uint8_t data) m_screen1_address = (m_screen1_address & 0x3f00) | data; if (!screen().vblank()) m_start1change = (m_linecounter / m_scanline_per_char_row) + 1; + else + m_start1change = 0; break; case 3: @@ -924,6 +945,8 @@ void scn2674_device::write(offs_t offset, uint8_t data) } if (!screen().vblank()) m_start1change = (m_linecounter / m_scanline_per_char_row) + 1; + else + m_start1change = 0; break; case 4: @@ -967,145 +990,191 @@ void scn2674_device::recompute_parameters() rectangle visarea(0, max_visible_x, 0, max_visible_y); screen().configure(horiz_pix_total, vert_pix_total, visarea, refresh.as_attoseconds()); - m_scanline_timer->adjust(screen().time_until_pos(0, 0), 0, screen().scan_period()); + m_linecounter = screen().vpos(); + m_scanline_timer->adjust(screen().time_until_pos((m_linecounter + 1) % vert_pix_total, 0), 0, screen().scan_period()); } -void scn2674_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(scn2674_device::scanline_timer) { - switch (id) + int dw = m_double_ht_wd ? m_double[0] : 0; // double width + if (((m_display_enabled_scanline) || (m_display_enabled_field && !m_interlace_enable)) && (!m_display_enabled)) { - case TIMER_SCANLINE: - { - int dw = m_double_ht_wd ? m_double[0] : 0; // double width - if (((m_display_enabled_scanline) || (m_display_enabled_field && !m_interlace_enable)) && (!m_display_enabled)) - { - m_display_enabled = true; - m_display_enabled_scanline = false; - m_display_enabled_field = false; - } + m_display_enabled = true; + m_dadd_enabled = true; + m_display_enabled_scanline = false; + m_display_enabled_field = false; + } - m_linecounter++; + m_linecounter++; - if (m_linecounter >= screen().height()) - { - m_linecounter = 0; - m_address = m_screen1_address; - } + if (m_linecounter >= screen().height()) + { + m_linecounter = 0; + m_address = m_screen1_address; + } - if (m_linecounter == (m_rows_per_screen * m_scanline_per_char_row)) - { - m_status_register |= 0x10; - if (BIT(m_irq_mask, 4)) - { - LOGMASKED(LOG_INTR, "V-Blank interrupt at line %d\n", m_linecounter); - m_irq_register |= 0x10; - m_intr_cb(ASSERT_LINE); - } - } + bool lastscan = m_linecounter == (m_rows_per_screen * m_scanline_per_char_row) - 1; + if (lastscan) + { + int horz_sync_begin = 2 * (m_equalizing_constant + 2 * m_horz_sync_width) - m_horz_sync_width - m_horz_back_porch; + m_vblank_timer->adjust(clocks_to_attotime(horz_sync_begin)); + } - if (m_linecounter >= (m_rows_per_screen * m_scanline_per_char_row)) - break; + if (m_linecounter >= (m_rows_per_screen * m_scanline_per_char_row)) + { + if (m_buffer_mode_select == 3 && m_linecounter == (screen().height() - 1)) + m_breq_timer->adjust(clocks_to_attotime(m_character_per_row + 1), ASSERT_LINE); + return; + } - int charrow = m_linecounter % m_scanline_per_char_row; - int tilerow = charrow; + int charrow = m_linecounter % m_scanline_per_char_row; + int tilerow = charrow; - // should be triggered at the start of each ROW (line zero for that row) - if (charrow == 0) - { - m_status_register |= 0x08; - if (BIT(m_irq_mask, 3)) - { - LOGMASKED(LOG_INTR, "Line Zero interrupt at line %d\n", m_linecounter); - m_irq_register |= 0x08; - m_intr_cb(ASSERT_LINE); - } - if (m_buffer_mode_select == 3) - m_breq_cb(ASSERT_LINE); - } - else if (m_buffer_mode_select == 3) - m_breq_cb(CLEAR_LINE); + // should be triggered at the start of each ROW (line zero for that row) + if (charrow == 0) + { + m_status_register |= 0x08; + if (BIT(m_irq_mask, 3)) + { + LOGMASKED(LOG_INTR, "Line Zero interrupt at line %d\n", m_linecounter); + m_irq_register |= 0x08; + m_intr_cb(ASSERT_LINE); + } + if (m_buffer_mode_select == 3) + { + m_mbc_cb(1); + m_breq_timer->adjust(clocks_to_attotime(m_character_per_row + 1), CLEAR_LINE); + } + } + else if (m_buffer_mode_select == 3 && charrow == (m_scanline_per_char_row - 1) && !lastscan) + m_breq_timer->adjust(clocks_to_attotime(m_character_per_row + 1), ASSERT_LINE); - // Handle screen splits - for (int s = 0; s < 2; s++) + // Handle screen splits + for (int s = 0; s < 2; s++) + { + if ((m_linecounter == ((m_split_register[s] + 1) * m_scanline_per_char_row)) && m_linecounter) + { + uint8_t flag = (s == 0) ? 0x04 : 0x01; + m_status_register |= flag; + if ((m_irq_mask & flag) != 0) { - if ((m_linecounter == ((m_split_register[s] + 1) * m_scanline_per_char_row)) && m_linecounter) - { - uint8_t flag = (s == 0) ? 0x04 : 0x01; - m_status_register |= flag; - if ((m_irq_mask & flag) != 0) - { - LOGMASKED(LOG_INTR, "Split Screen %d interrupt at line %d\n", s + 1, m_linecounter); - m_irq_register |= flag; - m_intr_cb(ASSERT_LINE); - } - if (m_spl[s]) - m_address = m_screen2_address; - if (!m_double_ht_wd) - dw = m_double[s]; - } + LOGMASKED(LOG_INTR, "Split Screen %d interrupt at line %d\n", s + 1, m_linecounter); + m_irq_register |= flag; + m_intr_cb(ASSERT_LINE); } + if (m_spl[s]) + m_address = m_screen2_address; + if (!m_double_ht_wd) + dw = m_double[s]; + } + } - if (!m_display_enabled) - break; + // WY-50 requires that normal row buffering take place even after a "display off" command + if (!m_dadd_enabled) + return; - if (m_use_row_table) - { - if (m_double_ht_wd) - dw = m_screen1_address >> 14; - if (!charrow) - { - uint16_t addr = m_screen2_address; - uint16_t line = m_char_space->read_word(addr); - m_screen1_address = line; - if (m_double_ht_wd) - { - dw = line >> 14; - line &= ~0xc000; - } - m_address = line; - addr += 2; - m_screen2_address = addr & 0x3fff; - } - } - else if (m_start1change && (m_start1change == (m_linecounter / m_scanline_per_char_row))) + if (m_use_row_table) + { + if (m_double_ht_wd) + dw = m_screen1_address >> 14; + if (!charrow) + { + uint16_t addr = m_screen2_address; + uint16_t line = m_char_space->read_word(addr); + m_screen1_address = line; + if (m_double_ht_wd) { - m_address = m_screen1_address; - m_start1change = 0; + dw = line >> 14; + line &= ~0xc000; } + m_address = line; + addr += 2; + m_screen2_address = addr & 0x3fff; + } + } + else if (m_start1change && (m_start1change == (m_linecounter / m_scanline_per_char_row))) + { + m_address = m_screen1_address; + m_start1change = 0; + } - if (dw == 2) - tilerow >>= 1; - else if (dw == 3) - tilerow = (charrow + m_scanline_per_char_row) >> 1; + if (dw == 2) + tilerow >>= 1; + else if (dw == 3) + tilerow = (charrow + m_scanline_per_char_row) >> 1; - uint16_t address = m_address; + uint16_t address = m_address; - for (int i = 0; i < m_character_per_row; i++) + const bool mbc = (charrow == 0) && (m_buffer_mode_select == 3); + const bool blink_on = (screen().frame_number() & (m_character_blink_rate_divisor >> 1)) != 0; + for (int i = 0; i < m_character_per_row; i++) + { + u8 charcode, attrcode = 0; + if (mbc && !m_mbc_char_cb.isnull()) + { + // row buffering DMA + charcode = m_mbc_char_cb(address); + m_char_space->write_byte(address, charcode); + if (m_attr_space != nullptr && !m_mbc_attr_cb.isnull()) { - bool cursor_on = ((address & 0x3fff) == m_cursor_address); - - if (!m_display_cb.isnull()) - m_display_cb(m_bitmap, - i * m_hpixels_per_column, - m_linecounter, - tilerow, - m_char_space->read_byte(address), - m_attr_space != nullptr ? m_attr_space->read_byte(address) : 0, - address, - (charrow >= m_cursor_first_scanline) && (charrow <= m_cursor_last_scanline) && cursor_on, - dw != 0, - m_gfx_enabled, - charrow == m_cursor_underline_position, - m_cursor_blink && (screen().frame_number() & m_cursor_rate_divisor)); - address = (address + 1) & 0xffff; - - if (address > ((m_display_buffer_last_address << 10) | 0x3ff)) - address = m_display_buffer_first_address; + attrcode = m_mbc_attr_cb(address); + m_attr_space->write_byte(address, attrcode); } + } + else + { + charcode = m_char_space->read_byte(address); + if (m_attr_space != nullptr) + attrcode = m_attr_space->read_byte(address); + } + + if (m_display_enabled && !m_display_cb.isnull()) + { + bool cursor_on = ((address & 0x3fff) == m_cursor_address) + && m_cursor_enabled + && (charrow >= m_cursor_first_scanline) + && (charrow <= m_cursor_last_scanline) + && (!m_cursor_blink || (screen().frame_number() & (m_cursor_rate_divisor >> 1)) != 0); + m_display_cb(m_bitmap, + i * m_hpixels_per_column, + m_linecounter, + tilerow, + charcode, + attrcode, + address, + cursor_on, + dw != 0, + m_gfx_enabled, + charrow == m_cursor_underline_position, + blink_on); - if (m_gfx_enabled || (charrow == (m_scanline_per_char_row - 1))) - m_address = address; } + address = (address + 1) & 0xffff; + + if (address > ((m_display_buffer_last_address << 10) | 0x3ff)) + address = m_display_buffer_first_address; + } + + if (m_gfx_enabled || (charrow == (m_scanline_per_char_row - 1))) + m_address = address; +} + +TIMER_CALLBACK_MEMBER(scn2674_device::breq_timer) +{ + LOGMASKED(LOG_INTR, "BREQ %sasserted at line %d\n", (param == ASSERT_LINE) ? "" : "de", m_linecounter); + m_breq_cb(param); + if (param == CLEAR_LINE) + m_mbc_cb(0); +} + +TIMER_CALLBACK_MEMBER(scn2674_device::vblank_timer) +{ + m_status_register |= 0x10; + if (BIT(m_irq_mask, 4)) + { + LOGMASKED(LOG_INTR, "V-Blank interrupt at line %d\n", m_linecounter); + m_irq_register |= 0x10; + m_intr_cb(ASSERT_LINE); } } |