From 3c775ba8e59d0628bda1a8f9912fccfaaaa30537 Mon Sep 17 00:00:00 2001 From: Michael Zapf Date: Thu, 3 Jun 2021 01:35:35 +0200 Subject: geneve/ti99: Fixed HFDC hangs on not connected drives; allows timed steps for sector i/o instead of buffered steps only --- src/devices/bus/ti99/peb/hfdc.cpp | 30 +++++++++++++---- src/devices/bus/ti99/peb/hfdc.h | 6 ++++ src/devices/machine/hdc92x4.cpp | 70 ++++++++++++++++++++++++++++----------- src/devices/machine/hdc92x4.h | 3 ++ 4 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/devices/bus/ti99/peb/hfdc.cpp b/src/devices/bus/ti99/peb/hfdc.cpp index bbbd0ca9fcd..204223fd19c 100644 --- a/src/devices/bus/ti99/peb/hfdc.cpp +++ b/src/devices/bus/ti99/peb/hfdc.cpp @@ -71,7 +71,7 @@ #define LOG_CRU (1U<<10) #define LOG_CONFIG (1U<<15) // Configuration -#define VERBOSE ( LOG_CONFIG | LOG_WARN ) +#define VERBOSE ( LOG_GENERAL | LOG_CONFIG | LOG_WARN ) #include "logmacro.h" DEFINE_DEVICE_TYPE_NS(TI99_HFDC, bus::ti99::peb, myarc_hfdc_device, "ti99_hfdc", "Myarc Hard and Floppy Disk Controller") @@ -82,6 +82,8 @@ namespace bus::ti99::peb { #define FDC_TAG "hdc9234" #define CLOCK_TAG "mm58274c" +#define NONE -1 + #define MOTOR_TIMER 1 #define TAPE_ADDR 0x0fc0 @@ -100,8 +102,12 @@ myarc_hfdc_device::myarc_hfdc_device(const machine_config &mconfig, const char * device_ti99_peribox_card_interface(mconfig, *this), m_motor_on_timer(nullptr), m_hdc9234(*this, FDC_TAG), - m_clock(*this, CLOCK_TAG), m_current_floppy(nullptr), - m_current_harddisk(nullptr), m_see_switches(false), + m_clock(*this, CLOCK_TAG), + m_current_floppy(nullptr), + m_current_harddisk(nullptr), + m_current_floppy_index(NONE), + m_current_hd_index(NONE), + m_see_switches(false), m_irq(), m_dip(), m_motor_running(false), m_inDsrArea(false), m_HDCsel(false), m_RTCsel(false), m_tapesel(false), m_RAMsel(false), m_ROMsel(false), m_address(0), @@ -714,7 +720,7 @@ enum void myarc_hfdc_device::connect_floppy_unit(int index) { // Check if we have a new floppy - if (m_floppy_unit[index] != m_current_floppy) + if (index != m_current_floppy_index) { // Clear all latched flags from other drives m_status_latch = 0; @@ -723,6 +729,7 @@ void myarc_hfdc_device::connect_floppy_unit(int index) // Connect new drive m_current_floppy = m_floppy_unit[index]; + m_current_floppy_index = index; // We don't use the READY line of floppy drives. // READY is asserted when DSKx = 1 @@ -732,7 +739,9 @@ void myarc_hfdc_device::connect_floppy_unit(int index) m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb(&myarc_hfdc_device::floppy_index_callback, this)); else LOGMASKED(LOG_WARN, "Connection to DSK%d failed because no drive is connected\n", index+1); - m_hdc9234->connect_floppy_drive(m_floppy_unit[index]); + + // Connect to HDC (or disconnect) + m_hdc9234->connect_floppy_drive(m_current_floppy); } // We can only run a floppy or a harddisk at a time, not both @@ -741,15 +750,16 @@ void myarc_hfdc_device::connect_floppy_unit(int index) void myarc_hfdc_device::connect_harddisk_unit(int index) { - if (m_harddisk_unit[index] != m_current_harddisk) + if (index != m_current_hd_index) { - // Clear all latched flags form other drives + // Clear all latched flags from other drives m_status_latch = 0; disconnect_hard_drives(); LOGMASKED(LOG_LINES, "Select hard disk WDS%d\n", index+1); // Connect new drive m_current_harddisk = m_harddisk_unit[index]; + m_current_hd_index = index; LOGMASKED(LOG_LINES, "Connect index callback WDS%d\n", index+1); if (m_current_harddisk != nullptr) @@ -760,6 +770,8 @@ void myarc_hfdc_device::connect_harddisk_unit(int index) } else LOGMASKED(LOG_WARN, "Connection to WDS%d failed because no drive is connected\n", index+1); + + // Connect to HDC (or disconnect) m_hdc9234->connect_hard_drive(m_current_harddisk); } @@ -776,6 +788,7 @@ void myarc_hfdc_device::disconnect_floppy_drives() m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb()); m_current_floppy = nullptr; } + m_current_floppy_index = NONE; } void myarc_hfdc_device::disconnect_hard_drives() @@ -787,6 +800,7 @@ void myarc_hfdc_device::disconnect_hard_drives() m_current_harddisk->setup_seek_complete_cb(mfm_harddisk_device::seek_complete_cb()); m_current_harddisk = nullptr; } + m_current_hd_index = NONE; } /* @@ -875,6 +889,8 @@ void myarc_hfdc_device::device_start() // The HFDC does not use READY; it has on-board RAM for DMA m_current_floppy = nullptr; m_current_harddisk = nullptr; + m_current_floppy_index = NONE; + m_current_hd_index = NONE; // Parent class members save_item(NAME(m_senila)); diff --git a/src/devices/bus/ti99/peb/hfdc.h b/src/devices/bus/ti99/peb/hfdc.h index d10cf3a9eae..370fb0289dd 100644 --- a/src/devices/bus/ti99/peb/hfdc.h +++ b/src/devices/bus/ti99/peb/hfdc.h @@ -111,6 +111,12 @@ private: // Currently selected hard drive mfm_harddisk_device* m_current_harddisk; + // Currently selected floppy disk index + int m_current_floppy_index; + + // Currently selected hard disk index + int m_current_hd_index; + // True: Access to DIP switch settings, false: access to line states bool m_see_switches; diff --git a/src/devices/machine/hdc92x4.cpp b/src/devices/machine/hdc92x4.cpp index fc1cf7e5304..967c6289a6c 100644 --- a/src/devices/machine/hdc92x4.cpp +++ b/src/devices/machine/hdc92x4.cpp @@ -516,6 +516,14 @@ bool hdc92x4_device::fm_mode() return ((m_register_w[MODE]&MO_DENSITY)!=0); } +/* + Tell whether we have timed steps or buffered steps. +*/ +bool hdc92x4_device::timed_steps() +{ + return ((m_register_w[MODE]&MO_STEPRATE)!=0); +} + /* Are we back on track 0? */ @@ -913,7 +921,14 @@ void hdc92x4_device::read_id(int& cont, bool implied_seek, bool wait_seek_comple // zero -> we're already there if (m_substate == VERIFY) cont = NEXT; - else m_track_delta = desired_cylinder() - current_cylinder(); + else + { + m_track_delta = desired_cylinder() - current_cylinder(); + if (m_track_delta > 0) + LOGMASKED(LOG_STEP, "Implied seek %d tracks inwards\n", m_track_delta); + if (m_track_delta < 0) + LOGMASKED(LOG_STEP, "Implied seek %d tracks outwards\n", -m_track_delta); + } break; @@ -1162,6 +1177,7 @@ void hdc92x4_device::data_transfer(int& cont) case DATA_TRANSFER_READ: // OK, sector has been read. // Check CRC + LOGMASKED(LOG_SUBSTATES, "substate DATA_TRANSFER_READ\n"); if (m_live_state.crc != 0) { // Set Retry Required flag @@ -1368,7 +1384,7 @@ void hdc92x4_device::reset_controller() */ void hdc92x4_device::drive_deselect() { - LOGMASKED(LOG_SELECT, "DESELECT command\n"); + LOGMASKED(LOG_COMMAND, "DESELECT command\n"); m_selected_drive_number = NODRIVE; m_output1 = 0x00; set_command_done(TC_SUCCESS); @@ -1397,7 +1413,7 @@ void hdc92x4_device::restore_drive() if (m_substate == UNDEF) { - LOGMASKED(LOG_RESTORE, "RESTORE command %02x\n", current_command()); + LOGMASKED(LOG_COMMAND, "RESTORE command %02x\n", current_command()); m_seek_count = 0; m_substate = RESTORE_CHECK; } @@ -1496,7 +1512,7 @@ void hdc92x4_device::step_drive() if (m_substate == UNDEF) { - LOGMASKED(LOG_STEP, "STEP IN/OUT command %02x\n", current_command()); + LOGMASKED(LOG_COMMAND, "STEP IN/OUT command %02x\n", current_command()); m_substate = STEP_ON; } @@ -1671,7 +1687,7 @@ void hdc92x4_device::drive_select() // Calculate the head load delays head_load_delay = head_load_delay_enable? m_register_w[DATA] * head_load_timer_increment[m_selected_drive_type] : 0; - LOGMASKED(LOG_SELECT, "DRIVE SELECT command (%02x): head load delay=%d, type=%d, drive=%d, pout=%02x, step_rate=%d\n", current_command(), head_load_delay, m_selected_drive_type, driveparm&3, m_register_w[RETRY_COUNT]&0x0f, pulse_width() + step_time()); + LOGMASKED(LOG_COMMAND, "DRIVE SELECT command (%02x): head load delay=%d, type=%d, drive=%d, pout=%02x, step_rate=%d\n", current_command(), head_load_delay, m_selected_drive_type, driveparm&3, m_register_w[RETRY_COUNT]&0x0f, pulse_width() + step_time()); // Copy the DMA registers to registers CURRENT_HEAD, CURRENT_CYLINDER, // and CURRENT_IDENT. This is required during formatting [1,2] @@ -1722,7 +1738,7 @@ void hdc92x4_device::drive_select() void hdc92x4_device::set_register_pointer() { m_register_pointer = current_command() & 0xf; - LOGMASKED(LOG_SETPTR, "SET REGISTER POINTER command; start reg=%d\n", m_register_pointer); + LOGMASKED(LOG_COMMAND, "SET REGISTER POINTER command; start reg=%d\n", m_register_pointer); // The specification does not say anything about the effect of setting an // invalid value (only "care should be taken") if (m_register_pointer > 10) @@ -1753,7 +1769,7 @@ void hdc92x4_device::seek_read_id() if (m_substate == UNDEF) { // Command init - LOGMASKED(LOG_READ, "SEEK / READ ID command %02x, CHS=(%d,%d,%d)\n", current_command(), desired_cylinder(), desired_head(), desired_sector()); + LOGMASKED(LOG_COMMAND, "SEEK / READ ID command %02x, CHS=(%d,%d,%d)\n", current_command(), desired_cylinder(), desired_head(), desired_sector()); m_substate = READ_ID; } @@ -1827,7 +1843,7 @@ void hdc92x4_device::read_sectors() { // Command init m_logical = (current_command() & 0x04)!=0; // used in VERIFY and DATA TRANSFER substate - LOGMASKED(LOG_READ, "READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", m_logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); + LOGMASKED(LOG_COMMAND, "READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", m_logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); m_bypass = !m_is_hdc9234 && (current_command() & 0x02)!=0; m_transfer_enabled = (current_command() & 0x01)!=0; @@ -1843,7 +1859,7 @@ void hdc92x4_device::read_sectors() switch (m_substate & 0xf0) { case READ_ID: - read_id(cont, implied_seek, true); // Always check SEEK COMPLETE + read_id(cont, implied_seek, !timed_steps()); // Check SEEK COMPLETE when time bits are 000 break; case VERIFY: verify(cont); // for physical, only verify the first sector @@ -1879,7 +1895,7 @@ void hdc92x4_device::read_track() { if (m_substate == UNDEF) { - LOGMASKED(LOG_READTRACK, "READ TRACK command %02x, head = %d\n", current_command(), desired_head()); + LOGMASKED(LOG_COMMAND, "READ TRACK command %02x, head = %d\n", current_command(), desired_head()); dma_address_out(m_register_w[DMA23_16], m_register_w[DMA15_8], m_register_w[DMA7_0]); m_transfer_enabled = (current_command() & 1)!=0; } @@ -2003,7 +2019,7 @@ void hdc92x4_device::format_track() { if (m_substate == UNDEF) { - LOGMASKED(LOG_FORMAT, "FORMAT TRACK command %02x, head = %d\n", current_command(), desired_head()); + LOGMASKED(LOG_COMMAND, "FORMAT TRACK command %02x, head = %d\n", current_command(), desired_head()); m_substate = WAITINDEX0; m_deleted = (current_command() & 0x10)!=0; m_reduced_write_current = (current_command() & 0x08)!=0; @@ -2118,7 +2134,7 @@ void hdc92x4_device::write_sectors() { // Command init m_logical = (current_command() & 0x20)!=0; - LOGMASKED(LOG_WRITE, "WRITE SECTORS %s command %02x, CHS=(%d,%d,%d)\n", m_logical? "LOGICAL" : "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); + LOGMASKED(LOG_COMMAND, "WRITE SECTORS %s command %02x, CHS=(%d,%d,%d)\n", m_logical? "LOGICAL" : "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); m_substate = READ_ID; @@ -2156,7 +2172,7 @@ void hdc92x4_device::write_sectors() switch (m_substate & 0xf0) { case READ_ID: - read_id(cont, implied_seek, true); // Always check SEEK COMPLETE + read_id(cont, implied_seek, !timed_steps()); // Check SEEK COMPLETE when time bits are 000 break; case VERIFY: verify(cont); @@ -3195,6 +3211,7 @@ void hdc92x4_device::live_run_hd_until(attotime limit) wait_for_realtime(VERIFY_FAILED); else wait_for_realtime(SEARCH_IDAM_FAILED); + return; } @@ -3874,6 +3891,11 @@ uint8_t hdc92x4_device::get_data_from_encoding(uint16_t raw) return (value >> 14) & 0xff; } +/* + TODO: Check whether the whole rollback concept makes sense in this + controller. Unlike the wd17xx, this controller contains a lot more state, + including the external RAM connected via DMA. +*/ void hdc92x4_device::rollback() { m_live_state = m_checkpoint_state; @@ -4302,7 +4324,7 @@ void hdc92x4_device::write(offs_t offset, uint8_t data) { if ((offset & 1) == 0) { - LOGMASKED(LOG_COMMAND, "New register write access %02x\n", data & 0xff); + LOGMASKED(LOG_DETAIL, "New register write access %02x\n", data & 0xff); if (m_executing) LOGMASKED(LOG_WARN, "Error - previous command %02x not completed; register access ignored\n", current_command()); else { @@ -4312,7 +4334,7 @@ void hdc92x4_device::write(offs_t offset, uint8_t data) } else { - LOGMASKED(LOG_COMMAND, "New incoming command %02x\n", data); + LOGMASKED(LOG_DETAIL, "New incoming command %02x\n", data); if (m_executing) LOGMASKED(LOG_WARN, "Error - previous command %02x not completed; new command %02x ignored\n", current_command(), data); else { @@ -4599,15 +4621,20 @@ void hdc92x4_device::seek_complete_handler() int level = seek_complete()? ASSERT_LINE : CLEAR_LINE; LOGMASKED(LOG_LINES, "[%s] Seek complete handler; level=%d\n", ttsn(), level); - // Synchronize our position on the track - live_sync(); - + // Some commands may wait for SEEK_COMPLETE regardless of the step rate if (waiting_for_line(SEEKCOMP_LINE, level)) { + // Synchronize our position on the track + live_sync(); + m_substate = m_state_after_line; m_state_after_line = UNDEF; reenter_command_processing(); } + else + { + if (level==ASSERT_LINE) LOGMASKED(LOG_LINES, "[%s] Ignoring seek complete signal\n", ttsn()); + } } /* @@ -4718,8 +4745,11 @@ void hdc92x4_device::connect_floppy_drive(floppy_image_device* floppy) void hdc92x4_device::connect_hard_drive(mfm_harddisk_device* harddisk) { m_harddisk = harddisk; - m_hd_encoding = m_harddisk->get_encoding(); - LOGMASKED(LOG_DETAIL, "HD encoding = %d\n", m_hd_encoding); + if (harddisk != nullptr) + { + m_hd_encoding = m_harddisk->get_encoding(); + LOGMASKED(LOG_DETAIL, "HD encoding = %d\n", m_hd_encoding); + } } /* diff --git a/src/devices/machine/hdc92x4.h b/src/devices/machine/hdc92x4.h index bef99dcb108..dea7717d2b3 100644 --- a/src/devices/machine/hdc92x4.h +++ b/src/devices/machine/hdc92x4.h @@ -364,6 +364,9 @@ protected: // Are we in FM mode? bool fm_mode(); + // Do we have timed steps? + bool timed_steps(); + // Seek completed? bool seek_complete(); -- cgit v1.2.3