OSDN Git Service

a8a3873ceb9ec397225a4ccf8ea8f67ba1ba58c4
[csp-qt/common_source_project-fm7.git] / source / src / vm / bubcom80 / display.cpp
1 /*
2         Systems Formulate BUBCOM80 Emulator 'eBUBCOM80'
3
4         Author : Takeda.Toshiya
5         Date   : 2018.05.08-
6
7         [ display ]
8 */
9
10 #include "display.h"
11 #include "cmt.h"
12 #include "../pcm1bit.h"
13 #include "../z80.h"
14
15 namespace BUBCOM80 {
16 #define EVENT_BUSREQ    0
17
18 void DISPLAY::initialize()
19 {
20         for(int i = 0; i < 256; i++) {
21                 uint8_t *dest = sg_pattern + 8 * i;
22                 dest[0] = dest[1] = ((i & 0x01) ? 0xf0 : 0) | ((i & 0x02) ? 0x0f : 0);
23                 dest[2] = dest[3] = ((i & 0x04) ? 0xf0 : 0) | ((i & 0x08) ? 0x0f : 0);
24                 dest[4] = dest[5] = ((i & 0x10) ? 0xf0 : 0) | ((i & 0x20) ? 0x0f : 0);
25                 dest[6] = dest[7] = ((i & 0x40) ? 0xf0 : 0) | ((i & 0x80) ? 0x0f : 0);
26         }
27         memset(font, 0x00, sizeof(font));
28         memset(vram, 0x00, sizeof(vram));
29         
30         for(int i = 0; i < 8; i++) {
31                 palette_text_pc [i] = RGBA_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0, 255); // A is a flag for crt filter
32                 palette_graph_pc[i] = RGBA_COLOR((i & 2) ? 255 : 0, (i & 4) ? 255 : 0, (i & 1) ? 255 : 0,   0);
33         }
34         color = true;
35         width40 = false;
36         mode = 0x80;
37         
38         register_frame_event(this);
39         register_vline_event(this);
40 }
41
42 #define STORE_DMAC_CONTEXTS() \
43         DEVICE *d_mem = dmac.mem; \
44         DEVICE *d_ch0 = dmac.ch[0].io; \
45         DEVICE *d_ch1 = dmac.ch[1].io; \
46         DEVICE *d_ch2 = dmac.ch[2].io; \
47         DEVICE *d_ch3 = dmac.ch[3].io
48
49 #define RESTORE_DMAC_CONTEXTS() \
50         dmac.mem = d_mem; \
51         dmac.ch[0].io = d_ch0; \
52         dmac.ch[1].io = d_ch1; \
53         dmac.ch[2].io = d_ch2; \
54         dmac.ch[3].io = d_ch3;
55
56 void DISPLAY::reset()
57 {
58         memset(&crtc, 0, sizeof(crtc));
59         crtc.reset();
60         update_timing();
61         
62         STORE_DMAC_CONTEXTS();
63         memset(&dmac, 0, sizeof(dmac));
64         RESTORE_DMAC_CONTEXTS();
65 }
66
67 void DISPLAY::write_io8(uint32_t addr, uint32_t data)
68 {
69         switch(addr) {
70         case 0x10:
71                 crtc.write_param(data);
72                 if(crtc.timing_changed) {
73                         update_timing();
74                         crtc.timing_changed = false;
75                 }
76                 break;
77         case 0x11:
78                 crtc.write_cmd(data);
79                 break;
80         case 0x20:
81                 d_prn->write_signal(SIG_PRINTER_DATA, data, 0xff);
82                 break;
83         case 0x50:
84                 d_cmt->write_signal(SIG_CMT_REMOTE, data, 0x01);
85                 color = ((data & 0x04) != 0);
86                 width40 = ((data & 0x08) != 0);
87                 d_pcm->write_signal(SIG_PCM1BIT_ON, data, 0x10);
88                 d_prn->write_signal(SIG_PRINTER_STROBE, data, 0x20);
89                 break;
90         case 0x60:
91         case 0x61:
92         case 0x62:
93         case 0x63:
94         case 0x64:
95         case 0x65:
96         case 0x66:
97         case 0x67:
98         case 0x68:
99                 dmac.write_io8(addr, data);
100                 break;
101         case 0x3ff0:
102                 mode = data;
103                 break;
104         default:
105                 if(addr >= 0x800 && addr < 0x1000) {
106                         font[addr & 0x7ff] = data;
107                 } else if(addr >= 0x4000 && addr < 0x10000) {
108                         vram[addr] = data;
109                 }
110                 break;
111         }
112 }
113
114 uint32_t DISPLAY::read_io8(uint32_t addr)
115 {
116         switch(addr) {
117         case 0x10:
118                 return crtc.read_param();
119         case 0x11:
120                 return crtc.read_status();
121         case 0x20:
122                 return d_prn->read_signal(SIG_PRINTER_BUSY) & 0x40;
123         case 0x50:
124                 // bit1: 1=WIDTH80, 0=WIDTH40
125                 return 0xff; // dipswitch???
126         case 0x60:
127         case 0x61:
128         case 0x62:
129         case 0x63:
130         case 0x64:
131         case 0x65:
132         case 0x66:
133         case 0x67:
134         case 0x68:
135                 return dmac.read_io8(addr);
136         case 0x3ff0:
137                 return (crtc.vblank ? 0x40 : 0);
138         default:
139                 if(addr >= 0x800 && addr < 0x1000) {
140                         return font[addr & 0x7ff];
141                 } else if(addr >= 0x4000 && addr < 0x10000) {
142                         return vram[addr];
143                 }
144                 break;
145         }
146         return 0x0f;
147 }
148
149 void DISPLAY::write_dma_io8(uint32_t addr, uint32_t data)
150 {
151         // to crtc
152         crtc.write_buffer(data);
153 }
154
155 void DISPLAY::write_signal(int id, uint32_t data, uint32_t mask)
156 {
157         switch(id) {
158         case SIG_DISPLAY_DMAC_CH0:
159         case SIG_DISPLAY_DMAC_CH1:
160         case SIG_DISPLAY_DMAC_CH2:
161         case SIG_DISPLAY_DMAC_CH3:
162                 if(data & mask) {
163                         if(!dmac.ch[id].running) {
164                                 dmac.start(id);
165                         }
166                         dmac.run(id);
167                 }
168                 break;
169         }
170 }
171
172 void DISPLAY::event_callback(int event_id, int err)
173 {
174         switch(event_id) {
175         case EVENT_BUSREQ:
176                 d_cpu->write_signal(SIG_CPU_BUSREQ, 0, 0);
177                 break;
178         }
179 }
180
181 void DISPLAY::event_frame()
182 {
183         crtc.update_blink();
184 }
185
186 void DISPLAY::event_vline(int v, int clock)
187 {
188         int disp_line = crtc.height * crtc.char_height;
189         
190         if(v == 0) {
191                 if(crtc.status & 0x10) {
192                         // start dma transfer to crtc
193                         dmac.start(2);
194                         if(!dmac.ch[2].running) {
195                                 // dma underrun occurs !!!
196                                 crtc.status |= 8;
197 //                              crtc.status &= ~0x10;
198                         } else {
199                                 crtc.status &= ~8;
200                         }
201                         // dma wait cycles
202                         // from memory access test on PC-8801MA2 (XM8 version 1.20)
203                         busreq_clocks = (int)((double)(dmac.ch[2].count.sd + 1) * 5.95 / (double)disp_line + 0.5);
204                 }
205                 crtc.start();
206         }
207         if(v < disp_line) {
208                 if(/*(crtc.status & 0x10) && */dmac.ch[2].running) {
209                         // bus request
210                         d_cpu->write_signal(SIG_CPU_BUSREQ, 1, 1);
211                         register_event_by_clock(this, EVENT_BUSREQ, busreq_clocks, false, NULL);
212                         // run dma transfer to crtc
213                         if((v % crtc.char_height) == 0) {
214                                 for(int i = 0; i < 80 + crtc.attrib.num * 2; i++) {
215                                         dmac.run(2);
216                                 }
217                         }
218                 }
219         } else if(v == disp_line) {
220                 if(/*(crtc.status & 0x10) && */dmac.ch[2].running) {
221                         dmac.finish(2);
222                 }
223                 crtc.expand_buffer();
224                 crtc.finish();
225         }
226 }
227
228 void DISPLAY::update_timing()
229 {
230         int lines_per_frame = (crtc.height + crtc.vretrace) * crtc.char_height;
231         double frames_per_sec = 15980.0 / (double)lines_per_frame;
232         
233         set_frames_per_sec(frames_per_sec);
234         set_lines_per_frame(lines_per_frame);
235 }
236
237 void DISPLAY::draw_screen()
238 {
239         draw_text();
240         draw_graph();
241         
242         for(int y = 0; y < 200; y++) {
243                 scrntype_t* dest0 = emu->get_screen_buffer(y * 2);
244                 scrntype_t* dest1 = emu->get_screen_buffer(y * 2 + 1);
245                 uint8_t* src_t = text[y];
246                 uint8_t* src_g = graph[y];
247                 
248                 for(int x = 0; x < 640; x++) {
249                         uint32_t t = src_t[x];
250                         uint32_t g = src_g[x];
251                         dest0[x] = t ? palette_text_pc[t & 7] : palette_graph_pc[g ? g : (mode & 7)];
252                 }
253                 if(config.scan_line) {
254                         memset(dest1, 0, 640 * sizeof(scrntype_t));
255                 } else {
256                         for(int x = 0; x < 640; x++) {
257                                 dest1[x] = dest0[x];
258                         }
259                 }
260         }
261         emu->screen_skip_line(true);
262 }
263
264 /*
265         attributes:
266         
267         bit7: graph=1/character=0
268         bit6: green
269         bit5: red
270         bit4: blue
271         bit3: under line
272         bit2: upper line
273         bit1: secret
274         bit0: reverse
275 */
276
277 void DISPLAY::draw_text()
278 {
279         if(crtc.status & 0x88) {
280                 // dma underrun
281                 crtc.status &= ~0x80;
282                 memset(crtc.text.expand, 0, 200 * 80);
283                 memset(crtc.attrib.expand, crtc.reverse ? 3 : 2, 200 * 80);
284         }
285         // for Advanced Fantasian Opening (20line) (XM8 version 1.00)
286         if(!(crtc.status & 0x10)) {
287 //      if(!(crtc.status & 0x10) || (crtc.status & 8)) {
288                 memset(crtc.text.expand, 0, 200 * 80);
289                 for(int y = 0; y < 200; y++) {
290                         for(int x = 0; x < 80; x++) {
291                                 crtc.attrib.expand[y][x] &= 0x70;
292                                 crtc.attrib.expand[y][x] |= 0x02;
293                         }
294                 }
295 //              memset(crtc.attrib.expand, 2, 200 * 80);
296         }
297         
298         // for Xak2 opening
299         memset(text, 8, sizeof(text));
300         
301         int char_height = crtc.char_height;
302         
303         if(crtc.skip_line) {
304                 char_height <<= 1;
305         }
306         for(int cy = 0, ytop = 0; cy < crtc.height && ytop < 200; cy++, ytop += char_height) {
307                 for(int x = 0, cx = 0; cx < crtc.width; x += 8, cx++) {
308                         if(width40 && (cx & 1)) {
309                                 continue;
310                         }
311                         uint8_t attrib = crtc.attrib.expand[cy][cx];
312                         uint8_t color = (attrib & 0x70) ? (attrib >> 4) : 8;
313                         bool under_line = ((attrib & 8) != 0);
314                         bool upper_line = ((attrib & 4) != 0);
315                         bool secret = ((attrib & 2) != 0);
316                         bool reverse = ((attrib & 1) != 0);
317                         
318                         uint8_t code = secret ? 0 : crtc.text.expand[cy][cx];
319                         uint8_t *pattern = ((attrib & 0x80) ? sg_pattern : font) + code * 8;
320                         
321                         for(int l = 0, y = ytop; l < char_height && y < 200; l++, y++) {
322                                 uint8_t pat = (l < 8) ? pattern[l] : 0;
323                                 if((upper_line && l == 0) || (under_line && l >= 7)) {
324                                         pat = 0xff;
325                                 }
326                                 if(reverse) {
327                                         pat ^= 0xff;
328                                 }
329                                 
330                                 uint8_t *dest = &text[y][x];
331                                 if(width40) {
332                                         dest[ 0] = dest[ 1] = (pat & 0x80) ? color : 0;
333                                         dest[ 2] = dest[ 3] = (pat & 0x40) ? color : 0;
334                                         dest[ 4] = dest[ 5] = (pat & 0x20) ? color : 0;
335                                         dest[ 6] = dest[ 7] = (pat & 0x10) ? color : 0;
336                                         dest[ 8] = dest[ 9] = (pat & 0x08) ? color : 0;
337                                         dest[10] = dest[11] = (pat & 0x04) ? color : 0;
338                                         dest[12] = dest[13] = (pat & 0x02) ? color : 0;
339                                         dest[14] = dest[15] = (pat & 0x01) ? color : 0;
340                                 } else {
341                                         dest[0] = (pat & 0x80) ? color : 0;
342                                         dest[1] = (pat & 0x40) ? color : 0;
343                                         dest[2] = (pat & 0x20) ? color : 0;
344                                         dest[3] = (pat & 0x10) ? color : 0;
345                                         dest[4] = (pat & 0x08) ? color : 0;
346                                         dest[5] = (pat & 0x04) ? color : 0;
347                                         dest[6] = (pat & 0x02) ? color : 0;
348                                         dest[7] = (pat & 0x01) ? color : 0;
349                                 }
350                         }
351                 }
352         }
353 }
354
355 void DISPLAY::draw_graph()
356 {
357         uint8_t *vram_b, *vram_r, *vram_g;
358         
359         switch(mode & 0xe0) {
360         case 0x00:
361                 vram_b = vram_r = vram_g = vram + 0x0000; // null
362                 break;
363         case 0xc0:
364                 vram_b = vram_r = vram_g = vram + 0x8000; // blue
365                 break;
366         case 0xe0:
367                 vram_b = vram_r = vram_g = vram + 0xc000; // red
368                 break;
369         case 0xa0:
370                 vram_b = vram_r = vram_g = vram + 0x4000; // green
371                 break;
372         default:
373                 vram_b = vram + 0x8000; // blue
374                 vram_r = vram + 0xc000; // red
375                 vram_g = vram + 0x4000; // green
376                 break;
377         }
378         for(int y = 0, src = 0; y < 200; y ++) {
379                 for(int x = 0; x < 80; x++) {
380                         uint8_t b = vram_b[src];
381                         uint8_t r = vram_r[src];
382                         uint8_t g = vram_g[src];
383                         uint8_t* d = &graph[y][x << 3];
384                         
385                         d[0] = ((b & 0x80) >> 7) | ((r & 0x80) >> 6) | ((g & 0x80) >> 5);
386                         d[1] = ((b & 0x40) >> 6) | ((r & 0x40) >> 5) | ((g & 0x40) >> 4);
387                         d[2] = ((b & 0x20) >> 5) | ((r & 0x20) >> 4) | ((g & 0x20) >> 3);
388                         d[3] = ((b & 0x10) >> 4) | ((r & 0x10) >> 3) | ((g & 0x10) >> 2);
389                         d[4] = ((b & 0x08) >> 3) | ((r & 0x08) >> 2) | ((g & 0x08) >> 1);
390                         d[5] = ((b & 0x04) >> 2) | ((r & 0x04) >> 1) | ((g & 0x04) >> 0);
391                         d[6] = ((b & 0x02) >> 1) | ((r & 0x02) >> 0) | ((g & 0x02) << 1);
392                         d[7] = ((b & 0x01) >> 0) | ((r & 0x01) << 1) | ((g & 0x01) << 2);
393                         
394                         src = (src + 1) & 0x3fff;
395                 }
396         }
397 }
398
399 /* ----------------------------------------------------------------------------
400         CRTC (uPD3301)
401 ---------------------------------------------------------------------------- */
402
403 void crtc_t::reset()
404 {
405         blink.rate = 24;
406         cursor.type = cursor.mode = -1;
407         cursor.x = cursor.y = -1;
408         attrib.data = 0x70;
409         attrib.num = 20;
410         width = 80;
411         height = 25;
412         char_height = 8;
413         skip_line = false;
414         vretrace = 7;
415         timing_changed = false;
416         reverse = 0;
417         intr_mask = 3;
418 }
419
420 void crtc_t::write_cmd(uint8_t data)
421 {
422         cmd = (data >> 5) & 7;
423         cmd_ptr = 0;
424         switch(cmd) {
425         case 0: // reset
426                 status &= ~0x16;
427                 status |= 0x80; // fix
428                 cursor.x = cursor.y = -1;
429                 break;
430         case 1: // start display
431                 reverse = data & 1;
432 //              status |= 0x10;
433                 status |= 0x90; // fix
434                 status &= ~8;
435                 break;
436         case 2: // set interrupt mask
437                 if(!(data & 1)) {
438 //                      status = 0; // from M88
439                         status = 0x80; // fix
440                 }
441                 intr_mask = data & 3;
442                 break;
443         case 3: // read light pen
444                 status &= ~1;
445                 break;
446         case 4: // load cursor position ON/OFF
447                 cursor.type = (data & 1) ? cursor.mode : -1;
448                 break;
449         case 5: // reset interrupt
450                 status &= ~6;
451                 break;
452         case 6: // reset counters
453                 status &= ~6;
454                 break;
455         }
456 }
457
458 void crtc_t::write_param(uint8_t data)
459 {
460         switch(cmd) {
461         case 0:
462                 switch(cmd_ptr) {
463                 case 0:
464                         width = min((data & 0x7f) + 2, 80);
465                         break;
466                 case 1:
467                         if(height != (data & 0x3f) + 1) {
468                                 height = (data & 0x3f) + 1;
469                                 timing_changed = true;
470                         }
471                         blink.rate = 32 * ((data >> 6) + 1);
472                         break;
473                 case 2:
474                         if(char_height != (data & 0x1f) + 1) {
475                                 char_height = (data & 0x1f) + 1;
476                                 timing_changed = true;
477                         }
478                         cursor.mode = (data >> 5) & 3;
479                         skip_line = ((data & 0x80) != 0);
480                         break;
481                 case 3:
482                         if(vretrace != ((data >> 5) & 7) + 1) {
483                                 vretrace = ((data >> 5) & 7) + 1;
484                                 timing_changed = true;
485                         }
486                         break;
487                 case 4:
488                         mode = (data >> 5) & 7;
489                         attrib.num = (mode & 1) ? 0 : min((data & 0x1f) + 1, 20);
490                         break;
491                 }
492                 break;
493         case 4:
494                 switch(cmd_ptr) {
495                 case 0:
496                         cursor.x = data;
497                         break;
498                 case 1:
499                         cursor.y = data;
500                         break;
501                 }
502                 break;
503         case 6:
504                 status = 0;
505                 break;
506         }
507         cmd_ptr++;
508 }
509
510 uint32_t crtc_t::read_param()
511 {
512         uint32_t val = 0xff;
513         
514         switch(cmd) {
515         case 3: // read light pen
516                 switch(cmd_ptr) {
517                 case 0:
518                         val = 0; // fix me
519                         break;
520                 case 1:
521                         val = 0; // fix me
522                         break;
523                 }
524                 break;
525         default:
526                 // XM8 version 1.10
527                 val = read_status();
528                 break;
529         }
530         cmd_ptr++;
531         return val;
532 }
533
534 uint32_t crtc_t::read_status()
535 {
536         if(status & 8) {
537                 return status & ~0x10;
538         } else {
539                 return status;
540         }
541 }
542
543 void crtc_t::start()
544 {
545         memset(buffer, 0, sizeof(buffer));
546         buffer_ptr = 0;
547         vblank = false;
548 }
549
550 void crtc_t::finish()
551 {
552         if((status & 0x10) && !(intr_mask & 1)) {
553                 status |= 2;
554         }
555         vblank = true;
556 }
557
558 void crtc_t::write_buffer(uint8_t data)
559 {
560         buffer[(buffer_ptr++) & 0x3fff] = data;
561 }
562
563 uint8_t crtc_t::read_buffer(int ofs)
564 {
565         if(ofs < buffer_ptr) {
566                 return buffer[ofs];
567         }
568         // dma underrun occurs !!!
569         status |= 8;
570 //      status &= ~0x10;
571         return 0;
572 }
573
574 void crtc_t::update_blink()
575 {
576         // from m88
577         if(++blink.counter > blink.rate) {
578                 blink.counter = 0;
579         }
580         blink.attrib = (blink.counter < blink.rate / 4) ? 2 : 0;
581         blink.cursor = (blink.counter <= blink.rate / 4) || (blink.rate / 2 <= blink.counter && blink.counter <= 3 * blink.rate / 4);
582 }
583
584 void crtc_t::expand_buffer()
585 {
586         int char_height_tmp = char_height;
587         int exitline = -1;
588         
589         if(skip_line) {
590                 char_height_tmp <<= 1;
591         }
592         if(!(status & 0x10)) {
593                 exitline = 0;
594                 goto underrun;
595         }
596         for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
597                 for(int cx = 0; cx < width; cx++) {
598                         text.expand[cy][cx] = read_buffer(ofs + cx);
599                 }
600                 if((status & 8) && exitline == -1) {
601                         exitline = cy;
602 //                      goto underrun;
603                 }
604         }
605         if(mode & 4) {
606                 // non transparent
607                 for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
608                         for(int cx = 0; cx < width; cx += 2) {
609                                 set_attrib(read_buffer(ofs + cx + 1));
610                                 attrib.expand[cy][cx] = attrib.expand[cy][cx + 1] = attrib.data;
611                         }
612                         if((status & 8) && exitline == -1) {
613                                 exitline = cy;
614 //                              goto underrun;
615                         }
616                 }
617         } else {
618                 // transparent
619                 if(mode & 1) {
620                         memset(attrib.expand, 0x70, sizeof(attrib.expand));
621                 } else {
622                         for(int cy = 0, ytop = 0, ofs = 0; cy < height && ytop < 200; cy++, ytop += char_height_tmp, ofs += 80 + attrib.num * 2) {
623                                 uint8_t flags[128];
624                                 memset(flags, 0, sizeof(flags));
625                                 for(int i = 2 * (attrib.num - 1); i >= 0; i -= 2) {
626                                         flags[read_buffer(ofs + i + 80) & 0x7f] = 1;
627                                 }
628                                 attrib.data &= 0xf3; // for PC-8801mkIIFR \95t\91®\83f\83\82
629                                 
630                                 for(int cx = 0, pos = 0; cx < width; cx++) {
631                                         if(flags[cx]) {
632                                                 set_attrib(read_buffer(ofs + pos + 81));
633                                                 pos += 2;
634                                         }
635                                         attrib.expand[cy][cx] = attrib.data;
636                                 }
637                                 if((status & 8) && exitline == -1) {
638                                         exitline = cy;
639 //                                      goto underrun;
640                                 }
641                         }
642                 }
643         }
644         if(cursor.x < 80 && cursor.y < 200) {
645                 if((cursor.type & 1) && blink.cursor) {
646                         // no cursor
647                 } else {
648                         static const uint8_t ctype[5] = {0, 8, 8, 1, 1};
649                         attrib.expand[cursor.y][cursor.x] ^= ctype[cursor.type + 1];
650                 }
651         }
652         // only burst mode
653 underrun:
654         if(exitline != -1) {
655                 for(int cy = exitline; cy < 200; cy++) {
656                         memset(&text.expand[cy][0], 0, width);
657                         memset(&attrib.expand[cy][0], 0x70, width); // color=7
658                 }
659         }
660 }
661
662 void crtc_t::set_attrib(uint8_t code)
663 {
664         if(mode & 2) {
665                 // color
666                 if(code & 8) {
667                         attrib.data = (attrib.data & 0x0f) | (code & 0xf0);
668                 } else {
669                         attrib.data = (attrib.data & 0xf0) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
670                         attrib.data ^= reverse;
671                         attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
672                 }
673         } else {
674                 attrib.data = 0x70 | (code & 0x80) | ((code >> 2) & 0x0d) | ((code << 1) & 2);
675                 attrib.data ^= reverse;
676                 attrib.data ^= ((code & 2) && !(code & 1)) ? blink.attrib : 0;
677         }
678 }
679
680 /* ----------------------------------------------------------------------------
681         DMAC (uPD8257)
682 ---------------------------------------------------------------------------- */
683
684 void dmac_t::write_io8(uint32_t addr, uint32_t data)
685 {
686         int c = (addr >> 1) & 3;
687         
688         switch(addr & 0x0f) {
689         case 0:
690         case 2:
691         case 4:
692         case 6:
693                 if(!high_low) {
694                         if((mode & 0x80) && c == 2) {
695                                 ch[3].addr.b.l = data;
696                         }
697                         ch[c].addr.b.l = data;
698                 } else {
699                         if((mode & 0x80) && c == 2) {
700                                 ch[3].addr.b.h = data;
701                         }
702                         ch[c].addr.b.h = data;
703                 }
704                 high_low = !high_low;
705                 break;
706         case 1:
707         case 3:
708         case 5:
709         case 7:
710                 if(!high_low) {
711                         if((mode & 0x80) && c == 2) {
712                                 ch[3].count.b.l = data;
713                         }
714                         ch[c].count.b.l = data;
715                 } else {
716                         if((mode & 0x80) && c == 2) {
717                                 ch[3].count.b.h = data & 0x3f;
718                                 ch[3].mode = data & 0xc0;
719                         }
720                         ch[c].count.b.h = data & 0x3f;
721                         ch[c].mode = data & 0xc0;
722                 }
723                 high_low = !high_low;
724                 break;
725         case 8:
726                 mode = data;
727                 high_low = false;
728                 break;
729         }
730 }
731
732 uint32_t dmac_t::read_io8(uint32_t addr)
733 {
734         uint32_t val = 0xff;
735         int c = (addr >> 1) & 3;
736         
737         switch(addr & 0x0f) {
738         case 0:
739         case 2:
740         case 4:
741         case 6:
742                 if(!high_low) {
743                         val = ch[c].addr.b.l;
744                 } else {
745                         val = ch[c].addr.b.h;
746                 }
747                 high_low = !high_low;
748                 break;
749         case 1:
750         case 3:
751         case 5:
752         case 7:
753                 if(!high_low) {
754                         val = ch[c].count.b.l;
755                 } else {
756                         val = (ch[c].count.b.h & 0x3f) | ch[c].mode;
757                 }
758                 high_low = !high_low;
759                 break;
760         case 8:
761                 val = status;
762                 status &= 0xf0;
763 //              high_low = false;
764                 break;
765         }
766         return val;
767 }
768
769 void dmac_t::start(int c)
770 {
771         if(mode & (1 << c)) {
772                 status &= ~(1 << c);
773                 ch[c].running = true;
774         } else {
775                 ch[c].running = false;
776         }
777 }
778
779 void dmac_t::finish(int c)
780 {
781         if(ch[c].running) {
782                 while(ch[c].count.sd >= 0) {
783                         run(c);
784                 }
785         }
786 }
787
788 void dmac_t::run(int c)
789 {
790         if(ch[c].running) {
791                 if(ch[c].count.sd >= 0) {
792                         if(ch[c].mode == 0x80) {
793                                 ch[c].io->write_dma_io8(0, mem->read_dma_data8(ch[c].addr.w.l));
794                         } else if(ch[c].mode == 0x40) {
795                                 mem->write_dma_data8(ch[c].addr.w.l, ch[c].io->read_dma_io8(0));
796                         }
797                         ch[c].addr.sd++;
798                         ch[c].count.sd--;
799                 }
800                 if(ch[c].count.sd < 0) {
801                         if((mode & 0x80) && c == 2) {
802                                 ch[2].addr.sd = ch[3].addr.sd;
803                                 ch[2].count.sd = ch[3].count.sd;
804                                 ch[2].mode = ch[3].mode;
805                         } else if(mode & 0x40) {
806                                 mode &= ~(1 << c);
807                         }
808                         status |= (1 << c);
809                         ch[c].running = false;
810                 }
811         }
812 }
813
814 #define STATE_VERSION   1
815
816 bool DISPLAY::process_state(FILEIO* state_fio, bool loading)
817 {
818         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
819                 return false;
820         }
821         if(!state_fio->StateCheckInt32(this_device_id)) {
822                 return false;
823         }
824         state_fio->StateBuffer(font, sizeof(font), 1);
825         state_fio->StateBuffer(vram, sizeof(vram), 1);
826         state_fio->StateInt32(busreq_clocks);
827         state_fio->StateBool(color);
828         state_fio->StateBool(width40);
829         state_fio->StateUint8(mode);
830         //state_fio->StateBuffer(&crtc, sizeof(crtc), 1);
831         {
832                 // crtc
833                 /* struct */{
834                         state_fio->StateInt32(crtc.blink.rate);
835                         state_fio->StateInt32(crtc.blink.counter);
836                         state_fio->StateUint8(crtc.blink.cursor);
837                         state_fio->StateUint8(crtc.blink.attrib);
838                 } /* blink */;
839                 /*struct */{
840                         state_fio->StateInt32(crtc.cursor.type);
841                         state_fio->StateInt32(crtc.cursor.mode);
842                         state_fio->StateInt32(crtc.cursor.x);
843                         state_fio->StateInt32(crtc.cursor.y);
844                 } /* cursor */;
845                 /*struct */{
846                         state_fio->StateUint8(crtc.attrib.data);
847                         state_fio->StateInt32(crtc.attrib.num);
848                         state_fio->StateBuffer(crtc.attrib.expand, sizeof(crtc.attrib.expand), 1);
849                 } /* attrib */;
850                 /* struct */{
851                         state_fio->StateBuffer(crtc.text.expand, sizeof(crtc.text.expand), 1);
852                 } /*text; */
853                 state_fio->StateInt32(crtc.width);
854                 state_fio->StateInt32(crtc.height);
855                 state_fio->StateInt32(crtc.char_height);
856                 state_fio->StateBool(crtc.skip_line);
857                 state_fio->StateInt32(crtc.vretrace);
858                 state_fio->StateBool(crtc.timing_changed);
859                 state_fio->StateBuffer(crtc.buffer, sizeof(crtc.buffer), 1);
860                 state_fio->StateInt32(crtc.buffer_ptr);
861                 state_fio->StateUint8(crtc.cmd);
862                 state_fio->StateInt32(crtc.cmd_ptr);
863                 state_fio->StateUint8(crtc.mode);
864                 state_fio->StateUint8(crtc.reverse);
865                 state_fio->StateUint8(crtc.intr_mask);
866                 state_fio->StateUint8(crtc.status);
867                 state_fio->StateBool(crtc.vblank);
868         }
869         STORE_DMAC_CONTEXTS();
870         //state_fio->StateBuffer(&dmac, sizeof(dmac), 1);
871         { // dmac
872
873                 for(int i = 0; i < 4; i++) {
874                         state_fio->StateUint32(dmac.ch[i].addr.d);
875                         state_fio->StateUint32(dmac.ch[i].count.d);
876                         state_fio->StateUint8(dmac.ch[i].mode);
877                         state_fio->StateInt32(dmac.ch[i].nbytes);
878                         state_fio->StateBool(dmac.ch[i].running);
879                 } /* ch[4] */
880                 state_fio->StateUint8(dmac.mode);
881                 state_fio->StateUint8(dmac.status);
882                 state_fio->StateBool(dmac.high_low);
883         }               
884         RESTORE_DMAC_CONTEXTS();
885         return true;
886 }
887 }