diff --git a/Source/ePC-8801MA/vm/disk.cpp b/Source/ePC-8801MA/vm/disk.cpp index cee1ba6..db57803 100644 --- a/Source/ePC-8801MA/vm/disk.cpp +++ b/Source/ePC-8801MA/vm/disk.cpp @@ -397,11 +397,12 @@ void DISK::close() } ejected = true; } - inserted = write_protected = false; - file_size.d = 0; - sector_size.sd = sector_num.sd = 0; - sector = NULL; -} + inserted = write_protected = false; + file_size.d = 0; + sector_size.sd = sector_num.sd = 0; + sector = NULL; + track_mfm = drive_mfm; +} bool DISK::get_track(int trk, int side) { @@ -429,36 +430,53 @@ bool DISK::get_track(int trk, int side) return false; } - // track found - sector = buffer + offset.d; - sector_num.read_2bytes_le_from(sector + 4); - pair data_size; - data_size.read_2bytes_le_from(sector + 14); - - // create each sector position in track - int sync_size = drive_mfm ? 12 : 6; - int am_size = drive_mfm ? 3 : 0; - int gap0_size = drive_mfm ? 80 : 40; - int gap1_size = drive_mfm ? 50 : 26; - int gap2_size = drive_mfm ? 22 : 11; - int gap3_size = 0, gap4_size; - - if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) { - if(drive_mfm) { - if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54; - if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84; - if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116; - } else { - if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27; + // track found + sector = buffer + offset.d; + sector_num.read_2bytes_le_from(sector + 4); + pair data_size; + data_size.read_2bytes_le_from(sector + 14); + + // detect actual density from sector headers in this track. + track_mfm = false; + if(sector_num.sd == 0) { + track_mfm = drive_mfm; + } else { + uint8* t = sector; + for(int i = 0; i < sector_num.sd; i++) { + data_size.read_2bytes_le_from(t + 14); + // t[6]: 0x00 = MFM(double-density), 0x40 = FM(single-density) + if(t[6] == 0x00) { + track_mfm = true; + break; + } + t += data_size.sd + 0x10; + } + } + + // create each sector position in track + int sync_size = track_mfm ? 12 : 6; + int am_size = track_mfm ? 3 : 0; + int gap0_size = track_mfm ? 80 : 40; + int gap1_size = track_mfm ? 50 : 26; + int gap2_size = track_mfm ? 22 : 11; + int gap3_size = 0, gap4_size; + + if(media_type == MEDIA_TYPE_144 || media_type == MEDIA_TYPE_2HD) { + if(track_mfm) { + if(data_size.sd == 256 && sector_num.sd == 26) gap3_size = 54; + if(data_size.sd == 512 && sector_num.sd == 15) gap3_size = 84; + if(data_size.sd == 1024 && sector_num.sd == 8) gap3_size = 116; + } else { + if(data_size.sd == 128 && sector_num.sd == 26) gap3_size = 27; if(data_size.sd == 256 && sector_num.sd == 15) gap3_size = 42; if(data_size.sd == 512 && sector_num.sd == 8) gap3_size = 58; } } else { - if(drive_mfm) { - if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51; - if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80; - if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116; - } else { + if(track_mfm) { + if(data_size.sd == 256 && sector_num.sd == 16) gap3_size = 51; + if(data_size.sd == 512 && sector_num.sd == 9) gap3_size = 80; + if(data_size.sd == 1024 && sector_num.sd == 5) gap3_size = 116; + } else { if(data_size.sd == 128 && sector_num.sd == 16) gap3_size = 27; if(data_size.sd == 256 && sector_num.sd == 9) gap3_size = 42; if(data_size.sd == 512 && sector_num.sd == 5) gap3_size = 58; @@ -524,11 +542,11 @@ bool DISK::make_track(int trk, int side) return false; } - // make track image - int sync_size = drive_mfm ? 12 : 6; - int am_size = drive_mfm ? 3 : 0; - int gap2_size = drive_mfm ? 22 : 11; - uint8 gap_data = drive_mfm ? 0x4e : 0xff; + // make track image + int sync_size = track_mfm ? 12 : 6; + int am_size = track_mfm ? 3 : 0; + int gap2_size = track_mfm ? 22 : 11; + uint8 gap_data = track_mfm ? 0x4e : 0xff; // preamble memset(track, gap_data, track_size); @@ -753,10 +771,11 @@ bool DISK::format_track(int trk, int side) offset.d = DISK_BUFFER_SIZE; offset.write_4bytes_le_to(buffer + 0x20 + trkside * 4); - trim_required = true; - sector_num.sd = 0; - return true; -} + trim_required = true; + sector_num.sd = 0; + track_mfm = drive_mfm; + return true; +} void DISK::insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool crc_error, uint8 fill_data, int length) { @@ -776,7 +795,7 @@ void DISK::insert_sector(uint8 c, uint8 h, uint8 r, uint8 n, bool deleted, bool t[3] = n; t[4] = sector_num.b.l; t[5] = sector_num.b.h; - t[6] = drive_mfm ? 0 : 0x40; + t[6] = track_mfm ? 0 : 0x40; t[7] = deleted ? 0x10 : 0; t[8] = crc_error ? 0xb0 : t[7]; // FIXME: always data crc error ? t[14] = (length >> 0) & 0xff; @@ -881,12 +900,12 @@ int DISK::get_max_tracks() int DISK::get_track_size() { - if(inserted) { - return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100; - } else { - return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100; - } -} + if(inserted) { + return media_type == MEDIA_TYPE_144 ? 12500 : media_type == MEDIA_TYPE_2HD ? 10410 : track_mfm ? 6250 : 3100; + } else { + return drive_type == DRIVE_TYPE_144 ? 12500 : drive_type == DRIVE_TYPE_2HD ? 10410 : drive_mfm ? 6250 : 3100; + } +} double DISK::get_usec_per_bytes(int bytes) { @@ -1553,11 +1572,11 @@ bool DISK::standard_to_d88(int type, int ncyl, int nside, int nsec, int size) return true; } -#define STATE_VERSION 4 +#define STATE_VERSION 5 -void DISK::save_state(FILEIO* state_fio) -{ - state_fio->FputUint32(STATE_VERSION); +void DISK::save_state(FILEIO* state_fio) +{ + state_fio->FputUint32(STATE_VERSION); state_fio->Fwrite(buffer, sizeof(buffer), 1); state_fio->Fwrite(orig_path, sizeof(orig_path), 1); @@ -1576,10 +1595,11 @@ void DISK::save_state(FILEIO* state_fio) state_fio->FputInt32(is_special_disk); state_fio->Fwrite(track, sizeof(track), 1); state_fio->FputInt32(sector_num.sd); - state_fio->FputBool(invalid_format); - state_fio->FputBool(no_skew); - state_fio->Fwrite(sync_position, sizeof(sync_position), 1); - state_fio->Fwrite(id_position, sizeof(id_position), 1); + state_fio->FputBool(invalid_format); + state_fio->FputBool(no_skew); + state_fio->FputBool(track_mfm); + state_fio->Fwrite(sync_position, sizeof(sync_position), 1); + state_fio->Fwrite(id_position, sizeof(id_position), 1); state_fio->Fwrite(data_position, sizeof(data_position), 1); state_fio->FputInt32(sector ? (int)(sector - buffer) : -1); state_fio->FputInt32(sector_size.sd); @@ -1594,9 +1614,10 @@ void DISK::save_state(FILEIO* state_fio) bool DISK::load_state(FILEIO* state_fio) { - if(state_fio->FgetUint32() != STATE_VERSION) { - return false; - } + uint32 state_version = state_fio->FgetUint32(); + if(state_version < 4 || state_version > STATE_VERSION) { + return false; + } state_fio->Fread(buffer, sizeof(buffer), 1); state_fio->Fread(orig_path, sizeof(orig_path), 1); state_fio->Fread(dest_path, sizeof(dest_path), 1); @@ -1613,11 +1634,16 @@ bool DISK::load_state(FILEIO* state_fio) is_fdi_image = state_fio->FgetBool(); is_special_disk = state_fio->FgetInt32(); state_fio->Fread(track, sizeof(track), 1); - sector_num.sd = state_fio->FgetInt32(); - invalid_format = state_fio->FgetBool(); - no_skew = state_fio->FgetBool(); - state_fio->Fread(sync_position, sizeof(sync_position), 1); - state_fio->Fread(id_position, sizeof(id_position), 1); + sector_num.sd = state_fio->FgetInt32(); + invalid_format = state_fio->FgetBool(); + no_skew = state_fio->FgetBool(); + if(state_version >= 5) { + track_mfm = state_fio->FgetBool(); + } else { + track_mfm = true; + } + 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; @@ -1626,9 +1652,12 @@ bool DISK::load_state(FILEIO* state_fio) density = state_fio->FgetUint8(); deleted = state_fio->FgetBool(); crc_error = state_fio->FgetBool(); - drive_type = state_fio->FgetUint8(); - drive_rpm = state_fio->FgetInt32(); + drive_type = state_fio->FgetUint8(); + drive_rpm = state_fio->FgetInt32(); drive_mfm = state_fio->FgetBool(); + if(state_version < 5) { + track_mfm = drive_mfm; + } return true; } diff --git a/Source/ePC-8801MA/vm/disk.h b/Source/ePC-8801MA/vm/disk.h index 535a9f7..35c2d98 100644 --- a/Source/ePC-8801MA/vm/disk.h +++ b/Source/ePC-8801MA/vm/disk.h @@ -151,12 +151,13 @@ class DISK file_size.d = 0; sector_size.sd = sector_num.sd = 0; sector = NULL; - drive_type = DRIVE_TYPE_UNK; - drive_rpm = 0; - drive_mfm = true; - static int num = 0; - drive_num = num++; - } + drive_type = DRIVE_TYPE_UNK; + drive_rpm = 0; + drive_mfm = true; + track_mfm = true; + static int num = 0; + drive_num = num++; + } ~DISK() { if(inserted) { @@ -215,12 +216,13 @@ class DISK // track uint8 track[TRACK_BUFFER_SIZE]; pair sector_num; - bool invalid_format; - bool no_skew; - int cur_track, cur_side; - - int sync_position[256]; - int id_position[256]; + bool invalid_format; + bool no_skew; + int cur_track, cur_side; + bool track_mfm; + + int sync_position[256]; + int id_position[256]; int data_position[256]; // sector diff --git a/Source/ePC-8801MA/vm/event.h b/Source/ePC-8801MA/vm/event.h index 0575d5f..80cea41 100644 --- a/Source/ePC-8801MA/vm/event.h +++ b/Source/ePC-8801MA/vm/event.h @@ -14,8 +14,8 @@ #include "../emu.h" #include "device.h" -#define MAX_CPU 8 -#define MAX_SOUND 8 +#define MAX_CPU 8 +#define MAX_SOUND 16 #define MAX_LINES 1024 #define MAX_EVENT 64 #define NO_EVENT -1 @@ -201,10 +201,12 @@ class EVENT : public DEVICE { set_context_cpu(device, CPU_CLOCKS); } - void set_context_sound(DEVICE* device) - { - d_sound[dcount_sound++] = device; - } + void set_context_sound(DEVICE* device) + { + if(dcount_sound < MAX_SOUND) { + d_sound[dcount_sound++] = device; + } + } bool now_skip(); #ifdef SDL void abort_main_cpu() { d_cpu[0].device->write_signal(SIG_CPU_FIRQ, 1, 1); } diff --git a/Source/ePC-8801MA/vm/i8251.cpp b/Source/ePC-8801MA/vm/i8251.cpp index fb6eb7f..cf5e57d 100644 --- a/Source/ePC-8801MA/vm/i8251.cpp +++ b/Source/ePC-8801MA/vm/i8251.cpp @@ -60,10 +60,12 @@ void I8251::reset() #else recv = 0xff; #endif // SDL - // dont reset dsr - status &= DSR; - status |= TXRDY | TXE; - txen = rxen = loopback = false; + // dont reset dsr + status &= DSR; + status |= TXRDY | TXE; + // XM8 v1.10 behavior: transmitter remains enabled after reset. + txen = true; + rxen = loopback = false; recv_buffer->clear(); send_buffer->clear(); diff --git a/Source/ePC-8801MA/vm/i8251.h b/Source/ePC-8801MA/vm/i8251.h index 81e48fa..7b974c3 100644 --- a/Source/ePC-8801MA/vm/i8251.h +++ b/Source/ePC-8801MA/vm/i8251.h @@ -55,6 +55,7 @@ class I8251 : public DEVICE init_output_signals(&outputs_dtr); init_output_signals(&outputs_rst); init_output_signals(&outputs_rts); + set_device_name(_T("8251 SIO")); } ~I8251() {} diff --git a/Source/ePC-8801MA/vm/i8253.h b/Source/ePC-8801MA/vm/i8253.h index cebf57b..5dd0473 100644 --- a/Source/ePC-8801MA/vm/i8253.h +++ b/Source/ePC-8801MA/vm/i8253.h @@ -75,6 +75,7 @@ class I8253 : public DEVICE counter[i].freq = 0; } device_model = INTEL_8253; + set_device_name(_T("8253 PIT")); } ~I8253() {} diff --git a/Source/ePC-8801MA/vm/i8255.h b/Source/ePC-8801MA/vm/i8255.h index c5e4630..4950aa0 100644 --- a/Source/ePC-8801MA/vm/i8255.h +++ b/Source/ePC-8801MA/vm/i8255.h @@ -34,12 +34,13 @@ class I8255 : public DEVICE public: I8255(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu) { - for(int i = 0; i < 3; i++) { - init_output_signals(&port[i].outputs); - port[i].wreg = port[i].rreg = 0;//0xff; - } - clear_ports_by_cmdreg = false; - } + for(int i = 0; i < 3; i++) { + init_output_signals(&port[i].outputs); + port[i].wreg = port[i].rreg = 0;//0xff; + } + clear_ports_by_cmdreg = false; + set_device_name(_T("8255 PIO")); + } ~I8255() {} // common functions diff --git a/Source/ePC-8801MA/vm/upd1990a.cpp b/Source/ePC-8801MA/vm/upd1990a.cpp index 62bfd84..84b2587 100644 --- a/Source/ePC-8801MA/vm/upd1990a.cpp +++ b/Source/ePC-8801MA/vm/upd1990a.cpp @@ -59,9 +59,10 @@ void UPD1990A::write_signal(int id, uint32 data, uint32 mask) #endif } clk = next; - } else if(id == SIG_UPD1990A_STB) { - bool next = ((data & mask) != 0); - if(!stb && next && !clk) { + } else if(id == SIG_UPD1990A_STB) { + bool next = ((data & mask) != 0); + // Accept strobe on rising edge regardless of current CLK level. + if(!stb && next) { #ifdef HAS_UPD4990A if(cmd == 7) { mode = shift_cmd | 0x80; diff --git a/Source/ePC-8801MA/vm/upd1990a.h b/Source/ePC-8801MA/vm/upd1990a.h index 651b36c..1bba2b8 100644 --- a/Source/ePC-8801MA/vm/upd1990a.h +++ b/Source/ePC-8801MA/vm/upd1990a.h @@ -54,10 +54,13 @@ class UPD1990A : public DEVICE hold = false; dout = 0; dout_changed = false; -#ifdef HAS_UPD4990A - shift_cmd = 0; -#endif - } +#ifdef HAS_UPD4990A + shift_cmd = 0; + set_device_name(_T("uPD4990A RTC")); +#else + set_device_name(_T("uPD1990A RTC")); +#endif + } ~UPD1990A() {} // common functions diff --git a/Source/ePC-8801MA/vm/upd765a.cpp b/Source/ePC-8801MA/vm/upd765a.cpp index e972e16..2478815 100644 --- a/Source/ePC-8801MA/vm/upd765a.cpp +++ b/Source/ePC-8801MA/vm/upd765a.cpp @@ -15,9 +15,10 @@ #define EVENT_PHASE 0 #define EVENT_DRQ 1 #define EVENT_LOST 2 -#define EVENT_RESULT7 3 -#define EVENT_INDEX 4 -#define EVENT_SEEK 5 +#define EVENT_RESULT7 3 +#define EVENT_INDEX 4 +#define EVENT_SEEK 5 +#define EVENT_UNLOAD 9 #define PHASE_IDLE 0 #define PHASE_CMD 1 @@ -134,13 +135,17 @@ cancel_event(this, result7_id); \ result7_id = -1; \ } \ - for(int d = 0; d < 4; d++) { \ - if(seek_id[d] != -1) { \ - cancel_event(this, seek_id[d]); \ - seek_id[d] = -1; \ - } \ - } \ -} + for(int d = 0; d < 4; d++) { \ + if(seek_id[d] != -1) { \ + cancel_event(this, seek_id[d]); \ + seek_id[d] = -1; \ + } \ + if(head_unload_id[d] != -1) { \ + cancel_event(this, head_unload_id[d]); \ + head_unload_id[d] = -1; \ + } \ + } \ +} void UPD765A::initialize() { @@ -172,15 +177,18 @@ void UPD765A::initialize() // initialize fdc memset(fdc, 0, sizeof(fdc)); + memset(head_load, 0, sizeof(head_load)); memset(buffer, 0, sizeof(buffer)); phase = prevphase = PHASE_IDLE; status = S_RQM; seekstat = 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; - no_dma_mode = false; + 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; + head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; + head_unload_time = 0; + no_dma_mode = false; motor_on = false; // motor off force_ready = false; reset_signal = true; @@ -211,16 +219,18 @@ void UPD765A::release() } } -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; - - set_irq(false); - set_drq(false); -} +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; + head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; + head_load[0] = head_load[1] = head_load[2] = head_load[3] = false; + + set_irq(false); + set_drq(false); +} void UPD765A::write_io8(uint32 addr, uint32 data) { @@ -493,20 +503,31 @@ void UPD765A::event_callback(int event_id, int err) result = ST1_OR; set_drq(false); shift_to_result7(); - } else if(event_id == EVENT_RESULT7) { - result7_id = -1; - shift_to_result7_event(); - } else if(event_id == EVENT_INDEX) { - int drv = hdu & DRIVE_MASK; - bool now_index = (disk[drv]->inserted && get_cur_position(drv) == 0); - if(prev_index != now_index) { - write_signals(&outputs_index, now_index ? 0xffffffff : 0); - prev_index = now_index; - } - } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) { - int drv = event_id - EVENT_SEEK; - seek_id[drv] = -1; - seek_event(drv); + } else if(event_id == EVENT_RESULT7) { + result7_id = -1; + shift_to_result7_event(); + } else if(event_id == EVENT_INDEX) { + int drv = hdu & DRIVE_MASK; + // index hole signal width is approximately 5ms. + bool now_index = (disk[drv]->inserted && + get_cur_position(drv) < disk[drv]->get_bytes_per_usec(5000)); + if(prev_index != now_index) { + write_signals(&outputs_index, now_index ? 0xffffffff : 0); + prev_index = now_index; + } + } else if(event_id >= EVENT_SEEK && event_id < EVENT_SEEK + 4) { + int drv = event_id - EVENT_SEEK; + seek_id[drv] = -1; + seek_event(drv); + } else if(event_id >= EVENT_UNLOAD && event_id < EVENT_UNLOAD + 4) { + int drv = event_id - EVENT_UNLOAD; + if(head_load[drv]) { + if(d_noise_head_up != NULL) { + d_noise_head_up->play(); + } + head_load[drv] = false; + } + head_unload_id[drv] = -1; } } @@ -745,13 +766,11 @@ void UPD765A::seek(int drv, int trk) } } -void UPD765A::seek_event(int drv) -{ - int trk = fdc[drv].track; - - if(drv >= MAX_DRIVE) { - fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; - } else if(force_ready || disk[drv]->inserted) { +void UPD765A::seek_event(int drv) +{ + if(drv >= MAX_DRIVE) { + fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE | ST0_NR | ST0_AT; + } else if(force_ready || disk[drv]->inserted) { fdc[drv].result = (drv & DRIVE_MASK) | ST0_SE; } else { #ifdef UPD765A_NO_ST0_AT_FOR_SEEK @@ -768,16 +787,17 @@ void UPD765A::seek_event(int drv) disk[drv]->changed = false; } -void UPD765A::cmd_read_data() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(8); - break; - case PHASE_CMD: - get_sector_params(); - REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); - break; +void UPD765A::cmd_read_data() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(8); + break; + case PHASE_CMD: + get_sector_params(); + start_transfer(); + REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); + break; case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { @@ -787,11 +807,11 @@ void UPD765A::cmd_read_data() #endif // SDL read_data((command & 0x1f) == 12, false); break; - case PHASE_READ: - if(result) { - shift_to_result7(); - break; - } + case PHASE_READ: + if(result) { + shift_to_result7(); + break; + } if(!id_incr()) { REGISTER_PHASE_EVENT(PHASE_TIMER, 2000); break; @@ -802,24 +822,25 @@ void UPD765A::cmd_read_data() CANCEL_EVENT(); shift_to_result7(); break; - case PHASE_TIMER: -// result = ST0_AT | ST1_EN; - result = ST1_EN; - shift_to_result7(); - break; - } -} + case PHASE_TIMER: +// result = ST0_AT | ST1_EN; + result = ST1_EN; + shift_to_result7(); + break; + } +} -void UPD765A::cmd_write_data() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(8); - break; - case PHASE_CMD: - get_sector_params(); - REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); - break; +void UPD765A::cmd_write_data() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(8); + break; + case PHASE_CMD: + get_sector_params(); + start_transfer(); + REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); + break; case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { @@ -838,11 +859,11 @@ void UPD765A::cmd_write_data() if(result) { shift_to_result7(); } else { - int length = 0x80 << (id[3] & 7); - if(!(id[3] & 7)) { - length = __min(dtl, 0x80); - memset(buffer + length, 0, 0x80 - length); - } + int length = 0x80 << min((int)id[3], 7); + if(id[3] == 0) { + length = __min(dtl, 0x80); + memset(buffer + length, 0, 0x80 - length); + } shift_to_write(length); } break; @@ -876,17 +897,18 @@ void UPD765A::cmd_write_data() } } -void UPD765A::cmd_scan() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(9); - break; - case PHASE_CMD: - get_sector_params(); - dtl = dtl | 0x100; - REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); - break; +void UPD765A::cmd_scan() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(9); + break; + case PHASE_CMD: + get_sector_params(); + dtl = dtl | 0x100; + start_transfer(); + REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); + break; case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { @@ -920,16 +942,17 @@ void UPD765A::cmd_scan() } } -void UPD765A::cmd_read_diagnostic() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(8); - break; - case PHASE_CMD: - get_sector_params(); - REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); - break; +void UPD765A::cmd_read_diagnostic() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(8); + break; + case PHASE_CMD: + get_sector_params(); + start_transfer(); + REGISTER_PHASE_EVENT_NEW(PHASE_EXEC, get_usec_to_exec_phase()); + break; case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { @@ -939,11 +962,11 @@ void UPD765A::cmd_read_diagnostic() #endif // SDL read_diagnostic(); break; - case PHASE_READ: - if(result) { - shift_to_result7(); - break; - } + case PHASE_READ: + if(result & ~ST1_ND) { + shift_to_result7(); + break; + } if(!id_incr()) { REGISTER_PHASE_EVENT(PHASE_TIMER, 2000); break; @@ -954,13 +977,13 @@ void UPD765A::cmd_read_diagnostic() CANCEL_EVENT(); shift_to_result7(); break; - case PHASE_TIMER: -// result = ST0_AT | ST1_EN; - result = ST1_EN; - shift_to_result7(); - break; - } -} + case PHASE_TIMER: +// result = ST0_AT | ST1_EN; + result |= ST1_EN; + shift_to_result7(); + break; + } +} void UPD765A::read_data(bool deleted, bool scan) { @@ -985,7 +1008,7 @@ void UPD765A::read_data(bool deleted, bool scan) REGISTER_PHASE_EVENT(PHASE_TIMER, 100000); return; } - int length = (id[3] & 7) ? (0x80 << (id[3] & 7)) : (__min(dtl, 0x80)); + int length = (id[3] != 0) ? (0x80 << min((int)id[3], 7)) : (__min(dtl, 0x80)); if(!scan) { shift_to_read(length); } else { @@ -1030,7 +1053,7 @@ void UPD765A::read_diagnostic() 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 << (id[3] & 7)); + shift_to_read(0x80 << min((int)id[3], 7)); return; } @@ -1250,16 +1273,17 @@ bool UPD765A::id_incr() return false; } -void UPD765A::cmd_read_id() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(1); - break; - case PHASE_CMD: - set_hdu(buffer[0]); -// break; - case PHASE_EXEC: +void UPD765A::cmd_read_id() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(1); + break; + case PHASE_CMD: + set_hdu(buffer[0]); + start_transfer(); +// break; + case PHASE_EXEC: #ifdef SDL if (force_ready && !disk[hdu & DRIVE_MASK]->inserted) { REGISTER_PHASE_EVENT(PHASE_EXEC, 1000000); @@ -1287,11 +1311,11 @@ void UPD765A::cmd_read_id() } } -void UPD765A::cmd_write_id() -{ - switch(phase) { - case PHASE_IDLE: - shift_to_cmd(5); +void UPD765A::cmd_write_id() +{ + switch(phase) { + case PHASE_IDLE: + shift_to_cmd(5); break; case PHASE_CMD: set_hdu(buffer[0]); @@ -1299,13 +1323,14 @@ void UPD765A::cmd_write_id() eot = buffer[2]; gpl = buffer[3]; dtl = buffer[4]; // temporary - if(!eot) { - REGISTER_PHASE_EVENT(PHASE_TIMER, 1000000); - break; - } - fdc[hdu & DRIVE_MASK].next_trans_position = get_cur_position(hdu & DRIVE_MASK); - shift_to_write(4 * eot); - break; + if(!eot) { + REGISTER_PHASE_EVENT(PHASE_TIMER, 1000000); + break; + } + start_transfer(); + fdc[hdu & DRIVE_MASK].next_trans_position = get_cur_position(hdu & DRIVE_MASK); + shift_to_write(4 * eot); + break; case PHASE_TC: case PHASE_WRITE: REGISTER_PHASE_EVENT(PHASE_TIMER, 4000000); @@ -1377,14 +1402,15 @@ uint32 UPD765A::write_id() if((result = check_cond(true)) != 0) { return result; } - if(disk[drv]->write_protected) { - return ST0_AT | ST1_NW; - } - - disk[drv]->format_track(trk, side); - for(int i = 0; i < eot && i < 256; i++) { - for(int j = 0; j < 4; j++) { - id[j] = buffer[4 * i + j]; + if(disk[drv]->write_protected) { + return ST0_AT | ST1_NW; + } + + disk[drv]->track_mfm = ((command & 0x40) != 0); + disk[drv]->format_track(trk, side); + for(int i = 0; i < eot && i < 256; i++) { + for(int j = 0; j < 4; j++) { + id[j] = buffer[4 * i + j]; } disk[drv]->insert_sector(id[0], id[1], id[2], id[3], false, false, dtl, length); } @@ -1397,12 +1423,13 @@ void UPD765A::cmd_specify() case PHASE_IDLE: shift_to_cmd(2); break; - case PHASE_CMD: - step_rate_time = buffer[0] >> 4; - no_dma_mode = ((buffer[1] & 1) != 0); - shift_to_idle(); - status = 0x80;//0xff; - break; + case PHASE_CMD: + step_rate_time = buffer[0] >> 4; + head_unload_time = buffer[1] >> 1; + no_dma_mode = ((buffer[1] & 1) != 0); + shift_to_idle(); + status = 0x80;//0xff; + break; } } @@ -1480,22 +1507,23 @@ void UPD765A::shift_to_result(int length) count = length; } -void UPD765A::shift_to_result7() -{ -#ifdef UPD765A_WAIT_RESULT7 +void UPD765A::shift_to_result7() +{ +#ifdef UPD765A_WAIT_RESULT7 if(result7_id != -1) { cancel_event(this, result7_id); result7_id = -1; } - if(phase != PHASE_TIMER) { - register_event(this, EVENT_RESULT7, 100, false, &result7_id); - } else -#endif - shift_to_result7_event(); -} + if(phase != PHASE_TIMER) { + register_event(this, EVENT_RESULT7, 100, false, &result7_id); + } else +#endif + shift_to_result7_event(); + finish_transfer(); +} -void UPD765A::shift_to_result7_event() -{ +void UPD765A::shift_to_result7_event() +{ #ifdef UPD765A_NO_ST1_EN_OR_FOR_RESULT7 // for NEC PC-9801 (XANADU) result &= ~(ST1_EN | ST1_OR); @@ -1507,18 +1535,50 @@ void UPD765A::shift_to_result7_event() buffer[4] = id[1]; buffer[5] = id[2]; buffer[6] = id[3]; - set_irq(true); - shift_to_result(7); -} + set_irq(true); + shift_to_result(7); +} + +void UPD765A::start_transfer() +{ + int drv = hdu & DRIVE_MASK; + + if(head_unload_id[drv] != -1) { + cancel_event(this, head_unload_id[drv]); + head_unload_id[drv] = -1; + } + if(!head_load[drv]) { + if(d_noise_head_down != NULL) { + d_noise_head_down->play(); + } + head_load[drv] = true; + } +} + +void UPD765A::finish_transfer() +{ + int drv = hdu & DRIVE_MASK; + + if(head_load[drv]) { + if(head_unload_id[drv] != -1) { + cancel_event(this, head_unload_id[drv]); + } + int time = (16 * (head_unload_time + 1)) * 1000; // msec -> usec + if(disk[drv]->drive_type == DRIVE_TYPE_2HD) { + time /= 2; + } + register_event(this, EVENT_UNLOAD + drv, time, false, &head_unload_id[drv]); + } +} // ---------------------------------------------------------------------------- // timing // ---------------------------------------------------------------------------- -int UPD765A::get_cur_position(int drv) -{ - return (int)(fdc[drv].cur_position + passed_usec(fdc[drv].prev_clock) / disk[drv]->get_usec_per_bytes(1)) % disk[drv]->get_track_size(); -} +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() { @@ -1580,11 +1640,11 @@ void UPD765A::open_disk(int drv, const _TCHAR* path, int bank) #ifdef _FDC_DEBUG_LOG emu->out_debug_log("FDC: Disk Changed (Drive=%d)\n", drv); #endif - if(raise_irq_when_media_changed) { - fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI; - set_irq(true); - } - } + if(raise_irq_when_media_changed) { + fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI | ST0_NR; + set_irq(true); + } + } } } @@ -1595,10 +1655,20 @@ void UPD765A::open_disk(int drv, _TCHAR path[], int bank) void UPD765A::close_disk(int drv) { - if(drv < MAX_DRIVE && disk[drv]->inserted) { - disk[drv]->close(); -#ifdef _FDC_DEBUG_LOG - emu->out_debug_log("FDC: Disk Ejected (Drive=%d)\n", drv); + if(drv < MAX_DRIVE && disk[drv]->inserted) { + if(head_unload_id[drv] != -1) { + cancel_event(this, head_unload_id[drv]); + head_unload_id[drv] = -1; + } + if(head_load[drv]) { + if(d_noise_head_up != NULL) { + d_noise_head_up->play(); + } + head_load[drv] = false; + } + disk[drv]->close(); +#ifdef _FDC_DEBUG_LOG + emu->out_debug_log("FDC: Disk Ejected (Drive=%d)\n", drv); #endif if(raise_irq_when_media_changed) { fdc[drv].result = (drv & DRIVE_MASK) | ST0_AI; @@ -1687,10 +1757,10 @@ void UPD765A::set_drive_mfm(int drv, bool mfm) } } -#define STATE_VERSION 1 +#define STATE_VERSION 2 -void UPD765A::save_state(FILEIO* state_fio) -{ +void UPD765A::save_state(FILEIO* state_fio) +{ state_fio->FputUint32(STATE_VERSION); state_fio->FputInt32(this_device_id); @@ -1731,18 +1801,22 @@ void UPD765A::save_state(FILEIO* state_fio) state_fio->FputInt32(lost_id); state_fio->FputInt32(result7_id); state_fio->Fwrite(seek_id, sizeof(seek_id), 1); - state_fio->FputBool(force_ready); - state_fio->FputBool(reset_signal); - state_fio->FputBool(prev_index); - state_fio->FputUint32(prev_drq_clock); -} - + state_fio->FputBool(force_ready); + state_fio->FputBool(reset_signal); + state_fio->FputBool(prev_index); + state_fio->FputUint32(prev_drq_clock); + state_fio->Fwrite(head_load, sizeof(head_load), 1); + state_fio->FputInt32(head_unload_time); + state_fio->Fwrite(head_unload_id, sizeof(head_unload_id), 1); +} + bool UPD765A::load_state(FILEIO* state_fio) { - if(state_fio->FgetUint32() != STATE_VERSION) { - return false; - } - if(state_fio->FgetInt32() != this_device_id) { + uint32 state_version = state_fio->FgetUint32(); + if(state_version < 1 || state_version > STATE_VERSION) { + return false; + } + if(state_fio->FgetInt32() != this_device_id) { return false; } state_fio->Fread(fdc, sizeof(fdc), 1); @@ -1784,10 +1858,19 @@ bool UPD765A::load_state(FILEIO* state_fio) lost_id = state_fio->FgetInt32(); result7_id = state_fio->FgetInt32(); state_fio->Fread(seek_id, sizeof(seek_id), 1); - force_ready = state_fio->FgetBool(); - reset_signal = state_fio->FgetBool(); - prev_index = state_fio->FgetBool(); + force_ready = state_fio->FgetBool(); + reset_signal = state_fio->FgetBool(); + prev_index = state_fio->FgetBool(); prev_drq_clock = state_fio->FgetUint32(); + if(state_version >= 2) { + state_fio->Fread(head_load, sizeof(head_load), 1); + head_unload_time = state_fio->FgetInt32(); + state_fio->Fread(head_unload_id, sizeof(head_unload_id), 1); + } else { + head_load[0] = head_load[1] = head_load[2] = head_load[3] = false; + head_unload_time = 0; + head_unload_id[0] = head_unload_id[1] = head_unload_id[2] = head_unload_id[3] = -1; + } return true; } diff --git a/Source/ePC-8801MA/vm/upd765a.h b/Source/ePC-8801MA/vm/upd765a.h index c69299c..c560152 100644 --- a/Source/ePC-8801MA/vm/upd765a.h +++ b/Source/ePC-8801MA/vm/upd765a.h @@ -42,37 +42,39 @@ class UPD765A : public DEVICE NOISE* d_noise_head_up; // fdc - struct { - uint8 track; - uint8 result; - bool access; + struct { + uint8 track; + uint8 result; + bool access; // timing int cur_position; - int next_trans_position; - uint32 prev_clock; - } fdc[4]; - DISK* disk[4]; + int next_trans_position; + uint32 prev_clock; + } fdc[4]; + bool head_load[4]; + DISK* disk[4]; uint8 hdu, hdue, id[4], eot, gpl, dtl; int phase, prevphase; - uint8 status, seekstat, command; - uint32 result; - int step_rate_time; - bool no_dma_mode, motor_on; + uint8 status, seekstat, command; + uint32 result; + int step_rate_time; + int head_unload_time; + bool no_dma_mode, motor_on; #ifdef UPD765A_DMA_MODE bool dma_data_lost; #endif bool irq_masked, drq_masked; - uint8* bufptr; - uint8 buffer[0x8000]; - int count; - int event_phase; - int phase_id, drq_id, lost_id, result7_id, seek_id[4]; - bool force_ready; - bool reset_signal; - bool prev_index; + uint8* bufptr; + uint8 buffer[0x8000]; + int count; + int event_phase; + int phase_id, drq_id, lost_id, result7_id, seek_id[4], head_unload_id[4]; + bool force_ready; + bool reset_signal; + bool prev_index; // timing uint32 prev_drq_clock; @@ -91,10 +93,12 @@ class UPD765A : public DEVICE void shift_to_exec(); void shift_to_read(int length); void shift_to_write(int length); - void shift_to_scan(int length); - void shift_to_result(int length); - void shift_to_result7(); - void shift_to_result7_event(); + void shift_to_scan(int length); + void shift_to_result(int length); + void shift_to_result7(); + void shift_to_result7_event(); + void start_transfer(); + void finish_transfer(); // command void process_cmd(int cmd);