HDC9234: Added HD track reading; several bug fixes.

This commit is contained in:
Michael Zapf 2015-07-05 17:15:01 +02:00
parent 571a4e88d9
commit 445fa7422d
3 changed files with 217 additions and 90 deletions

View File

@ -16,7 +16,7 @@
The HDC9234 controller is also referred to as the "Universal Disk Controller" (UDC) The HDC9234 controller is also referred to as the "Universal Disk Controller" (UDC)
by the data book by the data book
Michael Zapf, September 2014 Michael Zapf, July 2015
***************************************************************************/ ***************************************************************************/
@ -54,8 +54,10 @@
#define TRACE_INDEX 0 #define TRACE_INDEX 0
#define TRACE_DMA 0 #define TRACE_DMA 0
#define TRACE_DONE 0 #define TRACE_DONE 0
#define TRACE_FAIL 0 #define TRACE_FAIL 1
#define TRACE_AUXBUS 0 #define TRACE_AUXBUS 0
#define TRACE_HEADER 0
#define TRACE_GAPS 0
#define TRACE_DETAIL 0 #define TRACE_DETAIL 0
@ -66,14 +68,17 @@
ECC ECC
Write long (see MODE register; only useful with ECC) Write long (see MODE register; only useful with ECC)
Tape operations Tape operations
Read track (HD) AT mode (HD)
FM-encoded HD
=== Implemented but untested === === Implemented but untested ===
Burst mode
Restore Restore
Poll drives Poll drives
Seek/Read ID Seek/Read ID
Read track (floppy) Read track
=== TODO ===
Create a common state machine for HD and floppy
*/ */
/* /*
@ -488,9 +493,24 @@ bool hdc9234_device::drive_ready()
return (m_register_r[DRIVE_STATUS] & HDC_DS_READY)!=0; return (m_register_r[DRIVE_STATUS] & HDC_DS_READY)!=0;
} }
/*
Doing a track read?
*/
bool hdc9234_device::reading_track()
{
return (current_command() & 0xfe) == 0x5a;
}
/* /*
Accessor functions for specific parameters. Accessor functions for specific parameters.
*/ */
/*
In SMC mode, the cylinder number is stored in bit positions 4,5,6 of the
head register and in the 8 bits of the cylinder register.
This is true for the desired cyl/head, current cyl/head, and the header
fields on the track.
*/
int hdc9234_device::desired_head() int hdc9234_device::desired_head()
{ {
return m_register_w[DESIRED_HEAD] & 0x0f; return m_register_w[DESIRED_HEAD] & 0x0f;
@ -688,9 +708,9 @@ void hdc9234_device::read_id(int& cont, bool implied_seek, bool wait_seek_comple
break; break;
} }
if (TRACE_READID && TRACE_SUBSTATES) if (TRACE_READID)
{ {
logerror("%s: substate READ_ID1\n", tag()); if (TRACE_SUBSTATES) logerror("%s: substate READ_ID1\n", tag());
logerror("%s: DESIRED_CYL = %d; CURRENT_CYL = %d\n", tag(), desired_cylinder(), current_cylinder()); logerror("%s: DESIRED_CYL = %d; CURRENT_CYL = %d\n", tag(), desired_cylinder(), current_cylinder());
} }
@ -775,7 +795,7 @@ void hdc9234_device::read_id(int& cont, bool implied_seek, bool wait_seek_comple
contents of the DESIRED_HEAD/CYLINDER/SECTOR registers contents of the DESIRED_HEAD/CYLINDER/SECTOR registers
- checks the CRC - checks the CRC
*/ */
void hdc9234_device::verify(int& cont, bool verify_all) void hdc9234_device::verify(int& cont)
{ {
cont = CONTINUE; cont = CONTINUE;
@ -842,7 +862,7 @@ void hdc9234_device::verify(int& cont, bool verify_all)
break; break;
case VERIFY3: case VERIFY3:
if (TRACE_VERIFY) logerror("%s: Total bytes read: %d\n", tag(), m_live_state.bit_count_total / 16); if (TRACE_VERIFY) logerror("%s: Next IDAM found; total bytes read: %d\n", tag(), m_live_state.bit_count_total / 16);
if ((m_register_r[CHIP_STATUS] & CS_COMPERR) != 0) 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()); if (TRACE_FAIL) logerror("%s: VERIFY failed to find sector CHS=(%d,%d,%d)\n", tag(), desired_cylinder(), desired_head(), desired_sector());
@ -851,7 +871,7 @@ void hdc9234_device::verify(int& cont, bool verify_all)
} }
// Continue with the loop // Continue with the loop
if (verify_all || !m_first_sector_found) if (m_logical || !m_first_sector_found)
{ {
// this is for the logical sector reading/writing // this is for the logical sector reading/writing
m_substate = VERIFY1; m_substate = VERIFY1;
@ -905,10 +925,16 @@ void hdc9234_device::data_transfer(int& cont)
if (m_transfer_enabled) dma_address_out(m_register_w[DMA23_16], m_register_w[DMA15_8], m_register_w[DMA7_0]); if (m_transfer_enabled) dma_address_out(m_register_w[DMA23_16], m_register_w[DMA15_8], m_register_w[DMA7_0]);
if (TRACE_TRANSFER && TRACE_DETAIL) logerror("%s: %s sector CHS=(%d,%d,%d)\n", tag(), m_write? "write" : "read", if (TRACE_TRANSFER && TRACE_DETAIL)
{
if (m_logical)
logerror("%s: %s sector CHS=(%d,%d,%d)\n", tag(), m_write? "Write" : "Read",
desired_cylinder(), desired_cylinder(),
desired_head(), desired_head(),
desired_sector()); desired_sector());
else
logerror("%s: %s next sector on track\n", tag(), m_write? "Write" : "Read");
}
if (m_write) if (m_write)
{ {
@ -970,8 +996,9 @@ void hdc9234_device::data_transfer(int& cont)
dma_address = (dma_address + calc_sector_size()) & 0xffffff; dma_address = (dma_address + calc_sector_size()) & 0xffffff;
m_register_w[DMA23_16] = m_register_r[DMA23_16] = (dma_address & 0xff0000) >> 16; m_register_w[DMA23_16] = m_register_r[DMA23_16] = (dma_address & 0xff0000) >> 16;
m_register_w[DMA15_8] = m_register_r[DMA15_8] = (dma_address & 0x00ff00) >> 16; m_register_w[DMA15_8] = m_register_r[DMA15_8] = (dma_address & 0x00ff00) >> 8;
m_register_w[DMA7_0] = m_register_r[DMA7_0] = (dma_address & 0x0000ff) >> 16; m_register_w[DMA7_0] = m_register_r[DMA7_0] = (dma_address & 0x0000ff);
if (TRACE_TRANSFER) logerror("%s: New DMA address = %06x\n", tag(), dma_address);
} }
// Decrement the count // Decrement the count
@ -989,8 +1016,8 @@ void hdc9234_device::data_transfer(int& cont)
// What happens when we exceed the highest sector number // What happens when we exceed the highest sector number
// in the track? We have to assume that this is possible // in the track? We have to assume that this is possible
// and that in this case the VERIFY routine fails. // and that in this case the VERIFY routine fails.
m_register_w[DESIRED_SECTOR] = (desired_sector() + 1) & 0xff; if (m_logical) m_register_w[DESIRED_SECTOR] = (desired_sector() + 1) & 0xff;
m_substate = VERIFY1; m_substate = VERIFY2;
cont = NEXT; cont = NEXT;
m_live_state.bit_count_total = 0; m_live_state.bit_count_total = 0;
} }
@ -1012,16 +1039,17 @@ void hdc9234_device::data_transfer(int& cont)
dma_address = (dma_address + calc_sector_size()) & 0xffffff; dma_address = (dma_address + calc_sector_size()) & 0xffffff;
m_register_w[DMA23_16] = m_register_r[DMA23_16] = (dma_address & 0xff0000) >> 16; m_register_w[DMA23_16] = m_register_r[DMA23_16] = (dma_address & 0xff0000) >> 16;
m_register_w[DMA15_8] = m_register_r[DMA15_8] = (dma_address & 0x00ff00) >> 16; m_register_w[DMA15_8] = m_register_r[DMA15_8] = (dma_address & 0x00ff00) >> 8;
m_register_w[DMA7_0] = m_register_r[DMA7_0] = (dma_address & 0x0000ff) >> 16; m_register_w[DMA7_0] = m_register_r[DMA7_0] = (dma_address & 0x0000ff);
if (TRACE_TRANSFER) logerror("%s: New DMA address = %06x\n", tag(), dma_address);
} }
// Decrement the count // Decrement the count
m_register_w[SECTOR_COUNT] = (m_register_w[SECTOR_COUNT]-1) & 0xff; m_register_w[SECTOR_COUNT] = (m_register_w[SECTOR_COUNT]-1) & 0xff;
if (m_register_w[SECTOR_COUNT] != 0 && !m_stop_after_index) if (m_register_w[SECTOR_COUNT] != 0 && !m_stop_after_index)
{ {
m_register_w[DESIRED_SECTOR] = (desired_sector() + 1) & 0xff; if (m_logical) m_register_w[DESIRED_SECTOR] = (desired_sector() + 1) & 0xff;
m_substate = VERIFY1; m_substate = VERIFY2;
cont = NEXT; cont = NEXT;
m_live_state.bit_count_total = 0; m_live_state.bit_count_total = 0;
} }
@ -1462,6 +1490,7 @@ void hdc9234_device::seek_read_id()
bool step_enable = (current_command() & 0x04)==1; bool step_enable = (current_command() & 0x04)==1;
bool wait_seek_comp = (current_command() & 0x02)==1; bool wait_seek_comp = (current_command() & 0x02)==1;
bool do_verify = (current_command() & 0x01)==1; bool do_verify = (current_command() & 0x01)==1;
m_logical = true;
while (cont == NEXT) while (cont == NEXT)
{ {
@ -1474,7 +1503,7 @@ void hdc9234_device::seek_read_id()
if (!do_verify) if (!do_verify)
cont = SUCCESS; cont = SUCCESS;
else else
verify(cont, true); verify(cont);
break; break;
case DATA_TRANSFER: case DATA_TRANSFER:
// No data transfer here. Just exit. // No data transfer here. Just exit.
@ -1512,12 +1541,12 @@ void hdc9234_device::seek_read_id()
*/ */
void hdc9234_device::read_sectors() void hdc9234_device::read_sectors()
{ {
bool logical = (current_command() & 0x04)!=0; m_logical = (current_command() & 0x04)!=0;
if (m_substate == UNDEF) if (m_substate == UNDEF)
{ {
// Command init // Command init
if (TRACE_READ) logerror("%s: READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", tag(), logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); if (TRACE_READ) logerror("%s: READ SECTORS %s command %02x, CHS=(%d,%d,%d)\n", tag(), m_logical? "LOGICAL": "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector());
m_retry_save = m_register_w[RETRY_COUNT]; m_retry_save = m_register_w[RETRY_COUNT];
m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); m_multi_sector = (m_register_w[SECTOR_COUNT] != 1);
m_write = false; m_write = false;
@ -1537,7 +1566,7 @@ void hdc9234_device::read_sectors()
read_id(cont, implied_seek, true); // Always check SEEK COMPLETE read_id(cont, implied_seek, true); // Always check SEEK COMPLETE
break; break;
case VERIFY: case VERIFY:
verify(cont, logical); // for physical, only verify the first sector verify(cont); // for physical, only verify the first sector
break; break;
case DATA_TRANSFER: case DATA_TRANSFER:
data_transfer(cont); data_transfer(cont);
@ -1579,13 +1608,16 @@ void hdc9234_device::read_track()
switch (m_substate) switch (m_substate)
{ {
case WAITINDEX0: case WAITINDEX0:
if (TRACE_READTRACK && TRACE_DETAIL) logerror("%s: Read track - waiting for index hole\n", tag());
if (!index_hole()) if (!index_hole())
{ {
m_substate = WAITINDEX1; m_substate = WAITINDEX1;
cont = NEXT;
} }
else else
{ {
// We're above the index hole; wait for the index line going down // We're above the index hole; wait for the index line going down
if (TRACE_READTRACK && TRACE_DETAIL) logerror("%s: Index hole just passing by ... waiting for next\n", tag());
wait_line(INDEX_LINE, ASSERT_LINE, WAITINDEX1, false); wait_line(INDEX_LINE, ASSERT_LINE, WAITINDEX1, false);
cont = WAIT; cont = WAIT;
} }
@ -1596,13 +1628,15 @@ void hdc9234_device::read_track()
cont = WAIT; cont = WAIT;
break; break;
case TRACKSTART: case TRACKSTART:
if (TRACE_READTRACK && TRACE_DETAIL) logerror("%s: Read track - index hole arrived\n", tag());
live_start(READ_TRACK); live_start(READ_TRACK);
wait_line(INDEX_LINE, ASSERT_LINE, TRACKDONE, true);
cont = WAIT; cont = WAIT;
break; break;
case TRACKDONE: case TRACKDONE:
if (TRACE_READTRACK && TRACE_SUBSTATES) logerror("%s: Track reading done\n", tag()); if (TRACE_READTRACK && TRACE_SUBSTATES) logerror("%s: Track reading done\n", tag());
cont = SUCCESS; cont = SUCCESS;
m_out_dmarq(CLEAR_LINE);
m_out_dip(CLEAR_LINE);
break; break;
} }
} }
@ -1706,7 +1740,7 @@ void hdc9234_device::format_track()
switch (m_substate) switch (m_substate)
{ {
case WAITINDEX0: case WAITINDEX0:
if (TRACE_FORMAT && TRACE_DETAIL) logerror("%s: Formatting - wait for index hole\n", tag()); if (TRACE_FORMAT && TRACE_DETAIL) logerror("%s: Format track - waiting for index hole\n", tag());
if (!index_hole()) if (!index_hole())
{ {
m_substate = WAITINDEX1; m_substate = WAITINDEX1;
@ -1726,7 +1760,7 @@ void hdc9234_device::format_track()
cont = WAIT; cont = WAIT;
break; break;
case TRACKSTART: case TRACKSTART:
if (TRACE_FORMAT && TRACE_DETAIL) logerror("%s: Formatting - index hole arrived\n", tag()); if (TRACE_FORMAT && TRACE_DETAIL) logerror("%s: Format track - index hole arrived\n", tag());
live_start(FORMAT_TRACK); live_start(FORMAT_TRACK);
cont = WAIT; cont = WAIT;
break; break;
@ -1766,11 +1800,11 @@ void hdc9234_device::format_track()
*/ */
void hdc9234_device::write_sectors() void hdc9234_device::write_sectors()
{ {
bool logical = (current_command() & 0x20)!=0; m_logical = (current_command() & 0x20)!=0;
if (m_substate == UNDEF) if (m_substate == UNDEF)
{ {
if (TRACE_WRITE) logerror("%s: WRITE SECTORS %s command %02x, CHS=(%d,%d,%d)\n", tag(), logical? "LOGICAL" : "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector()); if (TRACE_WRITE) logerror("%s: WRITE SECTORS %s command %02x, CHS=(%d,%d,%d)\n", tag(), m_logical? "LOGICAL" : "PHYSICAL", current_command(), desired_cylinder(), desired_head(), desired_sector());
m_multi_sector = (m_register_w[SECTOR_COUNT] != 1); m_multi_sector = (m_register_w[SECTOR_COUNT] != 1);
m_substate = READ_ID; m_substate = READ_ID;
@ -1815,7 +1849,7 @@ void hdc9234_device::write_sectors()
read_id(cont, implied_seek, true); // Always check SEEK COMPLETE read_id(cont, implied_seek, true); // Always check SEEK COMPLETE
break; break;
case VERIFY: case VERIFY:
verify(cont, logical); verify(cont);
break; break;
case DATA_TRANSFER: case DATA_TRANSFER:
m_write = true; m_write = true;
@ -2130,7 +2164,7 @@ void hdc9234_device::live_run_until(attotime limit)
if(slot > 4) if(slot > 4)
{ {
// We successfully read the ID fields; let's wait for the machine time to catch up. // We successfully read the ID fields; let's wait for the machine time to catch up.
if ((current_command() & 0xfe) == 0x5a) if (reading_track())
// Continue if we're reading a complete track // Continue if we're reading a complete track
wait_for_realtime(READ_TRACK_ID_DONE); wait_for_realtime(READ_TRACK_ID_DONE);
else else
@ -2302,7 +2336,7 @@ void hdc9234_device::live_run_until(attotime limit)
// CRC // CRC
if (slot == calc_sector_size()+1) if (slot == calc_sector_size()+1)
{ {
if ((current_command() & 0xfe)==0x5a) if (reading_track())
{ {
// Reading a track? Continue with next ID. // Reading a track? Continue with next ID.
wait_for_realtime(READ_TRACK_ID); wait_for_realtime(READ_TRACK_ID);
@ -2870,7 +2904,6 @@ void hdc9234_device::live_run_hd_until(attotime limit)
break; break;
case READ_ID_FIELDS_INTO_REGS: case READ_ID_FIELDS_INTO_REGS:
if (TRACE_LIVE && m_last_live_state != READ_ID_FIELDS_INTO_REGS) if (TRACE_LIVE && m_last_live_state != READ_ID_FIELDS_INTO_REGS)
{ {
logerror("%s: [%s live] READ_ID_FIELDS_INTO_REGS\n", tag(),tts(m_live_state.time).c_str()); logerror("%s: [%s live] READ_ID_FIELDS_INTO_REGS\n", tag(),tts(m_live_state.time).c_str());
@ -2888,7 +2921,7 @@ void hdc9234_device::live_run_hd_until(attotime limit)
if(slot > 5) if(slot > 5)
{ {
// We successfully read the ID fields; let's wait for the machine time to catch up. // We successfully read the ID fields; let's wait for the machine time to catch up.
if ((current_command() & 0xfe) == 0x5a) if (reading_track())
// Continue if we're reading a complete track // Continue if we're reading a complete track
wait_for_realtime(READ_TRACK_ID_DONE); wait_for_realtime(READ_TRACK_ID_DONE);
else else
@ -2968,7 +3001,8 @@ void hdc9234_device::live_run_hd_until(attotime limit)
// Request bus release // Request bus release
// For hard disk, get it only for the first byte and then keep the bus until the last byte. // For hard disk, get it only for the first byte and then keep the bus until the last byte.
// HD: bit_counter increases by 16 for MFM_BYTE, SEPARATED(_SIMPLE) and by 1 for MFM_BIT // HD: bit_counter increases by 16 for MFM_BYTE, SEPARATED(_SIMPLE) and by 1 for MFM_BIT
if (m_transfer_enabled && (m_live_state.bit_counter == 1 || m_live_state.bit_counter == 16)) // If we are reading a track, the DMA must have already been granted
if (!reading_track() && m_transfer_enabled && (m_live_state.bit_counter == 1 || m_live_state.bit_counter == 16))
{ {
set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); set_bits(m_register_r[INT_STATUS], ST_OVRUN, true);
m_out_dmarq(ASSERT_LINE); m_out_dmarq(ASSERT_LINE);
@ -2999,7 +3033,7 @@ void hdc9234_device::live_run_hd_until(attotime limit)
m_out_dmarq(CLEAR_LINE); m_out_dmarq(CLEAR_LINE);
checkpoint(); checkpoint();
if ((current_command() & 0xfe)==0x5a) if (reading_track())
{ {
// Reading a track? Continue with next ID. // Reading a track? Continue with next ID.
wait_for_realtime(READ_TRACK_ID); wait_for_realtime(READ_TRACK_ID);
@ -3071,7 +3105,7 @@ void hdc9234_device::live_run_hd_until(attotime limit)
case WRITE_TRACK_BYTE: case WRITE_TRACK_BYTE:
if (write_to_mfmhd(limit)) if (write_to_mfmhd(limit))
{ {
logerror("%s: [%s live] write limit reached\n", tag(), tts(m_live_state.time).c_str()); if (TRACE_LIVE) logerror("%s: [%s live] write limit reached\n", tag(), tts(m_live_state.time).c_str());
return; return;
} }
@ -3213,6 +3247,46 @@ void hdc9234_device::live_run_hd_until(attotime limit)
} }
break; break;
// ==================================================
// Track reading (HD)
// ==================================================
//
// Read the next ID fields, then the sector contents.
// Continue until the next index hole shows up (live_abort).
case READ_TRACK:
if (TRACE_LIVE) logerror("%s: READ_TRACK\n", tag());
m_live_state.state = READ_TRACK_ID;
break;
case READ_TRACK_ID:
m_live_state.state = SEARCH_IDAM;
// Ask for access to bus
set_bits(m_register_r[INT_STATUS], ST_OVRUN, true);
m_out_dmarq(ASSERT_LINE);
break;
case READ_TRACK_ID_DONE:
if ((m_register_r[INT_STATUS] & ST_OVRUN)!=0)
{
// We need an ACK right now, or the header bytes will be lost
if (TRACE_FAIL) logerror("%s: No DMA ACK - buffer overrun\n", tag());
set_bits(m_register_r[INT_STATUS], TC_DATAERR, true);
m_live_state.state = IDLE;
return;
}
if (TRACE_LIVE) logerror("%s: READ_TRACK_ID_DONE\n", tag());
m_out_dip(ASSERT_LINE);
// Write the header via DMA
for (int slot = 0; slot < 6; slot++)
m_out_dma(0, m_register_r[id_field[slot]], 0xff);
// Continue with reading the sector data
m_live_state.state = SEARCH_DAM;
wait_line(INDEX_LINE, ASSERT_LINE, TRACKDONE, true);
break;
// =========== HD formatting ============= // =========== HD formatting =============
// Live states for track formatting // Live states for track formatting
// Write GAP 1 // Write GAP 1
@ -3233,12 +3307,12 @@ void hdc9234_device::live_run_hd_until(attotime limit)
case WRITE_GAP1: case WRITE_GAP1:
// GAP1 length is in DMA15_8 // GAP1 length is in DMA15_8
if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing GAP1; size=%d\n", tag(), m_gap1_size); if (TRACE_GAPS) logerror("%s: Writing GAP1; size=%d\n", tag(), m_gap1_size);
write_on_track(encode_hd(0x4e), m_gap1_size, WRITE_IDAM_SYNC); write_on_track(encode_hd(0x4e), m_gap1_size, WRITE_IDAM_SYNC);
break; break;
case WRITE_IDAM_SYNC: case WRITE_IDAM_SYNC:
if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing IDAM sync, size=%d\n", tag(), m_sync_size); if (TRACE_GAPS) logerror("%s: Writing IDAM sync, size=%d\n", tag(), m_sync_size);
write_on_track(encode_hd(0x00), m_sync_size, WRITE_IDAM); write_on_track(encode_hd(0x00), m_sync_size, WRITE_IDAM);
break; break;
@ -3246,7 +3320,7 @@ void hdc9234_device::live_run_hd_until(attotime limit)
// Set the over/underrun flag and hope that it will be cleared before we enter the next state (after writing) // Set the over/underrun flag and hope that it will be cleared before we enter the next state (after writing)
set_bits(m_register_r[INT_STATUS], ST_OVRUN, true); set_bits(m_register_r[INT_STATUS], ST_OVRUN, true);
m_out_dmarq(ASSERT_LINE); m_out_dmarq(ASSERT_LINE);
if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing IDAM and header\n", tag()); if (TRACE_HEADER) logerror("%s: Writing IDAM and header: ", tag());
write_on_track(encode_a1_hd(), 1, WRITE_HEADER); write_on_track(encode_a1_hd(), 1, WRITE_HEADER);
m_live_state.byte_counter = 5; // TODO: Check this for AT mode m_live_state.byte_counter = 5; // TODO: Check this for AT mode
m_live_state.crc = 0xffff; m_live_state.crc = 0xffff;
@ -3261,6 +3335,7 @@ void hdc9234_device::live_run_hd_until(attotime limit)
m_out_dip(ASSERT_LINE); m_out_dip(ASSERT_LINE);
m_live_state.byte_counter--; m_live_state.byte_counter--;
UINT8 headbyte = m_in_dma(0, 0xff); UINT8 headbyte = m_in_dma(0, 0xff);
if (TRACE_HEADER) logerror("%02x ", headbyte);
write_on_track(encode_hd(headbyte), 1, (m_live_state.byte_counter>0)? WRITE_HEADER : WRITE_HEADER_CRC); write_on_track(encode_hd(headbyte), 1, (m_live_state.byte_counter>0)? WRITE_HEADER : WRITE_HEADER_CRC);
if (m_live_state.byte_counter==0) if (m_live_state.byte_counter==0)
@ -3277,29 +3352,32 @@ void hdc9234_device::live_run_hd_until(attotime limit)
if (m_live_state.byte_counter > 0) if (m_live_state.byte_counter > 0)
{ {
UINT8 crct = (m_live_state.crc >> 8) & 0xff; UINT8 crct = (m_live_state.crc >> 8) & 0xff;
if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Write CRC byte %02x\n", tag(), crct); if (TRACE_HEADER) logerror("%02x ", crct);
m_live_state.byte_counter--; m_live_state.byte_counter--;
write_on_track(encode_hd(crct), 1, WRITE_HEADER_CRC); write_on_track(encode_hd(crct), 1, WRITE_HEADER_CRC);
} }
else else
{
if (TRACE_HEADER) logerror("\n");
m_live_state.state = WRITE_GAP2; m_live_state.state = WRITE_GAP2;
}
break; break;
case WRITE_GAP2: case WRITE_GAP2:
if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing GAP2, size=%d\n", tag(), m_gap2_size); if (TRACE_GAPS) logerror("%s: Writing GAP2, size=%d\n", tag(), m_gap2_size);
write_on_track(encode_hd(0x4e), m_gap2_size, WRITE_DAM_SYNC); write_on_track(encode_hd(0x4e), m_gap2_size, WRITE_DAM_SYNC);
break; break;
case WRITE_GAP3: case WRITE_GAP3:
m_sector_count--; m_sector_count--;
if (TRACE_WRITE && TRACE_DETAIL) logerror("%s: Writing GAP3, size=%d\n", tag(), m_gap3_size); if (TRACE_GAPS) logerror("%s: Writing GAP3, size=%d\n", tag(), m_gap3_size);
write_on_track(encode_hd(0x4e), m_gap3_size, (m_sector_count>0)? WRITE_IDAM_SYNC : WRITE_GAP4); write_on_track(encode_hd(0x4e), m_gap3_size, (m_sector_count>0)? WRITE_IDAM_SYNC : WRITE_GAP4);
break; break;
case WRITE_GAP4: case WRITE_GAP4:
// Write bytes up to the end of the track // Write bytes up to the end of the track
wait_line(INDEX_LINE, ASSERT_LINE, TRACKDONE, true); wait_line(INDEX_LINE, ASSERT_LINE, TRACKDONE, true);
if (TRACE_WRITE && TRACE_DETAIL && m_last_live_state != WRITE_GAP4) if (TRACE_GAPS && m_last_live_state != WRITE_GAP4)
{ {
logerror("%s: Writing GAP4\n", tag()); logerror("%s: Writing GAP4\n", tag());
m_last_live_state = WRITE_GAP4; m_last_live_state = WRITE_GAP4;
@ -3309,13 +3387,6 @@ void hdc9234_device::live_run_hd_until(attotime limit)
break; break;
// -------------------------------------------------------- // --------------------------------------------------------
// ==================================================
// Live states for track reading
// ==================================================
// Quite simple. Read the next ID fields, then the sector contents.
// Continue until the next index hole shows up (live_abort).
default: default:
if (TRACE_LIVE) logerror("%s: Unknown state: %02x\n", tag(), m_live_state.state); if (TRACE_LIVE) logerror("%s: Unknown state: %02x\n", tag(), m_live_state.state);
break; break;
@ -3425,14 +3496,17 @@ void hdc9234_device::skip_on_track(int repeat, int next_state)
UINT8 hdc9234_device::get_data_from_encoding(UINT16 raw) UINT8 hdc9234_device::get_data_from_encoding(UINT16 raw)
{ {
return (raw & 0x4000 ? 0x80 : 0x00) | unsigned int value = 0;
(raw & 0x1000 ? 0x40 : 0x00) |
(raw & 0x0400 ? 0x20 : 0x00) | if (!using_floppy() && (m_hd_encoding == SEPARATED || m_hd_encoding == SEPARATED_SIMPLE)) return raw & 0xff;
(raw & 0x0100 ? 0x10 : 0x00) |
(raw & 0x0040 ? 0x08 : 0x00) | for (int i=0; i < 8; i++)
(raw & 0x0010 ? 0x04 : 0x00) | {
(raw & 0x0004 ? 0x02 : 0x00) | value <<= 1;
(raw & 0x0001 ? 0x01 : 0x00); value |= (raw & 0x4000);
raw <<= 2;
}
return (value >> 14) & 0xff;
} }
void hdc9234_device::rollback() void hdc9234_device::rollback()
@ -4257,7 +4331,7 @@ void hdc9234_device::connect_hard_drive(mfm_harddisk_device* harddisk)
{ {
m_harddisk = harddisk; m_harddisk = harddisk;
m_hd_encoding = m_harddisk->get_encoding(); m_hd_encoding = m_harddisk->get_encoding();
if (TRACE_DETAIL) logerror("%s: HD encoding = %d\n", tag(), m_hd_encoding); if (TRACE_SELECT && TRACE_DETAIL) logerror("%s: HD encoding = %d\n", tag(), m_hd_encoding);
} }
/* /*
@ -4332,6 +4406,7 @@ void hdc9234_device::device_reset()
m_line_level = CLEAR_LINE; m_line_level = CLEAR_LINE;
m_live_state.state = IDLE; m_live_state.state = IDLE;
m_live_state.time = attotime::never; m_live_state.time = attotime::never;
m_logical = true;
m_multi_sector = false; m_multi_sector = false;
m_output1 = 0; m_output1 = 0;
m_output2 = 0x80; m_output2 = 0x80;

View File

@ -372,6 +372,9 @@ private:
// Used in RESTORE to find out when to give up // Used in RESTORE to find out when to give up
int m_seek_count; int m_seek_count;
// Read/write logical or physical?
bool m_logical;
// Signals to abort writing // Signals to abort writing
bool m_stopwrite; bool m_stopwrite;
@ -402,6 +405,9 @@ private:
// Is the attached drive ready? // Is the attached drive ready?
bool drive_ready(); bool drive_ready();
// Are we reading a track?
bool reading_track();
// Delivers the desired head // Delivers the desired head
int desired_head(); int desired_head();
@ -437,7 +443,7 @@ private:
// Common subprograms READ ID, VERIFY, and DATA TRANSFER // Common subprograms READ ID, VERIFY, and DATA TRANSFER
void read_id(int& cont, bool implied_seek, bool wait_seek_complete); void read_id(int& cont, bool implied_seek, bool wait_seek_complete);
void verify(int& cont, bool verify_all); void verify(int& cont);
void data_transfer(int& cont); void data_transfer(int& cont);
// =================================================== // ===================================================

View File

@ -23,14 +23,17 @@
#include "ti99_hd.h" #include "ti99_hd.h"
#define TRACE_STEPS 1 #define TRACE_STEPS 0
#define TRACE_SIGNALS 1 #define TRACE_SIGNALS 0
#define TRACE_READ 0 #define TRACE_READ 0
#define TRACE_WRITE 0 #define TRACE_WRITE 0
#define TRACE_CACHE 1 #define TRACE_CACHE 0
#define TRACE_RWTRACK 0 #define TRACE_RWTRACK 0
#define TRACE_BITS 0 #define TRACE_BITS 0
#define TRACE_DETAIL 0 #define TRACE_DETAIL 0
#define TRACE_TIMING 0
#define TRACE_IMAGE 0
#define TRACE_STATE 1
enum enum
{ {
@ -163,7 +166,7 @@ attotime mfm_harddisk_device::track_end_time()
if (!m_revolution_start_time.is_never()) if (!m_revolution_start_time.is_never())
{ {
endtime = m_revolution_start_time + nexttime; endtime = m_revolution_start_time + nexttime;
if (TRACE_DETAIL) logerror("%s: Track start time = %s, end time = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(endtime).c_str()); if (TRACE_TIMING) logerror("%s: Track start time = %s, end time = %s\n", tag(), tts(m_revolution_start_time).c_str(), tts(endtime).c_str());
} }
return endtime; return endtime;
} }
@ -218,7 +221,7 @@ void mfm_harddisk_device::device_timer(emu_timer &timer, device_timer_id id, int
{ {
m_ready = true; m_ready = true;
m_recalibrated = true; m_recalibrated = true;
if (TRACE_SIGNALS) logerror("%s: Spinup complete, drive recalibrated and positioned at cylinder %d; drive is READY\n", tag(), m_current_cylinder); if (TRACE_STATE) logerror("%s: Spinup complete, drive recalibrated and positioned at cylinder %d; drive is READY\n", tag(), m_current_cylinder);
if (!m_ready_cb.isnull()) m_ready_cb(this, ASSERT_LINE); if (!m_ready_cb.isnull()) m_ready_cb(this, ASSERT_LINE);
} }
else else
@ -358,7 +361,7 @@ bool mfm_harddisk_device::find_position(attotime &from_when, const attotime &lim
// Reached the end // Reached the end
if (bytepos >= 10416) 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(from_when).c_str()); if (TRACE_TIMING) 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; m_revolution_start_time += m_rev_time;
cell = (from_when - m_revolution_start_time).as_ticks(10000000); cell = (from_when - m_revolution_start_time).as_ticks(10000000);
bytepos = cell / 16; bytepos = cell / 16;
@ -366,7 +369,7 @@ bool mfm_harddisk_device::find_position(attotime &from_when, const attotime &lim
if (bytepos < 0) 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(from_when).c_str()); if (TRACE_TIMING) 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; bytepos = 0;
} }
bit = cell % 16; bit = cell % 16;
@ -450,7 +453,7 @@ bool mfm_harddisk_device::write(attotime &from_when, const attotime &limit, UINT
track[bytepos] = cdata; 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); if (TRACE_WRITE) if ((bitpos&0x0f)==0) logerror("%s: Wrote data=%04x (c=%d,h=%d) at position %04x\n", tag(), track[bytepos], m_current_cylinder, m_current_head, bytepos);
return false; return false;
} }
@ -809,11 +812,15 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde
int sec_il_start = 0; int sec_il_start = 0;
int sec_number = 0; int sec_number = 0;
int identfield = 0;
int cylfield = 0;
int headfield = 0;
int sizefield = (size >> 7)-1;
// Round up // Round up
int delta = (sectorcount + interleave-1) / interleave; int delta = (sectorcount + interleave-1) / interleave;
if (TRACE_DETAIL) logerror("%s: cyl=%02x head=%02x: sector sequence = ", tag(), cylinder&0xff, head&0xff); if (TRACE_DETAIL) logerror("%s: cyl=%d head=%d: sector sequence = ", tag(), cylinder, head);
for (int sector = 0; sector < sectorcount; sector++) for (int sector = 0; sector < sectorcount; sector++)
{ {
if (TRACE_DETAIL) logerror("%02d ", sec_number); if (TRACE_DETAIL) logerror("%02d ", sec_number);
@ -823,13 +830,18 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde
// Write IDAM // Write IDAM
mfm_encode_a1(slot, position); mfm_encode_a1(slot, position);
mfm_encode(slot, position, cylinder_to_ident(cylinder));
// Write header (according to MDM5: CHSL) // Write header
mfm_encode(slot, position, cylinder & 0xff); identfield = cylinder_to_ident(cylinder);
mfm_encode(slot, position, head & 0xff); cylfield = cylinder & 0xff;
headfield = ((cylinder & 0x700)>>4) | (head&0x0f);
mfm_encode(slot, position, identfield);
mfm_encode(slot, position, cylfield);
mfm_encode(slot, position, headfield);
mfm_encode(slot, position, sec_number); mfm_encode(slot, position, sec_number);
mfm_encode(slot, position, (size >> 7)-1); mfm_encode(slot, position, sizefield);
// logerror("%s: Created header (%02x,%02x,%02x,%02x)\n", tag(), identfield, cylfield, headfield, sector);
// Write CRC for header. // Write CRC for header.
int crc = m_current_crc; int crc = m_current_crc;
@ -847,9 +859,16 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde
mfm_encode(slot, position, 0xfb); mfm_encode(slot, position, 0xfb);
// Get sector content from CHD // Get sector content from CHD
chd_error state = m_chd->read_units(chs_to_lba(cylinder, head, sec_number), sector_content); int lbaposition = chs_to_lba(cylinder, head, sec_number);
if (state != CHDERR_NONE) if (lbaposition>=0)
break; {
chd_error state = m_chd->read_units(lbaposition, sector_content);
if (state != CHDERR_NONE) break;
}
else
{
logerror("%s: Invalid CHS data (%d,%d,%d); not loading from CHD\n", tag(), cylinder, head, sector);
}
for (int i=0; i < size; i++) for (int i=0; i < size; i++)
mfm_encode(slot, position, sector_content[i]); mfm_encode(slot, position, sector_content[i]);
@ -874,7 +893,7 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde
{ {
// Fill the rest with 0x4e // Fill the rest with 0x4e
mfm_encode(slot, position, 0x4e, TRACKIMAGE_SIZE-position); mfm_encode(slot, position, 0x4e, TRACKIMAGE_SIZE-position);
if (TRACE_DETAIL) if (TRACE_IMAGE)
{ {
showtrack(slot->encdata, TRACKIMAGE_SIZE); showtrack(slot->encdata, TRACKIMAGE_SIZE);
} }
@ -929,6 +948,7 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot)
UINT8 byte; UINT8 byte;
bool search_header = true; bool search_header = true;
int ident = 0;
int cylinder = 0; int cylinder = 0;
int head = 0; int head = 0;
int sector = 0; int sector = 0;
@ -939,6 +959,16 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot)
int interleave_prec = -1; int interleave_prec = -1;
bool check_interleave = true; bool check_interleave = true;
if (TRACE_IMAGE)
{
for (int i=0; i < TRACKIMAGE_SIZE; i++)
{
if ((i % 16)==0) logerror("\n%04x: ", i);
logerror("%02x ", (m_encoding==MFM_BITS || m_encoding==MFM_BYTE)? mfm_decode(track[i]) : (track[i]&0xff));
}
logerror("\n");
}
// We have to go through the bytes of the track and save a sector as soon as one shows up // We have to go through the bytes of the track and save a sector as soon as one shows up
while (bytepos < TRACKIMAGE_SIZE) while (bytepos < TRACKIMAGE_SIZE)
{ {
@ -979,10 +1009,17 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot)
if (search_header) if (search_header)
{ {
// Found a header // Found a header
// ident = buffer[0]; // check? ident = buffer[0];
cylinder = buffer[1]; // Highest three bits are in the head field
head = buffer[2]; cylinder = buffer[1] | ((buffer[2]&0x70)<<4);
head = buffer[2] & 0x0f;
sector = buffer[3]; sector = buffer[3];
int identexp = cylinder_to_ident(cylinder);
if (identexp != ident)
{
logerror("%s: MFM HD: Field error; ident = %02x (expected %02x) for sector chs=(%d,%d,%d)\n", tag(), ident, identexp, cylinder, head, sector);
}
// Count the sectors for the interleave // Count the sectors for the interleave
if (check_interleave) if (check_interleave)
@ -1005,6 +1042,9 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot)
{ {
// Sector contents // Sector contents
// Write the sectors to the CHD // Write the sectors to the CHD
int lbaposition = chs_to_lba(cylinder, head, sector);
if (lbaposition>=0)
{
if (TRACE_DETAIL) logerror("%s: MFM HD: Writing sector chs=(%d,%d,%d) to CHD\n", tag(), cylinder, head, sector); 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); chd_error state = m_chd->write_units(chs_to_lba(cylinder, head, sector), buffer);
@ -1012,12 +1052,18 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot)
{ {
logerror("%s: MFM HD: Write error while writing sector chs=(%d,%d,%d)\n", tag(), cylinder, head, sector); logerror("%s: MFM HD: Write error while writing sector chs=(%d,%d,%d)\n", tag(), cylinder, head, sector);
} }
}
else
{
logerror("%s: Invalid CHS data in track image: (%d,%d,%d); not saving to CHD\n", tag(), cylinder, head, sector);
}
search_header = true; search_header = true;
} }
} }
else else
{ {
logerror("%s: MFM HD: CRC error\n", tag()); logerror("%s: MFM HD: CRC error in %s of (%d,%d,%d)\n", tag(), search_header? "header" : "data", cylinder, head, sector);
search_header = true; search_header = true;
} }
// search next A1 // search next A1