2 SHARP MZ-800 Emulator 'EmuZ-800'
3 SHARP MZ-1500 Emulator 'EmuZ-1500'
4 SHARP MZ-2200 Emulator 'EmuZ-2200'
6 Author : Takeda.Toshiya
12 #include "quickdisk.h"
13 #include "../z80sio.h"
15 #define MZT_HEADER_SIZE 128
16 #define HEADER_SIZE 64
18 #define EVENT_RESTORE 0
22 #define PERIOD_RESTORE 100
24 #define PERIOD_END 1000000
26 #define DATA_SYNC 0x16
27 #define DATA_MARK 0xa5
29 #define DATA_BREAK 0x100
30 #define DATA_EMPTY 0x101
32 #define HEADER_BLOCK_ID 0
33 #define DATA_BLOCK_ID 1
35 void QUICKDISK::initialize()
37 insert = protect = false;
39 first_data = send_break = true;
42 void QUICKDISK::release()
47 void QUICKDISK::reset()
53 restore_id = end_id = -1;
66 L: reach to head position
67 H: reset, reach to end of disk, DTRB is L->H
70 L: write disk / stop motor at the end of disk
74 H: stop motor at the end of disk
77 #define REGISTER_RESTORE_EVENT() { \
78 if(restore_id == -1) { \
79 register_event(this, EVENT_RESTORE, PERIOD_RESTORE, false, &restore_id); \
83 #define CANCEL_RESTORE_EVENT() { \
84 if(restore_id != -1) { \
85 cancel_event(this, restore_id); \
90 #define REGISTER_END_EVENT() { \
92 cancel_event(this, end_id); \
94 register_event(this, EVENT_END, PERIOD_END, false, &end_id); \
97 #define CANCEL_END_EVENT() { \
99 cancel_event(this, end_id); \
104 #define WRITE_BUFFER(v) { \
105 if(buffer_ptr < QUICKDISK_BUFFER_SIZE) { \
106 if(buffer[buffer_ptr] != v) { \
107 buffer[buffer_ptr] = v; \
114 void QUICKDISK::write_signal(int id, uint32_t data, uint32_t mask)
116 bool next = ((data & mask) != 0);
118 if(id == QUICKDISK_SIO_RTSA) {
123 } else if(!wrga && next) {
128 } else if(id == QUICKDISK_SIO_DTRB) {
131 if(motor_on && wrga) {
134 REGISTER_END_EVENT();
136 // start motor and restore to home position
138 REGISTER_RESTORE_EVENT();
141 } else if(!mton && next) {
142 // L->H: home signal is high
146 } else if(id == QUICKDISK_SIO_SYNC) {
147 // enter hunt/sync phase
150 // hack: start to send for verify
157 } else if(id == QUICKDISK_SIO_RXDONE) {
160 } else if(id == QUICKDISK_SIO_DATA || id == QUICKDISK_SIO_BREAK) {
162 if(!(motor_on && !wrga)) {
165 if(id == QUICKDISK_SIO_DATA) {
167 // write sync chars at the top of message
168 WRITE_BUFFER(DATA_SYNC);
169 WRITE_BUFFER(DATA_SYNC);
173 write_ptr = buffer_ptr;
174 } else if(id == QUICKDISK_SIO_BREAK) {
176 WRITE_BUFFER(DATA_BREAK);
182 if(buffer_ptr < QUICKDISK_BUFFER_SIZE) {
183 REGISTER_END_EVENT();
191 uint32_t QUICKDISK::read_signal(int ch)
193 // access lamp signal
201 void QUICKDISK::event_callback(int event_id, int err)
203 if(event_id == EVENT_RESTORE) {
204 // reached to home position
207 } else if(event_id == EVENT_END) {
208 // reached to end of disk
214 void QUICKDISK::restore()
216 // reached to home position
219 first_data = send_break = true;
225 void QUICKDISK::send_data()
227 if(!(motor_on && wrga) || restore_id != -1) {
231 if(buffer_ptr < QUICKDISK_BUFFER_SIZE && buffer[buffer_ptr] != DATA_EMPTY) {
232 if(buffer[buffer_ptr] == DATA_BREAK) {
235 d_sio->write_signal(SIG_Z80SIO_BREAK_CH0, 1, 1);
238 // wait until sio enters hunt/sync phase
246 d_sio->write_signal(SIG_Z80SIO_RECV_CH0, buffer[buffer_ptr++], 0xff);
249 REGISTER_END_EVENT();
251 // reached to end of disk
257 void QUICKDISK::write_crc()
259 if(!wrga && write_ptr != 0) {
260 buffer_ptr = write_ptr;
262 WRITE_BUFFER(DATA_CRC);
263 WRITE_BUFFER(DATA_CRC);
264 WRITE_BUFFER(DATA_SYNC);
265 WRITE_BUFFER(DATA_SYNC);
266 // don't increment pointer !!!
267 WRITE_BUFFER(DATA_BREAK);
273 void QUICKDISK::end_of_disk()
278 // reached to end of disk
282 REGISTER_RESTORE_EVENT();
287 void QUICKDISK::set_insert(bool val)
290 d_sio->write_signal(SIG_Z80SIO_DCD_CH0, val ? 0 : 1, 1);
294 void QUICKDISK::set_protect(bool val)
297 d_sio->write_signal(SIG_Z80SIO_CTS_CH0, val ? 1 : 0, 1);
301 void QUICKDISK::set_home(bool val)
304 d_sio->write_signal(SIG_Z80SIO_DCD_CH1, val ? 1 : 0, 1);
309 void QUICKDISK::open_disk(const _TCHAR* path)
311 // check current disk image
313 if(_tcsicmp(file_path, path) == 0) {
316 // close current disk
319 memset(buffer, 0, sizeof(buffer));
322 FILEIO* fio = new FILEIO();
323 if(fio->Fopen(path, FILEIO_READ_BINARY)) {
324 my_tcscpy_s(file_path, _MAX_PATH, path);
327 for(int i = 0; i < QUICKDISK_BUFFER_SIZE; i++) {
328 buffer[i] = DATA_EMPTY;
334 if(check_file_extension(file_path, _T(".mzt")) || check_file_extension(file_path, _T(".q20"))) {
336 fio->Fseek(0, FILEIO_SEEK_END);
337 int remain = fio->Ftell();
338 fio->Fseek(0, FILEIO_SEEK_SET);
341 int block_num_ptr = 0;
344 buffer[buffer_ptr++] = DATA_BREAK;
345 buffer[buffer_ptr++] = DATA_SYNC;
346 buffer[buffer_ptr++] = DATA_SYNC;
347 buffer[buffer_ptr++] = DATA_MARK;
348 block_num_ptr = buffer_ptr;
349 buffer[buffer_ptr++] = 0; // block number
350 buffer[buffer_ptr++] = DATA_CRC;
351 buffer[buffer_ptr++] = DATA_CRC;
352 buffer[buffer_ptr++] = DATA_SYNC;
353 buffer[buffer_ptr++] = DATA_SYNC;
354 buffer[buffer_ptr++] = DATA_BREAK;
356 while(remain >= MZT_HEADER_SIZE) {
358 uint8_t header[MZT_HEADER_SIZE], ram[0x20000];
359 fio->Fread(header, MZT_HEADER_SIZE, 1);
360 remain -= MZT_HEADER_SIZE;
363 int size = header[0x12] | (header[0x13] << 8);
364 int offs = header[0x14] | (header[0x15] << 8);
365 memset(ram, 0, sizeof(ram));
366 fio->Fread(ram + offs, size, 1);
369 // apply mz700win patch
370 if(header[0x40] == 'P' && header[0x41] == 'A' && header[0x42] == 'T' && header[0x43] == ':') {
371 int patch_ofs = 0x44;
372 for(; patch_ofs < 0x80; ) {
373 uint16_t patch_addr = header[patch_ofs] | (header[patch_ofs + 1] << 8);
375 if(patch_addr == 0xffff) {
378 int patch_len = header[patch_ofs++];
379 for(int i = 0; i < patch_len; i++) {
380 ram[patch_addr + i] = header[patch_ofs++];
384 for(int i = 0x40; i < patch_ofs; i++) {
390 buffer[block_num_ptr] = ++num_block;
392 buffer[buffer_ptr++] = DATA_SYNC;
393 buffer[buffer_ptr++] = DATA_SYNC;
394 buffer[buffer_ptr++] = DATA_MARK;
395 buffer[buffer_ptr++] = HEADER_BLOCK_ID;
396 buffer[buffer_ptr++] = HEADER_SIZE;
397 buffer[buffer_ptr++] = 0;
398 buffer[buffer_ptr++] = header[0]; // attribute
399 for(int i = 0; i < 17; i++) {
400 buffer[buffer_ptr++] = header[i + 1]; // file name
402 buffer[buffer_ptr++] = header[0x3e]; // lock
403 buffer[buffer_ptr++] = header[0x3f]; // secret
404 buffer[buffer_ptr++] = header[0x12]; // file size
405 buffer[buffer_ptr++] = header[0x13];
406 buffer[buffer_ptr++] = header[0x14]; // load addr
407 buffer[buffer_ptr++] = header[0x15];
408 buffer[buffer_ptr++] = header[0x16]; // exec addr
409 buffer[buffer_ptr++] = header[0x17];
410 for(int i = 26; i < HEADER_SIZE; i++) {
411 buffer[buffer_ptr++] = 0; // comment
413 buffer[buffer_ptr++] = DATA_CRC;
414 buffer[buffer_ptr++] = DATA_CRC;
415 buffer[buffer_ptr++] = DATA_SYNC;
416 buffer[buffer_ptr++] = DATA_SYNC;
417 buffer[buffer_ptr++] = DATA_BREAK;
420 buffer[block_num_ptr] = ++num_block;
422 buffer[buffer_ptr++] = DATA_SYNC;
423 buffer[buffer_ptr++] = DATA_SYNC;
424 buffer[buffer_ptr++] = DATA_MARK;
425 buffer[buffer_ptr++] = DATA_BLOCK_ID;
426 buffer[buffer_ptr++] = (uint8_t)(size & 0xff);
427 buffer[buffer_ptr++] = (uint8_t)(size >> 8);
428 for(int i = 0; i < size; i++) {
429 buffer[buffer_ptr++] = ram[offs + i];
431 buffer[buffer_ptr++] = DATA_CRC;
432 buffer[buffer_ptr++] = DATA_CRC;
433 buffer[buffer_ptr++] = DATA_SYNC;
434 buffer[buffer_ptr++] = DATA_SYNC;
435 buffer[buffer_ptr++] = DATA_BREAK;
440 fio->Fread(header, sizeof(header), 1);
441 if(memcmp(header, "-QD format-", 11) != 0) {
442 fio->Fseek(0, FILEIO_SEEK_SET);
447 int sync_top_ptr = 0, sync_num = 0, sync_num_prev = 0, data;
449 buffer[buffer_ptr++] = DATA_BREAK;
451 while((data = fio->Fgetc()) != EOF) {
452 if(data == DATA_SYNC) {
454 sync_top_ptr = buffer_ptr;
458 sync_num_prev = sync_num;
462 if(sync_num_prev >= 4 && sync_num == 0) {
463 buffer[buffer_ptr++] = DATA_SYNC;
464 buffer[buffer_ptr++] = DATA_SYNC;
465 buffer[buffer_ptr++] = data;
469 if(sync_num_prev >= 4 && sync_num == 0 && data == 0x00) {
470 buffer_ptr = sync_top_ptr;
471 buffer[buffer_ptr++] = DATA_SYNC;
472 buffer[buffer_ptr++] = DATA_SYNC;
473 buffer[buffer_ptr++] = DATA_BREAK;
476 buffer[buffer_ptr++] = data;
482 set_protect(FILEIO::IsFileProtected(path));
490 void QUICKDISK::close_disk()
498 CANCEL_RESTORE_EVENT();
502 void QUICKDISK::release_disk()
504 if(insert && !protect && modified) {
506 _TCHAR file_path_tmp[_MAX_PATH];
507 if(check_file_extension(file_path, _T(".mzt")) || check_file_extension(file_path, _T(".q20"))) {
508 my_tcscpy_s(file_path_tmp, _MAX_PATH, file_path);
510 my_stprintf_s(file_path_tmp, _MAX_PATH, _T("%s.mzt"), get_file_path_without_extensiton(file_path));
512 // save blocks as mzt file
513 FILEIO* fio = new FILEIO();
514 if(!fio->Fopen(file_path_tmp, FILEIO_WRITE_BINARY)) {
515 fio->Fopen(create_local_path(_T("temporary_saved_quick_disk.mzt")), FILEIO_WRITE_BINARY);
517 if(fio->IsOpened()) {
518 int block_num = buffer[4];
521 for(int i = 0; i < block_num; i++) {
522 if(buffer[buffer_ptr] == DATA_EMPTY) {
525 int id = buffer[buffer_ptr + 3] & 3;
526 int size = buffer[buffer_ptr + 4] | (buffer[buffer_ptr + 5] << 8);
529 if(id == HEADER_BLOCK_ID) {
531 uint8_t header[MZT_HEADER_SIZE];
532 memset(header, 0, sizeof(header));
534 header[0x00] = (uint8_t)buffer[buffer_ptr + 0]; // attribute
535 for(int i = 1; i <= 17; i++) {
536 header[i] = (uint8_t)buffer[buffer_ptr + i]; // file name
538 header[0x3e] = (uint8_t)buffer[buffer_ptr + 18]; // lock
539 header[0x3f] = (uint8_t)buffer[buffer_ptr + 19]; // lock
540 header[0x12] = (uint8_t)buffer[buffer_ptr + 20]; // file size
541 header[0x13] = (uint8_t)buffer[buffer_ptr + 21];
542 header[0x14] = (uint8_t)buffer[buffer_ptr + 22]; // load addr
543 header[0x15] = (uint8_t)buffer[buffer_ptr + 23];
544 header[0x16] = (uint8_t)buffer[buffer_ptr + 24]; // exec addr
545 header[0x17] = (uint8_t)buffer[buffer_ptr + 25];
546 fio->Fwrite(header, MZT_HEADER_SIZE, 1);
549 for(int i = 0; i < size; i++) {
550 fio->Fputc(buffer[buffer_ptr + i]);
553 buffer_ptr += size + 5;
561 #define STATE_VERSION 1
563 bool QUICKDISK::process_state(FILEIO* state_fio, bool loading)
565 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
568 if(!state_fio->StateCheckInt32(this_device_id)) {
571 state_fio->StateBuffer(file_path, sizeof(file_path), 1);
572 state_fio->StateBool(insert);
573 state_fio->StateBool(protect);
574 state_fio->StateBool(home);
575 state_fio->StateBool(modified);
576 state_fio->StateBool(accessed);
577 //state_fio->StateBuffer(buffer, sizeof(buffer), 1);
578 for(int i = 0; i < QUICKDISK_BUFFER_SIZE; i++) {
579 state_fio->StateUint16(buffer[i]);
581 state_fio->StateInt32(buffer_ptr);
582 state_fio->StateInt32(write_ptr);
583 state_fio->StateBool(first_data);
584 state_fio->StateBool(send_break);
585 state_fio->StateBool(wrga);
586 state_fio->StateBool(mton);
587 state_fio->StateBool(sync);
588 state_fio->StateBool(motor_on);
589 state_fio->StateInt32(restore_id);
590 state_fio->StateInt32(end_id);