Files
86Box/src/disc_sector.c

463 lines
16 KiB
C

/* Copyright holders: Sarah Walker, Tenshi
see COPYING for more details
*/
#include "ibm.h"
#include "disc.h"
#include "disc_sector.h"
#include "fdd.h"
/*Handling for 'sector based' image formats (like .IMG) as opposed to 'stream based' formats (eg .FDI)*/
#define MAX_SECTORS 256
typedef struct
{
uint8_t c, h, r, n;
int rate;
uint8_t *data;
} sector_t;
static sector_t disc_sector_data[2][2][MAX_SECTORS];
static int disc_sector_count[2][2];
void (*disc_sector_writeback[2])(int drive);
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
};
static int disc_sector_state[2] = {0, 0};
static int disc_sector_track[2] = {0, 0};
static int disc_sector_side[2] = {0, 0};
static int disc_sector_drive;
static int disc_sector_sector[2] = {0, 0};
static int disc_sector_n[2] = {0, 0};
static int disc_intersector_delay[2] = {0, 0};
static int disc_postdata_delay[2] = {0, 0};
static int disc_track_delay[2] = {0, 0};
static int disc_gap4_delay[2] = {0, 0};
static uint8_t disc_sector_fill[2] = {0, 0};
static int cur_sector[2], cur_byte[2];
static int index_count[2];
int raw_tsize[2] = {6250, 6250};
int gap2_size[2] = {22, 22};
int gap3_size[2] = {0, 0};
int gap4_size[2] = {0, 0};
void disc_sector_reset(int drive, int side)
{
disc_sector_count[drive][side] = 0;
disc_intersector_delay[drive] = 0;
disc_postdata_delay[drive] = 0;
disc_track_delay[drive] = 0;
disc_gap4_delay[drive] = 0;
cur_sector[drive] = 0;
cur_byte[drive] = 0;
index_count[drive] = 0;
}
void disc_sector_add(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n, int rate, uint8_t *data)
{
sector_t *s = &disc_sector_data[drive][side][disc_sector_count[drive][side]];
//pclog("disc_sector_add: drive=%i side=%i %i r=%i\n", drive, side, disc_sector_count[drive][side],r );
if (disc_sector_count[drive][side] >= MAX_SECTORS)
return;
s->c = c;
s->h = h;
s->r = r;
s->n = n;
s->rate = rate;
s->data = data;
disc_sector_count[drive][side]++;
}
static int get_bitcell_period(int drive)
{
return (disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].rate * 300) / fdd_getrpm(drive);
}
void disc_sector_readsector(int drive, int sector, int track, int side, int rate, int sector_size)
{
pclog("disc_sector_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);
disc_sector_track[drive] = track;
disc_sector_side[drive] = side;
disc_sector_drive = drive;
disc_sector_sector[drive] = sector;
disc_sector_n[drive] = sector_size;
if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive]) disc_track_delay[drive] = pre_track;
index_count[drive] = 0;
if (sector == SECTOR_FIRST)
disc_sector_state[drive] = STATE_READ_FIND_FIRST_SECTOR;
else if (sector == SECTOR_NEXT)
disc_sector_state[drive] = STATE_READ_FIND_NEXT_SECTOR;
else
disc_sector_state[drive] = STATE_READ_FIND_SECTOR;
}
void disc_sector_writesector(int drive, int sector, int track, int side, int rate, int sector_size)
{
// pclog("disc_sector_writesector: fdc_period=%i img_period=%i rate=%i\n", fdc_get_bitcell_period(), get_bitcell_period(), rate);
disc_sector_track[drive] = track;
disc_sector_side[drive] = side;
disc_sector_drive = drive;
disc_sector_sector[drive] = sector;
disc_sector_n[drive] = sector_size;
if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive]) disc_track_delay[drive] = pre_track;
index_count[drive] = 0;
disc_sector_state[drive] = STATE_WRITE_FIND_SECTOR;
}
void disc_sector_readaddress(int drive, int track, int side, int rate)
{
// pclog("disc_sector_readaddress: fdc_period=%i img_period=%i rate=%i track=%i side=%i\n", fdc_get_bitcell_period(), get_bitcell_period(), rate, track, side);
disc_sector_track[drive] = track;
disc_sector_side[drive] = side;
disc_sector_drive = drive;
if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive])
{
disc_track_delay[drive] = pre_track;
index_count[drive] = -1;
}
else
index_count[drive] = 0;
disc_sector_state[drive] = STATE_READ_FIND_ADDRESS;
}
void disc_sector_format(int drive, int track, int side, int rate, uint8_t fill)
{
disc_sector_track[drive] = track;
disc_sector_side[drive] = side;
disc_sector_drive = drive;
disc_sector_fill[drive] = fill;
index_count[drive] = 0;
disc_sector_state[drive] = STATE_FORMAT_FIND;
}
void disc_sector_stop(int drive)
{
disc_sector_state[drive] = STATE_IDLE;
}
static void index_pulse(int drive)
{
if (disc_sector_state[drive] != STATE_IDLE) fdc_indexpulse();
}
void disc_sector_prepare_track_layout(int drive, int side)
{
}
static void advance_byte()
{
int drive = disc_sector_drive;
if (disc_postdata_delay[drive])
{
disc_postdata_delay[drive]--;
return;
}
if (disc_gap4_delay[drive])
{
disc_gap4_delay[drive]--;
return;
}
if (disc_track_delay[drive])
{
if (disc_track_delay[drive] == pre_track)
{
index_pulse(drive);
if (disc_sector_state[drive] != STATE_IDLE) index_count[drive]++;
}
disc_track_delay[drive]--;
return;
}
if (disc_intersector_delay[drive])
{
disc_intersector_delay[drive]--;
return;
}
cur_byte[drive]++;
if (cur_byte[drive] >= (128 << disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].n))
{
cur_byte[drive] = 0;
cur_sector[drive]++;
disc_postdata_delay[drive] = post_gap + (gap3_size[drive]);
if (cur_sector[drive] >= disc_sector_count[drive][disc_sector_side[drive]])
{
cur_sector[drive] = 0;
disc_gap4_delay[drive] = (gap4_size[drive]);
disc_track_delay[drive] = pre_track;
disc_intersector_delay[drive] = pre_gap + gap2_size[drive] + pre_data;
}
else
{
disc_gap4_delay[drive] = 0;
disc_track_delay[drive] = 0;
disc_intersector_delay[drive] = pre_gap + gap2_size[drive] + pre_data;
}
}
return;
}
int disc_gap_has_ended(int drive)
{
return (disc_postdata_delay[drive] == (post_gap + (gap3_size[drive]) - fdc_get_gap() - length_crc));
}
void disc_sector_poll()
{
sector_t *s;
int data;
int drive = disc_sector_drive;
if (cur_sector[drive] >= disc_sector_count[drive][disc_sector_side[drive]])
cur_sector[drive] = 0;
if (disc_sector_n[drive])
{
if (cur_byte[drive] >= (128 << disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].n))
cur_byte[drive] = 0;
}
else
{
if (cur_byte[drive] >= fdc_get_dtl())
cur_byte[drive] = 0;
}
/* Note: Side to read from should be chosen from FDC head select rather than from the sector ID. */
s = &disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]];
switch (disc_sector_state[drive])
{
case STATE_IDLE:
advance_byte();
break;
case STATE_READ_FIND_SECTOR:
if (index_count[drive] > 1)
{
pclog("READ: Sector (%i %i %i %i) not found (last: %i %i %i %i) (period=%i,%i) (ic=%i)\n", s->c, s->h, s->r, s->n, disc_sector_track[drive], disc_sector_side[drive], disc_sector_sector[drive], disc_sector_n[drive], fdc_get_bitcell_period(), get_bitcell_period(drive), index_count[drive]);
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (/*cur_byte[drive] || */ disc_sector_track[drive] != s->c ||
disc_sector_side[drive] != s->h ||
disc_sector_sector[drive] != s->r ||
((disc_sector_n[drive] != s->n) && (disc_sector_n[drive])) ||
(fdc_get_bitcell_period() != get_bitcell_period(drive)) ||
!fdd_can_read_medium(drive ^ fdd_swap) ||
disc_intersector_delay[drive] || disc_postdata_delay[drive] || disc_track_delay[drive] || disc_gap4_delay[drive])
{
advance_byte();
break;
}
disc_sector_state[drive] = STATE_READ_SECTOR;
case STATE_READ_SECTOR:
if (!disc_postdata_delay[drive])
{
if (fdc_data(s->data[cur_byte[drive]]))
{
return;
}
}
advance_byte();
if (!cur_byte[drive] && disc_gap_has_ended(drive))
{
disc_sector_state[drive] = STATE_IDLE;
fdc_finishread(drive);
}
break;
case STATE_READ_FIND_FIRST_SECTOR:
if (!fdd_can_read_medium(drive ^ fdd_swap))
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (cur_byte[drive] || !index_count[drive] || fdc_get_bitcell_period() != get_bitcell_period(drive) ||
disc_intersector_delay[drive] || disc_postdata_delay[drive] || disc_track_delay[drive] || disc_gap4_delay[drive])
{
advance_byte();
break;
}
disc_sector_state[drive] = STATE_READ_FIRST_SECTOR;
case STATE_READ_FIRST_SECTOR:
if (!disc_postdata_delay[drive])
{
if (fdc_data(s->data[cur_byte[drive]]))
return;
}
advance_byte();
if (!cur_byte[drive] && disc_gap_has_ended(drive))
{
disc_sector_state[drive] = STATE_IDLE;
fdc_finishread(drive);
}
break;
case STATE_READ_FIND_NEXT_SECTOR:
if (!fdd_can_read_medium(drive ^ fdd_swap))
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (index_count[drive] > 0)
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (cur_byte[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) ||
disc_intersector_delay[drive] || disc_postdata_delay[drive] || disc_track_delay[drive] || disc_gap4_delay[drive])
{
advance_byte();
break;
}
disc_sector_state[drive] = STATE_READ_NEXT_SECTOR;
case STATE_READ_NEXT_SECTOR:
if (!disc_postdata_delay[drive])
{
if (fdc_data(s->data[cur_byte[drive]]))
break;
}
advance_byte();
if (!cur_byte[drive] && disc_gap_has_ended(drive))
{
disc_sector_state[drive] = STATE_IDLE;
fdc_finishread(drive);
}
break;
case STATE_WRITE_FIND_SECTOR:
if (!fdd_can_read_medium(drive ^ fdd_swap))
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (writeprot[drive] || swwp)
{
fdc_writeprotect();
}
if (index_count[drive] > 1)
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (cur_byte[drive] || disc_sector_track[drive] != s->c ||
disc_sector_side[drive] != s->h ||
disc_sector_sector[drive] != s->r ||
((disc_sector_n[drive] != s->n) && (disc_sector_n[drive])) ||
(fdc_get_bitcell_period() != get_bitcell_period(drive)) ||
disc_intersector_delay[drive] || disc_postdata_delay[drive] || disc_track_delay[drive] || disc_gap4_delay[drive])
{
advance_byte();
break;
}
disc_sector_state[drive] = STATE_WRITE_SECTOR;
case STATE_WRITE_SECTOR:
if (!disc_postdata_delay[drive])
{
data = fdc_getdata(cur_byte[drive] == ((128 << s->n) - 1));
if (data == -1)
break;
if (!disable_write) s->data[cur_byte[drive]] = data;
}
advance_byte();
if (!cur_byte[drive] && disc_gap_has_ended(drive))
{
disc_sector_state[drive] = STATE_IDLE;
if (!disable_write) disc_sector_writeback[drive](drive);
fdc_finishread(drive);
}
break;
case STATE_READ_FIND_ADDRESS:
if (!fdd_can_read_medium(drive ^ fdd_swap))
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (index_count[drive] > 0)
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (cur_byte[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) ||
disc_intersector_delay[drive] || disc_postdata_delay[drive] || disc_track_delay[drive] || disc_gap4_delay[drive])
{
advance_byte();
break;
}
disc_sector_state[drive] = STATE_READ_ADDRESS;
case STATE_READ_ADDRESS:
fdc_sectorid(s->c, s->h, s->r, s->n, 0, 0);
disc_sector_state[drive] = STATE_IDLE;
break;
case STATE_FORMAT_FIND:
if (writeprot[drive] || swwp)
{
fdc_writeprotect();
}
if (!index_count[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) ||
disc_intersector_delay[drive] || disc_postdata_delay[drive] || disc_track_delay[drive] || disc_gap4_delay[drive])
{
advance_byte();
break;
}
if (!(fdd_can_read_medium(drive ^ fdd_swap)))
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
if (fdc_get_bitcell_period() != get_bitcell_period(drive))
{
fdc_notfound();
disc_sector_state[drive] = STATE_IDLE;
break;
}
disc_sector_state[drive] = STATE_FORMAT;
case STATE_FORMAT:
if (!disc_intersector_delay[drive] && fdc_get_bitcell_period() == get_bitcell_period(drive) && !disable_write)
s->data[cur_byte[drive]] = disc_sector_fill[drive];
advance_byte();
if (index_count[drive] == 2)
{
if (!disable_write) disc_sector_writeback[drive](drive);
fdc_finishread(drive);
disc_sector_state[drive] = STATE_IDLE;
}
break;
}
}