summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/crtc_ega.h
blob: e5a267bed902a65a07ff38bb7a3b7c2385a84598 (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
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol
/**********************************************************************

    IBM EGA CRT Controller emulation

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

#ifndef MAME_VIDEO_CRTC_EGA_H
#define MAME_VIDEO_CRTC_EGA_H


#define CRTC_EGA_BEGIN_UPDATE(_name) void _name(bitmap_ind16 &bitmap, const rectangle &cliprect)
#define CRTC_EGA_ROW_UPDATE(_name)   void _name(bitmap_ind16 &bitmap,    \
												const rectangle &cliprect, uint16_t ma, uint8_t ra,                 \
												uint16_t y, uint8_t x_count, int8_t cursor_x)
#define CRTC_EGA_END_UPDATE(_name)   void _name(bitmap_ind16 &bitmap, const rectangle &cliprect)


class crtc_ega_device : public device_t,
						public device_video_interface
{
public:
	/* callback definitions */
	typedef device_delegate<void (bitmap_ind16 &bitmap, const rectangle &cliprect)> begin_update_delegate;
	typedef device_delegate<void (bitmap_ind16 &bitmap, const rectangle &cliprect, uint16_t ma, uint8_t ra, uint16_t y, uint8_t x_count, int8_t cursor_x)> row_update_delegate;
	typedef device_delegate<void (bitmap_ind16 &bitmap, const rectangle &cliprect)> end_update_delegate;


	crtc_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	auto res_out_de_callback() { return m_res_out_de_cb.bind(); }
	auto res_out_hsync_callback() { return m_res_out_hsync_cb.bind(); }
	auto res_out_vsync_callback() { return m_res_out_vsync_cb.bind(); }
	auto res_out_vblank_callback() { return m_res_out_vblank_cb.bind(); }

	template <typename... T> void set_begin_update_callback(T &&... args) { m_begin_update_cb.set(std::forward<T>(args)...); }
	template <typename... T> void set_row_update_callback(T &&... args) { m_row_update_cb.set(std::forward<T>(args)...); }
	template <typename... T> void set_end_update_callback(T &&... args) { m_end_update_cb.set(std::forward<T>(args)...); }
	void config_set_hpixels_per_column(int hpixels_per_column) { m_hpixels_per_column = hpixels_per_column; }

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

	/* read from the currently selected register */
	uint8_t register_r();

	/* write to the currently selected register */
	void register_w(uint8_t data);

	/* return the current value on the MA0-MA15 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 */
	void assert_light_pen_input();

	/* set the clock of the chip */
	void set_clock(int clock);

	/* 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_ind16 &bitmap, const rectangle &cliprect);

protected:
	// 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;

private:
	devcb_write_line   m_res_out_de_cb;
	devcb_write_line   m_res_out_hsync_cb;
	devcb_write_line   m_res_out_vsync_cb;
	devcb_write_line   m_res_out_vblank_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 */
	row_update_delegate        m_row_update_cb;

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

	/* ega/vga register file */
	uint8_t   m_horiz_char_total; /* 0x00 */
	uint8_t   m_horiz_disp;           /* 0x01 */
	uint8_t   m_horiz_blank_start;    /* 0x02 */
	uint8_t   m_horiz_blank_end;  /* 0x03/0x05 */
	uint8_t   m_ena_vert_access;  /* 0x03 */
	uint8_t   m_de_skew;          /* 0x03 */
	uint8_t   m_horiz_retr_start; /* 0x04 */
	uint8_t   m_horiz_retr_end;       /* 0x05 */
	uint8_t   m_horiz_retr_skew;  /* 0x05 */
	uint16_t  m_vert_total;           /* 0x06/0x07 */
	uint8_t   m_preset_row_scan;  /* 0x08 */
	uint8_t   m_byte_panning;     /* 0x08 */
	uint8_t   m_max_ras_addr;     /* 0x09 */
	uint8_t   m_scan_doubling;        /* 0x09 */
	uint8_t   m_cursor_start_ras; /* 0x0a */
	uint8_t   m_cursor_disable;       /* 0x0a */
	uint8_t   m_cursor_end_ras;       /* 0x0b */
	uint8_t   m_cursor_skew;      /* 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_vert_retr_start;  /* 0x10/0x07 */
	uint8_t   m_vert_retr_end;        /* 0x11 */
	uint8_t   m_protect;          /* 0x11 */
	uint8_t   m_bandwidth;            /* 0x11 */
	uint16_t  m_vert_disp_end;        /* 0x12/0x07 */
	uint8_t   m_offset;               /* 0x13 */
	uint8_t   m_underline_loc;        /* 0x14 */
	uint16_t  m_vert_blank_start; /* 0x15/0x07/0x09 */
	uint8_t   m_vert_blank_end;       /* 0x16 */
	uint8_t   m_mode_control;     /* 0x17 */
	uint16_t  m_line_compare;     /* 0x18/0x07/0x09 */

	/* other internal state */
	uint8_t   m_register_address_latch;
	bool    m_cursor_state; /* 0 = off, 1 = on */
	uint8_t   m_cursor_blink_count;
	int     m_hpixels_per_column;       /* number of pixels per video memory address */

	/* output signals */
	int     m_cur;
	int     m_hsync;
	int     m_vsync;
	int     m_vblank;
	int     m_de;

	/* internal counters */
	uint8_t   m_character_counter;
	uint8_t   m_hsync_width_counter;
	uint16_t  m_line_counter;
	uint8_t   m_raster_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 constexpr device_timer_id TIMER_LINE = 0;
	static constexpr device_timer_id TIMER_DE_OFF = 1;
	static constexpr device_timer_id TIMER_CUR_ON = 2;
	static constexpr device_timer_id TIMER_CUR_OFF = 3;
	static constexpr device_timer_id TIMER_HSYNC_ON = 4;
	static constexpr device_timer_id TIMER_HSYNC_OFF = 5;
	static constexpr device_timer_id TIMER_LIGHT_PEN_LATCH = 6;

	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;

	/* computed values - do NOT state save these! */
	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;
	uint16_t  m_current_disp_addr;    /* the display address currently drawn */
	uint8_t   m_light_pen_latched;
	bool    m_has_valid_parameters;

	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_vblank(int state);
	void set_cur(int state);
	void handle_line_timer();
	void update_cursor_state();
};

DECLARE_DEVICE_TYPE(CRTC_EGA, crtc_ega_device)

#endif // MAME_VIDEO_CRTC_EGA_H