1 // license:BSD-3-Clause
2 // copyright-holders:Wilbert Pol,Nigel Barnes
3 /**********************************************************************
4 
5     Motorola MC6845 and compatible CRT controller emulation
6 
7 ***********************************************************************
8                             ____    ____
9                    GND   1 |*   \__/    | 40  VS
10                 _RESET   2 |            | 39  HS
11                  LPSTB   3 |            | 38  RA0
12                    MA0   4 |            | 37  RA1
13                    MA1   5 |            | 36  RA2
14                    MA2   6 |            | 35  RA3
15                    MA3   7 |            | 34  RA4
16                    MA4   8 |            | 33  D0
17                    MA5   9 |            | 32  D1
18                    MA6  10 |            | 31  D2
19                    MA7  11 |   MC6845   | 30  D3
20                    MA8  12 |            | 29  D4
21                    MA9  13 |            | 28  D5
22                   MA10  14 |            | 27  D6
23                   MA11  15 |            | 26  D7
24                   MA12  16 |            | 25  _CS
25                   MA13  17 |            | 24  RS
26                     DE  18 |            | 23  E
27                 CURSOR  19 |            | 22  R/_W
28                    Vcc  20 |____________| 21  CLK
29 
30 **********************************************************************/
31 
32 #ifndef MAME_VIDEO_MC6845_H
33 #define MAME_VIDEO_MC6845_H
34 
35 #pragma once
36 
37 
38 /* callback definitions */
39 #define MC6845_RECONFIGURE(name)  void name(int width, int height, const rectangle &visarea, attoseconds_t frame_period)
40 
41 #define MC6845_BEGIN_UPDATE(name)  void name(bitmap_rgb32 &bitmap, const rectangle &cliprect)
42 
43 #define MC6845_UPDATE_ROW(name)     void name(bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t ma, uint8_t ra, \
44 												uint16_t y, uint8_t x_count, int8_t cursor_x, int de, int hbp, int vbp)
45 
46 #define MC6845_END_UPDATE(name)     void name(bitmap_rgb32 &bitmap, const rectangle &cliprect)
47 
48 #define MC6845_ON_UPDATE_ADDR_CHANGED(name) void name(int address, int strobe)
49 
50 
51 class mc6845_device :   public device_t,
52 						public device_video_interface
53 {
54 public:
55 	typedef device_delegate<void (int width, int height, const rectangle &visarea, attoseconds_t frame_period)> reconfigure_delegate;
56 	typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect)> begin_update_delegate;
57 	typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t ma, uint8_t ra,
58 									uint16_t y, uint8_t x_count, int8_t cursor_x, int de, int hbp, int vbp)> update_row_delegate;
59 	typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect)> end_update_delegate;
60 	typedef device_delegate<void (int address, int strobe)> on_update_addr_changed_delegate;
61 
62 	// construction/destruction
63 	mc6845_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
64 
set_show_border_area(bool show)65 	void set_show_border_area(bool show) { m_show_border_area = show; }
set_visarea_adjust(int min_x,int max_x,int min_y,int max_y)66 	void set_visarea_adjust(int min_x, int max_x, int min_y, int max_y)
67 	{
68 		m_visarea_adjust_min_x = min_x;
69 		m_visarea_adjust_max_x = max_x;
70 		m_visarea_adjust_min_y = min_y;
71 		m_visarea_adjust_max_y = max_y;
72 	}
set_char_width(int pixels)73 	void set_char_width(int pixels) { m_hpixels_per_column = pixels; }
74 
set_reconfigure_callback(T &&...args)75 	template <typename... T> void set_reconfigure_callback(T &&... args) { m_reconfigure_cb.set(std::forward<T>(args)...); }
set_begin_update_callback(T &&...args)76 	template <typename... T> void set_begin_update_callback(T &&... args) { m_begin_update_cb.set(std::forward<T>(args)...); }
set_update_row_callback(T &&...args)77 	template <typename... T> void set_update_row_callback(T &&... args) { m_update_row_cb.set(std::forward<T>(args)...); }
set_end_update_callback(T &&...args)78 	template <typename... T> void set_end_update_callback(T &&... args) { m_end_update_cb.set(std::forward<T>(args)...); }
set_on_update_addr_change_callback(T &&...args)79 	template <typename... T> void set_on_update_addr_change_callback(T &&... args) { m_on_update_addr_changed_cb.set(std::forward<T>(args)...); }
80 
out_de_callback()81 	auto out_de_callback() { return m_out_de_cb.bind(); }
out_cur_callback()82 	auto out_cur_callback() { return m_out_cur_cb.bind(); }
out_hsync_callback()83 	auto out_hsync_callback() { return m_out_hsync_cb.bind(); }
out_vsync_callback()84 	auto out_vsync_callback() { return m_out_vsync_cb.bind(); }
85 
86 	/* select one of the registers for reading or writing */
87 	void address_w(uint8_t data);
88 
89 	/* read from the status register */
90 	uint8_t status_r();
91 
92 	/* read from the currently selected register */
93 	uint8_t register_r();
94 
95 	/* write to the currently selected register */
96 	void register_w(uint8_t data);
97 
98 	// read display enable line state
99 	DECLARE_READ_LINE_MEMBER( de_r );
100 
101 	// read cursor line state
102 	DECLARE_READ_LINE_MEMBER( cursor_r );
103 
104 	// read horizontal sync line state
105 	DECLARE_READ_LINE_MEMBER( hsync_r );
106 
107 	// read vertical sync line state
108 	DECLARE_READ_LINE_MEMBER( vsync_r );
109 
110 	/* return the current value on the MA0-MA13 pins */
111 	uint16_t get_ma();
112 
113 	/* return the current value on the RA0-RA4 pins */
114 	uint8_t get_ra();
115 
116 	/* simulates the LO->HI clocking of the light pen pin (pin 3) */
117 	void assert_light_pen_input();
118 
119 	/* set number of pixels per video memory address */
120 	void set_hpixels_per_column(int hpixels_per_column);
121 
122 	/* updates the screen -- this will call begin_update(),
123 	   followed by update_row() repeatedly and after all row
124 	   updating is complete, end_update() */
125 	uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
126 
127 protected:
128 	mc6845_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
129 
130 	// device-level overrides
131 	virtual void device_start() override;
132 	virtual void device_reset() override;
133 	virtual void device_post_load() override;
134 	virtual void device_clock_changed() override;
135 	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
136 
cclks_to_attotime(uint64_t clocks)137 	attotime cclks_to_attotime(uint64_t clocks) const { return clocks_to_attotime(clocks * m_clk_scale); }
attotime_to_cclks(const attotime & duration)138 	uint64_t attotime_to_cclks(const attotime &duration) const { return attotime_to_clocks(duration) / m_clk_scale; }
139 
140 	bool m_supports_disp_start_addr_r;
141 	bool m_supports_vert_sync_width;
142 	bool m_supports_status_reg_d5;
143 	bool m_supports_status_reg_d6;
144 	bool m_supports_status_reg_d7;
145 	bool m_supports_transparent;
146 
147 	/* register file */
148 	uint8_t   m_horiz_char_total;     /* 0x00 */
149 	uint8_t   m_horiz_disp;           /* 0x01 */
150 	uint8_t   m_horiz_sync_pos;       /* 0x02 */
151 	uint8_t   m_sync_width;           /* 0x03 */
152 	uint8_t   m_vert_char_total;      /* 0x04 */
153 	uint8_t   m_vert_total_adj;       /* 0x05 */
154 	uint8_t   m_vert_disp;            /* 0x06 */
155 	uint8_t   m_vert_sync_pos;        /* 0x07 */
156 	uint8_t   m_mode_control;         /* 0x08 */
157 	uint8_t   m_max_ras_addr;         /* 0x09 */
158 	uint8_t   m_cursor_start_ras;     /* 0x0a */
159 	uint8_t   m_cursor_end_ras;       /* 0x0b */
160 	uint16_t  m_disp_start_addr;      /* 0x0c/0x0d */
161 	uint16_t  m_cursor_addr;          /* 0x0e/0x0f */
162 	uint16_t  m_light_pen_addr;       /* 0x10/0x11 */
163 	uint16_t  m_update_addr;          /* 0x12/0x13 */
164 
165 	/* other internal state */
166 	uint8_t   m_register_address_latch;
167 	bool    m_cursor_state;
168 	uint8_t   m_cursor_blink_count;
169 	bool    m_update_ready_bit;
170 	/* output signals */
171 	int     m_cur;
172 	int     m_hsync;
173 	int     m_vsync;
174 	int     m_de;
175 
176 	/* internal counters */
177 	uint8_t   m_character_counter;        /* Not used yet */
178 	uint8_t   m_hsync_width_counter;  /* Not used yet */
179 	uint8_t   m_line_counter;
180 	uint8_t   m_raster_counter;
181 	uint8_t   m_adjust_counter;
182 	uint8_t   m_vsync_width_counter;
183 
184 	bool    m_line_enable_ff;       /* Internal flip flop which is set when the line_counter is reset and reset when vert_disp is reached */
185 	uint8_t   m_vsync_ff;
186 	uint8_t   m_adjust_active;
187 	uint16_t  m_line_address;
188 	int16_t   m_cursor_x;
189 
190 	/* timers */
191 	static const device_timer_id TIMER_LINE = 0;
192 	static const device_timer_id TIMER_DE_OFF = 1;
193 	static const device_timer_id TIMER_CUR_ON = 2;
194 	static const device_timer_id TIMER_CUR_OFF = 3;
195 	static const device_timer_id TIMER_HSYNC_ON = 4;
196 	static const device_timer_id TIMER_HSYNC_OFF = 5;
197 	static const device_timer_id TIMER_LIGHT_PEN_LATCH = 6;
198 	static const device_timer_id TIMER_UPD_ADR = 7;
199 	static const device_timer_id TIMER_UPD_TRANS = 8;
200 
201 	emu_timer *m_line_timer;
202 	emu_timer *m_de_off_timer;
203 	emu_timer *m_cur_on_timer;
204 	emu_timer *m_cur_off_timer;
205 	emu_timer *m_hsync_on_timer;
206 	emu_timer *m_hsync_off_timer;
207 	emu_timer *m_light_pen_latch_timer;
208 	emu_timer *m_upd_adr_timer;
209 	emu_timer *m_upd_trans_timer;
210 
211 	/* computed values - do NOT state save these! */
212 	/* These computed are used to define the screen parameters for a driver */
213 	uint16_t  m_horiz_pix_total;
214 	uint16_t  m_vert_pix_total;
215 	uint16_t  m_max_visible_x;
216 	uint16_t  m_max_visible_y;
217 	uint16_t  m_hsync_on_pos;
218 	uint16_t  m_hsync_off_pos;
219 	uint16_t  m_vsync_on_pos;
220 	uint16_t  m_vsync_off_pos;
221 	bool    m_has_valid_parameters;
222 	bool    m_display_disabled_msg_shown;
223 
224 	uint16_t   m_current_disp_addr;   /* the display address currently drawn (used only in mc6845_update) */
225 
226 	bool     m_light_pen_latched;
227 	attotime m_upd_time;
228 
229 	void update_upd_adr_timer();
230 	void call_on_update_address(int strobe);
231 	void transparent_update();
232 	void recompute_parameters(bool postload);
233 	void update_counters();
234 	void set_de(int state);
235 	void set_hsync(int state);
236 	void set_vsync(int state);
237 	void set_cur(int state);
238 	bool match_line();
239 	virtual bool check_cursor_visible(uint16_t ra, uint16_t line_addr);
240 	void handle_line_timer();
241 	virtual void update_cursor_state();
242 	virtual uint8_t draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect);
243 
244 	/************************
245 	 interface CRTC - driver
246 	 ************************/
247 
248 	bool m_show_border_area;        /* visible screen area (false) active display (true) active display + blanking */
249 	int m_noninterlace_adjust;      /* adjust max ras in non-interlace mode */
250 	int m_interlace_adjust;         /* adjust max ras in interlace mode */
251 
252 	uint32_t m_clk_scale;
253 
254 	/* visible screen area adjustment */
255 	int m_visarea_adjust_min_x;
256 	int m_visarea_adjust_max_x;
257 	int m_visarea_adjust_min_y;
258 	int m_visarea_adjust_max_y;
259 
260 	int m_hpixels_per_column;       /* number of pixels per video memory address */
261 
262 	reconfigure_delegate m_reconfigure_cb;
263 
264 	/* if specified, this gets called before any pixel update,
265 	 optionally return a pointer that will be passed to the
266 	 update and tear down callbacks */
267 	begin_update_delegate m_begin_update_cb;
268 
269 	/* this gets called for every row, the driver must output
270 	 x_count * hpixels_per_column pixels.
271 	 cursor_x indicates the character position where the cursor is, or -1
272 	 if there is no cursor on this row */
273 	update_row_delegate  m_update_row_cb;
274 
275 	/* if specified, this gets called after all row updating is complete */
276 	end_update_delegate  m_end_update_cb;
277 
278 	/* Called whenever the update address changes
279 	 * For vblank/hblank timing strobe indicates the physical update.
280 	 * vblank/hblank timing not supported yet! */
281 	on_update_addr_changed_delegate m_on_update_addr_changed_cb;
282 
283 	/* if specified, this gets called for every change of the display enable pin (pin 18) */
284 	devcb_write_line            m_out_de_cb;
285 
286 	/* if specified, this gets called for every change of the cursor pin (pin 19) */
287 	devcb_write_line            m_out_cur_cb;
288 
289 	/* if specified, this gets called for every change of the HSYNC pin (pin 39) */
290 	devcb_write_line            m_out_hsync_cb;
291 
292 	/* if specified, this gets called for every change of the VSYNC pin (pin 40) */
293 	devcb_write_line            m_out_vsync_cb;
294 };
295 
296 
297 class mc6845_1_device : public mc6845_device
298 {
299 public:
300 	mc6845_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
301 
302 protected:
303 	virtual void device_start() override;
304 	virtual void device_reset() override;
305 };
306 
307 class r6545_1_device : public mc6845_device
308 {
309 public:
310 	r6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
311 
312 protected:
313 	virtual void device_start() override;
314 	virtual void device_reset() override;
315 };
316 
317 class c6545_1_device : public mc6845_device
318 {
319 public:
320 	c6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
321 
322 protected:
323 	virtual void device_start() override;
324 	virtual void device_reset() override;
325 };
326 
327 class hd6845s_device : public mc6845_device
328 {
329 public:
330 	hd6845s_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
331 
332 protected:
333 	hd6845s_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
334 
335 	virtual void device_start() override;
336 	virtual void device_reset() override;
337 	virtual bool check_cursor_visible(uint16_t ra, uint16_t line_addr) override;
338 };
339 
340 class sy6545_1_device : public mc6845_device
341 {
342 public:
343 	sy6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
344 
345 protected:
346 	virtual void device_start() override;
347 	virtual void device_reset() override;
348 };
349 
350 class sy6845e_device : public mc6845_device
351 {
352 public:
353 	sy6845e_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
354 
355 protected:
356 	virtual void device_start() override;
357 	virtual void device_reset() override;
358 };
359 
360 class hd6345_device : public hd6845s_device
361 {
362 public:
363 	hd6345_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
364 
365 	void address_w(uint8_t data);
366 	uint8_t register_r();
367 	void register_w(uint8_t data);
368 
369 protected:
370 	virtual void device_start() override;
371 	virtual void device_reset() override;
372 
373 	/* register file */
374 	uint8_t   m_disp2_pos;            /* 0x12 */
375 	uint16_t  m_disp2_start_addr;     /* 0x13/0x14 */
376 	uint8_t   m_disp3_pos;            /* 0x15 */
377 	uint16_t  m_disp3_start_addr;     /* 0x16/0x17 */
378 	uint8_t   m_disp4_pos;            /* 0x18 */
379 	uint16_t  m_disp4_start_addr;     /* 0x19/0x1a */
380 	uint8_t   m_vert_sync_pos_adj;    /* 0x1b */
381 	uint8_t   m_smooth_scroll_ras;    /* 0x1d */
382 	uint8_t   m_control1;             /* 0x1e */
383 	uint8_t   m_control2;             /* 0x1f */
384 	uint8_t   m_control3;             /* 0x20 */
385 	uint8_t   m_mem_width_offs;       /* 0x21 */
386 	uint8_t   m_cursor2_start_ras;    /* 0x22 */
387 	uint8_t   m_cursor2_end_ras;      /* 0x23 */
388 	uint16_t  m_cursor2_addr;         /* 0x24/0x25 */
389 	uint8_t   m_cursor_width;         /* 0x26 */
390 	uint8_t   m_cursor2_width;        /* 0x27 */
391 
392 	virtual uint8_t draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect) override;
393 };
394 
395 class ams40489_device : public mc6845_device
396 {
397 public:
398 	ams40489_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
399 
400 protected:
401 	virtual void device_start() override;
402 	virtual void device_reset() override;
403 };
404 
405 class mos8563_device : public mc6845_device,
406 						public device_memory_interface,
407 						public device_palette_interface
408 {
409 public:
410 	mos8563_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
411 
412 	void address_w(uint8_t data);
413 	uint8_t status_r();
414 	uint8_t register_r();
415 	void register_w(uint8_t data);
416 
417 	inline uint8_t read_videoram(offs_t offset);
418 	inline void write_videoram(offs_t offset, uint8_t data);
419 
420 	MC6845_UPDATE_ROW( vdc_update_row );
421 
422 protected:
423 	mos8563_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
424 
425 	// device-level overrides
426 	virtual void device_start() override;
427 	virtual void device_reset() override;
428 	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
429 
430 	// device_memory_interface overrides
431 	virtual space_config_vector memory_space_config() const override;
432 
433 	// device_palette_interface overrides
palette_entries()434 	virtual uint32_t palette_entries() const override { return 16; }
435 
436 	const address_space_config      m_videoram_space_config;
437 
438 	uint8_t m_char_buffer[80];
439 	uint8_t m_attr_buffer[80];
440 
441 	bool    m_char_blink_state;
442 	uint8_t   m_char_blink_count;
443 
444 	/* register file */
445 	uint16_t  m_attribute_addr;       /* 0x14/0x15 */
446 	uint8_t   m_horiz_char;           /* 0x16 */
447 	uint8_t   m_vert_char_disp;       /* 0x17 */
448 	uint8_t   m_vert_scroll;          /* 0x18 */
449 	uint8_t   m_horiz_scroll;         /* 0x19 */
450 	uint8_t   m_color;                /* 0x1a */
451 	uint8_t   m_row_addr_incr;        /* 0x1b */
452 	uint8_t   m_char_base_addr;       /* 0x1c */
453 	uint8_t   m_underline_ras;        /* 0x1d */
454 	uint8_t   m_word_count;           /* 0x1e */
455 	uint8_t   m_data;                 /* 0x1f */
456 	uint16_t  m_block_addr;           /* 0x20/0x21 */
457 	uint16_t  m_de_begin;             /* 0x22/0x23 */
458 	uint8_t   m_dram_refresh;         /* 0x24 */
459 	uint8_t   m_sync_polarity;        /* 0x25 */
460 
461 	int m_revision;
462 
463 	virtual void update_cursor_state() override;
464 	virtual uint8_t draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect) override;
465 
466 	static const device_timer_id TIMER_BLOCK_COPY = 9;
467 
468 	emu_timer *m_block_copy_timer;
469 
470 	void mos8563_videoram_map(address_map &map);
471 };
472 
473 class mos8568_device : public mos8563_device
474 {
475 public:
476 	mos8568_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
477 
478 protected:
479 	// device-level overrides
480 	virtual void device_start() override;
481 	virtual void device_reset() override;
482 };
483 
484 
485 DECLARE_DEVICE_TYPE(MC6845,   mc6845_device)
486 DECLARE_DEVICE_TYPE(MC6845_1, mc6845_1_device)
487 DECLARE_DEVICE_TYPE(R6545_1,  r6545_1_device)
488 DECLARE_DEVICE_TYPE(C6545_1,  c6545_1_device)
489 DECLARE_DEVICE_TYPE(HD6845S,  hd6845s_device)
490 DECLARE_DEVICE_TYPE(SY6545_1, sy6545_1_device)
491 DECLARE_DEVICE_TYPE(SY6845E,  sy6845e_device)
492 DECLARE_DEVICE_TYPE(HD6345,   hd6345_device)
493 DECLARE_DEVICE_TYPE(AMS40489, ams40489_device)
494 DECLARE_DEVICE_TYPE(MOS8563,  mos8563_device)
495 DECLARE_DEVICE_TYPE(MOS8568,  mos8568_device)
496 
497 #endif // MAME_VIDEO_MC6845_H
498