OSDN Git Service

[VM][I286] Save cpustate without StateBuffer().
[csp-qt/common_source_project-fm7.git] / source / src / vm / hc80 / io.cpp
1 /*
2         EPSON HC-80 Emulator 'eHC-80'
3
4         Author : Takeda.Toshiya
5         Date   : 2008.03.14 -
6
7         [ i/o ]
8 */
9
10 #include "io.h"
11 #include "../beep.h"
12 #include "../ptf20.h"
13 #include "../../fifo.h"
14
15 //#define OUT_CMD_LOG
16
17 // interrupt bits
18 #define BIT_7508        0x01
19 #define BIT_8251        0x02
20 #define BIT_CD          0x04
21 #define BIT_ICF         0x08
22 #define BIT_OVF         0x10
23 #define BIT_EXT         0x20
24
25 // 6303
26 #define BIT_OBF         0x01
27 #define BIT_IBF         0x02
28 #define BIT_F1          0x08
29 #define RCD00           0
30 #define RCD01           1
31 #define RCD02           2
32 #define RCD03           3
33 #define RCD04           11
34 #define RCD05           12
35 #define RCD06           13
36 #define RCD07           41
37 #define RCD08           42
38 #define RCD09           43
39 #define RCD10           44
40 #define RCD11           45
41 #define RCD11_1         46
42 #define RCD12           61
43 #define RCD13           62
44 #define RCD14           63
45 #define RCD15           71
46
47 // TF-20
48 #define DID_FIRST       0x31
49 #define DS_SEL          0x05
50 #define SOH             0x01
51 #define STX             0x02
52 #define EOT             0x04
53 #define ACK             0x06
54
55 // intelligent ram disk
56 #define IRAMDISK_WAIT   1
57 #define IRAMDISK_IN     0
58 #define IRAMDISK_OUT    1
59
60 #define EVENT_FRC       0
61 #define EVENT_1SEC      1
62 #define EVENT_6303      2
63
64 static const int key_tbl[256] = {
65         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x56,0x57,0xff,0xff,0xff,0x71,0xff,0xff,
66         0xb3,0xb2,0xff,0x10,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,
67         0x73,0xff,0xff,0xff,0xff,0x63,0x55,0x65,0x64,0xff,0xff,0xff,0xff,0x80,0x81,0xff,
68         0x52,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x50,0x51,0xff,0xff,0xff,0xff,0xff,0xff,
69         0xff,0x66,0x40,0x76,0x30,0x22,0x31,0x32,0x33,0x27,0x34,0x35,0x36,0x42,0x41,0x60,
70         0x61,0x20,0x23,0x67,0x24,0x26,0x77,0x21,0x75,0x25,0x74,0xff,0xff,0xff,0xff,0xff,
71         0x52,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x50,0x51,0xff,0xff,0xff,0xff,0xff,0xff,
72         0x03,0x04,0x05,0x06,0x07,0xff,0xff,0xff,0xff,0xff,0x01,0x02,0xff,0xff,0xff,0xff,
73         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
74         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
75         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
76         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x70,0x37,0x43,0x53,0x44,0x45,
77         0x62,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
78         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x46,0x72,0x47,0x54,0xff,
79         0xff,0xff,0x72,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
80         0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
81 };
82
83 static const uint8_t dot_tbl[8] = {
84         0x80, 0x40, 0x20, 0x10, 8, 4, 2, 1
85 };
86 #if defined(Q_OS_WIN)
87 DLL_PREFIX_I struct cur_time_s cur_time;
88 #endif
89
90 void HC80_IO::initialize()
91 {
92         // config
93         device_type = config.device_type;
94         
95         // init ram and external ram disk
96         memset(ram, 0, sizeof(ram));
97         memset(ext, 0, 0x20000);
98         memset(ext + 0x20000, 0xff, 0x20000);
99         extar = 0;
100         extcr = 0;
101         
102         // load images
103         FILEIO* fio = new FILEIO();
104         if(fio->Fopen(create_local_path(_T("BASIC.ROM")), FILEIO_READ_BINARY)) {
105                 fio->Fread(basic, 0x4000, 1);
106                 memcpy(basic + 0x4000, basic, 0x4000);
107                 fio->Fread(basic + 0x4000, 0x4000, 1);
108                 fio->Fclose();
109         }
110         if(fio->Fopen(create_local_path(_T("UTIL.ROM")), FILEIO_READ_BINARY)) {
111                 fio->Fread(util, 0x4000, 1);
112                 memcpy(util + 0x4000, util, 0x4000);
113                 fio->Fread(util + 0x4000, 0x4000, 1);
114                 fio->Fclose();
115         }
116         if(fio->Fopen(create_local_path(_T("VRAM.BIN")), FILEIO_READ_BINARY)) {
117                 fio->Fread(ram + 0x8000, 0x1800, 1);
118                 fio->Fclose();
119         }
120         if(fio->Fopen(create_local_path(_T("EXTRAM.BIN")), FILEIO_READ_BINARY)) {
121                 fio->Fread(ext, 0x20000, 1);
122                 fio->Fclose();
123         }
124         if(fio->Fopen(create_local_path(_T("INTRAM.BIN")), FILEIO_READ_BINARY)) {
125                 fio->Fread(iramdisk_sectors, sizeof(iramdisk_sectors), 1);
126                 fio->Fclose();
127         }
128         if(fio->Fopen(create_local_path(_T("EXT.ROM")), FILEIO_READ_BINARY)) {
129                 fio->Fread(ext + 0x20000, 0x20000, 1);
130                 fio->Fclose();
131         }
132         if(fio->Fopen(create_local_path(_T("FONT.ROM")), FILEIO_READ_BINARY)) {
133                 fio->Fread(font, sizeof(font), 1);
134                 fio->Fclose();
135         }
136         delete fio;
137         
138         // init sub cpu
139         cmd6303_buf = new FIFO(1024);
140         rsp6303_buf = new FIFO(1024);
141         tf20_buf = new FIFO(1024);
142         
143         cmd7508_buf = new FIFO(16);
144         rsp7508_buf = new FIFO(16);
145         key_buf = new FIFO(7);
146         
147         // set pallete
148         pd = RGB_COLOR(48, 56, 16);
149         pb = RGB_COLOR(160, 168, 160);
150         
151         // init 7508
152         get_host_time(&cur_time);
153         onesec_intr = alarm_intr = false;
154         onesec_intr_enb = alarm_intr_enb = kb_intr_enb = true;
155         res_7508 = kb_caps = false;
156         
157         // register events
158         register_frame_event(this);
159         register_event_by_clock(this, EVENT_FRC, 0x40000, true, NULL);
160         register_event_by_clock(this, EVENT_1SEC, CPU_CLOCKS, true, &register_id);
161         register_event_by_clock(this, EVENT_6303, 100, true, NULL);
162 }
163
164 void HC80_IO::release()
165 {
166         // save external ram disk
167         FILEIO* fio = new FILEIO();
168         if(fio->Fopen(create_local_path(_T("VRAM.BIN")), FILEIO_WRITE_BINARY)) {
169                 fio->Fwrite(ram + 0x8000, 0x1800, 1);
170                 fio->Fclose();
171         }
172         if(fio->Fopen(create_local_path(_T("EXTRAM.BIN")), FILEIO_WRITE_BINARY)) {
173                 fio->Fwrite(ext, 0x20000, 1);
174                 fio->Fclose();
175         }
176         if(fio->Fopen(create_local_path(_T("INTRAM.BIN")), FILEIO_WRITE_BINARY)) {
177                 fio->Fwrite(iramdisk_sectors, sizeof(iramdisk_sectors), 1);
178                 fio->Fclose();
179         }
180         delete fio;
181         
182         cmd6303_buf->release();
183         delete cmd6303_buf;
184         rsp6303_buf->release();
185         delete rsp6303_buf;
186         tf20_buf->release();
187         delete tf20_buf;
188         
189         cmd7508_buf->release();
190         delete cmd7508_buf;
191         rsp7508_buf->release();
192         delete rsp7508_buf;
193         key_buf->release();
194         delete key_buf;
195 }
196
197 void HC80_IO::reset()
198 {
199         // reset gapnit
200         bcr = slbcr = isr = ier = ioctlr = 0;
201         icrc = icrb = 0;
202         ear = beep = false;
203         res_z80 = true;
204         key_buf->clear();
205         
206         // reset 6303
207         psr = 0;
208         cs_addr = 0x8100;
209         gs_addr = 0x9500;
210         lcd_on = true;
211         scr_mode = 1;
212         num_lines = 0;
213         flash_block = 0;
214         cs_blocks = gs_blocks = 0;
215         memset(cs_block, 0, sizeof(cs_block));
216         memset(gs_block, 0, sizeof(gs_block));
217         memset(udgc, 0, sizeof(udgc));
218         wnd_ptr_x = wnd_ptr_y = 0;
219         blink = 0;
220         
221         // reset intelligent ram disk
222         iramdisk_count = 0;
223         iramdisk_ptr = iramdisk_buf;
224 }
225
226 void HC80_IO::sysreset()
227 {
228         // reset 7508
229         onesec_intr = alarm_intr = false;
230         onesec_intr_enb = alarm_intr_enb = kb_intr_enb = true;
231         res_7508 = true;
232 }
233
234 void HC80_IO::write_signal(int id, uint32_t data, uint32_t mask)
235 {
236         if(id == SIG_IO_RXRDY) {
237                 // notify rxrdy is changed from i8251
238                 if(data & mask) {
239                         isr |= BIT_8251;
240                 } else {
241                         isr &= ~BIT_8251;
242                 }
243                 update_intr();
244         } else if(id == SIG_IO_BARCODE) {
245                 // signal from barcode reader
246                 if(!slbcr) {
247                         bool next = ((data & mask) != 0);
248                         if((bcr == 2 && ear && !next) || (bcr == 4 && !ear && next) || (bcr == 6 && ear != next)) {
249                                 icrb = get_passed_clock(cur_clock) / 4;
250                                 isr |= BIT_ICF;
251                                 update_intr();
252                         }
253                         ear = next;
254                 }
255         } else if(id == SIG_IO_TF20) {
256                 // recv from tf20
257                 tf20_buf->write(data);
258         }
259 }
260
261 void HC80_IO::event_frame()
262 {
263         d_beep->write_signal(SIG_BEEP_ON, beep ? 1 : 0, 1);
264         beep = false;
265         blink++;
266 }
267
268 void HC80_IO::event_callback(int event_id, int err)
269 {
270         if(event_id == EVENT_FRC) {
271                 // FRC overflow event
272                 cur_clock = get_current_clock();
273                 isr |= BIT_OVF;
274                 update_intr();
275         } else if(event_id == EVENT_1SEC) {
276                 // update rtc
277                 if(cur_time.initialized) {
278                         cur_time.increment();
279                 } else {
280                         get_host_time(&cur_time);       // resync
281                         cur_time.initialized = true;
282                 }
283                 onesec_intr = true;
284                 if(onesec_intr_enb) {
285                         isr |= BIT_7508;
286                         update_intr();
287                 }
288         } else if(event_id == EVENT_6303) {
289                 // communicate between z80 and 6303
290                 if(psr & BIT_OBF) {
291                         psr &= ~BIT_OBF;
292                         process_6303();
293                 }
294                 if(!rsp6303_buf->empty()) {
295                         psr |= BIT_IBF;
296                 }
297         }
298 }
299
300 void HC80_IO::write_io8(uint32_t addr, uint32_t data)
301 {
302         //this->out_debug_log(_T("OUT %2x,%2x\n"), addr & 0xff, data);
303         switch(addr & 0xff) {
304         case 0x00:
305                 // CTLR1
306                 bcr = data & 6;
307                 d_mem->write_signal(0, data, 1);
308                 break;
309         case 0x01:
310                 // CMDR
311                 if(data & 4) {
312                         isr &= ~BIT_OVF;
313                         update_intr();
314                 }
315                 //if(data & 2) {
316                 //      rdysio = false;
317                 //}
318                 //if(data & 1) {
319                 //      rdysio = true;
320                 //}
321                 break;
322         case 0x02:
323                 // CTLR2
324                 break;
325         case 0x04:
326                 // IER
327                 ier = data;
328                 break;
329         case 0x06:
330                 // SIOR
331                 send_to_7508(data);
332                 break;
333         case 0x0c:
334                 // 8251 data write
335                 d_sio->write_io8(0, data);
336                 break;
337         case 0x0d:
338                 // 8251 command write
339                 d_sio->write_io8(1, data);
340                 break;
341         case 0x0e:
342                 // 6303 send data
343                 cmd6303_buf->write(data);
344                 psr |= BIT_OBF;
345 #ifdef OUT_CMD_LOG
346                 this->out_debug_log(_T("%4x\tDAT %2x\n"), get_cpu_pc(0), data);
347 #endif
348                 break;
349         case 0x0f:
350                 // 6303 send command
351                 cmd6303 = data;
352                 psr |= BIT_OBF;
353 #ifdef OUT_CMD_LOG
354                 this->out_debug_log(_T("\n%4x\tCMD %2x\n"), vm->get_cpu_pc(), data);
355 #endif
356                 break;
357         case 0x80:
358                 if(device_type == 1) {
359                         iramdisk_write_data(data);
360                 }
361                 break;
362         case 0x81:
363                 if(device_type == 1) {
364                         iramdisk_write_cmd(data);
365                 }
366                 break;
367         case 0x90:
368                 // EXTAR
369                 if(device_type == 2) {
370                         extar = (extar & 0xffff00) | data;
371                 }
372                 break;
373         case 0x91:
374                 // EXTAR
375                 if(device_type == 2) {
376                         extar = (extar & 0xff00ff) | (data << 8);
377                 }
378                 break;
379         case 0x92:
380                 // EXTAR
381                 if(device_type == 2) {
382                         extar = (extar & 0x00ffff) | ((data & 7) << 16);
383                 }
384                 break;
385         case 0x93:
386                 // EXTOR
387                 if(device_type == 2) {
388                         if(extar < 0x20000) {
389                                 ext[extar] = data;
390                         }
391                         extar = (extar & 0xffff00) | ((extar + 1) & 0xff);
392                 }
393                 break;
394         case 0x94:
395                 // EXTCR
396                 if(device_type == 2) {
397                         extcr = data;
398                 }
399                 break;
400         }
401 }
402
403 uint32_t HC80_IO::read_io8(uint32_t addr)
404 {
405         uint32_t val = 0xff;
406 //      this->out_debug_log(_T("IN %2x\n"), addr & 0xff);
407         
408         switch(addr & 0xff) {
409         case 0x00:
410                 // ICRL.C (latch FRC value)
411                 icrc = get_passed_clock(cur_clock) / 4;
412                 return icrc & 0xff;
413         case 0x01:
414                 // ICRH.C
415                 return (icrc >> 8) & 0xff;
416         case 0x02:
417                 // ICRL.B
418                 return icrb & 0xff;
419         case 0x03:
420                 // ICRH.B
421                 isr &= ~BIT_ICF;
422                 update_intr();
423                 return (icrb >> 8) & 0xff;
424         case 0x04:
425                 // ISR
426                 return isr;
427         case 0x05:
428                 // STR
429                 return 8 | 4 | (ear ? 1 : 0);   // always rdysio=rdy=true
430         case 0x06:
431                 // SIOR
432                 return rec_from_7508();
433         case 0x0c:
434                 // 8251 data read
435                 isr &= ~BIT_8251;
436                 update_intr();
437                 return d_sio->read_io8(0);
438         case 0x0d:
439                 // 8251 status read
440                 return d_sio->read_io8(1);
441         case 0x0e:
442                 // 6303 status
443                 return psr;
444         case 0x0f:
445                 // 6303 recv data
446                 val = rsp6303_buf->read();
447                 psr &= ~BIT_IBF;
448                 if(!rsp6303_buf->empty()) {
449                         psr &= ~BIT_F1;
450                 }
451 #ifdef OUT_CMD_LOG
452                 this->out_debug_log(_T("%4x\tRCV %2x\n"), vm->get_cpu_pc(), val);
453 #endif
454                 return val;
455         case 0x80:
456                 if(device_type == 1) {
457                         return iramdisk_read_data();
458                 }
459                 return 0xff;
460         case 0x81:
461                 if(device_type == 1) {
462                         return iramdisk_read_stat();
463                 }
464                 return 0xff;
465         case 0x93:
466                 // EXTIR
467                 if(device_type == 2) {
468                         if(extar < 0x40000) {
469                                 val = ext[extar];
470                         }
471                         extar = (extar & 0xffff00) | ((extar + 1) & 0xff);
472                         return val;
473                 }
474                 return 0xff;
475         case 0x94:
476                 // EXTSR
477                 if(device_type == 2) {
478                         return extcr & ~0x80;
479                 }
480                 return 0xff;
481         }
482         return 0xff;
483 }
484
485 uint32_t HC80_IO::get_intr_ack()
486 {
487         if(isr & BIT_7508) {
488                 isr &= ~BIT_7508;
489                 return 0xf0;
490         } else if(isr & BIT_8251) {
491                 return 0xf2;
492         } else if(isr & BIT_CD) {
493                 return 0xf4;
494         } else if(isr & BIT_ICF) {
495                 return 0xf6;
496         } else if(isr & BIT_OVF) {
497                 return 0xf8;
498         } else if(isr & BIT_EXT) {
499                 return 0xfa;
500         }
501         // unknown
502         return 0xff;
503 }
504
505 void HC80_IO::update_intr()
506 {
507         // set int signal
508         bool next = ((isr & ier & 0x3f) != 0);
509         d_cpu->set_intr_line(next, true, 0);
510 }
511
512 // ----------------------------------------------------------------------------
513 // 7508
514 // ----------------------------------------------------------------------------
515
516 void HC80_IO::send_to_7508(uint8_t val)
517 {
518         int res;
519         
520         // process command
521         cmd7508_buf->write(val);
522         uint8_t cmd = cmd7508_buf->read_not_remove(0);
523         
524         switch(cmd) {
525         case 0x01:
526                 // power off
527                 cmd7508_buf->read();
528                 break;
529         case 0x02:
530                 // status / key
531                 cmd7508_buf->read();
532                 if((onesec_intr && onesec_intr_enb) || (alarm_intr && alarm_intr_enb) || res_z80 || res_7508) {
533                         res = 0xc1;
534                         res |= (onesec_intr && onesec_intr_enb) ? 0x20 : 0;
535                         res |= (res_z80 ? 0x10 : 0) | (res_7508 ? 8 : 0);
536                         res |= (alarm_intr && alarm_intr_enb) ? 2 : 0;
537                         // clear interrupt
538                         onesec_intr = alarm_intr = res_z80 = res_7508 = false;
539                 } else if(key_buf->count()) {
540                         res = key_buf->read();
541                 } else {
542                         res = 0xbf;
543                 }
544                 rsp7508_buf->write(res);
545                 // request next interrupt
546                 if(key_buf->count() && kb_intr_enb) {
547                         isr |= BIT_7508;
548                         update_intr();
549                 }
550                 break;
551         case 0x03:
552                 // kb reset
553                 cmd7508_buf->read();
554                 key_buf->clear();
555                 kb_rep_spd1 = 42 | 0x80;
556                 kb_rep_spd2 = 18 | 0x80;
557                 kb_intr_enb = true;
558                 break;
559         case 0x04:
560                 // kb repeat timer 1 set
561                 if(cmd7508_buf->count() == 2) {
562                         cmd7508_buf->read();
563                         kb_rep_spd1 = cmd7508_buf->read();
564                 }
565                 break;
566         case 0x05:
567                 // kb repeat off
568                 cmd7508_buf->read();
569                 kb_rep_enb = false;
570                 break;
571         case 0x06:
572                 // kb interrupt off
573                 cmd7508_buf->read();
574                 kb_intr_enb = false;
575                 break;
576         case 0x07:
577                 // clock read
578                 cmd7508_buf->read();
579                 rsp7508_buf->write(TO_BCD_HI(cur_time.year));
580                 rsp7508_buf->write(TO_BCD_LO(cur_time.year));
581                 rsp7508_buf->write(TO_BCD(cur_time.month));
582                 rsp7508_buf->write(TO_BCD(cur_time.day));
583                 rsp7508_buf->write(TO_BCD(cur_time.hour));
584                 rsp7508_buf->write(TO_BCD(cur_time.minute));
585                 rsp7508_buf->write(TO_BCD(cur_time.second));
586                 rsp7508_buf->write(cur_time.day_of_week);
587                 break;
588         case 0x08:
589                 // power switch read
590                 cmd7508_buf->read();
591                 rsp7508_buf->write(1);
592                 break;
593         case 0x09:
594                 // alarm read
595                 cmd7508_buf->read();
596                 rsp7508_buf->write(alarm[0]);
597                 rsp7508_buf->write(alarm[1]);
598                 rsp7508_buf->write(alarm[2]);
599                 rsp7508_buf->write(alarm[3]);
600                 rsp7508_buf->write(alarm[4]);
601                 rsp7508_buf->write(alarm[5]);
602                 break;
603         case 0x0a:
604                 // dip switch read
605                 cmd7508_buf->read();
606                 res = 0xf;      // ascii keyboard
607                 rsp7508_buf->write(res);
608                 break;
609         case 0x0b:
610                 // set power failure detect voltage
611                 if(cmd7508_buf->count() == 2) {
612                         cmd7508_buf->read();
613                         cmd7508_buf->read();
614                 }
615                 break;
616         case 0x0c:
617                 // read buttery voltage
618                 cmd7508_buf->read();
619                 rsp7508_buf->write(0xe0);
620                 break;
621         case 0x0d:
622                 // 1 sec interrupt off
623                 cmd7508_buf->read();
624                 onesec_intr_enb = false;
625                 break;
626         case 0x0e:
627                 // kb clear
628                 cmd7508_buf->read();
629                 key_buf->clear();
630                 break;
631         case 0x0f:
632                 // system reset
633                 cmd7508_buf->read();
634                 res_7508 = true;
635                 break;
636         case 0x14:
637                 // kb repeat timer 2 set
638                 if(cmd7508_buf->count() == 2) {
639                         cmd7508_buf->read();
640                         kb_rep_spd2 = cmd7508_buf->read();
641                 }
642                 break;
643         case 0x15:
644                 // kb repeat on
645                 cmd7508_buf->read();
646                 kb_rep_enb = true;
647                 break;
648         case 0x16:
649                 // kb interrupt on
650                 cmd7508_buf->read();
651                 kb_intr_enb = true;
652                 break;
653         case 0x17:
654                 // clock write
655                 if(cmd7508_buf->count() == 9) {
656                         cmd7508_buf->read();
657                         int year10 = cmd7508_buf->read();
658                         int year1 = cmd7508_buf->read();
659                         int month = cmd7508_buf->read();
660                         int day = cmd7508_buf->read();
661                         int hour = cmd7508_buf->read();
662                         int minute = cmd7508_buf->read();
663                         int second = cmd7508_buf->read();
664                         int day_of_week = cmd7508_buf->read();
665                         
666                         if((month & 0x0f) == 0 || (day & 0x0f) == 0) {
667                                 // invalid date
668                                 get_host_time(&cur_time);
669                         } else {
670                                 bool changed = false;
671                                 if((year10 & 0x0f) != 0x0f && (year1 & 0x0f) != 0x0f) {
672                                         cur_time.year = (year10 & 0x0f) * 10 + (year1 & 0x0f);
673                                         cur_time.update_year();
674                                         changed = true;
675                                 }
676                                 if((month & 0x0f) != 0x0f) {
677                                         cur_time.month = FROM_BCD(month & 0x1f);
678                                         changed = true;
679                                 }
680                                 if((day & 0x0f) != 0x0f) {
681                                         cur_time.day = FROM_BCD(day & 0x3f);
682                                         changed = true;
683                                 }
684                                 if((hour & 0x0f) != 0x0f) {
685                                         cur_time.hour = FROM_BCD(hour & 0x3f);
686                                         changed = true;
687                                 }
688                                 if((minute & 0x0f) != 0x0f) {
689                                         cur_time.minute = FROM_BCD(minute & 0x7f);
690                                         changed = true;
691                                 }
692                                 if((second & 0x0f) != 0x0f) {
693                                         cur_time.second = FROM_BCD(second & 0x7f);
694                                         changed = true;
695                                 }
696 //                              if((day_of_week & 0x0f) != 0x0f) {
697 //                                      cur_time.day_of_week = day_of_week & 0x07;
698 //                                      changed = true;
699 //                              }
700                                 if(changed) {
701                                         cur_time.update_day_of_week();
702                                         // restart event
703                                         cancel_event(this, register_id);
704                                         register_event_by_clock(this, EVENT_1SEC, CPU_CLOCKS, true, &register_id);
705                                 }
706                         }
707                 }
708                 break;
709         case 0x19:
710                 // alarm set
711                 if(cmd7508_buf->count() == 7) {
712                         cmd7508_buf->read();
713                         alarm[0] = cmd7508_buf->read();
714                         alarm[1] = cmd7508_buf->read();
715                         alarm[2] = cmd7508_buf->read();
716                         alarm[3] = cmd7508_buf->read();
717                         alarm[4] = cmd7508_buf->read();
718                         alarm[5] = cmd7508_buf->read();
719                 }
720                 break;
721         case 0x1b:
722                 // set full charge voltage
723                 if(cmd7508_buf->count() == 2) {
724                         cmd7508_buf->read();
725                         cmd7508_buf->read();
726                 }
727                 break;
728         case 0x1c:
729                 // read temperature
730                 cmd7508_buf->read();
731                 rsp7508_buf->write(0x90);
732                 break;
733         case 0x1d:
734                 // 1 sec interrupt on
735                 cmd7508_buf->read();
736                 onesec_intr_enb = true;
737                 break;
738         case 0x24:
739                 // kb repeat timer 1 read
740                 cmd7508_buf->read();
741                 rsp7508_buf->write(kb_rep_spd1);
742                 break;
743         case 0x29:
744                 // alarm off
745                 cmd7508_buf->read();
746                 alarm_intr_enb = false;
747                 break;
748         case 0x2c:
749                 // read analog jack 1
750                 cmd7508_buf->read();
751                 rsp7508_buf->write(0);
752                 break;
753         case 0x34:
754                 // kb repeat timer 2 read
755                 cmd7508_buf->read();
756                 rsp7508_buf->write(kb_rep_spd2);
757                 break;
758         case 0x39:
759                 // alarm on
760                 cmd7508_buf->read();
761                 alarm_intr_enb = true;
762                 break;
763         case 0x3c:
764                 // read analog jack 2
765                 cmd7508_buf->read();
766                 rsp7508_buf->write(0);
767                 break;
768         default:
769                 // unknown cmd
770                 cmd7508_buf->read();
771                 this->out_debug_log(_T("unknown cmd %2x\n"), cmd);
772         }
773 }
774
775 uint8_t HC80_IO::rec_from_7508()
776 {
777         return rsp7508_buf->read();
778 }
779
780 void HC80_IO::key_down(int code)
781 {
782         if(code == 0x14) {
783                 // toggle caps lock
784                 kb_caps = !kb_caps;
785                 update_key(kb_caps ? 0xb4 : 0xa4);
786                 update_key(kb_caps ? 0xa4 : 0xb4);
787         } else {
788                 update_key(key_tbl[code & 0xff]);
789         }
790 }
791
792 void HC80_IO::key_up(int code)
793 {
794         if(code == 0x10) {
795                 update_key(0xa3);       // break shift
796         } else if(code == 0x11) {
797                 update_key(0xa2);       // break ctrl
798         }
799 }
800
801 void HC80_IO::update_key(int code)
802 {
803         if(code != 0xff) {
804                 // add to buffer
805                 if(code == 0x10) {
806                         // stop key
807                         key_buf->clear();
808                         key_buf->write(code);
809                 } else {
810                         key_buf->write(code);
811                 }
812                 
813                 // key interrupt
814                 if(kb_intr_enb || (!kb_intr_enb && code == 0x10)) {
815                         isr |= BIT_7508;
816                         update_intr();
817                 }
818         }
819 }
820
821 // ----------------------------------------------------------------------------
822 // 6303
823 // ----------------------------------------------------------------------------
824
825 void HC80_IO::process_6303()
826 {
827         switch(cmd6303) {
828         case 0x00:
829                 // read data
830                 if(cmd6303_buf->count() == 2) {
831                         uint16_t addr = cmd6303_buf->read() << 8;
832                         addr |= cmd6303_buf->read();
833                         rsp6303_buf->write(RCD00);
834                         rsp6303_buf->write(ram[addr]);
835                         psr |= BIT_F1;
836                 }
837                 break;
838         case 0x01:
839                 // write data
840                 if(cmd6303_buf->count() == 4) {
841                         uint16_t addr = cmd6303_buf->read() << 8;
842                         addr |= cmd6303_buf->read();
843                         uint8_t val = cmd6303_buf->read();
844                         uint8_t ope = cmd6303_buf->read();
845                         if(ope == 1) {
846                                 ram[addr] &= val;
847                         } else if(ope == 2) {
848                                 ram[addr] |= val;
849                         } else if(ope == 3) {
850                                 ram[addr] ^= val;
851                         } else {
852                                 ram[addr] = val;
853                         }
854                         rsp6303_buf->write(RCD00);
855                         psr |= BIT_F1;
856                 }
857                 break;
858         case 0x02:
859                 // execute routine
860                 if(cmd6303_buf->count() == 2) {
861                         uint16_t addr = cmd6303_buf->read() << 8;
862                         addr |= cmd6303_buf->read();
863                         // unknown
864                         rsp6303_buf->write(RCD00);
865                         psr |= BIT_F1;
866                 }
867                 break;
868         case 0x0b:
869                 // unknown (initialize???)
870                 rsp6303_buf->write(RCD00);
871                 psr |= BIT_F1;
872                 break;
873         case 0x10:
874                 // define screen mode
875                 if(cmd6303_buf->count() == 16) {
876                         cs_addr = cmd6303_buf->read() << 8;
877                         cs_addr |= cmd6303_buf->read();
878                         gs_addr = cmd6303_buf->read() << 8;
879                         gs_addr |= cmd6303_buf->read();
880                         cmd6303_buf->read();
881                         cmd6303_buf->read();
882                         cmd6303_buf->read();
883                         cmd6303_buf->read();
884                         cmd6303_buf->read();
885                         cmd6303_buf->read();
886                         cmd6303_buf->read();
887                         cmd6303_buf->read();
888                         uint16_t bottom = cmd6303_buf->read() << 8;
889                         bottom |= cmd6303_buf->read();
890                         cmd6303_buf->read();
891                         cmd6303_buf->read();
892                         rsp6303_buf->write(RCD00);
893                         psr |= BIT_F1;
894                         // go to character screen mode ???
895                         scr_mode = 0xff;
896                         // stop block flashing ???
897                         flash_block = 0;
898                         cs_blocks = gs_blocks = 0;
899                         // clear screen ???
900                         memset(&ram[cs_addr], 0, bottom - cs_addr);
901                 }
902                 break;
903         case 0x11:
904                 // turn on/off lcd
905                 if(cmd6303_buf->count() == 1) {
906                         lcd_on = cmd6303_buf->read();
907                         rsp6303_buf->write(RCD00);
908                         psr |= BIT_F1;
909                 }
910                 break;
911         case 0x12:
912                 // select screen
913                 if(cmd6303_buf->count() == 1) {
914                         scr_mode = cmd6303_buf->read();
915                         if(!scr_mode) {
916                                 scr_ptr = cs_addr;
917                         }
918                         rsp6303_buf->write(RCD00);
919                         psr |= BIT_F1;
920                 }
921                 break;
922         case 0x13:
923                 // read screen pointer
924                 rsp6303_buf->write(RCD00);
925                 rsp6303_buf->write(scr_ptr >> 8);
926                 rsp6303_buf->write(scr_ptr & 0xff);
927                 psr |= BIT_F1;
928                 break;
929         case 0x14:
930                 // set screen pointer
931                 if(cmd6303_buf->count() == 2) {
932                         scr_ptr = cmd6303_buf->read() << 8;
933                         scr_ptr |= cmd6303_buf->read();
934                         rsp6303_buf->write(RCD00);
935                         psr |= BIT_F1;
936                         // stop block flashing ???
937                         flash_block = 0;
938                         cs_blocks = gs_blocks = 0;
939                 }
940                 break;
941         case 0x15:
942                 // define number of lines
943                 if(cmd6303_buf->count() == 1) {
944                         num_lines = cmd6303_buf->read();
945                         rsp6303_buf->write(RCD00);
946                         psr |= BIT_F1;
947                 }
948                 break;
949         case 0x16:
950                 // define cursor mode
951                 if(cmd6303_buf->count() == 1) {
952                         curs_mode = cmd6303_buf->read();
953                         rsp6303_buf->write(RCD00);
954                         psr |= BIT_F1;
955                 }
956                 break;
957         case 0x17:
958                 // read cursur position
959                 rsp6303_buf->write(RCD00);
960                 rsp6303_buf->write(curs_x);
961                 rsp6303_buf->write(curs_y);
962                 psr |= BIT_F1;
963                 break;
964         case 0x18:
965                 // set cursor position
966                 if(cmd6303_buf->count() == 2) {
967                         curs_x = cmd6303_buf->read();
968                         curs_y = cmd6303_buf->read();
969                         rsp6303_buf->write(RCD00);
970                         psr |= BIT_F1;
971                 }
972                 break;
973         case 0x19:
974                 // start/stop control block flashing
975                 if(cmd6303_buf->count() == 1) {
976                         flash_block = cmd6303_buf->read();
977                         rsp6303_buf->write(RCD00);
978                         psr |= BIT_F1;
979                 }
980                 break;
981         case 0x1a:
982                 // clear screen
983                 if(cmd6303_buf->count() == 4) {
984                         uint8_t scr = cmd6303_buf->read();
985                         uint8_t code = cmd6303_buf->read();
986                         int sy = cmd6303_buf->read();
987                         int num = cmd6303_buf->read();
988                         if(scr) {
989                                 // char screen
990                                 for(int y = 0; y < num; y++) {
991                                         if(sy + y < 64) {
992                                                 memset(&ram[cs_addr + (sy + y) * 80], code, 80);
993                                         }
994                                 }
995                         } else {
996                                 // graph screen
997                                 for(int y = 0; y < num; y++) {
998                                         if(sy + y < 8) {
999                                                 memset(&ram[gs_addr + (sy + y) * 60 * 8], code, 60 * 8);
1000                                         }
1001                                 }
1002                         }
1003                         rsp6303_buf->write(RCD00);
1004                         psr |= BIT_F1;
1005                 }
1006                 break;
1007         case 0x1b:
1008                 // read character font
1009                 if(cmd6303_buf->count() == 1) {
1010                         int ofs = cmd6303_buf->read() << 3;
1011                         rsp6303_buf->write(RCD00);
1012                         for(int i = 0; i < 8; i++) {
1013                                 rsp6303_buf->write(font[ofs + i]);
1014                         }
1015                         psr |= BIT_F1;
1016                 }
1017                 break;
1018         case 0x20:
1019                 // define user defined graphic character
1020                 if(cmd6303_buf->count() >= 3) {
1021                         int lx = cmd6303_buf->read_not_remove(1);
1022                         int ly = cmd6303_buf->read_not_remove(2);
1023                         if(cmd6303_buf->count() == lx * ly + 3) {
1024                                 uint8_t code = cmd6303_buf->read();
1025                                 bool pre = (udgc[code][0] && udgc[code][1]);
1026                                 for(int i = 0; i < lx * ly + 2; i++) {
1027                                         uint8_t d = cmd6303_buf->read();
1028                                         if(!pre) {
1029                                                 udgc[code][i] = d;
1030                                         }
1031                                 }
1032                                 if(!code) {
1033                                         memset(udgc, 0, sizeof(udgc));
1034                                 }
1035                                 rsp6303_buf->write(RCD00);
1036                                 psr |= BIT_F1;
1037                         }
1038                 }
1039                 break;
1040         case 0x21:
1041                 // define graphic screen block flashing data
1042                 if(cmd6303_buf->count() >= 1) {
1043                         int cnt = cmd6303_buf->read_not_remove(0);
1044                         if(cmd6303_buf->count() == cnt * 3 + 1) {
1045                                 gs_blocks = cmd6303_buf->read();
1046                                 for(int i = 0; i < gs_blocks; i++) {
1047                                         gs_block[i][0] = cmd6303_buf->read();
1048                                         gs_block[i][1] = cmd6303_buf->read();
1049                                         gs_block[i][2] = cmd6303_buf->read();
1050                                 }
1051                                 rsp6303_buf->write(RCD00);
1052                                 psr |= BIT_F1;
1053                         }
1054                 }
1055                 break;
1056         case 0x22:
1057                 // draw character font on graphic screen
1058                 if(cmd6303_buf->count() == 4) {
1059                         int x = cmd6303_buf->read() << 8;
1060                         x |= cmd6303_buf->read();
1061                         int y = cmd6303_buf->read();
1062                         int ofs = cmd6303_buf->read() << 3;
1063                         for(int l = 0; l < 8; l++) {
1064                                 uint8_t pat = font[ofs + l];
1065                                 draw_point(x + 0, y + l, pat & 0x20);
1066                                 draw_point(x + 1, y + l, pat & 0x10);
1067                                 draw_point(x + 2, y + l, pat & 0x08);
1068                                 draw_point(x + 3, y + l, pat & 0x04);
1069                                 draw_point(x + 4, y + l, pat & 0x02);
1070                                 draw_point(x + 5, y + l, pat & 0x01);
1071                         }
1072                         rsp6303_buf->write(RCD00);
1073                         psr |= BIT_F1;
1074                 }
1075                 break;
1076         case 0x23:
1077                 // draw user defined character on graphics screen
1078                 if(cmd6303_buf->count() >= 3) {
1079                         int dx = cmd6303_buf->read();
1080                         int dy = cmd6303_buf->read();
1081                         uint8_t code = cmd6303_buf->read();
1082                         int lx = udgc[code][0];
1083                         int ly = udgc[code][1];
1084                         uint8_t* pat = &udgc[code][2];
1085                         if(lx && ly) {
1086                                 for(int y = 0; y < ly; y++) {
1087                                         for(int x = 0; x < lx; x++) {
1088                                                 if(dx + x < 60 && dy + y < 64) {
1089                                                         ram[gs_addr + (dx + x + (dy + y) * 60)] = *pat++;
1090                                                 }
1091                                         }
1092                                 }
1093                         }
1094                         rsp6303_buf->write(RCD00);
1095                         psr |= BIT_F1;
1096                 }
1097                 break;
1098         case 0x24:
1099                 // read graphics screen data
1100                 if(cmd6303_buf->count() == 3) {
1101                         int x = cmd6303_buf->read();
1102                         int y = cmd6303_buf->read();
1103                         uint8_t* src = &ram[gs_addr + (x + y * 60)];
1104                         int cnt = cmd6303_buf->read();
1105                         rsp6303_buf->write(RCD00);
1106                         for(int i = 0; i < cnt; i++) {
1107                                 rsp6303_buf->write(src[i]);
1108                         }
1109                         psr |= BIT_F1;
1110                 }
1111                 break;
1112         case 0x25:
1113                 // display data on graphics screen
1114                 if(cmd6303_buf->count() >= 4) {
1115                         int lx = cmd6303_buf->read_not_remove(2);
1116                         int ly = cmd6303_buf->read_not_remove(3);
1117                         if(cmd6303_buf->count() == lx * ly + 5) {
1118                                 int dx = cmd6303_buf->read();
1119                                 int dy = cmd6303_buf->read();
1120                                 lx = cmd6303_buf->read();
1121                                 ly = cmd6303_buf->read();
1122                                 uint8_t ope = cmd6303_buf->read();
1123                                 for(int y = 0; y < ly; y++) {
1124                                         for(int x = 0; x < lx; x++) {
1125                                                 uint8_t d = cmd6303_buf->read();
1126                                                 if(dx + x < 60 && dy + y < 64) {
1127                                                         if(ope == 1) {
1128                                                                 ram[gs_addr + (dx + x + (dy + y) * 60)] &= d;
1129                                                         } else if(ope == 2) {
1130                                                                 ram[gs_addr + (dx + x + (dy + y) * 60)] |= d;
1131                                                         } else if(ope == 3) {
1132                                                                 ram[gs_addr + (dx + x + (dy + y) * 60)] ^= d;
1133                                                         } else {
1134                                                                 ram[gs_addr + (dx + x + (dy + y) * 60)] = d;
1135                                                         }
1136                                                 }
1137                                         }
1138                                 }
1139                                 rsp6303_buf->write(RCD00);
1140                                 psr |= BIT_F1;
1141                         }
1142                 }
1143                 break;
1144         case 0x26:
1145                 // move graphics screen block
1146                 if(cmd6303_buf->count() == 6) {
1147                         int sx = cmd6303_buf->read();
1148                         int sy = cmd6303_buf->read();
1149                         int lx = cmd6303_buf->read();
1150                         int ly = cmd6303_buf->read();
1151                         int dx = cmd6303_buf->read();
1152                         int dy = cmd6303_buf->read();
1153                         for(int y = 0; y < ly; y++) {
1154                                 for(int x = 0; x < lx; x++) {
1155                                         if(sx + x < 60 && sy + y < 64) {
1156                                                 mov[y][x] = ram[gs_addr + (sx + x + (sy + y) * 60)];
1157                                                 ram[gs_addr + (sx + x + (sy + y) * 60)] = 0;
1158                                         }
1159                                 }
1160                         }
1161                         for(int y = 0; y < ly; y++) {
1162                                 for(int x = 0; x < lx; x++) {
1163                                         if(dx + x < 60 && dy + y < 64) {
1164                                                 ram[gs_addr + (dx + x + (dy + y) * 60)] = mov[y][x];
1165                                         }
1166                                 }
1167                         }
1168                         rsp6303_buf->write(RCD00);
1169                         psr |= BIT_F1;
1170                 }
1171                 break;
1172         case 0x27:
1173                 // define point
1174                 if(cmd6303_buf->count() == 4) {
1175                         int x = cmd6303_buf->read() << 8;
1176                         x |= cmd6303_buf->read();
1177                         int y = cmd6303_buf->read();
1178                         uint8_t ope = cmd6303_buf->read();
1179                         if(ope == 1) {
1180                                 draw_point(x, y, 0);
1181                         } else {
1182                                 draw_point(x, y, 1);
1183                         }
1184                         rsp6303_buf->write(RCD00);
1185                         psr |= BIT_F1;
1186                 }
1187                 break;
1188         case 0x28:
1189                 // read point
1190                 if(cmd6303_buf->count() == 3) {
1191                         int x = cmd6303_buf->read() << 8;
1192                         x |= cmd6303_buf->read();
1193                         int y = cmd6303_buf->read();
1194                         rsp6303_buf->write(RCD00);
1195                         rsp6303_buf->write(get_point(x, y));
1196                         psr |= BIT_F1;
1197                 }
1198                 break;
1199         case 0x29:
1200                 // draw line
1201                 if(cmd6303_buf->count() == 11) {
1202                         int sx = cmd6303_buf->read() << 8;
1203                         sx |= cmd6303_buf->read();
1204                         int sy = cmd6303_buf->read() << 8;
1205                         sy |= cmd6303_buf->read();
1206                         int ex = cmd6303_buf->read() << 8;
1207                         ex |= cmd6303_buf->read();
1208                         int ey = cmd6303_buf->read() << 8;
1209                         ey |= cmd6303_buf->read();
1210                         uint16_t ope = cmd6303_buf->read() << 8;
1211                         ope |= cmd6303_buf->read();
1212                         uint8_t mode = cmd6303_buf->read();
1213                         if(mode == 1) {
1214                                 draw_line(sx, sy, ex, ey, ~ope);
1215                         } else {
1216                                 draw_line(sx, sy, ex, ey, ope);
1217                         }
1218                         rsp6303_buf->write(RCD00);
1219                         psr |= BIT_F1;
1220                 }
1221                 break;
1222         case 0x30:
1223                 // user defined character
1224                 if(cmd6303_buf->count() == 9) {
1225                         int code = cmd6303_buf->read();
1226                         if(code < 0xe0) {
1227                                 for(int i = 0; i < 8; i++) {
1228                                         cmd6303_buf->read();
1229                                 }
1230                                 rsp6303_buf->write(RCD06);
1231                         } else {
1232                                 int ofs = code << 3;
1233                                 for(int i = 0; i < 8; i++) {
1234                                         font[ofs + i] = cmd6303_buf->read();
1235                                 }
1236                                 rsp6303_buf->write(RCD00);
1237                         }
1238                         psr |= BIT_F1;
1239                 }
1240                 break;
1241         case 0x31:
1242                 // define character screen block flashing data
1243                 if(cmd6303_buf->count() >= 1) {
1244                         int cnt = cmd6303_buf->read_not_remove(0);
1245                         if(cmd6303_buf->count() == cnt * 3 + 1) {
1246                                 cs_blocks = cmd6303_buf->read();
1247                                 for(int i = 0; i < cs_blocks; i++) {
1248                                         cs_block[i][0] = cmd6303_buf->read();
1249                                         cs_block[i][1] = cmd6303_buf->read();
1250                                         cs_block[i][2] = cmd6303_buf->read();
1251                                 }
1252                                 rsp6303_buf->write(RCD00);
1253                                 psr |= BIT_F1;
1254                         }
1255                 }
1256                 break;
1257         case 0x32:
1258                 // read window pointer
1259                 rsp6303_buf->write(RCD00);
1260                 rsp6303_buf->write(wnd_ptr_x);
1261                 rsp6303_buf->write(wnd_ptr_y);
1262                 psr |= BIT_F1;
1263                 break;
1264         case 0x33:
1265                 // set window pointer
1266                 if(cmd6303_buf->count() == 2) {
1267                         wnd_ptr_x = cmd6303_buf->read();
1268                         wnd_ptr_y = cmd6303_buf->read();
1269                         rsp6303_buf->write(RCD00);
1270                         psr |= BIT_F1;
1271                 }
1272                 break;
1273         case 0x34:
1274                 // read character screen data
1275                 if(cmd6303_buf->count() == 3) {
1276                         int x = cmd6303_buf->read();
1277                         int y = cmd6303_buf->read();
1278                         uint8_t* src = &ram[cs_addr + (x + y * 80)];
1279                         int cnt = cmd6303_buf->read();
1280                         rsp6303_buf->write(RCD00);
1281                         for(int i = 0; i < cnt; i++) {
1282                                 rsp6303_buf->write(src[i]);
1283                         }
1284                         psr |= BIT_F1;
1285                 }
1286                 break;
1287         case 0x35:
1288                 // display data on character screen
1289                 if(cmd6303_buf->count() >= 4) {
1290                         int cnt = cmd6303_buf->read_not_remove(2);
1291                         if(cmd6303_buf->count() == cnt + 3) {
1292                                 int x = cmd6303_buf->read();
1293                                 int y = cmd6303_buf->read();
1294                                 uint8_t* dest = &ram[cs_addr + (x + y * 80)];
1295                                 cnt = cmd6303_buf->read();
1296                                 for(int i = 0; i < cnt; i++) {
1297                                         dest[i] = cmd6303_buf->read();
1298                                 }
1299                                 rsp6303_buf->write(RCD00);
1300                                 psr |= BIT_F1;
1301                         }
1302                 }
1303                 break;
1304         case 0x36:
1305                 // move character screen block
1306                 if(cmd6303_buf->count() == 6) {
1307                         int sx = cmd6303_buf->read();
1308                         int sy = cmd6303_buf->read();
1309                         int lx = cmd6303_buf->read();
1310                         int ly = cmd6303_buf->read();
1311                         int dx = cmd6303_buf->read();
1312                         int dy = cmd6303_buf->read();
1313                         for(int y = 0; y < ly; y++) {
1314                                 for(int x = 0; x < lx; x++) {
1315                                         if(sx + x < 80 && sy + y < 64) {
1316                                                 mov[y][x] = ram[cs_addr + (sx + x + (sy + y) * 80)];
1317 //                                              ram[cs_addr + (sx + x + (sy + y) * 80)] = 0;
1318                                         }
1319                                 }
1320                         }
1321                         for(int y = 0; y < ly; y++) {
1322                                 for(int x = 0; x < lx; x++) {
1323                                         if(dx + x < 80 && dy + y < 64) {
1324                                                 ram[cs_addr + (dx + x + (dy + y) * 80)] = mov[y][x];
1325                                         }
1326                                 }
1327                         }
1328                         rsp6303_buf->write(RCD00);
1329                         psr |= BIT_F1;
1330                 }
1331                 break;
1332         case 0x40:
1333                 // read microcassette status
1334                 rsp6303_buf->write(RCD00);
1335                 rsp6303_buf->write(0);
1336                 psr |= BIT_F1;
1337                 break;
1338         case 0x41:
1339                 // head on
1340                 rsp6303_buf->write(RCD07);
1341                 psr |= BIT_F1;
1342                 break;
1343         case 0x42:
1344                 // head off
1345                 rsp6303_buf->write(RCD00);
1346                 psr |= BIT_F1;
1347                 break;
1348         case 0x43:
1349                 // rewind n counts
1350         case 0x44:
1351                 // fast foward n counts
1352                 if(cmd6303_buf->count() == 2) {
1353                         cmd6303_buf->read();
1354                         cmd6303_buf->read();
1355                         rsp6303_buf->write(RCD07);
1356                         psr |= BIT_F1;
1357                 }
1358                 break;
1359         case 0x45:
1360                 // rewind
1361         case 0x47:
1362                 // slow rewind
1363                 rsp6303_buf->write(RCD07);
1364                 psr |= BIT_F1;
1365                 break;
1366         case 0x46:
1367                 // fast foward
1368         case 0x48:
1369                 // play
1370         case 0x49:
1371                 // record
1372         case 0x4a:
1373                 // stop
1374                 rsp6303_buf->write(RCD00);
1375                 psr |= BIT_F1;
1376                 break;
1377         case 0x4b:
1378                 // read write protect pin
1379                 rsp6303_buf->write(RCD00);
1380                 rsp6303_buf->write(0);
1381                 psr |= BIT_F1;
1382                 break;
1383         case 0x4c:
1384                 // read counter
1385                 rsp6303_buf->write(RCD00);
1386                 rsp6303_buf->write(0);
1387                 rsp6303_buf->write(0);
1388                 psr |= BIT_F1;
1389                 break;
1390         case 0x4d:
1391                 // set counter
1392                 if(cmd6303_buf->count() == 2) {
1393                         cmd6303_buf->read();
1394                         cmd6303_buf->read();
1395                         rsp6303_buf->write(RCD00);
1396                         psr |= BIT_F1;
1397                 }
1398                 break;
1399         case 0x55:
1400                 // set write protect area pointer
1401                 if(cmd6303_buf->count() == 2) {
1402                         cmd6303_buf->read();
1403                         cmd6303_buf->read();
1404                         rsp6303_buf->write(RCD00);
1405                         psr |= BIT_F1;
1406                 }
1407                 break;
1408         case 0x56:
1409                 // reset write protect area pointer
1410                 rsp6303_buf->write(RCD00);
1411                 psr |= BIT_F1;
1412                 break;
1413         case 0x60:
1414                 // read serial i/o status
1415                 rsp6303_buf->write(RCD00);
1416                 rsp6303_buf->write(0x20 | (tf20_buf->count() ? 0x80 : 0));
1417                 psr |= BIT_F1;
1418                 break;
1419         case 0x61:
1420                 // set serial port bit rate
1421                 if(cmd6303_buf->count() == 1) {
1422                         cmd6303_buf->read();
1423                         rsp6303_buf->write(RCD00);
1424                         psr |= BIT_F1;
1425                 }
1426                 break;
1427         case 0x62:
1428                 // serial input
1429                 rsp6303_buf->write(RCD00);
1430                 rsp6303_buf->write(tf20_buf->read());
1431                 psr |= BIT_F1;
1432                 break;
1433         case 0x63:
1434                 // serial output
1435                 if(cmd6303_buf->count() == 1) {
1436                         d_tf20->write_signal(SIGNAL_TF20_SIO, cmd6303_buf->read(), 0xff);
1437                         rsp6303_buf->write(RCD00);
1438                         psr |= BIT_F1;
1439                 }
1440                 break;
1441         case 0x64:
1442                 // send data with header
1443                 if(cmd6303_buf->count() >= 6) {
1444                         int cnt = cmd6303_buf->read_not_remove(5);
1445                         if(cmd6303_buf->count() == cnt + 7) {
1446                                 int rcv = cmd6303_buf->read();
1447                                 int fmt = cmd6303_buf->read();
1448                                 int did = cmd6303_buf->read();
1449                                 int sid = cmd6303_buf->read();
1450                                 int fnc = cmd6303_buf->read();
1451                                 int siz = cmd6303_buf->read();
1452                                 
1453                                 // epsp protocol
1454                                 tf20_buf->clear();
1455                                 d_tf20->write_signal(SIGNAL_TF20_SIO, DID_FIRST, 0xff);
1456                                 d_tf20->write_signal(SIGNAL_TF20_SIO, did, 0xff);
1457                                 d_tf20->write_signal(SIGNAL_TF20_SIO, sid, 0xff);
1458                                 d_tf20->write_signal(SIGNAL_TF20_SIO, DS_SEL, 0xff);
1459                                 tf20_buf->read();       // recv ack
1460                                 d_tf20->write_signal(SIGNAL_TF20_SIO, SOH, 0xff);
1461                                 d_tf20->write_signal(SIGNAL_TF20_SIO, fmt, 0xff);
1462                                 d_tf20->write_signal(SIGNAL_TF20_SIO, did, 0xff);
1463                                 d_tf20->write_signal(SIGNAL_TF20_SIO, sid, 0xff);
1464                                 d_tf20->write_signal(SIGNAL_TF20_SIO, fnc, 0xff);
1465                                 d_tf20->write_signal(SIGNAL_TF20_SIO, siz, 0xff);
1466                                 d_tf20->write_signal(SIGNAL_TF20_SIO, 0, 0xff);
1467                                 tf20_buf->read();       // recv ack
1468                                 d_tf20->write_signal(SIGNAL_TF20_SIO, STX, 0xff);
1469                                 for(int i = 0; i < siz + 1; i++) {
1470                                         d_tf20->write_signal(SIGNAL_TF20_SIO, cmd6303_buf->read(), 0xff);
1471                                 }
1472                                 d_tf20->write_signal(SIGNAL_TF20_SIO, 0, 0xff);
1473                                 d_tf20->write_signal(SIGNAL_TF20_SIO, 0, 0xff);
1474                                 tf20_buf->read();       // recv ack
1475                                 d_tf20->write_signal(SIGNAL_TF20_SIO, EOT, 0xff);
1476                                 
1477                                 rsp6303_buf->write(RCD00);
1478                                 if(rcv) {
1479                                         rsp6303_buf->write(0);
1480                                         tf20_buf->read();
1481                                         rsp6303_buf->write(fmt = tf20_buf->read());
1482                                         rsp6303_buf->write(did = tf20_buf->read());
1483                                         rsp6303_buf->write(sid = tf20_buf->read());
1484                                         rsp6303_buf->write(fnc = tf20_buf->read());
1485                                         rsp6303_buf->write(siz = tf20_buf->read());
1486                                         tf20_buf->read();
1487                                         d_tf20->write_signal(SIGNAL_TF20_SIO, ACK, 0xff);       // ack
1488                                         tf20_buf->read();
1489                                         for(int i = 0; i < siz + 1; i++) {
1490                                                 rsp6303_buf->write(tf20_buf->read());
1491                                         }
1492                                         d_tf20->write_signal(SIGNAL_TF20_SIO, ACK, 0xff);       // ack
1493                                         d_tf20->write_signal(SIGNAL_TF20_SIO, EOT, 0xff);       // eot
1494                                         tf20_buf->clear();
1495                                 }
1496                                 psr |= BIT_F1;
1497                         }
1498                 }
1499                 break;
1500         case 0x65:
1501                 // receive data with header
1502                 rsp6303_buf->write(RCD00);
1503                 {
1504                         // epsp protocol
1505                         int fmt, did, sid, fnc, siz;
1506                         rsp6303_buf->write(0);
1507                         tf20_buf->read();
1508                         rsp6303_buf->write(fmt = tf20_buf->read());
1509                         rsp6303_buf->write(did = tf20_buf->read());
1510                         rsp6303_buf->write(sid = tf20_buf->read());
1511                         rsp6303_buf->write(fnc = tf20_buf->read());
1512                         rsp6303_buf->write(siz = tf20_buf->read());
1513                         tf20_buf->read();
1514                         d_tf20->write_signal(SIGNAL_TF20_SIO, ACK, 0xff);       // ack
1515                         tf20_buf->read();
1516                         for(int i = 0; i < siz + 1; i++) {
1517                                 rsp6303_buf->write(tf20_buf->read());
1518                         }
1519                         d_tf20->write_signal(SIGNAL_TF20_SIO, ACK, 0xff);       // ack
1520                         d_tf20->write_signal(SIGNAL_TF20_SIO, EOT, 0xff);       // eot
1521                         tf20_buf->clear();
1522                 }
1523                 psr |= BIT_F1;
1524                 break;
1525         case 0x70:
1526                 // turn on/off prom cupsule power
1527                 if(cmd6303_buf->count() == 1) {
1528                         cmd6303_buf->read();
1529                         rsp6303_buf->write(RCD00);
1530                         psr |= BIT_F1;
1531                 }
1532                 break;
1533         case 0x71:
1534                 // read data
1535                 if(cmd6303_buf->count() == 4) {
1536                         cmd6303_buf->read();
1537                         uint16_t addr = cmd6303_buf->read() << 8;
1538                         addr |= cmd6303_buf->read();
1539                         addr ^= 0x4000;
1540                         int cnt = cmd6303_buf->read();
1541                         if(cnt == 0) cnt = 256;
1542                         rsp6303_buf->write(RCD00);
1543                         for(int i = 0; i < cnt; i++) {
1544                                 if(addr & 0x8000) {
1545                                         rsp6303_buf->write(util[(addr + i) & 0x7fff]);
1546                                 } else {
1547                                         rsp6303_buf->write(basic[(addr + i) & 0x7fff]);
1548                                 }
1549                         }
1550                         psr |= BIT_F1;
1551                 }
1552                 break;
1553         case 0x72:
1554                 // turn on/off speaker power
1555                 if(cmd6303_buf->count() == 1) {
1556                         cmd6303_buf->read();
1557                         rsp6303_buf->write(RCD00);
1558                         psr |= BIT_F1;
1559                 }
1560                 break;
1561         case 0x73:
1562                 // turn on/off speaker power
1563                 if(cmd6303_buf->count() == 3) {
1564                         cmd6303_buf->read();
1565                         cmd6303_buf->read();
1566                         cmd6303_buf->read();
1567                         rsp6303_buf->write(RCD00);
1568                         psr |= BIT_F1;
1569                 }
1570                 break;
1571         case 0x74:
1572                 // melody
1573                 if(cmd6303_buf->count() == 3) {
1574                         cmd6303_buf->read();
1575                         cmd6303_buf->read();
1576                         cmd6303_buf->read();
1577                         rsp6303_buf->write(RCD00);
1578                         psr |= BIT_F1;
1579                 }
1580                 break;
1581         }
1582 }
1583
1584 uint8_t HC80_IO::get_point(int x, int y)
1585 {
1586         if(0 <= x && x < 480 && 0 <= y && y < 64) {
1587                 uint8_t bit = dot_tbl[x & 7];
1588                 int ofs = y * 60 + (x >> 3);
1589                 return ram[gs_addr + ofs] & bit;
1590         }
1591         return 0;
1592 }
1593
1594 void HC80_IO::draw_point(int x, int y, uint16_t dot)
1595 {
1596         if(0 <= x && x < 480 && 0 <= y && y < 64) {
1597                 uint8_t bit = dot_tbl[x & 7];
1598                 int ofs = y * 60 + (x >> 3);
1599                 if(dot) {
1600                         ram[gs_addr + ofs] |= bit;
1601                 } else {
1602                         ram[gs_addr + ofs] &= ~bit;
1603                 }
1604         }
1605 }
1606
1607 void HC80_IO::draw_line(int sx, int sy, int ex, int ey, uint16_t ope)
1608 {
1609         int next_x = sx, next_y = sy;
1610         int delta_x = abs(ex - sx) * 2;
1611         int delta_y = abs(ey - sy) * 2;
1612         int step_x = (ex < sx) ? -1 : 1;
1613         int step_y = (ey < sy) ? -1 : 1;
1614         
1615         draw_point(sx, sy, ope & 0x8000);
1616         ope = (ope << 1) | (ope & 0x8000 ? 1 : 0);
1617         if(delta_x > delta_y) {
1618                 int frac = delta_y - delta_x / 2;
1619                 while(next_x != ex) {
1620                         if(frac >= 0) {
1621                                 next_y += step_y;
1622                                 frac -= delta_x;
1623                         }
1624                         next_x += step_x;
1625                         frac += delta_y;
1626                         draw_point(next_x, next_y, ope & 0x8000);
1627                         ope = (ope << 1) | (ope & 0x8000 ? 1 : 0);
1628                 }
1629         } else {
1630                 int frac = delta_x - delta_y / 2;
1631                 while(next_y != ey) {
1632                         if(frac >= 0) {
1633                                 next_x += step_x;
1634                                 frac -= delta_y;
1635                         }
1636                         next_y += step_y;
1637                         frac += delta_x;
1638                         draw_point(next_x, next_y, ope & 0x8000);
1639                         ope = (ope << 1) | (ope & 0x8000 ? 1 : 0);
1640                 }
1641         }
1642         draw_point(ex, ey, ope & 0x8000);
1643 }
1644
1645 // ----------------------------------------------------------------------------
1646 // intelligent ram disk by Mr.Dennis Heynlein
1647 // ----------------------------------------------------------------------------
1648
1649 /*
1650 0x81 (W)        CommandByte c to RAMDisk
1651 0x81 (R)        Statusbyte      
1652                 Bit 0 : Readable DataByte on 0x81 is pending
1653                 Bit 1 : Receive of Data/Command is busy
1654                 Bit 7 and 6 = 0 (ident the RAMdisc)
1655
1656 0x80 (R/W)      DataByte d
1657
1658 Commands:       RESET           -       input:  c(00)
1659                                         output: d(SWITCHSTATE)          
1660
1661                 READSECTOR      -       input:  c(01) d(TRACK) d(SECTOR)
1662                                         output: d(ERRORSTATE) d(SECTORBYTE)*128
1663                 
1664                 READMEMDIRECT   -       input:  c(02) d(BANK) d(HIGHBYTE) d(LOWBYTE)
1665                                         output: d(ERRORSTATE) d(BYTE)
1666
1667                 WRITESECTOR     -       input:  c(03) d(TRACK) d(SECTOR) d(SECTORBYTE)*128
1668                                         output: d(ERRORSTATE)
1669
1670                 WRITEMEMDIRECT  -       input:  c(04) d(HIGHBYTE) d(LOWBYTE) d(BYTE)
1671                                         output: d(ERRORSTATE)
1672
1673                 INIT_BITMAP     -       input:  c(05)
1674                                         output: d(ERRORSTATE)
1675
1676 ERRORSTATE:     Bit 0 = Ramdiscsize
1677                 Bit 1 = Geometric
1678                 Bit 2 = Writeprotect
1679
1680 HIGHBYTE:       0 - 0xef
1681 LOWBYTE:        0-255
1682 TRACK:          0-14
1683 SECTOR:         0-63
1684 BANK:           1 or 2
1685 */
1686
1687 void HC80_IO::iramdisk_write_data(uint8_t val)
1688 {
1689         if(iramdisk_dest == IRAMDISK_IN && iramdisk_count) {
1690                 *(iramdisk_ptr++) = val;
1691                 iramdisk_count--;
1692         }
1693         if(!iramdisk_count) {
1694                 iramdisk_dest = IRAMDISK_OUT;
1695                 iramdisk_ptr = iramdisk_buf;
1696                 int track = iramdisk_buf[0];
1697                 int sector = iramdisk_buf[1];
1698                 
1699                 switch(iramdisk_cmd) {
1700                 case 1: //READSECTOR
1701                         if(track > 14 || sector > 63) {
1702                                 iramdisk_buf[0] = 2;
1703                         } else {
1704                                 iramdisk_buf[0] = 0;
1705                                 for(int t = 0;t < 128; t++) {
1706                                         iramdisk_buf[t + 1] = iramdisk_sectors[track][sector][t];
1707                                 }
1708                         }
1709                         iramdisk_count = 129; //ERRORCODE + 128 Bytes
1710                         break;
1711                 case 3: //WRITESECTOR
1712                         if(track > 14 || sector > 63) {
1713                                 iramdisk_buf[0] = 2;
1714                         } else {
1715                                 iramdisk_buf[0] = 0;
1716                                 for(int t = 0; t < 128; t++) {
1717                                         iramdisk_sectors[track][sector][t] = iramdisk_buf[t+2];
1718                                 }
1719                         }
1720                         iramdisk_count = 1; //ERRORCODE
1721                         break;
1722                 case 2: //READMEMDIRECT
1723                         iramdisk_count = 2; //ERRORCODE + 1 Byte
1724                         break;
1725                 case 4: //WRITEMEMDIRECT
1726                         iramdisk_count = 1; //ERRORCODE
1727                         break;
1728                 }
1729         }
1730 }
1731
1732 void HC80_IO::iramdisk_write_cmd(uint8_t val)
1733 {
1734         iramdisk_cmd = val;
1735         iramdisk_count = 0;
1736         iramdisk_ptr = iramdisk_buf;
1737         iramdisk_dest = IRAMDISK_IN;
1738         
1739         switch(iramdisk_cmd) {
1740         case 1:
1741                 iramdisk_count = 2;
1742                 break;
1743         case 2:
1744         case 4:
1745                 iramdisk_count = 3;
1746                 break;
1747         case 3:
1748                 iramdisk_count = 130;
1749                 break;
1750         default:
1751                 //PROCESS-1-BYTE_CMDs
1752                 iramdisk_count = 1;
1753                 iramdisk_dest = IRAMDISK_OUT;
1754                 if(iramdisk_cmd == 0) {
1755                         iramdisk_buf[0] = 1;    // RESET
1756                 } else {
1757                         iramdisk_buf[0] = 0;    //INIT
1758                 }
1759         }
1760 }
1761
1762 uint8_t HC80_IO::iramdisk_read_data()
1763 {
1764         if(iramdisk_dest == IRAMDISK_OUT) {
1765                 if(iramdisk_count) {
1766                         iramdisk_count--;
1767                         if(!iramdisk_count) {
1768                                 iramdisk_dest = IRAMDISK_IN;
1769                         }
1770                         return *(iramdisk_ptr++);
1771                 }
1772         }
1773         return 0;
1774 }
1775
1776 uint8_t HC80_IO::iramdisk_read_stat()
1777 {
1778         if(iramdisk_dest == IRAMDISK_OUT) {
1779                 return IRAMDISK_WAIT;
1780         } else {
1781                 return 0;
1782         }
1783 }
1784
1785 // ----------------------------------------------------------------------------
1786 // video
1787 // ----------------------------------------------------------------------------
1788
1789
1790 void HC80_IO::draw_screen()
1791 {
1792         if(lcd_on) {
1793                 memset(lcd, 0, sizeof(lcd));
1794                 if(scr_mode) {
1795                         // char screen
1796                         uint8_t* vram = &ram[scr_ptr];
1797                         for(int y = 0; y < (num_lines ? 7 : 8); y++) {
1798                                 int py = num_lines ? (y * 9 + 1) : y * 8;
1799                                 for(int x = 0; x < 80; x++) {
1800                                         int px = x * 6;
1801                                         int ofs = vram[y * 80 + x] << 3;
1802                                         for(int l = 0; l < 8; l++) {
1803                                                 uint8_t pat = font[ofs + l];
1804                                                 lcd[py + l][px + 0] = (pat & 0x20) ? 0xff : 0;
1805                                                 lcd[py + l][px + 1] = (pat & 0x10) ? 0xff : 0;
1806                                                 lcd[py + l][px + 2] = (pat & 0x08) ? 0xff : 0;
1807                                                 lcd[py + l][px + 3] = (pat & 0x04) ? 0xff : 0;
1808                                                 lcd[py + l][px + 4] = (pat & 0x02) ? 0xff : 0;
1809                                                 lcd[py + l][px + 5] = (pat & 0x01) ? 0xff : 0;
1810                                         }
1811                                 }
1812                         }
1813                         // block flashing
1814                         if(flash_block) {
1815                                 int yofs = (scr_ptr - cs_addr) / 80;
1816                                 for(int i = 0; i < cs_blocks; i++) {
1817                                         int x = cs_block[i][0];
1818                                         int y = cs_block[i][1] - yofs;
1819                                         if(0 <= x && x < 80 && 0 <= y && y < 8) {
1820                                                 int px = x * 6;
1821                                                 int py = y * 8;
1822                                                 for(int l = 0; l < 8; l++) {
1823                                                         lcd[py + l][px + 0] = ~lcd[py + l][px + 0];
1824                                                         lcd[py + l][px + 1] = ~lcd[py + l][px + 1];
1825                                                         lcd[py + l][px + 2] = ~lcd[py + l][px + 2];
1826                                                         lcd[py + l][px + 3] = ~lcd[py + l][px + 3];
1827                                                         lcd[py + l][px + 4] = ~lcd[py + l][px + 4];
1828                                                         lcd[py + l][px + 5] = ~lcd[py + l][px + 5];
1829                                                 }
1830                                         }
1831                                 }
1832                         }
1833                         // draw cursor
1834                         if(curs_mode & 1) {
1835                                 if(!(curs_mode & 2) || (blink & 32)) {
1836                                         int px = curs_x * 6;
1837                                         int py = curs_y * 8;
1838                                         int st = (curs_mode & 4) ? 0 : 7;
1839                                         if(px + 6 - 1 < SCREEN_WIDTH) {
1840                                                 for(int l = st; l < 8 && py + l < SCREEN_HEIGHT; l++) {
1841                                                         memset(&lcd[py + l][px], 0xff, 6);
1842                                                 }
1843                                         }
1844                                 }
1845                         }
1846                 } else {
1847                         // graph screen
1848                         uint8_t* vram = &ram[gs_addr];
1849                         for(int y = 0; y < 64; y++) {
1850                                 for(int x = 0; x < 60; x++) {
1851                                         int px = x * 8;
1852                                         uint8_t pat = *vram++;
1853                                         lcd[y][px + 0] = (pat & 0x80) ? 0xff : 0;
1854                                         lcd[y][px + 1] = (pat & 0x40) ? 0xff : 0;
1855                                         lcd[y][px + 2] = (pat & 0x20) ? 0xff : 0;
1856                                         lcd[y][px + 3] = (pat & 0x10) ? 0xff : 0;
1857                                         lcd[y][px + 4] = (pat & 0x08) ? 0xff : 0;
1858                                         lcd[y][px + 5] = (pat & 0x04) ? 0xff : 0;
1859                                         lcd[y][px + 6] = (pat & 0x02) ? 0xff : 0;
1860                                         lcd[y][px + 7] = (pat & 0x01) ? 0xff : 0;
1861                                 }
1862                         }
1863                         // block flashing
1864                         if(flash_block) {
1865                                 for(int i = 0; i < gs_blocks; i++) {
1866                                         int x = gs_block[i][0];
1867                                         int y = gs_block[i][1];
1868                                         if(0 <= x && x < 60 && 0 <= y && y < 8) {
1869                                                 int px = x * 8;
1870                                                 int py = y * 8;
1871                                                 for(int l = 0; l < 8; l++) {
1872                                                         lcd[py + l][px + 0] = ~lcd[py + l][px + 0];
1873                                                         lcd[py + l][px + 1] = ~lcd[py + l][px + 1];
1874                                                         lcd[py + l][px + 2] = ~lcd[py + l][px + 2];
1875                                                         lcd[py + l][px + 3] = ~lcd[py + l][px + 3];
1876                                                         lcd[py + l][px + 4] = ~lcd[py + l][px + 4];
1877                                                         lcd[py + l][px + 5] = ~lcd[py + l][px + 5];
1878                                                         lcd[py + l][px + 6] = ~lcd[py + l][px + 6];
1879                                                         lcd[py + l][px + 7] = ~lcd[py + l][px + 7];
1880                                                 }
1881                                         }
1882                                 }
1883                         }
1884                 }
1885                 for(int y = 0; y < 64; y++) {
1886                         scrntype_t* dest = emu->get_screen_buffer(y);
1887                         for(int x = 0; x < 480; x++) {
1888                                 dest[x] = lcd[y][x] ? pd : pb;
1889                         }
1890                 }
1891         } else {
1892                 for(int y = 0; y < 64; y++) {
1893                         scrntype_t* dest = emu->get_screen_buffer(y);
1894                         for(int x = 0; x < 480; x++) {
1895                                 dest[x] = pb;
1896                         }
1897                 }
1898         }
1899 }
1900
1901 #define STATE_VERSION   1
1902
1903 bool HC80_IO::process_state(FILEIO* state_fio, bool loading)
1904 {
1905         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
1906                 return false;
1907         }
1908         if(!state_fio->StateCheckInt32(this_device_id)) {
1909                 return false;
1910         }
1911         state_fio->StateUint32(cur_clock);
1912         state_fio->StateUint8(bcr);
1913         state_fio->StateUint8(slbcr);
1914         state_fio->StateUint8(isr);
1915         state_fio->StateUint8(ier);
1916         state_fio->StateUint8(ioctlr);
1917         state_fio->StateUint32(icrc);
1918         state_fio->StateUint32(icrb);
1919         state_fio->StateBool(ear);
1920         state_fio->StateUint8(vadr);
1921         state_fio->StateUint8(yoff);
1922         if(!cmd7508_buf->process_state((void *)state_fio, loading)) {
1923                 return false;
1924         }
1925         if(!rsp7508_buf->process_state((void *)state_fio, loading)) {
1926                 return false;
1927         }
1928         if(!cur_time.process_state((void *)state_fio, loading)) {
1929                 return false;
1930         }
1931         state_fio->StateInt32(register_id);
1932         state_fio->StateBool(onesec_intr);
1933         state_fio->StateBool(onesec_intr_enb);
1934         state_fio->StateBool(alarm_intr);
1935         state_fio->StateBool(alarm_intr_enb);
1936         state_fio->StateBuffer(alarm, sizeof(alarm), 1);
1937         if(!key_buf->process_state((void *)state_fio, loading)) {
1938                 return false;
1939         }
1940         state_fio->StateBool(kb_intr_enb);
1941         state_fio->StateBool(kb_rep_enb);
1942         state_fio->StateBool(kb_caps);
1943         state_fio->StateUint8(kb_rep_spd1);
1944         state_fio->StateUint8(kb_rep_spd2);
1945         state_fio->StateBool(beep);
1946         state_fio->StateBool(res_z80);
1947         state_fio->StateBool(res_7508);
1948         state_fio->StateUint8(cmd6303);
1949         state_fio->StateUint8(psr);
1950         if(!cmd6303_buf->process_state((void *)state_fio, loading)) {
1951                 return false;
1952         }
1953         if(!rsp6303_buf->process_state((void *)state_fio, loading)) {
1954                 return false;
1955         }
1956         state_fio->StateBuffer(ram, sizeof(ram), 1);
1957         state_fio->StateUint16(cs_addr);
1958         state_fio->StateUint16(gs_addr);
1959         state_fio->StateUint8(lcd_on);
1960         state_fio->StateUint8(scr_mode);
1961         state_fio->StateUint16(scr_ptr);
1962         state_fio->StateUint8(num_lines);
1963         state_fio->StateUint8(curs_mode);
1964         state_fio->StateUint8(curs_x);
1965         state_fio->StateUint8(curs_y);
1966         state_fio->StateUint8(wnd_ptr_x);
1967         state_fio->StateUint8(wnd_ptr_y);
1968         state_fio->StateUint8(flash_block);
1969         state_fio->StateUint8(cs_blocks);
1970         state_fio->StateBuffer(cs_block, sizeof(cs_block), 1);
1971         state_fio->StateUint8(gs_blocks);
1972         state_fio->StateBuffer(gs_block, sizeof(gs_block), 1);
1973         state_fio->StateBuffer(font, sizeof(font), 1);
1974         state_fio->StateBuffer(udgc, sizeof(udgc), 1);
1975         state_fio->StateBuffer(mov, sizeof(mov), 1);
1976         state_fio->StateBuffer(lcd, sizeof(lcd), 1);
1977         state_fio->StateInt32(blink);
1978         if(!tf20_buf->process_state((void *)state_fio, loading)) {
1979                 return false;
1980         }
1981         state_fio->StateInt32(device_type);
1982         state_fio->StateBuffer(ext, sizeof(ext), 1);
1983         state_fio->StateUint32(extar);
1984         state_fio->StateUint8(extcr);
1985         state_fio->StateBuffer(iramdisk_sectors, sizeof(iramdisk_sectors), 1);
1986         state_fio->StateUint8(iramdisk_cmd);
1987         state_fio->StateInt32(iramdisk_count);
1988         state_fio->StateInt32(iramdisk_dest);
1989         state_fio->StateBuffer(iramdisk_buf, sizeof(iramdisk_buf), 1);
1990         if(loading) {
1991                 iramdisk_ptr = iramdisk_buf + state_fio->FgetInt32_LE();
1992         } else {
1993                 state_fio->FputInt32_LE((int)(iramdisk_ptr - iramdisk_buf));
1994         }
1995         return true;
1996 }