diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/emu/bus/ti99_peb/hfdc.c | 4 | ||||
-rw-r--r-- | src/emu/machine/ti99_hd.c | 274 | ||||
-rw-r--r-- | src/emu/machine/ti99_hd.h | 73 |
3 files changed, 248 insertions, 103 deletions
diff --git a/src/emu/bus/ti99_peb/hfdc.c b/src/emu/bus/ti99_peb/hfdc.c index f4facb82034..aa286cbeee1 100644 --- a/src/emu/bus/ti99_peb/hfdc.c +++ b/src/emu/bus/ti99_peb/hfdc.c @@ -1012,7 +1012,9 @@ SLOT_INTERFACE_END static SLOT_INTERFACE_START( hfdc_harddisks ) SLOT_INTERFACE( "generic", MFMHD_GENERIC ) // Generic high-level emulation - SLOT_INTERFACE( "st225", MFMHD_ST225 ) // Seagate ST-225 and others + SLOT_INTERFACE( "st213", MFMHD_ST213 ) // Seagate ST-213 (10 MB) + SLOT_INTERFACE( "st225", MFMHD_ST225 ) // Seagate ST-225 (20 MB) + SLOT_INTERFACE( "st251", MFMHD_ST251 ) // Seagate ST-251 (40 MB) SLOT_INTERFACE_END MACHINE_CONFIG_FRAGMENT( ti99_hfdc ) diff --git a/src/emu/machine/ti99_hd.c b/src/emu/machine/ti99_hd.c index 5895d6a0243..b74ce8f6289 100644 --- a/src/emu/machine/ti99_hd.c +++ b/src/emu/machine/ti99_hd.c @@ -34,6 +34,7 @@ #define TRACE_TIMING 0 #define TRACE_IMAGE 0 #define TRACE_STATE 1 +#define TRACE_CONFIG 1 enum { @@ -51,7 +52,6 @@ enum }; #define TRACKSLOTS 5 -#define TRACKIMAGE_SIZE 10416 // Provide the buffer for a complete track, including preambles and gaps #define OFFLIMIT -1 @@ -69,8 +69,18 @@ mfm_harddisk_device::mfm_harddisk_device(const machine_config &mconfig, device_t { m_spinupms = 10000; m_cachelines = TRACKSLOTS; - m_max_cylinder = 0; + m_max_cylinders = 0; + m_phys_cylinders = 0; // We will get this value for generic drives from the image m_max_heads = 0; + m_cell_size = 100; + m_rpm = 3600; // MFM drives have a revolution rate of 3600 rpm (i.e. 60/sec) + m_trackimage_size = (int)((60000000000L / (m_rpm * m_cell_size)) / 16 + 1); + m_cache = NULL; + // We will calculate default values from the time specs later. + m_seeknext_time = 0; + m_maxseek_time = 0; + m_actual_cylinders = 0; + m_park_pos = 0; } mfm_harddisk_device::~mfm_harddisk_device() @@ -84,17 +94,15 @@ void mfm_harddisk_device::device_start() m_seek_timer = timer_alloc(SEEK_TM); m_cache_timer = timer_alloc(CACHE_TM); - m_rev_time = attotime::from_hz(60); + m_rev_time = attotime::from_hz(m_rpm/60); + m_index_timer->adjust(attotime::from_hz(m_rpm/60), 0, attotime::from_hz(m_rpm/60)); - // MFM drives have a revolution rate of 3600 rpm (i.e. 60/sec) - m_index_timer->adjust(attotime::from_hz(60), 0, attotime::from_hz(60)); - - m_current_cylinder = 615; // Park position + m_current_cylinder = m_park_pos; // Park position 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 + // In 5 second periods, check whether the cache has dirty lines m_cache_timer->adjust(attotime::from_msec(5000), 0, attotime::from_msec(5000)); } @@ -111,15 +119,41 @@ void mfm_harddisk_device::device_reset() void mfm_harddisk_device::device_stop() { - global_free(m_cache); + if (m_cache!=NULL) global_free(m_cache); } +/* + Load the image from the CHD. We also calculate the head timing here + because we need the number of cylinders, and for generic drives we get + them from the CHD. +*/ bool mfm_harddisk_device::call_load() { bool loaded = harddisk_image_device::call_load(); if (loaded==IMAGE_INIT_PASS) { - m_cache->init(get_chd_file(), tag(), m_max_cylinder, m_max_heads, m_cachelines, m_encoding); + m_cache->init(get_chd_file(), tag(), m_trackimage_size, m_max_cylinders, m_max_heads, m_cachelines, m_encoding); + + // Head timing + // We assume that the real times are 80% of the max times + // The single-step time includes the settle time, so does the max time + // From that we calculate the actual cylinder-by-cylinder time and the settle time + + m_actual_cylinders = m_cache->get_cylinders(); + if (m_phys_cylinders == 0) m_phys_cylinders = m_actual_cylinders+1; + + m_park_pos = m_phys_cylinders-1; + + float realnext = (m_seeknext_time==0)? 10 : (m_seeknext_time * 0.8); + float realmax = (m_maxseek_time==0)? (m_actual_cylinders * 0.2) : (m_maxseek_time * 0.8); + float settle_us = ((m_actual_cylinders-1.0) * realnext - realmax) / (m_actual_cylinders-2.0) * 1000; + float step_us = realnext * 1000 - settle_us; + if (TRACE_CONFIG) logerror("%s: Calculated settle time: %0.2f ms, step: %d us\n", tag(), settle_us/1000, (int)step_us); + + m_settle_time = attotime::from_usec((int)settle_us); + m_step_time = attotime::from_usec((int)step_us); + + m_current_cylinder = m_park_pos; } else { @@ -130,7 +164,7 @@ bool mfm_harddisk_device::call_load() void mfm_harddisk_device::call_unload() { - m_cache->cleanup(); + if (m_cache!=NULL) m_cache->cleanup(); harddisk_image_device::call_unload(); } @@ -176,7 +210,7 @@ void mfm_harddisk_device::device_timer(emu_timer &timer, device_timer_id id, int switch (id) { case INDEX_TM: - /* Simple index hole handling. We assume that there is only a short pulse. */ + // Simple index hole handling. We assume that there is only a short pulse. m_revolution_start_time = machine().time(); if (!m_index_pulse_cb.isnull()) { @@ -207,7 +241,7 @@ void mfm_harddisk_device::device_timer(emu_timer &timer, device_timer_id id, int { // Start the settle timer m_step_phase = STEP_SETTLE; - m_seek_timer->adjust(attotime::from_usec(16800)); + m_seek_timer->adjust(m_settle_time); if (TRACE_STEPS && TRACE_DETAIL) logerror("%s: Arrived at target cylinder %d, settling ...\n", tag(), m_current_cylinder); } break; @@ -241,7 +275,7 @@ void mfm_harddisk_device::recalibrate() { if (TRACE_STEPS) logerror("%s: Recalibrate to track 0\n", tag()); direction_in_w(CLEAR_LINE); - while (-m_track_delta < 620) + while (-m_track_delta < m_phys_cylinders) { step_w(ASSERT_LINE); step_w(CLEAR_LINE); @@ -254,14 +288,16 @@ void mfm_harddisk_device::head_move() if (steps < 0) steps = -steps; if (TRACE_STEPS) logerror("%s: Moving head by %d step(s) %s\n", tag(), steps, (m_track_delta<0)? "outward" : "inward"); - int disttime = steps*200; + // We simulate the head movement by pausing for n*step_time with n being the cylinder delta m_step_phase = STEP_MOVING; - m_seek_timer->adjust(attotime::from_usec(disttime)); + m_seek_timer->adjust(m_step_time * steps); + + if (TRACE_TIMING) logerror("%s: Head movement takes %s time\n", tag(), tts(m_step_time * steps).c_str()); // We pretend that we already arrived // TODO: Check auto truncation? m_current_cylinder += m_track_delta; if (m_current_cylinder < 0) m_current_cylinder = 0; - if (m_current_cylinder > 670) m_current_cylinder = 670; + if (m_current_cylinder >= m_actual_cylinders) m_current_cylinder = m_actual_cylinders-1; m_track_delta = 0; } @@ -303,14 +339,6 @@ void mfm_harddisk_device::direction_in_w(line_state line) - When the timer expires (mode=settle) - When the counter is not zero, go to (1) - When the counter is zero, signal seek_complete; done - - Step timing: - per track = 20 ms max, full seek: 150 ms max (615 tracks); both including settling time - We assume t(1) = 17; t(615)=140 - t(i) = s+d*i - s=(615*t(1)-t(615))/614 - d=t(1)-s - s=16800 us, d=200 us */ void mfm_harddisk_device::step_w(line_state line) @@ -328,12 +356,12 @@ void mfm_harddisk_device::step_w(line_state line) // Counter will be adjusted according to the direction (+-1) m_track_delta += (m_seek_inward)? +1 : -1; if (TRACE_STEPS && TRACE_DETAIL) logerror("%s: Got seek pulse; track delta %d\n", tag(), m_track_delta); - if (m_track_delta < -670 || m_track_delta > 670) + if (m_track_delta < -m_phys_cylinders || m_track_delta > m_phys_cylinders) { if (TRACE_STEPS) logerror("%s: Excessive step pulses - doing auto-truncation\n", tag()); m_autotruncation = true; } - m_seek_timer->adjust(attotime::from_usec(250)); + m_seek_timer->adjust(attotime::from_usec(250)); // Start step collect timer } m_step_line = line; } @@ -345,25 +373,27 @@ void mfm_harddisk_device::step_w(line_state line) */ bool mfm_harddisk_device::find_position(attotime &from_when, const attotime &limit, int &bytepos, int &bit) { + // Frequency + UINT32 freq = 1000000000/m_cell_size; + // 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) - int cell = (from_when - m_revolution_start_time).as_ticks(10000000); + int cell = (from_when - m_revolution_start_time).as_ticks(freq); - from_when += attotime::from_nsec((m_encoding==MFM_BITS)? 100 : 1600); + from_when += attotime::from_nsec((m_encoding==MFM_BITS)? m_cell_size : (16*m_cell_size)); if (from_when > limit) return true; bytepos = cell / 16; // Reached the end - if (bytepos >= 10416) + if (bytepos >= m_trackimage_size) { 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; - cell = (from_when - m_revolution_start_time).as_ticks(10000000); + cell = (from_when - m_revolution_start_time).as_ticks(freq); bytepos = cell / 16; } @@ -464,15 +494,48 @@ mfm_hd_generic_device::mfm_hd_generic_device(const machine_config &mconfig, cons const device_type MFMHD_GENERIC = &device_creator<mfm_hd_generic_device>; +/* + Various models. +*/ +mfm_hd_st213_device::mfm_hd_st213_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: mfm_harddisk_device(mconfig, MFMHD_ST213, "Seagate ST-213 MFM hard disk", tag, owner, clock, "mfm_hd_st213", __FILE__) +{ + m_phys_cylinders = 670; + m_max_cylinders = 615; // 0..614 + m_park_pos = 620; + m_max_heads = 2; + m_seeknext_time = 20; // time for one step including settle time + m_maxseek_time = 150; +} + +const device_type MFMHD_ST213 = &device_creator<mfm_hd_st213_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__) { - m_max_cylinder = 615; + m_phys_cylinders = 670; + m_max_cylinders = 615; + m_park_pos = 620; m_max_heads = 4; + m_seeknext_time = 20; + m_maxseek_time = 150; } const device_type MFMHD_ST225 = &device_creator<mfm_hd_st225_device>; +mfm_hd_st251_device::mfm_hd_st251_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) +: mfm_harddisk_device(mconfig, MFMHD_ST251, "Seagate ST-251 MFM hard disk", tag, owner, clock, "mfm_hd_st251", __FILE__) +{ + m_phys_cylinders = 821; + m_max_cylinders = 820; + m_park_pos = 820; + m_max_heads = 6; + m_seeknext_time = 8; + m_maxseek_time = 70; +} + +const device_type MFMHD_ST251 = &device_creator<mfm_hd_st251_device>; + // =========================================================== // Track cache // The cache holds track images to be read by the controller. @@ -483,6 +546,7 @@ mfmhd_trackimage_cache::mfmhd_trackimage_cache(): m_tracks(NULL) { m_current_crc = 0; + m_tracksize = 0; } mfmhd_trackimage_cache::~mfmhd_trackimage_cache() @@ -507,8 +571,8 @@ void mfmhd_trackimage_cache::write_back_one() { 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); + write_track(m_chd, current->encdata, m_tracksize, current->cylinder, current->head); + current->dirty = false; break; } mfmhd_trackimage* currenttmp = current->next; @@ -525,7 +589,11 @@ void mfmhd_trackimage_cache::cleanup() 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); + if (current->dirty) + { + write_track(m_chd, current->encdata, m_tracksize, current->cylinder, current->head); + current->dirty = false; + } mfmhd_trackimage* currenttmp = current->next; current = currenttmp; } @@ -545,7 +613,7 @@ 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) +void mfmhd_trackimage_cache::init(chd_file* chdfile, const char* dtag, int tracksize, int maxcyl, int maxhead, int trackslots, mfmhd_enc_t encoding) { m_encoding = encoding; m_tagdev = dtag; @@ -557,6 +625,7 @@ void mfmhd_trackimage_cache::init(chd_file* chdfile, const char* dtag, int maxcy std::string metadata; m_calc_interleave = 0; + m_tracksize = tracksize; m_chd = chdfile; if (chdfile==NULL) @@ -571,14 +640,16 @@ void mfmhd_trackimage_cache::init(chd_file* chdfile, const char* dtag, int maxcy { throw emu_fatalerror("Failed to read CHD metadata"); } + if (TRACE_CONFIG) logerror("%s: CHD metadata: %s\n", tag(), metadata.c_str()); // Parse the metadata if (sscanf(metadata.c_str(), HARD_DISK_METADATA_FORMAT, &m_cylinders, &m_heads, &m_sectors_per_track, &m_sectorsize) != 4) { throw emu_fatalerror("Invalid metadata"); } + if (TRACE_CONFIG) logerror("%s: CHD image has geometry cyl=%d, head=%d, sect=%d, size=%d\n", tag(), m_cylinders, m_heads, m_sectors_per_track, m_sectorsize); - if (maxcyl != 0 && m_cylinders > maxcyl) + if (maxcyl != 0 && (m_cylinders != maxcyl || m_heads != maxhead)) { throw emu_fatalerror("Image geometry does not fit this kind of hard drive: drive=(%d,%d), image=(%d,%d)", maxcyl, maxhead, m_cylinders, m_heads); } @@ -592,10 +663,13 @@ void mfmhd_trackimage_cache::init(chd_file* chdfile, const char* dtag, int maxcy if (TRACE_CACHE && TRACE_DETAIL) logerror("%s: MFM HD allocate cache slot\n", tag()); previous = current; current = global_alloc(mfmhd_trackimage); - current->encdata = global_alloc_array(UINT16, TRACKIMAGE_SIZE); + current->encdata = global_alloc_array(UINT16, tracksize); // Load the first tracks into the slots - state = load_track(current, cylinder, head, 32, 256, 4); + state = load_track(m_chd, current->encdata, m_tracksize, cylinder, head); + current->dirty = false; + current->cylinder = cylinder; + current->head = head; if (state != CHDERR_NONE) throw emu_fatalerror("Cannot load (c=%d,h=%d) from hard disk", cylinder, head); @@ -700,8 +774,15 @@ UINT16* mfmhd_trackimage_cache::get_trackimage(int cylinder, int head) current = previous->next; if (TRACE_CACHE) logerror("%s: MFM HD cache: evict line (c=%d,h=%d)\n", tag(), current->cylinder, current->head); - if (current->dirty) write_back(current); - state = load_track(current, cylinder, head, 32, 256, 4); + if (current->dirty) + { + write_track(m_chd, current->encdata, m_tracksize, current->cylinder, current->head); + current->dirty = false; + } + state = load_track(m_chd, current->encdata, m_tracksize, cylinder, head); + current->dirty = false; + current->cylinder = cylinder; + current->head = head; } // If we are here we have a CHD error. return NULL; @@ -710,19 +791,19 @@ UINT16* mfmhd_trackimage_cache::get_trackimage(int cylinder, int head) /* Create MFM encoding. */ -void mfmhd_trackimage_cache::mfm_encode(mfmhd_trackimage* slot, int& position, UINT8 byte, int count) +void mfmhd_trackimage_cache::mfm_encode(UINT16* trackimage, int& position, UINT8 byte, int count) { - mfm_encode_mask(slot, position, byte, count, 0x00); + mfm_encode_mask(trackimage, position, byte, count, 0x00); } -void mfmhd_trackimage_cache::mfm_encode_a1(mfmhd_trackimage* slot, int& position) +void mfmhd_trackimage_cache::mfm_encode_a1(UINT16* trackimage, int& position) { m_current_crc = 0xffff; - mfm_encode_mask(slot, position, 0xa1, 1, 0x04); + mfm_encode_mask(trackimage, position, 0xa1, 1, 0x04); // 0x443b; CRC for A1 } -void mfmhd_trackimage_cache::mfm_encode_mask(mfmhd_trackimage* slot, int& position, UINT8 byte, int count, int mask) +void mfmhd_trackimage_cache::mfm_encode_mask(UINT16* trackimage, int& position, UINT8 byte, int count, int mask) { UINT16 encclock = 0; UINT16 encdata = 0; @@ -768,7 +849,7 @@ void mfmhd_trackimage_cache::mfm_encode_mask(mfmhd_trackimage* slot, int& positi else encclock <<= 8; - slot->encdata[position++] = (encclock | encdata); + trackimage[position++] = (encclock | encdata); // When we write the byte multiple times, check whether the next encoding // differs from the previous because of the last bit @@ -781,7 +862,7 @@ void mfmhd_trackimage_cache::mfm_encode_mask(mfmhd_trackimage* slot, int& positi for (int j=1; j < count; j++) { - slot->encdata[position++] = (encclock | encdata); + trackimage[position++] = (encclock | encdata); m_current_crc = ccitt_crc16_one(m_current_crc, byte); } } @@ -790,10 +871,14 @@ 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) +chd_error mfmhd_trackimage_cache::load_track(chd_file* file, UINT16* trackimage, int tracksize, int cylinder, int head) { chd_error state = CHDERR_NONE; + int sectorcount = 32; + int size = 256; + int interleave = 4; + UINT8 sector_content[1024]; if (TRACE_RWTRACK) logerror("%s: MFM HD cache: load track (c=%d,h=%d) from CHD\n", tag(), cylinder, head); @@ -808,7 +893,7 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde // both be set to the same number and loaded in the appropriate registers. // Gap 1 - mfm_encode(slot, position, 0x4e, 16); + mfm_encode(trackimage, position, 0x4e, 16); int sec_il_start = 0; int sec_number = 0; @@ -826,43 +911,43 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde if (TRACE_DETAIL) logerror("%02d ", sec_number); // Sync gap - mfm_encode(slot, position, 0x00, 13); + mfm_encode(trackimage, position, 0x00, 13); // Write IDAM - mfm_encode_a1(slot, position); + mfm_encode_a1(trackimage, position); // Write header identfield = cylinder_to_ident(cylinder); 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, sizefield); + mfm_encode(trackimage, position, identfield); + mfm_encode(trackimage, position, cylfield); + mfm_encode(trackimage, position, headfield); + mfm_encode(trackimage, position, sec_number); + mfm_encode(trackimage, position, sizefield); // logerror("%s: Created header (%02x,%02x,%02x,%02x)\n", tag(), identfield, cylfield, headfield, sector); // Write CRC for header. int crc = m_current_crc; - mfm_encode(slot, position, (crc >> 8) & 0xff); - mfm_encode(slot, position, crc & 0xff); + mfm_encode(trackimage, position, (crc >> 8) & 0xff); + mfm_encode(trackimage, position, crc & 0xff); // Gap 2 - mfm_encode(slot, position, 0x4e, 3); + mfm_encode(trackimage, position, 0x4e, 3); // Sync - mfm_encode(slot, position, 0x00, 13); + mfm_encode(trackimage, position, 0x00, 13); // Write DAM - mfm_encode_a1(slot, position); - mfm_encode(slot, position, 0xfb); + mfm_encode_a1(trackimage, position); + mfm_encode(trackimage, position, 0xfb); // Get sector content from CHD int lbaposition = chs_to_lba(cylinder, head, sec_number); if (lbaposition>=0) { - chd_error state = m_chd->read_units(lbaposition, sector_content); + chd_error state = file->read_units(lbaposition, sector_content); if (state != CHDERR_NONE) break; } else @@ -871,16 +956,16 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde } for (int i=0; i < size; i++) - mfm_encode(slot, position, sector_content[i]); + mfm_encode(trackimage, position, sector_content[i]); // Write CRC for content. crc = m_current_crc; - mfm_encode(slot, position, (crc >> 8) & 0xff); - mfm_encode(slot, position, crc & 0xff); + mfm_encode(trackimage, position, (crc >> 8) & 0xff); + mfm_encode(trackimage, position, crc & 0xff); // Gap 3 - mfm_encode(slot, position, 0x00, 3); - mfm_encode(slot, position, 0x4e, 19); + mfm_encode(trackimage, position, 0x00, 3); + mfm_encode(trackimage, position, 0x4e, 19); // Calculate next sector number sec_number += delta; @@ -892,17 +977,12 @@ chd_error mfmhd_trackimage_cache::load_track(mfmhd_trackimage* slot, int cylinde if (state == CHDERR_NONE) { // Fill the rest with 0x4e - mfm_encode(slot, position, 0x4e, TRACKIMAGE_SIZE-position); + mfm_encode(trackimage, position, 0x4e, tracksize-position); if (TRACE_IMAGE) { - showtrack(slot->encdata, TRACKIMAGE_SIZE); + showtrack(trackimage, tracksize); } } - - slot->dirty = false; - slot->cylinder = cylinder; - slot->head = head; - return state; } @@ -932,14 +1012,12 @@ UINT8 mfmhd_trackimage_cache::mfm_decode(UINT16 raw) 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) +void mfmhd_trackimage_cache::write_track(chd_file* file, UINT16* trackimage, int tracksize, int current_cylinder, int current_head) { - if (TRACE_CACHE) 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(), current_cylinder, current_head); UINT8 buffer[1024]; // for header or sector content - UINT16 *track = slot->encdata; - int bytepos = 0; int state = SEARCH_A1; int count = 0; @@ -961,23 +1039,23 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot) if (TRACE_IMAGE) { - for (int i=0; i < TRACKIMAGE_SIZE; i++) + for (int i=0; i < tracksize; 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("%02x ", (m_encoding==MFM_BITS || m_encoding==MFM_BYTE)? mfm_decode(trackimage[i]) : (trackimage[i]&0xff)); } logerror("\n"); } // 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 < tracksize) { 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)) + if (((m_encoding==MFM_BITS || m_encoding==MFM_BYTE) && trackimage[bytepos]==0x4489) + || (m_encoding==SEPARATED && trackimage[bytepos]==0x0aa1) + || (m_encoding==SEPARATED_SIMPLE && trackimage[bytepos]==0xffa1)) { state = FOUND_A1; count = search_header? 7 : 259; @@ -991,9 +1069,9 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot) // read next values into array if (m_encoding==MFM_BITS || m_encoding==MFM_BYTE) { - byte = mfm_decode(track[bytepos]); + byte = mfm_decode(trackimage[bytepos]); } - else byte = (track[bytepos] & 0xff); + else byte = (trackimage[bytepos] & 0xff); crc = ccitt_crc16_one(crc, byte); // logerror("%s: MFM HD: Byte = %02x, CRC=%04x\n", tag(), byte, crc); @@ -1021,6 +1099,16 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot) logerror("%s: MFM HD: Field error; ident = %02x (expected %02x) for sector chs=(%d,%d,%d)\n", tag(), ident, identexp, cylinder, head, sector); } + if (cylinder != current_cylinder) + { + logerror("%s: MFM HD: Sector header of sector %d defines cylinder = %02x (should be %02x)\n", tag(), sector, cylinder, current_cylinder); + } + + if (head != current_head) + { + logerror("%s: MFM HD: Sector header of sector %d defines head = %02x (should be %02x)\n", tag(), sector, head, current_head); + } + // Count the sectors for the interleave if (check_interleave) { @@ -1045,8 +1133,8 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot) 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); - chd_error state = m_chd->write_units(chs_to_lba(cylinder, head, sector), buffer); + if (TRACE_DETAIL) logerror("%s: MFM HD: Writing sector chs=(%d,%d,%d) to CHD\n", tag(), current_cylinder, current_head, sector); + chd_error state = file->write_units(chs_to_lba(current_cylinder, current_head, sector), buffer); if (state != CHDERR_NONE) { @@ -1079,8 +1167,6 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot) break; } } - // Clear the dirty flag - slot->dirty = false; if (check_interleave == false) { @@ -1090,7 +1176,7 @@ void mfmhd_trackimage_cache::write_back(mfmhd_trackimage* slot) 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); + logerror("%s: MFM HD cache: write back complete (c=%d,h=%d), interleave = %d\n", tag(), current_cylinder, current_head, m_calc_interleave); } } diff --git a/src/emu/machine/ti99_hd.h b/src/emu/machine/ti99_hd.h index c6cd8acccfc..c33426983e8 100644 --- a/src/emu/machine/ti99_hd.h +++ b/src/emu/machine/ti99_hd.h @@ -44,20 +44,21 @@ 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); + void init(chd_file* chdfile, const char* tag, int tracksize, 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(); + int get_cylinders() { return m_cylinders; } 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); + void mfm_encode(UINT16* trackimage, int& position, UINT8 byte, int count=1); + void mfm_encode_a1(UINT16* trackimage, int& position); + void mfm_encode_mask(UINT16* trackimage, 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); + chd_error load_track(chd_file* file, UINT16* trackimage, int tracksize, int cylinder, int head); + void write_track(chd_file* file, UINT16* trackimage, int tracksize, int cylinder, int head); int chs_to_lba(int cylinder, int head, int sector); UINT8 cylinder_to_ident(int cylinder); @@ -72,6 +73,7 @@ private: int m_heads; int m_sectors_per_track; int m_sectorsize; + int m_tracksize; int m_calc_interleave; void showtrack(UINT16* enctrack, int length); @@ -140,12 +142,20 @@ protected: ready_cb m_ready_cb; seek_complete_cb m_seek_complete_cb; - int m_max_cylinder; - int m_max_heads; + int m_max_cylinders; + int m_phys_cylinders; + int m_actual_cylinders; // after reading the CHD + int m_max_heads; + int m_park_pos; + int m_maxseek_time; + int m_seeknext_time; private: mfmhd_enc_t m_encoding; + int m_cell_size; // nanoseconds + int m_trackimage_size; // number of 16-bit cell blocks (data bytes) int m_spinupms; + int m_rpm; int m_cachelines; bool m_ready; int m_current_cylinder; @@ -163,6 +173,9 @@ private: attotime m_revolution_start_time; attotime m_rev_time; + attotime m_settle_time; + attotime m_step_time; + mfmhd_trackimage_cache* m_cache; void prepare_track(int cylinder, int head); @@ -170,6 +183,16 @@ private: void recalibrate(); }; +/* + The Generic drive is a MFM drive that has just enough heads and cylinders + to handle the CHD image. + + Specific Seagate models: + + ST-213: 10 MB + ST-225: 20 MB + ST-251: 40 MB +*/ class mfm_hd_generic_device : public mfm_harddisk_device { public: @@ -178,6 +201,14 @@ public: extern const device_type MFMHD_GENERIC; +class mfm_hd_st213_device : public mfm_harddisk_device +{ +public: + mfm_hd_st213_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_ST213; + class mfm_hd_st225_device : public mfm_harddisk_device { public: @@ -186,6 +217,15 @@ public: extern const device_type MFMHD_ST225; +class mfm_hd_st251_device : public mfm_harddisk_device +{ +public: + mfm_hd_st251_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); +}; + +extern const device_type MFMHD_ST251; + + /* Connector for a MFM hard disk. See also floppy.c */ class mfm_harddisk_connector : public device_t, public device_slot_interface @@ -227,4 +267,21 @@ extern const device_type MFM_HD_CONNECTOR; MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) \ static_cast<mfm_harddisk_connector *>(device)->configure(_enc, _spinupms, _cache); + +/* + Hard disk format +*/ +class harddisk_image_format_t +{ +public: + harddisk_image_format_t(); + virtual ~harddisk_image_format_t(); + + // Load the image. + virtual bool load() = 0; + + // Save the image. + virtual bool save() = 0; +}; + #endif |