summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Michael Zapf <Michael.Zapf@mizapf.de>2015-06-28 18:06:21 +0200
committer Michael Zapf <Michael.Zapf@mizapf.de>2015-06-28 18:06:21 +0200
commit9b3b4cdf053a8696ce2a570ed6700835fc1f8c0f (patch)
treecb69ee2b0c29ad07e1c67a1e496e2db1fdf079e7 /src
parent4653801ad42679d19ed6090e280eb69cabbd1ea4 (diff)
ti99: MFM HD can write; modern HFDC now default
Diffstat (limited to 'src')
-rw-r--r--src/emu/bus/ti99_peb/hfdc.c20
-rw-r--r--src/emu/bus/ti99_peb/hfdc.h3
-rw-r--r--src/emu/bus/ti99_peb/peribox.c16
-rw-r--r--src/emu/machine/hdc9234.c411
-rw-r--r--src/emu/machine/hdc9234.h11
-rw-r--r--src/emu/machine/ti99_hd.c383
-rw-r--r--src/emu/machine/ti99_hd.h29
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;