/********************************************************************** Motorola MC6845 and compatible CRT controller emulation Copyright Nicola Salmoria and the MAME Team. Visit http://mamedev.org for licensing and usage restrictions. The following variations exist that are different in functionality and not just in speed rating(1): * Motorola 6845, 6845-1 * Hitachi 46505 * Rockwell 6545, 6545-1 (= Synertek SY6545-1) * MOS Technology 6545-1 (1) as per the document at http://www.6502.org/users/andre/hwinfo/crtc/diffs.html The various speed rated devices are identified by a letter, for example M68A45, M68B45, etc. The chip is originally designed by Hitachi, not by Motorola. **********************************************************************/ #include "emu.h" #include "mc6845.h" #include "machine/devhelpr.h" #define LOG (0) const device_type MC6845 = &device_creator; const device_type MC6845_1 = &device_creator; const device_type R6545_1 = &device_creator; const device_type C6545_1 = &device_creator; const device_type H46505 = &device_creator; const device_type HD6845 = &device_creator; const device_type SY6545_1 = &device_creator; const device_type SY6845E = &device_creator; /* mode macros */ #define MODE_TRANSPARENT ((m_mode_control & 0x08) != 0) #define MODE_TRANSPARENT_PHI2 ((m_mode_control & 0x88) == 0x88) /* FIXME: not supported yet */ #define MODE_TRANSPARENT_BLANK ((m_mode_control & 0x88) == 0x08) #define MODE_UPDATE_STROBE ((m_mode_control & 0x40) != 0) #define MODE_CURSOR_SKEW ((m_mode_control & 0x20) != 0) #define MODE_DISPLAY_ENABLE_SKEW ((m_mode_control & 0x10) != 0) #define MODE_ROW_COLUMN_ADDRESSING ((m_mode_control & 0x04) != 0) void mc6845_device::device_config_complete() { const mc6845_interface *intf = reinterpret_cast(static_config()); if ( intf != NULL ) { *static_cast(this) = *intf; } else { m_screen_tag = NULL; m_hpixels_per_column = 0; m_begin_update = NULL; m_update_row = NULL; m_end_update = NULL; m_on_update_addr_changed = NULL; memset(&m_out_de_func, 0, sizeof(m_out_de_func)); memset(&m_out_cur_func, 0, sizeof(m_out_cur_func)); memset(&m_out_hsync_func, 0, sizeof(m_out_hsync_func)); memset(&m_out_vsync_func, 0, sizeof(m_out_vsync_func)); } } mc6845_device::mc6845_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, type, name, tag, owner, clock) { } mc6845_device::mc6845_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, MC6845, "mc6845", tag, owner, clock) { } void mc6845_device::device_post_load() { recompute_parameters(true); } void mc6845_device::call_on_update_address(int strobe) { if (m_on_update_addr_changed) m_upd_trans_timer->adjust(attotime::zero, (m_update_addr << 8) | strobe); else fatalerror("M6845: transparent memory mode without handler\n"); } WRITE8_MEMBER( mc6845_device::address_w ) { m_register_address_latch = data & 0x1f; } READ8_MEMBER( mc6845_device::status_r ) { UINT8 ret = 0; /* VBLANK bit */ if (m_supports_status_reg_d5 && !m_line_enable_ff) ret = ret | 0x20; /* light pen latched */ if (m_supports_status_reg_d6 && m_light_pen_latched) ret = ret | 0x40; /* UPDATE ready */ if (m_supports_status_reg_d7 && m_update_ready_bit) ret = ret | 0x80; return ret; } READ8_MEMBER( mc6845_device::register_r ) { UINT8 ret = 0; switch (m_register_address_latch) { case 0x0c: ret = m_supports_disp_start_addr_r ? (m_disp_start_addr >> 8) & 0xff : 0; break; case 0x0d: ret = m_supports_disp_start_addr_r ? (m_disp_start_addr >> 0) & 0xff : 0; 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; case 0x1f: if (m_supports_transparent && MODE_TRANSPARENT) { if(MODE_TRANSPARENT_PHI2) { m_update_addr++; m_update_addr &= 0x3fff; call_on_update_address(0); } else { /* MODE_TRANSPARENT_BLANK */ if(m_update_ready_bit) { m_update_ready_bit = false; update_upd_adr_timer(); } } } break; /* all other registers are write only and return 0 */ default: break; } return ret; } WRITE8_MEMBER( mc6845_device::register_w ) { if (LOG) logerror("%s:M6845 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_sync_pos = data & 0xff; break; case 0x03: m_sync_width = data & 0xff; break; case 0x04: m_vert_char_total = data & 0x7f; break; case 0x05: m_vert_total_adj = data & 0x1f; break; case 0x06: m_vert_disp = data & 0x7f; break; case 0x07: m_vert_sync_pos = data & 0x7f; break; case 0x08: m_mode_control = data & 0xff; break; case 0x09: m_max_ras_addr = data & 0x1f; break; case 0x0a: m_cursor_start_ras = data & 0x7f; break; case 0x0b: m_cursor_end_ras = data & 0x1f; break; case 0x0c: m_disp_start_addr = ((data & 0x3f) << 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 & 0x3f) << 8) | (m_cursor_addr & 0x00ff); break; case 0x0f: m_cursor_addr = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break; case 0x10: /* read-only */ break; case 0x11: /* read-only */ break; case 0x12: if (m_supports_transparent) { m_update_addr = ((data & 0x3f) << 8) | (m_update_addr & 0x00ff); if(MODE_TRANSPARENT_PHI2) call_on_update_address(0); } break; case 0x13: if (m_supports_transparent) { m_update_addr = ((data & 0xff) << 0) | (m_update_addr & 0xff00); if(MODE_TRANSPARENT_PHI2) call_on_update_address(0); } break; case 0x1f: if (m_supports_transparent && MODE_TRANSPARENT) { if(MODE_TRANSPARENT_PHI2) { m_update_addr++; m_update_addr &= 0x3fff; call_on_update_address(0); } else { /* MODE_TRANSPARENT_BLANK */ if(m_update_ready_bit) { m_update_ready_bit = false; update_upd_adr_timer(); } } } break; default: break; } /* display message if the Mode Control register is not zero */ if ((m_register_address_latch == 0x08) && (m_mode_control != 0)) if (!m_supports_transparent) popmessage("Mode Control %02X is not supported!!!", m_mode_control); recompute_parameters(false); } void mc6845_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 + 1) * m_hpixels_per_column; UINT16 vert_pix_total = (m_vert_char_total + 1) * (m_max_ras_addr + 1) + m_vert_total_adj; /* determine the visible area, avoid division by 0 */ UINT16 max_visible_x = m_horiz_disp * m_hpixels_per_column - 1; UINT16 max_visible_y = m_vert_disp * (m_max_ras_addr + 1) - 1; /* determine the syncing positions */ UINT8 horiz_sync_char_width = m_sync_width & 0x0f; UINT8 vert_sync_pix_width = m_supports_vert_sync_width ? (m_sync_width >> 4) & 0x0f : 0x10; if (horiz_sync_char_width == 0) horiz_sync_char_width = 0x10; if (vert_sync_pix_width == 0) vert_sync_pix_width = 0x10; /* determine the transparent update cycle time, 1 update every 4 character clocks */ m_upd_time = attotime::from_hz(m_clock) * (4 * m_hpixels_per_column); hsync_on_pos = m_horiz_sync_pos * m_hpixels_per_column; hsync_off_pos = hsync_on_pos + (horiz_sync_char_width * m_hpixels_per_column); vsync_on_pos = m_vert_sync_pos * (m_max_ras_addr + 1); vsync_off_pos = vsync_on_pos + vert_sync_pix_width; /* the Commodore PET computers program a horizontal synch pulse that extends past the scanline width. I assume that the real device will clamp it */ 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; /* 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)) { rectangle visarea; attoseconds_t refresh = HZ_TO_ATTOSECONDS(m_clock) * (m_horiz_char_total + 1) * vert_pix_total; visarea.min_x = 0; visarea.min_y = 0; visarea.max_x = max_visible_x; visarea.max_y = max_visible_y; if (LOG) logerror("M6845 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; 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 mc6845_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 mc6845_device::set_de(int state) { if ( m_de != state ) { m_de = state; if ( m_de ) { /* If the upd_adr_timer was running, cancel it */ m_upd_adr_timer->adjust(attotime::never); } else { /* if transparent update was requested fire the update timer */ if(!m_update_ready_bit) update_upd_adr_timer(); } if ( !m_res_out_de_func.isnull() ) m_res_out_de_func( m_de ); } } void mc6845_device::set_hsync(int state) { if ( m_hsync != state ) { m_hsync = state; if ( !m_res_out_hsync_func.isnull() ) m_res_out_hsync_func( m_hsync ); } } void mc6845_device::set_vsync(int state) { if ( m_vsync != state ) { m_vsync = state; if ( !m_res_out_vsync_func.isnull() ) m_res_out_vsync_func( m_vsync ); } } void mc6845_device::set_cur(int state) { if ( m_cur != state ) { m_cur = state; if ( !m_res_out_cur_func.isnull() ) m_res_out_cur_func( m_cur ); } } void mc6845_device::update_upd_adr_timer() { if (! m_de && m_supports_transparent) m_upd_adr_timer->adjust(m_upd_time); } void mc6845_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 ) { UINT8 vsync_width = m_supports_vert_sync_width ? (m_sync_width >> 4) & 0x0f : 0; m_vsync_width_counter = ( m_vsync_width_counter + 1 ) & 0x0F; /* Check if we've reached end of VSYNC */ if ( m_vsync_width_counter == vsync_width ) { m_vsync_ff = 0; new_vsync = FALSE; } } if ( m_raster_counter == m_max_ras_addr ) { /* Check if we have reached the end of the vertical area */ if ( m_line_counter == m_vert_char_total ) { m_adjust_counter = 0; m_adjust_active = 1; } m_raster_counter = 0; m_line_counter = ( m_line_counter + 1 ) & 0x7F; m_line_address = ( m_line_address + m_horiz_disp ) & 0x3fff; /* Check if we've reached the end of active display */ if ( m_line_counter == m_vert_disp ) { m_line_enable_ff = false; } /* Check if VSYNC should be enabled */ if ( m_line_counter == m_vert_sync_pos ) { m_vsync_width_counter = 0; m_vsync_ff = 1; new_vsync = TRUE; } } else { m_raster_counter = ( m_raster_counter + 1 ) & 0x1F; } if ( m_adjust_active ) { /* Check if we have reached the end of a full cycle */ if ( m_adjust_counter == m_vert_total_adj ) { m_adjust_active = 0; m_raster_counter = 0; m_line_counter = 0; m_line_address = m_disp_start_addr; m_line_enable_ff = true; /* also update the cursor state now */ update_cursor_state(); if (m_screen != NULL) m_screen->reset_origin(); } else { m_adjust_counter = ( m_adjust_counter + 1 ) & 0x1F; } } if ( m_line_enable_ff ) { /* Schedule DE off signal change */ m_de_off_timer->adjust(attotime::from_ticks( m_horiz_disp, 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)) ) { 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_sync_pos, m_clock ) ); /* Schedule our next callback */ m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 1, m_clock ) ); /* Set VSYNC and DE signals */ set_vsync( new_vsync ); set_de( m_line_enable_ff ? TRUE : FALSE ); } void mc6845_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: { UINT8 hsync_width = ( m_sync_width & 0x0f ) ? ( m_sync_width & 0x0f ) : 0x10; 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; case TIMER_UPD_ADR: /* fire a update address strobe */ call_on_update_address(0); break; case TIMER_UPD_TRANS: { int addr = (param >> 8); int strobe = (param & 0xff); /* call the callback function -- we know it exists */ m_on_update_addr_changed(this, addr, strobe); if(!m_update_ready_bit && MODE_TRANSPARENT_BLANK) { m_update_addr++; m_update_addr &= 0x3fff; m_update_ready_bit = true; } } break; } } UINT16 mc6845_device::get_ma() { update_counters(); return ( m_line_address + m_character_counter ) & 0x3fff; } UINT8 mc6845_device::get_ra() { return m_raster_counter; } void mc6845_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 mc6845_device::set_clock(int clock) { /* validate arguments */ assert(clock > 0); if (clock != m_clock) { m_clock = clock; recompute_parameters(true); } } void mc6845_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(false); } } void mc6845_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 */ default: 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; } } void mc6845_device::update(bitmap_t *bitmap, const rectangle *cliprect) { assert(bitmap != NULL); assert(cliprect != NULL); if (m_has_valid_parameters) { UINT16 y; void *param = NULL; assert(m_update_row != NULL); /* call the set up function if any */ if (m_begin_update != NULL) param = m_begin_update(this, 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) && (m_cursor_addr >= m_current_disp_addr) && (m_cursor_addr < (m_current_disp_addr + m_horiz_disp)); /* 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 */ if (MODE_ROW_COLUMN_ADDRESSING) { UINT8 cc = 0; UINT8 cr = y / (m_max_ras_addr + 1); UINT16 ma = (cr << 8) | cc; m_update_row(this, bitmap, cliprect, ma, ra, y, m_horiz_disp, cursor_x, param); } else { m_update_row(this, bitmap, cliprect, m_current_disp_addr, ra, y, m_horiz_disp, cursor_x, param); } /* update MA if the last raster address */ if (ra == m_max_ras_addr) m_current_disp_addr = (m_current_disp_addr + m_horiz_disp) & 0x3fff; } /* call the tear down function if any */ if (m_end_update != NULL) m_end_update(this, bitmap, cliprect, param); } else popmessage("Invalid MC6845 screen parameters - display disabled!!!"); } void mc6845_device::device_start() { assert(m_clock > 0); assert(m_hpixels_per_column > 0); /* resolve callbacks */ m_res_out_de_func.resolve(m_out_de_func, *this); m_res_out_cur_func.resolve(m_out_cur_func, *this); m_res_out_hsync_func.resolve(m_out_hsync_func, *this); m_res_out_vsync_func.resolve(m_out_vsync_func, *this); /* get the screen device */ if ( m_screen_tag != NULL ) { m_screen = downcast(machine().device(m_screen_tag)); if (m_screen == NULL) { astring tempstring; m_screen = downcast(machine().device(owner()->subtag(tempstring,m_screen_tag))); } assert(m_screen != NULL); } else m_screen = NULL; /* 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); m_upd_adr_timer = timer_alloc(TIMER_UPD_ADR); m_upd_trans_timer = timer_alloc(TIMER_UPD_TRANS); /* Use some large startup values */ m_horiz_char_total = 0xff; m_max_ras_addr = 0x1f; m_vert_char_total = 0x7f; m_supports_disp_start_addr_r = true; m_supports_vert_sync_width = false; m_supports_status_reg_d5 = false; m_supports_status_reg_d6 = false; m_supports_status_reg_d7 = false; m_supports_transparent = false; m_has_valid_parameters = false; m_line_enable_ff = false; m_vsync_ff = 0; m_raster_counter = 0; m_adjust_active = 0; m_horiz_sync_pos = 1; m_vert_sync_pos = 1; m_de = 0; m_sync_width = 1; m_vert_char_total = 0; m_vert_disp = 0; m_horiz_pix_total = m_vert_pix_total = 0; m_max_visible_x = m_max_visible_y = 0; m_hsync_on_pos = m_vsync_on_pos = 0; m_hsync_off_pos = m_vsync_off_pos = 0; m_vsync = m_hsync = 0; m_line_counter = 0; m_horiz_disp = m_vert_disp = 0; m_vert_sync_pos = 0; m_vert_total_adj = 0; m_cursor_start_ras = m_cursor_end_ras = 0; m_cursor_blink_count = 0; m_cursor_state = 0; m_update_ready_bit = 0; m_cursor_state = 0; m_raster_counter = 0; m_cursor_start_ras = 0; m_cursor_end_ras = m_cursor_addr = 0; m_line_address = 0; m_current_disp_addr = 0; m_line_address = 0; 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_sync_pos)); save_item(NAME(m_sync_width)); save_item(NAME(m_vert_char_total)); save_item(NAME(m_vert_total_adj)); save_item(NAME(m_vert_disp)); save_item(NAME(m_vert_sync_pos)); save_item(NAME(m_mode_control)); save_item(NAME(m_max_ras_addr)); 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_update_addr)); save_item(NAME(m_update_ready_bit)); save_item(NAME(m_cur)); save_item(NAME(m_hsync)); save_item(NAME(m_vsync)); save_item(NAME(m_de)); save_item(NAME(m_character_counter)); save_item(NAME(m_hsync_width_counter)); save_item(NAME(m_line_counter)); save_item(NAME(m_raster_counter)); save_item(NAME(m_adjust_counter)); save_item(NAME(m_vsync_width_counter)); save_item(NAME(m_line_enable_ff)); save_item(NAME(m_vsync_ff)); save_item(NAME(m_adjust_active)); save_item(NAME(m_line_address)); save_item(NAME(m_cursor_x)); save_item(NAME(m_has_valid_parameters)); } void mc6845_1_device::device_start() { mc6845_device::device_start(); m_supports_disp_start_addr_r = true; m_supports_vert_sync_width = true; m_supports_status_reg_d5 = false; m_supports_status_reg_d6 = false; m_supports_status_reg_d7 = false; m_supports_transparent = false; } void c6545_1_device::device_start() { mc6845_device::device_start(); m_supports_disp_start_addr_r = false; m_supports_vert_sync_width = true; m_supports_status_reg_d5 = true; m_supports_status_reg_d6 = true; m_supports_status_reg_d7 = false; m_supports_transparent = false; } void r6545_1_device::device_start() { mc6845_device::device_start(); m_supports_disp_start_addr_r = false; m_supports_vert_sync_width = true; m_supports_status_reg_d5 = true; m_supports_status_reg_d6 = true; m_supports_status_reg_d7 = true; m_supports_transparent = true; } void h46505_device::device_start() { mc6845_device::device_start(); m_supports_disp_start_addr_r = false; m_supports_vert_sync_width = false; m_supports_status_reg_d5 = false; m_supports_status_reg_d6 = false; m_supports_status_reg_d7 = false; m_supports_transparent = false; } void hd6845_device::device_start() { mc6845_device::device_start(); m_supports_disp_start_addr_r = false; m_supports_vert_sync_width = true; m_supports_status_reg_d5 = false; m_supports_status_reg_d6 = false; m_supports_status_reg_d7 = false; m_supports_transparent = false; } void sy6545_1_device::device_start() { mc6845_device::device_start(); m_supports_disp_start_addr_r = false; m_supports_vert_sync_width = true; m_supports_status_reg_d5 = true; m_supports_status_reg_d6 = true; m_supports_status_reg_d7 = true; m_supports_transparent = true; } void sy6845e_device::device_start() { mc6845_device::device_start(); m_supports_disp_start_addr_r = false; m_supports_vert_sync_width = true; m_supports_status_reg_d5 = true; m_supports_status_reg_d6 = true; m_supports_status_reg_d7 = true; m_supports_transparent = true; } void mc6845_device::device_reset() { /* internal registers other than status remain unchanged, all outputs go low */ if ( !m_res_out_de_func.isnull() ) m_res_out_de_func( FALSE ); if ( !m_res_out_hsync_func.isnull() ) m_res_out_hsync_func( FALSE ); if ( !m_res_out_vsync_func.isnull() ) m_res_out_vsync_func( FALSE ); if ( ! m_line_timer->enabled( ) ) { m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 1, m_clock ) ); } m_light_pen_latched = false; m_cursor_addr = 0; m_line_address = 0; m_horiz_disp = 0; m_cursor_x = 0; } void r6545_1_device::device_reset() { mc6845_device::device_reset(); } void h46505_device::device_reset() { mc6845_device::device_reset(); } void mc6845_1_device::device_reset() { mc6845_device::device_reset(); } void hd6845_device::device_reset() { mc6845_device::device_reset(); } void c6545_1_device::device_reset() { mc6845_device::device_reset(); } void sy6545_1_device::device_reset() { mc6845_device::device_reset(); } void sy6845e_device::device_reset() { mc6845_device::device_reset(); } r6545_1_device::r6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : mc6845_device(mconfig, R6545_1, "r6545_1", tag, owner, clock) { } h46505_device::h46505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : mc6845_device(mconfig, H46505, "h46505", tag, owner, clock) { } mc6845_1_device::mc6845_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : mc6845_device(mconfig, MC6845_1, "mc6845_1", tag, owner, clock) { } hd6845_device::hd6845_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : mc6845_device(mconfig, HD6845, "hd6845", tag, owner, clock) { } c6545_1_device::c6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : mc6845_device(mconfig, C6545_1, "c6545_1", tag, owner, clock) { } sy6545_1_device::sy6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : mc6845_device(mconfig, SY6545_1, "sy6545_1", tag, owner, clock) { } sy6845e_device::sy6845e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : mc6845_device(mconfig, SY6845E, "sy6845e", tag, owner, clock) { }