summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/crtc_ega.cpp
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
commit7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch)
treef310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/devices/video/crtc_ega.cpp
parenta57b46ae933badd7441ce1644711dbb851e2b504 (diff)
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/devices/video/crtc_ega.cpp')
-rw-r--r--src/devices/video/crtc_ega.cpp728
1 files changed, 728 insertions, 0 deletions
diff --git a/src/devices/video/crtc_ega.cpp b/src/devices/video/crtc_ega.cpp
new file mode 100644
index 00000000000..102df087008
--- /dev/null
+++ b/src/devices/video/crtc_ega.cpp
@@ -0,0 +1,728 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol
+/**********************************************************************
+
+ IBM EGA CRT Controller emulation
+
+ This controller is very loosely based on the mc6845.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "crtc_ega.h"
+
+
+#define LOG (1)
+
+
+const device_type CRTC_EGA = &device_creator<crtc_ega_device>;
+
+
+crtc_ega_device::crtc_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, CRTC_EGA, "crtc_EGA", tag, owner, clock, "crtc_ega", __FILE__),
+ device_video_interface(mconfig, *this, false),
+ m_res_out_de_cb(*this),
+ m_res_out_hsync_cb(*this),
+ m_res_out_vsync_cb(*this),
+ m_res_out_vblank_cb(*this),
+ m_hpixels_per_column(0)
+{
+}
+
+
+void crtc_ega_device::device_post_load()
+{
+ recompute_parameters(true);
+}
+
+
+WRITE8_MEMBER( crtc_ega_device::address_w )
+{
+ m_register_address_latch = data & 0x1f;
+}
+
+
+READ8_MEMBER( crtc_ega_device::register_r )
+{
+ UINT8 ret = 0;
+
+ switch (m_register_address_latch)
+ {
+ case 0x0c: ret = (m_disp_start_addr >> 8) & 0xff; break;
+ case 0x0d: ret = (m_disp_start_addr >> 0) & 0xff; break;
+ case 0x0e: ret = (m_cursor_addr >> 8) & 0xff; break;
+ case 0x0f: ret = (m_cursor_addr >> 0) & 0xff; break;
+ case 0x10: ret = (m_light_pen_addr >> 8) & 0xff; m_light_pen_latched = FALSE; break;
+ case 0x11: ret = (m_light_pen_addr >> 0) & 0xff; m_light_pen_latched = FALSE; break;
+
+ /* all other registers are write only and return 0 */
+ default: break;
+ }
+
+ return ret;
+}
+
+
+WRITE8_MEMBER( crtc_ega_device::register_w )
+{
+ if (LOG) logerror("%s CRTC_EGA: reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
+
+ switch (m_register_address_latch)
+ {
+ case 0x00: m_horiz_char_total = data & 0xff; break;
+ case 0x01: m_horiz_disp = data & 0xff; break;
+ case 0x02: m_horiz_blank_start = data & 0xff; break;
+ case 0x03: m_horiz_blank_end = ((data & 0x1f) << 0) | (m_horiz_blank_end & 0x20);
+ m_de_skew = ((data & 0x60) >> 5);
+ m_ena_vert_access = data & 0x80;
+ break;
+ case 0x04: m_horiz_retr_start = data & 0xff; break;
+ case 0x05: m_horiz_retr_end = data & 0x1f;
+ m_horiz_retr_skew = ((data & 0x60) >> 5);
+ m_horiz_blank_end = ((data & 0x80) >> 2) | (m_horiz_blank_end & 0x1f);
+ break;
+ case 0x06: m_vert_total = ((data & 0xff) << 0) | (m_vert_total & 0x0300); break;
+ case 0x07: m_vert_total = ((data & 0x01) << 8) | (m_vert_total & 0x02ff);
+ m_vert_disp_end = ((data & 0x02) << 7) | (m_vert_disp_end & 0x02ff);
+ m_vert_retr_start = ((data & 0x04) << 6) | (m_vert_retr_start & 0x02ff);
+ m_vert_blank_start = ((data & 0x08) << 5) | (m_vert_blank_start & 0x02ff);
+ m_line_compare = ((data & 0x10) << 4) | (m_line_compare & 0x02ff);
+ m_vert_total = ((data & 0x20) << 4) | (m_vert_total & 0x01ff);
+ m_vert_disp_end = ((data & 0x40) << 3) | (m_vert_disp_end & 0x1ff);
+ m_vert_retr_start = ((data & 0x80) << 2) | (m_vert_retr_start & 0x01ff);
+ break;
+ case 0x08: m_preset_row_scan = data & 0x1f;
+ m_byte_panning = ((data & 0x60) >> 5);
+ break;
+ case 0x09: m_max_ras_addr = data & 0x1f;
+ m_vert_blank_start = ((data & 0x20) << 4) | (m_vert_blank_start & 0x01ff);
+ m_line_compare = ((data & 0x40) << 3) | (m_line_compare & 0x01ff);
+ m_scan_doubling = data & 0x80;
+ break;
+ case 0x0a: m_cursor_start_ras = data & 0x1f;
+ m_cursor_disable = data & 0x20;
+ break;
+ case 0x0b: m_cursor_end_ras = data & 0x1f;
+ m_cursor_skew = ((data & 0x60) >> 5);
+ break;
+ case 0x0c: m_disp_start_addr = ((data & 0xff) << 8) | (m_disp_start_addr & 0x00ff); break;
+ case 0x0d: m_disp_start_addr = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break;
+ case 0x0e: m_cursor_addr = ((data & 0xff) << 8) | (m_cursor_addr & 0x00ff); break;
+ case 0x0f: m_cursor_addr = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break;
+ case 0x10: m_vert_retr_start = ((data & 0xff) << 0) | (m_vert_retr_start & 0x0300); break;
+ case 0x11: m_vert_retr_end = data & 0x0f;
+ m_bandwidth = data & 0x40;
+ m_protect = data & 0x80;
+ break;
+ case 0x12: m_vert_disp_end = ((data & 0xff) << 0) | (m_vert_disp_end & 0x0300); break;
+ case 0x13: m_offset = data & 0xff; break;
+ case 0x14: m_underline_loc = data & 0x7f; break;
+ case 0x15: m_vert_blank_start = ((data & 0xff) << 0) | (m_vert_blank_start & 0x0300); break;
+ case 0x16: m_vert_blank_end = data & 0x7f; break;
+ case 0x17: m_mode_control = data & 0xff; break;
+ case 0x18: m_line_compare = ((data & 0xff) << 0) | (m_line_compare & 0x0300); break;
+ default: break;
+ }
+
+ recompute_parameters(false);
+}
+
+
+void crtc_ega_device::recompute_parameters(bool postload)
+{
+ UINT16 hsync_on_pos, hsync_off_pos, vsync_on_pos, vsync_off_pos;
+
+ /* compute the screen sizes */
+ UINT16 horiz_pix_total = (m_horiz_char_total + 2) * m_hpixels_per_column;
+ UINT16 vert_pix_total = m_vert_total + 1;
+
+ /* determine the visible area, avoid division by 0 */
+ UINT16 max_visible_x = ( m_horiz_disp + 1 ) * m_hpixels_per_column - 1;
+ UINT16 max_visible_y = m_vert_disp_end;
+
+ /* determine the syncing positions */
+ int horiz_sync_char_width = ( m_horiz_retr_end + 1 ) - ( m_horiz_retr_start & 0x1f );
+ int vert_sync_pix_width = m_vert_retr_end - ( m_vert_retr_start & 0x0f );
+
+ if (horiz_sync_char_width <= 0)
+ horiz_sync_char_width += 0x10;
+
+ if (vert_sync_pix_width <= 0)
+ vert_sync_pix_width += 0x10;
+
+ hsync_on_pos = m_horiz_retr_start * m_hpixels_per_column;
+ hsync_off_pos = hsync_on_pos + (horiz_sync_char_width * m_hpixels_per_column);
+ vsync_on_pos = m_vert_retr_start; /* + 1 ?? */
+ vsync_off_pos = vsync_on_pos + vert_sync_pix_width;
+
+ if (hsync_off_pos > horiz_pix_total)
+ hsync_off_pos = horiz_pix_total;
+
+ if (vsync_off_pos > vert_pix_total)
+ vsync_off_pos = vert_pix_total;
+
+ if ( vsync_on_pos >= vsync_off_pos )
+ {
+ vsync_on_pos = vsync_off_pos - 2;
+ }
+
+ /* update only if screen parameters changed, unless we are coming here after loading the saved state */
+ if (postload ||
+ (horiz_pix_total != m_horiz_pix_total) || (vert_pix_total != m_vert_pix_total) ||
+ (max_visible_x != m_max_visible_x) || (max_visible_y != m_max_visible_y) ||
+ (hsync_on_pos != m_hsync_on_pos) || (vsync_on_pos != m_vsync_on_pos) ||
+ (hsync_off_pos != m_hsync_off_pos) || (vsync_off_pos != m_vsync_off_pos))
+ {
+ /* update the screen if we have valid data */
+ if ((horiz_pix_total > 0) && (max_visible_x < horiz_pix_total) &&
+ (vert_pix_total > 0) && (max_visible_y < vert_pix_total) &&
+ (hsync_on_pos <= horiz_pix_total) && (vsync_on_pos <= vert_pix_total) &&
+ (hsync_on_pos != hsync_off_pos))
+ {
+ attoseconds_t refresh = HZ_TO_ATTOSECONDS(m_clock) * (m_horiz_char_total + 2) * vert_pix_total;
+
+ rectangle visarea(0, max_visible_x, 0, max_visible_y);
+
+ if (LOG) logerror("CRTC_EGA config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x Freq: %ffps\n",
+ horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
+
+ if ( m_screen != NULL )
+ m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh);
+
+ m_has_valid_parameters = true;
+ }
+ else
+ {
+ m_has_valid_parameters = false;
+ if (LOG) logerror("CRTC_EGA bad config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x\n",
+ horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1);
+
+ }
+
+ m_horiz_pix_total = horiz_pix_total;
+ m_vert_pix_total = vert_pix_total;
+ m_max_visible_x = max_visible_x;
+ m_max_visible_y = max_visible_y;
+ m_hsync_on_pos = hsync_on_pos;
+ m_hsync_off_pos = hsync_off_pos;
+ m_vsync_on_pos = vsync_on_pos;
+ m_vsync_off_pos = vsync_off_pos;
+ }
+}
+
+
+void crtc_ega_device::update_counters()
+{
+ m_character_counter = m_line_timer->elapsed().as_ticks( m_clock );
+
+ if ( m_hsync_off_timer->enabled() )
+ {
+ m_hsync_width_counter = m_hsync_off_timer->elapsed().as_ticks( m_clock );
+ }
+}
+
+
+void crtc_ega_device::set_de(int state)
+{
+ if (m_de != state)
+ {
+ m_de = state;
+
+ if (!m_res_out_de_cb.isnull())
+ m_res_out_de_cb(m_de);
+ }
+}
+
+
+void crtc_ega_device::set_hsync(int state)
+{
+ if (m_hsync != state)
+ {
+ m_hsync = state;
+
+ if (!m_res_out_hsync_cb.isnull())
+ m_res_out_hsync_cb(m_hsync);
+ }
+}
+
+
+void crtc_ega_device::set_vsync(int state)
+{
+ if (m_vsync != state)
+ {
+ m_vsync = state;
+
+ if (!m_res_out_vsync_cb.isnull())
+ m_res_out_vsync_cb(m_vsync);
+ }
+}
+
+
+void crtc_ega_device::set_vblank(int state)
+{
+ if (m_vblank != state)
+ {
+ m_vblank = state;
+
+ if (!m_res_out_vblank_cb.isnull())
+ m_res_out_vblank_cb(m_vblank);
+ }
+}
+
+
+void crtc_ega_device::set_cur(int state)
+{
+ if (m_cur != state)
+ {
+ m_cur = state;
+
+// if (!m_res_out_cur_cb.isnull())
+// m_res_out_cur_cb(m_cur);
+ }
+}
+
+
+void crtc_ega_device::handle_line_timer()
+{
+ int new_vsync = m_vsync;
+
+ m_character_counter = 0;
+ m_cursor_x = -1;
+
+ /* Check if VSYNC is active */
+ if ( m_vsync_ff )
+ {
+ m_vsync_width_counter = ( m_vsync_width_counter + 1 ) & 0x0F;
+
+ /* Check if we've reached end of VSYNC */
+ if ( m_vsync_width_counter == m_vert_retr_end )
+ {
+ m_vsync_ff = 0;
+
+ new_vsync = FALSE;
+ }
+ }
+
+ if ( m_raster_counter == m_max_ras_addr )
+ {
+ m_raster_counter = 0;
+ m_line_address = ( m_line_address + m_horiz_disp + 1 ) & 0xffff;
+ }
+ else
+ {
+ m_raster_counter = ( m_raster_counter + 1 ) & 0x1F;
+ }
+
+ m_line_counter = ( m_line_counter + 1 ) & 0x3ff;
+
+ /* Check if we've reached the end of active display */
+ if ( m_line_counter == m_vert_disp_end )
+ {
+ m_line_enable_ff = false;
+ }
+
+ /* Check if VSYNC should be enabled */
+ if ( m_line_counter == m_vert_retr_start )
+ {
+ m_vsync_width_counter = 0;
+ m_vsync_ff = 1;
+
+ new_vsync = TRUE;
+ }
+
+ /* Check if we have reached the end of the vertical area */
+ if ( m_line_counter == m_vert_total )
+ {
+ m_line_counter = 0;
+ m_line_address = m_disp_start_addr;
+ m_line_enable_ff = true;
+ set_vblank( FALSE );
+ /* also update the cursor state now */
+ update_cursor_state();
+
+ if (m_screen != NULL)
+ m_screen->reset_origin();
+ }
+
+ if ( m_line_enable_ff )
+ {
+ /* Schedule DE off signal change */
+ m_de_off_timer->adjust(attotime::from_ticks( m_horiz_disp + 1, m_clock ));
+
+ /* Is cursor visible on this line? */
+ if ( m_cursor_state &&
+ (m_raster_counter >= (m_cursor_start_ras & 0x1f)) &&
+ (m_raster_counter <= m_cursor_end_ras) &&
+ (m_cursor_addr >= m_line_address) &&
+ (m_cursor_addr < (m_line_address + m_horiz_disp + 1)) )
+ {
+ m_cursor_x = m_cursor_addr - m_line_address;
+
+ /* Schedule CURSOR ON signal */
+ m_cur_on_timer->adjust( attotime::from_ticks( m_cursor_x, m_clock ) );
+ }
+ }
+
+ /* Schedule HSYNC on signal */
+ m_hsync_on_timer->adjust( attotime::from_ticks( m_horiz_blank_start, m_clock ) );
+
+ /* Set VBlank signal */
+ if ( m_line_counter == m_vert_disp_end + 1 )
+ {
+ set_vblank( TRUE );
+ }
+
+ /* Schedule our next callback */
+ m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 2, m_clock ) );
+
+ /* Set VSYNC and DE signals */
+ set_vsync( new_vsync );
+ set_de( m_line_enable_ff ? TRUE : FALSE );
+}
+
+
+void crtc_ega_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_LINE:
+ handle_line_timer();
+ break;
+
+ case TIMER_DE_OFF:
+ set_de( FALSE );
+ break;
+
+ case TIMER_CUR_ON:
+ set_cur( TRUE );
+
+ /* Schedule CURSOR off signal */
+ m_cur_off_timer->adjust( attotime::from_ticks( 1, m_clock ) );
+ break;
+
+ case TIMER_CUR_OFF:
+ set_cur( FALSE );
+ break;
+
+ case TIMER_HSYNC_ON:
+ {
+ INT8 hsync_width = ( 0x20 | m_horiz_blank_end ) - ( m_horiz_blank_start & 0x1f );
+
+ if ( hsync_width <= 0 )
+ {
+ hsync_width += 0x20;
+ }
+
+ m_hsync_width_counter = 0;
+ set_hsync( TRUE );
+
+ /* Schedule HSYNC off signal */
+ m_hsync_off_timer->adjust( attotime::from_ticks( hsync_width, m_clock ) );
+ }
+ break;
+
+ case TIMER_HSYNC_OFF:
+ set_hsync( FALSE );
+ break;
+
+ case TIMER_LIGHT_PEN_LATCH:
+ m_light_pen_addr = get_ma();
+ m_light_pen_latched = true;
+ break;
+ }
+}
+
+
+UINT16 crtc_ega_device::get_ma()
+{
+ update_counters();
+
+ return m_line_address + m_character_counter;
+}
+
+
+UINT8 crtc_ega_device::get_ra()
+{
+ return m_raster_counter;
+}
+
+
+void crtc_ega_device::assert_light_pen_input()
+{
+ /* compute the pixel coordinate of the NEXT character -- this is when the light pen latches */
+ /* set the timer that will latch the display address into the light pen registers */
+ m_light_pen_latch_timer->adjust(attotime::from_ticks( 1, m_clock ));
+}
+
+
+void crtc_ega_device::set_clock(int clock)
+{
+ /* validate arguments */
+ assert(clock > 0);
+
+ if (clock != m_clock)
+ {
+ m_clock = clock;
+ recompute_parameters(true);
+ }
+}
+
+
+void crtc_ega_device::set_hpixels_per_column(int hpixels_per_column)
+{
+ /* validate arguments */
+ assert(hpixels_per_column > 0);
+
+ if (hpixels_per_column != m_hpixels_per_column)
+ {
+ m_hpixels_per_column = hpixels_per_column;
+ recompute_parameters(true);
+ }
+}
+
+
+void crtc_ega_device::update_cursor_state()
+{
+ /* save and increment cursor counter */
+ UINT8 last_cursor_blink_count = m_cursor_blink_count;
+ m_cursor_blink_count = m_cursor_blink_count + 1;
+
+ /* switch on cursor blinking mode */
+ switch (m_cursor_start_ras & 0x60)
+ {
+ /* always on */
+ case 0x00: m_cursor_state = true; break;
+
+ /* always off */
+ case 0x20: m_cursor_state = false; break;
+
+ /* fast blink */
+ case 0x40:
+ if ((last_cursor_blink_count & 0x10) != (m_cursor_blink_count & 0x10))
+ {
+ m_cursor_state = !m_cursor_state;
+ }
+ break;
+
+ /* slow blink */
+ case 0x60:
+ if ((last_cursor_blink_count & 0x20) != (m_cursor_blink_count & 0x20))
+ {
+ m_cursor_state = !m_cursor_state;
+ }
+ break;
+ }
+}
+
+
+UINT32 crtc_ega_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ assert(bitmap.valid());
+
+ if (m_has_valid_parameters)
+ {
+ UINT16 y;
+
+ assert(!m_row_update_cb.isnull());
+
+ /* call the set up function if any */
+ if (!m_begin_update_cb.isnull())
+ m_begin_update_cb(bitmap, cliprect);
+
+ if (cliprect.min_y == 0)
+ {
+ /* read the start address at the beginning of the frame */
+ m_current_disp_addr = m_disp_start_addr;
+ }
+
+ /* for each row in the visible region */
+ for (y = cliprect.min_y; y <= cliprect.max_y; y++)
+ {
+ /* compute the current raster line */
+ UINT8 ra = y % (m_max_ras_addr + 1);
+
+ /* check if the cursor is visible and is on this scanline */
+ int cursor_visible = m_cursor_state &&
+ (ra >= (m_cursor_start_ras & 0x1f)) &&
+ ( (ra <= (m_cursor_end_ras & 0x1f)) || ((m_cursor_end_ras & 0x1f) == 0x00 )) &&
+ (m_cursor_addr >= m_current_disp_addr) &&
+ (m_cursor_addr < (m_current_disp_addr + ( m_horiz_disp + 1 )));
+
+ /* compute the cursor X position, or -1 if not visible */
+ INT8 cursor_x = cursor_visible ? (m_cursor_addr - m_current_disp_addr) : -1;
+
+ /* call the external system to draw it */
+ m_row_update_cb(bitmap, cliprect, m_current_disp_addr, ra, y, m_horiz_disp + 1, cursor_x);
+
+ /* update MA if the last raster address */
+ if (ra == m_max_ras_addr)
+ m_current_disp_addr = (m_current_disp_addr + m_horiz_disp + 1) & 0xffff;
+ }
+
+ /* call the tear down function if any */
+ if (!m_end_update_cb.isnull())
+ m_end_update_cb(bitmap, cliprect);
+ }
+ else
+ logerror("Invalid crtc_ega screen parameters - display disabled!!!\n");
+
+ return 0;
+}
+
+
+/* device interface */
+void crtc_ega_device::device_start()
+{
+ /* validate arguments */
+ assert(m_clock > 0);
+ assert(m_hpixels_per_column > 0);
+
+ /* resolve callbacks */
+ m_res_out_de_cb.resolve();
+ m_res_out_hsync_cb.resolve();
+ m_res_out_vsync_cb.resolve();
+ m_res_out_vblank_cb.resolve();
+
+ /* bind delegates */
+ m_begin_update_cb.bind_relative_to(*owner());
+ m_row_update_cb.bind_relative_to(*owner());
+ m_end_update_cb.bind_relative_to(*owner());
+
+ /* create the timers */
+ m_line_timer = timer_alloc(TIMER_LINE);
+ m_de_off_timer = timer_alloc(TIMER_DE_OFF);
+ m_cur_on_timer = timer_alloc(TIMER_CUR_ON);
+ m_cur_off_timer = timer_alloc(TIMER_CUR_OFF);
+ m_hsync_on_timer = timer_alloc(TIMER_HSYNC_ON);
+ m_hsync_off_timer = timer_alloc(TIMER_HSYNC_OFF);
+ m_light_pen_latch_timer = timer_alloc(TIMER_LIGHT_PEN_LATCH);
+
+ /* Use some large startup values */
+ m_horiz_char_total = 0xff;
+ m_max_ras_addr = 0x1f;
+ m_vert_total = 0x3ff;
+
+ m_ena_vert_access = 0;
+ m_de_skew = 0;
+ m_horiz_retr_start = 0;
+ m_horiz_retr_end = 0;
+ m_horiz_retr_skew = 0;
+ m_preset_row_scan = 0;
+ m_byte_panning = 0;
+ m_scan_doubling = 0;
+ m_cursor_start_ras = 0x20;
+ m_cursor_disable = 0;
+ m_cursor_end_ras = 0;
+ m_cursor_skew = 0;
+ m_disp_start_addr = 0;
+ m_light_pen_addr = 0;
+ m_vert_retr_end = 0;
+ m_protect = 0;
+ m_bandwidth = 0;
+ m_offset = 0;
+ m_underline_loc = 0;
+ m_vert_blank_end = 0;
+ m_mode_control = 0;
+ m_line_compare = 0;
+ m_register_address_latch = 0;
+ m_cursor_state = false;
+ m_cursor_blink_count = 0;
+ m_cur = 0;
+ m_hsync = 0;
+ m_vsync = 0;
+ m_vblank = 0;
+ m_de = 0;
+ m_character_counter = 0;
+ m_hsync_width_counter = 0;
+ m_vsync_width_counter = 0;
+ m_line_enable_ff = false;
+ m_vsync_ff = 0;
+ m_adjust_active = 0;
+
+ m_current_disp_addr = 0;
+ m_light_pen_latched = FALSE;
+ m_has_valid_parameters = false;
+
+ /* register for state saving */
+ save_item(NAME(m_hpixels_per_column));
+ save_item(NAME(m_register_address_latch));
+ save_item(NAME(m_horiz_char_total));
+ save_item(NAME(m_horiz_disp));
+ save_item(NAME(m_horiz_blank_start));
+ save_item(NAME(m_mode_control));
+ save_item(NAME(m_cursor_start_ras));
+ save_item(NAME(m_cursor_end_ras));
+ save_item(NAME(m_disp_start_addr));
+ save_item(NAME(m_cursor_addr));
+ save_item(NAME(m_light_pen_addr));
+ save_item(NAME(m_light_pen_latched));
+ save_item(NAME(m_cursor_state));
+ save_item(NAME(m_cursor_blink_count));
+ save_item(NAME(m_horiz_blank_end));
+ save_item(NAME(m_ena_vert_access));
+ save_item(NAME(m_de_skew));
+ save_item(NAME(m_horiz_retr_start));
+ save_item(NAME(m_horiz_retr_end));
+ save_item(NAME(m_horiz_retr_skew));
+ save_item(NAME(m_vert_total));
+ save_item(NAME(m_preset_row_scan));
+ save_item(NAME(m_byte_panning));
+ save_item(NAME(m_max_ras_addr));
+ save_item(NAME(m_scan_doubling));
+ save_item(NAME(m_cursor_disable));
+ save_item(NAME(m_cursor_skew));
+ save_item(NAME(m_vert_retr_start));
+ save_item(NAME(m_vert_retr_end));
+ save_item(NAME(m_protect));
+ save_item(NAME(m_bandwidth));
+ save_item(NAME(m_vert_disp_end));
+ save_item(NAME(m_offset));
+ save_item(NAME(m_underline_loc));
+ save_item(NAME(m_vert_blank_start));
+ save_item(NAME(m_vert_blank_end));
+ save_item(NAME(m_line_compare));
+}
+
+
+void crtc_ega_device::device_reset()
+{
+ /* internal registers other than status remain unchanged, all outputs go low */
+ if (!m_res_out_de_cb.isnull())
+ m_res_out_de_cb(false);
+
+ if (!m_res_out_hsync_cb.isnull())
+ m_res_out_hsync_cb(false);
+
+ if (!m_res_out_vsync_cb.isnull())
+ m_res_out_vsync_cb(false);
+
+ if (!m_res_out_vblank_cb.isnull())
+ m_res_out_vblank_cb(false);
+
+ if (!m_line_timer->enabled())
+ {
+ m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 2, m_clock ) );
+ }
+
+ m_light_pen_latched = false;
+
+ m_cursor_addr = 0;
+ m_line_address = 0;
+ m_horiz_disp = 0;
+ m_cursor_x = 0;
+ m_horiz_blank_start = 0;
+ m_horiz_blank_end = 0;
+ m_vert_disp_end = 0;
+ m_vert_retr_start = 0;
+ m_vert_blank_start = 0;
+ m_line_counter = 0;
+ m_raster_counter = 0;
+ m_horiz_pix_total = 0;
+ m_vert_pix_total = 0;
+ m_max_visible_x = 0;
+ m_max_visible_y = 0;
+ m_hsync_on_pos = 0;
+ m_vsync_on_pos = 0;
+ m_hsync_off_pos = 0;
+ m_vsync_off_pos = 0;
+}