summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/scn2674.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/scn2674.cpp')
-rw-r--r--src/devices/video/scn2674.cpp303
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);
}
}