OSDN Git Service

6089bf6c5c1d9eaaac65eb6c93513baaf80bd3d4
[csp-qt/common_source_project-fm7.git] / source / src / vm / hc20 / memory.cpp
1 /*
2         EPSON HC-20 Emulator 'eHC-20'
3
4         Author : Takeda.Toshiya
5         Date   : 2011.05.23-
6
7         [ memory ]
8 */
9
10 #include "memory.h"
11 #include "../beep.h"
12 #include "../hd6301.h"
13 #include "../z80sio.h"
14 #include "../../fifo.h"
15
16 #define SET_BANK(s, e, w, r) { \
17         int sb = (s) >> 13, eb = (e) >> 13; \
18         for(int i = sb; i <= eb; i++) { \
19                 if((w) == wdmy) { \
20                         wbank[i] = wdmy; \
21                 } else { \
22                         wbank[i] = (w) + 0x2000 * (i - sb); \
23                 } \
24                 if((r) == rdmy) { \
25                         rbank[i] = rdmy; \
26                 } else { \
27                         rbank[i] = (r) + 0x2000 * (i - sb); \
28                 } \
29         } \
30 }
31
32 #define INT_KEYBOARD    1
33 #define INT_CLOCK       2
34 #define INT_POWER       4
35
36 #define EVENT_SOUND     0
37
38 static int key_table[8][10] = {
39         // PAUSE=F6, MENU=F7, BREAK=F8 NUM=F9 CLR=F10 SCRN=F11 PRINT=PgUp PAPER=PgDn
40         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x70, 0x00,
41         0x38, 0x39, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0x71, 0x00,
42         0xc0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x72, 0x00,
43         0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x73, 0x00,
44         0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x74, 0x00,
45         0x58, 0x59, 0x5a, 0xdb, 0xdd, 0xdc, 0x27, 0x25, 0x22, 0x10,
46         0x0d, 0x20, 0x09, 0x00, 0x00, 0x78, 0x00, 0x34, 0x00, 0x11,
47         0x79, 0x7a, 0x77, 0x75, 0x2e, 0x76, 0x00, 0x00, 0x00, 0x21
48 };
49
50 void MEMORY::initialize()
51 {
52         // initialize memory
53         memset(ram, 0, sizeof(ram));
54         memset(rom, 0, sizeof(rom));
55         memset(ext, 0, sizeof(ext));
56         memset(rdmy, 0xff, sizeof(rdmy));
57         
58         // load backuped ram / rom images
59         FILEIO* fio = new FILEIO();
60         if(fio->Fopen(create_local_path(_T("DRAM.BIN")), FILEIO_READ_BINARY)) {
61                 fio->Fread(ram, sizeof(ram), 1);
62                 fio->Fclose();
63         } else if(fio->Fopen(create_local_path(_T("BACKUP.BIN")), FILEIO_READ_BINARY)) {
64                 // for compatibility
65                 fio->Fread(ram, sizeof(ram), 1);
66                 fio->Fclose();
67         }
68         if(fio->Fopen(create_local_path(_T("BASIC.ROM")), FILEIO_READ_BINARY)) {
69                 fio->Fread(rom, sizeof(rom), 1);
70                 fio->Fclose();
71         }
72         if(fio->Fopen(create_local_path(_T("EXT.ROM")), FILEIO_READ_BINARY)) {
73                 fio->Fread(ext, sizeof(ext), 1);
74                 fio->Fclose();
75         }
76         delete fio;
77         
78 //      SET_BANK(0x0000, 0x3fff, ram, ram);
79 //      SET_BANK(0x4000, 0x7fff, wdmy, rdmy);
80         SET_BANK(0x0000, 0x7fff, ram, ram);
81         SET_BANK(0x8000, 0xffff, wdmy, rom);
82         
83         // init command buffer
84         cmd_buf = new FIFO(512);
85         memset(slave_mem, 0, sizeof(slave_mem));
86         
87         // init sound
88         double tone_tmp[13];
89         tone_tmp[9] = 110.0;
90         for(int i = 8; i >= 0; i--) {
91                 tone_tmp[i] = tone_tmp[i + 1] / 1.05946;
92         }
93         for(int i = 10; i < 13; i++) {
94                 tone_tmp[i] = tone_tmp[i - 1] * 1.05946;
95         }
96         static const int tone_index[7] = {0, 2, 4, 5, 7, 9, 11};
97         for(int i = 0; i < 4; i++) {
98                 for(int j = 0; j < 7; j++) {
99                         tone_table[i * 7 + j +  1] = tone_tmp[tone_index[j]    ] * (2 << i);
100                         tone_table[i * 7 + j + 29] = tone_tmp[tone_index[j] + 1] * (2 << i);
101                 }
102         }
103         tone_table[0] = 0;
104         
105         // init keyboard
106         memset(key_stat, 0, sizeof(key_stat));
107         memset(key_flag, 0, sizeof(key_flag));
108         
109         for(int i = 0; i < 8; i++) {
110                 for(int j = 0; j < 10; j++) {
111                         key_flag[key_table[i][j]] = 1;
112                 }
113         }
114         key_flag[0] = key_flag[0x10] = key_flag[0x11] = key_flag[0x12] = 0;
115         
116         // init cmt
117         cmt_count = 0;
118         cmt_play = cmt_rec = false;
119         cmt_fio = new FILEIO();
120         
121         // init lcd
122         pd = RGB_COLOR(48, 56, 16);
123         pb = RGB_COLOR(160, 168, 160);
124         memset(lcd, 0, sizeof(lcd));
125         
126         // register event
127         register_event_by_clock(this, EVENT_SOUND, 256, true, NULL);
128 }
129
130 void MEMORY::release()
131 {
132         // save battery backuped ram
133         FILEIO* fio = new FILEIO();
134         if(fio->Fopen(create_local_path(_T("DRAM.BIN")), FILEIO_WRITE_BINARY)) {
135                 fio->Fwrite(ram, sizeof(ram), 1);
136                 fio->Fclose();
137         }
138         delete fio;
139         
140         // release cmt
141         close_tape();
142         delete cmt_fio;
143         
144         // release command buffer
145         cmd_buf->release();
146         delete cmd_buf;
147 }
148
149 void MEMORY::reset()
150 {
151         // select internal rom
152 //      SET_BANK(0x4000, 0x7fff, wdmy, rdmy);
153         SET_BANK(0x8000, 0xbfff, wdmy, rom);
154         
155         cmd_buf->clear();
156         sio_select = true;
157         special_cmd_masked = true;
158         
159         sound_ptr = sound_count = 0;
160         sound_freq = 0;
161         
162         key_strobe = 0xff;
163         key_data = 0x3ff;
164         key_intmask = 0;
165         
166         close_tape();
167         
168         lcd_select = 0;
169         lcd_clock = 0;
170         
171         int_status = 0;
172         int_mask = 0;
173 }
174
175 void MEMORY::write_data8(uint32_t addr, uint32_t data)
176 {
177         addr &= 0xffff;
178         if(addr < 0x40) {
179                 switch(addr) {
180                 case 0x20:
181                         if(key_strobe != data) {
182                                 key_strobe = data;
183                                 update_keyboard();
184                         }
185                         break;
186                 case 0x26:
187                         lcd_select = data & 0x0f;
188                         key_intmask = data & 0x10;
189                         // interrupt mask reset in sleep mode
190                         if(int_mask) {
191                                 int_mask = 0;
192 //                              update_intr();
193                         }
194                         break;
195                 case 0x2a:
196                         lcd_data = data;
197                         lcd_clock = 8;
198                         break;
199                 case 0x2c:
200                         // used for interrupt mask setting in sleep mode
201                         if(!int_mask) {
202                                 int_mask = 1;
203 //                              update_intr();
204                         }
205                         break;
206                 case 0x30:
207 //                      SET_BANK(0x4000, 0x7fff, ram + 0x4000, ram + 0x4000);
208                         SET_BANK(0x8000, 0xbfff, wdmy, ext);
209                         break;
210                 case 0x32:
211                 case 0x33:
212 //                      SET_BANK(0x4000, 0x7fff, wdmy, rdmy);
213                         SET_BANK(0x8000, 0xbfff, wdmy, rom);
214                         break;
215                 }
216                 ram[addr] = data;
217         } else if(addr < 0x80) {
218                 d_rtc->write_io8(1, addr & 0x3f);
219                 d_rtc->write_io8(0, data);
220         } else {
221                 wbank[(addr >> 13) & 7][addr & 0x1fff] = data;
222         }
223 }
224
225 uint32_t MEMORY::read_data8(uint32_t addr)
226 {
227         addr &= 0xffff;
228         if(addr < 0x40) {
229                 switch(addr) {
230                 case 0x20:
231                         return key_strobe;
232                 case 0x22:
233                         return key_data & 0xff;
234                 case 0x26:
235                         // interrupt mask reset in sleep mode
236                         if(int_mask) {
237                                 int_mask = 0;
238 //                              update_intr();
239                         }
240                         break;
241                 case 0x28:
242                         // bit6: power switch interrupt flag (0=active)
243                         // bit7: busy signal of lcd controller (0=busy)
244                         return ((key_data >> 8) & 3) | ((int_status & INT_POWER) ? 0 : 0x40) | 0xa8;
245                 case 0x2a:
246                 case 0x2b:
247                         if(lcd_clock > 0 && --lcd_clock <= 0) {
248                                 int c = lcd_select & 7;
249                                 if(c >= 1 && c <= 6) {
250                                         lcd_t *block = &lcd[c - 1];
251                                         if(lcd_select & 8) {
252                                                 block->bank = lcd_data & 0x40 ? 40 : 0;
253                                                 block->addr = lcd_data & 0x3f;
254                                         } else if(block->addr < 40) {
255                                                 block->buffer[block->bank + block->addr] = lcd_data;
256                                                 block->addr++;
257                                         }
258                                 }
259                         }
260                         break;
261                 case 0x2c:
262                         // used for interrupt mask setting in sleep mode
263                         if(!int_mask) {
264                                 int_mask = 1;
265 //                              update_intr();
266                         }
267                         break;
268                 case 0x30:
269 //                      SET_BANK(0x4000, 0x7fff, ram + 0x4000, ram + 0x4000);
270                         SET_BANK(0x8000, 0xbfff, ext, rom);
271                         break;
272                 case 0x32:
273                 case 0x33:
274 //                      SET_BANK(0x4000, 0x7fff, wdmy, rdmy);
275                         SET_BANK(0x8000, 0xbfff, wdmy, rom);
276                         break;
277                 }
278 //              return ram[addr];
279                 return addr;
280         } else if(addr < 0x80) {
281                 d_rtc->write_io8(1, addr & 0x3f);
282                 return d_rtc->read_io8(0);
283         }
284         return rbank[(addr >> 13) & 7][addr & 0x1fff];
285 }
286
287 void MEMORY::write_signal(int id, uint32_t data, uint32_t mask)
288 {
289         if(id == SIG_MEMORY_PORT_2) {
290                 sio_select = ((data & 0x04) != 0);
291         } else if(id == SIG_MEMORY_SIO_MAIN) {
292                 if(!sio_select) {
293                         d_sio_tf20->write_signal(SIG_Z80SIO_RECV_CH0, data, 0xff);
294                 } else {
295                         send_to_slave(data & mask);
296                 }
297         } else if(id == SIG_MEMORY_SIO_TF20) {
298                 if(!sio_select) {
299                         send_to_main(data & mask);
300                 }
301         } else if(id == SIG_MEMORY_RTC_IRQ) {
302                 if(data & mask) {
303                         if(!(int_status & INT_CLOCK)) {
304                                 int_status |= INT_CLOCK;
305                                 update_intr();
306                         }
307                 } else {
308                         if((int_status & INT_CLOCK) && (int_status &= ~INT_CLOCK) == 0) {
309                                 update_intr();
310                         }
311                 }
312         }
313 }
314
315 void MEMORY::event_callback(int event_id, int err)
316 {
317         if(event_id == EVENT_SOUND) {
318                 update_sound();
319         }
320 }
321
322 void MEMORY::update_sound()
323 {
324         if(sound_ptr < sound_count) {
325                 if(sound[sound_ptr].remain-- == 0) {
326                         if(++sound_ptr == sound_count) {
327                                 d_beep->write_signal(SIG_BEEP_ON, 0, 0);
328                                 send_to_main(sound_reply);
329                                 return;
330                         }
331                         sound[sound_ptr].remain = sound[sound_ptr].period;
332                 }
333                 if(sound_freq != sound[sound_ptr].freq) {
334                         sound_freq = sound[sound_ptr].freq;
335                         if(sound_freq != 0) {
336                                 d_beep->set_frequency(sound_freq);
337                                 d_beep->write_signal(SIG_BEEP_ON, 1, 1);
338                         } else {
339                                 d_beep->write_signal(SIG_BEEP_ON, 0, 0);
340                         }
341                 }
342         }
343 }
344
345 void MEMORY::update_keyboard()
346 {
347         key_data = 0x3ff;
348         
349         if(key_strobe == 0) {
350                 // clear key interrupt
351                 if((int_status & INT_KEYBOARD) && (int_status &= ~INT_KEYBOARD) == 0) {
352                         update_intr();
353                 }
354                 d_cpu->write_signal(SIG_MC6801_PORT_1, 0x20, 0x20);
355                 
356                 // clear key buffer except shift/ctrl/alt keys
357                 uint8_t key_stat_10 = key_stat[0x10];
358                 uint8_t key_stat_11 = key_stat[0x11];
359                 uint8_t key_stat_12 = key_stat[0x12];
360                 memset(key_stat, 0, sizeof(key_stat));
361                 key_stat[0x10] = key_stat_10;
362                 key_stat[0x11] = key_stat_11;
363                 key_stat[0x12] = key_stat_12;
364         }
365         for(int i = 0; i < 8; i++) {
366                 if(key_strobe & (1 << i)) {
367                         continue;
368                 }
369                 for(int j = 0; j < 10; j++) {
370                         if(key_stat[key_table[i][j]]) {
371                                 key_data &= ~(1 << j);
372                         }
373                 }
374                 // dip-switch
375                 if(i < 4 && (config.dipswitch & (1 << i))) {
376                         key_data &= ~0x200;
377                 }
378         }
379 }
380
381 void MEMORY::notify_power_off()
382 {
383         int_status |= INT_POWER;
384         update_intr();
385 }
386
387 void MEMORY::key_down(int code)
388 {
389         key_stat[code] = 1;
390         
391         if(key_flag[code]) {
392                 // raise key interrupt
393                 if(!(int_status & INT_KEYBOARD)) {
394                         int_status |= INT_KEYBOARD;
395                         update_intr();
396                 }
397                 d_cpu->write_signal(SIG_MC6801_PORT_1, 0, 0x20);
398         }
399 }
400
401 void MEMORY::key_up(int code)
402 {
403         key_stat[code] = 0;
404 }
405
406 void MEMORY::update_intr()
407 {
408 //      d_cpu->write_signal(SIG_CPU_IRQ, (int_status && !int_mask) ? 1 : 0, 1);
409         d_cpu->write_signal(SIG_CPU_IRQ, int_status ? 1 : 0, 1);
410 }
411
412 void MEMORY::send_to_slave(uint8_t val)
413 {
414         cmd_buf->write(val);
415         uint8_t cmd = cmd_buf->read_not_remove(0);
416         
417 //      this->out_debug_log(_T("Command = %2x"), cmd);
418 //      for(int i = 1; i < cmd_buf->count(); i++) {
419 //              this->out_debug_log(_T(" %2x"), cmd_buf->read_not_remove(i));
420 //      }
421 //      this->out_debug_log(_T("\n"));
422         
423         switch(cmd) {
424         case 0x00: // slave mcpu ready check
425         case 0x01: // sets the constants required by slave mcu
426         case 0x02: // initialization
427                 cmd_buf->read();
428                 send_to_main(0x01);
429                 break;
430         case 0x03: // opens masks for special commands
431                 if(cmd_buf->count() == 2) {
432                         cmd_buf->read();
433                         special_cmd_masked = (cmd_buf->read() != 0xaa);
434                 }
435                 send_to_main(0x01);
436                 break;  
437         case 0x04: // closes masks for special commands
438                 special_cmd_masked = true;
439                 cmd_buf->read();
440                 send_to_main(0x01);
441                 break;
442         case 0x05: // reads slave mcu memory
443                 if(special_cmd_masked) {
444                         cmd_buf->read();
445                         send_to_main(0x0f);
446                         break;
447                 }
448                 if(cmd_buf->count() == 3) {
449                         cmd_buf->read();
450                         int ofs = cmd_buf->read() << 8;
451                         ofs |= cmd_buf->read();
452                         send_to_main(slave_mem[ofs]);
453                         break;
454                 }
455                 send_to_main(0x01);
456                 break;
457         case 0x06: // stores slave mcu memory
458         case 0x07: // logical or operation
459         case 0x08: // logical and operation
460                 if(special_cmd_masked) {
461                         cmd_buf->read();
462                         send_to_main(0x0f);
463                         break;
464                 }
465                 if(cmd_buf->count() == 4) {
466                         cmd_buf->read();
467                         int ofs = cmd_buf->read() << 8;
468                         ofs |= cmd_buf->read();
469                         if(cmd == 6) {
470                                 slave_mem[ofs] = cmd_buf->read();
471                         } else if(cmd == 7) {
472                                 slave_mem[ofs] |= cmd_buf->read();
473                         } else if(cmd == 8) {
474                                 slave_mem[ofs] &= cmd_buf->read();
475                         }
476                 }
477                 send_to_main(0x01);
478                 break;
479         case 0x09: // bar-code reader power on
480         case 0x0a: // bar-code reader power off
481                 cmd_buf->read();
482                 send_to_main(0x01);
483                 break;
484         case 0x0b: // sets the program counter to a specified value
485                 if(special_cmd_masked) {
486                         cmd_buf->read();
487                         send_to_main(0x0f);
488                         break;
489                 }
490                 if(cmd_buf->count() == 3) {
491                         cmd_buf->read();
492                         int ofs = cmd_buf->read() << 8;
493                         ofs |= cmd_buf->read();
494                         // todo: implements known routines
495                 }
496                 send_to_main(0x01);
497                 break;
498         case 0x0c: // terminate process
499                 cmd_buf->read();
500                 send_to_main(0x02);
501                 // stop sound
502                 d_beep->write_signal(SIG_BEEP_ON, 0, 0);
503                 sound_ptr = sound_count;
504                 break;
505         case 0x0d: // cuts off power supply
506                 if(cmd_buf->count() == 2) {
507                         cmd_buf->read();
508                         if(cmd_buf->read() == 0xaa) {
509                                 emu->power_off();
510                                 break;
511                         }
512                 }
513                 send_to_main(0x01);
514                 break;
515         case 0x10: // prints out 6-dot data (bit0-5) to the built-in printer
516         case 0x11: // feeds the specified number of dot lines to the built-in printer
517                 if(cmd_buf->count() == 2) {
518                         cmd_buf->clear();
519                 }
520                 send_to_main(0x01);
521                 break;  
522         case 0x12: // paper feed operation (1.2sec)
523                 cmd_buf->read();
524                 send_to_main(0x01);
525                 break;
526         case 0x20: // executes external cassette ready check
527                 send_to_main(0x21);
528                 cmd_buf->read();
529                 break;
530         case 0x21: // sets constants for the external cassette
531                 if(cmd_buf->count() == 1) {
532                         send_to_main(0x01);
533                         break;
534                 }
535                 if(cmd_buf->count() == 9) {
536                         cmd_buf->clear();
537                 }
538                 send_to_main(0x21);
539                 break;
540         case 0x22: // turns the external cassette rem terminal on
541         case 0x23: // turns the external cassette rem terminal off
542                 cmd_buf->read();
543                 send_to_main(0x01);
544                 break;
545         case 0x24: // writes 1 block of data in EPSON format
546                 if(cmd_buf->count() == 1) {
547                         send_to_main(0x01);
548                         break;
549                 }
550                 if(cmd_buf->count() >= 5 && cmd_buf->count() == cmd_buf->read_not_remove(3) * 256 + cmd_buf->read_not_remove(4) + 5) {
551                         if(cmt_rec) {
552                                 for(int i = 0; i < 5; i++) {
553                                         cmd_buf->read();
554                                 }
555                                 while(!cmd_buf->empty()) {
556                                         cmt_buffer[cmt_count++] = cmd_buf->read();
557                                         if(cmt_count >= CMT_BUFFER_SIZE) {
558                                                 cmt_fio->Fwrite(cmt_buffer, cmt_count, 1);
559                                                 cmt_count = 0;
560                                         }
561                                 }
562                         } else {
563                                 cmd_buf->clear();
564                         }
565                 }
566                 send_to_main(0x21);
567                 break;
568         case 0x25: // outputs number of ff patterns
569                 if(cmd_buf->count() == 1) {
570                         send_to_main(0x01);
571                         break;
572                 }
573                 if(cmd_buf->count() == 3) {
574                         cmd_buf->clear();
575                 }
576                 send_to_main(0x21);
577                 break;
578         case 0x26: // inputs files from the external cassette
579         case 0x27: // inputs files from the external cassette
580         case 0x28: // inputs files from the external cassette
581                 if(cmd_buf->count() == 1) {
582                         send_to_main(0x01);
583                         break;
584                 }
585                 if(cmd_buf->count() == 5) {
586                         int len = cmd_buf->read_not_remove(3) * 256 + cmd_buf->read_not_remove(4);
587                         cmd_buf->clear();
588                         send_to_main(0x21);
589                         for(int i = 0; i < len; i++) {
590                                 send_to_main(cmt_buffer[cmt_count++]);
591                         }
592                         // ???
593                         send_to_main(0x01);
594                         break;
595                 }
596                 send_to_main(0x21);
597                 break;
598         case 0x2b: // specifies the input signal for the external cassette
599                 if(cmd_buf->count() == 1) {
600                         send_to_main(0x01);
601                         break;
602                 }
603                 if(cmd_buf->count() == 2) {
604                         cmd_buf->clear();
605                 }
606                 send_to_main(0x21);
607                 break;
608         case 0x30: // specifies the tone and duration and sounds the piezo speaker
609                 if(cmd_buf->count() == 1) {
610                         send_to_main(0x01);
611                         break;
612                 }
613                 if(cmd_buf->count() == 3) {
614                         cmd_buf->read();
615                         int tone = cmd_buf->read();
616                         int period = cmd_buf->read();
617                         if(tone >= 0 && tone <= 56 && period != 0) {
618                                 sound[0].freq = tone_table[tone];
619                                 sound[0].period = CPU_CLOCKS * period / 256 / 10;
620                                 sound[0].remain = sound[0].period;
621                                 sound_ptr = 0;
622                                 sound_count = 1;
623                                 sound_reply = 0x31;
624                                 break;
625                         }
626                 }
627                 send_to_main(0x31);
628                 break;
629         case 0x31: // specifies the frequency and duration and sounds the piezo speaker
630                 if(cmd_buf->count() == 1) {
631                         send_to_main(0x01);
632                         break;
633                 }
634                 if(cmd_buf->count() == 5) {
635                         cmd_buf->read();
636                         int freq = cmd_buf->read() << 8;
637                         freq |= cmd_buf->read();
638                         int period = cmd_buf->read() << 8;
639                         period |= cmd_buf->read();
640                         if(freq != 0 && period != 0) {
641                                 sound[0].freq = CPU_CLOCKS / freq / 2.0;
642                                 sound[0].period = period;
643                                 sound[0].remain = sound[0].period;
644                                 sound_ptr = 0;
645                                 sound_count = 1;
646                                 sound_reply = 0x31;
647                                 break;
648                         }
649                 }
650                 send_to_main(0x31);
651                 break;
652         case 0x32: // sounds the speaker for 0.03 sec at tone 6
653         case 0x33: // sounds the speaker for 1 sec at tone 20
654                 cmd_buf->read();
655                 if(cmd == 0x32) {
656                         sound[0].freq = tone_table[6];
657                         sound[0].period = CPU_CLOCKS * 3 / 256 / 100;
658                 } else {
659                         sound[0].freq = tone_table[20];
660                         sound[0].period = CPU_CLOCKS / 256;
661                 }
662                 sound[0].remain = sound[0].period;
663                 sound_ptr = 0;
664                 sound_count = 1;
665                 sound_reply = 0x01;
666                 break;
667         case 0x34: // sets melody data in the slave mcu
668                 if(cmd_buf->count() == 1) {
669                         send_to_main(0x01);
670                         break;
671                 }
672                 if(val == 0xff) {
673                         cmd_buf->read();
674                         sound_count = 0;
675                         while(!cmd_buf->empty()) {
676                                 int tone = cmd_buf->read();
677                                 int period = cmd_buf->read();
678                                 if(tone >= 0 && tone <= 56 && period != 0) {
679                                         sound[sound_count].freq = tone_table[tone];
680                                         sound[sound_count].period = CPU_CLOCKS * period / 256 / 10;
681                                         sound_count++;
682                                 }
683                         }
684                         sound_ptr = sound_count;
685                 }
686                 send_to_main(0x31);
687                 break;
688         case 0x35: // sounds the melody data specified in command 34
689                 if(sound_count) {
690                         sound[0].remain = sound[0].period;
691                         sound_ptr = 0;
692                         sound_reply = 0x01;
693                         break;
694                 }
695                 send_to_main(0x01);
696                 break;
697         case 0x40: // turns the serial driver on
698         case 0x41: // turns the serial driver off
699                 cmd_buf->read();
700                 send_to_main(0x01);
701                 break;
702         case 0x48: // sets the polynomial expression used for CRC check
703                 if(cmd_buf->count() == 1) {
704                         send_to_main(0x01);
705                         break;
706                 }
707                 if(cmd_buf->count() == 3) {
708                         cmd_buf->clear();
709                 }
710                 send_to_main(0x41);
711                 break;
712         case 0x50: // identifies the plug-in option
713                 cmd_buf->read();
714                 send_to_main(0x02);
715                 break;
716         case 0x51: // turns power of plug-in rom cartridge on
717         case 0x52: // turns power of plug-in rom cartridge off
718                 cmd_buf->read();
719                 send_to_main(0x01);
720                 break;
721         case 0x60: // executes micro cassette ready check (no respose)
722                 cmd_buf->read();
723                 break;
724         default:
725                 // unknown command
726                 this->out_debug_log(_T("Unknown Command = %2x\n"), cmd);
727                 send_to_main(0x0f);
728                 break;
729         }
730 }
731
732 void MEMORY::send_to_main(uint8_t val)
733 {
734         // send to main cpu
735         d_cpu->write_signal(SIG_MC6801_SIO_RECV, val, 0xff);
736 }
737
738 void MEMORY::play_tape(const _TCHAR* file_path)
739 {
740         close_tape();
741         
742         if(cmt_fio->Fopen(file_path, FILEIO_READ_BINARY)) {
743                 memset(cmt_buffer, 0, sizeof(cmt_buffer));
744                 cmt_fio->Fread(cmt_buffer, sizeof(cmt_buffer), 1);
745                 cmt_fio->Fclose();
746                 cmt_count = 0;
747                 cmt_play = true;
748         }
749 }
750
751 void MEMORY::rec_tape(const _TCHAR* file_path)
752 {
753         close_tape();
754         
755         if(cmt_fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {
756                 my_tcscpy_s(cmt_file_path, _MAX_PATH, file_path);
757                 cmt_count = 0;
758                 cmt_rec = true;
759         }
760 }
761
762 void MEMORY::close_tape()
763 {
764         if(cmt_fio->IsOpened()) {
765                 if(cmt_rec && cmt_count) {
766                         cmt_fio->Fwrite(cmt_buffer, cmt_count, 1);
767                 }
768                 cmt_fio->Fclose();
769         }
770         cmt_count = 0;
771         cmt_play = cmt_rec = false;
772 }
773
774 void MEMORY::draw_screen()
775 {
776         static const int xtop[12] = {0, 0, 40, 40, 80, 80, 0, 0, 40, 40, 80, 80};
777         static const int ytop[12] = {0, 8, 0, 8, 0, 8, 16, 24, 16, 24, 16, 24};
778         
779         for(int c = 0; c < 12; c++) {
780                 int x = xtop[c];
781                 int y = ytop[c];
782                 int ofs = (c & 1) ? 40 : 0;
783                 
784                 for(int i = 0; i < 40; i++) {
785                         uint8_t pat = lcd[c >> 1].buffer[ofs + i];
786                         lcd_render[y + 0][x + i] = (pat & 0x01) ? pd : pb;
787                         lcd_render[y + 1][x + i] = (pat & 0x02) ? pd : pb;
788                         lcd_render[y + 2][x + i] = (pat & 0x04) ? pd : pb;
789                         lcd_render[y + 3][x + i] = (pat & 0x08) ? pd : pb;
790                         lcd_render[y + 4][x + i] = (pat & 0x10) ? pd : pb;
791                         lcd_render[y + 5][x + i] = (pat & 0x20) ? pd : pb;
792                         lcd_render[y + 6][x + i] = (pat & 0x40) ? pd : pb;
793                         lcd_render[y + 7][x + i] = (pat & 0x80) ? pd : pb;
794                 }
795         }
796         for(int y = 0; y < 32; y++) {
797                 scrntype_t* dest = emu->get_screen_buffer(y);
798                 my_memcpy(dest, lcd_render[y], sizeof(scrntype_t) * 120);
799         }
800 }
801
802 #define STATE_VERSION   1
803
804 #include "../../statesub.h"
805
806 void MEMORY::decl_state()
807 {
808         enter_decl_state(STATE_VERSION);
809
810         DECL_STATE_ENTRY_BOOL(tmp_wbank_is_ext); // (wbank[0x8000 >> 13] == ext);
811         DECL_STATE_ENTRY_BOOL(tmp_rbank_is_ext); // (rbank[0x8000 >> 13] == ext);
812
813         DECL_STATE_ENTRY_1D_ARRAY(rom, sizeof(rom));
814         DECL_STATE_ENTRY_1D_ARRAY(ext, sizeof(ext));
815         DECL_STATE_ENTRY_FIFO(cmd_buf);
816         
817         DECL_STATE_ENTRY_BOOL(sio_select);
818         DECL_STATE_ENTRY_BOOL(special_cmd_masked);
819         DECL_STATE_ENTRY_1D_ARRAY(slave_mem, sizeof(slave_mem));
820         {
821                 DECL_STATE_ENTRY_DOUBLE_STRIDE((sound[0].freq),  sizeof(sound) / sizeof(sound[0]), sizeof(sound[0]));
822                 DECL_STATE_ENTRY_INT32_STRIDE((sound[0].period), sizeof(sound) / sizeof(sound[0]), sizeof(sound[0]));
823                 DECL_STATE_ENTRY_INT32_STRIDE((sound[0].remain), sizeof(sound) / sizeof(sound[0]), sizeof(sound[0]));
824         }
825
826         DECL_STATE_ENTRY_INT32(sound_ptr);
827         DECL_STATE_ENTRY_INT32(sound_count);
828         DECL_STATE_ENTRY_UINT8(sound_reply);
829         DECL_STATE_ENTRY_DOUBLE(sound_freq);
830         DECL_STATE_ENTRY_1D_ARRAY(key_stat, sizeof(key_stat));
831         DECL_STATE_ENTRY_1D_ARRAY(key_flag, sizeof(key_flag));
832         DECL_STATE_ENTRY_INT32(key_data);
833         DECL_STATE_ENTRY_INT32(key_strobe);
834         DECL_STATE_ENTRY_INT32(key_intmask);
835         DECL_STATE_ENTRY_BOOL(cmt_play);
836         DECL_STATE_ENTRY_BOOL(cmt_rec);
837         DECL_STATE_ENTRY_STRING(cmt_file_path, sizeof(cmt_file_path));
838         DECL_STATE_ENTRY_CMT_RECORDING(cmt_fio, cmt_rec, cmt_file_path);
839         
840         DECL_STATE_ENTRY_INT32(cmt_count);
841         DECL_STATE_ENTRY_1D_ARRAY(cmt_buffer, sizeof(cmt_buffer));
842         for(int i = 0; i < 6; i++) {
843                 DECL_STATE_ENTRY_1D_ARRAY_MEMBER((lcd[i].buffer), 80, i);
844                 DECL_STATE_ENTRY_INT32_MEMBER((lcd[i].bank), i);
845                 DECL_STATE_ENTRY_INT32_MEMBER((lcd[i].addr), i);
846         }
847
848         DECL_STATE_ENTRY_UINT8(lcd_select);
849         DECL_STATE_ENTRY_UINT8(lcd_data);
850         DECL_STATE_ENTRY_INT32(lcd_clock);
851         DECL_STATE_ENTRY_INT32(int_status);
852         DECL_STATE_ENTRY_INT32(int_mask);
853
854         leave_decl_state();
855 }
856
857 void MEMORY::save_state(FILEIO* state_fio)
858 {
859         tmp_wbank_is_ext = (wbank[0x8000 >> 13] == ext);
860         tmp_rbank_is_ext = (rbank[0x8000 >> 13] == ext);
861         
862         if(state_entry != NULL) {
863                 state_entry->save_state(state_fio);
864         }
865 //      state_fio->FputUint32(STATE_VERSION);
866 //      state_fio->FputInt32(this_device_id);
867         
868 //      state_fio->FputBool(wbank[0x8000 >> 13] == ext);
869 //      state_fio->FputBool(rbank[0x8000 >> 13] == ext);
870 //      state_fio->Fwrite(rom, sizeof(rom), 1);
871 //      state_fio->Fwrite(ext, sizeof(ext), 1);
872 //      cmd_buf->save_state((void *)state_fio);
873 //      state_fio->FputBool(sio_select);
874 //      state_fio->FputBool(special_cmd_masked);
875 //      state_fio->Fwrite(slave_mem, sizeof(slave_mem), 1);
876 //      state_fio->Fwrite(sound, sizeof(sound), 1);
877 //      state_fio->FputInt32(sound_ptr);
878 //      state_fio->FputInt32(sound_count);
879 //      state_fio->FputUint8(sound_reply);
880 //      state_fio->FputDouble(sound_freq);
881 //      state_fio->Fwrite(key_stat, sizeof(key_stat), 1);
882 //      state_fio->Fwrite(key_flag, sizeof(key_flag), 1);
883 //      state_fio->FputInt32(key_data);
884 //      state_fio->FputInt32(key_strobe);
885 //      state_fio->FputInt32(key_intmask);
886 //      state_fio->FputBool(cmt_play);
887 //      state_fio->FputBool(cmt_rec);
888 //      state_fio->Fwrite(cmt_file_path, sizeof(cmt_file_path), 1);
889 //      if(cmt_rec && cmt_fio->IsOpened()) {
890 //              int length_tmp = (int)cmt_fio->Ftell();
891 //              cmt_fio->Fseek(0, FILEIO_SEEK_SET);
892 //              state_fio->FputInt32(length_tmp);
893 //              while(length_tmp != 0) {
894 //                      uint8_t buffer_tmp[1024];
895 //                      int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
896 //                      cmt_fio->Fread(buffer_tmp, length_rw, 1);
897 //                      state_fio->Fwrite(buffer_tmp, length_rw, 1);
898 //                      length_tmp -= length_rw;
899 //              }
900 //      } else {
901 //              state_fio->FputInt32(0);
902 //      }
903 //      state_fio->FputInt32(cmt_count);
904 //      state_fio->Fwrite(cmt_buffer, sizeof(cmt_buffer), 1);
905 //      state_fio->Fwrite(lcd, sizeof(lcd), 1);
906 //      state_fio->FputUint8(lcd_select);
907 //      state_fio->FputUint8(lcd_data);
908 //      state_fio->FputInt32(lcd_clock);
909 //      state_fio->FputInt32(int_status);
910 //      state_fio->FputInt32(int_mask);
911 }
912
913 bool MEMORY::load_state(FILEIO* state_fio)
914 {
915         close_tape();
916         
917         bool mb = false;
918         if(state_entry != NULL) {
919                 mb = state_entry->load_state(state_fio);
920         }
921         if(!mb) {
922                 return false;
923         }
924 //      if(state_fio->FgetUint32() != STATE_VERSION) {
925 //              return false;
926 //      }
927 //      if(state_fio->FgetInt32() != this_device_id) {
928 //              return false;
929 //      }
930 //      bool wr = state_fio->FgetBool();
931 //      bool rd = state_fio->FgetBool();
932 //      state_fio->Fread(rom, sizeof(rom), 1);
933 //      state_fio->Fread(ext, sizeof(ext), 1);
934 //      if(!cmd_buf->load_state((void *)state_fio)) {
935 //              return false;
936 //      }
937 //      sio_select = state_fio->FgetBool();
938 //      special_cmd_masked = state_fio->FgetBool();
939 //      state_fio->Fread(slave_mem, sizeof(slave_mem), 1);
940 //      state_fio->Fread(sound, sizeof(sound), 1);
941 //      sound_ptr = state_fio->FgetInt32();
942 //      sound_count = state_fio->FgetInt32();
943 //      sound_reply = state_fio->FgetUint8();
944 //      sound_freq = state_fio->FgetDouble();
945 //      state_fio->Fread(key_stat, sizeof(key_stat), 1);
946 //      state_fio->Fread(key_flag, sizeof(key_flag), 1);
947 //      key_data = state_fio->FgetInt32();
948 //      key_strobe = state_fio->FgetInt32();
949 //      key_intmask = state_fio->FgetInt32();
950 //      cmt_play = state_fio->FgetBool();
951 //      cmt_rec = state_fio->FgetBool();
952 //      state_fio->Fread(cmt_file_path, sizeof(cmt_file_path), 1);
953 //      int length_tmp = state_fio->FgetInt32();
954 //      if(cmt_rec) {
955 //              cmt_fio->Fopen(cmt_file_path, FILEIO_READ_WRITE_NEW_BINARY);
956 //              while(length_tmp != 0) {
957 //                      uint8_t buffer_tmp[1024];
958 //                      int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
959 //                      state_fio->Fread(buffer_tmp, length_rw, 1);
960 //                      if(cmt_fio->IsOpened()) {
961 //                              cmt_fio->Fread(buffer_tmp, length_rw, 1);
962 //                      }
963 //                      length_tmp -= length_rw;
964 //              }
965 //      }
966 //      cmt_count = state_fio->FgetInt32();
967 //      state_fio->Fread(cmt_buffer, sizeof(cmt_buffer), 1);
968 //      state_fio->Fread(lcd, sizeof(lcd), 1);
969 //      lcd_select = state_fio->FgetUint8();
970 //      lcd_data = state_fio->FgetUint8();
971 //      lcd_clock = state_fio->FgetInt32();
972 //      int_status = state_fio->FgetInt32();
973 //      int_mask = state_fio->FgetInt32();
974         
975         // post process
976         SET_BANK(0x8000, 0xbfff, tmp_wbank_is_ext ? ext : wdmy, tmp_rbank_is_ext ? ext : rom);
977         return true;
978 }
979