From 25f36dc6cc9fc65a30565e5366e22ee48d512520 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 19:25:41 +0900 Subject: [PATCH 1/9] =?UTF-8?q?disk/upd765a:=20=E3=82=BB=E3=82=AF=E3=82=BF?= =?UTF-8?q?=E5=AF=86=E5=BA=A6=E5=88=A4=E5=AE=9A=E3=82=92=E5=85=B1=E9=80=9A?= =?UTF-8?q?=E5=AE=9F=E8=A3=85=E5=AF=84=E3=81=9B=E3=81=97WRITE=20ID?= =?UTF-8?q?=E3=81=AEMFM=E8=A8=AD=E5=AE=9A=E9=A0=86=E5=BA=8F=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/disk.cpp | 44 +++++++++++++++++++------------- Source/ePC-8801MA/vm/disk.h | 18 +++++++------ Source/ePC-8801MA/vm/upd765a.cpp | 10 ++++---- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index db57803..761b8cc 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -401,6 +401,7 @@ void DISK::close() file_size.d = 0; sector_size.sd = sector_num.sd = 0; sector = NULL; + sector_mfm = drive_mfm; track_mfm = drive_mfm; } @@ -680,7 +681,7 @@ bool DISK::get_sector_info(int trk, int side, int index, uint8* c, uint8* h, uin *n = id[3]; } if(mfm != NULL) { - *mfm = (density == 0x00); + *mfm = sector_mfm; } if(length != NULL) { *length = sector_size.sd; @@ -690,24 +691,30 @@ bool DISK::get_sector_info(int trk, int side, int index, uint8* c, uint8* h, uin void DISK::set_sector_info(uint8 *t) { - // header info - id[0] = t[0]; - id[1] = t[1]; - id[2] = t[2]; - id[3] = t[3]; - uint16 crc = 0; - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]); - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]); - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]); - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]); - id[4] = (crc >> 8) & 0xff; - id[5] = (crc >> 0) & 0xff; + // header info + int am_size = track_mfm ? 3 : 0; + uint16 crc = 0xffff; + for(int i = 0; i < am_size; i++) { + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ 0xa1]); + } + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ 0xfe]); + id[0] = t[0]; + id[1] = t[1]; + id[2] = t[2]; + id[3] = t[3]; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]); + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]); + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]); + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]); + id[4] = (crc >> 8) & 0xff; + id[5] = (crc >> 0) & 0xff; // http://www,gnu-darwin.or.jp/www001/src/ports/emulators/quasi88/work/quasi88-0.6.3/document/FORMAT.TXT // t[6]: 0x00 = double-density, 0x40 = single-density // t[7]: 0x00 = normal, 0x10 = deleted mark // t[8]: 0x00 = valid, 0x10 = valid (deleted data), 0xa0 = id crc error, 0xb0 = data crc error, 0xe0 = address mark missing, 0xf0 = data mark missing - density = t[6]; - deleted = (t[7] != 0); + density = t[6]; + sector_mfm = (density == 0x00); + deleted = (t[7] != 0); if(config.ignore_crc) { crc_error = false; } else { @@ -1648,9 +1655,10 @@ bool DISK::load_state(FILEIO* state_fio) int offset = state_fio->FgetInt32(); sector = (offset != -1) ? buffer + offset : NULL; sector_size.sd = state_fio->FgetInt32(); - state_fio->Fread(id, sizeof(id), 1); - density = state_fio->FgetUint8(); - deleted = state_fio->FgetBool(); + state_fio->Fread(id, sizeof(id), 1); + density = state_fio->FgetUint8(); + sector_mfm = (density == 0x00); + deleted = state_fio->FgetBool(); crc_error = state_fio->FgetBool(); drive_type = state_fio->FgetUint8(); drive_rpm = state_fio->FgetInt32(); diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index 35c2d98..9a22620 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -147,10 +147,11 @@ class DISK public: DISK(EMU* parent_emu) : emu(parent_emu) { - inserted = ejected = write_protected = changed = false; - file_size.d = 0; - sector_size.sd = sector_num.sd = 0; - sector = NULL; + inserted = ejected = write_protected = changed = false; + file_size.d = 0; + sector_size.sd = sector_num.sd = 0; + sector = NULL; + sector_mfm = true; drive_type = DRIVE_TYPE_UNK; drive_rpm = 0; drive_mfm = true; @@ -228,10 +229,11 @@ class DISK // sector uint8* sector; pair sector_size; - uint8 id[6]; - uint8 density; - bool deleted; - bool crc_error; + uint8 id[6]; + uint8 density; + bool sector_mfm; + bool deleted; + bool crc_error; // drive uint8 drive_type; diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 0e08d4c..0c4d968 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1134,7 +1134,7 @@ uint32 UPD765A::read_sector() if(!disk[drv]->get_sector(trk, side, i)) { continue; } - if((command & 0x40) != (disk[drv]->density == 0x00 ? 0x40 : 0)) { + if((command & 0x40) != (disk[drv]->sector_mfm ? 0x40 : 0)) { continue; } cy = disk[drv]->id[0]; @@ -1204,7 +1204,7 @@ uint32 UPD765A::write_sector(bool deleted) if(!disk[drv]->get_sector(trk, side, i)) { continue; } - if((command & 0x40) != (disk[drv]->density == 0x00 ? 0x40 : 0)) { + if((command & 0x40) != (disk[drv]->sector_mfm ? 0x40 : 0)) { continue; } cy = disk[drv]->id[0]; @@ -1249,7 +1249,7 @@ uint32 UPD765A::find_id() if(!disk[drv]->get_sector(trk, side, i)) { continue; } - if((command & 0x40) != (disk[drv]->density == 0x00 ? 0x40 : 0)) { + if((command & 0x40) != (disk[drv]->sector_mfm ? 0x40 : 0)) { continue; } cy = disk[drv]->id[0]; @@ -1431,7 +1431,7 @@ uint32 UPD765A::read_id() if(!disk[drv]->get_sector(trk, side, index)) { continue; } - if((command & 0x40) != (disk[drv]->density == 0x00 ? 0x40 : 0)) { + if((command & 0x40) != (disk[drv]->sector_mfm ? 0x40 : 0)) { continue; } id[0] = disk[drv]->id[0]; @@ -1458,8 +1458,8 @@ uint32 UPD765A::write_id() return ST0_AT | ST1_NW; } - disk[drv]->track_mfm = ((command & 0x40) != 0); disk[drv]->format_track(trk, side); + disk[drv]->track_mfm = ((command & 0x40) != 0); for(int i = 0; i < eot && i < 256; i++) { for(int j = 0; j < 4; j++) { id[j] = buffer[4 * i + j]; From 2c2688fe7b9d6c6f512b1a2ac718837d0212632d Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 19:26:44 +0900 Subject: [PATCH 2/9] =?UTF-8?q?disk:=20MFM=E3=83=88=E3=83=A9=E3=83=83?= =?UTF-8?q?=E3=82=AF=E7=94=9F=E6=88=90=E6=99=82=E3=81=AEID/DATA=20CRC?= =?UTF-8?q?=E8=A8=88=E7=AE=97=E3=82=92common=E4=BA=92=E6=8F=9B=E3=81=AB?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/disk.cpp | 65 +++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index 761b8cc..08e8562 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -571,25 +571,27 @@ bool DISK::make_track(int trk, int side) data_size.read_2bytes_le_from(t + 14); int p = sync_position[i]; - // sync - for(int j = 0; j < sync_size; j++) { - if(p < track_size) track[p++] = 0x00; - } - // am1 - for(int j = 0; j < am_size; j++) { - if(p < track_size) track[p++] = 0xa1; - } - if(p < track_size) track[p++] = 0xfe; - // id - if(p < track_size) track[p++] = t[0]; - if(p < track_size) track[p++] = t[1]; - if(p < track_size) track[p++] = t[2]; - if(p < track_size) track[p++] = t[3]; - uint16 crc = 0; - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]); - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]); - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]); - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]); + // sync + for(int j = 0; j < sync_size; j++) { + if(p < track_size) track[p++] = 0x00; + } + // am1 + uint16 crc = 0xffff; + for(int j = 0; j < am_size; j++) { + if(p < track_size) track[p++] = 0xa1; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ 0xa1]); + } + if(p < track_size) track[p++] = 0xfe; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ 0xfe]); + // id + if(p < track_size) track[p++] = t[0]; + if(p < track_size) track[p++] = t[1]; + if(p < track_size) track[p++] = t[2]; + if(p < track_size) track[p++] = t[3]; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0]]); + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[1]]); + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[2]]); + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]); if(p < track_size) track[p++] = (crc >> 8) & 0xff; if(p < track_size) track[p++] = (crc >> 0) & 0xff; // gap2 @@ -600,17 +602,20 @@ bool DISK::make_track(int trk, int side) for(int j = 0; j < sync_size; j++) { if(p < track_size) track[p++] = 0x00; } - // am2 - for(int j = 0; j < am_size; j++) { - if(p < track_size) track[p++] = 0xa1; - } - if(p < track_size) track[p++] = (t[7] != 0) ? 0xf8 : 0xfb; - // data - crc = 0; - for(int j = 0; j < data_size.sd; j++) { - if(p < track_size) track[p++] = t[0x10 + j]; - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]); - } + // am2 + crc = 0xffff; + for(int j = 0; j < am_size; j++) { + if(p < track_size) track[p++] = 0xa1; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ 0xa1]); + } + uint8 am2 = (t[7] != 0) ? 0xf8 : 0xfb; + if(p < track_size) track[p++] = am2; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ am2]); + // data + for(int j = 0; j < data_size.sd; j++) { + if(p < track_size) track[p++] = t[0x10 + j]; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]); + } if(p < track_size) track[p++] = (crc >> 8) & 0xff; if(p < track_size) track[p++] = (crc >> 0) & 0xff; From b3d86f8ac5f23ac0624491bb0cec5faad7634927 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 21:17:54 +0900 Subject: [PATCH 3/9] =?UTF-8?q?disk/upd765a:=20CRC=E3=82=A8=E3=83=A9?= =?UTF-8?q?=E3=83=BC=E7=A8=AE=E5=88=A5=E3=82=92=E5=88=86=E9=9B=A2=E3=81=97?= =?UTF-8?q?FDC=E7=B5=90=E6=9E=9C=E3=82=B9=E3=83=86=E3=83=BC=E3=82=BF?= =?UTF-8?q?=E3=82=B9=E3=82=92common=E4=BA=92=E6=8F=9B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/disk.cpp | 38 +++++++++++++++++++++----------- Source/ePC-8801MA/vm/disk.h | 5 +++++ Source/ePC-8801MA/vm/upd765a.cpp | 4 ++-- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index 08e8562..ee204ea 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -402,6 +402,9 @@ void DISK::close() sector_size.sd = sector_num.sd = 0; sector = NULL; sector_mfm = drive_mfm; + addr_crc_error = false; + data_crc_error = false; + crc_error = false; track_mfm = drive_mfm; } @@ -720,14 +723,17 @@ void DISK::set_sector_info(uint8 *t) density = t[6]; sector_mfm = (density == 0x00); deleted = (t[7] != 0); - if(config.ignore_crc) { - crc_error = false; - } else { - crc_error = ((t[8] & 0xf0) != 0x00 && (t[8] & 0xf0) != 0x10); - } - sector = t + 0x10; - sector_size.read_2bytes_le_from(t + 14); -} + if(config.ignore_crc) { + addr_crc_error = false; + data_crc_error = false; + } else { + addr_crc_error = ((t[8] & 0xf0) == 0xa0); + data_crc_error = ((t[8] & 0xf0) == 0xb0); + } + crc_error = addr_crc_error || data_crc_error; + sector = t + 0x10; + sector_size.read_2bytes_le_from(t + 14); +} void DISK::set_deleted(bool value) { @@ -743,10 +749,12 @@ void DISK::set_deleted(bool value) void DISK::set_crc_error(bool value) { - if(sector != NULL) { - uint8 *t = sector - 0x10; - t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]); // FIXME: always data crc error ? - } + if(sector != NULL) { + uint8 *t = sector - 0x10; + t[8] = (t[8] & 0x0f) | (value ? 0xb0 : t[7]); + } + addr_crc_error = false; + data_crc_error = value; crc_error = value; } @@ -757,6 +765,8 @@ void DISK::set_data_mark_missing() t[8] = (t[8] & 0x0f) | 0xf0; t[14] = t[15] = 0; } + addr_crc_error = false; + data_crc_error = false; crc_error = false; } @@ -1664,7 +1674,9 @@ bool DISK::load_state(FILEIO* state_fio) density = state_fio->FgetUint8(); sector_mfm = (density == 0x00); deleted = state_fio->FgetBool(); - crc_error = state_fio->FgetBool(); + crc_error = state_fio->FgetBool(); + addr_crc_error = false; + data_crc_error = crc_error; drive_type = state_fio->FgetUint8(); drive_rpm = state_fio->FgetInt32(); drive_mfm = state_fio->FgetBool(); diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index 9a22620..ee917ae 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -152,6 +152,9 @@ class DISK sector_size.sd = sector_num.sd = 0; sector = NULL; sector_mfm = true; + addr_crc_error = false; + data_crc_error = false; + crc_error = false; drive_type = DRIVE_TYPE_UNK; drive_rpm = 0; drive_mfm = true; @@ -233,6 +236,8 @@ class DISK uint8 density; bool sector_mfm; bool deleted; + bool addr_crc_error; + bool data_crc_error; bool crc_error; // drive diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 0c4d968..c79d51e 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1158,8 +1158,8 @@ uint32 UPD765A::read_sector() } fdc[drv].next_trans_position = disk[drv]->data_position[i]; - if(disk[drv]->crc_error && !disk[drv]->ignore_crc()) { - return ST0_AT | ST1_DE | ST2_DD; + if((disk[drv]->addr_crc_error || disk[drv]->data_crc_error) && !disk[drv]->ignore_crc()) { + return ST0_AT | ST1_DE | (disk[drv]->data_crc_error ? ST2_DD : 0); } if(disk[drv]->deleted) { return ST2_CM; From 5cf040d89a8c10e3c9807c1205f6a4dd4a8579b2 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 21:19:42 +0900 Subject: [PATCH 4/9] =?UTF-8?q?disk/upd765a:=20D88=E4=B8=8D=E5=AE=89?= =?UTF-8?q?=E5=AE=9A=E3=82=BB=E3=82=AF=E3=82=BF=E3=81=AE=E8=AA=AD=E3=81=BF?= =?UTF-8?q?=E5=87=BA=E3=81=97=E5=87=A6=E7=90=86=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/disk.cpp | 84 +++++++++++++++++++++++++++++--- Source/ePC-8801MA/vm/disk.h | 20 +++++--- Source/ePC-8801MA/vm/upd765a.cpp | 15 +++--- 3 files changed, 97 insertions(+), 22 deletions(-) diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index ee204ea..c6b3957 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -401,6 +401,7 @@ void DISK::close() file_size.d = 0; sector_size.sd = sector_num.sd = 0; sector = NULL; + unstable = NULL; sector_mfm = drive_mfm; addr_crc_error = false; data_crc_error = false; @@ -629,8 +630,9 @@ bool DISK::make_track(int trk, int side) bool DISK::get_sector(int trk, int side, int index) { - sector_size.sd = sector_num.sd = 0; - sector = NULL; + sector_size.sd = sector_num.sd = 0; + sector = NULL; + unstable = NULL; // disk not inserted or invalid media type if(!(inserted && check_media_type())) { @@ -657,9 +659,10 @@ bool DISK::get_sector(int trk, int side, int index) uint8* t = buffer + offset.d; sector_num.read_2bytes_le_from(t + 4); - if(index >= sector_num.sd) { - return false; - } + if(index >= sector_num.sd) { + return false; + } + unstable = get_unstable_sector(t, index); // skip sector for(int i = 0; i < index; i++) { @@ -671,6 +674,68 @@ bool DISK::get_sector(int trk, int side, int index) return true; } +int DISK::get_track_num(uint8* t) +{ + int position = (int)(t - buffer); + int result = -1; + pair offset; + + offset.read_4bytes_le_from(buffer + 0x1c); + if(position < offset.sd) { + int max_tracks = 164; + for(int track = 0; track < 164; track++) { + offset.read_4bytes_le_from(buffer + 0x20 + track * 4); + if(offset.sd != 0) { + if(offset.sd < 0x2b0) { + max_tracks = min((offset.sd - 0x20) >> 2, 164); + } + break; + } + } + for(int track = 0; track < max_tracks; track++) { + offset.read_4bytes_le_from(buffer + 0x20 + track * 4); + if(offset.sd != 0 && position >= offset.sd) { + if(position == offset.sd) { + result = track; + break; + } else { + result = max(track, result); + } + } + } + } + return result; +} + +uint8* DISK::get_unstable_sector(uint8* t, int index) +{ + int track = get_track_num(t); + if(track < 0) { + return NULL; + } + pair offset, num, idx, data_size; + offset.read_4bytes_le_from(buffer + 0x20 + track * 4); + t = buffer + offset.d; + num.read_2bytes_le_from(t + 4); + + for(int i = 0; i < num.sd; i++) { + data_size.read_2bytes_le_from(t + 14); + t += data_size.sd + 0x10; + } + if(track == get_track_num(t)) { + num.read_2bytes_le_from(t + 4); + for(int i = 0; i < num.sd; i++) { + idx.read_2bytes_le_from(t + 9); + if(idx.sd == index) { + return t + 0x10; + } + data_size.read_2bytes_le_from(t + 14); + t += data_size.sd + 0x10; + } + } + return NULL; +} + bool DISK::get_sector_info(int trk, int side, int index, uint8* c, uint8* h, uint8* r, uint8* n, bool* mfm, int* length) { if(!get_sector(trk, side, index)) { @@ -795,6 +860,8 @@ bool DISK::format_track(int trk, int side) trim_required = true; sector_num.sd = 0; + sector = NULL; + unstable = NULL; track_mfm = drive_mfm; return true; } @@ -1667,9 +1734,10 @@ bool DISK::load_state(FILEIO* state_fio) state_fio->Fread(sync_position, sizeof(sync_position), 1); state_fio->Fread(id_position, sizeof(id_position), 1); state_fio->Fread(data_position, sizeof(data_position), 1); - int offset = state_fio->FgetInt32(); - sector = (offset != -1) ? buffer + offset : NULL; - sector_size.sd = state_fio->FgetInt32(); + int offset = state_fio->FgetInt32(); + sector = (offset != -1) ? buffer + offset : NULL; + unstable = NULL; + sector_size.sd = state_fio->FgetInt32(); state_fio->Fread(id, sizeof(id), 1); density = state_fio->FgetUint8(); sector_mfm = (density == 0x00); diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index ee917ae..130fe55 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -48,8 +48,8 @@ class DISK { protected: EMU* emu; -private: - FILEIO* fi; +private: + FILEIO* fi; uint8 buffer[DISK_BUFFER_SIZE + TRACK_BUFFER_SIZE]; _TCHAR orig_path[_MAX_PATH]; _TCHAR dest_path[_MAX_PATH]; @@ -57,9 +57,11 @@ class DISK pair file_size; int file_bank; uint32 crc32; - bool trim_required; - bool temporary; - uint8 fdi_header[4096]; + bool trim_required; + bool temporary; + uint8 fdi_header[4096]; + int get_track_num(uint8* t); + uint8* get_unstable_sector(uint8* t, int index); void set_sector_info(uint8 *t); void trim_buffer(); @@ -151,6 +153,7 @@ class DISK file_size.d = 0; sector_size.sd = sector_num.sd = 0; sector = NULL; + unstable = NULL; sector_mfm = true; addr_crc_error = false; data_crc_error = false; @@ -229,9 +232,10 @@ class DISK int id_position[256]; int data_position[256]; - // sector - uint8* sector; - pair sector_size; + // sector + uint8* sector; + uint8* unstable; + pair sector_size; uint8 id[6]; uint8 density; bool sector_mfm; diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index c79d51e..152d4a8 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1149,12 +1149,15 @@ uint32 UPD765A::read_sector() continue; } // sector number is matched - if(disk[drv]->invalid_format) { - memset(buffer, disk[drv]->drive_mfm ? 0x4e : 0xff, sizeof(buffer)); - memcpy(buffer, disk[drv]->sector, disk[drv]->sector_size.sd); - } else { - memcpy(buffer, disk[drv]->track + disk[drv]->data_position[i], disk[drv]->get_track_size() - disk[drv]->data_position[i]); - memcpy(buffer + disk[drv]->get_track_size() - disk[drv]->data_position[i], disk[drv]->track, disk[drv]->data_position[i]); + if(disk[drv]->invalid_format) { + for(int j = 0; j < disk[drv]->sector_size.sd; j++) { + uint8 mask = disk[drv]->unstable ? disk[drv]->unstable[j] : 0; + buffer[j] = (disk[drv]->sector[j] & ~mask) | (rand() & mask); + } + memset(buffer + disk[drv]->sector_size.sd, disk[drv]->drive_mfm ? 0x4e : 0xff, sizeof(buffer) - disk[drv]->sector_size.sd); + } else { + memcpy(buffer, disk[drv]->track + disk[drv]->data_position[i], disk[drv]->get_track_size() - disk[drv]->data_position[i]); + memcpy(buffer + disk[drv]->get_track_size() - disk[drv]->data_position[i], disk[drv]->track, disk[drv]->data_position[i]); } fdc[drv].next_trans_position = disk[drv]->data_position[i]; From feef768c8e6992836fb52df8b88a5e45981f892e Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 21:34:37 +0900 Subject: [PATCH 5/9] =?UTF-8?q?disk/upd765a:=20data=E6=AC=A0=E8=90=BD?= =?UTF-8?q?=E3=82=BB=E3=82=AF=E3=82=BF=E3=81=A82D/2DD=E3=83=88=E3=83=A9?= =?UTF-8?q?=E3=83=83=E3=82=AF=E5=A4=89=E6=8F=9B=E3=82=92common=E4=BA=92?= =?UTF-8?q?=E6=8F=9B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/disk.cpp | 237 ++++++++++++++++++++----------- Source/ePC-8801MA/vm/upd765a.cpp | 47 ++++-- 2 files changed, 185 insertions(+), 99 deletions(-) diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index c6b3957..9b0692b 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -409,11 +409,21 @@ void DISK::close() track_mfm = drive_mfm; } -bool DISK::get_track(int trk, int side) -{ - sector_size.sd = sector_num.sd = 0; - invalid_format = false; - no_skew = true; +bool DISK::get_track(int trk, int side) +{ + sector_size.sd = sector_num.sd = 0; + invalid_format = false; + no_skew = true; + if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) { + if(trk >= 0) { + if(trk & 1) { + return false; // unformat track on 2DD side mapping + } + trk >>= 1; + } + } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) { + if(trk >= 0) trk <<= 1; + } // disk not inserted or invalid media type if(!(inserted && check_media_type())) { @@ -488,56 +498,86 @@ bool DISK::get_track(int trk, int side) } } - uint8* t = sector; - int total = sync_size + (am_size + 1); - - for(int i = 0; i < sector_num.sd; i++) { - data_size.read_2bytes_le_from(t + 14); - total += sync_size + (am_size + 1) + (4 + 2) + gap2_size + sync_size + (am_size + 1); - total += data_size.sd + 2; - if(t[2] != i + 1) { - no_skew = false; - } - t += data_size.sd + 0x10; - } - if(gap3_size == 0) { - gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (sector_num.sd + 1); - } - gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * sector_num.sd; - - if(gap3_size < 8 || gap4_size < 8) { - gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + sector_num.sd + 1); - gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * sector_num.sd; - } - if(gap3_size < 8 || gap4_size < 8) { - gap0_size = gap1_size = gap3_size = gap4_size = 32; - invalid_format = true; - } - int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size; - - t = sector; - total = preamble_size; + uint8* t = sector; + int total = 0, valid_sector_num = 0; + + for(int i = 0; i < sector_num.sd; i++) { + data_size.read_2bytes_le_from(t + 14); + sync_position[i] = total; // for invalid format case + total += sync_size + (am_size + 1) + (4 + 2) + gap2_size; + if(data_size.sd > 0) { + total += sync_size + (am_size + 1); + total += data_size.sd + 2; + valid_sector_num++; + } + if(t[2] != i + 1) { + no_skew = false; + } + t += data_size.sd + 0x10; + } + total += sync_size + (am_size + 1); // sync in preamble + if(gap3_size == 0) { + gap3_size = (get_track_size() - total - gap0_size - gap1_size) / (valid_sector_num + 1); + } + gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num; + + if(gap3_size < 8 || gap4_size < 8) { + gap0_size = gap1_size = gap3_size = (get_track_size() - total) / (2 + valid_sector_num + 1); + gap4_size = get_track_size() - total - gap0_size - gap1_size - gap3_size * valid_sector_num; + } + if(gap3_size < 8 || gap4_size < 8) { + gap0_size = gap1_size = gap3_size = gap4_size = 8; + invalid_format = true; + } + int preamble_size = gap0_size + sync_size + (am_size + 1) + gap1_size; + if(invalid_format) { + total -= sync_size + (am_size + 1); + for(int i = 0; i < sector_num.sd; i++) { + sync_position[i] *= get_track_size() - preamble_size - gap4_size; + sync_position[i] /= total; + } + } + + t = sector; + total = preamble_size; sync_position[array_length(sync_position) - 1] = gap0_size; // sync position in preamble - for(int i = 0; i < sector_num.sd; i++) { - data_size.read_2bytes_le_from(t + 14); - if(invalid_format) { - total = preamble_size + (get_track_size() - preamble_size - gap4_size) * i / sector_num.sd; - } - sync_position[i] = total; - total += sync_size + (am_size + 1); - id_position[i] = total; - total += (4 + 2) + gap2_size + sync_size + (am_size + 1); - data_position[i] = total; - total += data_size.sd + 2 + gap3_size; - t += data_size.sd + 0x10; - } + for(int i = 0; i < sector_num.sd; i++) { + data_size.read_2bytes_le_from(t + 14); + if(invalid_format) { + total = preamble_size + sync_position[i]; + } + sync_position[i] = total; + total += sync_size; + total += am_size + 1; + id_position[i] = total; + total += (4 + 2) + gap2_size; + if(data_size.sd > 0) { + total += sync_size + (am_size + 1); + data_position[i] = total; + total += data_size.sd + 2; + total += gap3_size; + } else { + data_position[i] = total; // no data field + } + t += data_size.sd + 0x10; + } return true; } -bool DISK::make_track(int trk, int side) -{ - int track_size = get_track_size(); +bool DISK::make_track(int trk, int side) +{ + if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) { + if(trk >= 0) { + if(trk & 1) { + return false; + } + trk >>= 1; + } + } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) { + if(trk >= 0) trk <<= 1; + } + int track_size = get_track_size(); if(!get_track(trk, side)) { // create a dummy track @@ -598,33 +638,40 @@ bool DISK::make_track(int trk, int side) crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[3]]); if(p < track_size) track[p++] = (crc >> 8) & 0xff; if(p < track_size) track[p++] = (crc >> 0) & 0xff; - // gap2 - for(int j = 0; j < gap2_size; j++) { - if(p < track_size) track[p++] = gap_data; - } - // sync - for(int j = 0; j < sync_size; j++) { - if(p < track_size) track[p++] = 0x00; - } - // am2 - crc = 0xffff; - for(int j = 0; j < am_size; j++) { - if(p < track_size) track[p++] = 0xa1; - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ 0xa1]); + // gap2 + for(int j = 0; j < gap2_size; j++) { + if(p < track_size) track[p++] = gap_data; } - uint8 am2 = (t[7] != 0) ? 0xf8 : 0xfb; - if(p < track_size) track[p++] = am2; - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ am2]); - // data - for(int j = 0; j < data_size.sd; j++) { - if(p < track_size) track[p++] = t[0x10 + j]; - crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]); + // data field (may be absent) + if(data_size.sd > 0) { + // sync + for(int j = 0; j < sync_size; j++) { + if(p < track_size) track[p++] = 0x00; + } + // am2 + crc = 0xffff; + for(int j = 0; j < am_size; j++) { + if(p < track_size) track[p++] = 0xa1; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ 0xa1]); + } + uint8 am2 = (t[7] != 0) ? 0xf8 : 0xfb; + if(p < track_size) track[p++] = am2; + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ am2]); + // data + uint8* u = get_unstable_sector(sector, i); + for(int j = 0; j < data_size.sd; j++) { + if(p < track_size) { + uint8 mask = u ? u[j] : 0; + track[p++] = (t[0x10 + j] & ~mask) | (rand() & mask); + } + crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]); + } + if(p < track_size) track[p++] = (crc >> 8) & 0xff; + if(p < track_size) track[p++] = (crc >> 0) & 0xff; } - if(p < track_size) track[p++] = (crc >> 8) & 0xff; - if(p < track_size) track[p++] = (crc >> 0) & 0xff; - - t += data_size.sd + 0x10; - } + + t += data_size.sd + 0x10; + } return true; } @@ -640,11 +687,21 @@ bool DISK::get_sector(int trk, int side, int index) } // search track - if(trk == -1 && side == -1) { - trk = cur_track; - side = cur_side; - } - int trkside = trk * 2 + (side & 1); + if(trk == -1 && side == -1) { + trk = cur_track; + side = cur_side; + } + if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) { + if(trk >= 0) { + if(trk & 1) { + return false; + } + trk >>= 1; + } + } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) { + if(trk >= 0) trk <<= 1; + } + int trkside = trk * 2 + (side & 1); if(!(0 <= trkside && trkside < 164)) { return false; } @@ -835,11 +892,21 @@ void DISK::set_data_mark_missing() crc_error = false; } -bool DISK::format_track(int trk, int side) -{ - // disk not inserted or invalid media type - if(!(inserted && check_media_type())) { - return false; +bool DISK::format_track(int trk, int side) +{ + if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) { + if(trk >= 0) { + if(trk & 1) { + return false; + } + trk >>= 1; + } + } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) { + if(trk >= 0) trk <<= 1; + } + // disk not inserted or invalid media type + if(!(inserted && check_media_type())) { + return false; } // search track diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 152d4a8..a020c06 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -1090,20 +1090,39 @@ void UPD765A::read_diagnostic() REGISTER_PHASE_EVENT(PHASE_EXEC, 10000); return; } - if(result) { - shift_to_result7(); - return; - } - if(!disk[drv]->make_track(trk, side)) { - result = ST1_ND; - shift_to_result7(); - return; - } - - // read from the 1st sector data - memcpy(buffer, disk[drv]->track + disk[drv]->data_position[0], disk[drv]->get_track_size() - disk[drv]->data_position[0]); - memcpy(buffer + disk[drv]->get_track_size() - disk[drv]->data_position[0], disk[drv]->track, disk[drv]->data_position[0]); - fdc[drv].next_trans_position = disk[drv]->data_position[0]; + if(result) { + shift_to_result7(); + return; + } + if(!disk[drv]->make_track(trk, side)) { + result = ST0_AT | ST1_MA; + shift_to_result7(); + return; + } + bool found = false; + for(int i = 0; i < disk[drv]->sector_num.sd; i++) { + if(!disk[drv]->get_sector(trk, side, i)) { + continue; + } + if((command & 0x40) != (disk[drv]->sector_mfm ? 0x40 : 0)) { + continue; + } + found = true; + if(disk[drv]->id[0] != id[0] || disk[drv]->id[1] != id[1] || disk[drv]->id[2] != id[2] || disk[drv]->id[3] != id[3]) { + result = ST1_ND; + } + break; + } + if(!found) { + result = ST0_AT | ST1_MA; + shift_to_result7(); + return; + } + + // read from the 1st sector data + memcpy(buffer, disk[drv]->track + disk[drv]->data_position[0], disk[drv]->get_track_size() - disk[drv]->data_position[0]); + memcpy(buffer + disk[drv]->get_track_size() - disk[drv]->data_position[0], disk[drv]->track, disk[drv]->data_position[0]); + fdc[drv].next_trans_position = disk[drv]->data_position[0]; shift_to_read(0x80 << min((int)id[3], 7)); return; From b70cc27bc8f42c3a74564b8972d9219903e3f456 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 22:01:06 +0900 Subject: [PATCH 6/9] =?UTF-8?q?upd765a:=20SEEK=E6=99=82=E9=96=93=E3=82=B9?= =?UTF-8?q?=E3=82=B1=E3=83=BC=E3=83=AB=E3=81=A8DEVSTAT=E3=83=88=E3=83=A9?= =?UTF-8?q?=E3=83=83=E3=82=AF=E5=88=A4=E5=AE=9A=E3=82=92common=E4=BA=92?= =?UTF-8?q?=E6=8F=9B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 35 ++++++++++++++------------------ 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index a020c06..97959c9 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -534,16 +534,16 @@ void UPD765A::event_callback(int event_id, int err) int drv = event_id - EVENT_SEEK_STEP; if(cur_track[drv] < fdc[drv].track) { cur_track[drv]++; + if(d_noise_seek != NULL) { + d_noise_seek->play(); + } } else if(cur_track[drv] > fdc[drv].track) { cur_track[drv]--; - } - if(seek_step_remain[drv] > 0) { - seek_step_remain[drv]--; if(d_noise_seek != NULL) { d_noise_seek->play(); } } - if((cur_track[drv] == fdc[drv].track || seek_step_remain[drv] <= 0) && seek_step_id[drv] != -1) { + if(cur_track[drv] == fdc[drv].track && seek_step_id[drv] != -1) { cancel_event(this, seek_step_id[drv]); seek_step_id[drv] = -1; } @@ -553,7 +553,6 @@ void UPD765A::event_callback(int event_id, int err) cancel_event(this, seek_step_id[drv]); seek_step_id[drv] = -1; } - seek_step_remain[drv] = 0; cur_track[drv] = fdc[drv].track; seek_id[drv] = -1; seek_event(drv); @@ -733,9 +732,9 @@ uint8 UPD765A::get_devstat(int drv) return ST3_FT | drv; } return drv | - ((cur_track[drv] & 1) ? ST3_HD : 0) | + ((fdc[drv].track & 1) ? ST3_HD : 0) | ST3_TS | - (cur_track[drv] ? 0 : ST3_T0) | + (fdc[drv].track ? 0 : ST3_T0) | ((force_ready || disk[drv]->inserted) ? ST3_RY : 0) | (disk[drv]->write_protected ? ST3_WP : 0); } @@ -768,26 +767,25 @@ void UPD765A::cmd_recalib() void UPD765A::seek(int drv, int trk) { - // get distance - int distance = abs(trk - cur_track[drv]); - int steptime = 32 - 2 * step_rate_time; + int steptime = (32 - 2 * step_rate_time) * 1000; // msec -> usec if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { steptime /= 2; } - if(steptime <= 0) { - steptime = 1; - } - int seektime = (distance == 0) ? 120 : steptime * distance + 500; // usec if(drv >= MAX_DRIVE) { // invalid drive number fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; set_irq(true); } else { + cur_track[drv] = fdc[drv].track; fdc[drv].track = trk; + int distance = abs(trk - cur_track[drv]); + int seektime = (distance == 0) ? 120 : steptime * distance + 500; // usec #ifdef UPD765A_DONT_WAIT_SEEK - if(distance > 0 && d_noise_seek != NULL) { - d_noise_seek->play(); + if(cur_track[drv] != fdc[drv].track) { + if(d_noise_seek != NULL) { + d_noise_seek->play(); + } } cur_track[drv] = fdc[drv].track; seek_event(drv); @@ -803,14 +801,11 @@ void UPD765A::seek(int drv, int trk) #ifdef SDL if (config.ignore_crc) { seektime = 100; - distance = 0; } #endif // SDL - if(distance > 0) { + if(cur_track[drv] != fdc[drv].track) { seek_step_remain[drv] = distance; register_event(this, EVENT_SEEK_STEP + drv, steptime, true, &seek_step_id[drv]); - } else { - cur_track[drv] = fdc[drv].track; } register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]); seekstat |= 1 << drv; From adef4ff6acfdca258f2d8ebfbd20de0762212f8f Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 22:08:24 +0900 Subject: [PATCH 7/9] =?UTF-8?q?upd765a:=20SEEK=E6=99=82=E9=96=93=E5=A4=89?= =?UTF-8?q?=E6=9B=B4=E3=82=92=E5=AE=89=E5=85=A8=E5=81=B4=E3=81=B8=E6=88=BB?= =?UTF-8?q?=E3=81=97=E3=83=88=E3=83=A9=E3=83=83=E3=82=AF=E5=88=A4=E5=AE=9A?= =?UTF-8?q?=E3=82=92=E5=BE=93=E6=9D=A5=E6=8C=99=E5=8B=95=E3=81=AB=E5=BE=A9?= =?UTF-8?q?=E5=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 97959c9..af5f37a 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -534,16 +534,16 @@ void UPD765A::event_callback(int event_id, int err) int drv = event_id - EVENT_SEEK_STEP; if(cur_track[drv] < fdc[drv].track) { cur_track[drv]++; - if(d_noise_seek != NULL) { - d_noise_seek->play(); - } } else if(cur_track[drv] > fdc[drv].track) { cur_track[drv]--; + } + if(seek_step_remain[drv] > 0) { + seek_step_remain[drv]--; if(d_noise_seek != NULL) { d_noise_seek->play(); } } - if(cur_track[drv] == fdc[drv].track && seek_step_id[drv] != -1) { + if((cur_track[drv] == fdc[drv].track || seek_step_remain[drv] <= 0) && seek_step_id[drv] != -1) { cancel_event(this, seek_step_id[drv]); seek_step_id[drv] = -1; } @@ -553,6 +553,7 @@ void UPD765A::event_callback(int event_id, int err) cancel_event(this, seek_step_id[drv]); seek_step_id[drv] = -1; } + seek_step_remain[drv] = 0; cur_track[drv] = fdc[drv].track; seek_id[drv] = -1; seek_event(drv); @@ -732,9 +733,9 @@ uint8 UPD765A::get_devstat(int drv) return ST3_FT | drv; } return drv | - ((fdc[drv].track & 1) ? ST3_HD : 0) | + ((cur_track[drv] & 1) ? ST3_HD : 0) | ST3_TS | - (fdc[drv].track ? 0 : ST3_T0) | + (cur_track[drv] ? 0 : ST3_T0) | ((force_ready || disk[drv]->inserted) ? ST3_RY : 0) | (disk[drv]->write_protected ? ST3_WP : 0); } @@ -767,25 +768,26 @@ void UPD765A::cmd_recalib() void UPD765A::seek(int drv, int trk) { - int steptime = (32 - 2 * step_rate_time) * 1000; // msec -> usec + int steptime = 32 - 2 * step_rate_time; if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { steptime /= 2; } + if(steptime <= 0) { + steptime = 1; + } if(drv >= MAX_DRIVE) { // invalid drive number fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; set_irq(true); } else { - cur_track[drv] = fdc[drv].track; - fdc[drv].track = trk; + // get distance int distance = abs(trk - cur_track[drv]); int seektime = (distance == 0) ? 120 : steptime * distance + 500; // usec + fdc[drv].track = trk; #ifdef UPD765A_DONT_WAIT_SEEK - if(cur_track[drv] != fdc[drv].track) { - if(d_noise_seek != NULL) { - d_noise_seek->play(); - } + if(distance > 0 && d_noise_seek != NULL) { + d_noise_seek->play(); } cur_track[drv] = fdc[drv].track; seek_event(drv); @@ -803,9 +805,11 @@ void UPD765A::seek(int drv, int trk) seektime = 100; } #endif // SDL - if(cur_track[drv] != fdc[drv].track) { + if(distance > 0) { seek_step_remain[drv] = distance; register_event(this, EVENT_SEEK_STEP + drv, steptime, true, &seek_step_id[drv]); + } else { + cur_track[drv] = fdc[drv].track; } register_event(this, EVENT_SEEK + drv, seektime, false, &seek_id[drv]); seekstat |= 1 << drv; From 531e03668c278b5feb74c762c7979f49f9be2454 Mon Sep 17 00:00:00 2001 From: bubio Date: Fri, 13 Feb 2026 22:10:53 +0900 Subject: [PATCH 8/9] =?UTF-8?q?upd765a:=20Wizardry=E8=AA=BF=E6=9F=BB?= =?UTF-8?q?=E7=94=A8=E3=81=AEFDC=E3=83=88=E3=83=AC=E3=83=BC=E3=82=B9?= =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=82=92=E8=BF=BD=E5=8A=A0=EF=BC=88XM8=5FFDC?= =?UTF-8?q?=5FTRACE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/ePC-8801MA/vm/upd765a.cpp | 173 +++++++++++++++++++++---------- 1 file changed, 120 insertions(+), 53 deletions(-) diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index af5f37a..9fc11ab 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -11,6 +11,9 @@ #include "upd765a.h" #include "disk.h" #include "noise.h" +#include +#include +#include #define EVENT_PHASE 0 #define EVENT_DRQ 1 @@ -69,7 +72,40 @@ #define ST3_WP 0x40 #define ST3_FT 0x80 -#define DRIVE_MASK 3 +#define DRIVE_MASK 3 + +static FILE* g_fdc_trace_file = NULL; +static bool g_fdc_trace_checked = false; +static int g_fdc_trace_lines = 0; + +static bool fdc_trace_enabled() +{ + if(!g_fdc_trace_checked) { + const char* env = getenv("XM8_FDC_TRACE"); + if(env != NULL && env[0] != '\0' && env[0] != '0') { + g_fdc_trace_file = fopen("xm8_fdc_trace.log", "w"); + } + g_fdc_trace_checked = true; + } + return g_fdc_trace_file != NULL; +} + +static void fdc_trace(const char* fmt, ...) +{ + if(!fdc_trace_enabled()) { + return; + } + if(g_fdc_trace_lines > 20000) { + return; + } + va_list ap; + va_start(ap, fmt); + vfprintf(g_fdc_trace_file, fmt, ap); + va_end(ap); + fputc('\n', g_fdc_trace_file); + fflush(g_fdc_trace_file); + g_fdc_trace_lines++; +} #define REGISTER_PHASE_EVENT(phs, usec) { \ if(phase_id != -1) { \ @@ -155,6 +191,7 @@ void UPD765A::initialize() { + fdc_trace("=== FDC trace start ==="); // initialize d88 handler for(int i = 0; i < 4; i++) { disk[i] = new DISK(emu); @@ -218,15 +255,22 @@ void UPD765A::initialize() } } -void UPD765A::release() -{ - for(int i = 0; i < 4; i++) { - if(disk[i]) { - disk[i]->close(); - delete disk[i]; - } - } -} +void UPD765A::release() +{ + for(int i = 0; i < 4; i++) { + if(disk[i]) { + disk[i]->close(); + delete disk[i]; + } + } + if(g_fdc_trace_file != NULL) { + fdc_trace("=== FDC trace end ==="); + fclose(g_fdc_trace_file); + g_fdc_trace_file = NULL; + g_fdc_trace_checked = false; + g_fdc_trace_lines = 0; + } +} void UPD765A::reset() { @@ -646,9 +690,10 @@ void UPD765A::set_hdu(uint8 val) // command // ---------------------------------------------------------------------------- -void UPD765A::process_cmd(int cmd) -{ - switch(cmd & 0x1f) { +void UPD765A::process_cmd(int cmd) +{ + fdc_trace("cmd=%02x phase=%d hdu=%d C=%02x H=%02x R=%02x N=%02x", cmd & 0x1f, phase, hdu & DRIVE_MASK, id[0], id[1], id[2], id[3]); + switch(cmd & 0x1f) { case 0x02: cmd_read_diagnostic(); break; @@ -784,6 +829,7 @@ void UPD765A::seek(int drv, int trk) // get distance int distance = abs(trk - cur_track[drv]); int seektime = (distance == 0) ? 120 : steptime * distance + 500; // usec + fdc_trace("seek: drv=%d from=%d to=%d dist=%d steptime=%d seektime=%d", drv, cur_track[drv], trk, distance, steptime, seektime); fdc[drv].track = trk; #ifdef UPD765A_DONT_WAIT_SEEK if(distance > 0 && d_noise_seek != NULL) { @@ -831,8 +877,9 @@ void UPD765A::seek_event(int drv) fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; #endif } - set_irq(true); - seekstat &= ~(1 << drv); + set_irq(true); + seekstat &= ~(1 << drv); + fdc_trace("seek_end: drv=%d cur=%d target=%d result=%02x", drv, cur_track[drv], fdc[drv].track, fdc[drv].result); // reset dsch flag disk[drv]->changed = false; @@ -1134,19 +1181,21 @@ uint32 UPD765A::read_sector() int side = (hdu >> 2) & 1; // get sector counts in the current track - if(!disk[drv]->make_track(trk, side)) { -#ifdef _FDC_DEBUG_LOG - emu->out_debug_log("FDC: TRACK NOT FOUND (TRK=%d SIDE=%d)\n", trk, side); -#endif - return ST0_AT | ST1_MA; - } + if(!disk[drv]->make_track(trk, side)) { +#ifdef _FDC_DEBUG_LOG + emu->out_debug_log("FDC: TRACK NOT FOUND (TRK=%d SIDE=%d)\n", trk, side); +#endif + fdc_trace("read_sector: track not found drv=%d trk=%d side=%d", drv, trk, side); + return ST0_AT | ST1_MA; + } int secnum = disk[drv]->sector_num.sd; - if(!secnum) { -#ifdef _FDC_DEBUG_LOG - emu->out_debug_log("FDC: NO SECTORS IN TRACK (TRK=%d SIDE=%d)\n", trk, side); -#endif - return ST0_AT | ST1_MA; - } + if(!secnum) { +#ifdef _FDC_DEBUG_LOG + emu->out_debug_log("FDC: NO SECTORS IN TRACK (TRK=%d SIDE=%d)\n", trk, side); +#endif + fdc_trace("read_sector: no sectors drv=%d trk=%d side=%d", drv, trk, side); + return ST0_AT | ST1_MA; + } int cy = -1; for(int i = 0; i < secnum; i++) { if(!disk[drv]->get_sector(trk, side, i)) { @@ -1164,6 +1213,7 @@ uint32 UPD765A::read_sector() continue; } if(disk[drv]->sector_size.sd == 0) { + fdc_trace("read_sector: zero size drv=%d trk=%d side=%d idx=%d", drv, trk, side, i); continue; } // sector number is matched @@ -1180,28 +1230,35 @@ uint32 UPD765A::read_sector() fdc[drv].next_trans_position = disk[drv]->data_position[i]; if((disk[drv]->addr_crc_error || disk[drv]->data_crc_error) && !disk[drv]->ignore_crc()) { + fdc_trace("read_sector: crc err drv=%d trk=%d side=%d idx=%d C=%02x H=%02x R=%02x N=%02x addr=%d data=%d", drv, trk, side, i, disk[drv]->id[0], disk[drv]->id[1], disk[drv]->id[2], disk[drv]->id[3], disk[drv]->addr_crc_error ? 1 : 0, disk[drv]->data_crc_error ? 1 : 0); return ST0_AT | ST1_DE | (disk[drv]->data_crc_error ? ST2_DD : 0); } if(disk[drv]->deleted) { + fdc_trace("read_sector: deleted mark drv=%d trk=%d side=%d idx=%d C=%02x H=%02x R=%02x N=%02x", drv, trk, side, i, disk[drv]->id[0], disk[drv]->id[1], disk[drv]->id[2], disk[drv]->id[3]); return ST2_CM; } - return 0; - } + fdc_trace("read_sector: ok drv=%d trk=%d side=%d idx=%d C=%02x H=%02x R=%02x N=%02x len=%d", drv, trk, side, i, disk[drv]->id[0], disk[drv]->id[1], disk[drv]->id[2], disk[drv]->id[3], disk[drv]->sector_size.sd); + return 0; + } #ifdef _FDC_DEBUG_LOG emu->out_debug_log("FDC: SECTOR NOT FOUND (TRK=%d SIDE=%d ID=%2x,%2x,%2x,%2x)\n", trk, side, id[0], id[1], id[2], id[3]); #endif if(cy == -1) { + fdc_trace("read_sector: no density/id match drv=%d trk=%d side=%d req=%02x,%02x,%02x,%02x", drv, trk, side, id[0], id[1], id[2], id[3]); return ST0_AT | ST1_MA; } if(cy != id[0] && cy != -1) { if(cy == 0xff) { + fdc_trace("read_sector: bad cylinder drv=%d trk=%d side=%d reqC=%02x gotC=%02x", drv, trk, side, id[0], cy); return ST0_AT | ST1_ND | ST2_BC; - } else { - return ST0_AT | ST1_ND | ST2_NC; - } - } - return ST0_AT | ST1_ND; -} + } else { + fdc_trace("read_sector: no cylinder drv=%d trk=%d side=%d reqC=%02x gotC=%02x", drv, trk, side, id[0], cy); + return ST0_AT | ST1_ND | ST2_NC; + } + } + fdc_trace("read_sector: not found drv=%d trk=%d side=%d req=%02x,%02x,%02x,%02x", drv, trk, side, id[0], id[1], id[2], id[3]); + return ST0_AT | ST1_ND; +} uint32 UPD765A::write_sector(bool deleted) { @@ -1212,14 +1269,16 @@ uint32 UPD765A::write_sector(bool deleted) if(disk[drv]->write_protected) { return ST0_AT | ST1_NW; } - // get sector counts in the current track - if(!disk[drv]->get_track(trk, side)) { - return ST0_AT | ST1_MA; - } - int secnum = disk[drv]->sector_num.sd; - if(!secnum) { - return ST0_AT | ST1_MA; - } + // get sector counts in the current track + if(!disk[drv]->get_track(trk, side)) { + fdc_trace("find_id: track not found drv=%d trk=%d side=%d", drv, trk, side); + return ST0_AT | ST1_MA; + } + int secnum = disk[drv]->sector_num.sd; + if(!secnum) { + fdc_trace("find_id: no sectors drv=%d trk=%d side=%d", drv, trk, side); + return ST0_AT | ST1_MA; + } int cy = -1; for(int i = 0; i < secnum; i++) { if(!disk[drv]->get_sector(trk, side, i)) { @@ -1280,22 +1339,27 @@ uint32 UPD765A::find_id() if(disk[drv]->sector_size.sd == 0) { continue; } - // sector number is matched - fdc[drv].next_trans_position = disk[drv]->data_position[i]; - return 0; - } + // sector number is matched + fdc[drv].next_trans_position = disk[drv]->data_position[i]; + fdc_trace("find_id: ok drv=%d trk=%d side=%d idx=%d C=%02x H=%02x R=%02x N=%02x", drv, trk, side, i, disk[drv]->id[0], disk[drv]->id[1], disk[drv]->id[2], disk[drv]->id[3]); + return 0; + } if(cy == -1) { + fdc_trace("find_id: no density/id match drv=%d trk=%d side=%d req=%02x,%02x,%02x,%02x", drv, trk, side, id[0], id[1], id[2], id[3]); return ST0_AT | ST1_MA; } if(cy != id[0] && cy != -1) { if(cy == 0xff) { + fdc_trace("find_id: bad cylinder drv=%d trk=%d side=%d reqC=%02x gotC=%02x", drv, trk, side, id[0], cy); return ST0_AT | ST1_ND | ST2_BC; - } else { - return ST0_AT | ST1_ND | ST2_NC; - } - } - return ST0_AT | ST1_ND; -} + } else { + fdc_trace("find_id: no cylinder drv=%d trk=%d side=%d reqC=%02x gotC=%02x", drv, trk, side, id[0], cy); + return ST0_AT | ST1_ND | ST2_NC; + } + } + fdc_trace("find_id: not found drv=%d trk=%d side=%d req=%02x,%02x,%02x,%02x", drv, trk, side, id[0], id[1], id[2], id[3]); + return ST0_AT | ST1_ND; +} uint32 UPD765A::check_cond(bool write) { @@ -1460,8 +1524,10 @@ uint32 UPD765A::read_id() id[2] = disk[drv]->id[2]; id[3] = disk[drv]->id[3]; fdc[drv].next_trans_position = disk[drv]->id_position[index] + 6; + fdc_trace("read_id: ok drv=%d trk=%d side=%d idx=%d C=%02x H=%02x R=%02x N=%02x", drv, trk, side, index, id[0], id[1], id[2], id[3]); return 0; } + fdc_trace("read_id: not found drv=%d trk=%d side=%d req=%02x,%02x,%02x,%02x", drv, trk, side, id[0], id[1], id[2], id[3]); return ST0_AT | ST1_MA; } @@ -1500,6 +1566,7 @@ void UPD765A::cmd_specify() step_rate_time = buffer[0] >> 4; head_unload_time = buffer[1] >> 1; no_dma_mode = ((buffer[1] & 1) != 0); + fdc_trace("specify: srt=%d hut=%d ndma=%d", step_rate_time, head_unload_time, no_dma_mode ? 1 : 0); shift_to_idle(); status = 0x80;//0xff; break; From ead1603e38a6e1d8d67867d87e481e5d0ed44ba1 Mon Sep 17 00:00:00 2001 From: bubio Date: Sat, 14 Feb 2026 14:29:08 +0900 Subject: [PATCH 9/9] =?UTF-8?q?4MHz=E3=81=A7Wizardry=E8=B5=B7=E5=8B=95?= =?UTF-8?q?=E3=82=92=E5=AE=89=E5=AE=9A=E5=8C=96=EF=BC=88FDC=E3=82=BF?= =?UTF-8?q?=E3=82=A4=E3=83=9F=E3=83=B3=E3=82=B0=E8=AA=BF=E6=95=B4=E3=81=A8?= =?UTF-8?q?=E8=B5=B7=E5=8B=95=E3=83=97=E3=83=AD=E3=83=95=E3=82=A1=E3=82=A4?= =?UTF-8?q?=E3=83=AB=E6=95=B4=E7=90=86=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 47 +++- Source/ePC-8801MA/vm/disk.cpp | 92 +++++-- Source/ePC-8801MA/vm/disk.h | 2 +- Source/ePC-8801MA/vm/event.cpp | 76 +++--- Source/ePC-8801MA/vm/upd765a.cpp | 445 +++++++++++++++++++++++-------- 5 files changed, 476 insertions(+), 186 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e9587de..0ff7549 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,28 +2,55 @@ "version": "0.2.0", "configurations": [ { - "name": "(lldb) Launch macOS", - "type": "cppdbg", + "name": "macOS: 通常起動 (lldb extension)", + "type": "lldb", "request": "launch", "program": "${workspaceFolder}/build/XM8.app/Contents/MacOS/xm8", "args": [], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": true, - "MIMode": "lldb" + "cwd": "${workspaceFolder}" }, { - "name": "(gdb) Launch Linux", + "name": "Linux: 通常起動 (gdb)", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/build/xm8", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", - "environment": [], "externalConsole": false, "MIMode": "gdb" + }, + { + "name": "macOS: Wizardry 安定化 (LOST=15000 + CONST_EXEC=1)", + "type": "lldb", + "request": "launch", + "program": "${workspaceFolder}/build/XM8.app/Contents/MacOS/xm8", + "args": [], + "cwd": "${workspaceFolder}", + "env": { + "XM8_FDC_TRACE_MAX_LINES": "400000", + "XM8_FDC_SEEK_SCALE": "1000", + "XM8_DISABLE_UNSTABLE_MASK": "1", + "XM8_FDC_LOST_USEC": "15000", + "XM8_FDC_CONST_EXEC_USEC": "1", + "XM8_FDC_TRACE_FILE": "xm8_fdc_trace_wiz_stable.log" + } + }, + { + "name": "macOS: FDCトレース基準 (scale=1000, no-unstable)", + "type": "lldb", + "request": "launch", + "program": "${workspaceFolder}/build/XM8.app/Contents/MacOS/xm8", + "args": [], + "cwd": "${workspaceFolder}", + "env": { + "XM8_FDC_TRACE": "1", + "XM8_FDC_TRACE_IO": "1", + "XM8_FDC_TRACE_MAX_LINES": "400000", + "XM8_FDC_SEEK_SCALE": "1000", + "XM8_DISABLE_UNSTABLE_MASK": "1", + "XM8_FDC_TRACE_FILE": "xm8_fdc_trace_s1000_nounstable.log" + } } ] -} \ No newline at end of file +} diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index 9b0692b..6519640 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -7,7 +7,8 @@ [ d88 handler ] */ -#include "disk.h" +#include "disk.h" +#include // crc table static const uint16 crc_table[256] = { @@ -70,7 +71,19 @@ static const int secsize[8] = { 128, 256, 512, 1024, 2048, 4096, 8192, 16384 }; -static uint8 tmp_buffer[DISK_BUFFER_SIZE]; +static uint8 tmp_buffer[DISK_BUFFER_SIZE]; +static bool g_disable_unstable_checked = false; +static bool g_disable_unstable = false; + +static bool disable_unstable_mask() +{ + if(!g_disable_unstable_checked) { + const char* env = getenv("XM8_DISABLE_UNSTABLE_MASK"); + g_disable_unstable = (env != NULL && env[0] != '\0' && env[0] != '0'); + g_disable_unstable_checked = true; + } + return g_disable_unstable; +} typedef struct { int type; @@ -567,20 +580,13 @@ bool DISK::get_track(int trk, int side) bool DISK::make_track(int trk, int side) { - if(media_type == MEDIA_TYPE_2D && drive_type == DRIVE_TYPE_2DD) { - if(trk >= 0) { - if(trk & 1) { - return false; - } - trk >>= 1; - } - } else if(media_type == MEDIA_TYPE_2DD && drive_type == DRIVE_TYPE_2D) { - if(trk >= 0) trk <<= 1; - } + // get_track() already applies 2D/2DD logical<->physical track conversion. + // Converting here as well causes a double-conversion mismatch between + // make_track() generated data positions and get_sector() lookups. int track_size = get_track_size(); - - if(!get_track(trk, side)) { - // create a dummy track + + if(!get_track(trk, side)) { + // create a dummy track for(int i = 0; i < track_size; i++) { track[i] = rand(); } @@ -658,10 +664,10 @@ bool DISK::make_track(int trk, int side) if(p < track_size) track[p++] = am2; crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ am2]); // data - uint8* u = get_unstable_sector(sector, i); + uint8* u = get_unstable_sector(sector, i, t[0], t[1], t[2], t[3], data_size.sd); for(int j = 0; j < data_size.sd; j++) { if(p < track_size) { - uint8 mask = u ? u[j] : 0; + uint8 mask = (u != NULL && !disable_unstable_mask()) ? u[j] : 0; track[p++] = (t[0x10 + j] & ~mask) | (rand() & mask); } crc = (uint16)((crc << 8) ^ crc_table[(uint8)(crc >> 8) ^ t[0x10 + j]]); @@ -719,14 +725,16 @@ bool DISK::get_sector(int trk, int side, int index) if(index >= sector_num.sd) { return false; } - unstable = get_unstable_sector(t, index); - - // skip sector - for(int i = 0; i < index; i++) { - pair data_size; - data_size.read_2bytes_le_from(t + 14); - t += data_size.sd + 0x10; - } + + // skip sector + for(int i = 0; i < index; i++) { + pair data_size; + data_size.read_2bytes_le_from(t + 14); + t += data_size.sd + 0x10; + } + pair target_size; + target_size.read_2bytes_le_from(t + 14); + unstable = get_unstable_sector(buffer + offset.d, index, t[0], t[1], t[2], t[3], target_size.sd); set_sector_info(t); return true; } @@ -764,29 +772,57 @@ int DISK::get_track_num(uint8* t) return result; } -uint8* DISK::get_unstable_sector(uint8* t, int index) +uint8* DISK::get_unstable_sector(uint8* t, int index, uint8 c, uint8 h, uint8 r, uint8 n, int size) { int track = get_track_num(t); if(track < 0) { return NULL; } + uint8* end = buffer + sizeof(buffer); pair offset, num, idx, data_size; offset.read_4bytes_le_from(buffer + 0x20 + track * 4); t = buffer + offset.d; + if(t < buffer || t + 0x10 > end) { + return NULL; + } num.read_2bytes_le_from(t + 4); + if(num.sd <= 0 || num.sd > 256) { + return NULL; + } for(int i = 0; i < num.sd; i++) { + if(t + 0x10 > end) { + return NULL; + } data_size.read_2bytes_le_from(t + 14); + if(data_size.sd < 0 || data_size.sd > 16384 || t + data_size.sd + 0x10 > end) { + return NULL; + } t += data_size.sd + 0x10; } if(track == get_track_num(t)) { + if(t < buffer || t + 0x10 > end) { + return NULL; + } num.read_2bytes_le_from(t + 4); + if(num.sd <= 0 || num.sd > 256) { + return NULL; + } for(int i = 0; i < num.sd; i++) { + if(t + 0x10 > end) { + return NULL; + } idx.read_2bytes_le_from(t + 9); + data_size.read_2bytes_le_from(t + 14); + if(data_size.sd < 0 || data_size.sd > 16384 || t + data_size.sd + 0x10 > end) { + return NULL; + } if(idx.sd == index) { - return t + 0x10; + if(t[0] == c && t[1] == h && t[2] == r && t[3] == n && data_size.sd == size) { + return t + 0x10; + } + return NULL; } - data_size.read_2bytes_le_from(t + 14); t += data_size.sd + 0x10; } } diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index 130fe55..81027ed 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -61,7 +61,7 @@ class DISK bool temporary; uint8 fdi_header[4096]; int get_track_num(uint8* t); - uint8* get_unstable_sector(uint8* t, int index); + uint8* get_unstable_sector(uint8* t, int index, uint8 c, uint8 h, uint8 r, uint8 n, int size); void set_sector_info(uint8 *t); void trim_buffer(); diff --git a/Source/ePC-8801MA/vm/event.cpp b/Source/ePC-8801MA/vm/event.cpp index d4c91ee..b4677d8 100644 --- a/Source/ePC-8801MA/vm/event.cpp +++ b/Source/ePC-8801MA/vm/event.cpp @@ -7,19 +7,19 @@ [ event manager ] */ -#include "event.h" +#include "event.h" #ifdef SDL #include "z80.h" #endif // SDL #define EVENT_MIX 0 -#ifdef SDL -#define SINGLE_EXEC_TIMEOUT 10000 - // exit single exec mode (us) -#endif // SDL - -void EVENT::initialize() +#ifdef SDL +#define SINGLE_EXEC_TIMEOUT 10000 + // exit single exec mode (us) +#endif // SDL + +void EVENT::initialize() { // load config if(!(0 <= config.cpu_power && config.cpu_power <= 4)) { @@ -127,9 +127,9 @@ void EVENT::reset() } #ifdef SDL -void EVENT::request_single_exec() -{ - if (single_exec == false) { +void EVENT::request_single_exec() +{ + if (single_exec == false) { // enter single execution mode single_exec = true; @@ -143,15 +143,15 @@ void EVENT::request_single_exec() } #endif // SDL -void EVENT::drive() -{ -#ifdef SDL - if (single_exec == true) { - // if passed 10ms, disable single_exec - if (passed_usec(single_exec_clock) > SINGLE_EXEC_TIMEOUT) { - single_exec = false; - } - } +void EVENT::drive() +{ +#ifdef SDL + if (single_exec == true) { + // if passed 10ms, disable single_exec + if (passed_usec(single_exec_clock) > SINGLE_EXEC_TIMEOUT) { + single_exec = false; + } + } #endif // SDL // raise pre frame events to update timing settings @@ -246,15 +246,15 @@ void EVENT::drive() main_cpu_exec = min_event_clock; } - if (main_cpu_exec > 0) { - // single execution ? - if (single_exec == true) { - if (main_cpu_exec > 4) { - main_cpu_exec = 4; - } - } - cpu_done = d_cpu[0].device->run(main_cpu_exec); - } + if (main_cpu_exec > 0) { + // single execution ? + if (single_exec == true) { + if (main_cpu_exec > 4) { + main_cpu_exec = 4; + } + } + cpu_done = d_cpu[0].device->run(main_cpu_exec); + } // if registered new event during main cpu execution, recalc min_event_clock if (regist_event_ctrl == true) { @@ -267,11 +267,11 @@ void EVENT::drive() // main 4MHz if (cpu_remain > 0) { sub_cpu_exec = cpu_remain; - if (single_exec == true) { - if (sub_cpu_exec > 4) { - sub_cpu_exec = 4; - } - } + if (single_exec == true) { + if (sub_cpu_exec > 4) { + sub_cpu_exec = 4; + } + } sub_cpu_done = d_cpu[1].device->run(sub_cpu_exec); cpu_remain -= sub_cpu_done; @@ -281,11 +281,11 @@ void EVENT::drive() // main 8MHz if (cpu_remain > 2) { sub_cpu_exec = cpu_remain / 2; - if (single_exec == true) { - if (sub_cpu_exec > 4) { - sub_cpu_exec = 4; - } - } + if (single_exec == true) { + if (sub_cpu_exec > 4) { + sub_cpu_exec = 4; + } + } sub_cpu_done = d_cpu[1].device->run(sub_cpu_exec); cpu_remain -= (sub_cpu_done * 2); diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index 9fc11ab..5bdb6a1 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -77,25 +77,138 @@ static FILE* g_fdc_trace_file = NULL; static bool g_fdc_trace_checked = false; static int g_fdc_trace_lines = 0; +static int g_fdc_trace_max_lines = 200000; +static bool g_fdc_trace_io_checked = false; +static bool g_fdc_trace_io = false; +static bool g_fdc_seek_scale_checked = false; +static int g_fdc_seek_scale = 1000; +static bool g_fdc_disable_unstable_checked = false; +static bool g_fdc_disable_unstable = true; +static bool g_fdc_const_exec_checked = false; +static bool g_fdc_const_exec = true; +static bool g_fdc_request_single_exec_checked = false; +static bool g_fdc_request_single_exec = true; +static bool g_fdc_tc_exec_checked = false; +static bool g_fdc_tc_exec = true; +static bool g_fdc_lost_usec_checked = false; +static int g_fdc_lost_usec = 15000; static bool fdc_trace_enabled() { if(!g_fdc_trace_checked) { const char* env = getenv("XM8_FDC_TRACE"); if(env != NULL && env[0] != '\0' && env[0] != '0') { - g_fdc_trace_file = fopen("xm8_fdc_trace.log", "w"); + const char* trace_path = getenv("XM8_FDC_TRACE_FILE"); + if(trace_path != NULL && trace_path[0] != '\0') { + g_fdc_trace_file = fopen(trace_path, "w"); + } else { + g_fdc_trace_file = fopen("xm8_fdc_trace.log", "w"); + } + } + const char* max_lines = getenv("XM8_FDC_TRACE_MAX_LINES"); + if(max_lines != NULL && max_lines[0] != '\0') { + long v = strtol(max_lines, NULL, 10); + if(v > 0 && v <= 2000000) { + g_fdc_trace_max_lines = (int)v; + } } g_fdc_trace_checked = true; } return g_fdc_trace_file != NULL; } +static bool fdc_trace_io_enabled() +{ + if(!g_fdc_trace_io_checked) { + const char* env = getenv("XM8_FDC_TRACE_IO"); + g_fdc_trace_io = (env != NULL && env[0] != '\0' && env[0] != '0'); + g_fdc_trace_io_checked = true; + } + return g_fdc_trace_io; +} + +static int fdc_seek_scale() +{ + if(!g_fdc_seek_scale_checked) { + const char* env = getenv("XM8_FDC_SEEK_SCALE"); + if(env != NULL && env[0] != '\0') { + long v = strtol(env, NULL, 10); + if(v >= 1 && v <= 10000) { + g_fdc_seek_scale = (int)v; + } + } + g_fdc_seek_scale_checked = true; + } + return g_fdc_seek_scale; +} + +static bool fdc_disable_unstable_mask() +{ + if(!g_fdc_disable_unstable_checked) { + const char* env = getenv("XM8_DISABLE_UNSTABLE_MASK"); + g_fdc_disable_unstable = (env != NULL && env[0] != '\0' && env[0] != '0'); + g_fdc_disable_unstable_checked = true; + } + return g_fdc_disable_unstable; +} + +static bool fdc_const_exec_timing() +{ + if(!g_fdc_const_exec_checked) { + const char* env = getenv("XM8_FDC_CONST_EXEC_USEC"); + g_fdc_const_exec = (env != NULL && env[0] != '\0' && env[0] != '0'); + g_fdc_const_exec_checked = true; + } + return g_fdc_const_exec; +} + +static bool fdc_request_single_exec_enabled() +{ + if(!g_fdc_request_single_exec_checked) { + const char* env = getenv("XM8_FDC_REQUEST_SINGLE_EXEC"); + if(env != NULL && env[0] != '\0') { + g_fdc_request_single_exec = (env[0] != '0'); + } + g_fdc_request_single_exec_checked = true; + } + return g_fdc_request_single_exec; +} + +static bool fdc_tc_exec_enabled() +{ + if(!g_fdc_tc_exec_checked) { + const char* env = getenv("XM8_FDC_TC_EXEC"); + if(env != NULL && env[0] != '\0') { + g_fdc_tc_exec = (env[0] != '0'); + } + g_fdc_tc_exec_checked = true; + } + return g_fdc_tc_exec; +} + +static int fdc_lost_event_usec() +{ + if(!g_fdc_lost_usec_checked) { + const char* env = getenv("XM8_FDC_LOST_USEC"); + if(env != NULL && env[0] != '\0') { + long v = strtol(env, NULL, 10); + if(v >= 1 && v <= 10000000) { + g_fdc_lost_usec = (int)v; + } else if(v <= 0) { + g_fdc_lost_usec = 0; + } + } + g_fdc_lost_usec_checked = true; + } + return g_fdc_lost_usec; +} + static void fdc_trace(const char* fmt, ...) { if(!fdc_trace_enabled()) { return; } - if(g_fdc_trace_lines > 20000) { + if(g_fdc_trace_lines > g_fdc_trace_max_lines) { return; } va_list ap; @@ -106,6 +219,17 @@ static void fdc_trace(const char* fmt, ...) fflush(g_fdc_trace_file); g_fdc_trace_lines++; } + +static uint32 fdc_hash_bytes(const uint8* data, int len) +{ + // FNV-1a 32-bit for lightweight sector content tracing. + uint32 hash = 2166136261u; + for(int i = 0; i < len; i++) { + hash ^= data[i]; + hash *= 16777619u; + } + return hash; +} #define REGISTER_PHASE_EVENT(phs, usec) { \ if(phase_id != -1) { \ @@ -227,6 +351,13 @@ void UPD765A::initialize() phase = prevphase = PHASE_IDLE; status = S_RQM; seekstat = 0; + command = 0; + result = 0; + hdue = 0; + id[0] = id[1] = id[2] = id[3] = 0; + eot = 0; + gpl = 0; + dtl = 0; bufptr = buffer; // temporary phase_id = drq_id = lost_id = result7_id = -1; seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; @@ -269,23 +400,69 @@ void UPD765A::release() g_fdc_trace_file = NULL; g_fdc_trace_checked = false; g_fdc_trace_lines = 0; + g_fdc_trace_max_lines = 200000; + g_fdc_trace_io_checked = false; + g_fdc_trace_io = false; } + g_fdc_disable_unstable_checked = false; + g_fdc_disable_unstable = true; + g_fdc_const_exec_checked = false; + g_fdc_const_exec = true; + g_fdc_request_single_exec_checked = false; + g_fdc_request_single_exec = true; + g_fdc_tc_exec_checked = false; + g_fdc_tc_exec = true; + g_fdc_lost_usec_checked = false; + g_fdc_lost_usec = 15000; } void UPD765A::reset() { shift_to_idle(); -// CANCEL_EVENT(); - phase_id = drq_id = lost_id = result7_id = -1; - seek_id[0] = seek_id[1] = seek_id[2] = seek_id[3] = -1; - seek_step_id[0] = seek_step_id[1] = seek_step_id[2] = seek_step_id[3] = -1; - seek_step_remain[0] = seek_step_remain[1] = seek_step_remain[2] = seek_step_remain[3] = 0; - head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; + if(phase_id != -1) { + cancel_event(this, phase_id); + phase_id = -1; + } + if(drq_id != -1) { + cancel_event(this, drq_id); + drq_id = -1; + } + if(lost_id != -1) { + cancel_event(this, lost_id); + lost_id = -1; + } + if(result7_id != -1) { + cancel_event(this, result7_id); + result7_id = -1; + } + for(int i = 0; i < 4; i++) { + if(seek_id[i] != -1) { + cancel_event(this, seek_id[i]); + } + if(seek_step_id[i] != -1) { + // Loop events are not guaranteed to be canceled by EVENT::reset(). + cancel_event(this, seek_step_id[i]); + } + if(head_unload_id[i] != -1) { + cancel_event(this, head_unload_id[i]); + } + seek_id[i] = -1; + seek_step_id[i] = -1; + seek_step_remain[i] = 0; + head_unload_id[i] = -1; + } head_load[0] = head_load[1] = head_load[2] = head_load[3] = false; cur_track[0] = fdc[0].track; cur_track[1] = fdc[1].track; cur_track[2] = fdc[2].track; cur_track[3] = fdc[3].track; + command = 0; + result = 0; + hdue = hdu; + id[0] = id[1] = id[2] = id[3] = 0; + eot = 0; + gpl = 0; + dtl = 0; set_irq(false); set_drq(false); @@ -404,17 +581,22 @@ uint32 UPD765A::read_io8(uint32 addr) uint8 data; status &= ~S_RQM; - switch(phase) { - case PHASE_RESULT: - data = *bufptr++; -#ifdef _FDC_DEBUG_LOG - emu->out_debug_log("FDC: RESULT=%2x\n", data); -#endif - if(--count) { - status |= S_RQM; - } else { - // EPSON QC-10 CP/M Plus - bool clear_irq = true; + switch(phase) { + case PHASE_RESULT: + { + int idx = (int)(bufptr - buffer); + data = *bufptr++; +#ifdef _FDC_DEBUG_LOG + emu->out_debug_log("FDC: RESULT=%2x\n", data); +#endif + if(fdc_trace_io_enabled()) { + fdc_trace("result_byte: cmd=%02x idx=%d data=%02x", command, idx, data); + } + if(--count) { + status |= S_RQM; + } else { + // EPSON QC-10 CP/M Plus + bool clear_irq = true; if((command & 0x1f) == 0x08) { for(int i = 0; i < 4; i++) { if(fdc[i].result) { @@ -426,11 +608,12 @@ uint32 UPD765A::read_io8(uint32 addr) if(clear_irq) { set_irq(false); } - shift_to_idle(); - } - return data; - - case PHASE_READ: + shift_to_idle(); + } + return data; + } + + case PHASE_READ: data = *bufptr++; #ifdef _FDC_DEBUG_LOG emu->out_debug_log("FDC: READ=%2x\n", data); @@ -488,18 +671,18 @@ void UPD765A::write_signal(int id, uint32 data, uint32 mask) reset(); } reset_signal = next; - } else if(id == SIG_UPD765A_TC) { -#ifdef SDL - // phase==PHASE_EXEC support (for Xanadu Scenario II) - if(phase == PHASE_READ || phase == PHASE_WRITE || phase == PHASE_SCAN || (phase == PHASE_RESULT && count == 7) || (phase == PHASE_EXEC)) { -#else - if(phase == PHASE_READ || phase == PHASE_WRITE || phase == PHASE_SCAN || (phase == PHASE_RESULT && count == 7)) { -#endif // SDL - if(data & mask) { - prevphase = phase; - phase = PHASE_TC; - process_cmd(command & 0x1f); - } + } else if(id == SIG_UPD765A_TC) { +#ifdef SDL + // phase==PHASE_EXEC support (for Xanadu Scenario II) + if(phase == PHASE_READ || phase == PHASE_WRITE || phase == PHASE_SCAN || (phase == PHASE_RESULT && count == 7) || (fdc_tc_exec_enabled() && phase == PHASE_EXEC)) { +#else + if(phase == PHASE_READ || phase == PHASE_WRITE || phase == PHASE_SCAN || (phase == PHASE_RESULT && count == 7)) { +#endif // SDL + if(data & mask) { + prevphase = phase; + phase = PHASE_TC; + process_cmd(command & 0x1f); + } } } else if(id == SIG_UPD765A_MOTOR) { motor_on = ((data & mask) != 0); @@ -539,13 +722,15 @@ uint32 UPD765A::read_signal(int ch) void UPD765A::event_callback(int event_id, int err) { -#ifdef SDL - request_single_exec(); -#endif // SDL - if(event_id == EVENT_PHASE) { - phase_id = -1; - phase = event_phase; - process_cmd(command & 0x1f); +#ifdef SDL + if(fdc_request_single_exec_enabled()) { + request_single_exec(); + } +#endif // SDL + if(event_id == EVENT_PHASE) { + phase_id = -1; + phase = event_phase; + process_cmd(command & 0x1f); } else if(event_id == EVENT_DRQ) { drq_id = -1; status |= S_RQM; @@ -640,21 +825,26 @@ void UPD765A::set_drq(bool val) } drq_id = lost_id = -1; // register data lost event if data exists - if(val) { -#ifdef UPD765A_DMA_MODE + if(val) { +#ifdef UPD765A_DMA_MODE // EPSON QC-10 CP/M Plus dma_data_lost = true; -#else - if((command & 0x1f) != 0x0d) { -#ifdef SDL - // for customized event manager + 2HD disk - register_event(this, EVENT_LOST, 30000, false, &lost_id); -#else - register_event(this, EVENT_LOST, disk[hdu & DRIVE_MASK]->get_usec_per_bytes(1), false, &lost_id); -#endif // SDL - } else { - // FIXME: write id - register_event(this, EVENT_LOST, 30000, false, &lost_id); +#else + if((command & 0x1f) != 0x0d) { +#ifdef SDL + // for customized event manager + 2HD disk + int usec = fdc_lost_event_usec(); + if(usec > 0) { + register_event(this, EVENT_LOST, usec, false, &lost_id); + } else { + register_event(this, EVENT_LOST, disk[hdu & DRIVE_MASK]->get_usec_per_bytes(1), false, &lost_id); + } +#else + register_event(this, EVENT_LOST, disk[hdu & DRIVE_MASK]->get_usec_per_bytes(1), false, &lost_id); +#endif // SDL + } else { + // FIXME: write id + register_event(this, EVENT_LOST, 30000, false, &lost_id); } #endif } @@ -692,7 +882,7 @@ void UPD765A::set_hdu(uint8 val) void UPD765A::process_cmd(int cmd) { - fdc_trace("cmd=%02x phase=%d hdu=%d C=%02x H=%02x R=%02x N=%02x", cmd & 0x1f, phase, hdu & DRIVE_MASK, id[0], id[1], id[2], id[3]); + fdc_trace("cmd=%02x op=%02x phase=%d hdu=%d C=%02x H=%02x R=%02x N=%02x", command, cmd & 0x1f, phase, hdu & DRIVE_MASK, id[0], id[1], id[2], id[3]); switch(cmd & 0x1f) { case 0x02: cmd_read_diagnostic(); @@ -743,44 +933,51 @@ void UPD765A::cmd_sence_devstat() case PHASE_IDLE: shift_to_cmd(1); break; - case PHASE_CMD: - set_hdu(buffer[0]); - buffer[0] = get_devstat(buffer[0] & DRIVE_MASK); - shift_to_result(1); - break; - } -} + case PHASE_CMD: + set_hdu(buffer[0]); + buffer[0] = get_devstat(buffer[0] & DRIVE_MASK); + fdc_trace("sense_devstat: drv=%d st3=%02x cur=%d tgt=%d", buffer[0] & DRIVE_MASK, buffer[0], cur_track[buffer[0] & DRIVE_MASK], fdc[buffer[0] & DRIVE_MASK].track); + shift_to_result(1); + break; + } +} void UPD765A::cmd_sence_intstat() { - for(int i = 0; i < 4; i++) { - if(fdc[i].result) { - buffer[0] = (uint8)fdc[i].result; - buffer[1] = (uint8)fdc[i].track; - fdc[i].result = 0; - shift_to_result(2); - return; - } - } + for(int i = 0; i < 4; i++) { + if(fdc[i].result) { + buffer[0] = (uint8)fdc[i].result; + buffer[1] = (uint8)fdc[i].track; + fdc[i].result = 0; + fdc_trace("sense_intstat: drv=%d st0=%02x pcn=%02x", i, buffer[0], buffer[1]); + shift_to_result(2); + return; + } + } #ifdef UPD765A_SENCE_INTSTAT_RESULT // IBM PC/JX buffer[0] = (uint8)ST0_AI; -#else - buffer[0] = (uint8)ST0_IC; -#endif - shift_to_result(1); -// status &= ~S_CB; -} +#else + buffer[0] = (uint8)ST0_IC; +#endif + fdc_trace("sense_intstat: no_pending st0=%02x", buffer[0]); + shift_to_result(1); +// status &= ~S_CB; +} uint8 UPD765A::get_devstat(int drv) { if(drv >= MAX_DRIVE) { return ST3_FT | drv; } + // Keep ST3 track-side bit based on commanded track like common_source_project. + // Using cur_track here can introduce host-timing dependent behavior while seek + // step events are in flight. + int track_for_st3 = fdc[drv].track; return drv | - ((cur_track[drv] & 1) ? ST3_HD : 0) | + ((track_for_st3 & 1) ? ST3_HD : 0) | ST3_TS | - (cur_track[drv] ? 0 : ST3_T0) | + (track_for_st3 ? 0 : ST3_T0) | ((force_ready || disk[drv]->inserted) ? ST3_RY : 0) | (disk[drv]->write_protected ? ST3_WP : 0); } @@ -820,16 +1017,24 @@ void UPD765A::seek(int drv, int trk) if(steptime <= 0) { steptime = 1; } + int seek_scale = fdc_seek_scale(); + int steptime_usec = steptime * seek_scale; + if(steptime_usec <= 0) { + steptime_usec = 1; + } if(drv >= MAX_DRIVE) { // invalid drive number fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; set_irq(true); } else { - // get distance - int distance = abs(trk - cur_track[drv]); - int seektime = (distance == 0) ? 120 : steptime * distance + 500; // usec - fdc_trace("seek: drv=%d from=%d to=%d dist=%d steptime=%d seektime=%d", drv, cur_track[drv], trk, distance, steptime, seektime); + // Match common_source_project: SEEK timing is based on previous + // commanded track, not current stepped track. + int prev_track = fdc[drv].track; + int distance = abs(trk - prev_track); + int seektime = (distance == 0) ? 120 : steptime_usec * distance + 500; // usec + fdc_trace("seek: drv=%d from=%d to=%d dist=%d steptime=%d steptime_us=%d scale=%d seektime=%d", drv, prev_track, trk, distance, steptime, steptime_usec, seek_scale, seektime); + cur_track[drv] = prev_track; fdc[drv].track = trk; #ifdef UPD765A_DONT_WAIT_SEEK if(distance > 0 && d_noise_seek != NULL) { @@ -853,7 +1058,7 @@ void UPD765A::seek(int drv, int trk) #endif // SDL if(distance > 0) { seek_step_remain[drv] = distance; - register_event(this, EVENT_SEEK_STEP + drv, steptime, true, &seek_step_id[drv]); + register_event(this, EVENT_SEEK_STEP + drv, steptime_usec, true, &seek_step_id[drv]); } else { cur_track[drv] = fdc[drv].track; } @@ -1216,10 +1421,13 @@ uint32 UPD765A::read_sector() fdc_trace("read_sector: zero size drv=%d trk=%d side=%d idx=%d", drv, trk, side, i); continue; } + if(disk[drv]->invalid_format) { + fdc_trace("read_sector: invalid_format drv=%d trk=%d side=%d idx=%d unstable=%d", drv, trk, side, i, (disk[drv]->unstable != NULL) ? 1 : 0); + } // sector number is matched if(disk[drv]->invalid_format) { for(int j = 0; j < disk[drv]->sector_size.sd; j++) { - uint8 mask = disk[drv]->unstable ? disk[drv]->unstable[j] : 0; + uint8 mask = (disk[drv]->unstable != NULL && !fdc_disable_unstable_mask()) ? disk[drv]->unstable[j] : 0; buffer[j] = (disk[drv]->sector[j] & ~mask) | (rand() & mask); } memset(buffer + disk[drv]->sector_size.sd, disk[drv]->drive_mfm ? 0x4e : 0xff, sizeof(buffer) - disk[drv]->sector_size.sd); @@ -1237,7 +1445,16 @@ uint32 UPD765A::read_sector() fdc_trace("read_sector: deleted mark drv=%d trk=%d side=%d idx=%d C=%02x H=%02x R=%02x N=%02x", drv, trk, side, i, disk[drv]->id[0], disk[drv]->id[1], disk[drv]->id[2], disk[drv]->id[3]); return ST2_CM; } - fdc_trace("read_sector: ok drv=%d trk=%d side=%d idx=%d C=%02x H=%02x R=%02x N=%02x len=%d", drv, trk, side, i, disk[drv]->id[0], disk[drv]->id[1], disk[drv]->id[2], disk[drv]->id[3], disk[drv]->sector_size.sd); + int transfer_len = (id[3] != 0) ? (0x80 << min((int)id[3], 7)) : min((int)dtl, 0x80); + transfer_len = min(transfer_len, disk[drv]->sector_size.sd); + uint32 data_hash = fdc_hash_bytes(buffer, transfer_len); + uint8 b0 = (transfer_len > 0) ? buffer[0] : 0; + uint8 b1 = (transfer_len > 1) ? buffer[1] : 0; + uint8 b2 = (transfer_len > 2) ? buffer[2] : 0; + uint8 b3 = (transfer_len > 3) ? buffer[3] : 0; + fdc_trace("read_sector: ok drv=%d trk=%d side=%d idx=%d C=%02x H=%02x R=%02x N=%02x seclen=%d xfer=%d hash=%08x b0=%02x b1=%02x b2=%02x b3=%02x", + drv, trk, side, i, disk[drv]->id[0], disk[drv]->id[1], disk[drv]->id[2], disk[drv]->id[3], + disk[drv]->sector_size.sd, transfer_len, data_hash, b0, b1, b2, b3); return 0; } #ifdef _FDC_DEBUG_LOG @@ -1639,13 +1856,16 @@ void UPD765A::shift_to_scan(int length) set_drq(true); } -void UPD765A::shift_to_result(int length) -{ - phase = PHASE_RESULT; - status = S_RQM | S_CB | S_DIO; - bufptr = buffer; - count = length; -} +void UPD765A::shift_to_result(int length) +{ + phase = PHASE_RESULT; + status = S_RQM | S_CB | S_DIO; + bufptr = buffer; + count = length; + if(fdc_trace_io_enabled()) { + fdc_trace("shift_result: cmd=%02x len=%d status=%02x", command, length, status); + } +} void UPD765A::shift_to_result7() { @@ -1664,17 +1884,18 @@ void UPD765A::shift_to_result7() void UPD765A::shift_to_result7_event() { -#ifdef UPD765A_NO_ST1_EN_OR_FOR_RESULT7 - // for NEC PC-9801 (XANADU) - result &= ~(ST1_EN | ST1_OR); -#endif - buffer[0] = (result & 0xf8) | (hdue & 7); - buffer[1] = uint8(result >> 8); - buffer[2] = uint8(result >> 16); - buffer[3] = id[0]; - buffer[4] = id[1]; - buffer[5] = id[2]; - buffer[6] = id[3]; +#ifdef UPD765A_NO_ST1_EN_OR_FOR_RESULT7 + // for NEC PC-9801 (XANADU) + result &= ~(ST1_EN | ST1_OR); +#endif + buffer[0] = (result & 0xf8) | (hdue & 7); + buffer[1] = uint8(result >> 8); + buffer[2] = uint8(result >> 16); + buffer[3] = id[0]; + buffer[4] = id[1]; + buffer[5] = id[2]; + buffer[6] = id[3]; + fdc_trace("result7: cmd=%02x st0=%02x st1=%02x st2=%02x C=%02x H=%02x R=%02x N=%02x", command, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6]); set_irq(true); shift_to_result(7); } @@ -1720,11 +1941,17 @@ int UPD765A::get_cur_position(int drv) return (fdc[drv].cur_position + disk[drv]->get_bytes_per_usec(passed_usec(fdc[drv].prev_clock))) % disk[drv]->get_track_size(); } -double UPD765A::get_usec_to_exec_phase() -{ - int drv = hdu & DRIVE_MASK; +double UPD765A::get_usec_to_exec_phase() +{ + int drv = hdu & DRIVE_MASK; int trk = fdc[drv].track; int side = (hdu >> 2) & 1; + + // Optional timing stabilization for troublesome titles: + // keep EXEC transition delay deterministic and independent of rotational position. + if(fdc_const_exec_timing()) { + return 100; + } // XXX: this image may have incorrect skew, so use constant period. if(!disk[drv]->correct_timing()) {