OSDN Git Service

[VM][WIP] Pre-process to apply new state framework.Still not buildable.
[csp-qt/common_source_project-fm7.git] / source / src / vm / hc40 / io.cpp
1 /*
2         EPSON HC-40 Emulator 'eHC-40'
3
4         Author : Takeda.Toshiya
5         Date   : 2008.02.23 -
6
7         [ i/o ]
8 */
9
10 #include "io.h"
11 #include "../beep.h"
12 #include "../datarec.h"
13 #include "../ptf20.h"
14 #include "../../fifo.h"
15
16 // interrupt bits
17 #define BIT_7508        0x01
18 #define BIT_ART         0x02
19 #define BIT_ICF         0x04
20 #define BIT_OVF         0x08
21 #define BIT_EXT         0x10
22
23 // art (8251 subset)
24 #define BUFFER_SIZE     0x40000
25 #define RECV_DELAY      100
26 #define TXRDY           0x01
27 #define RXRDY           0x02
28 #define TXE             0x04
29 #define PE              0x08
30 #define OE              0x10
31 #define FE              0x20
32 #define SYNDET          0x40
33 #define DSR             0x80
34
35 #define EVENT_FRC       0
36 #define EVENT_1SEC      1
37 #define EVENT_ART       2
38
39 static const int key_tbl[256] = {
40         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x56,0x57,0xff,0xff,0xff,0x71,0xff,0xff,
41         0xb3,0xb2,0xff,0x10,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,
42         0x73,0xff,0xff,0xff,0xff,0x63,0x55,0x65,0x64,0xff,0xff,0xff,0xff,0x80,0x81,0xff,
43         0x52,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x50,0x51,0xff,0xff,0xff,0xff,0xff,0xff,
44         0xff,0x66,0x40,0x76,0x30,0x22,0x31,0x32,0x33,0x27,0x34,0x35,0x36,0x42,0x41,0x60,
45         0x61,0x20,0x23,0x67,0x24,0x26,0x77,0x21,0x75,0x25,0x74,0xff,0xff,0xff,0xff,0xff,
46         0x52,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x50,0x51,0xff,0xff,0xff,0xff,0xff,0xff,
47         0x03,0x04,0x05,0x06,0x07,0xff,0xff,0xff,0xff,0xff,0x01,0x02,0xff,0xff,0xff,0xff,
48         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
49         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
50         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
51         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x70,0x37,0x43,0x53,0x44,0x45,
52         0x62,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
53         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x46,0x72,0x47,0x54,0xff,
54         0xff,0xff,0x72,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
55         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
56 };
57 #if defined(Q_OS_WIN)
58 DLL_PREFIX_I struct cur_time_s cur_time;
59 #endif
60
61 void IO::initialize()
62 {
63         // init external ram disk
64         memset(ext, 0, 0x20000);
65         memset(ext + 0x20000, 0xff, 0x20000);
66         extar = 0;
67         extcr = 0;
68         
69         // load external ram disk
70         FILEIO* fio = new FILEIO();
71         if(fio->Fopen(create_local_path(_T("EXTRAM.BIN")), FILEIO_READ_BINARY)) {
72                 fio->Fread(ext, 0x20000, 1);
73                 fio->Fclose();
74         }
75         if(fio->Fopen(create_local_path(_T("EXT.ROM")), FILEIO_READ_BINARY)) {
76                 fio->Fread(ext + 0x20000, 0x20000, 1);
77                 fio->Fclose();
78         }
79         delete fio;
80         
81         // init sub cpu
82         cmd_buf = new FIFO(16);
83         rsp_buf = new FIFO(16);
84         key_buf = new FIFO(7);
85         art_buf = new FIFO(BUFFER_SIZE);
86         
87         // set pallete
88         pd = RGB_COLOR(48, 56, 16);
89         pb = RGB_COLOR(160, 168, 160);
90         
91         // init 7508
92         get_host_time(&cur_time);
93         onesec_intr = alarm_intr = false;
94         onesec_intr_enb = alarm_intr_enb = kb_intr_enb = true;
95         res_7508 = kb_caps = false;
96         
97         // register events
98         register_frame_event(this);
99         register_event_by_clock(this, EVENT_FRC, 0x60000, true, NULL);
100         register_event_by_clock(this, EVENT_1SEC, CPU_CLOCKS, true, &register_id_1sec);
101 }
102
103 void IO::release()
104 {
105         // save external ram disk
106         FILEIO* fio = new FILEIO();
107         if(fio->Fopen(create_local_path(_T("EXTRAM.BIN")), FILEIO_WRITE_BINARY)) {
108                 fio->Fwrite(ext, 0x20000, 1);
109                 fio->Fclose();
110         }
111         delete fio;
112         
113         cmd_buf->release();
114         delete cmd_buf;
115         rsp_buf->release();
116         delete rsp_buf;
117         key_buf->release();
118         delete key_buf;
119         art_buf->release();
120         delete art_buf;
121 }
122
123 void IO::reset()
124 {
125         // reset gapnit
126         bcr = slbcr = isr = ier = bankr = ioctlr = 0;
127         icrc = icrb = 0;
128         ear = beep = false;
129         res_z80 = true;
130         
131         // reset art
132         artdir = 0xff;
133         artsr = TXRDY | TXE;
134         txen = rxen = false;
135         art_buf->clear();
136         register_id_art = -1;
137 }
138
139 void IO::sysreset()
140 {
141         // reset 7508
142         onesec_intr = alarm_intr = false;
143         onesec_intr_enb = alarm_intr_enb = kb_intr_enb = true;
144         res_7508 = true;
145 }
146
147 void IO::write_signal(int id, uint32_t data, uint32_t mask)
148 {
149         if(id == SIG_IO_DREC) {
150                 // signal from data recorder
151                 if(!slbcr) {
152                         bool next = ((data & mask) != 0);
153                         if((bcr == 2 && ear && !next) || (bcr == 4 && !ear && next) || (bcr == 6 && ear != next)) {
154                                 icrb = get_passed_clock(cur_clock) / 6;
155                                 isr |= BIT_ICF;
156                                 update_intr();
157                         }
158                         ear = next;
159                 }
160         } else if(id == SIG_IO_ART) {
161                 // data from art
162                 art_buf->write(data & mask);
163                 if(rxen && !art_buf->empty() && register_id_art == -1) {
164                         register_event(this, EVENT_ART, RECV_DELAY, false, &register_id_art);
165                 }
166         }
167 }
168
169 void IO::event_frame()
170 {
171         d_beep->write_signal(SIG_BEEP_ON, beep ? 1 : 0, 1);
172         beep = false;
173 }
174
175 void IO::event_callback(int event_id, int err)
176 {
177         if(event_id == EVENT_FRC) {
178                 // FRC overflow event
179                 cur_clock = get_current_clock();
180                 isr |= BIT_OVF;
181                 update_intr();
182         } else if(event_id == EVENT_1SEC) {
183                 // update rtc
184                 if(cur_time.initialized) {
185                         cur_time.increment();
186                 } else {
187                         get_host_time(&cur_time);       // resync
188                         cur_time.initialized = true;
189                 }
190                 onesec_intr = true;
191                 if(onesec_intr_enb) {
192                         isr |= BIT_7508;
193                         update_intr();
194                 }
195         } else if(event_id == EVENT_ART) {
196                 // recv from art event
197                 if(rxen && !(artsr & RXRDY)) {
198                         if(!art_buf->empty()) {
199                                 artdir = art_buf->read();
200                         }
201                         if(art_buf->empty()) {
202                                 artsr |= PE;
203                         }
204                         artsr |= RXRDY;
205                         // interrupt
206                         isr |= BIT_ART;
207                         update_intr();
208                 }
209                 // if data is still left in buffer, register event for next data
210                 if(rxen && !art_buf->empty()) {
211                         register_event(this, EVENT_ART, RECV_DELAY, false, &register_id_art);
212                 } else {
213                         register_id_art = -1;
214                 }
215         }
216 }
217
218 void IO::write_io8(uint32_t addr, uint32_t data)
219 {
220         switch(addr & 0xff) {
221         case 0x00:
222                 // CTLR1
223                 bcr = data & 6;
224                 slbcr = data & 1;
225                 break;
226         case 0x01:
227                 // CMDR
228                 if(data & 4) {
229                         isr &= ~BIT_OVF;
230                         update_intr();
231                 }
232                 //if(data & 2) {
233                 //      rdysio = false;
234                 //}
235                 //if(data & 1) {
236                 //      rdysio = true;
237                 //}
238                 break;
239         case 0x02:
240                 // CTLR2
241                 d_drec->write_signal(SIG_DATAREC_MIC, data, 1);
242                 d_drec->write_signal(SIG_DATAREC_REMOTE, data, 2);
243                 break;
244         case 0x04:
245                 // IER
246                 ier = data;
247                 break;
248         case 0x05:
249                 // BANKR
250                 d_mem->write_signal(0, data, 0xf0);
251                 bankr = data;
252                 // dont care EDU,ECA and CKSW now...
253                 break;
254         case 0x06:
255                 // SIOR
256                 send_to_7508(data);
257                 break;
258         case 0x08:
259                 // VADR
260                 vadr = data;
261                 break;
262         case 0x09:
263                 // YOFF
264                 yoff = data;
265                 break;
266         case 0x0a:
267                 // FR: dont care, always 72Hz
268                 break;
269         case 0x0b:
270                 // SPUR: dont care
271                 break;
272         case 0x14:
273                 // ARTDOR
274                 if(txen) {
275                         d_tf20->write_signal(SIGNAL_TF20_SIO, data, 0xff);
276                 }
277                 break;
278         case 0x15:
279                 // ARTMR
280                 break;
281         case 0x16:
282                 // ARTCR
283                 if(data & 0x10) {
284                         artsr &= ~(PE | OE | FE);
285                 }
286                 txen = ((data & 1) != 0);
287                 rxen = ((data & 4) != 0);
288                 if(rxen && !art_buf->empty() && register_id_art == -1) {
289                         register_event(this, EVENT_ART, RECV_DELAY, false, &register_id_art);
290                 }
291                 break;
292         case 0x19:
293                 // IOCTLR
294                 if((ioctlr & 0x80) != (data & 0x80)) {
295                         beep = true;
296                 }
297                 ioctlr = data;
298                 break;
299         case 0x90:
300                 // EXTAR
301                 extar = (extar & 0xffff00) | data;
302                 break;
303         case 0x91:
304                 // EXTAR
305                 extar = (extar & 0xff00ff) | (data << 8);
306                 break;
307         case 0x92:
308                 // EXTAR
309                 extar = (extar & 0x00ffff) | ((data & 7) << 16);
310                 break;
311         case 0x93:
312                 // EXTOR
313                 if(extar < 0x20000) {
314                         ext[extar] = data;
315                 }
316                 extar = (extar & 0xffff00) | ((extar + 1) & 0xff);
317                 break;
318         case 0x94:
319                 // EXTCR
320                 extcr = data;
321                 break;
322         }
323 }
324
325 uint32_t IO::read_io8(uint32_t addr)
326 {
327         uint32_t val = 0xff;
328         
329         switch(addr & 0xff) {
330         case 0x00:
331                 // ICRL.C (latch FRC value)
332                 icrc = get_passed_clock(cur_clock) / 6;
333                 return icrc & 0xff;
334         case 0x01:
335                 // ICRH.C
336                 return (icrc >> 8) & 0xff;
337         case 0x02:
338                 // ICRL.B
339                 return icrb & 0xff;
340         case 0x03:
341                 // ICRH.B
342                 isr &= ~BIT_ICF;
343                 update_intr();
344                 return (icrb >> 8) & 0xff;
345         case 0x04:
346                 // ISR
347                 return isr;
348         case 0x05:
349                 // STR
350                 return (bankr & 0xf0) | 8 | 4 | (ear ? 1 : 0);  // always rdysio=rdy=true
351         case 0x06:
352                 // SIOR
353                 return rec_from_7508();
354         case 0x14:
355                 // ARTDIR
356                 isr &= ~BIT_ART;
357                 update_intr();
358                 artsr &= ~RXRDY;
359                 return artdir;
360         case 0x15:
361                 // ARTSR
362                 return artsr;
363         case 0x16:
364                 // IOSTR
365                 return 0x40 | (artsr & RXRDY ? 8 : 0);  // not hand shake mode
366         case 0x93:
367                 // EXTIR
368                 if(extar < 0x40000) {
369                         val = ext[extar];
370                 }
371                 extar = (extar & 0xffff00) | ((extar + 1) & 0xff);
372                 return val;
373         case 0x94:
374                 // EXTSR
375                 return extcr & ~0x80;
376         }
377         return 0xff;
378 }
379
380 uint32_t IO::get_intr_ack()
381 {
382         if(isr & BIT_7508) {
383                 isr &= ~BIT_7508;
384                 return 0xf0;
385         } else if(isr & BIT_ART) {
386                 return 0xf2;
387         } else if(isr & BIT_ICF) {
388                 return 0xf4;
389         } else if(isr & BIT_OVF) {
390                 return 0xf6;
391         } else if(isr & BIT_EXT) {
392                 return 0xf8;
393         }
394         // unknown
395         return 0xff;
396 }
397
398 void IO::update_intr()
399 {
400         // set int signal
401         bool next = ((isr & ier & 0x1f) != 0);
402         d_cpu->set_intr_line(next, true, 0);
403 }
404
405 // ----------------------------------------------------------------------------
406 // 7508
407 // ----------------------------------------------------------------------------
408
409 void IO::send_to_7508(uint8_t val)
410 {
411         int res;
412         
413         // process command
414         cmd_buf->write(val);
415         uint8_t cmd = cmd_buf->read_not_remove(0);
416         
417         switch(cmd) {
418         case 0x01:
419                 // power off
420                 cmd_buf->read();
421                 break;
422         case 0x02:
423                 // status / key
424                 cmd_buf->read();
425                 if((onesec_intr && onesec_intr_enb) || (alarm_intr && alarm_intr_enb) || res_z80 || res_7508) {
426                         res = 0xc1;
427                         res |= (onesec_intr && onesec_intr_enb) ? 0x20 : 0;
428                         res |= (res_z80 ? 0x10 : 0) | (res_7508 ? 8 : 0);
429                         res |= (alarm_intr && alarm_intr_enb) ? 2 : 0;
430                         // clear interrupt
431                         onesec_intr = alarm_intr = res_z80 = res_7508 = false;
432                 } else if(key_buf->count()) {
433                         res = key_buf->read();
434                 } else {
435                         res = 0xbf;
436                 }
437                 rsp_buf->write(res);
438                 // request next interrupt
439                 if(key_buf->count() && kb_intr_enb) {
440                         isr |= BIT_7508;
441                         update_intr();
442                 }
443                 break;
444         case 0x03:
445                 // kb reset
446                 cmd_buf->read();
447                 key_buf->clear();
448                 kb_rep_spd1 = 42 | 0x80;
449                 kb_rep_spd2 = 18 | 0x80;
450                 kb_intr_enb = true;
451                 break;
452         case 0x04:
453                 // kb repeat timer 1 set
454                 if(cmd_buf->count() == 2) {
455                         cmd_buf->read();
456                         kb_rep_spd1 = cmd_buf->read();
457                 }
458                 break;
459         case 0x05:
460                 // kb repeat off
461                 cmd_buf->read();
462                 kb_rep_enb = false;
463                 break;
464         case 0x06:
465                 // kb interrupt off
466                 cmd_buf->read();
467                 kb_intr_enb = false;
468                 break;
469         case 0x07:
470                 // clock read
471                 cmd_buf->read();
472                 rsp_buf->write(TO_BCD_HI(cur_time.year));
473                 rsp_buf->write(TO_BCD_LO(cur_time.year));
474                 rsp_buf->write(TO_BCD(cur_time.month));
475                 rsp_buf->write(TO_BCD(cur_time.day));
476                 rsp_buf->write(TO_BCD(cur_time.hour));
477                 rsp_buf->write(TO_BCD(cur_time.minute));
478                 rsp_buf->write(TO_BCD(cur_time.second));
479                 rsp_buf->write(cur_time.day_of_week);
480                 break;
481         case 0x08:
482                 // power switch read
483                 cmd_buf->read();
484                 rsp_buf->write(1);
485                 break;
486         case 0x09:
487                 // alarm read
488                 cmd_buf->read();
489                 rsp_buf->write(alarm[0]);
490                 rsp_buf->write(alarm[1]);
491                 rsp_buf->write(alarm[2]);
492                 rsp_buf->write(alarm[3]);
493                 rsp_buf->write(alarm[4]);
494                 rsp_buf->write(alarm[5]);
495                 break;
496         case 0x0a:
497                 // dip switch read
498                 cmd_buf->read();
499                 res = 0;        // standard keyboard = 0, item keyboard = 0x80
500                 res |= 0x60;    // serial = 0, cart-printer = 0x20, rs-232c = 0x40, printer = 0x60
501 //              res |= 0x30;    // serial = 0, cart-printer = 0x10, rs-232c = 0x20, printer = 0x30
502                 res |= 0xf;     // ascii keyboard
503                 rsp_buf->write(res);
504                 break;
505         case 0x0b:
506                 // stop key interrupt disable -> kb interrupt on
507                 cmd_buf->read();
508                 kb_intr_enb = true;
509                 break;
510         case 0x0d:
511                 // 1 sec interrupt off
512                 cmd_buf->read();
513                 onesec_intr_enb = false;
514                 break;
515         case 0x0e:
516                 // kb clear
517                 cmd_buf->read();
518                 key_buf->clear();
519                 break;
520         case 0x0f:
521                 // system reset
522                 cmd_buf->read();
523                 res_7508 = true;
524                 break;
525         case 0x14:
526                 // kb repeat timer 2 set
527                 if(cmd_buf->count() == 2) {
528                         cmd_buf->read();
529                         kb_rep_spd2 = cmd_buf->read();
530                 }
531                 break;
532         case 0x15:
533                 // kb repeat on
534                 cmd_buf->read();
535                 kb_rep_enb = true;
536                 break;
537         case 0x16:
538                 // kb interrupt on
539                 cmd_buf->read();
540                 kb_intr_enb = true;
541                 break;
542         case 0x17:
543                 // clock write
544                 if(cmd_buf->count() == 9) {
545                         cmd_buf->read();
546                         int year10 = cmd_buf->read();
547                         int year1 = cmd_buf->read();
548                         int month = cmd_buf->read();
549                         int day = cmd_buf->read();
550                         int hour = cmd_buf->read();
551                         int minute = cmd_buf->read();
552                         int second = cmd_buf->read();
553                         int day_of_week = cmd_buf->read();
554                         
555                         if((month & 0x0f) == 0 || (day & 0x0f) == 0) {
556                                 // invalid date
557                                 get_host_time(&cur_time);
558                         } else {
559                                 bool changed = false;
560                                 if((year10 & 0x0f) != 0x0f && (year1 & 0x0f) != 0x0f) {
561                                         cur_time.year = (year10 & 0x0f) * 10 + (year1 & 0x0f);
562                                         cur_time.update_year();
563                                         changed = true;
564                                 }
565                                 if((month & 0x0f) != 0x0f) {
566                                         cur_time.month = FROM_BCD(month & 0x1f);
567                                         changed = true;
568                                 }
569                                 if((day & 0x0f) != 0x0f) {
570                                         cur_time.day = FROM_BCD(day & 0x3f);
571                                         changed = true;
572                                 }
573                                 if((hour & 0x0f) != 0x0f) {
574                                         cur_time.hour = FROM_BCD(hour & 0x3f);
575                                         changed = true;
576                                 }
577                                 if((minute & 0x0f) != 0x0f) {
578                                         cur_time.minute = FROM_BCD(minute & 0x7f);
579                                         changed = true;
580                                 }
581                                 if((second & 0x0f) != 0x0f) {
582                                         cur_time.second = FROM_BCD(second & 0x7f);
583                                         changed = true;
584                                 }
585 //                              if((day_of_week & 0x0f) != 0x0f) {
586 //                                      cur_time.day_of_week = day_of_week & 0x07;
587 //                                      changed = true;
588 //                              }
589                                 if(changed) {
590                                         cur_time.update_day_of_week();
591                                         // restart event
592                                         cancel_event(this, register_id_1sec);
593                                         register_event_by_clock(this, EVENT_1SEC, CPU_CLOCKS, true, &register_id_1sec);
594                                 }
595                         }
596                 }
597                 break;
598         case 0x19:
599                 // alarm set
600                 if(cmd_buf->count() == 7) {
601                         cmd_buf->read();
602                         alarm[0] = cmd_buf->read();
603                         alarm[1] = cmd_buf->read();
604                         alarm[2] = cmd_buf->read();
605                         alarm[3] = cmd_buf->read();
606                         alarm[4] = cmd_buf->read();
607                         alarm[5] = cmd_buf->read();
608                 }
609                 break;
610         case 0x1b:
611                 // stop key interrupt enable -> kb interrupt off
612                 cmd_buf->read();
613                 kb_intr_enb = false;
614                 break;
615         case 0x1d:
616                 // 1 sec interrupt on
617                 cmd_buf->read();
618                 onesec_intr_enb = true;
619                 break;
620         case 0x24:
621                 // kb repeat timer 1 read
622                 cmd_buf->read();
623                 rsp_buf->write(kb_rep_spd1);
624                 break;
625         case 0x29:
626                 // alarm off
627                 cmd_buf->read();
628                 alarm_intr_enb = false;
629                 break;
630         case 0x34:
631                 // kb repeat timer 2 read
632                 cmd_buf->read();
633                 rsp_buf->write(kb_rep_spd2);
634                 break;
635         case 0x39:
636                 // alarm on
637                 cmd_buf->read();
638                 alarm_intr_enb = true;
639                 break;
640         default:
641                 // unknown cmd
642                 cmd_buf->read();
643                 this->out_debug_log(_T("unknown cmd %2x\n"), cmd);
644         }
645 }
646
647 uint8_t IO::rec_from_7508()
648 {
649         return rsp_buf->read();
650 }
651
652 void IO::key_down(int code)
653 {
654         if(code == 0x14) {
655                 // toggle caps lock
656                 kb_caps = !kb_caps;
657                 update_key(kb_caps ? 0xb4 : 0xa4);
658                 update_key(kb_caps ? 0xa4 : 0xb4);
659         } else {
660                 update_key(key_tbl[code & 0xff]);
661         }
662 }
663
664 void IO::key_up(int code)
665 {
666         if(code == 0x10) {
667                 update_key(0xa3);       // break shift
668         } else if(code == 0x11) {
669                 update_key(0xa2);       // break ctrl
670         }
671 }
672
673 void IO::update_key(int code)
674 {
675         if(code != 0xff) {
676                 // add to buffer
677                 if(code == 0x10) {
678                         // stop key
679                         key_buf->clear();
680                         key_buf->write(code);
681                 } else {
682                         key_buf->write(code);
683                 }
684                 
685                 // key interrupt
686                 if(kb_intr_enb || (!kb_intr_enb && code == 0x10)) {
687                         isr |= BIT_7508;
688                         update_intr();
689                 }
690         }
691 }
692
693 // ----------------------------------------------------------------------------
694 // video
695 // ----------------------------------------------------------------------------
696
697 void IO::draw_screen()
698 {
699         if(yoff & 0x80) {
700                 uint8_t* vram = ram + ((vadr & 0xf8) << 8);
701                 for(int y = 0; y < 64; y++) {
702                         scrntype_t* dest = emu->get_screen_buffer((y - (yoff & 0x3f)) & 0x3f);
703                         for(int x = 0; x < 30; x++) {
704                                 uint8_t pat = *vram++;
705                                 dest[0] = (pat & 0x80) ? pd : pb;
706                                 dest[1] = (pat & 0x40) ? pd : pb;
707                                 dest[2] = (pat & 0x20) ? pd : pb;
708                                 dest[3] = (pat & 0x10) ? pd : pb;
709                                 dest[4] = (pat & 0x08) ? pd : pb;
710                                 dest[5] = (pat & 0x04) ? pd : pb;
711                                 dest[6] = (pat & 0x02) ? pd : pb;
712                                 dest[7] = (pat & 0x01) ? pd : pb;
713                                 dest += 8;
714                         }
715                         vram += 2;
716                 }
717         } else {
718                 for(int y = 0; y < 64; y++) {
719                         scrntype_t* dest = emu->get_screen_buffer(y);
720                         for(int x = 0; x < 240; x++) {
721                                 dest[x] = pb;
722                         }
723                 }
724         }
725 }
726
727 #define STATE_VERSION   1
728
729 #include "../../statesub.h"
730
731 void IO::decl_state()
732 {
733         enter_decl_state(STATE_VERSION);
734
735         DECL_STATE_ENTRY_UINT32(cur_clock);
736         DECL_STATE_ENTRY_UINT8(bcr);
737         DECL_STATE_ENTRY_UINT8(slbcr);
738         DECL_STATE_ENTRY_UINT8(isr);
739         DECL_STATE_ENTRY_UINT8(ier);
740         DECL_STATE_ENTRY_UINT8(bankr);
741         DECL_STATE_ENTRY_UINT8(ioctlr);
742         DECL_STATE_ENTRY_UINT32(icrc);
743         DECL_STATE_ENTRY_UINT32(icrb);
744         DECL_STATE_ENTRY_BOOL(ear);
745         DECL_STATE_ENTRY_UINT8(vadr);
746         DECL_STATE_ENTRY_UINT8(yoff);
747         DECL_STATE_ENTRY_FIFO(cmd_buf);
748         DECL_STATE_ENTRY_FIFO(rsp_buf);
749         DECL_STATE_ENTRY_CUR_TIME_T(cur_time);
750         
751         DECL_STATE_ENTRY_INT32(register_id_1sec);
752         DECL_STATE_ENTRY_BOOL(onesec_intr);
753         DECL_STATE_ENTRY_BOOL(onesec_intr_enb);
754         DECL_STATE_ENTRY_BOOL(alarm_intr);
755         DECL_STATE_ENTRY_BOOL(alarm_intr_enb);
756         DECL_STATE_ENTRY_1D_ARRAY(alarm, sizeof(alarm));
757         DECL_STATE_ENTRY_FIFO(key_buf);
758         DECL_STATE_ENTRY_BOOL(kb_intr_enb);
759         DECL_STATE_ENTRY_BOOL(kb_rep_enb);
760         DECL_STATE_ENTRY_BOOL(kb_caps);
761         DECL_STATE_ENTRY_UINT8(kb_rep_spd1);
762         DECL_STATE_ENTRY_UINT8(kb_rep_spd2);
763         DECL_STATE_ENTRY_FIFO(art_buf);
764         DECL_STATE_ENTRY_UINT8(artsr);
765         DECL_STATE_ENTRY_UINT8(artdir);
766         DECL_STATE_ENTRY_BOOL(txen);
767         DECL_STATE_ENTRY_BOOL(rxen);
768         DECL_STATE_ENTRY_BOOL(dsr);
769         DECL_STATE_ENTRY_INT32(register_id_art);
770         DECL_STATE_ENTRY_BOOL(beep);
771         DECL_STATE_ENTRY_BOOL(res_z80);
772         DECL_STATE_ENTRY_BOOL(res_7508);
773         DECL_STATE_ENTRY_1D_ARRAY(ext, sizeof(ext));
774         DECL_STATE_ENTRY_UINT32(extar);
775         DECL_STATE_ENTRY_UINT8(extcr);
776         
777         leave_decl_state();
778 }
779
780
781 void IO::save_state(FILEIO* state_fio)
782 {
783         if(state_entry != NULL) {
784                 state_entry->save_state(state_fio);
785         }
786 //      state_fio->FputUint32(STATE_VERSION);
787 //      state_fio->FputInt32(this_device_id);
788         
789 //      state_fio->FputUint32(cur_clock);
790 //      state_fio->FputUint8(bcr);
791 //      state_fio->FputUint8(slbcr);
792 //      state_fio->FputUint8(isr);
793 //      state_fio->FputUint8(ier);
794 //      state_fio->FputUint8(bankr);
795 //      state_fio->FputUint8(ioctlr);
796 //      state_fio->FputUint32(icrc);
797 //      state_fio->FputUint32(icrb);
798 //      state_fio->FputBool(ear);
799 //      state_fio->FputUint8(vadr);
800 //      state_fio->FputUint8(yoff);
801 //      cmd_buf->save_state((void *)state_fio);
802 //      rsp_buf->save_state((void *)state_fio);
803 //      cur_time.save_state((void *)state_fio);
804 //      state_fio->FputInt32(register_id_1sec);
805 //      state_fio->FputBool(onesec_intr);
806 //      state_fio->FputBool(onesec_intr_enb);
807 //      state_fio->FputBool(alarm_intr);
808 //      state_fio->FputBool(alarm_intr_enb);
809 //      state_fio->Fwrite(alarm, sizeof(alarm), 1);
810 //      key_buf->save_state((void *)state_fio);
811 //      state_fio->FputBool(kb_intr_enb);
812 //      state_fio->FputBool(kb_rep_enb);
813 //      state_fio->FputBool(kb_caps);
814 //      state_fio->FputUint8(kb_rep_spd1);
815 //      state_fio->FputUint8(kb_rep_spd2);
816 //      art_buf->save_state((void *)state_fio);
817 //      state_fio->FputUint8(artsr);
818 //      state_fio->FputUint8(artdir);
819 //      state_fio->FputBool(txen);
820 //      state_fio->FputBool(rxen);
821 //      state_fio->FputBool(dsr);
822 //      state_fio->FputInt32(register_id_art);
823 //      state_fio->FputBool(beep);
824 //      state_fio->FputBool(res_z80);
825 //      state_fio->FputBool(res_7508);
826 //      state_fio->Fwrite(ext, sizeof(ext), 1);
827 //      state_fio->FputUint32(extar);
828 //      state_fio->FputUint8(extcr);
829 }
830
831 bool IO::load_state(FILEIO* state_fio)
832 {
833         bool mb = false;
834         if(state_entry != NULL) {
835                 mb = state_entry->load_state(state_fio);
836         }
837         if(!mb) {
838                 return false;
839         }
840 //      if(state_fio->FgetUint32() != STATE_VERSION) {
841 //              return false;
842 //      }
843 //      if(state_fio->FgetInt32() != this_device_id) {
844 //              return false;
845 //      }
846 //      cur_clock = state_fio->FgetUint32();
847 //      bcr = state_fio->FgetUint8();
848 //      slbcr = state_fio->FgetUint8();
849 //      isr = state_fio->FgetUint8();
850 //      ier = state_fio->FgetUint8();
851 //      bankr = state_fio->FgetUint8();
852 //      ioctlr = state_fio->FgetUint8();
853 //      icrc = state_fio->FgetUint32();
854 //      icrb = state_fio->FgetUint32();
855 //      ear = state_fio->FgetBool();
856 //      vadr = state_fio->FgetUint8();
857 //      yoff = state_fio->FgetUint8();
858 //      if(!cmd_buf->load_state((void *)state_fio)) {
859 //              return false;
860 //      }
861 //      if(!rsp_buf->load_state((void *)state_fio)) {
862 //              return false;
863 //      }
864 //      if(!cur_time.load_state((void *)state_fio)) {
865 //              return false;
866 //      }
867         
868 //      register_id_1sec = state_fio->FgetInt32();
869 //      onesec_intr = state_fio->FgetBool();
870 //      onesec_intr_enb = state_fio->FgetBool();
871 //      alarm_intr = state_fio->FgetBool();
872 //      alarm_intr_enb = state_fio->FgetBool();
873 //      state_fio->Fread(alarm, sizeof(alarm), 1);
874 //      if(!key_buf->load_state((void *)state_fio)) {
875 //              return false;
876 //      }
877 //      kb_intr_enb = state_fio->FgetBool();
878 //      kb_rep_enb = state_fio->FgetBool();
879 //      kb_caps = state_fio->FgetBool();
880 //      kb_rep_spd1 = state_fio->FgetUint8();
881 //      kb_rep_spd2 = state_fio->FgetUint8();
882 //      if(!art_buf->load_state((void *)state_fio)) {
883 //              return false;
884 //      }
885 //      artsr = state_fio->FgetUint8();
886 //      artdir = state_fio->FgetUint8();
887 //      txen = state_fio->FgetBool();
888 //      rxen = state_fio->FgetBool();
889 //      dsr = state_fio->FgetBool();
890 //      register_id_art = state_fio->FgetInt32();
891 //      beep = state_fio->FgetBool();
892 //      res_z80 = state_fio->FgetBool();
893 //      res_7508 = state_fio->FgetBool();
894 //      state_fio->Fread(ext, sizeof(ext), 1);
895 //      extar = state_fio->FgetUint32();
896 //      extcr = state_fio->FgetUint8();
897         return true;
898 }
899
900 bool IO::process_state(FILEIO* state_fio, bool loading)
901 {
902         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
903                 return false;
904         }
905         if(!state_fio->StateCheckInt32(this_device_id)) {
906                 return false;
907         }
908         state_fio->StateUint32(cur_clock);
909         state_fio->StateUint8(bcr);
910         state_fio->StateUint8(slbcr);
911         state_fio->StateUint8(isr);
912         state_fio->StateUint8(ier);
913         state_fio->StateUint8(bankr);
914         state_fio->StateUint8(ioctlr);
915         state_fio->StateUint32(icrc);
916         state_fio->StateUint32(icrb);
917         state_fio->StateBool(ear);
918         state_fio->StateUint8(vadr);
919         state_fio->StateUint8(yoff);
920         if(!cmd_buf->process_state((void *)state_fio, loading)) {
921                 return false;
922         }
923         if(!rsp_buf->process_state((void *)state_fio, loading)) {
924                 return false;
925         }
926         if(!cur_time.process_state((void *)state_fio, loading)) {
927                 return false;
928         }
929         state_fio->StateInt32(register_id_1sec);
930         state_fio->StateBool(onesec_intr);
931         state_fio->StateBool(onesec_intr_enb);
932         state_fio->StateBool(alarm_intr);
933         state_fio->StateBool(alarm_intr_enb);
934         state_fio->StateBuffer(alarm, sizeof(alarm), 1);
935         if(!key_buf->process_state((void *)state_fio, loading)) {
936                 return false;
937         }
938         state_fio->StateBool(kb_intr_enb);
939         state_fio->StateBool(kb_rep_enb);
940         state_fio->StateBool(kb_caps);
941         state_fio->StateUint8(kb_rep_spd1);
942         state_fio->StateUint8(kb_rep_spd2);
943         if(!art_buf->process_state((void *)state_fio, loading)) {
944                 return false;
945         }
946         state_fio->StateUint8(artsr);
947         state_fio->StateUint8(artdir);
948         state_fio->StateBool(txen);
949         state_fio->StateBool(rxen);
950         state_fio->StateBool(dsr);
951         state_fio->StateInt32(register_id_art);
952         state_fio->StateBool(beep);
953         state_fio->StateBool(res_z80);
954         state_fio->StateBool(res_7508);
955         state_fio->StateBuffer(ext, sizeof(ext), 1);
956         state_fio->StateUint32(extar);
957         state_fio->StateUint8(extcr);
958         return true;
959 }