summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/mc6845.h
blob: d590141c10239e07e78e51627ed27588c2061c4c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol, Bartman/Abyss (HD6345)
/**********************************************************************

    Motorola MC6845 and compatible CRT controller emulation

**********************************************************************/

#ifndef MAME_VIDEO_MC6845_H
#define MAME_VIDEO_MC6845_H

#pragma once


#define MCFG_MC6845_ADD(_tag, _variant, _screen_tag, _clock) \
	MCFG_DEVICE_ADD(_tag, _variant, _clock) \
	MCFG_VIDEO_SET_SCREEN(_screen_tag)

#define MCFG_MOS8563_ADD(_tag, _screen_tag, _clock, _map) \
	MCFG_DEVICE_ADD(_tag, MOS8563, _clock) \
	MCFG_VIDEO_SET_SCREEN(_screen_tag) \
	MCFG_DEVICE_ADDRESS_MAP(0, _map)

#define MCFG_MOS8568_ADD(_tag, _screen_tag, _clock, _map) \
	MCFG_DEVICE_ADD(_tag, MOS8568, _clock) \
	MCFG_VIDEO_SET_SCREEN(_screen_tag) \
	MCFG_DEVICE_ADDRESS_MAP(0, _map)


#define MCFG_MC6845_SHOW_BORDER_AREA(_show) \
	downcast<mc6845_device &>(*device).set_show_border_area(_show);

#define MCFG_MC6845_VISAREA_ADJUST(_minx, _maxx, _miny, _maxy) \
	downcast<mc6845_device &>(*device).set_visarea_adjust(_minx, _maxx, _miny, _maxy);

#define MCFG_MC6845_CHAR_WIDTH(_pixels) \
	downcast<mc6845_device &>(*device).set_char_width(_pixels);

#define MCFG_MC6845_RECONFIGURE_CB(_class, _method) \
	downcast<mc6845_device &>(*device).set_reconfigure_callback(mc6845_device::reconfigure_delegate(&_class::_method, #_class "::" #_method, this));

#define MCFG_MC6845_BEGIN_UPDATE_CB(_class, _method) \
	downcast<mc6845_device &>(*device).set_begin_update_callback(mc6845_device::begin_update_delegate(&_class::_method, #_class "::" #_method, this));

#define MCFG_MC6845_UPDATE_ROW_CB(_class, _method) \
	downcast<mc6845_device &>(*device).set_update_row_callback(mc6845_device::update_row_delegate(&_class::_method, #_class "::" #_method, this));

#define MCFG_MC6845_END_UPDATE_CB(_class, _method) \
	downcast<mc6845_device &>(*device).set_end_update_callback(mc6845_device::end_update_delegate(&_class::_method, #_class "::" #_method, this));

#define MCFG_MC6845_ADDR_CHANGED_CB(_class, _method) \
	downcast<mc6845_device &>(*device).set_on_update_addr_change_callback(mc6845_device::on_update_addr_changed_delegate(&_class::_method, #_class "::" #_method, this));

#define MCFG_MC6845_OUT_DE_CB(_write) \
	devcb = &downcast<mc6845_device &>(*device).set_out_de_callback(DEVCB_##_write);

#define MCFG_MC6845_OUT_CUR_CB(_write) \
	devcb = &downcast<mc6845_device &>(*device).set_out_cur_callback(DEVCB_##_write);

#define MCFG_MC6845_OUT_HSYNC_CB(_write) \
	devcb = &downcast<mc6845_device &>(*device).set_out_hsync_callback(DEVCB_##_write);

#define MCFG_MC6845_OUT_VSYNC_CB(_write) \
	devcb = &downcast<mc6845_device &>(*device).set_out_vsync_callback(DEVCB_##_write);


/* callback definitions */
#define MC6845_RECONFIGURE(name)  void name(int width, int height, const rectangle &visarea, attoseconds_t frame_period)

#define MC6845_BEGIN_UPDATE(name)  void name(bitmap_rgb32 &bitmap, const rectangle &cliprect)

#define MC6845_UPDATE_ROW(name)     void name(bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t ma, uint8_t ra, \
												uint16_t y, uint8_t x_count, int8_t cursor_x, int de, int hbp, int vbp)

#define MC6845_END_UPDATE(name)     void name(bitmap_rgb32 &bitmap, const rectangle &cliprect)

#define MC6845_ON_UPDATE_ADDR_CHANGED(name) void name(int address, int strobe)


class mc6845_device :   public device_t,
						public device_video_interface
{
public:
	typedef device_delegate<void (int width, int height, const rectangle &visarea, attoseconds_t frame_period)> reconfigure_delegate;
	typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect)> begin_update_delegate;
	typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect, uint16_t ma, uint8_t ra,
									uint16_t y, uint8_t x_count, int8_t cursor_x, int de, int hbp, int vbp)> update_row_delegate;
	typedef device_delegate<void (bitmap_rgb32 &bitmap, const rectangle &cliprect)> end_update_delegate;
	typedef device_delegate<void (int address, int strobe)> on_update_addr_changed_delegate;

	// construction/destruction
	mc6845_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	void set_show_border_area(bool show) { m_show_border_area = show; }
	void set_visarea_adjust(int min_x, int max_x, int min_y, int max_y)
	{
		m_visarea_adjust_min_x = min_x;
		m_visarea_adjust_max_x = max_x;
		m_visarea_adjust_min_y = min_y;
		m_visarea_adjust_max_y = max_y;
	}
	void set_char_width(int pixels) { m_hpixels_per_column = pixels; }

	template <typename Object> void set_reconfigure_callback(Object &&cb) { m_reconfigure_cb = std::forward<Object>(cb); }
	template <typename Object> void set_begin_update_callback(Object &&cb) { m_begin_update_cb = std::forward<Object>(cb); }
	template <typename Object> void set_update_row_callback(Object &&cb) { m_update_row_cb = std::forward<Object>(cb); }
	template <typename Object> void set_end_update_callback(Object &&cb) { m_end_update_cb = std::forward<Object>(cb); }
	template <typename Object> void set_on_update_addr_change_callback(Object &&cb) { m_on_update_addr_changed_cb = std::forward<Object>(cb); }

	template <class Object> devcb_base &set_out_de_callback(Object &&cb) { return m_out_de_cb.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_out_cur_callback(Object &&cb) { return m_out_cur_cb.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_out_hsync_callback(Object &&cb) { return m_out_hsync_cb.set_callback(std::forward<Object>(cb)); }
	template <class Object> devcb_base &set_out_vsync_callback(Object &&cb) { return m_out_vsync_cb.set_callback(std::forward<Object>(cb)); }

	/* select one of the registers for reading or writing */
	DECLARE_WRITE8_MEMBER( address_w ) { write_address(data); }
	void write_address(uint8_t data);

	/* read from the status register */
	DECLARE_READ8_MEMBER( status_r ) { return read_status(); }
	uint8_t read_status();

	/* read from the currently selected register */
	DECLARE_READ8_MEMBER( register_r ) { return read_register(); }
	uint8_t read_register();

	/* write to the currently selected register */
	DECLARE_WRITE8_MEMBER( register_w ) { write_register(data); }
	void write_register(uint8_t data);

	// read display enable line state
	DECLARE_READ_LINE_MEMBER( de_r );

	// read cursor line state
	DECLARE_READ_LINE_MEMBER( cursor_r );

	// read horizontal sync line state
	DECLARE_READ_LINE_MEMBER( hsync_r );

	// read vertical sync line state
	DECLARE_READ_LINE_MEMBER( vsync_r );

	/* return the current value on the MA0-MA13 pins */
	uint16_t get_ma();

	/* return the current value on the RA0-RA4 pins */
	uint8_t get_ra();

	/* simulates the LO->HI clocking of the light pen pin (pin 3) */
	void assert_light_pen_input();

	/* set the clock (pin 21) of the chip */
	void set_clock(int clock);
	void set_clock(const XTAL &xtal) { set_clock(int(xtal.value())); }

	/* set number of pixels per video memory address */
	void set_hpixels_per_column(int hpixels_per_column);

	/* updates the screen -- this will call begin_update(),
	   followed by update_row() repeatedly and after all row
	   updating is complete, end_update() */
	uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);

protected:
	mc6845_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void device_post_load() override;
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;

	bool m_supports_disp_start_addr_r;
	bool m_supports_vert_sync_width;
	bool m_supports_status_reg_d5;
	bool m_supports_status_reg_d6;
	bool m_supports_status_reg_d7;
	bool m_supports_transparent;

	/* register file */
	uint8_t   m_horiz_char_total;     /* 0x00 */
	uint8_t   m_horiz_disp;           /* 0x01 */
	uint8_t   m_horiz_sync_pos;       /* 0x02 */
	uint8_t   m_sync_width;           /* 0x03 */
	uint8_t   m_vert_char_total;      /* 0x04 */
	uint8_t   m_vert_total_adj;       /* 0x05 */
	uint8_t   m_vert_disp;            /* 0x06 */
	uint8_t   m_vert_sync_pos;        /* 0x07 */
	uint8_t   m_mode_control;         /* 0x08 */
	uint8_t   m_max_ras_addr;         /* 0x09 */
	uint8_t   m_cursor_start_ras;     /* 0x0a */
	uint8_t   m_cursor_end_ras;       /* 0x0b */
	uint16_t  m_disp_start_addr;      /* 0x0c/0x0d */
	uint16_t  m_cursor_addr;          /* 0x0e/0x0f */
	uint16_t  m_light_pen_addr;       /* 0x10/0x11 */
	uint16_t  m_update_addr;          /* 0x12/0x13 */

	/* other internal state */
	uint8_t   m_register_address_latch;
	bool    m_cursor_state;
	uint8_t   m_cursor_blink_count;
	bool    m_update_ready_bit;
	/* output signals */
	int     m_cur;
	int     m_hsync;
	int     m_vsync;
	int     m_de;

	/* internal counters */
	uint8_t   m_character_counter;        /* Not used yet */
	uint8_t   m_hsync_width_counter;  /* Not used yet */
	uint8_t   m_line_counter;
	uint8_t   m_raster_counter;
	uint8_t   m_adjust_counter;
	uint8_t   m_vsync_width_counter;

	bool    m_line_enable_ff;       /* Internal flip flop which is set when the line_counter is reset and reset when vert_disp is reached */
	uint8_t   m_vsync_ff;
	uint8_t   m_adjust_active;
	uint16_t  m_line_address;
	int16_t   m_cursor_x;

	/* timers */
	static const device_timer_id TIMER_LINE = 0;
	static const device_timer_id TIMER_DE_OFF = 1;
	static const device_timer_id TIMER_CUR_ON = 2;
	static const device_timer_id TIMER_CUR_OFF = 3;
	static const device_timer_id TIMER_HSYNC_ON = 4;
	static const device_timer_id TIMER_HSYNC_OFF = 5;
	static const device_timer_id TIMER_LIGHT_PEN_LATCH = 6;
	static const device_timer_id TIMER_UPD_ADR = 7;
	static const device_timer_id TIMER_UPD_TRANS = 8;

	emu_timer *m_line_timer;
	emu_timer *m_de_off_timer;
	emu_timer *m_cur_on_timer;
	emu_timer *m_cur_off_timer;
	emu_timer *m_hsync_on_timer;
	emu_timer *m_hsync_off_timer;
	emu_timer *m_light_pen_latch_timer;
	emu_timer *m_upd_adr_timer;
	emu_timer *m_upd_trans_timer;

	/* computed values - do NOT state save these! */
	/* These computed are used to define the screen parameters for a driver */
	uint16_t  m_horiz_pix_total;
	uint16_t  m_vert_pix_total;
	uint16_t  m_max_visible_x;
	uint16_t  m_max_visible_y;
	uint16_t  m_hsync_on_pos;
	uint16_t  m_hsync_off_pos;
	uint16_t  m_vsync_on_pos;
	uint16_t  m_vsync_off_pos;
	bool    m_has_valid_parameters;

	uint16_t   m_current_disp_addr;   /* the display address currently drawn (used only in mc6845_update) */

	bool     m_light_pen_latched;
	attotime m_upd_time;

	void update_upd_adr_timer();
	void call_on_update_address(int strobe);
	void transparent_update();
	void recompute_parameters(bool postload);
	void update_counters();
	void set_de(int state);
	void set_hsync(int state);
	void set_vsync(int state);
	void set_cur(int state);
	void handle_line_timer();
	virtual void update_cursor_state();
	virtual uint8_t draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect);

	/************************
	 interface CRTC - driver
	 ************************/

	bool m_show_border_area;        /* visible screen area (false) active display (true) active display + blanking */
	int m_noninterlace_adjust;      /* adjust max ras in non-interlace mode */
	int m_interlace_adjust;         /* adjust max ras in interlace mode */

	/* visible screen area adjustment */
	int m_visarea_adjust_min_x;
	int m_visarea_adjust_max_x;
	int m_visarea_adjust_min_y;
	int m_visarea_adjust_max_y;

	int m_hpixels_per_column;       /* number of pixels per video memory address */

	reconfigure_delegate m_reconfigure_cb;

	/* if specified, this gets called before any pixel update,
	 optionally return a pointer that will be passed to the
	 update and tear down callbacks */
	begin_update_delegate m_begin_update_cb;

	/* this gets called for every row, the driver must output
	 x_count * hpixels_per_column pixels.
	 cursor_x indicates the character position where the cursor is, or -1
	 if there is no cursor on this row */
	update_row_delegate  m_update_row_cb;

	/* if specified, this gets called after all row updating is complete */
	end_update_delegate  m_end_update_cb;

	/* Called whenever the update address changes
	 * For vblank/hblank timing strobe indicates the physical update.
	 * vblank/hblank timing not supported yet! */
	on_update_addr_changed_delegate m_on_update_addr_changed_cb;

	/* if specified, this gets called for every change of the display enable pin (pin 18) */
	devcb_write_line            m_out_de_cb;

	/* if specified, this gets called for every change of the cursor pin (pin 19) */
	devcb_write_line            m_out_cur_cb;

	/* if specified, this gets called for every change of the HSYNC pin (pin 39) */
	devcb_write_line            m_out_hsync_cb;

	/* if specified, this gets called for every change of the VSYNC pin (pin 40) */
	devcb_write_line            m_out_vsync_cb;
};


class mc6845_1_device : public mc6845_device
{
public:
	mc6845_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class r6545_1_device : public mc6845_device
{
public:
	r6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class c6545_1_device : public mc6845_device
{
public:
	c6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class h46505_device : public mc6845_device
{
public:
	h46505_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class hd6845_device : public mc6845_device
{
public:
	hd6845_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class sy6545_1_device : public mc6845_device
{
public:
	sy6545_1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class sy6845e_device : public mc6845_device
{
public:
	sy6845e_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

// HD6345/HD6445 CRTC-II
// http://bitsavers.informatik.uni-stuttgart.de/pdf/hitachi/_dataBooks/1987_Hitachi_8_16_Bit_Peripheral_LSI_Data_Book.pdf, pp. 99
class hd6345_device : public mc6845_device
{
public:
	hd6345_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	DECLARE_WRITE8_MEMBER(address_w);
	DECLARE_READ8_MEMBER(register_r);
	DECLARE_WRITE8_MEMBER(register_w);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class ams40041_device : public mc6845_device
{
public:
	ams40041_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class ams40489_device : public mc6845_device
{
public:
	ams40489_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	virtual void device_start() override;
	virtual void device_reset() override;
};

class mos8563_device : public mc6845_device,
						public device_memory_interface,
						public device_palette_interface
{
public:
	mos8563_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	DECLARE_WRITE8_MEMBER( address_w );
	DECLARE_READ8_MEMBER( status_r );
	DECLARE_READ8_MEMBER( register_r );
	DECLARE_WRITE8_MEMBER( register_w );

	inline uint8_t read_videoram(offs_t offset);
	inline void write_videoram(offs_t offset, uint8_t data);

	MC6845_UPDATE_ROW( vdc_update_row );

protected:
	mos8563_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);

	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;
	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;

	// device_memory_interface overrides
	virtual space_config_vector memory_space_config() const override;

	// device_palette_interface overrides
	virtual uint32_t palette_entries() const override { return 16; }

	const address_space_config      m_videoram_space_config;

	uint8_t m_char_buffer[80];
	uint8_t m_attr_buffer[80];

	bool    m_char_blink_state;
	uint8_t   m_char_blink_count;

	/* register file */
	uint16_t  m_attribute_addr;       /* 0x14/0x15 */
	uint8_t   m_horiz_char;           /* 0x16 */
	uint8_t   m_vert_char_disp;       /* 0x17 */
	uint8_t   m_vert_scroll;          /* 0x18 */
	uint8_t   m_horiz_scroll;         /* 0x19 */
	uint8_t   m_color;                /* 0x1a */
	uint8_t   m_row_addr_incr;        /* 0x1b */
	uint8_t   m_char_base_addr;       /* 0x1c */
	uint8_t   m_underline_ras;        /* 0x1d */
	uint8_t   m_word_count;           /* 0x1e */
	uint8_t   m_data;                 /* 0x1f */
	uint16_t  m_block_addr;           /* 0x20/0x21 */
	uint16_t  m_de_begin;             /* 0x22/0x23 */
	uint8_t   m_dram_refresh;         /* 0x24 */
	uint8_t   m_sync_polarity;        /* 0x25 */

	int m_revision;

	virtual void update_cursor_state() override;
	virtual uint8_t draw_scanline(int y, bitmap_rgb32 &bitmap, const rectangle &cliprect) override;

	static const device_timer_id TIMER_BLOCK_COPY = 9;

	emu_timer *m_block_copy_timer;

	void mos8563_videoram_map(address_map &map);
};

class mos8568_device : public mos8563_device
{
public:
	mos8568_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

protected:
	// device-level overrides
	virtual void device_start() override;
	virtual void device_reset() override;
};


DECLARE_DEVICE_TYPE(MC6845,   mc6845_device)
DECLARE_DEVICE_TYPE(MC6845_1, mc6845_1_device)
DECLARE_DEVICE_TYPE(R6545_1,  r6545_1_device)
DECLARE_DEVICE_TYPE(C6545_1,  c6545_1_device)
DECLARE_DEVICE_TYPE(H46505,   h46505_device)
DECLARE_DEVICE_TYPE(HD6845,   hd6845_device)
DECLARE_DEVICE_TYPE(SY6545_1, sy6545_1_device)
DECLARE_DEVICE_TYPE(SY6845E,  sy6845e_device)
DECLARE_DEVICE_TYPE(HD6345,   hd6345_device)
DECLARE_DEVICE_TYPE(AMS40041, ams40041_device)
DECLARE_DEVICE_TYPE(AMS40489, ams40489_device)
DECLARE_DEVICE_TYPE(MOS8563,  mos8563_device)
DECLARE_DEVICE_TYPE(MOS8568,  mos8568_device)

#endif // MAME_VIDEO_MC6845_H