OSDN Git Service

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