1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol,Nigel Barnes
3 /**********************************************************************
4 
5     Motorola MC6845 and compatible CRT controller emulation
6 
7     The following variations exist that are different in
8     functionality and not just in speed rating(1):
9         * Motorola 6845, 6845-1
10         * Hitachi 6845 (= 46505R), 6845S (= 46505S), 6345/6445
11         * Rockwell 6545, 6545-1 (= Synertek SY6545-1)
12         * MOS Technology 6545-1
13 
14     (1) as per the document at
15     http://www.6502.org/users/andre/hwinfo/crtc/diffs.html
16 
17     The various speed rated devices are usually identified by a
18     letter, e.g. MC68A45, MC68B45. Hitachi's older HD46505 numbering
19     identifies speed by numerical suffixes (-1, -2), which other
20     manufacturers use to identify functional variants instead.
21 
22     The chip is originally designed by Hitachi, not by Motorola.
23 
24 **********************************************************************/
25 
26 /*
27 
28     TODO:
29 
30     - Change device video emulation x/y offsets when "show border color"
31       is true
32     - Support 'interlace and video' mode
33 
34     - mos8563
35         - horizontal scroll
36         - vertical scroll
37         - bitmap modes
38         - display enable begin/end
39 
40     - hd6345
41         - smooth scrolling
42         - second cursor
43         - interrupt request
44 
45 */
46 
47 #include "emu.h"
48 #include "mc6845.h"
49 
50 #include "screen.h"
51 
52 #define LOG_SETUP   (1 << 1U)
53 #define LOG_REGS    (1 << 2U)
54 #define LOG_CONF    (1 << 3U)
55 
56 //#define VERBOSE (LOG_SETUP|LOG_CONF|LOG_REGS)
57 //#define LOG_OUTPUT_STREAM std::cout
58 
59 #include "logmacro.h"
60 
61 #define LOGSETUP(...)   LOGMASKED(LOG_SETUP,  __VA_ARGS__)
62 #define LOGREGS(...)    LOGMASKED(LOG_REGS,  __VA_ARGS__)
63 #define LOGCONF(...)    LOGMASKED(LOG_CONF,  __VA_ARGS__)
64 
65 DEFINE_DEVICE_TYPE(MC6845,   mc6845_device,   "mc6845",   "Motorola MC6845 CRTC")
66 DEFINE_DEVICE_TYPE(MC6845_1, mc6845_1_device, "mc6845_1", "Motorola MC6845-1 CRTC")
67 DEFINE_DEVICE_TYPE(R6545_1,  r6545_1_device,  "r6545_1",  "Rockwell R6545-1 CRTC")
68 DEFINE_DEVICE_TYPE(C6545_1,  c6545_1_device,  "c6545_1",  "C6545-1 CRTC")
69 DEFINE_DEVICE_TYPE(HD6845S,  hd6845s_device,  "hd6845s",  "Hitachi HD6845S CRTC") // same as HD46505S
70 DEFINE_DEVICE_TYPE(SY6545_1, sy6545_1_device, "sy6545_1", "Synertek SY6545-1 CRTC")
71 DEFINE_DEVICE_TYPE(SY6845E,  sy6845e_device,  "sy6845e",  "Synertek SY6845E CRTC")
72 DEFINE_DEVICE_TYPE(HD6345,   hd6345_device,   "hd6345",   "Hitachi HD6345 CRTC-II")
73 DEFINE_DEVICE_TYPE(AMS40489, ams40489_device, "ams40489", "AMS40489 ASIC (CRTC)")
74 DEFINE_DEVICE_TYPE(MOS8563,  mos8563_device,  "mos8563",  "MOS 8563 VDC")
75 DEFINE_DEVICE_TYPE(MOS8568,  mos8568_device,  "mos8568",  "MOS 8568 VDC")
76 
77 
78 /* mode macros */
79 #define MODE_TRANSPARENT            ((m_mode_control & 0x08) != 0)
80 #define MODE_TRANSPARENT_PHI2       ((m_mode_control & 0x88) == 0x88)
81 /* FIXME: not supported yet */
82 #define MODE_TRANSPARENT_BLANK      ((m_mode_control & 0x88) == 0x08)
83 #define MODE_UPDATE_STROBE          ((m_mode_control & 0x40) != 0)
84 #define MODE_CURSOR_SKEW            ((m_mode_control & 0x20) != 0)
85 #define MODE_DISPLAY_ENABLE_SKEW    ((m_mode_control & 0x10) != 0)
86 #define MODE_ROW_COLUMN_ADDRESSING  ((m_mode_control & 0x04) != 0)
87 #define MODE_INTERLACE_AND_VIDEO    ((m_mode_control & 0x03) == 3)
88 
89 #define VSS_CBRATE                  BIT(m_vert_scroll, 5)
90 #define VSS_RVS                     BIT(m_vert_scroll, 6)
91 #define VSS_COPY                    BIT(m_vert_scroll, 7)
92 
93 #define HSS_DBL                     BIT(m_horiz_scroll, 4)
94 #define HSS_SEMI                    BIT(m_horiz_scroll, 5)
95 #define HSS_ATTR                    BIT(m_horiz_scroll, 6)
96 #define HSS_TEXT                    BIT(m_horiz_scroll, 7)
97 
98 #define ATTR_COLOR                  (attr & 0x0f)
99 #define ATTR_BACKGROUND             (attr & 0x0f)
100 #define ATTR_FOREGROUND             (attr >> 4)
101 #define ATTR_BLINK                  BIT(attr, 4)
102 #define ATTR_UNDERLINE              BIT(attr, 5)
103 #define ATTR_REVERSE                BIT(attr, 6)
104 #define ATTR_ALTERNATE_CHARSET      BIT(attr, 7)
105 
106 
mc6845_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)107 mc6845_device::mc6845_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
108 	: device_t(mconfig, type, tag, owner, clock)
109 	, device_video_interface(mconfig, *this, false)
110 	, m_show_border_area(true)
111 	, m_noninterlace_adjust(0)
112 	, m_interlace_adjust(0)
113 	, m_clk_scale(1)
114 	, m_visarea_adjust_min_x(0)
115 	, m_visarea_adjust_max_x(0)
116 	, m_visarea_adjust_min_y(0)
117 	, m_visarea_adjust_max_y(0)
118 	, m_hpixels_per_column(0)
119 	, m_reconfigure_cb(*this)
120 	, m_begin_update_cb(*this)
121 	, m_update_row_cb(*this)
122 	, m_end_update_cb(*this)
123 	, m_on_update_addr_changed_cb(*this)
124 	, m_out_de_cb(*this)
125 	, m_out_cur_cb(*this)
126 	, m_out_hsync_cb(*this)
127 	, m_out_vsync_cb(*this)
128 {
129 }
130 
mc6845_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)131 mc6845_device::mc6845_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
132 	: mc6845_device(mconfig, MC6845, tag, owner, clock)
133 {
134 }
135 
136 
device_post_load()137 void mc6845_device::device_post_load()
138 {
139 	recompute_parameters(true);
140 }
141 
142 
device_clock_changed()143 void mc6845_device::device_clock_changed()
144 {
145 	recompute_parameters(true);
146 }
147 
148 
call_on_update_address(int strobe)149 void mc6845_device::call_on_update_address(int strobe)
150 {
151 	if (!m_on_update_addr_changed_cb.isnull())
152 		m_upd_trans_timer->adjust(attotime::zero, (m_update_addr << 8) | strobe);
153 	else
154 		fatalerror("M6845: transparent memory mode without handler\n");
155 }
156 
157 
address_w(uint8_t data)158 void mc6845_device::address_w(uint8_t data)
159 {
160 	m_register_address_latch = data & 0x1f;
161 }
162 
163 
status_r()164 uint8_t mc6845_device::status_r()
165 {
166 	uint8_t ret = 0;
167 
168 	/* VBLANK bit */
169 	if (m_supports_status_reg_d5 && !m_line_enable_ff)
170 		ret = ret | 0x20;
171 
172 	/* light pen latched */
173 	if (m_supports_status_reg_d6 && m_light_pen_latched)
174 		ret = ret | 0x40;
175 
176 	/* UPDATE ready */
177 	if (m_supports_status_reg_d7 && m_update_ready_bit)
178 		ret = ret | 0x80;
179 
180 	return ret;
181 }
182 
183 
transparent_update()184 void mc6845_device::transparent_update()
185 {
186 	if (m_supports_transparent && MODE_TRANSPARENT)
187 	{
188 		if (MODE_TRANSPARENT_PHI2)
189 		{
190 			m_update_addr++;
191 			m_update_addr &= 0x3fff;
192 			call_on_update_address(MODE_UPDATE_STROBE);
193 		}
194 		else
195 		{
196 			/* MODE_TRANSPARENT_BLANK */
197 			if (m_update_ready_bit)
198 			{
199 				m_update_ready_bit = false;
200 				update_upd_adr_timer();
201 			}
202 		}
203 	}
204 }
205 
206 
register_r()207 uint8_t mc6845_device::register_r()
208 {
209 	uint8_t ret = 0;
210 
211 	switch (m_register_address_latch)
212 	{
213 		case 0x0c:  ret = m_supports_disp_start_addr_r ? (m_disp_start_addr >> 8) & 0xff : 0; break;
214 		case 0x0d:  ret = m_supports_disp_start_addr_r ? (m_disp_start_addr >> 0) & 0xff : 0; break;
215 		case 0x0e:  ret = (m_cursor_addr    >> 8) & 0xff; break;
216 		case 0x0f:  ret = (m_cursor_addr    >> 0) & 0xff; break;
217 		// FIXME: status flag should not be reset if LPEN input is held high
218 		case 0x10:  ret = (m_light_pen_addr >> 8) & 0xff; m_light_pen_latched = false; break;
219 		case 0x11:  ret = (m_light_pen_addr >> 0) & 0xff; m_light_pen_latched = false; break;
220 		case 0x1f:  transparent_update(); break;
221 
222 		/* all other registers are write only and return 0 */
223 		default: break;
224 	}
225 
226 	return ret;
227 }
228 
229 
register_w(uint8_t data)230 void mc6845_device::register_w(uint8_t data)
231 {
232 	LOGREGS("%s:M6845 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
233 
234 	/* Omits LOGSETUP logs of cursor registers as they tend to be spammy */
235 	if (m_register_address_latch < 0x0e &&
236 		m_register_address_latch != 0x0a &&
237 		m_register_address_latch != 0x0b) LOGSETUP(" * %02x <= %3u [%02x] %s\n", m_register_address_latch,
238 							  data, data, std::array<char const *, 16>
239 		 {{ "R0 - Horizontal Total",       "R1 - Horizontal Displayed",   "R2 - Horizontal Sync Position",
240 			"R3 - Sync Width",             "R4 - Vertical Total",         "R5 - Vertical Total Adjust",
241 			"R6 - Vertical Displayed",     "R7 - Vertical Sync Position", "R8 - Interlace & Skew",
242 			"R9 - Maximum Raster Address", "R10 - Cursor Start Raster",   "R11 - Cursor End Raster",
243 			"R12 - Start Address (H)",     "R13 - Start Address (L)",     "R14 - Cursor (H)",
244 			"R15 - Cursor (L)" }}[(m_register_address_latch & 0x0f)]);
245 
246 	switch (m_register_address_latch)
247 	{
248 		case 0x00:  m_horiz_char_total =   data & 0xff; break;
249 		case 0x01:  m_horiz_disp       =   data & 0xff; break;
250 		case 0x02:  m_horiz_sync_pos   =   data & 0xff; break;
251 		case 0x03:  m_sync_width       =   data & 0xff; break;
252 		case 0x04:  m_vert_char_total  =   data & 0x7f; break;
253 		case 0x05:  m_vert_total_adj   =   data & 0x1f; break;
254 		case 0x06:  m_vert_disp        =   data & 0x7f; break;
255 		case 0x07:  m_vert_sync_pos    =   data & 0x7f; break;
256 		case 0x08:  m_mode_control     =   data & 0xff; break;
257 		case 0x09:  m_max_ras_addr     =   data & 0x1f; break;
258 		case 0x0a:  m_cursor_start_ras =   data & 0x7f; break;
259 		case 0x0b:  m_cursor_end_ras   =   data & 0x1f; break;
260 		case 0x0c:  m_disp_start_addr  = ((data & 0x3f) << 8) | (m_disp_start_addr & 0x00ff); break;
261 		case 0x0d:  m_disp_start_addr  = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break;
262 		case 0x0e:  m_cursor_addr      = ((data & 0x3f) << 8) | (m_cursor_addr & 0x00ff); break;
263 		case 0x0f:  m_cursor_addr      = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break;
264 		case 0x10: /* read-only */ break;
265 		case 0x11: /* read-only */ break;
266 		case 0x12:
267 			if (m_supports_transparent)
268 			{
269 				m_update_addr = ((data & 0x3f) << 8) | (m_update_addr & 0x00ff);
270 				if(MODE_TRANSPARENT_PHI2)
271 					call_on_update_address(MODE_UPDATE_STROBE);
272 			}
273 			break;
274 		case 0x13:
275 			if (m_supports_transparent)
276 			{
277 				m_update_addr = ((data & 0xff) << 0) | (m_update_addr & 0xff00);
278 				if(MODE_TRANSPARENT_PHI2)
279 					call_on_update_address(MODE_UPDATE_STROBE);
280 			}
281 			break;
282 		case 0x1f:  transparent_update(); break;
283 		default: break;
284 	}
285 
286 	/* display message if the Mode Control register is not zero */
287 	if ((m_register_address_latch == 0x08) && (m_mode_control != 0))
288 		if (!m_supports_transparent)
289 			logerror("M6845: Mode Control %02X is not supported!!!\n", m_mode_control);
290 
291 	recompute_parameters(false);
292 }
293 
294 
address_w(uint8_t data)295 void mos8563_device::address_w(uint8_t data)
296 {
297 	m_register_address_latch = data & 0x3f;
298 }
299 
300 
status_r()301 uint8_t mos8563_device::status_r()
302 {
303 	uint8_t ret = m_revision;
304 
305 	/* VBLANK bit */
306 	if (!m_line_enable_ff)
307 		ret = ret | 0x20;
308 
309 	/* light pen latched */
310 	if (m_light_pen_latched)
311 		ret = ret | 0x40;
312 
313 	/* UPDATE ready */
314 	if (m_update_ready_bit)
315 		ret = ret | 0x80;
316 
317 	return ret;
318 }
319 
320 
register_r()321 uint8_t mos8563_device::register_r()
322 {
323 	uint8_t ret = 0xff;
324 
325 	switch (m_register_address_latch)
326 	{
327 		case 0x00:  ret = m_horiz_char_total; break;
328 		case 0x01:  ret = m_horiz_disp; break;
329 		case 0x02:  ret = m_horiz_sync_pos; break;
330 		case 0x03:  ret = m_sync_width; break;
331 		case 0x04:  ret = m_vert_char_total; break;
332 		case 0x05:  ret = m_vert_total_adj | 0xc0; break;
333 		case 0x06:  ret = m_vert_disp; break;
334 		case 0x07:  ret = m_vert_sync_pos; break;
335 		case 0x08:  ret = m_mode_control | 0xfc; break;
336 		case 0x09:  ret = m_max_ras_addr | 0xe0; break;
337 		case 0x0a:  ret = m_cursor_start_ras | 0x80; break;
338 		case 0x0b:  ret = m_cursor_end_ras | 0xe0; break;
339 		case 0x0c:  ret = (m_disp_start_addr >> 8) & 0xff; break;
340 		case 0x0d:  ret = (m_disp_start_addr >> 0) & 0xff; break;
341 		case 0x0e:  ret = (m_cursor_addr     >> 8) & 0xff; break;
342 		case 0x0f:  ret = (m_cursor_addr     >> 0) & 0xff; break;
343 		case 0x10:  ret = (m_light_pen_addr  >> 8) & 0xff; m_light_pen_latched = false; break;
344 		case 0x11:  ret = (m_light_pen_addr  >> 0) & 0xff; m_light_pen_latched = false; break;
345 		case 0x12:  ret = (m_update_addr     >> 8) & 0xff; break;
346 		case 0x13:  ret = (m_update_addr     >> 0) & 0xff; break;
347 		case 0x14:  ret = (m_attribute_addr  >> 8) & 0xff; break;
348 		case 0x15:  ret = (m_attribute_addr  >> 0) & 0xff; break;
349 		case 0x16:  ret = m_horiz_char; break;
350 		case 0x17:  ret = m_vert_char_disp | 0xe0; break;
351 		case 0x18:  ret = m_vert_scroll; break;
352 		case 0x19:  ret = m_horiz_scroll; break;
353 		case 0x1a:  ret = m_color; break;
354 		case 0x1b:  ret = m_row_addr_incr; break;
355 		case 0x1c:  ret = m_char_base_addr | 0x1f; break;
356 		case 0x1d:  ret = m_underline_ras | 0xe0; break;
357 		case 0x1e:  ret = m_word_count; break;
358 		case 0x1f:  ret = read_videoram(m_update_addr++); break;
359 		case 0x20:  ret = (m_block_addr      >> 8) & 0xff; break;
360 		case 0x21:  ret = (m_block_addr      >> 0) & 0xff; break;
361 		case 0x22:  ret = (m_de_begin        >> 8) & 0xff; break;
362 		case 0x23:  ret = (m_de_begin        >> 0) & 0xff; break;
363 		case 0x24:  ret = m_dram_refresh | 0xf0; break;
364 		case 0x25:  ret = m_sync_polarity | 0x3f; break;
365 	}
366 
367 	return ret;
368 }
369 
370 
register_w(uint8_t data)371 void mos8563_device::register_w(uint8_t data)
372 {
373 	LOGREGS("%s:MOS8563 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
374 
375 	switch (m_register_address_latch)
376 	{
377 		case 0x00:  m_horiz_char_total =   data & 0xff; break;
378 		case 0x01:  m_horiz_disp       =   data & 0xff; break;
379 		case 0x02:  m_horiz_sync_pos   =   data & 0xff; break;
380 		case 0x03:  m_sync_width       =   data & 0xff; break;
381 		case 0x04:  m_vert_char_total  =   data & 0xff; break;
382 		case 0x05:  m_vert_total_adj   =   data & 0x1f; break;
383 		case 0x06:  m_vert_disp        =   data & 0xff; break;
384 		case 0x07:  m_vert_sync_pos    =   data & 0xff; break;
385 		case 0x08:  m_mode_control     =   data & 0x03; break;
386 		case 0x09:  m_max_ras_addr     =   data & 0x1f; break;
387 		case 0x0a:  m_cursor_start_ras =   data & 0x7f; break;
388 		case 0x0b:  m_cursor_end_ras   =   data & 0x1f; break;
389 		case 0x0c:  m_disp_start_addr  = ((data & 0xff) << 8) | (m_disp_start_addr & 0x00ff); break;
390 		case 0x0d:  m_disp_start_addr  = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break;
391 		case 0x0e:  m_cursor_addr      = ((data & 0xff) << 8) | (m_cursor_addr & 0x00ff); break;
392 		case 0x0f:  m_cursor_addr      = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break;
393 		case 0x10: /* read-only */ break;
394 		case 0x11: /* read-only */ break;
395 		case 0x12:  m_update_addr      = ((data & 0xff) << 8) | (m_update_addr & 0x00ff); break;
396 		case 0x13:  m_update_addr      = ((data & 0xff) << 0) | (m_update_addr & 0xff00); break;
397 		case 0x14:  m_attribute_addr   = ((data & 0xff) << 8) | (m_attribute_addr & 0x00ff); break;
398 		case 0x15:  m_attribute_addr   = ((data & 0xff) << 0) | (m_attribute_addr & 0xff00); break;
399 		case 0x16:  m_horiz_char       =   data & 0xff; break;
400 		case 0x17:  m_vert_char_disp   =   data & 0x1f; break;
401 		case 0x18:  m_vert_scroll      =   data & 0xff; break;
402 		case 0x19:
403 			{
404 			int dbl = HSS_DBL;
405 			m_horiz_scroll = data & 0xff;
406 			if (dbl && !HSS_DBL) { m_clk_scale = 4; recompute_parameters(true); }
407 			if (!dbl && HSS_DBL) { m_clk_scale = 8; recompute_parameters(true); }
408 			break;
409 			}
410 		case 0x1a:  m_color            =   data & 0xff; break;
411 		case 0x1b:  m_row_addr_incr    =   data & 0xff; break;
412 		case 0x1c:  m_char_base_addr   =   data & 0xe0; break;
413 		case 0x1d:  m_underline_ras    =   data & 0x1f; break;
414 		case 0x1e:
415 			m_word_count = data & 0xff;
416 			m_update_ready_bit = 0;
417 			m_block_copy_timer->adjust(cclks_to_attotime(1));
418 			break;
419 		case 0x1f:
420 			m_data = data & 0xff;
421 			write_videoram(m_update_addr++, m_data);
422 			break;
423 		case 0x20:  m_block_addr       = ((data & 0xff) << 8) | (m_block_addr & 0x00ff); break;
424 		case 0x21:  m_block_addr       = ((data & 0xff) << 0) | (m_block_addr & 0xff00); break;
425 		case 0x22:  m_de_begin         = ((data & 0xff) << 8) | (m_de_begin & 0x00ff); break;
426 		case 0x23:  m_de_begin         = ((data & 0xff) << 0) | (m_de_begin & 0xff00); break;
427 		case 0x24:  m_dram_refresh     =   data & 0x0f; break;
428 		case 0x25:  m_sync_polarity    =   data & 0xc0; break;
429 	}
430 
431 	recompute_parameters(false);
432 }
433 
address_w(uint8_t data)434 void hd6345_device::address_w(uint8_t data)
435 {
436 	m_register_address_latch = data & 0x3f;
437 }
438 
439 
register_r()440 uint8_t hd6345_device::register_r()
441 {
442 	uint8_t ret = 0;
443 
444 	switch (m_register_address_latch)
445 	{
446 		case 0x0c:  ret = (m_disp_start_addr  >> 8) & 0xff; break;
447 		case 0x0d:  ret = (m_disp_start_addr  >> 0) & 0xff; break;
448 		case 0x0e:  ret = (m_cursor_addr      >> 8) & 0xff; break;
449 		case 0x0f:  ret = (m_cursor_addr      >> 0) & 0xff; break;
450 		case 0x10:  ret = (m_light_pen_addr   >> 8) & 0xff; m_light_pen_latched = false; break;
451 		case 0x11:  ret = (m_light_pen_addr   >> 0) & 0xff; m_light_pen_latched = false; break;
452 		case 0x12:  ret = m_disp2_pos; break;
453 		case 0x13:  ret = (m_disp2_start_addr >> 8) & 0xff; break;
454 		case 0x14:  ret = (m_disp2_start_addr >> 0) & 0xff; break;
455 		case 0x15:  ret = m_disp3_pos; break;
456 		case 0x16:  ret = (m_disp3_start_addr >> 8) & 0xff; break;
457 		case 0x17:  ret = (m_disp3_start_addr >> 0) & 0xff; break;
458 		case 0x18:  ret = m_disp4_pos; break;
459 		case 0x19:  ret = (m_disp4_start_addr >> 8) & 0xff; break;
460 		case 0x1a:  ret = (m_disp4_start_addr >> 0) & 0xff; break;
461 		case 0x1b:  ret = m_vert_sync_pos_adj; break;
462 		case 0x1c: /* TODO: light pen raster */ break;
463 		case 0x1d:  ret = m_smooth_scroll_ras; break;
464 		case 0x1f: /* TODO: status */ break;
465 		case 0x21:  ret = m_mem_width_offs; break;
466 		case 0x24:  ret = (m_cursor2_addr     >> 8) & 0xff; break;
467 		case 0x25:  ret = (m_cursor2_addr     >> 0) & 0xff; break;
468 		case 0x26:  ret = m_cursor_width; break;
469 		case 0x27:  ret = m_cursor2_width; break;
470 	}
471 
472 	return ret;
473 }
474 
register_w(uint8_t data)475 void hd6345_device::register_w(uint8_t data)
476 {
477 	LOGREGS("%s:HD6345 reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
478 
479 	/* Omits LOGSETUP logs of cursor registers as they tend to be spammy */
480 	if (m_register_address_latch < 0x28 &&
481 		m_register_address_latch != 0x0a && m_register_address_latch != 0x0a &&
482 		m_register_address_latch != 0x0e && m_register_address_latch != 0x0f)
483 		LOGSETUP(" * %02x <= %3u [%02x] %s\n", m_register_address_latch, data, data, std::array<char const *, 40>
484 		 {{ "R0 - Horizontal Total",            "R1 - Horizontal Displayed",        "R2 - Horizontal Sync Position",
485 			"R3 - Sync Width",                  "R4 - Vertical Total",              "R5 - Vertical Total Adjust",
486 			"R6 - Vertical Displayed",          "R7 - Vertical Sync Position",      "R8 - Interlace Mode & Skew",
487 			"R9 - Maximum Raster Address",      "R10 - Cursor 1 Start",             "R11 - Cursor 1 End",
488 			"R12 - Screen 1 Start Address (H)", "R13 - Screen 1 Start Address (L)", "R14 - Cursor 1 Address (H)",
489 			"R15 - Cursor 1 Address (L)",       "R16 - Light Pen (H)",              "R17 - Light Pen (L)",
490 			"R18 - Screen 2 Start Position",    "R19 - Screen 2 Start Address (H)", "R20 - Screen 2 Start Address (L)",
491 			"R21 - Screen 3 Start Position",    "R22 - Screen 3 Start Address (H)", "R23 - Screen 3 Start Address (L)",
492 			"R24 - Screen 4 Start Position",    "R25 - Screen 4 Start Address (H)", "R26 - Screen 4 Start Address (L)",
493 			"R27 - Vertical Sync Position Adj", "R28 - Light Pen Raster",           "R29 - Smooth Scrolling",
494 			"R30 - Control 1",                  "R31 - Control 2",                  "R32 - Control 3",
495 			"R33 - Memory Width Offset",        "R34 - Cursor 2 Start",             "R35 - Cursor 2 End",
496 			"R36 - Cursor 2 Address (H)",       "R37 - Cursor 2 Address (L)",       "R38 - Cursor 1 Width",
497 			"R39 - Cursor 2 Width" }}[(m_register_address_latch & 0x3f)]);
498 
499 	switch (m_register_address_latch)
500 	{
501 		case 0x00:  m_horiz_char_total =   data & 0xff; break;
502 		case 0x01:  m_horiz_disp       =   data & 0xff; break;
503 		case 0x02:  m_horiz_sync_pos   =   data & 0xff; break;
504 		case 0x03:  m_sync_width       =   data & 0xff; break;
505 		case 0x04:  m_vert_char_total  =   data & 0xff; break;
506 		case 0x05:  m_vert_total_adj   =   data & 0x1f; break;
507 		case 0x06:  m_vert_disp        =   data & 0xff; break;
508 		case 0x07:  m_vert_sync_pos    =   data & 0xff; break;
509 		case 0x08:  m_mode_control     =   data & 0xf3; break;
510 		case 0x09:  m_max_ras_addr     =   data & 0x1f; break;
511 		case 0x0a:  m_cursor_start_ras =   data & 0x7f; break;
512 		case 0x0b:  m_cursor_end_ras   =   data & 0x1f; break;
513 		case 0x0c:  m_disp_start_addr  = ((data & 0x3f) << 8) | (m_disp_start_addr & 0x00ff); break;
514 		case 0x0d:  m_disp_start_addr  = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break;
515 		case 0x0e:  m_cursor_addr      = ((data & 0x3f) << 8) | (m_cursor_addr & 0x00ff); break;
516 		case 0x0f:  m_cursor_addr      = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break;
517 		case 0x10: /* read-only */ break;
518 		case 0x11: /* read-only */ break;
519 		case 0x12:  m_disp2_pos         =   data & 0xff; break;
520 		case 0x13:  m_disp2_start_addr  = ((data & 0x3f) << 8) | (m_disp2_start_addr & 0x00ff); break;
521 		case 0x14:  m_disp2_start_addr  = ((data & 0xff) << 0) | (m_disp2_start_addr & 0xff00); break;
522 		case 0x15:  m_disp3_pos         =   data & 0xff; break;
523 		case 0x16:  m_disp3_start_addr  = ((data & 0x3f) << 8) | (m_disp3_start_addr & 0x00ff); break;
524 		case 0x17:  m_disp3_start_addr  = ((data & 0xff) << 0) | (m_disp3_start_addr & 0xff00); break;
525 		case 0x18:  m_disp4_pos         =   data & 0xff; break;
526 		case 0x19:  m_disp4_start_addr  = ((data & 0x3f) << 8) | (m_disp4_start_addr & 0x00ff); break;
527 		case 0x1a:  m_disp4_start_addr  = ((data & 0xff) << 0) | (m_disp4_start_addr & 0xff00); break;
528 		case 0x1b:  m_vert_sync_pos_adj =   data & 0x1f; break;
529 		case 0x1c: /* read-only */ break;
530 		case 0x1d:  m_smooth_scroll_ras =   data & 0x1f; break;
531 		case 0x1e:  m_control1          =   data & 0xff; break;
532 		case 0x1f:  m_control2          =   data & 0xf8; break;
533 		case 0x20:  m_control3          =   data & 0xfe; break;
534 		case 0x21:  m_mem_width_offs    =   data & 0xff; break;
535 		case 0x22:  m_cursor2_start_ras =   data & 0x7f; break;
536 		case 0x23:  m_cursor2_end_ras   =   data & 0x1f; break;
537 		case 0x24:  m_cursor2_addr      = ((data & 0x3f) << 8) | (m_cursor2_addr & 0x00ff); break;
538 		case 0x25:  m_cursor2_addr      = ((data & 0xff) << 0) | (m_cursor2_addr & 0xff00); break;
539 		case 0x26:  m_cursor_width      =   data & 0xff; break;
540 		case 0x27:  m_cursor2_width     =   data & 0xff; break;
541 	}
542 
543 	recompute_parameters(false);
544 }
545 
546 
read_videoram(offs_t offset)547 inline uint8_t mos8563_device::read_videoram(offs_t offset)
548 {
549 	return space(0).read_byte(offset);
550 }
551 
write_videoram(offs_t offset,uint8_t data)552 inline void mos8563_device::write_videoram(offs_t offset, uint8_t data)
553 {
554 	space(0).write_byte(offset, data);
555 }
556 
557 
READ_LINE_MEMBER(mc6845_device::de_r)558 READ_LINE_MEMBER( mc6845_device::de_r )
559 {
560 	return m_de;
561 }
562 
563 
READ_LINE_MEMBER(mc6845_device::cursor_r)564 READ_LINE_MEMBER( mc6845_device::cursor_r )
565 {
566 	return m_cur;
567 }
568 
569 
READ_LINE_MEMBER(mc6845_device::hsync_r)570 READ_LINE_MEMBER( mc6845_device::hsync_r )
571 {
572 	return m_hsync;
573 }
574 
575 
READ_LINE_MEMBER(mc6845_device::vsync_r)576 READ_LINE_MEMBER( mc6845_device::vsync_r )
577 {
578 	return m_vsync;
579 }
580 
581 
recompute_parameters(bool postload)582 void mc6845_device::recompute_parameters(bool postload)
583 {
584 	uint16_t hsync_on_pos, hsync_off_pos, vsync_on_pos, vsync_off_pos;
585 
586 	uint16_t video_char_height = m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust);   // fix garbage at the bottom of the screen (eg victor9k)
587 	// Would be useful for 'interlace and video' mode support...
588 	// uint16_t frame_char_height = (MODE_INTERLACE_AND_VIDEO ? m_max_ras_addr / 2 : m_max_ras_addr) + 1;
589 
590 	/* compute the screen sizes */
591 	uint16_t horiz_pix_total = (m_horiz_char_total + 1) * m_hpixels_per_column;
592 	uint16_t vert_pix_total = (m_vert_char_total + 1) * video_char_height + m_vert_total_adj;
593 
594 	/* determine the visible area, avoid division by 0 */
595 	uint16_t max_visible_x = m_horiz_disp * m_hpixels_per_column - 1;
596 	uint16_t max_visible_y = m_vert_disp * video_char_height - 1;
597 
598 	/* determine the syncing positions */
599 	uint8_t horiz_sync_char_width = m_sync_width & 0x0f;
600 	uint8_t vert_sync_pix_width = m_supports_vert_sync_width ? (m_sync_width >> 4) & 0x0f : 0x10;
601 
602 	if (horiz_sync_char_width == 0)
603 		horiz_sync_char_width = 0x10;
604 
605 	if (vert_sync_pix_width == 0)
606 		vert_sync_pix_width = 0x10;
607 
608 	/* determine the transparent update cycle time, 1 update every 4 character clocks */
609 	m_upd_time = cclks_to_attotime(4 * m_hpixels_per_column);
610 
611 	hsync_on_pos = m_horiz_sync_pos * m_hpixels_per_column;
612 	hsync_off_pos = hsync_on_pos + (horiz_sync_char_width * m_hpixels_per_column);
613 	vsync_on_pos = m_vert_sync_pos * video_char_height;
614 	vsync_off_pos = vsync_on_pos + vert_sync_pix_width;
615 
616 	// the Commodore PET computers have a non-standard 20kHz monitor which
617 	// requires a wider HSYNC pulse that extends past the scanline width
618 	if (hsync_off_pos > horiz_pix_total)
619 		hsync_off_pos = horiz_pix_total;
620 
621 	if (vsync_on_pos > vert_pix_total)
622 		vsync_on_pos = vert_pix_total;
623 
624 	if (vsync_off_pos > vert_pix_total)
625 		vsync_off_pos = vert_pix_total;
626 
627 	/* update only if screen parameters changed, unless we are coming here after loading the saved state */
628 	if (postload ||
629 		(horiz_pix_total != m_horiz_pix_total) || (vert_pix_total != m_vert_pix_total) ||
630 		(max_visible_x != m_max_visible_x) || (max_visible_y != m_max_visible_y) ||
631 		(hsync_on_pos != m_hsync_on_pos) || (vsync_on_pos != m_vsync_on_pos) ||
632 		(hsync_off_pos != m_hsync_off_pos) || (vsync_off_pos != m_vsync_off_pos))
633 	{
634 		/* update the screen if we have valid data */
635 		if ((horiz_pix_total > 0) && (max_visible_x < horiz_pix_total) &&
636 			(vert_pix_total > 0) && (max_visible_y < vert_pix_total) &&
637 			(hsync_on_pos <= horiz_pix_total) && (vsync_on_pos <= vert_pix_total) &&
638 			(hsync_on_pos != hsync_off_pos))
639 		{
640 			rectangle visarea;
641 
642 			attotime refresh = cclks_to_attotime((m_horiz_char_total + 1) * vert_pix_total);
643 
644 			// This doubles the vertical resolution, required for 'interlace and video' mode support.
645 			// Tested and works for super80v, which was designed with this in mind (choose green or monochrome colour in config switches).
646 			// However it breaks some other drivers (apricot,a6809,victor9k,bbc(mode7)).
647 			// So, it is commented out for now.
648 			// Also, the mode-register change needs to be added to the changed-parameter tests above.
649 			if (MODE_INTERLACE_AND_VIDEO)
650 			{
651 				//max_visible_y *= 2;
652 				//vert_pix_total *= 2;
653 			}
654 
655 			if(m_show_border_area)
656 				visarea.set(0, horiz_pix_total-2, 0, vert_pix_total-2);
657 			else
658 				visarea.set(0 + m_visarea_adjust_min_x, max_visible_x + m_visarea_adjust_max_x, 0 + m_visarea_adjust_min_y, max_visible_y + m_visarea_adjust_max_y);
659 
660 			LOGCONF("M6845 config screen: HTOTAL: %d  VTOTAL: %d  MAX_X: %d  MAX_Y: %d  HSYNC: %d-%d  VSYNC: %d-%d  Freq: %ffps\n",
661 				 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, refresh.as_hz());
662 
663 			if (has_screen())
664 				screen().configure(horiz_pix_total, vert_pix_total, visarea, refresh.as_attoseconds());
665 
666 			if(!m_reconfigure_cb.isnull())
667 				m_reconfigure_cb(horiz_pix_total, vert_pix_total, visarea, refresh.as_attoseconds());
668 
669 			m_has_valid_parameters = true;
670 		}
671 		else
672 			m_has_valid_parameters = false;
673 
674 		m_horiz_pix_total = horiz_pix_total;
675 		m_vert_pix_total = vert_pix_total;
676 		m_max_visible_x = max_visible_x;
677 		m_max_visible_y = max_visible_y;
678 		m_hsync_on_pos = hsync_on_pos;
679 		m_hsync_off_pos = hsync_off_pos;
680 		m_vsync_on_pos = vsync_on_pos;
681 		m_vsync_off_pos = vsync_off_pos;
682 		if ( (!m_reconfigure_cb.isnull()) && (!postload) )
683 			m_line_counter = 0;
684 	}
685 }
686 
687 
update_counters()688 void mc6845_device::update_counters()
689 {
690 	m_character_counter = attotime_to_cclks(m_line_timer->elapsed());
691 
692 	if (m_hsync_off_timer->enabled())
693 	{
694 		m_hsync_width_counter = attotime_to_cclks(m_hsync_off_timer->elapsed());
695 	}
696 }
697 
698 
set_de(int state)699 void mc6845_device::set_de(int state)
700 {
701 	if (m_de != state)
702 	{
703 		m_de = state;
704 
705 		if (m_de)
706 		{
707 			/* If the upd_adr_timer was running, cancel it */
708 			m_upd_adr_timer->adjust(attotime::never);
709 		}
710 		else
711 		{
712 			/* if transparent update was requested fire the update timer */
713 			if(!m_update_ready_bit)
714 				update_upd_adr_timer();
715 		}
716 
717 		m_out_de_cb(m_de);
718 	}
719 }
720 
721 
set_hsync(int state)722 void mc6845_device::set_hsync(int state)
723 {
724 	if (m_hsync != state)
725 	{
726 		m_hsync = state;
727 		m_out_hsync_cb(m_hsync);
728 	}
729 }
730 
731 
set_vsync(int state)732 void mc6845_device::set_vsync(int state)
733 {
734 	if (m_vsync != state)
735 	{
736 		m_vsync = state;
737 		m_out_vsync_cb(m_vsync);
738 	}
739 }
740 
741 
set_cur(int state)742 void mc6845_device::set_cur(int state)
743 {
744 	if (m_cur != state)
745 	{
746 		m_cur = state;
747 		m_out_cur_cb(m_cur);
748 	}
749 }
750 
751 
update_upd_adr_timer()752 void mc6845_device::update_upd_adr_timer()
753 {
754 	if (! m_de && m_supports_transparent)
755 		m_upd_adr_timer->adjust(m_upd_time);
756 }
757 
758 
match_line()759 bool mc6845_device::match_line()
760 {
761 	/* Check if we've reached the end of active display */
762 	if ( m_line_counter == m_vert_disp )
763 	{
764 		m_line_enable_ff = false;
765 		m_current_disp_addr = m_disp_start_addr;
766 	}
767 
768 	/* Check if VSYNC should be enabled */
769 	if ( m_line_counter == m_vert_sync_pos )
770 	{
771 		m_vsync_width_counter = 0;
772 		m_vsync_ff = 1;
773 
774 		return true;
775 	}
776 
777 	return false;
778 }
779 
780 
check_cursor_visible(uint16_t ra,uint16_t line_addr)781 bool mc6845_device::check_cursor_visible(uint16_t ra, uint16_t line_addr)
782 {
783 	if (!m_cursor_state)
784 		return false;
785 
786 	if ((m_cursor_addr < line_addr) ||
787 		(m_cursor_addr >= (line_addr + m_horiz_disp)))
788 	{
789 		// Not a cursor character line.
790 		return false;
791 	}
792 
793 	uint16_t cursor_start_ras = m_cursor_start_ras & 0x1f;
794 	uint16_t max_ras_addr = m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust) - 1;
795 
796 	if (cursor_start_ras > max_ras_addr)
797 	{
798 		// No cursor.
799 		return false;
800 	}
801 
802 	// TODO explore the edge cases in the 'interlace and video' mode.
803 
804 	if (cursor_start_ras <= m_cursor_end_ras)
805 	{
806 		if (m_cursor_end_ras > max_ras_addr)
807 		{
808 			// Wraps to produce a full cursor.
809 			return true;
810 		}
811 		// Cursor from start to end inclusive.
812 		return (ra >= cursor_start_ras) && (ra <= m_cursor_end_ras);
813 	}
814 
815 	// Otherwise cursor_start_ras > m_cursor_end_ras giving a split cursor.
816 	return (ra <= m_cursor_end_ras) || (ra >= cursor_start_ras);
817 }
818 
819 // The HD6845 cursor does not wrap as it does for the MC6845.
check_cursor_visible(uint16_t ra,uint16_t line_addr)820 bool hd6845s_device::check_cursor_visible(uint16_t ra, uint16_t line_addr)
821 {
822 	if (!m_cursor_state)
823 		return false;
824 
825 	if ((m_cursor_addr < line_addr) ||
826 		(m_cursor_addr >= (line_addr + m_horiz_disp)))
827 	{
828 		// Not a cursor character line.
829 		return false;
830 	}
831 
832 	uint16_t cursor_start_ras = m_cursor_start_ras & 0x1f;
833 	uint16_t max_ras_addr = m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust) - 1;
834 
835 	if (cursor_start_ras > max_ras_addr || cursor_start_ras > m_cursor_end_ras)
836 	{
837 		// No cursor.
838 		return false;
839 	}
840 
841 	// Cursor from start to end inclusive.
842 	return (ra >= cursor_start_ras) && (ra <= m_cursor_end_ras);
843 }
844 
845 
handle_line_timer()846 void mc6845_device::handle_line_timer()
847 {
848 	bool new_vsync = m_vsync;
849 
850 	m_character_counter = 0;
851 	m_cursor_x = -1;
852 
853 	/* Check if VSYNC is active */
854 	if ( m_vsync_ff )
855 	{
856 		uint8_t vsync_width = m_supports_vert_sync_width ? (m_sync_width >> 4) & 0x0f : 0;
857 
858 		m_vsync_width_counter = ( m_vsync_width_counter + 1 ) & 0x0F;
859 
860 		/* Check if we've reached end of VSYNC */
861 		if ( m_vsync_width_counter == vsync_width )
862 		{
863 			m_vsync_ff = 0;
864 
865 			new_vsync = false;
866 		}
867 	}
868 
869 	// For rudimentary 'interlace and video' support, m_raster_counter increments by 1 rather than the correct 2.
870 	// The correct test would be:
871 	// if ( m_raster_counter == (MODE_INTERLACE_AND_VIDEO ? m_max_ras_addr + 1 : m_max_ras_addr) )
872 	if ( m_raster_counter == m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust) - 1 )
873 	{
874 		/* Check if we have reached the end of the vertical area */
875 		if ( m_line_counter == m_vert_char_total )
876 		{
877 			m_adjust_counter = 0;
878 			m_adjust_active = 1;
879 		}
880 
881 		m_raster_counter = 0;
882 		m_line_counter = ( m_line_counter + 1 ) & 0x7F;
883 		m_line_address = ( m_line_address + m_horiz_disp ) & 0x3fff;
884 
885 		if (match_line())
886 			new_vsync = true;
887 	}
888 	else
889 	{
890 		// For rudimentary 'interlace and video' support, m_raster_counter increments by 1 rather than the correct 2.
891 		// m_raster_counter = ( m_raster_counter + (MODE_INTERLACE_AND_VIDEO ? 2 : 1) ) & 0x1F;
892 		m_raster_counter = ( m_raster_counter + 1 ) & 0x1F;
893 	}
894 
895 	if ( m_adjust_active )
896 	{
897 		/* Check if we have reached the end of a full cycle */
898 		if ( m_adjust_counter == m_vert_total_adj )
899 		{
900 			m_adjust_active = 0;
901 			m_raster_counter = 0;
902 			m_line_counter = 0;
903 			m_line_address = m_disp_start_addr;
904 			m_line_enable_ff = true;
905 
906 			if (m_supports_vert_sync_width)
907 			{
908 				if (match_line())
909 					new_vsync = true;
910 			}
911 
912 			/* also update the cursor state now */
913 			update_cursor_state();
914 
915 			if (has_screen())
916 				screen().reset_origin();
917 		}
918 		else
919 		{
920 			m_adjust_counter = ( m_adjust_counter + 1 ) & 0x1F;
921 		}
922 	}
923 
924 	if ( m_line_enable_ff )
925 	{
926 		/* Schedule DE off signal change */
927 		m_de_off_timer->adjust(cclks_to_attotime(m_horiz_disp));
928 
929 		/* Is cursor visible on this line? */
930 		if (check_cursor_visible(m_raster_counter, m_line_address))
931 		{
932 			m_cursor_x = m_cursor_addr - m_line_address;
933 
934 			/* Schedule CURSOR ON signal */
935 			m_cur_on_timer->adjust(cclks_to_attotime(m_cursor_x));
936 		}
937 	}
938 
939 	/* Schedule HSYNC on signal */
940 	m_hsync_on_timer->adjust(cclks_to_attotime(m_horiz_sync_pos));
941 
942 	/* Schedule our next callback */
943 	m_line_timer->adjust(cclks_to_attotime(m_horiz_char_total + 1));
944 
945 	/* Set VSYNC and DE signals */
946 	set_vsync( new_vsync );
947 	set_de( m_line_enable_ff ? true : false );
948 }
949 
950 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)951 void mc6845_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
952 {
953 	switch (id)
954 	{
955 	case TIMER_LINE:
956 		handle_line_timer();
957 		break;
958 
959 	case TIMER_DE_OFF:
960 		set_de( false );
961 		break;
962 
963 	case TIMER_CUR_ON:
964 		set_cur( true );
965 
966 		/* Schedule CURSOR off signal */
967 		m_cur_off_timer->adjust(cclks_to_attotime(1));
968 		break;
969 
970 	case TIMER_CUR_OFF:
971 		set_cur( false );
972 		break;
973 
974 	case TIMER_HSYNC_ON:
975 		{
976 			uint8_t hsync_width = ( m_sync_width & 0x0f ) ? ( m_sync_width & 0x0f ) : 0x10;
977 
978 			m_hsync_width_counter = 0;
979 			set_hsync( true );
980 
981 			/* Schedule HSYNC off signal */
982 			m_hsync_off_timer->adjust(cclks_to_attotime(hsync_width));
983 		}
984 		break;
985 
986 	case TIMER_HSYNC_OFF:
987 		set_hsync( false );
988 		break;
989 
990 	case TIMER_LIGHT_PEN_LATCH:
991 		m_light_pen_addr = get_ma();
992 		m_light_pen_latched = true;
993 		break;
994 
995 	case TIMER_UPD_ADR:
996 		/* fire a update address strobe */
997 		call_on_update_address(MODE_UPDATE_STROBE);
998 		break;
999 
1000 	case TIMER_UPD_TRANS:
1001 		{
1002 			int addr = (param >> 8);
1003 			int strobe = (param & 0xff);
1004 
1005 			/* call the callback function -- we know it exists */
1006 			m_on_update_addr_changed_cb(addr, strobe);
1007 
1008 			if(!m_update_ready_bit && MODE_TRANSPARENT_BLANK)
1009 			{
1010 				m_update_addr++;
1011 				m_update_addr &= 0x3fff;
1012 				m_update_ready_bit = true;
1013 			}
1014 		}
1015 		break;
1016 
1017 	}
1018 }
1019 
1020 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)1021 void mos8563_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
1022 {
1023 	switch (id)
1024 	{
1025 	case TIMER_BLOCK_COPY:
1026 	{
1027 		uint8_t data = VSS_COPY ? read_videoram(m_block_addr++) : m_data;
1028 
1029 		write_videoram(m_update_addr++, data);
1030 
1031 		if (--m_word_count)
1032 		{
1033 			m_block_copy_timer->adjust(cclks_to_attotime(1));
1034 		}
1035 		else
1036 		{
1037 			m_update_ready_bit = 1;
1038 		}
1039 		break;
1040 	}
1041 	default:
1042 		mc6845_device::device_timer(timer, id, param, ptr);
1043 		break;
1044 	}
1045 }
1046 
1047 
get_ma()1048 uint16_t mc6845_device::get_ma()
1049 {
1050 	update_counters();
1051 
1052 	return ( m_line_address + m_character_counter ) & 0x3fff;
1053 }
1054 
1055 
get_ra()1056 uint8_t mc6845_device::get_ra()
1057 {
1058 	return m_raster_counter;
1059 }
1060 
1061 
assert_light_pen_input()1062 void mc6845_device::assert_light_pen_input()
1063 {
1064 	/* compute the pixel coordinate of the NEXT character -- this is when the light pen latches */
1065 	/* set the timer that will latch the display address into the light pen registers */
1066 	m_light_pen_latch_timer->adjust(cclks_to_attotime(1));
1067 }
1068 
1069 
set_hpixels_per_column(int hpixels_per_column)1070 void mc6845_device::set_hpixels_per_column(int hpixels_per_column)
1071 {
1072 	/* validate arguments */
1073 	assert(hpixels_per_column > 0);
1074 
1075 	if (hpixels_per_column != m_hpixels_per_column)
1076 	{
1077 		m_hpixels_per_column = hpixels_per_column;
1078 		recompute_parameters(false);
1079 	}
1080 }
1081 
1082 
update_cursor_state()1083 void mc6845_device::update_cursor_state()
1084 {
1085 	/* save and increment cursor counter */
1086 	uint8_t last_cursor_blink_count = m_cursor_blink_count;
1087 	m_cursor_blink_count = m_cursor_blink_count + 1;
1088 
1089 	/* switch on cursor blinking mode */
1090 	switch (m_cursor_start_ras & 0x60)
1091 	{
1092 		/* always on */
1093 		case 0x00: m_cursor_state = true; break;
1094 
1095 		/* always off */
1096 		default:
1097 		case 0x20: m_cursor_state = false; break;
1098 
1099 		/* fast blink */
1100 		case 0x40:
1101 			if ((last_cursor_blink_count & 0x10) != (m_cursor_blink_count & 0x10))
1102 				m_cursor_state = !m_cursor_state;
1103 			break;
1104 
1105 		/* slow blink */
1106 		case 0x60:
1107 			if ((last_cursor_blink_count & 0x20) != (m_cursor_blink_count & 0x20))
1108 				m_cursor_state = !m_cursor_state;
1109 			break;
1110 	}
1111 }
1112 
1113 
draw_scanline(int y,bitmap_rgb32 & bitmap,const rectangle & cliprect)1114 uint8_t mc6845_device::draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1115 {
1116 	/* compute the current raster line */
1117 	uint8_t ra = y % (m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust));
1118 
1119 	// Check if the cursor is visible and is on this scanline.
1120 	int cursor_visible = check_cursor_visible(ra, m_current_disp_addr);
1121 
1122 	// Compute the cursor X position, or -1 if not visible. This position
1123 	// is in units of characters and is relative to the start of the
1124 	// displayable area, not relative to the screen bitmap origin.
1125 	int8_t cursor_x = cursor_visible ? (m_cursor_addr - m_current_disp_addr) : -1;
1126 	int de = (y <= m_max_visible_y) ? 1 : 0;
1127 	int vbp = m_vert_pix_total - m_vsync_off_pos;
1128 	if (vbp < 0) vbp = 0;
1129 	int hbp = m_horiz_pix_total - m_hsync_off_pos;
1130 	if (hbp < 0) hbp = 0;
1131 
1132 	/* call the external system to draw it */
1133 	if (MODE_ROW_COLUMN_ADDRESSING)
1134 	{
1135 		uint8_t cc = 0;
1136 		uint8_t cr = y / (m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust));
1137 		uint16_t ma = (cr << 8) | cc;
1138 
1139 		m_update_row_cb(bitmap, cliprect, ma + m_disp_start_addr, ra, y, m_horiz_disp, cursor_x, de, hbp, vbp);
1140 	}
1141 	else
1142 	{
1143 		m_update_row_cb(bitmap, cliprect, m_current_disp_addr, ra, y, m_horiz_disp, cursor_x, de, hbp, vbp);
1144 	}
1145 
1146 	/* update MA if the last raster address */
1147 	if (ra == m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust) - 1)
1148 		m_current_disp_addr = (m_current_disp_addr + m_horiz_disp) & 0x3fff;
1149 
1150 	return ra;
1151 }
1152 
1153 
draw_scanline(int y,bitmap_rgb32 & bitmap,const rectangle & cliprect)1154 uint8_t hd6345_device::draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1155 {
1156 	uint8_t ra = hd6845s_device::draw_scanline(y, bitmap, cliprect);
1157 
1158 	/* update MA for screen split */
1159 	if (ra == m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust) - 1)
1160 	{
1161 		int y_pos = y / (m_max_ras_addr + (MODE_INTERLACE_AND_VIDEO ? m_interlace_adjust : m_noninterlace_adjust));
1162 		if ((m_control1 & 0x03) > 0 && y_pos == m_disp2_pos && m_disp2_pos != m_disp3_pos && m_disp2_pos != m_disp4_pos)
1163 			m_current_disp_addr = m_disp2_start_addr;
1164 		if ((m_control1 & 0x03) > 1 && y_pos == m_disp3_pos && m_disp3_pos != m_disp2_pos && m_disp3_pos != m_disp4_pos)
1165 			m_current_disp_addr = m_disp3_start_addr;
1166 		if ((m_control1 & 0x03) > 2 && y_pos == m_disp4_pos && m_disp4_pos != m_disp2_pos && m_disp4_pos != m_disp3_pos)
1167 			m_current_disp_addr = m_disp4_start_addr;
1168 	}
1169 
1170 	return ra;
1171 }
1172 
1173 
screen_update(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)1174 uint32_t mc6845_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1175 {
1176 	assert(bitmap.valid());
1177 
1178 	if (m_has_valid_parameters)
1179 	{
1180 		assert(!m_update_row_cb.isnull());
1181 
1182 		if (m_display_disabled_msg_shown == true)
1183 		{
1184 			logerror("M6845: Valid screen parameters - display reenabled!!!\n");
1185 			m_display_disabled_msg_shown = false;
1186 		}
1187 
1188 		/* call the set up function if any */
1189 		if (!m_begin_update_cb.isnull())
1190 			m_begin_update_cb(bitmap, cliprect);
1191 
1192 		if (cliprect.min_y == 0)
1193 		{
1194 			/* read the start address at the beginning of the frame */
1195 			m_current_disp_addr = m_disp_start_addr;
1196 		}
1197 
1198 		/* for each row in the visible region */
1199 		for (uint16_t y = cliprect.min_y; y <= cliprect.max_y; y++)
1200 		{
1201 			this->draw_scanline(y, bitmap, cliprect);
1202 		}
1203 
1204 		/* call the tear down function if any */
1205 		if (!m_end_update_cb.isnull())
1206 			m_end_update_cb(bitmap, cliprect);
1207 	}
1208 	else
1209 	{
1210 		if (m_display_disabled_msg_shown == false)
1211 		{
1212 			logerror("M6845: Invalid screen parameters - display disabled!!!\n");
1213 			m_display_disabled_msg_shown = true;
1214 		}
1215 	}
1216 
1217 	return 0;
1218 }
1219 
1220 
device_start()1221 void mc6845_device::device_start()
1222 {
1223 	assert(clock() > 0);
1224 	assert(m_hpixels_per_column > 0);
1225 
1226 	/* bind delegates */
1227 	m_reconfigure_cb.resolve();
1228 	m_begin_update_cb.resolve();
1229 	m_update_row_cb.resolve();
1230 	m_end_update_cb.resolve();
1231 	m_on_update_addr_changed_cb.resolve();
1232 
1233 	/* resolve callbacks */
1234 	m_out_de_cb.resolve_safe();
1235 	m_out_cur_cb.resolve_safe();
1236 	m_out_hsync_cb.resolve_safe();
1237 	m_out_vsync_cb.resolve_safe();
1238 
1239 	/* create the timers */
1240 	m_line_timer = timer_alloc(TIMER_LINE);
1241 	m_de_off_timer = timer_alloc(TIMER_DE_OFF);
1242 	m_cur_on_timer = timer_alloc(TIMER_CUR_ON);
1243 	m_cur_off_timer = timer_alloc(TIMER_CUR_OFF);
1244 	m_hsync_on_timer = timer_alloc(TIMER_HSYNC_ON);
1245 	m_hsync_off_timer = timer_alloc(TIMER_HSYNC_OFF);
1246 	m_light_pen_latch_timer = timer_alloc(TIMER_LIGHT_PEN_LATCH);
1247 	m_upd_adr_timer = timer_alloc(TIMER_UPD_ADR);
1248 	m_upd_trans_timer = timer_alloc(TIMER_UPD_TRANS);
1249 
1250 	/* Use some large startup values */
1251 	m_horiz_char_total = 0xff;
1252 	m_max_ras_addr = 0x1f;
1253 	m_vert_char_total = 0x7f;
1254 	m_mode_control = 0x00;
1255 
1256 	m_supports_disp_start_addr_r = false;  // MC6845 can not read Display Start (double checked on datasheet)
1257 	m_supports_vert_sync_width = false;
1258 	m_supports_status_reg_d5 = false;
1259 	m_supports_status_reg_d6 = false;
1260 	m_supports_status_reg_d7 = false;
1261 	m_supports_transparent = false;
1262 	m_has_valid_parameters = false;
1263 	m_display_disabled_msg_shown = false;
1264 	m_line_enable_ff = false;
1265 	m_vsync_ff = 0;
1266 	m_raster_counter = 0;
1267 	m_adjust_active = 0;
1268 	m_horiz_sync_pos = 1;
1269 	m_vert_sync_pos = 1;
1270 	m_de = 0;
1271 	m_sync_width = 1;
1272 	m_horiz_pix_total = m_vert_pix_total = 0;
1273 	m_max_visible_x = m_max_visible_y = 0;
1274 	m_hsync_on_pos = m_vsync_on_pos = 0;
1275 	m_hsync_off_pos = m_vsync_off_pos = 0;
1276 	m_vsync = m_hsync = 0;
1277 	m_cur = 0;
1278 	m_line_counter = 0;
1279 	m_horiz_disp = m_vert_disp = 0;
1280 	m_vert_sync_pos = 0;
1281 	m_vert_total_adj = 0;
1282 	m_cursor_start_ras = m_cursor_end_ras = m_cursor_addr = 0;
1283 	m_cursor_blink_count = 0;
1284 	m_cursor_state = 0;
1285 	m_update_ready_bit = 0;
1286 	m_line_address = 0;
1287 	m_current_disp_addr = 0;
1288 	m_disp_start_addr = 0;
1289 	m_noninterlace_adjust = 1;
1290 	m_interlace_adjust = 1;
1291 
1292 	save_item(NAME(m_show_border_area));
1293 	save_item(NAME(m_visarea_adjust_min_x));
1294 	save_item(NAME(m_visarea_adjust_max_x));
1295 	save_item(NAME(m_visarea_adjust_min_y));
1296 	save_item(NAME(m_visarea_adjust_max_y));
1297 	save_item(NAME(m_hpixels_per_column));
1298 	save_item(NAME(m_register_address_latch));
1299 	save_item(NAME(m_horiz_char_total));
1300 	save_item(NAME(m_horiz_disp));
1301 	save_item(NAME(m_horiz_sync_pos));
1302 	save_item(NAME(m_sync_width));
1303 	save_item(NAME(m_vert_char_total));
1304 	save_item(NAME(m_vert_total_adj));
1305 	save_item(NAME(m_vert_disp));
1306 	save_item(NAME(m_vert_sync_pos));
1307 	save_item(NAME(m_mode_control));
1308 	save_item(NAME(m_max_ras_addr));
1309 	save_item(NAME(m_cursor_start_ras));
1310 	save_item(NAME(m_cursor_end_ras));
1311 	save_item(NAME(m_disp_start_addr));
1312 	save_item(NAME(m_cursor_addr));
1313 	save_item(NAME(m_light_pen_addr));
1314 	save_item(NAME(m_light_pen_latched));
1315 	save_item(NAME(m_cursor_state));
1316 	save_item(NAME(m_cursor_blink_count));
1317 	save_item(NAME(m_update_addr));
1318 	save_item(NAME(m_update_ready_bit));
1319 	save_item(NAME(m_cur));
1320 	save_item(NAME(m_hsync));
1321 	save_item(NAME(m_vsync));
1322 	save_item(NAME(m_de));
1323 	save_item(NAME(m_character_counter));
1324 	save_item(NAME(m_hsync_width_counter));
1325 	save_item(NAME(m_line_counter));
1326 	save_item(NAME(m_raster_counter));
1327 	save_item(NAME(m_adjust_counter));
1328 	save_item(NAME(m_vsync_width_counter));
1329 	save_item(NAME(m_line_enable_ff));
1330 	save_item(NAME(m_vsync_ff));
1331 	save_item(NAME(m_adjust_active));
1332 	save_item(NAME(m_line_address));
1333 	save_item(NAME(m_cursor_x));
1334 	save_item(NAME(m_has_valid_parameters));
1335 }
1336 
1337 
device_start()1338 void mc6845_1_device::device_start()
1339 {
1340 	mc6845_device::device_start();
1341 
1342 	m_supports_disp_start_addr_r = true;
1343 	m_supports_vert_sync_width = true;
1344 	m_supports_status_reg_d5 = false;
1345 	m_supports_status_reg_d6 = false;
1346 	m_supports_status_reg_d7 = false;
1347 	m_supports_transparent = false;
1348 }
1349 
1350 
device_start()1351 void c6545_1_device::device_start()
1352 {
1353 	mc6845_device::device_start();
1354 
1355 	m_supports_disp_start_addr_r = false;
1356 	m_supports_vert_sync_width = true;
1357 	m_supports_status_reg_d5 = true;
1358 	m_supports_status_reg_d6 = true;
1359 	m_supports_status_reg_d7 = false;
1360 	m_supports_transparent = false;
1361 }
1362 
1363 
device_start()1364 void r6545_1_device::device_start()
1365 {
1366 	mc6845_device::device_start();
1367 
1368 	m_supports_disp_start_addr_r = false;
1369 	m_supports_vert_sync_width = true;
1370 	m_supports_status_reg_d5 = true;
1371 	m_supports_status_reg_d6 = true;
1372 	m_supports_status_reg_d7 = true;
1373 	m_supports_transparent = true;
1374 }
1375 
1376 
device_start()1377 void hd6845s_device::device_start()
1378 {
1379 	mc6845_device::device_start();
1380 
1381 	m_supports_disp_start_addr_r = true;  // HD6845S can definitely read Display Start (double checked on datasheet)
1382 	m_supports_vert_sync_width = true;
1383 	m_supports_status_reg_d5 = false;
1384 	m_supports_status_reg_d6 = false;
1385 	m_supports_status_reg_d7 = false;
1386 	m_supports_transparent = false;
1387 
1388 	// Non-interlace Mode, Interlace Sync Mode - When total number of rasters is RN, RN-1 shall be programmed.
1389 	m_noninterlace_adjust = 1;
1390 	// Interlace Sync & Video Mode - When total number of rasters is RN, RN-2 shall be programmed.
1391 	m_interlace_adjust = 2;
1392 }
1393 
1394 
device_start()1395 void sy6545_1_device::device_start()
1396 {
1397 	mc6845_device::device_start();
1398 
1399 	m_supports_disp_start_addr_r = false;
1400 	m_supports_vert_sync_width = true;
1401 	m_supports_status_reg_d5 = true;
1402 	m_supports_status_reg_d6 = true;
1403 	m_supports_status_reg_d7 = true;
1404 	m_supports_transparent = true;
1405 }
1406 
1407 
device_start()1408 void sy6845e_device::device_start()
1409 {
1410 	mc6845_device::device_start();
1411 
1412 	m_supports_disp_start_addr_r = false;
1413 	m_supports_vert_sync_width = true;
1414 	m_supports_status_reg_d5 = true;
1415 	m_supports_status_reg_d6 = true;
1416 	m_supports_status_reg_d7 = true;
1417 	m_supports_transparent = true;
1418 }
1419 
1420 
device_start()1421 void hd6345_device::device_start()
1422 {
1423 	hd6845s_device::device_start();
1424 
1425 	m_disp2_pos = 0;
1426 	m_disp3_pos = 0;
1427 	m_disp4_pos = 0;
1428 	m_disp2_start_addr = 0;
1429 	m_disp3_start_addr = 0;
1430 	m_disp4_start_addr = 0;
1431 	m_vert_sync_pos_adj = 0;
1432 	m_smooth_scroll_ras = 0;
1433 	m_mem_width_offs = 0;
1434 	m_cursor2_start_ras = 0;
1435 	m_cursor2_end_ras = 0;
1436 	m_cursor2_addr = 0;
1437 	m_cursor_width = 0;
1438 	m_cursor2_width = 0;
1439 
1440 	save_item(NAME(m_disp2_pos));
1441 	save_item(NAME(m_disp2_start_addr));
1442 	save_item(NAME(m_disp3_pos));
1443 	save_item(NAME(m_disp3_start_addr));
1444 	save_item(NAME(m_disp4_pos));
1445 	save_item(NAME(m_disp4_start_addr));
1446 	save_item(NAME(m_vert_sync_pos_adj));
1447 	save_item(NAME(m_smooth_scroll_ras));
1448 	save_item(NAME(m_control1));
1449 	save_item(NAME(m_control2));
1450 	save_item(NAME(m_control3));
1451 	save_item(NAME(m_mem_width_offs));
1452 	save_item(NAME(m_cursor2_start_ras));
1453 	save_item(NAME(m_cursor2_end_ras));
1454 	save_item(NAME(m_cursor2_addr));
1455 	save_item(NAME(m_cursor_width));
1456 	save_item(NAME(m_cursor2_width));
1457 }
1458 
1459 
device_start()1460 void ams40489_device::device_start()
1461 {
1462 	mc6845_device::device_start();
1463 
1464 	m_supports_disp_start_addr_r = true;
1465 	m_supports_vert_sync_width = false;
1466 	m_supports_status_reg_d5 = false;
1467 	m_supports_status_reg_d6 = false;
1468 	m_supports_status_reg_d7 = false;
1469 	m_supports_transparent = false;
1470 }
1471 
1472 
device_start()1473 void mos8563_device::device_start()
1474 {
1475 	mc6845_device::device_start();
1476 
1477 	/* create the timers */
1478 	m_block_copy_timer = timer_alloc(TIMER_BLOCK_COPY);
1479 
1480 	m_supports_status_reg_d5 = true;
1481 	m_supports_status_reg_d6 = true;
1482 	m_supports_status_reg_d7 = true;
1483 	m_update_ready_bit = 1;
1484 
1485 	// default update_row delegate
1486 	m_update_row_cb.set(*this, FUNC(mos8563_device::vdc_update_row));
1487 
1488 	m_char_blink_state = false;
1489 	m_char_blink_count = 0;
1490 	m_attribute_addr = 0;
1491 	m_horiz_char = 0;
1492 	m_vert_char_disp = 0;
1493 	m_vert_scroll = 0;
1494 	m_horiz_scroll = 0;
1495 	m_color = 0;
1496 	m_row_addr_incr = 0;
1497 	m_char_base_addr = 0;
1498 	m_underline_ras = 0;
1499 	m_word_count = 0;
1500 	m_data = 0;
1501 	m_block_addr = 0;
1502 	m_de_begin = 0;
1503 	m_dram_refresh = 0;
1504 	m_sync_polarity = 0;
1505 
1506 	m_revision = 1;
1507 
1508 	// initialize video RAM
1509 	uint8_t data = 0xff;
1510 
1511 	for (offs_t offset = 0; offset < 0x10000; offset++)
1512 	{
1513 		write_videoram(offset, data);
1514 		data ^= 0xff;
1515 	}
1516 
1517 	// VICE palette
1518 	set_pen_color(0, rgb_t::black());
1519 	set_pen_color(1, rgb_t(0x55, 0x55, 0x55));
1520 	set_pen_color(2, rgb_t(0x00, 0x00, 0xaa));
1521 	set_pen_color(3, rgb_t(0x55, 0x55, 0xff));
1522 	set_pen_color(4, rgb_t(0x00, 0xaa, 0x00));
1523 	set_pen_color(5, rgb_t(0x55, 0xff, 0x55));
1524 	set_pen_color(6, rgb_t(0x00, 0xaa, 0xaa));
1525 	set_pen_color(7, rgb_t(0x55, 0xff, 0xff));
1526 	set_pen_color(8, rgb_t(0xaa, 0x00, 0x00));
1527 	set_pen_color(9, rgb_t(0xff, 0x55, 0x55));
1528 	set_pen_color(10, rgb_t(0xaa, 0x00, 0xaa));
1529 	set_pen_color(11, rgb_t(0xff, 0x55, 0xff));
1530 	set_pen_color(12, rgb_t(0xaa, 0x55, 0x00));
1531 	set_pen_color(13, rgb_t(0xff, 0xff, 0x55));
1532 	set_pen_color(14, rgb_t(0xaa, 0xaa, 0xaa));
1533 	set_pen_color(15, rgb_t::white());
1534 
1535 	save_item(NAME(m_char_buffer));
1536 	save_item(NAME(m_attr_buffer));
1537 	save_item(NAME(m_attribute_addr));
1538 	save_item(NAME(m_horiz_char));
1539 	save_item(NAME(m_vert_char_disp));
1540 	save_item(NAME(m_vert_scroll));
1541 	save_item(NAME(m_horiz_scroll));
1542 	save_item(NAME(m_color));
1543 	save_item(NAME(m_row_addr_incr));
1544 	save_item(NAME(m_char_base_addr));
1545 	save_item(NAME(m_underline_ras));
1546 	save_item(NAME(m_word_count));
1547 	save_item(NAME(m_data));
1548 	save_item(NAME(m_block_addr));
1549 	save_item(NAME(m_de_begin));
1550 	save_item(NAME(m_dram_refresh));
1551 	save_item(NAME(m_sync_polarity));
1552 	save_item(NAME(m_revision));
1553 	save_item(NAME(m_clk_scale));
1554 }
1555 
1556 
device_start()1557 void mos8568_device::device_start()
1558 {
1559 	mos8563_device::device_start();
1560 }
1561 
1562 
device_reset()1563 void mc6845_device::device_reset()
1564 {
1565 	/* internal registers other than status remain unchanged, all outputs go low */
1566 	m_out_de_cb(false);
1567 
1568 	m_out_hsync_cb(false);
1569 
1570 	m_out_vsync_cb(false);
1571 
1572 	if (!m_line_timer->enabled())
1573 		m_line_timer->adjust(cclks_to_attotime(m_horiz_char_total + 1));
1574 
1575 	m_light_pen_latched = false;
1576 
1577 	m_cursor_addr = 0;
1578 	m_line_address = 0;
1579 	m_horiz_disp = 0;
1580 	m_cursor_x = 0;
1581 	m_mode_control = 0;
1582 	m_register_address_latch = 0;
1583 	m_update_addr = 0;
1584 	m_light_pen_addr = 0;
1585 }
1586 
1587 
device_reset()1588 void r6545_1_device::device_reset() { mc6845_device::device_reset(); }
device_reset()1589 void mc6845_1_device::device_reset() { mc6845_device::device_reset(); }
device_reset()1590 void hd6845s_device::device_reset() { mc6845_device::device_reset(); }
device_reset()1591 void c6545_1_device::device_reset() { mc6845_device::device_reset(); }
device_reset()1592 void sy6545_1_device::device_reset() { mc6845_device::device_reset(); }
device_reset()1593 void sy6845e_device::device_reset() { mc6845_device::device_reset(); }
1594 
device_reset()1595 void hd6345_device::device_reset()
1596 {
1597 	hd6845s_device::device_reset();
1598 
1599 	m_control1 = 0;
1600 	m_control2 = 0;
1601 	m_control3 = 0;
1602 }
1603 
device_reset()1604 void ams40489_device::device_reset() { mc6845_device::device_reset(); }
1605 
device_reset()1606 void mos8563_device::device_reset()
1607 {
1608 	mc6845_device::device_reset();
1609 
1610 	m_sync_polarity = 0xc0;
1611 }
1612 
device_reset()1613 void mos8568_device::device_reset() { mos8563_device::device_reset(); }
1614 
1615 
1616 //-------------------------------------------------
1617 //  memory_space_config - return a description of
1618 //  any address spaces owned by this device
1619 //-------------------------------------------------
1620 
memory_space_config() const1621 device_memory_interface::space_config_vector mos8563_device::memory_space_config() const
1622 {
1623 	return space_config_vector {
1624 		std::make_pair(0, &m_videoram_space_config),
1625 	};
1626 }
1627 
1628 // default address maps
mos8563_videoram_map(address_map & map)1629 void mos8563_device::mos8563_videoram_map(address_map &map)
1630 {
1631 	if (!has_configured_map(0))
1632 		map(0x0000, 0xffff).ram();
1633 }
1634 
1635 
r6545_1_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1636 r6545_1_device::r6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1637 	: mc6845_device(mconfig, R6545_1, tag, owner, clock)
1638 {
1639 }
1640 
1641 
mc6845_1_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1642 mc6845_1_device::mc6845_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1643 	: mc6845_device(mconfig, MC6845_1, tag, owner, clock)
1644 {
1645 }
1646 
1647 
hd6845s_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)1648 hd6845s_device::hd6845s_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
1649 	: mc6845_device(mconfig, type, tag, owner, clock)
1650 {
1651 }
1652 
1653 
hd6845s_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1654 hd6845s_device::hd6845s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1655 	: mc6845_device(mconfig, HD6845S, tag, owner, clock)
1656 {
1657 }
1658 
1659 
c6545_1_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1660 c6545_1_device::c6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1661 	: mc6845_device(mconfig, C6545_1, tag, owner, clock)
1662 {
1663 }
1664 
1665 
sy6545_1_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1666 sy6545_1_device::sy6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1667 	: mc6845_device(mconfig, SY6545_1, tag, owner, clock)
1668 {
1669 }
1670 
1671 
sy6845e_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1672 sy6845e_device::sy6845e_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1673 	: mc6845_device(mconfig, SY6845E, tag, owner, clock)
1674 {
1675 }
1676 
1677 
hd6345_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1678 hd6345_device::hd6345_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1679 	: hd6845s_device(mconfig, HD6345, tag, owner, clock)
1680 {
1681 }
1682 
1683 
ams40489_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1684 ams40489_device::ams40489_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1685 	: mc6845_device(mconfig, AMS40489, tag, owner, clock)
1686 {
1687 }
1688 
1689 
mos8563_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)1690 mos8563_device::mos8563_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
1691 	: mc6845_device(mconfig, type, tag, owner, clock)
1692 	, device_memory_interface(mconfig, *this)
1693 	, device_palette_interface(mconfig, *this)
1694 	, m_videoram_space_config("videoram", ENDIANNESS_LITTLE, 8, 16, 0, address_map_constructor(FUNC(mos8563_device::mos8563_videoram_map), this))
1695 {
1696 	m_clk_scale = 8;
1697 }
1698 
1699 
mos8563_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1700 mos8563_device::mos8563_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1701 	: mos8563_device(mconfig, MOS8563, tag, owner, clock)
1702 {
1703 }
1704 
1705 
mos8568_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1706 mos8568_device::mos8568_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1707 	: mos8563_device(mconfig, MOS8568, tag, owner, clock)
1708 {
1709 }
1710 
1711 
update_cursor_state()1712 void mos8563_device::update_cursor_state()
1713 {
1714 	mc6845_device::update_cursor_state();
1715 
1716 	/* save and increment character blink counter */
1717 	uint8_t last_char_blink_count = m_char_blink_count;
1718 	m_char_blink_count++;
1719 
1720 	/* switch on character blinking mode */
1721 	if (VSS_CBRATE)
1722 	{
1723 		if ((last_char_blink_count & 0x20) != (m_char_blink_count & 0x20))
1724 			m_char_blink_state = !m_char_blink_state;
1725 	}
1726 	else
1727 	{
1728 		if ((last_char_blink_count & 0x10) != (m_char_blink_count & 0x10))
1729 			m_char_blink_state = !m_char_blink_state;
1730 	}
1731 }
1732 
1733 
draw_scanline(int y,bitmap_rgb32 & bitmap,const rectangle & cliprect)1734 uint8_t mos8563_device::draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect)
1735 {
1736 	uint8_t ra = mc6845_device::draw_scanline(y, bitmap, cliprect);
1737 
1738 	if (ra == m_max_ras_addr)
1739 		m_current_disp_addr = (m_current_disp_addr + m_row_addr_incr) & 0x3fff;
1740 
1741 	return ra;
1742 }
1743 
1744 
MC6845_UPDATE_ROW(mos8563_device::vdc_update_row)1745 MC6845_UPDATE_ROW( mos8563_device::vdc_update_row )
1746 {
1747 	ra += (m_vert_scroll & 0x0f);
1748 	ra &= 0x0f;
1749 
1750 	uint8_t cth = (m_horiz_char >> 4) + (HSS_DBL ? 0 : 1);
1751 	uint8_t cdh = (m_horiz_char & 0x0f) + (HSS_DBL ? 0 : 1);
1752 	uint8_t cdv = m_vert_char_disp;
1753 
1754 	for (int column = 0; column < x_count; column++)
1755 	{
1756 		uint8_t code = read_videoram(ma + column);
1757 		uint8_t attr = 0;
1758 
1759 		int fg = m_color >> 4;
1760 		int bg = m_color & 0x0f;
1761 
1762 		if (HSS_ATTR)
1763 		{
1764 			offs_t attr_addr = m_attribute_addr + ma + column;
1765 			attr = read_videoram(attr_addr);
1766 		}
1767 
1768 		if (HSS_TEXT)
1769 		{
1770 			if (HSS_ATTR)
1771 			{
1772 				fg = ATTR_FOREGROUND;
1773 				bg = ATTR_BACKGROUND;
1774 			}
1775 
1776 			if (VSS_RVS) code ^= 0xff;
1777 
1778 			for (int bit = 0; bit < cdh; bit++)
1779 			{
1780 				int x = (m_horiz_scroll & 0x0f) - cth + (column * cth) + bit;
1781 				if (x < 0) x = 0;
1782 				int color = BIT(code, 7) ? fg : bg;
1783 
1784 				bitmap.pix(vbp + y, hbp + x) = pen(de ? color : 0);
1785 			}
1786 		}
1787 		else
1788 		{
1789 			if (HSS_ATTR)
1790 			{
1791 				fg = ATTR_COLOR;
1792 			}
1793 
1794 			offs_t font_addr;
1795 
1796 			if (m_max_ras_addr < 16)
1797 			{
1798 				font_addr = ((m_char_base_addr & 0xe0) << 8) | (ATTR_ALTERNATE_CHARSET << 12) | (code << 4) | (ra & 0x0f);
1799 			}
1800 			else
1801 			{
1802 				font_addr = ((m_char_base_addr & 0xc0) << 8) | (ATTR_ALTERNATE_CHARSET << 13) | (code << 5) | (ra & 0x1f);
1803 			}
1804 
1805 			uint8_t data = read_videoram(font_addr);
1806 
1807 			if (ra >= cdv) data = 0;
1808 			if (ATTR_UNDERLINE && (ra == m_underline_ras)) data = 0xff;
1809 			if (ATTR_BLINK && !m_char_blink_state) data = 0;
1810 			if (ATTR_REVERSE) data ^= 0xff;
1811 			if (column == cursor_x) data ^= 0xff;
1812 			if (VSS_RVS) data ^= 0xff;
1813 
1814 			for (int bit = 0; bit < cdh; bit++)
1815 			{
1816 				int x = (m_horiz_scroll & 0x0f) - cth + (column * cth) + bit;
1817 				if (x < 0) x = 0;
1818 				int color = BIT(data, 7) ? fg : bg;
1819 
1820 				bitmap.pix(vbp + y, hbp + x) = pen(de ? color : 0);
1821 
1822 				if ((bit < 8) || !HSS_SEMI) data <<= 1;
1823 			}
1824 		}
1825 	}
1826 }
1827