OSDN Git Service

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