OSDN Git Service

[VM][STATE] Apply new framework to some VMs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pc6001 / sub.cpp
index 04b6437..bbac829 100644 (file)
-/*\r
-       NEC PC-6001 Emulator 'yaPC-6001'\r
-       NEC PC-6001mkII Emulator 'yaPC-6201'\r
-       NEC PC-6001mkIISR Emulator 'yaPC-6401'\r
-       NEC PC-6601 Emulator 'yaPC-6601'\r
-       NEC PC-6601SR Emulator 'yaPC-6801'\r
-\r
-       Author : Takeda.Toshiya\r
-       Date   : 2014.05.24-\r
-\r
-       [ sub cpu ]\r
-*/\r
-\r
-#include "sub.h"\r
-#include "timer.h"\r
-#include "../datarec.h"\r
-#include "../i8255.h"\r
-#include "../mcs48.h"\r
-#include "../../fileio.h"\r
-\r
-#define EVENT_PLAY     0\r
-#define EVENT_STOP     1\r
-\r
-static const uint8 key_matrix[16][8] = {\r
-       {0x00,  0x11,   0x10,   0x12,   0x00,   0x00,   0x00,   0x00},\r
-       {0x31,  0x51,   0x41,   0x5a,   0x4b,   0x49,   0x38,   0xbc},\r
-       {0x32,  0x57,   0x53,   0x58,   0x4c,   0x4f,   0x39,   0xbe},\r
-       {0x33,  0x45,   0x44,   0x43,   0xbb,   0x50,   0x70,   0xbf},\r
-       {0x34,  0x52,   0x46,   0x56,   0xba,   0xc0,   0x71,   0xe2},\r
-       {0x35,  0x54,   0x47,   0x42,   0xdd,   0xdb,   0x72,   0x20},\r
-       {0x36,  0x59,   0x48,   0x4e,   0xbd,   0xde,   0x73,   0x30},\r
-       {0x37,  0x55,   0x4a,   0x4d,   0x00,   0xdc,   0x74,   0x00},\r
-       {0x0d,  0x13,   0x26,   0x28,   0x27,   0x25,   0x09,   0x1b},\r
-       {0x15,  0x2d,   0x2e,   0x23,   0x24,   0x00,   0x00,   0x00},  // ROT=END\r
-       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},\r
-       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},\r
-       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},\r
-       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},\r
-       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},\r
-       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},\r
-};\r
-\r
-void SUB::initialize()\r
-{\r
-       fio = new FILEIO();\r
-       rec = false;\r
-       \r
-       key_stat = emu->key_buffer();\r
-       p1_out = 0x10;\r
-       p2_in = 0xff;\r
-       drec_in = rxrdy_in = false;\r
-       skip = false;\r
-       update_key = true;\r
-       register_frame_event(this);\r
-}\r
-\r
-void SUB::release()\r
-{\r
-       close_tape();\r
-       delete fio;\r
-}\r
-\r
-void SUB::reset()\r
-{\r
-       close_tape();\r
-       prev_command = 0;\r
-}\r
-\r
-#define SET_WR(v) d_pio->write_signal(SIG_I8255_PORT_C, (v) ? 0xff : 0, 0x10)\r
-#define SET_RD(v) d_pio->write_signal(SIG_I8255_PORT_C, (v) ? 0xff : 0, 0x40)\r
-\r
-void SUB::write_io8(uint32 addr, uint32 data)\r
-{\r
-       // FIXME: this function is referred from both 80c48 and z80\r
-       if((addr & 0xf0) == 0x90) {\r
-               // Z80\r
-               if((addr & 0xff) == 0x90) {\r
-                       if(prev_command == 0x38) {\r
-                               if(rec && index < sizeof(buffer)) {\r
-                                       buffer[index++] = data;\r
-                                       skip = true;\r
-                               }\r
-                               prev_command = 0;\r
-                       } else {\r
-                               switch(data) {\r
-                               case 0x19:\r
-//                                     d_drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);\r
-                                       register_event(this, EVENT_PLAY, 1000000.0, false, NULL);\r
-                                       break;\r
-                               case 0x1a:\r
-//                                     d_drec->write_signal(SIG_DATAREC_REMOTE, 0, 0);\r
-                                       register_event(this, EVENT_STOP, 1000000.0, false, NULL);\r
-                                       break;\r
-                               case 0x1e:\r
-                               case 0x3e:\r
-                                       baud = 1200;\r
-                                       break;\r
-                               case 0x1d:\r
-                               case 0x3d:\r
-                                       baud = 600;\r
-                                       break;\r
-                               }\r
-                               prev_command = data;\r
-                       }\r
-               }\r
-               d_pio->write_io8(addr, data);\r
-       } else {\r
-               // 8048\r
-               switch(addr) {\r
-               case MCS48_PORT_P1:\r
-                       if((p1_out & 0x0f) != (data & 0x0f)) {\r
-                               update_key = true;\r
-                       }\r
-                       p1_out = data;\r
-//                     d_drec->write_signal(SIG_DATAREC_OUT, data, 0x20);\r
-                       d_timer->write_signal(SIG_TIMER_IRQ_SUB_CPU, ~data, 0x80);\r
-                       break;\r
-               default:\r
-                       SET_WR(1);\r
-                       SET_WR(0);\r
-                       SET_WR(1);\r
-                       d_pio->write_signal(SIG_I8255_PORT_A, data, 0xff);\r
-                       break;\r
-               }\r
-       }\r
-}\r
-\r
-uint32 SUB::read_io8(uint32 addr)\r
-{\r
-       // FIXME: this function is referred from both 80c48 and z80\r
-       if((addr & 0xf0) == 0x90) {\r
-               // Z80\r
-               if((addr & 0xff) == 0x90) {\r
-                       return d_pio->read_io8(addr);\r
-               } else {\r
-                       return 0xff;\r
-               }\r
-       } else {\r
-               // 8048\r
-               switch(addr) {\r
-               case MCS48_PORT_P2:\r
-                       if(update_key) {\r
-                               int column = p1_out & 0x0f;\r
-                               int val = 0;\r
-                               for(int i = 0; i < 8; i++) {\r
-                                       if(key_stat[key_matrix[column][i]]) {\r
-                                               val |= 1 << i;\r
-                                       }\r
-                               }\r
-                               p2_in = (~val) & 0xff;\r
-                               update_key = false;\r
-                       }\r
-                       if(p1_out & 0x10) {\r
-                               return p2_in;\r
-                       } else {\r
-                               // bit3: signal from datarec\r
-                               // bit1: rxrdy from rs-232c\r
-                               return (rxrdy_in ? 2 : 0) | (drec_in ? 8 : 0) | (p2_in & 0xf0);\r
-                       }\r
-               case MCS48_PORT_T0:\r
-                       // PC5 -> T0\r
-                       return (d_pio->read_signal(SIG_I8255_PORT_C) >> 5) & 1;\r
-               default:\r
-                       SET_RD(1);\r
-                       SET_RD(0);\r
-                       SET_RD(1);\r
-                       return d_pio->read_signal(SIG_I8255_PORT_A);\r
-               }\r
-       }\r
-       return 0xff;\r
-}\r
-\r
-uint32 SUB::intr_ack()\r
-{\r
-       return d_pio->read_io8(0);\r
-}\r
-\r
-void SUB::event_frame()\r
-{\r
-       if(skip) {\r
-               request_skip_frames();\r
-               skip = false;\r
-       }\r
-       update_key = true;\r
-}\r
-\r
-void SUB::event_callback(int event_id, int err)\r
-{\r
-       if(event_id == EVENT_PLAY) {\r
-               d_drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);\r
-       } else if(event_id == EVENT_STOP) {\r
-               d_drec->write_signal(SIG_DATAREC_REMOTE, 0, 0);\r
-       }\r
-}\r
-\r
-void SUB::write_signal(int id, uint32 data, uint32 mask)\r
-{\r
-       if(id == SIG_SUB_DATAREC) {\r
-               drec_in = ((data & mask) != 0);\r
-       } else if(id == SIG_SUB_RXRDY) {\r
-               rxrdy_in = ((data & mask) != 0);\r
-       }\r
-}\r
-\r
-bool SUB::rec_tape(_TCHAR* file_path)\r
-{\r
-       close_tape();\r
-       \r
-       if(fio->Fopen(file_path, FILEIO_WRITE_BINARY)) {\r
-               index = 0;\r
-               rec = true;\r
-               is_wav = check_file_extension(file_path, _T(".wav"));\r
-               is_p6t = check_file_extension(file_path, _T(".p6t"));\r
-       }\r
-       return rec;\r
-}\r
-\r
-#pragma pack(1)\r
-typedef struct {\r
-       char id[4];\r
-       uint32 size;\r
-} wav_chunk_t;\r
-#pragma pack()\r
-\r
-#pragma pack(1)\r
-typedef struct {\r
-       wav_chunk_t riff_chunk;\r
-       char wave[4];\r
-       wav_chunk_t fmt_chunk;\r
-       uint16 format_id;\r
-       uint16 channels;\r
-       uint32 sample_rate;\r
-       uint32 data_speed;\r
-       uint16 block_size;\r
-       uint16 sample_bits;\r
-} wav_header_t;\r
-#pragma pack()\r
-\r
-static const uint8 pulse_1200hz[40] = {\r
-       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,\r
-       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,\r
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\r
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
-};\r
-\r
-static const uint8 pulse_2400hz[20] = {\r
-       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,\r
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
-};\r
-\r
-static const uint8 pulse_2400hz_x2[40] = {\r
-       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,\r
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\r
-       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,\r
-       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00\r
-};\r
-\r
-void SUB::close_tape()\r
-{\r
-       if(rec) {\r
-               if(is_wav) {\r
-                       wav_header_t wav_header;\r
-                       wav_chunk_t wav_chunk;\r
-                       int sample_rate = (baud == 600) ? 24000 : 48000;\r
-                       \r
-                       fio->Fwrite(&wav_header, sizeof(wav_header), 1);\r
-                       fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);\r
-                       \r
-                       for(int i = 0; i < 9600; i++) {\r
-                               fio->Fwrite((void *)pulse_2400hz, sizeof(pulse_2400hz), 1);\r
-                       }\r
-                       for(int i = 0; i < 16; i++) {\r
-                               fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);\r
-                               for(int j = 0; j < 8; j++) {\r
-                                       if(buffer[i] & (1 << j)) {\r
-                                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                                       } else {\r
-                                               fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);\r
-                                       }\r
-                               }\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                       }\r
-//                     for(int i = 0; i < 1280; i++) {\r
-                       for(int i = 0; i < 2400; i++) {\r
-                               fio->Fwrite((void *)pulse_2400hz, sizeof(pulse_2400hz), 1);\r
-                       }\r
-                       for(int i = 16; i < index; i++) {\r
-                               fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);\r
-                               for(int j = 0; j < 8; j++) {\r
-                                       if(buffer[i] & (1 << j)) {\r
-                                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                                       } else {\r
-                                               fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);\r
-                                       }\r
-                               }\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                       }\r
-#if 1\r
-                       for(int i = 0; i < 16; i++) {\r
-                               fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);\r
-                               for(int j = 0; j < 8; j++) {\r
-                                       fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);\r
-                               }\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                               fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);\r
-                       }\r
-#endif\r
-                       uint32 length = fio->Ftell();\r
-                       \r
-                       memcpy(wav_header.riff_chunk.id, "RIFF", 4);\r
-                       wav_header.riff_chunk.size = length - 8;\r
-                       memcpy(wav_header.wave, "WAVE", 4);\r
-                       memcpy(wav_header.fmt_chunk.id, "fmt ", 4);\r
-                       wav_header.fmt_chunk.size = 16;\r
-                       wav_header.format_id = 1;\r
-                       wav_header.channels = 1;\r
-                       wav_header.sample_rate = sample_rate;\r
-                       wav_header.data_speed = sample_rate;\r
-                       wav_header.block_size = 1;\r
-                       wav_header.sample_bits = 8;\r
-                       \r
-                       memcpy(wav_chunk.id, "data", 4);\r
-                       wav_chunk.size = length - sizeof(wav_header) - sizeof(wav_chunk);\r
-                       \r
-                       fio->Fseek(0, FILEIO_SEEK_SET);\r
-                       fio->Fwrite(&wav_header, sizeof(wav_header), 1);\r
-                       fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);\r
-               } else {\r
-                       fio->Fwrite(buffer, index, 1);\r
-                       if(is_p6t) {\r
-                               fio->Fputc('P');\r
-                               fio->Fputc('6');\r
-                               fio->FputUint8(2);\r
-                               fio->FputUint8(2);\r
-                               fio->FputUint8(0);\r
-                               fio->FputUint8(0);\r
-                               fio->FputUint8(0);\r
-                               fio->FputUint16(0);\r
-                               fio->FputUint16(0);\r
-                               \r
-                               fio->Fputc('T');\r
-                               fio->Fputc('I');\r
-                               fio->FputUint8(0);\r
-                               for(int i = 0; i < 6; i++) {\r
-                                       fio->FputUint8(buffer[10 + i]);\r
-                               }\r
-                               for(int i = 6; i < 16; i++) {\r
-                                       fio->FputUint8(0);\r
-                               }\r
-                               fio->FputUint16(baud);\r
-                               fio->FputUint16(3000);\r
-                               fio->FputUint16(4000);\r
-                               fio->FputUint32(0);\r
-                               fio->FputUint32(16);\r
-                               \r
-                               fio->Fputc('T');\r
-                               fio->Fputc('I');\r
-                               fio->FputUint8(0);\r
-                               for(int i = 0; i < 16; i++) {\r
-                                       fio->FputUint8(0);\r
-                               }\r
-                               fio->FputUint16(baud);\r
-                               fio->FputUint16(0);\r
-                               fio->FputUint16(1000);\r
-                               fio->FputUint32(16);\r
-                               fio->FputUint32(index - 16);\r
-                               \r
-                               fio->FputUint32(index);\r
-                       }\r
-               }\r
-               fio->Fclose();\r
-       }\r
-       rec = false;\r
-}\r
+/*
+       NEC PC-6001 Emulator 'yaPC-6001'
+       NEC PC-6001mkII Emulator 'yaPC-6201'
+       NEC PC-6001mkIISR Emulator 'yaPC-6401'
+       NEC PC-6601 Emulator 'yaPC-6601'
+       NEC PC-6601SR Emulator 'yaPC-6801'
+
+       Author : Takeda.Toshiya
+       Date   : 2014.05.24-
+
+       [ sub cpu ]
+*/
+
+#include "sub.h"
+#include "timer.h"
+#include "../datarec.h"
+#include "../i8255.h"
+#include "../mcs48.h"
+
+#define EVENT_PLAY     0
+#define EVENT_STOP     1
+
+static const uint8_t key_matrix[16][8] = {
+       {0x00,  0x11,   0x10,   0x12,   0x00,   0x00,   0x00,   0x00},
+       {0x31,  0x51,   0x41,   0x5a,   0x4b,   0x49,   0x38,   0xbc},
+       {0x32,  0x57,   0x53,   0x58,   0x4c,   0x4f,   0x39,   0xbe},
+       {0x33,  0x45,   0x44,   0x43,   0xbb,   0x50,   0x70,   0xbf},
+       {0x34,  0x52,   0x46,   0x56,   0xba,   0xc0,   0x71,   0xe2},
+       {0x35,  0x54,   0x47,   0x42,   0xdd,   0xdb,   0x72,   0x20},
+       {0x36,  0x59,   0x48,   0x4e,   0xbd,   0xde,   0x73,   0x30},
+       {0x37,  0x55,   0x4a,   0x4d,   0x00,   0xdc,   0x74,   0x00},
+       {0x0d,  0x13,   0x26,   0x28,   0x27,   0x25,   0x09,   0x1b},
+       {0x15,  0x2d,   0x2e,   0x23,   0x24,   0x00,   0x00,   0x00},  // ROT=END
+       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},
+       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},
+       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},
+       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},
+       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},
+       {0x00,  0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00},
+};
+
+void SUB::initialize()
+{
+       fio = new FILEIO();
+       rec = false;
+       
+       key_stat = emu->get_key_buffer();
+       p1_out = 0x10;
+       p2_in = 0xff;
+       drec_in = rxrdy_in = false;
+       skip = false;
+       update_key = true;
+       register_frame_event(this);
+}
+
+void SUB::release()
+{
+       close_tape();
+       delete fio;
+}
+
+void SUB::reset()
+{
+       close_tape();
+       prev_command = 0;
+}
+
+#define SET_WR(v) d_pio->write_signal(SIG_I8255_PORT_C, (v) ? 0xff : 0, 0x10)
+#define SET_RD(v) d_pio->write_signal(SIG_I8255_PORT_C, (v) ? 0xff : 0, 0x40)
+
+void SUB::write_io8(uint32_t addr, uint32_t data)
+{
+       // FIXME: this function is referred from both 80c48 and z80
+       if((addr & 0xf0) == 0x90) {
+               // Z80
+               if((addr & 0xff) == 0x90) {
+                       if(prev_command == 0x38) {
+                               if(rec && index < sizeof(buffer)) {
+                                       buffer[index++] = data;
+                                       skip = true;
+                               }
+                               prev_command = 0;
+                       } else {
+                               switch(data) {
+                               case 0x19:
+//                                     d_drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);
+                                       register_event(this, EVENT_PLAY, 1000000.0, false, NULL);
+                                       break;
+                               case 0x1a:
+//                                     d_drec->write_signal(SIG_DATAREC_REMOTE, 0, 0);
+                                       register_event(this, EVENT_STOP, 1000000.0, false, NULL);
+                                       break;
+                               case 0x1e:
+                               case 0x3e:
+                                       baud = 1200;
+                                       break;
+                               case 0x1d:
+                               case 0x3d:
+                                       baud = 600;
+                                       break;
+                               }
+                               prev_command = data;
+                       }
+               }
+               d_pio->write_io8(addr, data);
+       } else {
+               // 8048
+               switch(addr) {
+               case MCS48_PORT_P1:
+                       if((p1_out & 0x0f) != (data & 0x0f)) {
+                               update_key = true;
+                       }
+                       p1_out = data;
+//                     d_drec->write_signal(SIG_DATAREC_MIC, data, 0x20);
+                       d_timer->write_signal(SIG_TIMER_IRQ_SUB_CPU, ~data, 0x80);
+                       break;
+               default:
+                       SET_WR(1);
+                       SET_WR(0);
+                       SET_WR(1);
+                       d_pio->write_signal(SIG_I8255_PORT_A, data, 0xff);
+                       break;
+               }
+       }
+}
+
+uint32_t SUB::read_io8(uint32_t addr)
+{
+       // FIXME: this function is referred from both 80c48 and z80
+       if((addr & 0xf0) == 0x90) {
+               // Z80
+               if((addr & 0xff) == 0x90) {
+                       return d_pio->read_io8(addr);
+               } else {
+                       return 0xff;
+               }
+       } else {
+               // 8048
+               switch(addr) {
+               case MCS48_PORT_P2:
+                       if(update_key) {
+                               int column = p1_out & 0x0f;
+                               int val = 0;
+                               for(int i = 0; i < 8; i++) {
+                                       if(key_stat[key_matrix[column][i]]) {
+                                               val |= 1 << i;
+                                       }
+                               }
+                               p2_in = (~val) & 0xff;
+                               update_key = false;
+                       }
+                       if(p1_out & 0x10) {
+                               return p2_in;
+                       } else {
+                               // bit3: signal from datarec
+                               // bit1: rxrdy from rs-232c
+                               return (rxrdy_in ? 2 : 0) | (drec_in ? 8 : 0) | (p2_in & 0xf0);
+                       }
+               case MCS48_PORT_T0:
+                       // PC5 -> T0
+                       return (d_pio->read_signal(SIG_I8255_PORT_C) >> 5) & 1;
+               default:
+                       SET_RD(1);
+                       SET_RD(0);
+                       SET_RD(1);
+                       return d_pio->read_signal(SIG_I8255_PORT_A);
+               }
+       }
+       return 0xff;
+}
+
+uint32_t SUB::get_intr_ack()
+{
+       return d_pio->read_io8(0);
+}
+
+void SUB::event_frame()
+{
+       if(skip) {
+               request_skip_frames();
+               skip = false;
+       }
+       update_key = true;
+}
+
+void SUB::event_callback(int event_id, int err)
+{
+       if(event_id == EVENT_PLAY) {
+               d_drec->write_signal(SIG_DATAREC_REMOTE, 1, 1);
+       } else if(event_id == EVENT_STOP) {
+               d_drec->write_signal(SIG_DATAREC_REMOTE, 0, 0);
+       }
+}
+
+void SUB::write_signal(int id, uint32_t data, uint32_t mask)
+{
+       if(id == SIG_SUB_DATAREC) {
+               drec_in = ((data & mask) != 0);
+       } else if(id == SIG_SUB_RXRDY) {
+               rxrdy_in = ((data & mask) != 0);
+       }
+}
+
+bool SUB::rec_tape(const _TCHAR* file_path)
+{
+       close_tape();
+       
+       if(fio->Fopen(file_path, FILEIO_READ_WRITE_NEW_BINARY)) {
+               my_tcscpy_s(rec_file_path, _MAX_PATH, file_path);
+               index = 0;
+               rec = true;
+               is_wav = check_file_extension(file_path, _T(".wav"));
+               is_p6t = check_file_extension(file_path, _T(".p6t"));
+       }
+       return rec;
+}
+
+static const uint8_t pulse_1200hz[40] = {
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static const uint8_t pulse_2400hz[20] = {
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+static const uint8_t pulse_2400hz_x2[40] = {
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+       0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
+};
+
+void SUB::close_tape()
+{
+       if(fio->IsOpened()) {
+               if(rec) {
+                       if(is_wav) {
+                               wav_header_t wav_header;
+                               wav_chunk_t wav_chunk;
+                               int sample_rate = (baud == 600) ? 24000 : 48000;
+                               
+                               fio->Fwrite(&wav_header, sizeof(wav_header), 1);
+                               fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
+                               
+                               for(int i = 0; i < 9600; i++) {
+                                       fio->Fwrite((void *)pulse_2400hz, sizeof(pulse_2400hz), 1);
+                               }
+                               for(int i = 0; i < 16; i++) {
+                                       fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);
+                                       for(int j = 0; j < 8; j++) {
+                                               if(buffer[i] & (1 << j)) {
+                                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                                               } else {
+                                                       fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);
+                                               }
+                                       }
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                               }
+       //                      for(int i = 0; i < 1280; i++) {
+                               for(int i = 0; i < 2400; i++) {
+                                       fio->Fwrite((void *)pulse_2400hz, sizeof(pulse_2400hz), 1);
+                               }
+                               for(int i = 16; i < index; i++) {
+                                       fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);
+                                       for(int j = 0; j < 8; j++) {
+                                               if(buffer[i] & (1 << j)) {
+                                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                                               } else {
+                                                       fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);
+                                               }
+                                       }
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                               }
+#if 1
+                               for(int i = 0; i < 16; i++) {
+                                       fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);
+                                       for(int j = 0; j < 8; j++) {
+                                               fio->Fwrite((void *)pulse_1200hz, sizeof(pulse_1200hz), 1);
+                                       }
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                                       fio->Fwrite((void *)pulse_2400hz_x2, sizeof(pulse_2400hz_x2), 1);
+                               }
+#endif
+                               uint32_t length = fio->Ftell();
+#if 0                          
+                               pair_t __riff_chunk_size;
+                               pair_t __fmt_chunk_size;
+                               pair_t __wav_chunk_size;
+                               pair16_t __fmt_id;
+                               pair16_t __channels;
+                               pair_t __sample_rate;
+                               pair16_t __block_size;
+                               pair16_t __sample_bits;
+
+                               __riff_chunk_size.d = length - 8;
+                               __fmt_chunk_size.d = 16;
+                               __fmt_id.w = 1;
+                               __channels.w = 1;
+                               __sample_rate.d = sample_rate;
+                               __block_size.w = 1;
+                               __sample_bits.w = 8;
+       
+                               memcpy(wav_header.riff_chunk.id, "RIFF", 4);
+                               wav_header.riff_chunk.size = __riff_chunk_size.get_4bytes_le_to();
+       
+                               memcpy(wav_header.wave, "WAVE", 4);
+                               memcpy(wav_header.fmt_chunk.id, "fmt ", 4);
+                               wav_header.fmt_chunk.size = __riff_chunk_size.get_4bytes_le_to();
+                               wav_header.format_id = __fmt_id.get_2bytes_le_to();
+                               wav_header.channels = __channels.get_2byte_le_to();
+                               wav_header.sample_rate = __sample_rate.get_4bytes_le_to();
+                               wav_header.data_speed =  __sample_rate.get_4bytes_le_to();
+                               wav_header.block_size = __block_size.get_2bytes_le_to();
+                               wav_header.sample_bits = __sample_bits_get_2bytes_le_to();
+       
+                               memcpy(wav_chunk.id, "data", 4);
+                               __wav_chunk_size.d = length - sizeof(wav_header) - sizeof(wav_chunk);
+                               wav_chunk.size = __wav_chunk_size.get_4bytes_le_to();
+                               
+                               fio->Fseek(0, FILEIO_SEEK_SET);
+                               fio->Fwrite(&wav_header, sizeof(wav_header), 1);
+                               fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
+#else
+                               if(set_wav_header(&wav_header, &wav_chunk, 1, sample_rate, 8, length)) {
+                                       fio->Fseek(0, FILEIO_SEEK_SET);
+                                       fio->Fwrite(&wav_header, sizeof(wav_header), 1);
+                                       fio->Fwrite(&wav_chunk, sizeof(wav_chunk), 1);
+                               }
+#endif
+                       } else {
+                               fio->Fwrite(buffer, index, 1);
+                               if(is_p6t) {
+                                       fio->Fputc('P');
+                                       fio->Fputc('6');
+                                       fio->FputUint8(2);
+                                       fio->FputUint8(2);
+                                       fio->FputUint8(0);
+                                       fio->FputUint8(0);
+                                       fio->FputUint8(0);
+                                       fio->FputUint16(0);
+                                       fio->FputUint16(0);
+                                       
+                                       fio->Fputc('T');
+                                       fio->Fputc('I');
+                                       fio->FputUint8(0);
+                                       for(int i = 0; i < 6; i++) {
+                                               fio->FputUint8(buffer[10 + i]);
+                                       }
+                                       for(int i = 6; i < 16; i++) {
+                                               fio->FputUint8(0);
+                                       }
+                                       fio->FputUint16(baud);
+                                       fio->FputUint16(3000);
+                                       fio->FputUint16(4000);
+                                       fio->FputUint32(0);
+                                       fio->FputUint32(16);
+                                       
+                                       fio->Fputc('T');
+                                       fio->Fputc('I');
+                                       fio->FputUint8(0);
+                                       for(int i = 0; i < 16; i++) {
+                                               fio->FputUint8(0);
+                                       }
+                                       fio->FputUint16(baud);
+                                       fio->FputUint16(0);
+                                       fio->FputUint16(1000);
+                                       fio->FputUint32(16);
+                                       fio->FputUint32(index - 16);
+                                       
+                                       fio->FputUint32(index);
+                               }
+                       }
+               }
+               fio->Fclose();
+       }
+       rec = false;
+}
+
+#define STATE_VERSION  1
+
+bool SUB::process_state(FILEIO* state_fio, bool loading)
+{
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+               return false;
+       }
+       if(!state_fio->StateCheckInt32(this_device_id)) {
+               return false;
+       }
+       state_fio->StateInt32(p1_out);
+       state_fio->StateInt32(p2_in);
+       state_fio->StateBool(drec_in);
+       state_fio->StateBool(rxrdy_in);
+       state_fio->StateBool(update_key);
+       state_fio->StateBool(rec);
+       state_fio->StateBool(is_wav);
+       state_fio->StateBool(is_p6t);
+       state_fio->StateBuffer(rec_file_path, sizeof(rec_file_path), 1);
+       if(loading) {
+               int length_tmp = state_fio->FgetInt32_LE();
+               if(rec) {
+                       fio->Fopen(rec_file_path, FILEIO_READ_WRITE_NEW_BINARY);
+                       while(length_tmp != 0) {
+                               uint8_t buffer_tmp[1024];
+                               int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
+                               state_fio->Fread(buffer_tmp, length_rw, 1);
+                               if(fio->IsOpened()) {
+                                       fio->Fwrite(buffer_tmp, length_rw, 1);
+                               }
+                               length_tmp -= length_rw;
+                       }
+               }
+       } else {
+               if(rec && fio->IsOpened()) {
+                       int length_tmp = (int)fio->Ftell();
+                       fio->Fseek(0, FILEIO_SEEK_SET);
+                       state_fio->FputInt32_LE(length_tmp);
+                       while(length_tmp != 0) {
+                               uint8_t buffer_tmp[1024];
+                               int length_rw = min(length_tmp, (int)sizeof(buffer_tmp));
+                               fio->Fread(buffer_tmp, length_rw, 1);
+                               state_fio->Fwrite(buffer_tmp, length_rw, 1);
+                               length_tmp -= length_rw;
+                       }
+               } else {
+                       state_fio->FputInt32_LE(0);
+               }
+       }
+       state_fio->StateInt32(prev_command);
+       state_fio->StateInt32(baud);
+       state_fio->StateInt32(index);
+       state_fio->StateBool(skip);
+       state_fio->StateBuffer(buffer, sizeof(buffer), 1);
+       return true;
+}