Files
86Box/src/disc_86f.c

1209 lines
34 KiB
C
Raw Normal View History

/* Copyright holders: Tenshi
see COPYING for more details
*/
#include "ibm.h"
#include "disc.h"
#include "disc_86f.h"
#include "fdd.h"
#define MAX_SECTORS 256
int d86f_cur_track_pos[2] = {0, 0};
enum
{
STATE_IDLE,
STATE_READ_FIND_SECTOR,
STATE_READ_SECTOR,
STATE_READ_FIND_FIRST_SECTOR,
STATE_READ_FIRST_SECTOR,
STATE_READ_FIND_NEXT_SECTOR,
STATE_READ_NEXT_SECTOR,
STATE_WRITE_FIND_SECTOR,
STATE_WRITE_SECTOR,
STATE_READ_FIND_ADDRESS,
STATE_READ_ADDRESS,
STATE_FORMAT_FIND,
STATE_FORMAT,
STATE_SEEK
};
static int d86f_state[2] = {0, 0};
static int d86f_track[2] = {0, 0};
static int d86f_side[2] = {0, 0};
static int d86f_drive;
static int d86f_sector[2] = {0, 0};
static int d86f_n[2] = {0, 0};
static uint8_t d86f_fill[2] = {0, 0};
2016-09-01 21:50:27 +02:00
static int cur_sector[2];
static int index_count[2];
static int format_sector_count[2] = {0, 0};
static struct
{
FILE *f;
uint8_t disk_flags;
uint8_t track_data[2][25000];
uint8_t track_layout[2][25000];
uint8_t track_flags;
uint8_t track_in_file;
uint32_t track_pos[256];
uint32_t file_size;
} d86f[2];
/* Needed for formatting! */
int d86f_realtrack(int drive, int track)
{
if (!(d86f[drive].track_flags & 0x40) && fdd_doublestep_40(drive))
track /= 2;
return track;
}
void d86f_writeback(int drive, int track);
static uint16_t CRCTable[256];
2016-09-01 21:50:27 +02:00
/* 0 = MFM, 1 = FM, 2 = MFM perpendicular, 3 = reserved */
/* 4 = ISO, 0 = IBM */
int d86f_media_type = 0;
/* Bits 0-3 define byte type, bit 5 defines whether it is a per-track (0) or per-sector (1) byte, if bit 7 is set, the byte is the index hole. */
#define BYTE_GAP0 0x00
#define BYTE_GAP1 0x10
#define BYTE_GAP4 0x20
#define BYTE_GAP2 0x40
#define BYTE_GAP3 0x50
#define BYTE_I_SYNC 0x01
#define BYTE_ID_SYNC 0x41
#define BYTE_DATA_SYNC 0x51
#define BYTE_IAM_SYNC 0x02
#define BYTE_IDAM_SYNC 0x42
#define BYTE_DATAAM_SYNC 0x52
#define BYTE_IAM 0x03
#define BYTE_IDAM 0x43
#define BYTE_DATAAM 0x53
#define BYTE_ID 0x44
#define BYTE_DATA 0x54
#define BYTE_ID_CRC 0x45
#define BYTE_DATA_CRC 0x55
#define BYTE_INDEX_HOLE 0x80 /* 1 = index hole, 0 = regular byte */
#define BYTE_IS_SECTOR 0x40 /* 1 = per-sector, 0 = per-track */
#define BYTE_IS_POST_TRACK 0x20 /* 1 = after all sectors, 0 = before or during all sectors */
#define BYTE_IS_DATA 0x10 /* 1 = data, 0 = id */
#define BYTE_TYPE 0x0F /* 5 = crc, 4 = data, 3 = address mark, 2 = address mark sync, 1 = sync, 0 = gap */
#define BYTE_TYPE_GAP 0x00
#define BYTE_TYPE_SYNC 0x01
#define BYTE_TYPE_AM_SYNC 0x02
#define BYTE_TYPE_AM 0x03
#define BYTE_TYPE_DATA 0x04
#define BYTE_TYPE_CRC 0x05
static void d86f_setupcrc(uint16_t poly, uint16_t rvalue)
{
int c = 256, bc;
uint16_t crctemp;
while(c--)
{
crctemp = c << 8;
bc = 8;
while(bc--)
{
if(crctemp & 0x8000)
{
crctemp = (crctemp << 1) ^ poly;
}
else
{
crctemp <<= 1;
}
}
CRCTable[c] = crctemp;
}
}
typedef union {
uint16_t word;
uint8_t bytes[2];
} crc_t;
static crc_t crc[2];
static void d86f_calccrc(int drive, uint8_t byte)
{
crc[drive].word = (crc[drive].word << 8) ^ CRCTable[(crc[drive].word >> 8)^byte];
}
void d86f_init()
{
memset(d86f, 0, sizeof(d86f));
d86f_setupcrc(0x1021, 0xcdb4);
}
void d86f_load(int drive, char *fn)
{
uint32_t magic = 0;
uint32_t len = 0;
uint16_t version = 0;
int i = 0;
int j = 0;
writeprot[drive] = 0;
d86f[drive].f = fopen(fn, "rb+");
if (!d86f[drive].f)
{
d86f[drive].f = fopen(fn, "rb");
if (!d86f[drive].f)
return;
writeprot[drive] = 1;
}
fwriteprot[drive] = writeprot[drive];
fseek(d86f[drive].f, 0, SEEK_END);
len = ftell(d86f[drive].f);
fseek(d86f[drive].f, 0, SEEK_SET);
if (len < 52056)
{
/* File too small, abort. */
fclose(d86f[drive].f);
return;
}
fread(&magic, 4, 1, d86f[drive].f);
if (magic != 0x46423638)
{
/* File is not of the valid format, abort. */
pclog("86F: Unrecognized magic bytes: %08X\n", magic);
fclose(d86f[drive].f);
return;
}
fread(&version, 2, 1, d86f[drive].f);
if (version != 0x0100)
{
/* File is not of a recognized format version abort. */
pclog("86F: Unrecognized file version: %04X\n", version);
fclose(d86f[drive].f);
return;
}
fread(&(d86f[drive].disk_flags), 1, 1, d86f[drive].f);
if (((d86f[drive].disk_flags >> 1) & 3) == 3)
{
/* Invalid disk hole. */
pclog("86F: Unrecognized disk hole type 3\n");
fclose(d86f[drive].f);
return;
}
if (!writeprot[drive])
{
writeprot[drive] = (d86f[drive].disk_flags & 0x10) ? 1 : 0;
fwriteprot[drive] = writeprot[drive];
}
fread(d86f[drive].track_pos, 1, 1024, d86f[drive].f);
if (!(d86f[drive].track_pos[0]))
{
/* File has no track 0, abort. */
pclog("86F: No Track 0\n");
fclose(d86f[drive].f);
return;
}
/* Load track 0 flags as default. */
fseek(d86f[drive].f, d86f[drive].track_pos[0], SEEK_SET);
fread(&(d86f[drive].track_flags), 1, 1, d86f[drive].f);
fseek(d86f[drive].f, 0, SEEK_END);
d86f[drive].file_size = ftell(d86f[drive].f);
fseek(d86f[drive].f, 0, SEEK_SET);
drives[drive].seek = d86f_seek;
drives[drive].readsector = d86f_readsector;
drives[drive].writesector = d86f_writesector;
drives[drive].readaddress = d86f_readaddress;
drives[drive].hole = d86f_hole;
drives[drive].byteperiod = d86f_byteperiod;
drives[drive].poll = d86f_poll;
drives[drive].format = d86f_format;
drives[drive].realtrack = d86f_realtrack;
drives[drive].stop = d86f_stop;
}
int d86f_hole(int drive)
{
return (d86f[drive].disk_flags >> 1) & 3;
}
double d86f_byteperiod(int drive)
{
switch (d86f[drive].track_flags & 0x0f)
{
case 0x02: /* 125 kbps, FM */
if (!(d86f[drive].track_flags & 0x20))
{
/* 300 rpm, 125 kbps = 360 rpm, 150 kbps; so we do this trick for 360 rpm-only drives to accept them. */
return ((fdd_get_type(drive) & 3) == 2) ? (320.0 / 6.0) : 64.0;
}
return 64.0;
case 0x01: /* 150 kbps, FM */
if (d86f[drive].track_flags & 0x20)
{
/* 360 rpm, 150 kbps = 300 rpm, 125 kbps; so we do this trick for 300 rpm-only drives to accept them. */
return ((fdd_get_type(drive) & 3) == 1) ? 64.0 : (320.0 / 6.0);
}
return 320.0 / 6.0;
case 0x0A: /* 250 kbps, MFM */
case 0x00: /* 250 kbps, FM */
if (!(d86f[drive].track_flags & 0x20))
{
/* 300 rpm, 250 kbps = 360 rpm, 300 kbps; so we do this trick for 360 rpm-only drives to accept them. */
return ((fdd_get_type(drive) & 3) == 2) ? (160.0 / 6.0) : 32.0;
}
return 32.0;
case 0x09: /* 300 kbps, MFM */
if (d86f[drive].track_flags & 0x20)
{
/* 360 rpm, 300 kbps = 300 rpm, 250 kbps; so we do this trick for 300 rpm-only drives to accept them. */
return ((fdd_get_type(drive) & 3) == 1) ? 32.0 : (160.0 / 6.0);
}
return 160.0 / 6.0;
case 0x08: /* 500 kbps, MFM */
return 16.0;
case 0x0B: /* 1000 kbps, MFM */
return 8.0;
case 0x0D: /* 2000 kbps, MFM */
return 4.0;
default:
return 32.0;
}
return 32.0;
}
void d86f_close(int drive)
{
if (d86f[drive].f)
fclose(d86f[drive].f);
d86f[drive].f = NULL;
}
int d86f_get_sides(int drive)
{
return (d86f[drive].disk_flags & 8) ? 2 : 1;
}
int d86f_is_40_track(int drive)
{
return !(d86f[drive].disk_flags & 1);
}
int d86f_is_mfm(int drive)
{
return (d86f[drive].track_flags & 8) ? 1 : 0;
}
uint16_t d86f_get_raw_size(int drive)
{
double rate = 0.0;
int mfm = d86f_is_mfm(drive);
double rpm = (d86f[drive].track_flags & 0x20) ? 360.0 : 300.0;
double size = 6250.0;
switch (d86f[drive].track_flags & 7)
{
case 0:
rate = 500.0;
break;
case 1:
rate = 300.0;
break;
case 2:
rate = 250.0;
break;
case 3:
rate = 1000.0;
break;
case 5:
rate = 2000.0;
break;
}
if (!mfm) rate /= 2.0;
size = (size / 250.0) * rate;
size = (size * 300.0) / rpm;
return (uint16_t) size;
}
void d86f_seek(int drive, int track)
{
int sides = d86f_get_sides(drive);
int side;
if (d86f_is_40_track(drive) && fdd_doublestep_40(drive))
track /= 2;
memset(d86f[drive].track_layout[0], BYTE_GAP4, 25000);
memset(d86f[drive].track_data[0], 0xFF, 25000);
if (d86f_get_sides(drive) == 2)
{
memset(d86f[drive].track_layout[1], BYTE_GAP4, 25000);
memset(d86f[drive].track_data[1], 0xFF, 25000);
}
if (!(d86f[drive].track_pos[track]))
{
/* Track does not exist in the image, initialize it as unformatted. */
d86f[drive].track_in_file = 0;
d86f[drive].track_flags = 0x0A; /* 300 rpm, MFM, 250 kbps */
return;
}
d86f[drive].track_in_file = 1;
fseek(d86f[drive].f, d86f[drive].track_pos[track], SEEK_SET);
fread(&(d86f[drive].track_flags), 1, 1, d86f[drive].f);
fseek(d86f[drive].f, d86f[drive].track_pos[track] + 2, SEEK_SET);
2016-09-01 21:50:27 +02:00
fread(d86f[drive].track_layout[0], 1, d86f_get_raw_size(drive), d86f[drive].f);
fseek(d86f[drive].f, d86f[drive].track_pos[track] + 25002, SEEK_SET);
2016-09-01 21:50:27 +02:00
fread(d86f[drive].track_data[0], 1, d86f_get_raw_size(drive), d86f[drive].f);
if (d86f_get_sides(drive) == 2)
{
fseek(d86f[drive].f, d86f[drive].track_pos[track] + 50002, SEEK_SET);
2016-09-01 21:50:27 +02:00
fread(d86f[drive].track_layout[1], 1, d86f_get_raw_size(drive), d86f[drive].f);
fseek(d86f[drive].f, d86f[drive].track_pos[track] + 75002, SEEK_SET);
2016-09-01 21:50:27 +02:00
fread(d86f[drive].track_data[1], 1, d86f_get_raw_size(drive), d86f[drive].f);
}
}
void d86f_writeback(int drive, int track)
{
if (!d86f[drive].f)
return;
if (!d86f[drive].track_in_file)
return; /*Should never happen*/
fseek(d86f[drive].f, d86f[drive].track_pos[track], SEEK_SET);
fwrite(&(d86f[drive].track_flags), 1, 1, d86f[drive].f);
fseek(d86f[drive].f, d86f[drive].track_pos[track] + 2, SEEK_SET);
2016-09-01 21:50:27 +02:00
fwrite(d86f[drive].track_layout[0], 1, d86f_get_raw_size(drive), d86f[drive].f);
fseek(d86f[drive].f, d86f[drive].track_pos[track] + 25002, SEEK_SET);
2016-09-01 21:50:27 +02:00
fwrite(d86f[drive].track_data[0], 1, d86f_get_raw_size(drive), d86f[drive].f);
if (d86f_get_sides(drive) == 2)
{
fseek(d86f[drive].f, d86f[drive].track_pos[track] + 50002, SEEK_SET);
2016-09-01 21:50:27 +02:00
fwrite(d86f[drive].track_layout[1], 1, d86f_get_raw_size(drive), d86f[drive].f);
fseek(d86f[drive].f, d86f[drive].track_pos[track] + 75002, SEEK_SET);
2016-09-01 21:50:27 +02:00
fwrite(d86f[drive].track_data[1], 1, d86f_get_raw_size(drive), d86f[drive].f);
}
}
void d86f_reset(int drive, int side)
{
if (side == 0)
{
index_count[drive] = 0;
d86f_state[drive] = STATE_SEEK;
}
}
static int get_bitcell_period(int drive)
{
double rate = 0.0;
int mfm = (d86f[drive].track_flags & 8) ? 1 : 0;
double rpm = (d86f[drive].track_flags & 0x20) ? 360.0 : 300.0;
double size = 8000.0;
switch (d86f[drive].track_flags & 7)
{
case 0:
rate = 500.0;
break;
case 1:
rate = 300.0;
break;
case 2:
rate = 250.0;
break;
case 3:
rate = 1000.0;
break;
case 5:
rate = 2000.0;
break;
}
if (!mfm) rate /= 2.0;
size = (size * 250.0) / rate;
size = (size * 300.0) / rpm;
size = (size * fdd_getrpm(drive)) / 300.0;
return (int) size;
}
void d86f_readsector(int drive, int sector, int track, int side, int rate, int sector_size)
{
// pclog("d86f_readsector: fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate, sector, track, side);
d86f_track[drive] = track;
d86f_side[drive] = side;
if (side && (d86f_get_sides(drive) == 1))
{
fdc_notfound();
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
return;
}
d86f_drive = drive;
d86f_sector[drive] = sector;
d86f_n[drive] = sector_size;
index_count[drive] = 0;
if (sector == SECTOR_FIRST)
d86f_state[drive] = STATE_READ_FIND_FIRST_SECTOR;
else if (sector == SECTOR_NEXT)
d86f_state[drive] = STATE_READ_FIND_NEXT_SECTOR;
else
d86f_state[drive] = STATE_READ_FIND_SECTOR;
}
void d86f_writesector(int drive, int sector, int track, int side, int rate, int sector_size)
{
// pclog("d86f_writesector: fdc_period=%i img_period=%i rate=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate);
d86f_track[drive] = track;
d86f_side[drive] = side;
if (side && (d86f_get_sides(drive) == 1))
{
fdc_notfound();
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
return;
}
d86f_drive = drive;
d86f_sector[drive] = sector;
d86f_n[drive] = sector_size;
index_count[drive] = 0;
d86f_state[drive] = STATE_WRITE_FIND_SECTOR;
}
void d86f_readaddress(int drive, int track, int side, int rate)
{
// pclog("d86f_readaddress: fdc_period=%i img_period=%i rate=%i track=%i side=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate, track, side);
d86f_track[drive] = track;
d86f_side[drive] = side;
if (side && (d86f_get_sides(drive) == 1))
{
fdc_notfound();
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
return;
}
d86f_drive = drive;
index_count[drive] = 0;
d86f_state[drive] = STATE_READ_FIND_ADDRESS;
}
int d86f_is_iso(int drive)
{
return 0; /* Currently, we always use the IBM format, not ISO. */
}
void d86f_prepare_track_layout(int drive, int side)
{
int i = 0;
int j = 0;
int real_gap0_len = d86f_is_mfm(drive) ? 80 : 40;
int sync_len = d86f_is_mfm(drive) ? 12 : 6;
int am_len = d86f_is_mfm(drive) ? 4 : 1;
int real_gap1_len = d86f_is_mfm(drive) ? 50 : 26;
int real_gap2_len = (fdc_get_bit_rate() >= 1000) ? 41 : 22;
int real_gap3_len = fdc_get_gap();
memset(d86f[drive].track_layout[side], BYTE_GAP4, d86f_get_raw_size(drive));
i = 0;
if (!(d86f_is_iso(drive)))
{
memset(d86f[drive].track_layout[side] + i, BYTE_GAP0, real_gap0_len);
i += real_gap0_len;
memset(d86f[drive].track_layout[side] + i, BYTE_I_SYNC, sync_len);
i += sync_len;
if (d86f_is_mfm(drive))
{
memset(d86f[drive].track_layout[side] + i, BYTE_IAM_SYNC, 3);
i += 3;
}
memset(d86f[drive].track_layout[side] + i, BYTE_IAM, 1);
i++;
memset(d86f[drive].track_layout[side] + i, BYTE_GAP1, real_gap1_len);
i += real_gap1_len;
}
else
{
memset(d86f[drive].track_layout[side] + i, BYTE_GAP1, real_gap1_len);
i += real_gap1_len;
}
d86f[drive].track_layout[side][0] |= BYTE_INDEX_HOLE;
for (j = 0; j < fdc_get_format_sectors(); j++)
{
// pclog("Sector %i (%i)\n", j, s->n);
memset(d86f[drive].track_layout[side] + i, BYTE_ID_SYNC, sync_len);
i += sync_len;
if (d86f_is_mfm(drive))
{
memset(d86f[drive].track_layout[side] + i, BYTE_IDAM_SYNC, 3);
i += 3;
}
memset(d86f[drive].track_layout[side] + i, BYTE_IDAM, 1);
i++;
memset(d86f[drive].track_layout[side] + i, BYTE_ID, 4);
i += 4;
memset(d86f[drive].track_layout[side] + i, BYTE_ID_CRC, 2);
i += 2;
memset(d86f[drive].track_layout[side] + i, BYTE_GAP2, real_gap2_len);
i += real_gap2_len;
memset(d86f[drive].track_layout[side] + i, BYTE_DATA_SYNC, sync_len);
i += sync_len;
if (d86f_is_mfm(drive))
{
memset(d86f[drive].track_layout[side] + i, BYTE_DATAAM_SYNC, 3);
i += 3;
}
memset(d86f[drive].track_layout[side] + i, BYTE_DATAAM, 1);
i++;
memset(d86f[drive].track_layout[side] + i, BYTE_DATA, (128 << fdc_get_format_n()));
i += (128 << fdc_get_format_n());
memset(d86f[drive].track_layout[side] + i, BYTE_DATA_CRC, 2);
i += 2;
memset(d86f[drive].track_layout[side] + i, BYTE_GAP3, real_gap3_len);
i += real_gap3_len;
}
}
void d86f_format(int drive, int track, int side, int rate, uint8_t fill)
{
d86f_track[drive] = track;
d86f_side[drive] = side;
if (side && (d86f_get_sides(drive) == 1))
{
fdc_notfound();
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
return;
}
if ((track < 0) || (track > 256))
{
fdc_writeprotect();
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
return;
}
d86f_drive = drive;
d86f_fill[drive] = fill;
index_count[drive] = 0;
/* Let's prepare the track space and layout before filling. */
d86f[drive].track_flags &= 0xc0;
d86f[drive].track_flags |= (fdd_getrpm(drive ^ fdd_swap) == 360) ? 0x20 : 0;
d86f[drive].track_flags |= fdc_get_bit_rate();
d86f[drive].track_flags |= fdc_is_mfm() ? 8 : 0;
memset(d86f[drive].track_data[side], 0xFF, 25000);
d86f_prepare_track_layout(drive, side);
if (!d86f[drive].track_in_file)
{
/* Track is absent from the file, let's add it. */
d86f[drive].track_pos[track] = d86f[drive].file_size;
d86f[drive].file_size += (2 + 50000);
if (d86f_get_sides(drive) == 2)
{
d86f[drive].file_size += 50000;
}
d86f[drive].track_in_file = 1;
}
d86f_state[drive] = STATE_FORMAT_FIND;
format_sector_count[drive] = 0;
}
void d86f_stop(int drive)
{
d86f_state[drive] = STATE_IDLE;
}
static void index_pulse(int drive)
{
if (d86f_state[drive] != STATE_IDLE) fdc_indexpulse();
}
typedef struct {
uint8_t c;
uint8_t h;
uint8_t r;
uint8_t n;
} sector_data_t;
sector_data_t last_sector[2];
int d86f_match(int drive)
{
int temp;
temp = (d86f_track[drive] == last_sector[drive].c);
temp = temp && (d86f_side[drive] == last_sector[drive].h);
temp = temp && (d86f_sector[drive] == last_sector[drive].r);
temp = temp && (d86f_n[drive] == last_sector[drive].n);
return temp;
}
uint32_t d86f_get_data_len(int drive)
{
if (d86f_n[drive])
{
return (128 << ((uint32_t) d86f_n[drive]));
}
else
{
if (fdc_get_dtl() < 128)
{
return fdc_get_dtl();
}
else
{
return (128 << ((uint32_t) d86f_n[drive]));
}
}
}
int d86f_can_read_address(int drive)
{
int temp;
temp = (fdc_get_bitcell_period() == get_bitcell_period(drive));
temp = temp && fdd_can_read_medium(drive ^ fdd_swap);
temp = temp && (fdc_is_mfm() == d86f_is_mfm(drive));
return temp;
}
int d86f_can_format(int drive)
{
int temp;
temp = !writeprot[drive];
temp = temp && !swwp;
temp = temp && fdd_can_read_medium(drive ^ fdd_swap);
return temp;
}
int d86f_find_state(int drive)
{
int temp;
temp = (d86f_state[drive] == STATE_READ_FIND_SECTOR);
temp = temp || (d86f_state[drive] == STATE_READ_FIND_FIRST_SECTOR);
temp = temp || (d86f_state[drive] == STATE_READ_FIND_NEXT_SECTOR);
temp = temp || (d86f_state[drive] == STATE_WRITE_FIND_SECTOR);
temp = temp || (d86f_state[drive] == STATE_READ_FIND_ADDRESS);
temp = temp || (d86f_state[drive] == STATE_FORMAT_FIND);
return temp;
}
int d86f_find_state_nf(int drive)
{
int temp;
temp = (d86f_state[drive] == STATE_READ_FIND_SECTOR);
temp = temp || (d86f_state[drive] == STATE_READ_FIND_FIRST_SECTOR);
temp = temp || (d86f_state[drive] == STATE_READ_FIND_NEXT_SECTOR);
temp = temp || (d86f_state[drive] == STATE_WRITE_FIND_SECTOR);
temp = temp || (d86f_state[drive] == STATE_READ_FIND_ADDRESS);
return temp;
}
int d86f_read_state(int drive)
{
int temp;
temp = (d86f_state[drive] == STATE_READ_SECTOR);
temp = temp || (d86f_state[drive] == STATE_READ_FIRST_SECTOR);
temp = temp || (d86f_state[drive] == STATE_READ_NEXT_SECTOR);
return temp;
}
int d86f_section_pos[2] = {0, 0};
int data_pos[2] = {0, 0};
int d86f_data_size(int drive)
{
int temp;
temp = d86f_n[drive];
temp = 128 << temp;
return temp;
}
typedef union
{
uint32_t dword;
uint8_t byte_array[4];
} sector_id;
sector_id format_sector_id[2];
sector_id rw_sector_id[2];
crc_t crc_bytes[2];
static uint32_t datac[2] = {0, 0};
void d86f_poll()
{
int data;
int drive = d86f_drive;
int side = d86f_side[drive];
int found_sector = 0;
int b = 0;
int cur_id_pos = 0;
int cur_gap3_pos = 0;
uint8_t track_byte = 0;
uint8_t track_index = 0;
uint8_t track_sector = 0;
uint8_t track_byte_type = 0;
uint8_t old_track_byte = 0;
uint8_t old_track_index = 0;
uint8_t old_track_sector = 0;
uint8_t old_track_byte_type = 0;
if ((d86f_state[drive] == STATE_SEEK) || (d86f_state[drive] == STATE_IDLE))
{
d86f_cur_track_pos[drive]++;
d86f_cur_track_pos[drive] %= d86f_get_raw_size(drive);
return;
}
if (d86f_state[drive] == STATE_FORMAT_FIND)
{
if (!(d86f_can_format(drive)))
{
if (d86f_can_read_address(drive))
{
// pclog("d86f_poll(): Disk is write protected or attempting to format wrong number of sectors per track\n");
fdc_writeprotect();
}
else
{
// pclog("d86f_poll(): Unable to format at the requested density or bitcell period\n");
fdc_notfound();
}
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
d86f_cur_track_pos[drive]++;
d86f_cur_track_pos[drive] %= d86f_get_raw_size(drive);
return;
}
}
track_byte = d86f[drive].track_layout[side][d86f_cur_track_pos[drive]];
track_index = track_byte & BYTE_INDEX_HOLE;
track_sector = track_byte & BYTE_IS_SECTOR;
track_byte_type = track_byte & BYTE_TYPE;
if (track_index)
{
if (d86f_state[drive] != STATE_IDLE)
{
index_pulse(drive);
index_count[drive]++;
}
if (d86f_state[drive] == STATE_FORMAT)
{
// pclog("Index hole hit again, format finished\n");
d86f_state[drive] = STATE_IDLE;
if (!disable_write) d86f_writeback(drive, d86f_track[drive]);
fdc_sector_finishread(drive);
}
if ((d86f_state[drive] == STATE_FORMAT_FIND) && d86f_can_read_address(drive))
{
// pclog("Index hole hit, formatting track...\n");
d86f_state[drive] = STATE_FORMAT;
}
}
if (d86f_read_state(drive) || (d86f_state[drive] == STATE_WRITE_SECTOR))
{
/* For the first (data size) bytes, send to the FDC or receive from the FDC and write. */
if (d86f_read_state(drive) && (datac[drive] < d86f_data_size(drive)))
{
if (fdc_data(d86f[drive].track_data[side][d86f_cur_track_pos[drive]]))
{
/* Data failed to be sent to the FDC, abort. */
// pclog("d86f_poll(): Unable to send further data to the FDC\n");
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
d86f_cur_track_pos[drive]++;
d86f_cur_track_pos[drive] %= d86f_get_raw_size(drive);
return;
}
}
if ((d86f_state[drive] == STATE_WRITE_SECTOR) && (datac[drive] < d86f_data_size(drive)))
{
data = fdc_getdata(datac[drive] == ((128 << ((uint32_t) last_sector[drive].n)) - 1));
if (data == -1)
{
/* Data failed to be sent from the FDC, abort. */
// pclog("d86f_poll(): Unable to receive further data from the FDC\n");
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
d86f_cur_track_pos[drive]++;
d86f_cur_track_pos[drive] %= d86f_get_raw_size(drive);
return;
}
if (!disable_write)
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = data;
d86f[drive].track_layout[side][d86f_cur_track_pos[drive]] = BYTE_DATA;
if (!d86f_cur_track_pos[drive]) d86f[drive].track_layout[side][d86f_cur_track_pos[drive]] |= BYTE_INDEX_HOLE;
}
}
if (datac[drive] < d86f_data_size(drive))
{
d86f_calccrc(drive, d86f[drive].track_data[side][d86f_cur_track_pos[drive]]);
}
if (datac[drive] == d86f_data_size(drive))
{
if (d86f_read_state(drive))
{
crc_bytes[drive].bytes[0] = d86f[drive].track_data[side][d86f_cur_track_pos[drive]];
}
if (d86f_state[drive] == STATE_WRITE_SECTOR)
{
if (!disable_write)
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = crc[drive].bytes[0];
d86f[drive].track_layout[side][d86f_cur_track_pos[drive]] = BYTE_DATA_CRC;
if (!d86f_cur_track_pos[drive]) d86f[drive].track_layout[side][d86f_cur_track_pos[drive]] |= BYTE_INDEX_HOLE;
}
}
}
if (datac[drive] == (d86f_data_size(drive) + 1))
{
if (d86f_read_state(drive))
{
crc_bytes[drive].bytes[1] = d86f[drive].track_data[side][d86f_cur_track_pos[drive]];
}
if (d86f_state[drive] == STATE_WRITE_SECTOR)
{
if (!disable_write)
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = crc[drive].bytes[1];
d86f[drive].track_layout[side][d86f_cur_track_pos[drive]] = BYTE_DATA_CRC;
if (!d86f_cur_track_pos[drive]) d86f[drive].track_layout[side][d86f_cur_track_pos[drive]] |= BYTE_INDEX_HOLE;
}
}
}
if ((datac[drive] > (d86f_data_size(drive) + 1)) && (datac[drive] <= (d86f_data_size(drive) + fdc_get_gap() + 1)) && (d86f_state[drive] == STATE_WRITE_SECTOR) && !disable_write)
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = fdc_is_mfm() ? 0x4E : 0xFF;
d86f[drive].track_layout[side][d86f_cur_track_pos[drive]] = BYTE_GAP3;
if (!d86f_cur_track_pos[drive]) d86f[drive].track_layout[side][d86f_cur_track_pos[drive]] |= BYTE_INDEX_HOLE;
}
/* At the last data of the FDC-specified gap length, compare the calculated CRC with the one we read and error out if mismatch, otherwise finish with success. */
if (datac[drive] == (d86f_data_size(drive) + fdc_get_gap() + 1))
{
if (d86f_read_state(drive))
{
d86f_state[drive] = STATE_IDLE;
if (crc_bytes[drive].word != crc[drive].word)
{
// pclog("d86f_poll(): Data CRC error (%04X, %04X) (%i) (%04X)\n", crc_bytes[drive].word, crc[drive].word, d86f_data_size(drive), d86f_cur_track_pos[drive] - fdc_get_gap() - 1);
fdc_finishread();
fdc_datacrcerror();
}
else
{
fdc_sector_finishread();
}
index_count[drive] = 0;
d86f_cur_track_pos[drive]++;
d86f_cur_track_pos[drive] %= d86f_get_raw_size(drive);
return;
}
if (d86f_state[drive] == STATE_WRITE_SECTOR)
{
d86f_state[drive] = STATE_IDLE;
if (!disable_write) d86f_writeback(drive, d86f_track[drive]);
fdc_sector_finishread(drive);
index_count[drive] = 0;
d86f_cur_track_pos[drive]++;
d86f_cur_track_pos[drive] %= d86f_get_raw_size(drive);
return;
}
}
datac[drive]++;
}
switch(track_byte & ~BYTE_INDEX_HOLE)
{
case BYTE_GAP0:
case BYTE_GAP1:
case BYTE_GAP2:
case BYTE_GAP3:
case BYTE_GAP4:
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write) d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = fdc_is_mfm() ? 0x4E : 0xFF;
break;
case BYTE_IAM_SYNC:
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write) d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = 0xC2;
break;
case BYTE_IAM:
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write) d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = 0xFC;
break;
case BYTE_ID_SYNC:
if (d86f_state[drive] == STATE_FORMAT)
{
cur_id_pos = d86f_cur_track_pos[drive] - d86f_section_pos[drive];
if (!disable_write) d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = 0;
if (cur_id_pos > 3) break;
data = fdc_getdata(0);
if ((data == -1) && (cur_id_pos < 3))
{
/* Data failed to be sent from the FDC, abort. */
// pclog("d86f_poll(): Unable to receive further data from the FDC\n");
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
d86f_cur_track_pos[drive]++;
d86f_cur_track_pos[drive] %= d86f_get_raw_size(drive);
return;
}
format_sector_id[drive].byte_array[cur_id_pos] = data & 0xff;
d86f_calccrc(drive, format_sector_id[drive].byte_array[cur_id_pos]);
// pclog("format_sector_id[%i] = %i\n", cur_id_pos, format_sector_id[drive].byte_array[cur_id_pos]);
if (cur_id_pos == 3)
{
fdc_stop_id_request();
// pclog("Formatting sector: %08X...\n", format_sector_id[drive].dword);
}
}
break;
case BYTE_I_SYNC:
case BYTE_DATA_SYNC:
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write) d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = 0;
break;
case BYTE_IDAM_SYNC:
case BYTE_DATAAM_SYNC:
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write) d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = 0xA1;
break;
case BYTE_IDAM:
case BYTE_DATAAM:
if (d86f_find_state_nf(drive) || (d86f_state[drive] == STATE_FORMAT)) crc[drive].word = fdc_is_mfm() ? 0xcdb4 : 0xffff;
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write) d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = (track_byte == BYTE_IDAM) ? 0xFE : 0xFB;
if (d86f_state[drive] == STATE_FORMAT) d86f_calccrc(drive, d86f[drive].track_data[side][d86f_cur_track_pos[drive]]);
if (d86f_find_state_nf(drive) && ((d86f_state[drive] != STATE_WRITE_FIND_SECTOR) || ((track_byte & ~BYTE_INDEX_HOLE) == BYTE_IDAM)))
{
d86f_calccrc(drive, d86f[drive].track_data[side][d86f_cur_track_pos[drive]]);
}
break;
case BYTE_ID:
cur_id_pos = d86f_cur_track_pos[drive] - d86f_section_pos[drive];
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write)
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = format_sector_id[drive].byte_array[cur_id_pos];
}
if (d86f_find_state_nf(drive))
{
rw_sector_id[drive].byte_array[cur_id_pos] = d86f[drive].track_data[side][d86f_cur_track_pos[drive]];
}
if ((d86f_state[drive] == STATE_FORMAT) || d86f_find_state_nf(drive))
{
d86f_calccrc(drive, d86f[drive].track_data[side][d86f_cur_track_pos[drive]]);
}
break;
case BYTE_DATA:
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write)
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = d86f_fill[drive];
d86f_calccrc(drive, d86f_fill[drive]);
}
break;
case BYTE_ID_CRC:
cur_id_pos = d86f_cur_track_pos[drive] - d86f_section_pos[drive];
if (d86f_find_state_nf(drive))
{
crc_bytes[drive].bytes[0] = d86f[drive].track_data[side][(d86f_cur_track_pos[drive] - 1) % d86f_get_raw_size(drive)];
crc_bytes[drive].bytes[1] = d86f[drive].track_data[side][d86f_cur_track_pos[drive]];
}
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write)
{
if (cur_id_pos)
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = crc[drive].bytes[1];
}
else
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = crc[drive].bytes[0];
}
}
break;
case BYTE_DATA_CRC:
cur_id_pos = d86f_cur_track_pos[drive] - d86f_section_pos[drive];
if ((d86f_state[drive] == STATE_FORMAT) && !disable_write)
{
if (cur_id_pos)
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = crc[drive].bytes[1];
}
else
{
d86f[drive].track_data[side][d86f_cur_track_pos[drive]] = crc[drive].bytes[0];
}
}
break;
}
old_track_byte = track_byte;
old_track_index = track_index;
old_track_sector = track_sector;
old_track_byte_type = track_byte_type;
d86f_cur_track_pos[drive]++;
d86f_cur_track_pos[drive] %= d86f_get_raw_size(drive);
track_byte = d86f[drive].track_layout[side][d86f_cur_track_pos[drive]];
track_index = track_byte & BYTE_INDEX_HOLE;
track_sector = track_byte & BYTE_IS_SECTOR;
track_byte_type = track_byte & BYTE_TYPE;
if ((d86f_state[drive] != STATE_IDLE) && (d86f_state[drive] != STATE_SEEK))
{
if (index_count[drive] > 1)
{
if (d86f_find_state(drive))
{
/* The index hole has been hit twice and we're still in a find state.
This means sector finding has failed for whatever reason.
Abort with sector not found and set state to idle. */
// pclog("d86f_poll(): Sector not found (%i %i %i %i)\n", d86f_track[drive], d86f_side[drive], d86f_sector[drive], d86f_n[drive]);
fdc_notfound();
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
return;
}
}
}
if ((d86f_state[drive] == STATE_IDLE) || (d86f_state[drive] == STATE_SEEK)) return;
if (track_byte != old_track_byte)
{
// if (d86f_state[drive] == STATE_FORMAT) pclog("Track byte: %02X, old: %02X\n", track_byte, old_track_byte);
d86f_section_pos[drive] = d86f_cur_track_pos[drive];
switch(track_byte & ~BYTE_INDEX_HOLE)
{
case BYTE_ID_SYNC:
if (d86f_state[drive] == STATE_FORMAT)
{
// pclog("Requesting next sector ID...\n");
fdc_request_next_sector_id();
}
break;
case BYTE_GAP2:
if (d86f_find_state_nf(drive))
{
if (d86f_match(drive) && d86f_can_read_address(drive))
{
if (crc_bytes[drive].word != crc[drive].word)
{
// pclog("d86f_poll(): Header CRC error\n");
fdc_finishread();
fdc_headercrcerror();
d86f_state[drive] = STATE_IDLE;
index_count[drive] = 0;
return;
}
}
last_sector[drive].c = rw_sector_id[drive].byte_array[0];
last_sector[drive].h = rw_sector_id[drive].byte_array[1];
last_sector[drive].r = rw_sector_id[drive].byte_array[2];
last_sector[drive].n = rw_sector_id[drive].byte_array[3];
// pclog("Read sector ID in find state: %i %i %i %i (sought: %i, %i, %i, %i)\n", last_sector[drive].c, last_sector[drive].h, last_sector[drive].r, last_sector[drive].n, d86f_track[drive], d86f_side[drive], d86f_sector[drive], d86f_n[drive]);
}
if (d86f_state[drive] == STATE_FORMAT)
{
last_sector[drive].c = format_sector_id[drive].byte_array[0];
last_sector[drive].h = format_sector_id[drive].byte_array[1];
last_sector[drive].r = format_sector_id[drive].byte_array[2];
last_sector[drive].n = format_sector_id[drive].byte_array[3];
}
if ((d86f_state[drive] == STATE_READ_FIND_ADDRESS) && d86f_can_read_address(drive))
{
// pclog("Reading sector ID...\n");
fdc_sectorid(last_sector[drive].c, last_sector[drive].h, last_sector[drive].r, last_sector[drive].n, 0, 0);
d86f_state[drive] = STATE_IDLE;
}
break;
case BYTE_DATA:
if (d86f_read_state(drive) || (d86f_state[drive] == STATE_WRITE_SECTOR)) return;
datac[drive] = 0;
switch (d86f_state[drive])
{
case STATE_READ_FIND_SECTOR:
if (d86f_match(drive) && d86f_can_read_address(drive))
{
d86f_state[drive] = STATE_READ_SECTOR;
}
break;
case STATE_READ_FIND_FIRST_SECTOR:
if ((cur_sector[drive] == 0) && d86f_can_read_address(drive)) d86f_state[drive] = STATE_READ_FIRST_SECTOR;
break;
case STATE_READ_FIND_NEXT_SECTOR:
if (d86f_can_read_address(drive)) d86f_state[drive] = STATE_READ_NEXT_SECTOR;
break;
case STATE_WRITE_FIND_SECTOR:
if (d86f_match(drive) && d86f_can_read_address(drive))
{
if (!disable_write)
{
d86f[drive].track_data[side][(d86f_cur_track_pos[drive] - 1) % d86f_get_raw_size(drive)] = 0xFB;
}
d86f_calccrc(drive, d86f[drive].track_data[side][(d86f_cur_track_pos[drive] - 1) % d86f_get_raw_size(drive)]);
d86f_state[drive] = STATE_WRITE_SECTOR;
// pclog("Write start: %i %i %i %i, data size: %i (%i)\n", last_sector[drive].c, last_sector[drive].h, last_sector[drive].r, last_sector[drive].n, d86f_data_size(drive), d86f_n[drive]);
}
break;
}
break;
}
}
}