fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/chipset/e6845.c *
7 * Created: 2017-08-07 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2017-2022 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include <stdlib.h>
24#include <stdio.h>
25
26#include "e6845.h"
27
28
29#ifndef DEBUG_CRTC
30#define DEBUG_CRTC 0
31#endif
32
33
34void e6845_init (e6845_t *crt)
35{
36 unsigned i;
37
38 crt->ccol = 0;
39 crt->crow = 0;
40 crt->frame = 0;
41 crt->ma = 0;
42 crt->ra = 0;
43 crt->vsync_cnt = 0;
44 crt->index = 0;
45
46 for (i = 0; i < E6845_REG_CNT; i++) {
47 crt->reg[i] = 0;
48 }
49
50 crt->hsync_ext = NULL;
51 crt->hsync_fct = NULL;
52
53 crt->vsync_ext = NULL;
54 crt->vsync_fct = NULL;
55}
56
57void e6845_free (e6845_t *crt)
58{
59}
60
61void e6845_set_hsync_fct (e6845_t *crt, void *ext, void *fct)
62{
63 crt->hsync_ext = ext;
64 crt->hsync_fct = fct;
65}
66
67void e6845_set_vsync_fct (e6845_t *crt, void *ext, void *fct)
68{
69 crt->vsync_ext = ext;
70 crt->vsync_fct = fct;
71}
72
73unsigned e6845_get_start_address (const e6845_t *crt)
74{
75 unsigned val;
76
77 val = crt->reg[E6845_REG_AH];
78 val = (val << 8) | crt->reg[E6845_REG_AL];
79
80 return (val & 0x3fff);
81}
82
83unsigned e6845_get_cursor_address (const e6845_t *crt)
84{
85 unsigned val;
86
87 val = crt->reg[E6845_REG_CH];
88 val = (val << 8) | crt->reg[E6845_REG_CL];
89
90 return (val & 0x3fff);
91}
92
93unsigned e6845_get_cursor_mask (e6845_t *crt, int blink)
94{
95 unsigned mask;
96
97 mask = 0;
98
99 switch ((crt->reg[E6845_REG_CS] >> 5) & 3) {
100 case 0:
101 /* non-blink */
102 blink = 0;
103 break;
104
105 case 1:
106 /* non-display */
107 return (0);
108
109 case 2:
110 /* blink at 1/16 field rate */
111 mask = 16;
112 break;
113
114 case 3:
115 /* blink 1/32 field rate */
116 mask = 32;
117 break;
118 }
119
120 if (blink) {
121 if (crt->frame & mask) {
122 return (0);
123 }
124 }
125
126 if (crt->ra < (crt->reg[E6845_REG_CS] & 0x1f)) {
127 return (0);
128 }
129
130 if (crt->ra > (crt->reg[E6845_REG_CE] & 0x1f)) {
131 return (0);
132 }
133
134 return (~0U);
135}
136
137unsigned e6845_get_vtl (const e6845_t *crt)
138{
139 unsigned val;
140
141 val = (crt->reg[E6845_REG_ML] & 0x1f) + 1;
142 val *= (crt->reg[E6845_REG_VT] & 0x7f) + 1;
143 val += crt->reg[E6845_REG_VA] & 0x1f;
144
145 return (val);
146}
147
148unsigned e6845_get_vdl (const e6845_t *crt)
149{
150 unsigned val;
151
152 val = (crt->reg[E6845_REG_ML] & 0x1f) + 1;
153 val *= crt->reg[E6845_REG_VD] & 0x7f;
154
155 return (val);
156}
157
158unsigned e6845_get_vsl (const e6845_t *crt)
159{
160 unsigned val;
161
162 val = (crt->reg[E6845_REG_ML] & 0x1f) + 1;
163 val *= crt->reg[E6845_REG_VS] & 0x7f;
164
165 return (val);
166}
167
168int e6845_get_hde (const e6845_t *crt)
169{
170 if (crt->ccol < crt->reg[E6845_REG_HD]) {
171 return (1);
172 }
173
174 return (0);
175}
176
177int e6845_get_vde (const e6845_t *crt)
178{
179 if (crt->crow < (crt->reg[E6845_REG_VD] & 0x7f)) {
180 return (1);
181 }
182
183 return (0);
184}
185
186int e6845_get_de (const e6845_t *crt)
187{
188 if (crt->crow >= (crt->reg[E6845_REG_VD] & 0x7f)) {
189 return (0);
190 }
191
192 if (crt->ccol >= crt->reg[E6845_REG_HD]) {
193 return (0);
194 }
195
196 return (1);
197}
198
199void e6845_set_pen (e6845_t *crt)
200{
201 unsigned addr;
202
203 addr = (crt->ma + crt->ccol) & 0x3fff;
204
205 crt->reg[E6845_REG_LH] = (addr >> 8) & 0xff;
206 crt->reg[E6845_REG_LL] = addr & 0xff;
207}
208
209unsigned char e6845_get_index (const e6845_t *crt)
210{
211 return (crt->index);
212}
213
214unsigned char e6845_get_data (e6845_t *crt)
215{
216 if ((crt->index >= 12) && (crt->index <= 17)) {
217 return (crt->reg[crt->index]);
218 }
219
220 return (0);
221}
222
223unsigned char e6845_get_uint8 (e6845_t *crt, unsigned long addr)
224{
225 switch (addr) {
226 case 0:
227 return (e6845_get_index (crt));
228
229 case 1:
230 return (e6845_get_data (crt));
231 }
232
233 return (0);
234}
235
236unsigned short e6845_get_uint16 (e6845_t *crt, unsigned long addr)
237{
238 return (0);
239}
240
241void e6845_set_index (e6845_t *crt, unsigned char val)
242{
243 crt->index = val & 0x1f;
244}
245
246void e6845_set_data (e6845_t *crt, unsigned char val)
247{
248 if (crt->index >= E6845_REG_CNT) {
249 return;
250 }
251
252 crt->reg[crt->index] = val;
253}
254
255void e6845_set_uint8 (e6845_t *crt, unsigned long addr, unsigned char val)
256{
257 switch (addr) {
258 case 0:
259 e6845_set_index (crt, val);
260 break;
261
262 case 1:
263 e6845_set_data (crt, val);
264 break;
265 }
266}
267
268void e6850_set_uint16 (e6845_t *crt, unsigned long addr, unsigned short val)
269{
270}
271
272void e6845_reset (e6845_t *crt)
273{
274 unsigned i;
275
276 crt->ccol = 0;
277 crt->crow = 0;
278 crt->frame = 0;
279 crt->ma = 0;
280 crt->ra = 0;
281 crt->vsync_cnt = 0;
282 crt->index = 0;
283
284 for (i = 0; i < E6845_REG_CNT; i++) {
285 crt->reg[i] = 0;
286 }
287}
288
289static
290void e6845_hsync (e6845_t *crt)
291{
292 if (crt->hsync_fct == NULL) {
293 return;
294 }
295
296 crt->hsync_fct (crt->hsync_ext);
297}
298
299static
300void e6845_vsync (e6845_t *crt)
301{
302 if (crt->vsync_fct == NULL) {
303 return;
304 }
305
306 crt->vsync_fct (crt->vsync_ext);
307}
308
309void e6845_clock (e6845_t *crt, unsigned cnt)
310{
311 unsigned char hs, ht, vs, vt, va;
312
313 hs = crt->reg[E6845_REG_HS];
314 ht = crt->reg[E6845_REG_HT] + 1;
315
316 vs = crt->reg[E6845_REG_VS];
317 vt = crt->reg[E6845_REG_VT] + 1;
318 va = crt->reg[E6845_REG_VA];
319
320 while (cnt > 0) {
321 crt->ccol += 1;
322 cnt -= 1;
323
324 if (crt->ccol == hs) {
325 crt->hsync_cnt = crt->reg[E6845_REG_SW] & 15;
326 e6845_hsync (crt);
327 }
328 else if (crt->hsync_cnt > 0) {
329 crt->hsync_cnt -= 1;
330 }
331
332
333 if (crt->ccol >= ht) {
334 crt->ccol = 0;
335
336 if (crt->vsync_cnt > 0) {
337 crt->vsync_cnt -= 1;
338 }
339
340 crt->ra += 1;
341
342 if (crt->ra > crt->reg[E6845_REG_ML]) {
343 if (crt->crow < vt) {
344 crt->ma += crt->reg[E6845_REG_HD];
345 crt->ra = 0;
346 crt->crow += 1;
347 }
348 }
349
350 if ((crt->crow == vs) && (crt->ra == 0)) {
351 crt->vsync_cnt = 16;
352
353 e6845_vsync (crt);
354
355 crt->frame += 1;
356 crt->ma = e6845_get_start_address (crt);
357 }
358
359 if (((crt->crow == vt) && (crt->ra >= va)) || (crt->crow > vt)) {
360 crt->crow = 0;
361 crt->ma = e6845_get_start_address (crt);
362 crt->ra = 0;
363 }
364 }
365 }
366}