diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/bus/ti99_peb/hfdc.c | 20 | ||||
-rw-r--r-- | src/emu/bus/ti99_peb/hfdc.h | 3 | ||||
-rw-r--r-- | src/emu/bus/ti99_peb/peribox.c | 16 | ||||
-rw-r--r-- | src/emu/machine/hdc9234.c | 411 | ||||
-rw-r--r-- | src/emu/machine/hdc9234.h | 11 | ||||
-rw-r--r-- | src/emu/machine/ti99_hd.c | 383 | ||||
-rw-r--r-- | src/emu/machine/ti99_hd.h | 29 |
7 files changed, 750 insertions, 123 deletions
diff --git a/src/emu/bus/ti99_peb/hfdc.c b/src/emu/bus/ti99_peb/hfdc.c index 5d4f84795d1..0f5dccecace 100644 --- a/src/emu/bus/ti99_peb/hfdc.c +++ b/src/emu/bus/ti99_peb/hfdc.c @@ -90,7 +90,7 @@ Modern implementation. */ myarc_hfdc_device::myarc_hfdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : ti_expansion_card_device(mconfig, TI99_HFDC, "Myarc Hard and Floppy Disk Controller", tag, owner, clock, "ti99_hfdc_new", __FILE__), + : ti_expansion_card_device(mconfig, TI99_HFDC, "Myarc Hard and Floppy Disk Controller", tag, owner, clock, "ti99_hfdc", __FILE__), m_hdc9234(*this, FDC_TAG), m_clock(*this, CLOCK_TAG) { @@ -227,7 +227,9 @@ READ8Z_MEMBER(myarc_hfdc_device::readz) // 0101 10xx xxxx xxxx bank 2 // 0101 11xx xxxx xxxx bank 3 int bank = (m_address & 0x0c00) >> 10; - *value = m_buffer_ram[(m_ram_page[bank]<<10) | (m_address & 0x03ff)]; + + // If a DMA is in progress, do not respond + if (m_dip == CLEAR_LINE) *value = m_buffer_ram[(m_ram_page[bank]<<10) | (m_address & 0x03ff)]; if (TRACE_RAM) { if ((m_address & 1)==0) // only show even addresses with words @@ -305,7 +307,9 @@ WRITE8_MEMBER( myarc_hfdc_device::write ) // 0101 11xx xxxx xxxx bank 3 int bank = (m_address & 0x0c00) >> 10; if (TRACE_RAM) logerror("%s: %04x[%02x] <- %02x\n", tag(), m_address & 0xffff, m_ram_page[bank], data); - m_buffer_ram[(m_ram_page[bank]<<10) | (m_address & 0x03ff)] = data; + + // When a DMA is in progress, do not change anything + if (m_dip == CLEAR_LINE) m_buffer_ram[(m_ram_page[bank]<<10) | (m_address & 0x03ff)] = data; return; } // The rest is ROM @@ -704,6 +708,8 @@ void myarc_hfdc_device::connect_floppy_unit(int index) // Check if we have a new floppy if (m_floppy_unit[index] != m_current_floppy) { + // Clear all latched flags from other drives + m_status_latch = 0; disconnect_floppy_drives(); if (TRACE_LINES) logerror("%s: Select floppy drive DSK%d\n", tag(), index+1); @@ -729,6 +735,8 @@ void myarc_hfdc_device::connect_harddisk_unit(int index) { if (m_harddisk_unit[index] != m_current_harddisk) { + // Clear all latched flags form other drives + m_status_latch = 0; disconnect_hard_drives(); if (TRACE_LINES) logerror("%s: Select hard disk WDS%d\n", tag(), index+1); @@ -832,7 +840,7 @@ WRITE_LINE_MEMBER( myarc_hfdc_device::dip_w ) } /* - Read a byte from the onboard SRAM + Read a byte from the onboard SRAM. This is called from the HDC9234. */ READ8_MEMBER( myarc_hfdc_device::read_buffer ) { @@ -844,7 +852,7 @@ READ8_MEMBER( myarc_hfdc_device::read_buffer ) } /* - Write a byte to the onboard SRAM + Write a byte to the onboard SRAM. This is called from the HDC9234. */ WRITE8_MEMBER( myarc_hfdc_device::write_buffer ) { @@ -1067,7 +1075,7 @@ const device_type TI99_HFDC = &device_creator<myarc_hfdc_device>; #define LOG logerror myarc_hfdc_legacy_device::myarc_hfdc_legacy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : ti_expansion_card_device(mconfig, TI99_HFDC_LEG, "Myarc Hard and Floppy Disk Controller LEGACY", tag, owner, clock, "ti99_hfdc", __FILE__), + : ti_expansion_card_device(mconfig, TI99_HFDC_LEG, "Myarc Hard and Floppy Disk Controller LEGACY", tag, owner, clock, "ti99_hfdc_leg", __FILE__), m_hdc9234(*this, FDC_TAG), m_clock(*this, CLOCK_TAG) { diff --git a/src/emu/bus/ti99_peb/hfdc.h b/src/emu/bus/ti99_peb/hfdc.h index 19e7d0fc321..a7f434cc12d 100644 --- a/src/emu/bus/ti99_peb/hfdc.h +++ b/src/emu/bus/ti99_peb/hfdc.h @@ -142,6 +142,9 @@ private: // Recent address int m_address; + // DMA in progress + bool m_dma_in_progress; + // Device Service Routine ROM (firmware) UINT8* m_dsrrom; diff --git a/src/emu/bus/ti99_peb/peribox.c b/src/emu/bus/ti99_peb/peribox.c index c55fe82152c..f4a6f504ebe 100644 --- a/src/emu/bus/ti99_peb/peribox.c +++ b/src/emu/bus/ti99_peb/peribox.c @@ -432,15 +432,15 @@ SLOT_INTERFACE_START( peribox_slot7 ) SLOT_INTERFACE("ide", TI99_IDE) SLOT_INTERFACE("usbsm", TI99_USBSM) SLOT_INTERFACE("bwg", TI99_BWG) - SLOT_INTERFACE("hfdc", TI99_HFDC_LEG) - SLOT_INTERFACE("hfdcnew", TI99_HFDC) + SLOT_INTERFACE("hfdcleg", TI99_HFDC_LEG) + SLOT_INTERFACE("hfdc", TI99_HFDC) SLOT_INTERFACE_END SLOT_INTERFACE_START( peribox_slot8 ) SLOT_INTERFACE("tifdc", TI99_FDC) SLOT_INTERFACE("bwg", TI99_BWG) - SLOT_INTERFACE("hfdc", TI99_HFDC_LEG) - SLOT_INTERFACE("hfdcnew", TI99_HFDC) + SLOT_INTERFACE("hfdcleg", TI99_HFDC_LEG) + SLOT_INTERFACE("hfdc", TI99_HFDC) SLOT_INTERFACE_END MACHINE_CONFIG_FRAGMENT( peribox_device ) @@ -489,14 +489,14 @@ peribox_gen_device::peribox_gen_device(const machine_config &mconfig, const char SLOT_INTERFACE_START( peribox_slot7nobwg ) SLOT_INTERFACE("ide", TI99_IDE) SLOT_INTERFACE("usbsm", TI99_USBSM) - SLOT_INTERFACE("hfdc", TI99_HFDC_LEG) - SLOT_INTERFACE("hfdcnew", TI99_HFDC) + SLOT_INTERFACE("hfdcleg", TI99_HFDC_LEG) + SLOT_INTERFACE("hfdc", TI99_HFDC) SLOT_INTERFACE_END SLOT_INTERFACE_START( peribox_slot8nobwg ) SLOT_INTERFACE("tifdc", TI99_FDC) - SLOT_INTERFACE("hfdc", TI99_HFDC_LEG) - SLOT_INTERFACE("hfdcnew", TI99_HFDC) + SLOT_INTERFACE("hfdcleg", TI99_HFDC_LEG) + SLOT_INTERFACE("hfdc", TI99_HFDC) SLOT_INTERFACE_END SLOT_INTERFACE_START( peribox_slotg ) diff --git a/src/emu/machine/hdc9234.c b/src/emu/machine/hdc9234.c index 91c41fc21d6..f5973fb27ae 100644 --- a/src/emu/machine/hdc9234.c +++ b/src/emu/machine/hdc9234.c @@ -335,6 +335,7 @@ enum LIVE_STATES = 0x80, SEARCH_IDAM, SEARCH_IDAM_FAILED, + VERIFY_FAILED, READ_TWO_MORE_A1_IDAM, READ_IDENT, READ_ID_FIELDS_INTO_REGS, @@ -788,6 +789,10 @@ void hdc9234_device::verify(int& cont, bool verify_all) // find the desired sector. if (TRACE_VERIFY && TRACE_SUBSTATES) logerror("%s: substate VERIFY\n", tag()); + if (TRACE_VERIFY) logerror("%s: VERIFY: Find sector CHS=(%d,%d,%d)\n", tag(), + desired_cylinder(), + desired_head(), + desired_sector()); // If an error occurred (no IDAM found), terminate the command // (This test is only relevant when we did not have a seek phase before) @@ -837,13 +842,10 @@ void hdc9234_device::verify(int& cont, bool verify_all) break; case VERIFY3: - if ((m_register_r[CHIP_STATUS] & CS_SYNCERR) != 0) + if (TRACE_VERIFY) logerror("%s: Total bytes read: %d\n", tag(), m_live_state.bit_count_total / 16); + if ((m_register_r[CHIP_STATUS] & CS_COMPERR) != 0) { if (TRACE_FAIL) logerror("%s: VERIFY failed to find sector CHS=(%d,%d,%d)\n", tag(), desired_cylinder(), desired_head(), desired_sector()); - // live_run has set the sync error; clear it - set_bits(m_register_r[CHIP_STATUS], CS_SYNCERR, false); - // and set the compare error bit instead - set_bits(m_register_r[CHIP_STATUS], CS_COMPERR, true); cont = ERROR; break; } @@ -1772,8 +1774,26 @@ void hdc9234_device::write_sectors() m_precompensation = (current_command() & 0x07); // Important for DATA TRANSFER m_transfer_enabled = true; - m_sync_size = fm_mode()? 6 : 12; - m_gap2_size = fm_mode()? 11 : 22; + + // Something interesting here: + // + // The values for sync and gap2 are passed to the formatting routing + // but how do we know their values right now, when we are writing sectors? + // Since this is not clearly stated in the specification, we have to + // use the default values here + // Actually, why can we choose that value for formatting in the first place? + + if (using_floppy()) + { + m_sync_size = fm_mode()? 6 : 12; + m_gap2_size = fm_mode()? 11 : 22; + } + else + { + // Values for HD + m_sync_size = 13; + m_gap2_size = 3; + } m_write = false; // until we're writing } @@ -1972,7 +1992,11 @@ void hdc9234_device::live_run_until(attotime limit) // [1] p. 9: The ID field sync mark must be found within 33,792 byte times if (m_live_state.bit_count_total > 33792*16) { - wait_for_realtime(SEARCH_IDAM_FAILED); + // Desired sector not found within time + if (m_substate == VERIFY3) + wait_for_realtime(VERIFY_FAILED); + else + wait_for_realtime(SEARCH_IDAM_FAILED); return; } @@ -2008,6 +2032,11 @@ void hdc9234_device::live_run_until(attotime limit) m_live_state.state = IDLE; return; + case VERIFY_FAILED: + set_bits(m_register_r[CHIP_STATUS], CS_COMPERR, true); + m_live_state.state = IDLE; + return; + case READ_TWO_MORE_A1_IDAM: // This state only applies for MFM mode. if (TRACE_LIVE && m_last_live_state != READ_TWO_MORE_A1_IDAM) @@ -2052,7 +2081,13 @@ void hdc9234_device::live_run_until(attotime limit) if ((m_live_state.data_reg & 0xfc) != 0xfc) { // This may happen when we accidentally locked onto the DAM. Look for the next IDAM. - if (TRACE_LIVE) logerror("%s: Missing ident data after A1A1A1\n", tag()); + if (TRACE_LIVE) + { + if (m_live_state.data_reg == 0xf8 || m_live_state.data_reg == 0xfb) + logerror("%s: [%s live] Looks like a DAM; continue to next mark\n", tag(), tts(m_live_state.time).c_str()); + else + logerror("%s: [%s live] Missing ident data after A1A1A1, and it was not DAM; format corrupt?\n", tag(), tts(m_live_state.time).c_str()); + } m_live_state.state = SEARCH_IDAM; break; } @@ -2089,8 +2124,6 @@ void hdc9234_device::live_run_until(attotime limit) if(slot > 4) { // We successfully read the ID fields; let's wait for the machine time to catch up. - m_live_state.bit_count_total = 0; - if ((current_command() & 0xfe) == 0x5a) // Continue if we're reading a complete track wait_for_realtime(READ_TRACK_ID_DONE); @@ -2766,7 +2799,11 @@ void hdc9234_device::live_run_hd_until(attotime limit) // [1] p. 9: The ID field sync mark must be found within 33,792 byte times if (m_live_state.bit_count_total > 33792*16) { - wait_for_realtime(SEARCH_IDAM_FAILED); + // Desired sector not found within time + if (m_substate == VERIFY3) + wait_for_realtime(VERIFY_FAILED); + else + wait_for_realtime(SEARCH_IDAM_FAILED); return; } @@ -2786,6 +2823,11 @@ void hdc9234_device::live_run_hd_until(attotime limit) m_live_state.state = IDLE; return; + case VERIFY_FAILED: + set_bits(m_register_r[CHIP_STATUS], CS_COMPERR, true); + m_live_state.state = IDLE; + return; + case READ_IDENT: if (read_from_mfmhd(limit)) return; @@ -2795,8 +2837,13 @@ void hdc9234_device::live_run_hd_until(attotime limit) // Ident bytes are 111111xx if ((m_live_state.data_reg & 0xfc) != 0xfc) { - // This may happen when we accidentally locked onto the DAM. Look for the next IDAM. - if (TRACE_LIVE) logerror("%s: Missing ident byte after A1\n", tag()); + if (TRACE_LIVE) + { + if (m_live_state.data_reg == 0xf8 || m_live_state.data_reg == 0xfb) + logerror("%s: [%s live] Looks like a DAM; continue to next mark\n", tag(), tts(m_live_state.time).c_str()); + else + logerror("%s: [%s live] Missing ident data after A1, and it was not DAM; format corrupt?\n", tag(), tts(m_live_state.time).c_str()); + } m_live_state.state = SEARCH_IDAM; } else @@ -2826,8 +2873,6 @@ void hdc9234_device::live_run_hd_until(attotime limit) if(slot > 5) { // We successfully read the ID fields; let's wait for the machine time to catch up. - m_live_state.bit_count_total = 0; - if ((current_command() & 0xfe) == 0x5a) // Continue if we're reading a complete track wait_for_realtime(READ_TRACK_ID_DONE); @@ -2976,7 +3021,178 @@ void hdc9234_device::live_run_hd_until(attotime limit) if (TRACE_LIVE) logerror("%s: [%s live] Byte %02x sent via DMA\n", tag(),tts(m_live_state.time).c_str(), m_register_r[DATA] & 0xff); } m_live_state.state = READ_SECTOR_DATA; + break; + + // ==== Track R/W operations (HD), also used for sector writing =============== + case READ_TRACK_BYTE: + // The pause is implemented by doing dummy reads on the hard disk + if (read_from_mfmhd(limit)) + { + if (TRACE_LIVE) logerror("%s: [%s live] return; limit=%s\n", tag(), tts(m_live_state.time).c_str(), tts(limit).c_str()); + return; + } + + // Repeat until we have collected 16 bits + if ((m_live_state.bit_counter & 15)==0) + { + if (TRACE_READ && TRACE_DETAIL) logerror("%s: [%s live] Read byte %02x, repeat = %d\n", tag(), tts(m_live_state.time).c_str(), m_live_state.data_reg, m_live_state.repeat); + wait_for_realtime(READ_TRACK_NEXT_BYTE); + return; + } + break; + + case READ_TRACK_NEXT_BYTE: + m_live_state.state = READ_TRACK_BYTE; + m_live_state.repeat--; + if (m_live_state.repeat == 0) + { + // All bytes read + m_live_state.state = m_live_state.return_state; + checkpoint(); + } + break; + + case WRITE_TRACK_BYTE: + if (write_to_mfmhd(limit)) + return; + + if (m_live_state.bit_counter == 0) + { + // All bits written; get the next byte into the shift register + wait_for_realtime(WRITE_TRACK_NEXT_BYTE); + return; + } + break; + + case WRITE_TRACK_NEXT_BYTE: + m_live_state.state = WRITE_TRACK_BYTE; + m_live_state.repeat--; + + // Write all bytes + if (m_live_state.repeat == 0) + { + // All bytes written + m_live_state.state = m_live_state.return_state; + checkpoint(); + } + else + encode_again(); + + break; + + // ======= HD sector write ===================================== + + case WRITE_DAM_AND_SECTOR: + if (TRACE_LIVE) logerror("%s: [%s live] Skipping GAP2\n", tag(), tts(m_live_state.time).c_str()); + skip_on_track(m_gap2_size, WRITE_DAM_SYNC); + + break; + + case WRITE_DAM_SYNC: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sync zeros\n", tag()); + + // Clear the overrun/underrun flag + set_bits(m_register_r[INT_STATUS], ST_OVRUN, false); + write_on_track(encode_hd(0x00), m_sync_size, WRITE_A1); + break; + + case WRITE_A1: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write one A1\n", tag()); + write_on_track(encode_a1_hd(), 1, WRITE_DATAMARK); + break; + + case WRITE_DATAMARK: + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write data mark\n", tag()); + + // Init the CRC for the ident byte and sector + m_live_state.crc = 0x443b; // value for 1*A1 + + write_on_track(encode_hd(m_deleted? 0xf8 : 0xfb), 1, WRITE_SECDATA); + + m_live_state.byte_counter = calc_sector_size(); + + // Set the over/underrun flag and hope that it will be cleared before we start writing + // (only for sector writing) + if (m_substate == DATA_TRANSFER_WRITE) + { + set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); + m_out_dmarq(ASSERT_LINE); + } + break; + + case WRITE_SECDATA: + if (m_substate == DATA_TRANSFER_WRITE) + { + // Check whether DMA has been acknowledged + if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0) + { + // No, then stop here + m_live_state.state= NO_DMA_ACK; + } + else + { + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sector byte, %d to go\n", tag(), m_live_state.byte_counter); + + // For floppies, set this for each byte; for hard disk, set it only at the beginning + if (m_live_state.byte_counter == calc_sector_size()) + m_out_dip(ASSERT_LINE); + + m_register_r[DATA] = m_register_w[DATA] = m_in_dma(0, 0xff); + + if (m_live_state.byte_counter == 0) + { + m_out_dip(CLEAR_LINE); + m_out_dmarq(CLEAR_LINE); + } + + if (m_live_state.byte_counter > 0) + { + m_live_state.byte_counter--; + write_on_track(encode_hd(m_register_r[DATA]), 1, WRITE_SECDATA); + } + else + { + m_live_state.state = WRITE_DATA_CRC; + // TODO: Prepare for ECC; this is "only" CRC + m_live_state.byte_counter = 2; + } + } + } + else + { + // We are here in the context of track formatting. Write a + // blank sector + write_on_track(encode_hd(0xe5), m_sector_size, WRITE_DATA_CRC); + m_live_state.byte_counter = 2; + } + break; + + case WRITE_DATA_CRC: + if (m_live_state.byte_counter > 0) + { + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write CRC\n", tag()); + m_live_state.byte_counter--; + write_on_track(encode_hd((m_live_state.crc >> 8) & 0xff), 1, WRITE_DATA_CRC); + } + else + // Write a filler byte so that the last CRC bit is saved correctly + write_on_track(encode_hd(0xff), 1, WRITE_DONE); + + break; + + case WRITE_DONE: + if (m_substate == DATA_TRANSFER_WRITE) + { + if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write sector complete\n", tag()); + m_live_state.state = IDLE; + return; + } + else + { + // Continue for track writing: Write GAP3 + m_live_state.state = WRITE_GAP3; + } break; default: @@ -3188,16 +3404,17 @@ UINT16 hdc9234_device::encode(UINT8 byte) bool last_bit_set; check_pos = 0x80; + m_live_state.data_reg = byte; + raw = 0; + if (fm_mode()) { - // Set all clock bits - raw = 0xaaaa; - + raw = 0; // FM: data bit = 1 -> encode as 11 // data bit = 0 -> encode as 10 for (int i=0; i<8; i++) { - if (byte & check_pos) raw |= 0x4000 >> (2*i); + raw = (raw << 2) | (((byte & check_pos)!=0)? 0x11 : 0x10); check_pos >>= 1; } last_bit_set = ((byte & 1)!=0); @@ -3205,40 +3422,27 @@ UINT16 hdc9234_device::encode(UINT8 byte) else { last_bit_set = m_live_state.last_data_bit; - raw = 0; + for (int i=0; i<8; i++) { bool bit_set = ((byte & check_pos)!=0); // MFM: data bit = 1 -> encode as 01 // data bit = 0 -> encode as x0 (x = !last_bit) - if (bit_set) - raw |= 0x4000 >> (2*i); - else - raw |= (last_bit_set? 0x0000 : 0x8000) >> (2*i); + raw <<= 2; + if (bit_set) raw |= 1; + else + { + if (!last_bit_set) raw |= 2; + } last_bit_set = bit_set; check_pos >>= 1; } } - m_live_state.data_reg = byte; return raw; } -/* - Encode a byte for FM or MFM recording. Result is returned in the - shift register of m_live_state. -*/ -void hdc9234_device::encode_byte(UINT8 byte) -{ - UINT16 raw = encode(byte); - m_live_state.bit_counter = 16; - m_live_state.last_data_bit = raw & 1; - m_live_state.shift_reg = m_live_state.shift_reg_save = raw; - if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: [%s live] Write %02x (%04x)\n", tag(), tts(m_live_state.time).c_str(), byte, raw); - checkpoint(); -} - void hdc9234_device::encode_again() { encode_raw(m_live_state.shift_reg_save); @@ -3279,9 +3483,13 @@ void hdc9234_device::pll_reset(const attotime &when, bool output) void hdc9234_device::checkpoint() { // Commit bits from pll buffer to disk until live time (if there is something to write) - if (using_floppy()) m_pll.commit(m_floppy, m_live_state.time); + // For HD we do not use a PLL in this implementation + if (using_floppy()) + { + m_pll.commit(m_floppy, m_live_state.time); + m_checkpoint_pll = m_pll; + } m_checkpoint_state = m_live_state; - m_checkpoint_pll = m_pll; } // =========================================================================== @@ -3294,7 +3502,6 @@ void hdc9234_device::checkpoint() Return false: valid return Updates the CRC and the shift register. Also, the time is updated. - */ bool hdc9234_device::read_from_mfmhd(const attotime &limit) { @@ -3357,6 +3564,124 @@ bool hdc9234_device::read_from_mfmhd(const attotime &limit) return false; } +/* + Write one bit or complete byte from the shift register to the hard disk + at the point of time specified by the time in the live_state. + Return true: the time limit has been reached + Return false: valid return + Updates the CRC and the shift register. Also, the time is updated. +*/ +bool hdc9234_device::write_to_mfmhd(const attotime &limit) +{ + UINT16 data = 0; + int count; + bool offlimit; + + if (m_hd_encoding == MFM_BITS) + { + data = ((m_live_state.shift_reg & 0x8000)==0)? 0:1; + count = 1; + } + else + { + // We'll write the complete shift register in one go + data = m_live_state.shift_reg; + count = 16; + } + offlimit = m_harddisk->write(m_live_state.time, limit, data); + if (offlimit) return true; + + m_live_state.bit_counter -= count; + + // Calculate the CRC + if ((m_live_state.bit_counter & 1)==0) + { + if (m_hd_encoding == MFM_BITS) + { + if ((m_live_state.crc ^ ((data==0)? 0x8000 : 0x0000)) & 0x8000) + m_live_state.crc = (m_live_state.crc << 1) ^ 0x1021; + else + m_live_state.crc = m_live_state.crc << 1; + } + else + { + // Take the data byte from the stored copy in the data_reg + m_live_state.crc = ccitt_crc16_one(m_live_state.crc, m_live_state.data_reg); + } + } + + m_live_state.shift_reg = (m_live_state.shift_reg << count) & 0xffff; + return false; +} + +UINT16 hdc9234_device::encode_hd(UINT8 byte) +{ + UINT16 cells; + UINT8 check_pos; + bool last_bit_set; + check_pos = 0x80; + + last_bit_set = m_live_state.last_data_bit; + cells = 0; + + int databit = (m_hd_encoding==SEPARATED)? 0x0080 : 0x4000; + int shift = (m_hd_encoding==SEPARATED)? 1 : 2; + int clockbit = 0x8000; + + if (m_hd_encoding != SEPARATED_SIMPLE) + { + for (int i=0; i<8; i++) + { + bool bit_set = ((byte & check_pos)!=0); + + // MFM: data bit = 1 -> encode as 01 + // data bit = 0 -> encode as x0 (x = !last_bit) + + if (bit_set) + cells |= databit; + else + cells |= (last_bit_set? 0x0000 : clockbit); + + databit >>= shift; + clockbit >>= shift; + + last_bit_set = bit_set; + check_pos >>= 1; + } + } + else + { + cells = byte & 0x00ff; + } + + m_live_state.data_reg = byte; + return cells; +} + +UINT16 hdc9234_device::encode_a1_hd() +{ + UINT16 cells = 0; + + switch (m_hd_encoding) + { + case MFM_BITS: + case MFM_BYTE: + cells = 0x4489; + break; + case SEPARATED: + cells = 0x0aa1; + break; + case SEPARATED_SIMPLE: + cells = 0xffa1; + break; + } + + m_live_state.last_data_bit = true; + m_live_state.data_reg = 0xa1; + m_live_state.bit_counter = 16; + return cells; +} + // =========================================================================== diff --git a/src/emu/machine/hdc9234.h b/src/emu/machine/hdc9234.h index b6dad3fa4f2..ce85edaa21c 100644 --- a/src/emu/machine/hdc9234.h +++ b/src/emu/machine/hdc9234.h @@ -270,10 +270,6 @@ private: // Resets the PLL to the given time void pll_reset(const attotime &when, bool write); - // Encodes the byte using FM or MFM. Changes the m_live_state members - // shift_reg, data_reg, and last_data_bit - void encode_byte(UINT8 byte); - // Puts the word into the shift register directly. Changes the m_live_state members // shift_reg, and last_data_bit void encode_raw(UINT16 word); @@ -281,6 +277,10 @@ private: // Encodes a byte in FM or MFM. Called by encode_byte. UINT16 encode(UINT8 byte); + // Encodes a byte in FM or MFM. Called by encode_byte. + UINT16 encode_hd(UINT8 byte); + UINT16 encode_a1_hd(); + // Encode the latest byte again void encode_again(); @@ -299,6 +299,9 @@ private: // Read from the MFM HD bool read_from_mfmhd(const attotime &limit); + // Write to the MFM HD + bool write_to_mfmhd(const attotime &limit); + // ============================================== // Command state machine // ============================================== diff --git a/src/emu/machine/ti99_hd.c b/src/emu/machine/ti99_hd.c index 49aeb5b69d1..d335df23e3d 100644 --- a/src/emu/machine/ti99_hd.c +++ b/src/emu/machine/ti99_hd.c @@ -14,7 +14,8 @@ **************************************************************************/ -// TODO: Format +// TODO: Define format by a file +// Save interleave in CHD #include "emu.h" #include "formats/imageutl.h" @@ -22,10 +23,11 @@ #include "ti99_hd.h" -#define TRACE_STEPS 0 -#define TRACE_SIGNALS 0 +#define TRACE_STEPS 1 +#define TRACE_SIGNALS 1 #define TRACE_READ 0 -#define TRACE_CACHE 0 +#define TRACE_WRITE 0 +#define TRACE_CACHE 1 #define TRACE_RWTRACK 0 #define TRACE_BITS 0 #define TRACE_DETAIL 0 @@ -34,7 +36,8 @@ enum { INDEX_TM = 0, SPINUP_TM, - SEEK_TM + SEEK_TM, + CACHE_TM }; enum @@ -47,6 +50,8 @@ enum #define TRACKSLOTS 5 #define TRACKIMAGE_SIZE 10416 // Provide the buffer for a complete track, including preambles and gaps +#define OFFLIMIT -1 + std::string mfm_harddisk_device::tts(const attotime &t) { char buf[256]; @@ -61,6 +66,8 @@ mfm_harddisk_device::mfm_harddisk_device(const machine_config &mconfig, device_t { m_spinupms = 10000; m_cachelines = TRACKSLOTS; + m_max_cylinder = 0; + m_max_heads = 0; } mfm_harddisk_device::~mfm_harddisk_device() @@ -72,6 +79,8 @@ void mfm_harddisk_device::device_start() m_index_timer = timer_alloc(INDEX_TM); m_spinup_timer = timer_alloc(SPINUP_TM); m_seek_timer = timer_alloc(SEEK_TM); + m_cache_timer = timer_alloc(CACHE_TM); + m_rev_time = attotime::from_hz(60); // MFM drives have a revolution rate of 3600 rpm (i.e. 60/sec) @@ -81,6 +90,9 @@ void mfm_harddisk_device::device_start() m_spinup_timer->adjust(attotime::from_msec(m_spinupms)); m_cache = global_alloc(mfmhd_trackimage_cache); + + // In 5 second period, check whether the cache has dirty lines + m_cache_timer->adjust(attotime::from_msec(5000), 0, attotime::from_msec(5000)); } void mfm_harddisk_device::device_reset() @@ -101,7 +113,6 @@ void mfm_harddisk_device::device_stop() bool mfm_harddisk_device::call_load() { - setup_characteristics(); bool loaded = harddisk_image_device::call_load(); if (loaded==IMAGE_INIT_PASS) { @@ -114,6 +125,12 @@ bool mfm_harddisk_device::call_load() return loaded; } +void mfm_harddisk_device::call_unload() +{ + m_cache->cleanup(); + harddisk_image_device::call_unload(); +} + void mfm_harddisk_device::setup_index_pulse_cb(index_pulse_cb cb) { m_index_pulse_cb = cb; @@ -169,6 +186,10 @@ void mfm_harddisk_device::device_timer(emu_timer &timer, device_timer_id id, int recalibrate(); break; + case CACHE_TM: + m_cache->write_back_one(); + break; + case SEEK_TM: switch (m_step_phase) { @@ -315,44 +336,29 @@ void mfm_harddisk_device::step_w(line_state line) } /* - Reading bytes from the hard disk. - This is the byte-level access to the hard disk. We deliver the next data byte - together with the clock byte. - - Returns true if the time limit will be exceeded before reading the complete byte. - Otherwise returns the byte at the given position together with the clock byte. + Find the position of the cell. + Returns true when the current time exceeds the limit. + Returns the position as an index into the track array and the bit number. */ -bool mfm_harddisk_device::read(attotime &from_when, const attotime &limit, UINT16 &cdata) +bool mfm_harddisk_device::find_position(attotime &from_when, const attotime &limit, int &bytepos, int &bit) { - UINT16* track = m_cache->get_trackimage(m_current_cylinder, m_current_head); - - if (track==NULL) - { - // What shall we do in this case? - throw emu_fatalerror("Cannot read CHD image"); - } - - // We stop some few cells early each track, so lift the from_when time over - // the 2 microseconds. + // As we stop some few cells early each track, we adjust our position + // to the track start if (from_when < m_revolution_start_time) from_when = m_revolution_start_time; // Calculate the position in the track, given the from_when time and the revolution_start_time. - // Each cell takes 100 ns (10 MHz) - + // Each cell takes 100 ns (@10 MHz) int cell = (from_when - m_revolution_start_time).as_ticks(10000000); - attotime fw = from_when; - from_when += attotime::from_nsec((m_encoding==MFM_BITS)? 100 : 1600); if (from_when > limit) return true; - - int bytepos = cell / 16; + bytepos = cell / 16; // Reached the end if (bytepos >= 10416) { - if (TRACE_DETAIL) logerror("%s: Reached end: rev_start = %s, live = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(fw).c_str()); + if (TRACE_DETAIL) logerror("%s: Reached end: rev_start = %s, live = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(from_when).c_str()); m_revolution_start_time += m_rev_time; cell = (from_when - m_revolution_start_time).as_ticks(10000000); bytepos = cell / 16; @@ -360,16 +366,44 @@ bool mfm_harddisk_device::read(attotime &from_when, const attotime &limit, UINT1 if (bytepos < 0) { - if (TRACE_DETAIL) logerror("%s: Negative cell number: rev_start = %s, live = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(fw).c_str()); + if (TRACE_DETAIL) logerror("%s: Negative cell number: rev_start = %s, live = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(from_when).c_str()); bytepos = 0; } + bit = cell % 16; + + return false; +} + +/* + Reading bytes from the hard disk. + + Returns true if the time limit will be exceeded before reading the bit or complete byte. + Otherwise returns the bit at the given position, or the complete data byte with the clock byte. +*/ +bool mfm_harddisk_device::read(attotime &from_when, const attotime &limit, UINT16 &cdata) +{ + UINT16* track = m_cache->get_trackimage(m_current_cylinder, m_current_head); + + if (track==NULL) + { + // What shall we do in this case? + throw emu_fatalerror("Cannot read CHD image"); + } + + // Get a copy for later debug output + attotime fw = from_when; + + int bytepos = 0; + int bitpos = 0; + + bool offlimit = find_position(from_when, limit, bytepos, bitpos); + if (offlimit) return true; if (m_encoding == MFM_BITS) { // We will deliver a single bit - int cellno = cell % 16; - cdata = ((track[bytepos] << cellno) & 0x8000) >> 15; - if (TRACE_BITS) logerror("%s: Reading (c=%d,h=%d,bit=%d) at cell %d [%s] = %d\n", tag(), m_current_cylinder, m_current_head, cellno, cell, tts(fw).c_str(), cdata); + cdata = ((track[bytepos] << bitpos) & 0x8000) >> 15; + if (TRACE_BITS) logerror("%s: Reading (c=%d,h=%d,bit=%d) at cell %d [%s] = %d\n", tag(), m_current_cylinder, m_current_head, bitpos, ((bytepos<<4) + bitpos), tts(fw).c_str(), cdata); } else { @@ -380,15 +414,49 @@ bool mfm_harddisk_device::read(attotime &from_when, const attotime &limit, UINT1 return false; } -mfm_hd_generic_device::mfm_hd_generic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) -: mfm_harddisk_device(mconfig, MFMHD_GENERIC, "Generic MFM hard disk", tag, owner, clock, "mfm_harddisk", __FILE__) +/* + Writing bytes to the hard disk. + + Returns true if the time limit will be exceeded before writing the bit or complete byte. +*/ +bool mfm_harddisk_device::write(attotime &from_when, const attotime &limit, UINT16 cdata) { + UINT16* track = m_cache->get_trackimage(m_current_cylinder, m_current_head); + + if (track==NULL) + { + // What shall we do in this case? + throw emu_fatalerror("Cannot read CHD image"); + } + + int bytepos = 0; + int bitpos = 0; + + bool offlimit = find_position(from_when, limit, bytepos, bitpos); + if (offlimit) return true; + + m_cache->mark_current_as_dirty(); + + if (m_encoding == MFM_BITS) + { + // We will write a single bit + if (cdata != 0) track[bytepos] |= (0x8000 >> bitpos); + else track[bytepos] &= ~(0x8000 >> bitpos); + bitpos++; + } + else + { + // We will write a whole byte + track[bytepos] = cdata; + } + + if (TRACE_WRITE) if ((bitpos&0x0f)==0) logerror("%s: Writing data=%04x (c=%d,h=%d) at position %d\n", tag(), track[bytepos], m_current_cylinder, m_current_head, bytepos); + return false; } -void mfm_hd_generic_device::setup_characteristics() +mfm_hd_generic_device::mfm_hd_generic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: mfm_harddisk_device(mconfig, MFMHD_GENERIC, "Generic MFM hard disk", tag, owner, clock, "mfm_harddisk", __FILE__) { - m_max_cylinder = 0; - m_max_heads = 0; } const device_type MFMHD_GENERIC = &device_creator<mfm_hd_generic_device>; @@ -396,10 +464,6 @@ const device_type MFMHD_GENERIC = &device_creator<mfm_hd_generic_device>; mfm_hd_st225_device::mfm_hd_st225_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : mfm_harddisk_device(mconfig, MFMHD_ST225, "Seagate ST-225 MFM hard disk", tag, owner, clock, "mfm_hd_st225", __FILE__) { -} - -void mfm_hd_st225_device::setup_characteristics() -{ m_max_cylinder = 615; m_max_heads = 4; } @@ -423,19 +487,59 @@ mfmhd_trackimage_cache::~mfmhd_trackimage_cache() mfmhd_trackimage* current = m_tracks; if (TRACE_CACHE) logerror("%s: MFM HD cache destroy\n", tag()); + while (current != NULL) + { + global_free_array(current->encdata); + mfmhd_trackimage* currenttmp = current->next; + global_free(current); + current = currenttmp; + } +} + +void mfmhd_trackimage_cache::write_back_one() +{ + mfmhd_trackimage* current = m_tracks; + + while (current != NULL) + { + if (current->dirty) + { + if (TRACE_CACHE) logerror("%s: MFM HD cache: write back line c=%d h=%d\n", tag(), current->cylinder, current->head); + write_back(current); + break; + } + mfmhd_trackimage* currenttmp = current->next; + current = currenttmp; + } +} + +void mfmhd_trackimage_cache::cleanup() +{ + mfmhd_trackimage* current = m_tracks; + if (TRACE_CACHE) logerror("%s: MFM HD cache cleanup\n", tag()); + // Still dirty? while (current != NULL) { if (TRACE_CACHE) logerror("%s: MFM HD cache: evict line cylinder=%d head=%d\n", tag(), current->cylinder, current->head); if (current->dirty) write_back(current); - global_free_array(current->encdata); mfmhd_trackimage* currenttmp = current->next; - global_free(current); current = currenttmp; } } /* + Marks the recently loaded track as dirty. As every writing operations + is preceded by a lookup, writing will always be done on the first track in the list. +*/ +void mfmhd_trackimage_cache::mark_current_as_dirty() +{ + m_tracks->dirty = true; +} + +const char *encnames[] = { "MFM_BITS","MFM_BYTE","SEPARATE","SSIMPLE " }; + +/* Initialize the cache by loading the first <trackslots> tracks. */ void mfmhd_trackimage_cache::init(chd_file* chdfile, const char* dtag, int maxcyl, int maxhead, int trackslots, mfmhd_enc_t encoding) @@ -443,11 +547,12 @@ void mfmhd_trackimage_cache::init(chd_file* chdfile, const char* dtag, int maxcy m_encoding = encoding; m_tagdev = dtag; - if (TRACE_CACHE) logerror("%s: MFM HD cache init; using encoding %d\n", m_tagdev, encoding); + if (TRACE_CACHE) logerror("%s: MFM HD cache init; using encoding %s; cache size is %d tracks\n", m_tagdev, encnames[encoding], trackslots); chd_error state = CHDERR_NONE; mfmhd_trackimage* previous = NULL; mfmhd_trackimage* current = NULL; std::string metadata; + m_calc_interleave = 0; m_chd = chdfile; @@ -530,6 +635,20 @@ int mfmhd_trackimage_cache::chs_to_lba(int cylinder, int head, int sector) } /* + Calculate the ident byte from the cylinder. The specification does not + define idents beyond cylinder 1023, but formatting programs seem to + continue with 0xfd for cylinders between 1024 and 2047. +*/ +UINT8 mfmhd_trackimage_cache::cylinder_to_ident(int cylinder) +{ + if (cylinder < 256) return 0xfe; + if (cylinder < 512) return 0xff; + if (cylinder < 768) return 0xfc; + return 0xfd; +} + + +/* Delivers the track image. First look up the track image in the cache. If not present, load it from the CHD, convert it, and evict the least recently used line. @@ -666,6 +785,7 @@ void mfmhd_trackimage_cache::mfm_encode_mask(mfmhd_trackimage* slot, int& positi /* Load a track from the CHD. + TODO: Isolate the encoding into a separate format definition */ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinder, int head, int sectorcount, int size, int interleave) { @@ -673,11 +793,17 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde UINT8 sector_content[1024]; - if (TRACE_RWTRACK) logerror("%s: MFM HD cache: load (c=%d,h=%d) from CHD\n", tag(), cylinder, head); + if (TRACE_RWTRACK) logerror("%s: MFM HD cache: load track (c=%d,h=%d) from CHD\n", tag(), cylinder, head); m_lastbit = false; int position = 0; // will be incremented by each encode call + // According to MDM5 formatting: + // gap0=16 gap1=16 gap2=3 gap3=22 sync=13 count=32 size=2 + + // HFDC manual: When using the hard disk format, the values for GAP0 and GAP1 must + // both be set to the same number and loaded in the appropriate registers. + // Gap 1 mfm_encode(slot, position, 0x4e, 16); @@ -687,18 +813,19 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde // Round up int delta = (sectorcount + interleave-1) / interleave; - if (TRACE_DETAIL) logerror("cyl=%02x head=%02x: sector sequence = ", cylinder&0xff, head&0xff); + if (TRACE_DETAIL) logerror("%s: cyl=%02x head=%02x: sector sequence = ", tag(), cylinder&0xff, head&0xff); for (int sector = 0; sector < sectorcount; sector++) { if (TRACE_DETAIL) logerror("%02d ", sec_number); + // Sync gap mfm_encode(slot, position, 0x00, 13); // Write IDAM mfm_encode_a1(slot, position); - mfm_encode(slot, position, 0xfe); // ID field? + mfm_encode(slot, position, cylinder_to_ident(cylinder)); - // Write header + // Write header (according to MDM5: CHSL) mfm_encode(slot, position, cylinder & 0xff); mfm_encode(slot, position, head & 0xff); mfm_encode(slot, position, sec_number); @@ -760,13 +887,165 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde return state; } +enum +{ + SEARCH_A1=0, + FOUND_A1, + DAM_FOUND, + CHECK_CRC +}; + +UINT8 mfmhd_trackimage_cache::mfm_decode(UINT16 raw) +{ + unsigned int value = 0; + + for (int i=0; i < 8; i++) + { + value <<= 1; + + value |= (raw & 0x4000); + raw <<= 2; + } + return (value >> 14) & 0xff; +} + /* - TODO: Maybe use a scheduled write-back in addition to the eviction. + TODO: The CHD/track conversion should go in a separate format definition (see floppy) + (can also handle different header formats there) */ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot) { - if (TRACE_RWTRACK) logerror("%s: MFM HD cache: write back (c=%d,h=%d) to CHD\n", tag(), slot->cylinder, slot->head); + if (TRACE_CACHE) logerror("%s: MFM HD cache: write back (c=%d,h=%d) to CHD\n", tag(), slot->cylinder, slot->head); + + UINT8 buffer[1024]; // for header or sector content + + UINT16 *track = slot->encdata; + + int bytepos = 0; + int state = SEARCH_A1; + int count = 0; + int pos = 0; + UINT16 crc = 0; + UINT8 byte; + bool search_header = true; + + int cylinder = 0; + int head = 0; + int sector = 0; + + int headerpos = 0; + + int calc_interleave = 0; + int interleave_prec = -1; + bool check_interleave = true; + + // We have to go through the bytes of the track and save a sector as soon as one shows up + while (bytepos < TRACKIMAGE_SIZE) + { + switch (state) + { + case SEARCH_A1: + if (((m_encoding==MFM_BITS || m_encoding==MFM_BYTE) && track[bytepos]==0x4489) + || (m_encoding==SEPARATED && track[bytepos]==0x0aa1) + || (m_encoding==SEPARATED_SIMPLE && track[bytepos]==0xffa1)) + { + state = FOUND_A1; + count = search_header? 7 : 259; + crc = 0x443b; // init value with a1 + pos = 0; + } + bytepos++; + break; + + case FOUND_A1: + // read next values into array + if (m_encoding==MFM_BITS || m_encoding==MFM_BYTE) + { + byte = mfm_decode(track[bytepos]); + } + else byte = (track[bytepos] & 0xff); + + crc = ccitt_crc16_one(crc, byte); + // logerror("%s: MFM HD: Byte = %02x, CRC=%04x\n", tag(), byte, crc); + + // Put byte into buffer + // but not the data mark and the CRC + if (search_header || (count > 2 && count < 259)) buffer[pos++] = byte; + + if (--count == 0) + { + if (crc==0) + { + if (search_header) + { + // Found a header + // ident = buffer[0]; // check? + cylinder = buffer[1]; + head = buffer[2]; + sector = buffer[3]; + + // Count the sectors for the interleave + if (check_interleave) + { + if (interleave_prec == -1) interleave_prec = sector; + else + { + if (sector == interleave_prec+1) check_interleave = false; + calc_interleave++; + } + } + + if (calc_interleave == 0) calc_interleave = sector - buffer[3]; + // size = buffer[4]; + search_header = false; + if (TRACE_DETAIL) logerror("%s: MFM HD: Found sector chs=(%d,%d,%d)\n", tag(), cylinder, head, sector); + headerpos = pos; + } + else + { + // Sector contents + // Write the sectors to the CHD + if (TRACE_DETAIL) logerror("%s: MFM HD: Writing sector chs=(%d,%d,%d) to CHD\n", tag(), cylinder, head, sector); + chd_error state = m_chd->write_units(chs_to_lba(cylinder, head, sector), buffer); + + if (state != CHDERR_NONE) + { + logerror("%s: MFM HD: Write error while writing sector chs=(%d,%d,%d)\n", tag(), cylinder, head, sector); + } + search_header = true; + } + } + else + { + logerror("%s: MFM HD: CRC error\n", tag()); + search_header = true; + } + // search next A1 + state = SEARCH_A1; + + if (!search_header && (pos - headerpos) > 30) + { + logerror("%s: MFM HD: Error; missing DAM; searching next header\n", tag()); + search_header = true; + } + } + bytepos++; + break; + } + } + // Clear the dirty flag slot->dirty = false; + + if (check_interleave == false) + { + // Successfully determined the interleave + m_calc_interleave = calc_interleave; + } + + if (TRACE_CACHE) + { + logerror("%s: MFM HD cache: write back complete (c=%d,h=%d), interleave = %d\n", tag(), slot->cylinder, slot->head, m_calc_interleave); + } } /* diff --git a/src/emu/machine/ti99_hd.h b/src/emu/machine/ti99_hd.h index 02f5d4fb4e5..b1a9a87839d 100644 --- a/src/emu/machine/ti99_hd.h +++ b/src/emu/machine/ti99_hd.h @@ -44,16 +44,23 @@ class mfmhd_trackimage_cache public: mfmhd_trackimage_cache(); ~mfmhd_trackimage_cache(); - void init(chd_file* chdfile, const char* tag, int maxcyl, int maxhead, int trackslots, mfmhd_enc_t encoding); - UINT16* get_trackimage(int cylinder, int head); + void init(chd_file* chdfile, const char* tag, int maxcyl, int maxhead, int trackslots, mfmhd_enc_t encoding); + UINT16* get_trackimage(int cylinder, int head); + void mark_current_as_dirty(); + void cleanup(); + void write_back_one(); private: void mfm_encode(mfmhd_trackimage* slot, int& position, UINT8 byte, int count=1); void mfm_encode_a1(mfmhd_trackimage* slot, int& position); void mfm_encode_mask(mfmhd_trackimage* slot, int& position, UINT8 byte, int count, int mask); + UINT8 mfm_decode(UINT16 raw); + chd_error load_track(mfmhd_trackimage* slot, int cylinder, int head, int sectorcount, int size, int interleave); void write_back(mfmhd_trackimage* timg); int chs_to_lba(int cylinder, int head, int sector); + UINT8 cylinder_to_ident(int cylinder); + chd_file* m_chd; const char* m_tagdev; @@ -65,6 +72,8 @@ private: int m_heads; int m_sectors_per_track; int m_sectorsize; + + int m_calc_interleave; void showtrack(UINT16* enctrack, int length); const char* tag() { return m_tagdev; } }; @@ -96,9 +105,15 @@ public: line_state seek_complete_r() { return m_seek_complete? ASSERT_LINE : CLEAR_LINE; } ; line_state trk00_r() { return m_current_cylinder==0? ASSERT_LINE : CLEAR_LINE; } + // Common routine for read/write + bool find_position(attotime &from_when, const attotime &limit, int &bytepos, int &bitpos); + // Data output towards controller bool read(attotime &from_when, const attotime &limit, UINT16 &data); + // Data input from controller + bool write(attotime &from_when, const attotime &limit, UINT16 data); + // Step void step_w(line_state line); void direction_in_w(line_state line); @@ -107,6 +122,7 @@ public: void headsel_w(int head) { m_current_head = head & 0x0f; } bool call_load(); + void call_unload(); // Tells us the time when the track ends (next index pulse) attotime track_end_time(); @@ -117,10 +133,9 @@ protected: void device_reset(); void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); - virtual void setup_characteristics() = 0; std::string tts(const attotime &t); - emu_timer *m_index_timer, *m_spinup_timer, *m_seek_timer; + emu_timer *m_index_timer, *m_spinup_timer, *m_seek_timer, *m_cache_timer; index_pulse_cb m_index_pulse_cb; ready_cb m_ready_cb; seek_complete_cb m_seek_complete_cb; @@ -159,9 +174,6 @@ class mfm_hd_generic_device : public mfm_harddisk_device { public: mfm_hd_generic_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - void setup_characteristics(); }; extern const device_type MFMHD_GENERIC; @@ -170,9 +182,6 @@ class mfm_hd_st225_device : public mfm_harddisk_device { public: mfm_hd_st225_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - -protected: - void setup_characteristics(); }; extern const device_type MFMHD_ST225; |