OSDN Git Service

[INITIAL] Import 20141226 version of http://homepage3.nifty.com/takeda-toshiya/common...
[csp-qt/common_source_project-fm7.git] / source / src / vm / mz700 / quickdisk.cpp
diff --git a/source/src/vm/mz700/quickdisk.cpp b/source/src/vm/mz700/quickdisk.cpp
new file mode 100644 (file)
index 0000000..524ae68
--- /dev/null
@@ -0,0 +1,612 @@
+/*\r
+       SHARP MZ-800 Emulator 'EmuZ-800'\r
+       SHARP MZ-1500 Emulator 'EmuZ-1500'\r
+       SHARP MZ-2200 Emulator 'EmuZ-2200'\r
+\r
+       Author : Takeda.Toshiya\r
+       Date   : 2011.02.17-\r
+\r
+       [ quick disk ]\r
+*/\r
+\r
+#include "quickdisk.h"\r
+#include "../z80sio.h"\r
+#include "../../fileio.h"\r
+\r
+#define MZT_HEADER_SIZE        128\r
+#define HEADER_SIZE    64\r
+\r
+#define EVENT_RESTORE  0\r
+#define EVENT_END      1\r
+\r
+// 100usec\r
+#define PERIOD_RESTORE 100\r
+// 1sec\r
+#define PERIOD_END     1000000\r
+\r
+#define DATA_SYNC      0x16\r
+#define DATA_MARK      0xa5\r
+#define DATA_CRC       0xff\r
+#define DATA_BREAK     0x100\r
+#define DATA_EMPTY     0x101\r
+\r
+#define HEADER_BLOCK_ID        0\r
+#define DATA_BLOCK_ID  1\r
+\r
+void QUICKDISK::initialize()\r
+{\r
+       insert = protect = false;\r
+       home = true;\r
+       first_data = send_break = true;\r
+}\r
+\r
+void QUICKDISK::release()\r
+{\r
+       release_disk();\r
+}\r
+\r
+void QUICKDISK::reset()\r
+{\r
+       wrga = mton = true;\r
+       sync = false;\r
+       motor_on = false;\r
+       accessed = false;\r
+       restore_id = end_id = -1;\r
+       \r
+       set_insert(insert);\r
+       set_protect(protect);\r
+       set_home(true);\r
+}\r
+\r
+/*\r
+       PROTECT -> CTSA\r
+               H: write protected\r
+       INSERT -> DCDA\r
+               L: inserted\r
+       HOME -> DCDB\r
+               L: reach to head position\r
+               H: reset, reach to end of disk, DTRB is L->H\r
+\r
+       RTSA -> WRGA\r
+               L: write disk / stop motor at the end of disk\r
+               H: read disk\r
+       DTRB -> MTON\r
+               H->L: start motor\r
+               H: stop motor at the end of disk\r
+*/\r
+\r
+#define REGISTER_RESTORE_EVENT() { \\r
+       if(restore_id == -1) { \\r
+               register_event(this, EVENT_RESTORE, PERIOD_RESTORE, false, &restore_id); \\r
+       } \\r
+}\r
+\r
+#define CANCEL_RESTORE_EVENT() { \\r
+       if(restore_id != -1) { \\r
+               cancel_event(this, restore_id); \\r
+               restore_id = -1; \\r
+       } \\r
+}\r
+\r
+#define REGISTER_END_EVENT() { \\r
+       if(end_id != -1) { \\r
+               cancel_event(this, end_id); \\r
+       } \\r
+       register_event(this, EVENT_END, PERIOD_END, false, &end_id); \\r
+}\r
+\r
+#define CANCEL_END_EVENT() { \\r
+       if(end_id != -1) { \\r
+               cancel_event(this, end_id); \\r
+               end_id = -1; \\r
+       } \\r
+}\r
+\r
+#define WRITE_BUFFER(v) { \\r
+       if(buffer_ptr < QUICKDISK_BUFFER_SIZE) { \\r
+               if(buffer[buffer_ptr] != v) { \\r
+                       buffer[buffer_ptr] = v; \\r
+                       modified = true; \\r
+               } \\r
+               buffer_ptr++; \\r
+       } \\r
+}\r
+\r
+void QUICKDISK::write_signal(int id, uint32 data, uint32 mask)\r
+{\r
+       bool next = ((data & mask) != 0);\r
+       \r
+       if(id == QUICKDISK_SIO_RTSA) {\r
+               if(wrga && !next) {\r
+                       // start to write\r
+                       first_data = true;\r
+                       write_ptr = 0;\r
+               } else if(!wrga && next) {\r
+                       // end to write\r
+                       write_crc();\r
+               }\r
+               wrga = next;\r
+       } else if(id == QUICKDISK_SIO_DTRB) {\r
+               if(mton && !next) {\r
+                       // H->L: start motor\r
+                       if(motor_on && wrga) {\r
+                               // restart to send\r
+                               send_data();\r
+                               REGISTER_END_EVENT();\r
+                       } else {\r
+                               // start motor and restore to home position\r
+                               motor_on = true;\r
+                               REGISTER_RESTORE_EVENT();\r
+                               CANCEL_END_EVENT();\r
+                       }\r
+               } else if(!mton && next) {\r
+                       // L->H: home signal is high\r
+                       set_home(true);\r
+               }\r
+               mton = next;\r
+       } else if(id == QUICKDISK_SIO_SYNC) {\r
+               // enter hunt/sync phase\r
+               sync = next;\r
+               if(sync) {\r
+                       // hack: start to send for verify\r
+                       if(!wrga) {\r
+                               write_crc();\r
+                               wrga = true;\r
+                       }\r
+                       send_data();\r
+               }\r
+       } else if(id == QUICKDISK_SIO_RXDONE) {\r
+               // send next data\r
+               send_data();\r
+       } else if(id == QUICKDISK_SIO_DATA || id == QUICKDISK_SIO_BREAK) {\r
+               // write data\r
+               if(!(motor_on && !wrga)) {\r
+                       return;\r
+               }\r
+               if(id == QUICKDISK_SIO_DATA) {\r
+                       if(first_data) {\r
+                               // write sync chars at the top of message\r
+                               WRITE_BUFFER(DATA_SYNC);\r
+                               WRITE_BUFFER(DATA_SYNC);\r
+                               first_data = false;\r
+                       }\r
+                       WRITE_BUFFER(data);\r
+                       write_ptr = buffer_ptr;\r
+               } else if(id == QUICKDISK_SIO_BREAK) {\r
+                       write_crc();\r
+                       WRITE_BUFFER(DATA_BREAK);\r
+                       first_data = true;\r
+                       write_ptr = 0;\r
+               }\r
+               accessed = true;\r
+               \r
+               if(buffer_ptr < QUICKDISK_BUFFER_SIZE) {\r
+                       REGISTER_END_EVENT();\r
+               } else {\r
+                       CANCEL_END_EVENT();\r
+                       end_of_disk();\r
+               }\r
+       }\r
+}\r
+\r
+uint32 QUICKDISK::read_signal(int ch)\r
+{\r
+       // access lamp signal\r
+       if(accessed) {\r
+               accessed = false;\r
+               return 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+void QUICKDISK::event_callback(int event_id, int err)\r
+{\r
+       if(event_id == EVENT_RESTORE) {\r
+               // reached to home position\r
+               restore_id = -1;\r
+               restore();\r
+       } else if(event_id == EVENT_END) {\r
+               // reached to end of disk\r
+               end_id = -1;\r
+               end_of_disk();\r
+       }\r
+}\r
+\r
+void QUICKDISK::restore()\r
+{\r
+       // reached to home position\r
+       set_home(false);\r
+       buffer_ptr = 0;\r
+       first_data = send_break = true;\r
+       \r
+       // start to send\r
+       send_data();\r
+}\r
+\r
+void QUICKDISK::send_data()\r
+{\r
+       if(!(motor_on && wrga) || restore_id != -1) {\r
+               return;\r
+       }\r
+retry:\r
+       if(buffer_ptr < QUICKDISK_BUFFER_SIZE && buffer[buffer_ptr] != DATA_EMPTY) {\r
+               if(buffer[buffer_ptr] == DATA_BREAK) {\r
+                       // send break signal\r
+                       if(send_break) {\r
+                               d_sio->write_signal(SIG_Z80SIO_BREAK_CH0, 1, 1);\r
+                               send_break = false;\r
+                       }\r
+                       // wait until sio enters hunt/sync phase\r
+                       if(!sync) {\r
+                               return;\r
+                       }\r
+                       buffer_ptr++;\r
+                       goto retry;\r
+               }\r
+               // send data\r
+               d_sio->write_signal(SIG_Z80SIO_RECV_CH0, buffer[buffer_ptr++], 0xff);\r
+               send_break = true;\r
+               accessed = true;\r
+               REGISTER_END_EVENT();\r
+       } else {\r
+               // reached to end of disk\r
+               CANCEL_END_EVENT();\r
+               end_of_disk();\r
+       }\r
+}\r
+\r
+void QUICKDISK::write_crc()\r
+{\r
+       if(!wrga && write_ptr != 0) {\r
+               buffer_ptr = write_ptr;\r
+               \r
+               WRITE_BUFFER(DATA_CRC);\r
+               WRITE_BUFFER(DATA_CRC);\r
+               WRITE_BUFFER(DATA_SYNC);\r
+               WRITE_BUFFER(DATA_SYNC);\r
+               // don't increment pointer !!!\r
+               WRITE_BUFFER(DATA_BREAK);\r
+               buffer_ptr--;\r
+       }\r
+       write_ptr = 0;\r
+}\r
+\r
+void QUICKDISK::end_of_disk()\r
+{\r
+       // write crc\r
+       write_crc();\r
+       \r
+       // reached to end of disk\r
+       if(mton || !wrga) {\r
+               motor_on = false;\r
+       } else {\r
+               REGISTER_RESTORE_EVENT();\r
+       }\r
+       set_home(true);\r
+}\r
+\r
+void QUICKDISK::set_insert(bool val)\r
+{\r
+       // L=inserted\r
+       d_sio->write_signal(SIG_Z80SIO_DCD_CH0, val ? 0 : 1, 1);\r
+       insert = val;\r
+}\r
+\r
+void QUICKDISK::set_protect(bool val)\r
+{\r
+       // H=protected\r
+       d_sio->write_signal(SIG_Z80SIO_CTS_CH0, val ? 1 : 0, 1);\r
+       protect = val;\r
+}\r
+\r
+void QUICKDISK::set_home(bool val)\r
+{\r
+       if(home != val) {\r
+               d_sio->write_signal(SIG_Z80SIO_DCD_CH1, val ? 1 : 0, 1);\r
+               home = val;\r
+       }\r
+}\r
+\r
+void QUICKDISK::open_disk(_TCHAR path[])\r
+{\r
+       // check current disk image\r
+       if(insert) {\r
+               if(_tcsicmp(file_path, path) == 0) {\r
+                       return;\r
+               }\r
+               // close current disk\r
+               close_disk();\r
+       }\r
+       memset(buffer, 0, sizeof(buffer));\r
+       \r
+       // load disk image\r
+       FILEIO* fio = new FILEIO();\r
+       if(fio->Fopen(path, FILEIO_READ_BINARY)) {\r
+               _tcscpy(file_path, path);\r
+               \r
+               // clear buffer\r
+               for(int i = 0; i < QUICKDISK_BUFFER_SIZE; i++) {\r
+                       buffer[i] = DATA_EMPTY;\r
+               }\r
+               buffer_ptr = 0;\r
+               modified = false;\r
+               \r
+               // check extension\r
+               if(check_file_extension(file_path, _T(".mzt")) || check_file_extension(file_path, _T(".q20"))) {\r
+                       // load mzt file\r
+                       fio->Fseek(0, FILEIO_SEEK_END);\r
+                       int remain = fio->Ftell();\r
+                       fio->Fseek(0, FILEIO_SEEK_SET);\r
+                       \r
+                       int num_block = 0;\r
+                       int block_num_ptr = 0;\r
+                       \r
+                       // create block file\r
+                       buffer[buffer_ptr++] = DATA_BREAK;\r
+                       buffer[buffer_ptr++] = DATA_SYNC;\r
+                       buffer[buffer_ptr++] = DATA_SYNC;\r
+                       buffer[buffer_ptr++] = DATA_MARK;\r
+                       block_num_ptr = buffer_ptr;\r
+                       buffer[buffer_ptr++] = 0; // block number\r
+                       buffer[buffer_ptr++] = DATA_CRC;\r
+                       buffer[buffer_ptr++] = DATA_CRC;\r
+                       buffer[buffer_ptr++] = DATA_SYNC;\r
+                       buffer[buffer_ptr++] = DATA_SYNC;\r
+                       buffer[buffer_ptr++] = DATA_BREAK;\r
+                       \r
+                       while(remain >= MZT_HEADER_SIZE) {\r
+                               // load header\r
+                               uint8 header[MZT_HEADER_SIZE], ram[0x20000];\r
+                               fio->Fread(header, MZT_HEADER_SIZE, 1);\r
+                               remain -= MZT_HEADER_SIZE;\r
+                               \r
+                               // load data\r
+                               int size = header[0x12] | (header[0x13] << 8);\r
+                               int offs = header[0x14] | (header[0x15] << 8);\r
+                               memset(ram, 0, sizeof(ram));\r
+                               fio->Fread(ram + offs, size, 1);\r
+                               remain -= size;\r
+#if 0\r
+                               // apply mz700win patch\r
+                               if(header[0x40] == 'P' && header[0x41] == 'A' && header[0x42] == 'T' && header[0x43] == ':') {\r
+                                       int patch_ofs = 0x44;\r
+                                       for(; patch_ofs < 0x80; ) {\r
+                                               uint16 patch_addr = header[patch_ofs] | (header[patch_ofs + 1] << 8);\r
+                                               patch_ofs += 2;\r
+                                               if(patch_addr == 0xffff) {\r
+                                                       break;\r
+                                               }\r
+                                               int patch_len = header[patch_ofs++];\r
+                                               for(int i = 0; i < patch_len; i++) {\r
+                                                       ram[patch_addr + i] = header[patch_ofs++];\r
+                                               }\r
+                                       }\r
+                                       // clear patch data\r
+                                       for(int i = 0x40; i < patch_ofs; i++) {\r
+                                               header[i] = 0;\r
+                                       }\r
+                               }\r
+#endif\r
+                               // copy header\r
+                               buffer[block_num_ptr] = ++num_block;\r
+                               \r
+                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                               buffer[buffer_ptr++] = DATA_MARK;\r
+                               buffer[buffer_ptr++] = HEADER_BLOCK_ID;\r
+                               buffer[buffer_ptr++] = HEADER_SIZE;\r
+                               buffer[buffer_ptr++] = 0;\r
+                               buffer[buffer_ptr++] = header[0];       // attribute\r
+                               for(int i = 0; i < 17; i++) {\r
+                                       buffer[buffer_ptr++] = header[i + 1]; // file name\r
+                               }\r
+                               buffer[buffer_ptr++] = header[0x3e];    // lock\r
+                               buffer[buffer_ptr++] = header[0x3f];    // secret\r
+                               buffer[buffer_ptr++] = header[0x12];    // file size\r
+                               buffer[buffer_ptr++] = header[0x13];\r
+                               buffer[buffer_ptr++] = header[0x14];    // load addr\r
+                               buffer[buffer_ptr++] = header[0x15];\r
+                               buffer[buffer_ptr++] = header[0x16];    // exec addr\r
+                               buffer[buffer_ptr++] = header[0x17];\r
+                               for(int i = 26; i < HEADER_SIZE; i++) {\r
+                                       buffer[buffer_ptr++] = 0;       // comment\r
+                               }\r
+                               buffer[buffer_ptr++] = DATA_CRC;\r
+                               buffer[buffer_ptr++] = DATA_CRC;\r
+                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                               buffer[buffer_ptr++] = DATA_BREAK;\r
+                               \r
+                               // copy data\r
+                               buffer[block_num_ptr] = ++num_block;\r
+                               \r
+                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                               buffer[buffer_ptr++] = DATA_MARK;\r
+                               buffer[buffer_ptr++] = DATA_BLOCK_ID;\r
+                               buffer[buffer_ptr++] = (uint8)(size & 0xff);\r
+                               buffer[buffer_ptr++] = (uint8)(size >> 8);\r
+                               for(int i = 0; i < size; i++) {\r
+                                       buffer[buffer_ptr++] = ram[offs + i];\r
+                               }\r
+                               buffer[buffer_ptr++] = DATA_CRC;\r
+                               buffer[buffer_ptr++] = DATA_CRC;\r
+                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                               buffer[buffer_ptr++] = DATA_BREAK;\r
+                       }\r
+               } else {\r
+                       // check header\r
+                       uint8 header[16];\r
+                       fio->Fread(header, sizeof(header), 1);\r
+                       if(memcmp(header, "-QD format-", 11) != 0) {\r
+                               fio->Fseek(0, FILEIO_SEEK_SET);\r
+                       }\r
+                       \r
+                       // load raw file\r
+                       bool in_gap = true;\r
+                       int sync_top_ptr = 0, sync_num = 0, sync_num_prev = 0, data;\r
+                       \r
+                       buffer[buffer_ptr++] = DATA_BREAK;\r
+                       \r
+                       while((data = fio->Fgetc()) != EOF) {\r
+                               if(data == DATA_SYNC) {\r
+                                       if(sync_num == 0) {\r
+                                               sync_top_ptr = buffer_ptr;\r
+                                       }\r
+                                       sync_num++;\r
+                               } else {\r
+                                       sync_num_prev = sync_num;\r
+                                       sync_num = 0;\r
+                               }\r
+                               if(in_gap) {\r
+                                       if(sync_num_prev >= 4 && sync_num == 0) {\r
+                                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                                               buffer[buffer_ptr++] = data;\r
+                                               in_gap = false;\r
+                                       }\r
+                               } else {\r
+                                       if(sync_num_prev >= 4 && sync_num == 0 && data == 0x00) {\r
+                                               buffer_ptr = sync_top_ptr;\r
+                                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                                               buffer[buffer_ptr++] = DATA_SYNC;\r
+                                               buffer[buffer_ptr++] = DATA_BREAK;\r
+                                               in_gap = true;\r
+                                       } else {\r
+                                               buffer[buffer_ptr++] = data;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               set_insert(true);\r
+               set_protect(fio->IsProtected(path));\r
+               set_home(true);\r
+               \r
+               fio->Fclose();\r
+       }\r
+       delete fio;\r
+}\r
+\r
+void QUICKDISK::close_disk()\r
+{\r
+       release_disk();\r
+       set_insert(false);\r
+       set_protect(false);\r
+       set_home(true);\r
+       \r
+       // cancel all events\r
+       CANCEL_RESTORE_EVENT();\r
+       CANCEL_END_EVENT();\r
+}\r
+\r
+void QUICKDISK::release_disk()\r
+{\r
+       if(insert && !protect && modified) {\r
+               // check extension\r
+               _TCHAR file_path_tmp[_MAX_PATH];\r
+               if(check_file_extension(file_path, _T(".mzt")) || check_file_extension(file_path, _T(".q20"))) {\r
+                       _tcscpy(file_path_tmp, file_path);\r
+               } else {\r
+                       _stprintf(file_path_tmp, _T("%s.mzt"), get_file_path_without_extensiton(file_path));\r
+               }\r
+               // save blocks as mzt file\r
+               FILEIO* fio = new FILEIO();\r
+               if(fio->Fopen(file_path_tmp, FILEIO_WRITE_BINARY)) {\r
+                       int block_num = buffer[4];\r
+                       buffer_ptr = 10;\r
+                       \r
+                       for(int i = 0; i < block_num; i++) {\r
+                               if(buffer[buffer_ptr] == DATA_EMPTY) {\r
+                                       break;\r
+                               }\r
+                               int id = buffer[buffer_ptr + 3] & 3;\r
+                               int size = buffer[buffer_ptr + 4] | (buffer[buffer_ptr + 5] << 8);\r
+                               buffer_ptr += 6;\r
+                               \r
+                               if(id == HEADER_BLOCK_ID) {\r
+                                       // create mzt header\r
+                                       uint8 header[MZT_HEADER_SIZE];\r
+                                       memset(header, 0, sizeof(header));\r
+                                       \r
+                                       header[0x00] = (uint8)buffer[buffer_ptr + 0];   // attribute\r
+                                       for(int i = 1; i <= 17; i++) {\r
+                                               header[i] = (uint8)buffer[buffer_ptr + i];      // file name\r
+                                       }\r
+                                       header[0x3e] = (uint8)buffer[buffer_ptr + 18];  // lock\r
+                                       header[0x3f] = (uint8)buffer[buffer_ptr + 19];  // lock\r
+                                       header[0x12] = (uint8)buffer[buffer_ptr + 20];  // file size\r
+                                       header[0x13] = (uint8)buffer[buffer_ptr + 21];\r
+                                       header[0x14] = (uint8)buffer[buffer_ptr + 22];  // load addr\r
+                                       header[0x15] = (uint8)buffer[buffer_ptr + 23];\r
+                                       header[0x16] = (uint8)buffer[buffer_ptr + 24];  // exec addr\r
+                                       header[0x17] = (uint8)buffer[buffer_ptr + 25];\r
+                                       fio->Fwrite(header, MZT_HEADER_SIZE, 1);\r
+                               } else {\r
+                                       // data\r
+                                       for(int i = 0; i < size; i++) {\r
+                                               fio->Fputc(buffer[buffer_ptr + i]);\r
+                                       }\r
+                               }\r
+                               buffer_ptr += size + 5;\r
+                       }\r
+                       fio->Fclose();\r
+               }\r
+               delete fio;\r
+       }\r
+}\r
+\r
+#define STATE_VERSION  1\r
+\r
+void QUICKDISK::save_state(FILEIO* state_fio)\r
+{\r
+       state_fio->FputUint32(STATE_VERSION);\r
+       state_fio->FputInt32(this_device_id);\r
+       \r
+       state_fio->Fwrite(file_path, sizeof(file_path), 1);\r
+       state_fio->FputBool(insert);\r
+       state_fio->FputBool(protect);\r
+       state_fio->FputBool(home);\r
+       state_fio->FputBool(modified);\r
+       state_fio->FputBool(accessed);\r
+       state_fio->Fwrite(buffer, sizeof(buffer), 1);\r
+       state_fio->FputInt32(buffer_ptr);\r
+       state_fio->FputInt32(write_ptr);\r
+       state_fio->FputBool(first_data);\r
+       state_fio->FputBool(send_break);\r
+       state_fio->FputBool(wrga);\r
+       state_fio->FputBool(mton);\r
+       state_fio->FputBool(sync);\r
+       state_fio->FputBool(motor_on);\r
+       state_fio->FputInt32(restore_id);\r
+       state_fio->FputInt32(end_id);\r
+}\r
+\r
+bool QUICKDISK::load_state(FILEIO* state_fio)\r
+{\r
+       if(state_fio->FgetUint32() != STATE_VERSION) {\r
+               return false;\r
+       }\r
+       if(state_fio->FgetInt32() != this_device_id) {\r
+               return false;\r
+       }\r
+       state_fio->Fread(file_path, sizeof(file_path), 1);\r
+       insert = state_fio->FgetBool();\r
+       protect = state_fio->FgetBool();\r
+       home = state_fio->FgetBool();\r
+       modified = state_fio->FgetBool();\r
+       accessed = state_fio->FgetBool();\r
+       state_fio->Fread(buffer, sizeof(buffer), 1);\r
+       buffer_ptr = state_fio->FgetInt32();\r
+       write_ptr = state_fio->FgetInt32();\r
+       first_data = state_fio->FgetBool();\r
+       send_break = state_fio->FgetBool();\r
+       wrga = state_fio->FgetBool();\r
+       mton = state_fio->FgetBool();\r
+       sync = state_fio->FgetBool();\r
+       motor_on = state_fio->FgetBool();\r
+       restore_id = state_fio->FgetInt32();\r
+       end_id = state_fio->FgetInt32();\r
+       return true;\r
+}\r
+\r