#define VCD 0
// This routine decodes Corvus formated disks and other disks that use a
// bunch of 0's followed by one or other pattern to mark start and use rotation
// time from index to determine when to start looking.
//
// Copyright 2022 David Gesswein.
//
// 12/08/22 DJG Changed error message
// 10/02/22 DJG Suppress false reporting of needing --begin_time
// 07/20/22 DJG Process sector if bytes decoded exactly matches needed
// 03/17/22 DJG Handle large deltas and improved error message
// 10/29/21 DJG Added STRIDE_440 format
// 07/05/19 DJG Improved 3 bit head field handling
// 02/09/19 DJG Added CONTROLLER_SAGA_FOX
// 04/22/18 DJG Made code for setting bit rate match other routines
// 04/21/17 DJG Added parameter to mfm_check_header_values and added
// determining --begin_time if needed
// 11/20/16 DJG Add Vector4 format and fixes for marking data for
// fixing emulator data.
// 10/28/16 DJG Document extra header Cromemco drives have
// 10/07/16 DJG More fixes for Cromemco format. Change when looking for
// header to avoid false sync. Suppress out of data when all sectors read.
// 10/01/16 DJG Added Cromemco format
// 05/21/16 DJG Parameter change to mfm_mark* routines
// 12/31/15 DJG Parameter change to mfm_mark* routines
// 11/01/15 DJG Comment fixes
//
// This file is part of MFM disk utilities.
//
// MFM disk utilities is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// MFM disk utilities is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with MFM disk utilities. If not, see .
#define DEBUG 0
#define PRINT_ERR 1
#define WINDOW_FILTER 0
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "crc_ecc.h"
#include "emu_tran_file.h"
#include "mfm_decoder.h"
#include "msg.h"
#include "deltas_read.h"
// Type II PLL. Here so it will inline. Converted from continuous time
// by bilinear transformation. Coefficients adjusted to work best with
// my data. Could use some more work.
static inline float filter(float v, float *delay)
{
float in, out;
in = v + *delay;
out = in * 0.034446428576716f + *delay * -0.034124999994713f;
*delay = in;
return out;
}
// Decode bytes into header or sector data for the various formats we know about.
// The decoded data will be written to a file if one was specified.
// Since processing a header with errors can overwrite other good sectors this
// routine shouldn't be called if data has a CRC error.
//
// The format names are arbitrarily assigned to the first controller found
// writing that format.
// The format is
// CONTROLLER_CORVUS_H,
// The bit/clock timing is 11 MHz.
// No documentation on format
// The format is Headers is preceded by a large number of zero followed
// by a one. The header is 3 bytes immediately followed by the sector data.
// Sector start is determined by time from index. There is a gap between
// sectors where it does not write anything when formatting the track so
// whatever existing data (possibly at the normal MFM 10 MHz will be seen.
// 3 byte header + 2 byte CRC
// byte 0 head upper 3 bits, sector number lower 5
// byte 1 low byte of cylinder
// byte 2 high byte of cylinder
// Sector data for sector size
// 2 byte CRC code (polynomial 0x8005)
//
// CONTROLLER_CROMEMCO,
// At about 65,000 ns from index the track has a header
// byte 0 0x04
// byte 1 0xaa
// byte 2 low cylinder
// byte 3 high cylinder
// byte 4 head
//
// At about 190,000 ns the one sector has a header
// 9 byte header + 7 byte trailer + 2 byte CRC
// byte 0 0x04
// byte 1 0x00
// byte 2 0xaa
// byte 3 0xaa
// byte 4 0xaa
// byte 5 0x00
// byte 6 low cylinder
// byte 7 high cylinder
// byte 8 head
// 10240 bytes of data
// 0x00
// 0xaa
// 0xaa
// 0x00
// 2 byte CRC code (polynomial 0x8005, init value 0 with all
// above in the CRC))
//
// CONTROLLER_VECTOR4
// format 7100-6501_Disktest_Technical_Information_Oct82.pdf,
// pdf/vectorGraphics on bitsavers
// 30 bytes of zeros (not considered part of header
// byte 0 0xff
// byte 1 upper 4 bits head, lower 4 bits upper part of cylinder
// byte 2 lower 8 bits of cylinder
// byte 3 sector
// 256 bytes of sector data
// 4 byte ecc
//
// CONTROLLER_VECTOR4_ST506
// format 7100-6501_Disktest_Technical_Information_Oct82.pdf,
// pdf/vectorGraphics on bitsavers
// 30 bytes of zeros (not considered part of header
// byte 0 0xff
// byte 1 head
// byte 2 cylinder
// byte 3 sector
// 256 bytes of sector data
// 4 byte ecc
//
// CONTROLLER_STRIDE_440
// No documentation on format other than controller schematic
// http://www.bitsavers.org/pdf/sage/schematics/Sage-II_IV-Schematics.pdf
// Sync on 1 bit after a bunch of zeros
//
// Header is 28 bytes. Has more non zero bytes for unknown purpose
// byte 7 high of track count
// byte 8 low of track count
// 8192 bytes of sector data
// one extra byte
// 2 byte ecc
// Track number is zero for first track and counts up
//
// CONTROLLER_SAGA_FOX
// No information on format available
// Sector header mark seems to be a bunch of zeros followed by four ones
// All data is bit reversed. Information below is after bit reversing bytes
//
// Header
// byte 0 0xf0
// byte 1 cylinder
// byte 2 unkown drive was too small to know if upper cyl. Code assumes
// it is upper cyl.
// byte 3 head
// byte 4 sector
// byte 5 xor of cyl and head
// byte 6 xor of bytes 0-5
//
// Data
// byte 0 0xf0
// 256 bytes of data
// byte 257 unknown
// byte 258 xor of bytes 0-257
//
SECTOR_DECODE_STATUS corvus_process_data(STATE_TYPE *state, uint8_t bytes[],
int total_bytes,
uint64_t crc, int exp_cyl, int exp_head, int *sector_index,
DRIVE_PARAMS *drive_params, int *seek_difference,
SECTOR_STATUS sector_status_list[], int ecc_span,
SECTOR_DECODE_STATUS init_status)
{
static int sector_size;
static int bad_block;
static SECTOR_STATUS sector_status;
uint8_t cromemco_sync[] = {0x04, 0x00, 0xaa, 0xaa, 0xaa, 0x00};
if (*state == PROCESS_HEADER) {
*state = MARK_ID;
memset(§or_status, 0, sizeof(sector_status));
sector_status.status |= init_status | SECT_HEADER_FOUND;
sector_status.ecc_span_corrected_header = ecc_span;
if (ecc_span != 0) {
sector_status.status |= SECT_ECC_RECOVERED;
}
if (drive_params->controller == CONTROLLER_CORVUS_H) {
sector_status.cyl = bytes[1] | (bytes[2] << 8);
sector_status.head = mfm_fix_head(drive_params, exp_head, bytes[0] >> 5 );
sector_status.sector = bytes[0] & 0x1f;
} else if (drive_params->controller == CONTROLLER_CROMEMCO) {
sector_status.cyl = bytes[6] | (bytes[7] << 8);
sector_status.head = mfm_fix_head(drive_params, exp_head, bytes[8]);
sector_status.sector = 0; // Only 1 sector
if (memcmp(bytes, cromemco_sync, sizeof(cromemco_sync)) != 0) {
msg(MSG_ERR, "Bad alignment bytes %x %x %x %x %x %x on cyl %d,%d head %d,%d\n",
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5],
exp_cyl, sector_status.cyl,
exp_head, sector_status.head);
}
} else if (drive_params->controller == CONTROLLER_VECTOR4) {
if (bytes[0] != 0xff) {
msg(MSG_ERR, "Bad sync byte %x on cyl %d,%d head %d,%d\n",
bytes[0], exp_cyl, sector_status.cyl,
exp_head, sector_status.head);
sector_status.status |= SECT_BAD_HEADER;
}
sector_status.cyl = ((bytes[1] & 0xf) << 8) | bytes[2];
sector_status.head = mfm_fix_head(drive_params, exp_head,bytes[1] >> 4);
sector_status.sector = bytes[3];
} else if (drive_params->controller == CONTROLLER_VECTOR4_ST506) {
if (bytes[0] != 0xff) {
msg(MSG_ERR, "Bad sync byte %x on cyl %d,%d head %d,%d\n",
bytes[0], exp_cyl, sector_status.cyl,
exp_head, sector_status.head);
sector_status.status |= SECT_BAD_HEADER;
}
sector_status.cyl = bytes[2];
sector_status.head = mfm_fix_head(drive_params, exp_head, bytes[1]);
sector_status.sector = bytes[3];
} else if (drive_params->controller == CONTROLLER_STRIDE_440) {
int track = (bytes[7] << 8) + bytes[8];
sector_status.cyl = track / drive_params->num_head;
sector_status.head = track % drive_params->num_head;
sector_status.sector = 0;
} else if (drive_params->controller == CONTROLLER_SAGA_FOX) {
if (bytes[0] != 0xf0) {
msg(MSG_ERR, "Bad sync byte %x on cyl %d,%d head %d,%d\n",
bytes[0], exp_cyl, sector_status.cyl,
exp_head, sector_status.head);
sector_status.status |= SECT_BAD_HEADER;
}
sector_status.cyl = bytes[1] | (bytes[2] << 8);
sector_status.head = mfm_fix_head(drive_params, exp_head, bytes[3]);
sector_status.sector = bytes[4];
*state = MARK_DATA;
} else {
msg(MSG_FATAL,"Unknown controller type %d\n",drive_params->controller);
exit(1);
}
// Don't know how/if these are encoded in header
sector_size = drive_params->sector_size;
bad_block = 0;
msg(MSG_DEBUG,
"Got exp %d,%d cyl %d head %d sector %d size %d bad block %d\n",
exp_cyl, exp_head, sector_status.cyl, sector_status.head,
sector_status.sector, sector_size, bad_block);
if (crc != 0) {
sector_status.status |= SECT_BAD_DATA;
}
if (ecc_span != 0) {
sector_status.status |= SECT_ECC_RECOVERED;
}
mfm_check_header_values(exp_cyl, exp_head, sector_index, sector_size,
seek_difference, §or_status, drive_params, sector_status_list);
sector_status.ecc_span_corrected_data = ecc_span;
if (!mfm_controller_info[drive_params->controller].separate_data &&
!(sector_status.status & SECT_BAD_HEADER)) {
int dheader_bytes = mfm_controller_info[drive_params->controller].data_header_bytes;
if (mfm_write_sector(&bytes[dheader_bytes], drive_params, §or_status,
sector_status_list, &bytes[0], total_bytes) == -1) {
sector_status.status |= SECT_BAD_HEADER;
}
}
} else { // PROCESS_DATA
if (crc != 0) {
sector_status.status |= SECT_BAD_DATA;
}
if (ecc_span != 0) {
sector_status.status |= SECT_ECC_RECOVERED;
}
sector_status.ecc_span_corrected_data = ecc_span;
// TODO: If bad sector number the stats such as count of spare/bad
// sectors is not updated. We need to know the sector # to update
// our statistics array. This happens with RQDX3
if (!(sector_status.status & (SECT_BAD_HEADER | SECT_BAD_SECTOR_NUMBER))) {
int dheader_bytes = mfm_controller_info[drive_params->controller].data_header_bytes;
// Bytes[1] is because 0xa1 can't be updated from bytes since
// won't get encoded as special sync pattern
if (mfm_write_sector(&bytes[dheader_bytes], drive_params, §or_status,
sector_status_list, &bytes[1], total_bytes-1) == -1) {
sector_status.status |= SECT_BAD_HEADER;
}
}
*state = MARK_ID;
}
return sector_status.status;
}
// Decode a track's worth of deltas.
//
//
// drive_params: Drive parameters
// cyl,head: Physical Track data from
// deltas: MFM delta data to decode
// seek_difference: Return of difference between expected cyl and header
// sector_status_list: Return of status of decoded sector
// return: Or together of the status of each sector decoded
SECTOR_DECODE_STATUS corvus_decode_track(DRIVE_PARAMS *drive_params, int cyl,
int head, uint16_t deltas[], int *seek_difference,
SECTOR_STATUS sector_status_list[])
{
// This is which MFM clock and data bits are valid codes. So far haven't
// found a good way to use this.
//int valid_code[16] = { 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 };
// This converts the MFM clock and data bits into data bits.
int code_bits[16] = { 0, 1, 0, 0, 2, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 };
// This is the raw MFM data decoded with above
unsigned int raw_word = 0;
// Counter to know when to decode the next two bits.
int raw_bit_cntr = 0;
// The decoded bits
unsigned int decoded_word = 0;
// Counter to know when we have a bytes worth
int decoded_bit_cntr = 0;
// loop counter
int i;
// These are variables for the PLL filter. avg_bit_sep_time is the
// "VCO" frequency in delta counts
float avg_bit_sep_time; // 200 MHz clocks
float nominal_bit_sep_time; // 200 MHz clocks
// Clock time is the clock edge time from the VCO.
float clock_time = 0;
// How many bits the last delta corresponded to
int int_bit_pos;
// PLL filter state. Static works better since next track bit timing
// similar to previous though a bad track can put it off enough that
// the next track has errors. Retry should fix. TODO: Look at
static float filter_state = 0;
// Time in track for debugging
int track_time = 0;
// Counter for debugging
int tot_raw_bit_cntr = 0;
// Where we are in decoding a sector, Start looking for header ID mark
STATE_TYPE state = MARK_ID;
// Status of decoding returned
int sector_status = SECT_NO_STATUS;
// How many zeros we need to see before we will look for the sync bit.
// When write turns on and off can cause codes that cause false sync
// so this avoids them.
#define MARK_NUM_ZEROS 30
int sync_count = 0;
// Number of deltas available so far to process
int num_deltas;
// And number from last time
int last_deltas = 0;
// If we get too large a delta we need to process it in less than 32 bit
// word number of bits. This holds remaining number to process
int remaining_delta = 0;
// Maximum delta to process in one pass
int max_delta;
// Intermediate value
int tmp_raw_word;
// Collect bytes to further process here
uint8_t bytes[MAX_SECTOR_SIZE + 50];
// How many we need before passing them to the next routine
int bytes_needed = 0;
// Length to perform CRC over
int bytes_crc_len = 0;
// how many we have so far
int byte_cntr = 0;
// Sequential counter for counting sectors
int sector_index = 0;
// Count all the raw bits for emulation file
int all_raw_bits_count = 0;
// Time to look for next header in 200 MHz clock ticks. This will start
// looking at data a little into the beggining 0 words
int next_header_time;
// First address mark time in ns
int first_addr_mark_ns = 0;
// This reverses the bit ordering in a byte. The controller writes
// the header data LSB first not the normal MSB first.
static unsigned char rev_lookup[16] = {
0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf };
#define REV_BYTE(n)( (rev_lookup[n&0xf] << 4) | rev_lookup[(n & 0xf0)>>4])
nominal_bit_sep_time = 200e6 /
mfm_controller_info[drive_params->controller].clk_rate_hz;
max_delta = nominal_bit_sep_time * 22;
avg_bit_sep_time = nominal_bit_sep_time;
if (drive_params->controller == CONTROLLER_CORVUS_H) {
next_header_time = 71500;
} else if (drive_params->controller == CONTROLLER_CROMEMCO) {
// Zeros found earlier cause false syncs unless skipped. TODO:
// May be better to check for sync data following and resync if
// not correct for Coromemco.
next_header_time = 32000;
} else if (drive_params->controller == CONTROLLER_VECTOR4 ||
drive_params->controller == CONTROLLER_VECTOR4_ST506) {
next_header_time = 58000;
} else if (drive_params->controller == CONTROLLER_STRIDE_440) {
next_header_time = 10000;
} else if (drive_params->controller == CONTROLLER_SAGA_FOX) {
next_header_time = 91000;
} else {
msg(MSG_ERR, "Unknown controller\n");
exit(1);
}
#if VCD
long long int bit_time = 0;
FILE *out;
char str[100];
sprintf(str,"trk%d-%d.vcd",cyl,head);
out = fopen(str,"w");
fprintf(out,"$timescale 1ps $end\n");
fprintf(out,"$var wire 1 ^ data $end\n");
fprintf(out,"$var wire 1 & sector $end\n");
#endif
// Adjust time for when data capture started
next_header_time -= drive_params->start_time_ns / CLOCKS_TO_NS;
num_deltas = deltas_get_count(0);
raw_word = 0;
i = 1;
while (num_deltas >= 0) {
// We process what we have then check for more.
for (; i < num_deltas;) {
int delta_process;
// If no remaining delta process next else finish remaining
if (remaining_delta == 0) {
delta_process = deltas[i++];
remaining_delta = delta_process;
} else {
delta_process = remaining_delta;
}
// Don't overflow our 32 bit word
if (delta_process > max_delta) {
delta_process = max_delta;
}
track_time += delta_process;
// This is simulating a PLL/VCO clock sampling the data.
clock_time += delta_process;
remaining_delta -= delta_process;
// Move the clock in current frequency steps and count how many bits
// the delta time corresponds to
for (int_bit_pos = 0; clock_time > avg_bit_sep_time / 2;
clock_time -= avg_bit_sep_time, int_bit_pos++) {
}
// And then filter based on the time difference between the delta and
// the clock. Don't update PLL if this is a long burst without
// transitions
if (remaining_delta == 0) {
avg_bit_sep_time = nominal_bit_sep_time + filter(clock_time, &filter_state);
}
#if DEBUG
//printf("track %d clock %f\n", track_time, clock_time);
//if (cyl == 70 & head == 5 && track_time > next_header_time)
if (cyl == 0 && head == 0)
printf
(" delta %d %.2f int %d avg_bit %.2f time %d dec %08x raw %08x byte %d\n",
deltas[i], clock_time,
int_bit_pos, avg_bit_sep_time, track_time, decoded_word,
raw_word, byte_cntr);
#endif
if (all_raw_bits_count + int_bit_pos >= 32) {
all_raw_bits_count = mfm_save_raw_word(drive_params,
all_raw_bits_count, int_bit_pos, raw_word);
} else {
all_raw_bits_count += int_bit_pos;
}
// Shift based on number of bit times then put in the 1 from the
// delta. If we had a delta greater than the size of raw word we
// will lose the unprocessed bits in raw_word. This is unlikely
// to matter since this is invalid MFM data so the disk had a long
// drop out so many more bits are lost.
if (int_bit_pos >= sizeof(raw_word)*8) {
raw_word = 1;
} else {
raw_word = (raw_word << int_bit_pos) | 1;
}
tot_raw_bit_cntr += int_bit_pos;
raw_bit_cntr += int_bit_pos;
// Are we looking for a mark code?
if (state == MARK_ID || state == MARK_DATA) {
//printf("Raw %d %d %x\n",tot_raw_bit_cntr, sync_count, raw_word);
// These patterns are MFM encoded all zeros or all ones.
// We are looking for zeros so we assume they are zeros.
if (track_time > next_header_time &&
(raw_word == 0x55555555 || raw_word == 0xaaaaaaaa)) {
sync_count++;
} else {
if (sync_count < MARK_NUM_ZEROS) {
sync_count = 0;
}
}
// If we found enough zeros start looking for a 1
if (sync_count >= MARK_NUM_ZEROS ||
(drive_params->controller == CONTROLLER_SAGA_FOX &&
sync_count >= 20)) {
sync_count = 0;
if (state == MARK_ID) {
state = HEADER_SYNC;
} else {
state = DATA_SYNC;
}
raw_bit_cntr = 0;
decoded_word = 0;
decoded_bit_cntr = 0;
}
// We need to wait for the one bit to resynchronize.
} else if (state == HEADER_SYNC || state == DATA_SYNC) {
//printf("Raw %d %d %x\n",tot_raw_bit_cntr, sync_count, raw_word);
int found = 0;
// SAGA_FOX synced incorrectly with just 0x9
if (drive_params->controller == CONTROLLER_SAGA_FOX) {
found = (raw_word & 0xfff) == 0xaa9;
} else {
found = (raw_word & 0xf) == 0x9;
}
if (found) {
#if VCD
bit_time = track_time / 198e6 * 1e12;
fprintf(out,"#%lld\n1&\n", bit_time);
printf("Found header at %d %d %d\n",tot_raw_bit_cntr, track_time,
track_time + drive_params->start_time_ns / CLOCKS_TO_NS);
#endif
if (first_addr_mark_ns == 0) {
first_addr_mark_ns = track_time * CLOCKS_TO_NS;
}
// Figure out the length of data we should look for
bytes_crc_len = mfm_controller_info[drive_params->controller].header_bytes +
drive_params->sector_size +
mfm_controller_info[drive_params->controller].data_trailer_bytes +
drive_params->header_crc.length / 8;
// Time next header should start at
if (drive_params->controller == CONTROLLER_CORVUS_H) {
next_header_time += 164900;
raw_bit_cntr = -2;
// May be better to time from current track time in
} else if (drive_params->controller == CONTROLLER_VECTOR4 ||
drive_params->controller == CONTROLLER_VECTOR4_ST506) {
// case drive rotation speed varies
next_header_time = track_time + 96000;
raw_bit_cntr = 2;
} else if (drive_params->controller == CONTROLLER_STRIDE_440) {
// No more headers
next_header_time += INT_MAX/2;
raw_bit_cntr = 4;
} else if (drive_params->controller == CONTROLLER_CROMEMCO) {
// We need the 0x04 that is also the sync we are using
// to start decoding so back up
raw_bit_cntr = 12;
} else if (drive_params->controller == CONTROLLER_SAGA_FOX) {
// case drive rotation speed varies
if (state == HEADER_SYNC) {
next_header_time = track_time + 4000;
raw_bit_cntr = 10;
// Figure out the length of header we should look for
bytes_crc_len = mfm_controller_info[drive_params->controller].header_bytes +
drive_params->header_crc.length / 8;
} else {
next_header_time = track_time + 82000;
raw_bit_cntr = 10;
// Figure out the length of data we should look for
bytes_crc_len = mfm_controller_info[drive_params->controller].data_header_bytes +
drive_params->sector_size +
mfm_controller_info[drive_params->controller].data_trailer_bytes +
drive_params->data_crc.length / 8;
}
}
//printf("Next header at %d track time %d\n",next_header_time, track_time);
decoded_word = 0;
decoded_bit_cntr = 0;
// In this format header is attached to data so both
// will be processed in this state
if (state == HEADER_SYNC) {
state = PROCESS_HEADER;
} else {
state = PROCESS_DATA;
}
mfm_mark_header_location(all_raw_bits_count, raw_bit_cntr,
tot_raw_bit_cntr);
mfm_mark_data_location(all_raw_bits_count, raw_bit_cntr,
tot_raw_bit_cntr);
bytes_needed = bytes_crc_len;
// Must read enough extra bytes to ensure we send last 32
// bit word to mfm_save_raw_word
bytes_needed += 2;
if (bytes_needed >= sizeof(bytes)) {
printf("Too many bytes needed %d\n",bytes_needed);
exit(1);
}
byte_cntr = 0;
}
} else { // Collect decoded bytes in sector header or data
//printf("Raw %d %d %x\n",raw_bit_cntr, sync_count, raw_word);
int entry_state = state;
// If we have enough bits to decode do so. Stop if state changes
while (raw_bit_cntr >= 4 && entry_state == state) {
// If we have more than 4 only process 4 this time
raw_bit_cntr -= 4;
tmp_raw_word = raw_word >> raw_bit_cntr;
decoded_word =
(decoded_word << 2) | code_bits[tmp_raw_word & 0xf];
decoded_bit_cntr += 2;
#if VCD
fprintf(out,"#%lld\n%d^\n#%lld\n%d^\n", bit_time,
((decoded_word >> 1) & 1) ^ 1, bit_time + 90909*2, (decoded_word & 1) ^ 1);
bit_time += 90909*4;
#endif
// And if we have a bytes worth store it
if (decoded_bit_cntr >= 8) {
// Do we have enough to further process?
if (byte_cntr < bytes_needed) {
if (drive_params->controller == CONTROLLER_SAGA_FOX) {
bytes[byte_cntr++] = REV_BYTE(decoded_word);
} else {
bytes[byte_cntr++] = decoded_word;
}
//printf("Decoded %d %d %08x\n",byte_cntr, tot_raw_bit_cntr, decoded_word);
}
if (byte_cntr == bytes_needed) {
#if VCD
fprintf(out,"#%lld\n0&\n", bit_time);
#endif
mfm_mark_end_data(all_raw_bits_count, drive_params, cyl, head);
sector_status |= mfm_process_bytes(drive_params, bytes,
bytes_crc_len, bytes_needed, &state, cyl, head,
§or_index, seek_difference, sector_status_list, 0);
}
decoded_bit_cntr = 0;
}
}
}
}
// Finished what we had, any more?
// If we didn't get too many last time sleep so delta reader can run.
// Thread priorities might be better.
if (num_deltas - last_deltas <= 2000) {
usleep(500);
}
last_deltas = num_deltas;
num_deltas = deltas_get_count(i);
}
// If in PROCESS_DATA sector_index has been incremented for possible next sector
if ((state == PROCESS_HEADER && sector_index < drive_params->num_sectors) ||
(state == PROCESS_DATA && sector_index <= drive_params->num_sectors) ) {
float begin_time =
((bytes_needed - byte_cntr) * 16.0 *
1e9/mfm_controller_info[drive_params->controller].clk_rate_hz
+ first_addr_mark_ns) / 2 + drive_params->start_time_ns;
msg(MSG_ERR, "Ran out of data on sector index %d, try adding --begin_time %.0f to mfm_read command line\n",
sector_index, round(begin_time / 1000.0) * 1000.0);
}
// Force last partial word to be saved
mfm_save_raw_word(drive_params, all_raw_bits_count, 32-all_raw_bits_count,
raw_word);
// If we didn't find anything to decode return header error
if (sector_status == SECT_NO_STATUS) {
sector_status = SECT_BAD_HEADER;
}
#if VCD
fclose(out);
#endif
return sector_status;
}