1 /*
2 * KCemu -- The emulator for the KC85 homecomputer series and much more.
3 * Copyright (C) 1997-2010 Torsten Paul
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <ctype.h>
21 #include <stdio.h>
22
23 #include "kc/system.h"
24
25 #include "kc/kc.h"
26 #include "kc/z80.h"
27 #include "kc/gdc.h"
28
29 #include "libdbg/dbg.h"
30
31 using namespace std;
32
GDC(void)33 GDC::GDC(void) : InterfaceCircuit("VIS")
34 {
35 reset(true);
36 z80->register_ic(this);
37 }
38
~GDC(void)39 GDC::~GDC(void)
40 {
41 z80->unregister_ic(this);
42 }
43
44 byte_t
in(word_t addr)45 GDC::in(word_t addr)
46 {
47 byte_t val = 0xff;
48
49 switch (addr & 0x01)
50 {
51 case 0x00:
52 /*
53 * status register
54 *
55 * bit 0 (0x01): 0 not ready, 1 ready ? [17a1h]
56 * bit 1 (0x02): 0 ready, 1 not ready ? [1fa7h]
57 * bit 2 (0x04): 0 not ready, 1 ready ? [1797h]
58 * bit 5 (0x20): 1 while vertical retrace
59 */
60 val = _control;
61 break;
62 case 0x01:
63 if ((_cmd & 0xe4) == 0xa0)
64 {
65 if ((_ridx & 1) == 0)
66 val = _mem[_ptr];
67 else
68 {
69 val = _col[_ptr];
70 _ptr = (_ptr + 1) & 0xffff;
71 }
72 //printf("RDAT: %4d, ptr = %04x, val = %02x\n", _ridx, _ptr, val);
73 }
74 else if (_cmd == 0xe0)
75 {
76 switch (_ridx)
77 {
78 case 0: val = _ptr & 0xff; break;
79 case 1: val = (_ptr >> 8) & 0xff; break;
80 default:
81 val = 0;
82 break;
83 }
84 //printf("CURD: %4d, ptr = %04x, val = %02x\n", _ridx, _ptr, val);
85 }
86 else
87 val = _mem[_ptr];
88
89 _ridx++;
90 DBG(2, form("KCemu/GDC/in_data",
91 "GDC::in(): %04xh cmd = %02x, val = %02x\n",
92 addr, _cmd, val));
93 default:
94 break;
95 }
96
97 DBG(2, form("KCemu/GDC/in",
98 "GDC::in(): %04xh val = %02x\n",
99 addr, val));
100
101 return val;
102 }
103
104 void
out(word_t addr,byte_t val)105 GDC::out(word_t addr, byte_t val)
106 {
107 switch (addr & 0x01)
108 {
109 case 0x00:
110 _arg[_idx++] = val;
111 break;
112 case 0x01:
113 info();
114 _idx = 0;
115 _ridx = 0;
116 _cmd = val;
117 break;
118 }
119
120 DBG(2, form("KCemu/GDC/out",
121 "GDC::out(): %04xh: %04xh val = %02x [%c]\n",
122 z80->getPC(), addr, val, isprint(val) ? val : '.'));
123
124 if (_cmd == 0x00) // RESET
125 _screen_on = 0;
126
127 if ((_cmd & 0xfe) == 0x0e) // SYNC
128 _screen_on = _cmd & 1;
129
130 if ((_cmd & 0xfe) == 0x6e) // VSYNC
131 ;
132
133 if ((_cmd == 0x4b) && (_idx == 3)) // CCHAR
134 {
135 _nr_of_lines = _arg[0] & 0x1f;
136 _cursor_top = _arg[1] & 0x1f;
137 _cursor_bottom = (_arg[2] & 0xf8) >> 3;
138 }
139
140 if (_cmd == 0x6b) // START
141 ;
142
143 if ((_cmd & 0xfe) == 0x0c) // BCTRL
144 _screen_on = _cmd & 1;
145
146 if (_cmd == 0x46) // ZOOM
147 ;
148
149 if (_cmd == 0x49) // CURS
150 {
151 if (_idx == 2)
152 {
153 _ptr = ((int)_arg[1] * 256 + _arg[0]);
154 _pptr = 0;
155 }
156 else if (_idx == 3)
157 {
158 _ptr = (_ptr & 0xffff) | ((_arg[2] & 0x03) << 16);
159 _pptr = (_arg[2] >> 4) & 0x0f;
160 _mask = 1 << _pptr;
161 _mask_c = _mask >> 8;
162 }
163 }
164
165 if (((_cmd & 0xf0) == 0x70) && (_idx > 0)) // PRAM
166 {
167 int idx = (_cmd & 0x0f) + _idx - 1;
168 if (idx < 16)
169 _pram[idx] = val;
170 }
171
172 if (_cmd == 0x47) // PITCH
173 ;
174
175 if (((_cmd & 0xe4) == 0x20) && (_idx > 0)) // WDAT
176 {
177 switch (_cmd & 0x18)
178 {
179 case 0x00: /* type 00 - two byte transfer */
180 if (_idx & 1)
181 _mem[_ptr] = (_mask & val) | (~_mask & _mem[_ptr]);
182 else
183 {
184 _col[_ptr] = (_mask_c & val) | (~_mask_c & _col[_ptr]);
185 _ptr = (_ptr + 1) & 0xffff;
186 while ((_idx == 2) && _figs_dc > 0)
187 {
188 _mem[_ptr] = (_mask & _arg[0]) | (~_mask & _mem[_ptr]);
189 _col[_ptr] = (_mask_c & _arg[1]) | (~_mask_c & _col[_ptr]);
190 _ptr = (_ptr + 1) & 0xffff;
191 _figs_dc--;
192 }
193 }
194 break;
195 case 0x08: /* type 01 - invalid */
196 break;
197 case 0x10: /* type 10 - low byte of word */
198 _mem[_ptr] = (_mask & val) | (~_mask & _mem[_ptr]);
199 _ptr = (_ptr + 1) & 0xffff;
200 break;
201 case 0x18: /* type 11 - high byte of word */
202 _col[_ptr] = (_mask_c & val) | (~_mask_c & _col[_ptr]);
203 _ptr = (_ptr + 1) & 0xffff;
204 break;
205 }
206 }
207
208 if ((_cmd == 0x4a) && (_idx > 0)) // MASK
209 {
210 if (_idx == 1)
211 {
212 /*
213 * the z1013 gdc driver only loads the lower byte
214 * into the mask register :-(
215 */
216 _mask = _arg[0];
217 }
218 else
219 {
220 _mask = _arg[0] | (_arg[1] << 8);
221 _mask_c = _arg[1];
222 }
223 }
224
225 if ((_cmd == 0x4c) && (_idx > 2)) // FIGS
226 _figs_dc = _arg[1] | ((_arg[2] & 0x3f) << 8);
227
228 if (_cmd == 0x6c) // FIGD
229 ;
230
231 if (_cmd == 0x68) // GCHRD
232 ;
233
234 if ((_cmd & 0xe4) == 0xa0) // RDAT
235 _figs_dc = 0;
236
237 if (_cmd == 0xe0) // CURD
238 ;
239
240 if (_cmd == 0xc0) // LPRD
241 ;
242
243 if ((_cmd & 0xe4) == 0xa4) // DMAR
244 ;
245
246 if ((_cmd & 0xe4) == 0x24) // DMAW
247 ;
248 }
249
250 byte_t
get_mem(int addr)251 GDC::get_mem(int addr)
252 {
253 return _mem[addr & 0xffff];
254 }
255
256 byte_t
get_col(int addr)257 GDC::get_col(int addr)
258 {
259 return _col[addr & 0xffff];
260 }
261
262 bool
get_cursor(int addr)263 GDC::get_cursor(int addr)
264 {
265 if (addr != _ptr)
266 return false;
267
268 return true;
269 }
270
271 bool
get_cursor(int addr,int line)272 GDC::get_cursor(int addr, int line)
273 {
274 if (addr != _ptr)
275 return false;
276
277 if (line < _cursor_top)
278 return false;
279
280 if (line > _cursor_bottom)
281 return false;
282
283 return true;
284 }
285
286 int
get_nr_of_lines(void)287 GDC::get_nr_of_lines(void)
288 {
289 return _nr_of_lines;
290 }
291
292 int
get_screen_on(void)293 GDC::get_screen_on(void)
294 {
295 return _screen_on;
296 }
297
298 long
get_pram_SAD(int idx)299 GDC::get_pram_SAD(int idx)
300 {
301 if ((idx < 0) || (idx > 3))
302 return 0;
303
304 return _pram[4 * idx] | (_pram[4 * idx + 1] << 8) | ((_pram[4 * idx + 2] & 3) << 16);
305 }
306
307 long
get_pram_LEN(int idx)308 GDC::get_pram_LEN(int idx)
309 {
310 if ((idx < 0) || (idx > 3))
311 return 0;
312
313 return ((_pram[4 * idx + 2] & 0xf0) >> 4) | ((_pram[4 * idx + 3] & 0x3f) << 4);
314 }
315
316 void
v_retrace(bool value)317 GDC::v_retrace(bool value)
318 {
319 if (value)
320 _control |= 0x20;
321 else
322 _control &= ~0x20;
323 }
324
325 void
info(void)326 GDC::info(void)
327 {
328 switch (_cmd)
329 {
330 case 0x00:
331 DBG(2, form("KCemu/GDC/RESET",
332 "GDC: RESET ------------------------------- %02x\n"
333 "GDC: RESET mode %s\n"
334 "GDC: RESET -------------------------------\n",
335 _cmd,
336 ((_arg[0] & 0x20) ?
337 ((_arg[0] & 0x02) ? " invalid" : "character") :
338 ((_arg[0] & 0x02) ? " graphic": " mixed"))
339 ));
340 break;
341
342 case 0x0e: case 0x0f:
343 DBG(2, form("KCemu/GDC/SYNC",
344 "GDC: SYNC -------------------------------- %02x\n"
345 "GDC: SYNC display on/off %s\n"
346 "GDC: SYNC mode (C/G) %s (%d/%d)\n"
347 "GDC: SYNC retrace (I/S) %s (%d/%d)\n"
348 "GDC: SYNC refresh (D) %s\n"
349 "GDC: SYNC drawing (F) %s\n"
350 "GDC: SYNC --------------------------------\n",
351 _cmd,
352 (_cmd & 1) ? " on" : "off",
353
354 ((_arg[0] & 0x20) ?
355 ((_arg[0] & 0x02) ? " invalid" : "character") :
356 ((_arg[0] & 0x02) ? " graphic" : " mixed")),
357 (_arg[0] & 0x20) >> 5, // C
358 (_arg[0] & 0x02) >> 1, // G
359
360 ((_arg[0] & 0x08) ?
361 ((_arg[0] & 0x01) ? "zeilensprung" : "doppelbild") :
362 ((_arg[0] & 0x01) ? "invalid" : "kein zeilensprung")),
363 (_arg[0] & 0x08) >> 3, // I
364 (_arg[0] & 0x01), // S
365
366 ((_arg[0] & 0x04) ? "yes" : " no"),
367
368 ((_arg[0] & 0x10) ? "retrace only" : " always")
369 ));
370 break;
371
372 case 0x6e: case 0x6f:
373 DBG(2, form("KCemu/GDC/VSYNC",
374 "GDC: VSYNC ------------------------------- %02x\n"
375 "GDC: VSYNC external sync %s\n"
376 "GDC: VSYNC -------------------------------\n",
377 _cmd,
378 (_cmd & 1) ? "master" : " slave"));
379 break;
380
381 case 0x4b:
382 DBG(2, form("KCemu/GDC/CCHAR",
383 "GDC: CCHAR ------------------------------- %02x\n"
384 "GDC: CCHAR display cursor %s\n"
385 "GDC: CCHAR number of lines %5d\n"
386 "GDC: CCHAR cursor top %5d\n"
387 "GDC: CCHAR cursor bottom %5d\n"
388 "GDC: CCHAR steady cursor %s\n"
389 "GDC: CCHAR cursor blink frequency %5d\n"
390 "GDC: CCHAR -------------------------------\n",
391 _cmd,
392 (_arg[0] & 0x80) ? " on" : "off",
393 _nr_of_lines,
394 _cursor_top,
395 _cursor_bottom,
396 (_arg[1] & 0x20) ? " on" : "off",
397 ((_arg[1] & 0xc0) >> 6) | ((_arg[2] & 0x07) << 2)));
398 break;
399
400 case 0x6b:
401 DBG(2, form("KCemu/GDC/START",
402 "GDC: START ------------------------------- %02x\n"
403 "GDC: START -------------------------------\n",
404 _cmd));
405 break;
406
407 case 0x0c: case 0x0d:
408 DBG(2, form("KCemu/GDC/BCTRL",
409 "GDC: BCTRL ------------------------------- %02x\n"
410 "GDC: BCTRL display on/off %s\n"
411 "GDC: BCTRL -------------------------------\n",
412 _cmd,
413 (_cmd & 1) ? " on" : "off"));
414 break;
415
416 case 0x46:
417 DBG(2, form("KCemu/GDC/ZOOM",
418 "GDC: ZOOM -------------------------------- %02x\n"
419 "GDC: ZOOM --------------------------------\n",
420 _cmd));
421 break;
422
423 case 0x49:
424 DBG(2, form("KCemu/GDC/CURS",
425 "GDC: CURS -------------------------------- %02x\n"
426 "GDC: CURS set cursor to addr: %05x\n"
427 "GDC: CURS point address: %02x\n"
428 "GDC: CURS --------------------------------\n",
429 _cmd,
430 _ptr,
431 _pptr));
432 break;
433
434 case 0x70: case 0x71: case 0x72: case 0x73:
435 case 0x74: case 0x75: case 0x76: case 0x77:
436 case 0x78: case 0x79: case 0x7a: case 0x7b:
437 case 0x7c: case 0x7d: case 0x7e: case 0x7f:
438 DBG(2, form("KCemu/GDC/PRAM",
439 "GDC: PRAM -------------------------------- %02x\n"
440 "GDC: PRAM write starting at register %2d\n"
441 "GDC: PRAM register 0: %04x %04x %04x %04x\n"
442 "GDC: PRAM register 4: %04x %04x %04x %04x\n"
443 "GDC: PRAM register 8: %04x %04x %04x %04x\n"
444 "GDC: PRAM register 12: %04x %04x %04x %04x\n"
445 "GDC: PRAM SAD/LEN 1 %010x/%010x\n"
446 "GDC: PRAM IM/WD 1 %s/%d\n"
447 "GDC: PRAM SAD/LEN 2 %010x/%010x\n"
448 "GDC: PRAM IM/WD 2 %s/%d\n"
449 "GDC: PRAM SAD/LEN 3 %010x/%010x\n"
450 "GDC: PRAM IM/WD 3 %s/%d\n"
451 "GDC: PRAM SAD/LEN 4 %010x/%010x\n"
452 "GDC: PRAM IM/WD 4 %s/%d\n"
453 "GDC: PRAM --------------------------------\n",
454 _cmd,
455
456 _cmd & 15,
457 _pram[ 0], _pram[ 1], _pram[ 2], _pram[ 3],
458 _pram[ 4], _pram[ 5], _pram[ 6], _pram[ 7],
459 _pram[ 8], _pram[ 9], _pram[10], _pram[11],
460 _pram[12], _pram[13], _pram[14], _pram[15],
461
462 _pram[0] | (_pram[1] << 8) | ((_pram[2] & 3) << 16),
463 ((_pram[2] & 0xf0) >> 4) | ((_pram[3] & 0x3f) << 4),
464 ((_pram[3] & 0x40) >> 6) ? " graphic" : "character",
465 (_pram[3] & 0x80) >> 7,
466
467 _pram[4] | (_pram[5] << 8) | ((_pram[6] & 3) << 16),
468 ((_pram[6] & 0xf0) >> 4) | ((_pram[7] & 0x3f) << 4),
469 ((_pram[7] & 0x40) >> 6) ? " graphic" : "character",
470 (_pram[7] & 0x80) >> 7,
471
472 _pram[8] | (_pram[9] << 8) | ((_pram[10] & 3) << 16),
473 ((_pram[10] & 0xf0) >> 4) | ((_pram[11] & 0x3f) << 4),
474 ((_pram[11] & 0x40) >> 6) ? " graphic" : "character",
475 (_pram[11] & 0x80) >> 7,
476
477 _pram[12] | (_pram[13] << 8) | ((_pram[14] & 3) << 16),
478 ((_pram[14] & 0xf0) >> 4) | ((_pram[15] & 0x3f) << 4),
479 ((_pram[15] & 0x40) >> 6) ? " graphic" : "character",
480 (_pram[15] & 0x80) >> 7));
481 break;
482
483 case 0x47:
484 DBG(2, form("KCemu/GDC/PITCH",
485 "GDC: PITCH ------------------------------- %02x\n"
486 "GDC: PITCH line width %5d\n"
487 "GDC: PITCH -------------------------------\n",
488 _cmd,
489 _arg[0]));
490 break;
491
492 case 0x20: case 0x21: case 0x22: case 0x23:
493 case 0x28: case 0x29: case 0x2a: case 0x2b:
494 case 0x30: case 0x31: case 0x32: case 0x33:
495 case 0x38: case 0x39: case 0x3a: case 0x3b:
496 DBG(2, form("KCemu/GDC/WDAT",
497 "GDC: WDAT -------------------------------- %02x\n"
498 "GDC: WDAT type %d\n"
499 "GDC: WDAT MOD %d\n"
500 "GDC: WDAT arg[0] 0x%02x\n"
501 "GDC: WDAT arg[1] 0x%02x\n"
502 "GDC: WDAT --------------------------------\n",
503 _cmd,
504 (_cmd & 0x18) >> 3,
505 (_cmd & 3),
506 _arg[0],
507 _arg[1]));
508 break;
509
510 case 0x4a:
511 DBG(2, form("KCemu/GDC/MASK",
512 "GDC: MASK -------------------------------- %02x\n"
513 "GDC: MASK mask %04x\n"
514 "GDC: MASK --------------------------------\n",
515 _cmd,
516 _mask));
517 break;
518
519 case 0x4c:
520 DBG(2, form("KCemu/GDC/FIGS",
521 "GDC: FIGS -------------------------------- %02x\n"
522 "GDC: FIGS count %05d\n"
523 "GDC: FIGS --------------------------------\n",
524 _cmd,
525 _figs_dc));
526 break;
527
528 case 0x6c:
529 DBG(2, form("KCemu/GDC/FIGD",
530 "GDC: FIGD -------------------------------- %02x\n"
531 "GDC: FIGD --------------------------------\n",
532 _cmd));
533 break;
534
535 case 0x68:
536 DBG(2, form("KCemu/GDC/GCHRD",
537 "GDC: GCHRD ------------------------------- %02x\n"
538 "GDC: GCHRD -------------------------------\n",
539 _cmd));
540 break;
541
542 case 0xa0: case 0xa1: case 0xa2: case 0xa3:
543 case 0xa8: case 0xa9: case 0xaa: case 0xab:
544 case 0xb0: case 0xb1: case 0xb2: case 0xb3:
545 case 0xb8: case 0xb9: case 0xba: case 0xbb:
546 DBG(2, form("KCemu/GDC/RDAT",
547 "GDC: RDAT -------------------------------- %02x\n"
548 "GDC: RDAT type %d\n"
549 "GDC: RDAT MOD %d\n"
550 "GDC: RDAT --------------------------------\n",
551 _cmd,
552 (_cmd & 0x18) >> 3,
553 (_cmd & 3)));
554 break;
555
556 case 0xe0:
557 DBG(2, form("KCemu/GDC/CURD",
558 "GDC: CURD -------------------------------- %02x\n"
559 "GDC: CURD --------------------------------\n",
560 _cmd));
561 break;
562
563 case 0xc0:
564 DBG(2, form("KCemu/GDC/LPRD",
565 "GDC: LPRD -------------------------------- %02x\n"
566 "GDC: LPRD --------------------------------\n",
567 _cmd));
568 break;
569
570 case 0xa4: case 0xa5: case 0xa6: case 0xa7:
571 case 0xac: case 0xad: case 0xae: case 0xaf:
572 case 0xb4: case 0xb5: case 0xb6: case 0xb7:
573 case 0xbc: case 0xbd: case 0xbe: case 0xbf:
574 DBG(2, form("KCemu/GDC/DMAR",
575 "GDC: DMAR -------------------------------- %02x\n"
576 "GDC: DMAR type %d\n"
577 "GDC: DMAR MOD %d\n"
578 "GDC: DMAR --------------------------------\n",
579 _cmd,
580 (_cmd & 0x18) >> 3,
581 (_cmd & 3)));
582 break;
583
584 case 0x24: case 0x25: case 0x26: case 0x27:
585 case 0x2c: case 0x2d: case 0x2e: case 0x2f:
586 case 0x34: case 0x35: case 0x36: case 0x37:
587 case 0x3c: case 0x3d: case 0x3e: case 0x3f:
588 DBG(2, form("KCemu/GDC/DMAW",
589 "GDC: DMAW -------------------------------- %02x\n"
590 "GDC: DMAW type %d\n"
591 "GDC: DMAW MOD %d\n"
592 "GDC: DMAW --------------------------------\n",
593 _cmd,
594 (_cmd & 0x18) >> 3,
595 (_cmd & 3)));
596 break;
597
598 default:
599 cout << "CMD: 0x" << hex << (int)_cmd << " -";
600 for (int a = 0;a < _idx;a++)
601 cout << " 0x" << hex << (int)_arg[a];
602 cout << endl;
603 }
604 }
605
606 void
reti(void)607 GDC::reti(void)
608 {
609 }
610
611 void
irqreq(void)612 GDC::irqreq(void)
613 {
614 }
615
616 word_t
irqack(void)617 GDC::irqack(void)
618 {
619 return IRQ_NOT_ACK;
620 }
621
622 void
reset(bool power_on)623 GDC::reset(bool power_on)
624 {
625 _idx = 0;
626 _ptr = 0;
627 _pptr = 0;
628 _mask = 0;
629 _mask_c = 0;
630 _control = 5;
631 _figs_dc = 0;
632 _screen_on = 0;
633 _nr_of_lines = 0;
634 _cursor_top = 1;
635 _cursor_bottom = 0;
636
637 memset(_pram, 0, 16);
638 memset(_mem, 0x20, 65536); // FIXME: handle screen blanking
639 memset(_col, 0x00, 65536);
640 }
641