FDC changes :

- Seperated disk and disk drive emulation
- Support more drive types - 5.25" dual RPM, 3.5" DD, 3.5" HD, 3.5" HD 3-Mode
- Support drive swapping (FDC37c665 only)
- Support FDC FIFO
- Support other FDC 'enhanced mode' behaviour
- Support IBM XDF format images
- Formatting now formats both tracks, and uses correct 'fill' byte
- Various other improvements

Many of these changes provided by Battler
This commit is contained in:
TomW 2015-12-12 16:31:08 +00:00
commit eebdc165b2
16 changed files with 1530 additions and 340 deletions

View file

@ -5,7 +5,7 @@ WINDRES = windres.exe
CFLAGS = -O3 -march=i686 -fomit-frame-pointer
OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o \
codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_pentium.o codegen_x86.o compaq.o config.o cpu.o dac.o \
device.o disc.o disc_fdi.o disc_img.o dma.o fdc.o fdc37c665.o fdi2raw.o gameport.o headland.o i430lx.o i430fx.o \
device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o headland.o i430lx.o i430fx.o \
i430vx.o ide.o intel.o intel_flash.o io.o jim.o keyboard.o keyboard_amstrad.o keyboard_at.o \
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \

View file

@ -5,6 +5,7 @@
#include "disc_fdi.h"
#include "disc_img.h"
#include "fdc.h"
#include "fdd.h"
#include "timer.h"
int disc_drivesel = 0;
@ -57,6 +58,8 @@ loaders[]=
{
{"IMG", img_load, img_close, -1},
{"IMA", img_load, img_close, -1},
{"360", img_load, img_close, -1},
{"XDF", img_load, img_close, -1},
{"FDI", fdi_load, fdi_close, -1},
{0,0,0}
};
@ -105,6 +108,7 @@ void disc_close(int drive)
if (loaders[driveloaders[drive]].close) loaders[driveloaders[drive]].close(drive);
drive_empty[drive] = 1;
discfns[drive][0] = 0;
drives[drive].hole = NULL;
drives[drive].poll = NULL;
drives[drive].seek = NULL;
drives[drive].readsector = NULL;
@ -116,6 +120,20 @@ void disc_close(int drive)
int disc_notfound=0;
static int disc_period = 32;
int disc_hole(int drive)
{
drive ^= fdd_swap;
if (drives[drive].hole)
{
return drives[drive].hole(drive);
}
else
{
return 0;
}
}
void disc_poll()
{
disc_poll_time += disc_period * TIMER_USEC;
@ -131,14 +149,50 @@ void disc_poll()
}
}
void disc_set_rate(int rate)
int disc_get_bitcell_period(int rate)
{
int bit_rate;
switch (rate)
{
case 0: /*High density*/
bit_rate = 500;
break;
case 1: /*Double density (360 rpm)*/
bit_rate = 300;
break;
case 2: /*Double density*/
bit_rate = 250;
break;
case 3: /*Extended density*/
bit_rate = 1000;
break;
}
return 1000000 / bit_rate*2; /*Bitcell period in ns*/
}
void disc_set_rate(int drive, int drvden, int rate)
{
switch (rate)
{
case 0: /*High density*/
case 1: /*High density (360 rpm)*/
disc_period = 16;
break;
case 1:
switch(drvden)
{
case 0: /*Double density (360 rpm)*/
disc_period = 26;
break;
case 1: /*High density (360 rpm)*/
disc_period = 16;
break;
case 2:
disc_period = 4;
break;
}
case 2: /*Double density*/
disc_period = 32;
break;
@ -167,47 +221,64 @@ void disc_init()
int oldtrack[2] = {0, 0};
void disc_seek(int drive, int track)
{
// pclog("disc_seek: drive=%i track=%i\n", drive, track);
if (drives[drive].seek)
drives[drive].seek(drive, track);
// if (track != oldtrack[drive])
fdc_discchange_clear(drive);
// fdc_discchange_clear(drive);
// ddnoise_seek(track - oldtrack[drive]);
oldtrack[drive] = track;
disctime = 5000;
// oldtrack[drive] = track;
}
void disc_readsector(int drive, int sector, int track, int side, int density)
void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size)
{
drive ^= fdd_swap;
if (drives[drive].readsector)
drives[drive].readsector(drive, sector, track, side, density);
drives[drive].readsector(drive, sector, track, side, density, sector_size);
else
disc_notfound = 1000;
}
void disc_writesector(int drive, int sector, int track, int side, int density)
void disc_writesector(int drive, int sector, int track, int side, int density, int sector_size)
{
drive ^= fdd_swap;
if (drives[drive].writesector)
drives[drive].writesector(drive, sector, track, side, density);
drives[drive].writesector(drive, sector, track, side, density, sector_size);
else
disc_notfound = 1000;
}
void disc_readaddress(int drive, int track, int side, int density)
{
drive ^= fdd_swap;
if (drives[drive].readaddress)
drives[drive].readaddress(drive, track, side, density);
}
void disc_format(int drive, int track, int side, int density)
void disc_format(int drive, int track, int side, int density, uint8_t fill)
{
drive ^= fdd_swap;
if (drives[drive].format)
drives[drive].format(drive, track, side, density);
drives[drive].format(drive, track, side, density, fill);
else
disc_notfound = 1000;
}
void disc_stop(int drive)
{
drive ^= fdd_swap;
if (drives[drive].stop)
drives[drive].stop(drive);
}
void disc_set_drivesel(int drive)
{
drive ^= fdd_swap;
disc_drivesel = drive;
}

View file

@ -1,10 +1,11 @@
typedef struct
{
void (*seek)(int drive, int track);
void (*readsector)(int drive, int sector, int track, int side, int density);
void (*writesector)(int drive, int sector, int track, int side, int density);
void (*readsector)(int drive, int sector, int track, int side, int density, int sector_size);
void (*writesector)(int drive, int sector, int track, int side, int density, int sector_size);
void (*readaddress)(int drive, int track, int side, int density);
void (*format)(int drive, int track, int side, int density);
void (*format)(int drive, int track, int side, int density, uint8_t fill);
uint8_t (*hole)(int drive);
void (*stop)();
void (*poll)();
} DRIVE;
@ -20,13 +21,15 @@ void disc_init();
void disc_reset();
void disc_poll();
void disc_seek(int drive, int track);
void disc_readsector(int drive, int sector, int track, int side, int density);
void disc_writesector(int drive, int sector, int track, int side, int density);
void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size);
void disc_writesector(int drive, int sector, int track, int side, int density, int sector_size);
void disc_readaddress(int drive, int track, int side, int density);
void disc_format(int drive, int track, int side, int density);
void disc_format(int drive, int track, int side, int density, uint8_t fill);
int disc_hole(int drive);
void disc_stop(int drive);
int disc_empty(int drive);
void disc_set_rate(int rate);
void disc_set_rate(int drive, int drvden, int rate);
void disc_set_drivesel(int drive);
extern int disc_time;
extern int disc_poll_time;
extern int disc_drivesel;

View file

@ -22,7 +22,7 @@ static uint8_t fdi_timing[256*1024];
static int fdi_pos;
static int fdi_revs;
static int fdi_sector, fdi_track, fdi_side, fdi_drive, fdi_density;
static int fdi_sector, fdi_track, fdi_side, fdi_drive, fdi_density, fdi_n;
static int fdi_inread, fdi_inwrite, fdi_readpos, fdi_inreadaddr;
static uint16_t CRCTable[256];
@ -62,6 +62,19 @@ void fdi_init()
fdi_setupcrc(0x1021, 0xcdb4);
}
int fdi_hole(int drive)
{
switch (fdi2raw_get_bit_rate(fdi[drive].h))
{
case 1000:
return 2;
case 500:
return 1;
default:
return 0;
}
}
void fdi_load(int drive, char *fn)
{
writeprot[drive] = fwriteprot[drive] = 1;
@ -76,6 +89,7 @@ void fdi_load(int drive, char *fn)
drives[drive].readsector = fdi_readsector;
drives[drive].writesector = fdi_writesector;
drives[drive].readaddress = fdi_readaddress;
drives[drive].hole = fdi_hole;
drives[drive].poll = fdi_poll;
drives[drive].format = fdi_format;
drives[drive].stop = fdi_stop;
@ -137,12 +151,13 @@ void fdi_writeback(int drive, int track)
return;
}
void fdi_readsector(int drive, int sector, int track, int side, int rate)
void fdi_readsector(int drive, int sector, int track, int side, int rate, int sector_size)
{
fdi_revs = 0;
fdi_sector = sector;
fdi_track = track;
fdi_side = side;
fdi_n = sector_size;
fdi_drive = drive;
if (rate == 2)
fdi_density = 1;
@ -161,12 +176,13 @@ void fdi_readsector(int drive, int sector, int track, int side, int rate)
fdi_readpos = 0;
}
void fdi_writesector(int drive, int sector, int track, int side, int rate)
void fdi_writesector(int drive, int sector, int track, int side, int rate, int sector_size)
{
fdi_revs = 0;
fdi_sector = sector;
fdi_track = track;
fdi_side = side;
fdi_n = sector_size;
fdi_drive = drive;
if (rate == 2)
fdi_density = 1;
@ -202,7 +218,7 @@ void fdi_readaddress(int drive, int track, int side, int rate)
fdi_readpos = 0;
}
void fdi_format(int drive, int track, int side, int rate)
void fdi_format(int drive, int track, int side, int rate, uint8_t fill)
{
fdi_revs = 0;
fdi_track = track;
@ -324,7 +340,7 @@ void fdi_poll()
if (!pollbytesleft)
{
// pclog("Header over %i,%i %i,%i\n", fdi_sectordat[0], fdi_sectordat[2], fdi_track, fdi_sector);
if ((fdi_sectordat[0] == fdi_track && (fdi_sectordat[2] == fdi_sector || fdi_sector == SECTOR_NEXT)) || fdi_inreadaddr)
if ((fdi_sectordat[0] == fdi_track && (fdi_sectordat[3] == fdi_n) && (fdi_sectordat[2] == fdi_sector || fdi_sector == SECTOR_NEXT)) || fdi_inreadaddr)
{
crc = (fdi_density) ? 0xcdb4 : 0xffff;
calccrc(0xFE);

View file

@ -2,9 +2,10 @@ void fdi_init();
void fdi_load(int drive, char *fn);
void fdi_close(int drive);
void fdi_seek(int drive, int track);
void fdi_readsector(int drive, int sector, int track, int side, int density);
void fdi_writesector(int drive, int sector, int track, int side, int density);
void fdi_readsector(int drive, int sector, int track, int side, int density, int sector_size);
void fdi_writesector(int drive, int sector, int track, int side, int density, int sector_size);
void fdi_readaddress(int drive, int sector, int side, int density);
void fdi_format(int drive, int sector, int side, int density);
void fdi_format(int drive, int sector, int side, int density, uint8_t fill);
int fdi_hole(int drive);
void fdi_stop();
void fdi_poll();

View file

@ -1,6 +1,8 @@
#include "ibm.h"
#include "fdd.h"
#include "disc.h"
#include "disc_img.h"
#include "disc_sector.h"
static struct
{
@ -9,35 +11,126 @@ static struct
int sectors, tracks, sides;
int sector_size;
int rate;
int xdf_type; /* 0 = not XDF, 1-5 = one of the five XDF types */
int hole;
double bitcell_period_300rpm;
} img[2];
//static FILE *img_f[2];
//static uint8_t trackinfoa[2][2][20*1024];
//static int img_dblside[2];
//static int img_sectors[2], img_size[2], img_trackc[2];
//static int img_dblstep[2];
//static int img_density[2];
static uint8_t xdf_track0[5][3];
static uint8_t xdf_spt[5];
static uint8_t xdf_map[5][24][3];
static int img_sector, img_track, img_side, img_drive;
static int img_inread, img_readpos, img_inwrite, img_inreadaddr;
static int img_notfound;
static int img_rsector=0;
static int img_informat=0;
static int img_sector_next;
void img_writeback(int drive, int track);
static int img_pause = 0;
static int img_index = 6250;
static int img_sector_size_code(int drive)
{
switch(img[drive].sector_size)
{
case 128:
return 0;
case 256:
return 1;
default:
case 512:
return 2;
case 1024:
return 3;
case 2048:
return 4;
case 4096:
return 5;
case 8192:
return 6;
case 16384:
return 7;
}
}
void img_init()
{
memset(img, 0, sizeof(img));
// adl[0] = adl[1] = 0;
img_notfound = 0;
}
static void add_to_map(uint8_t *arr, uint8_t p1, uint8_t p2, uint8_t p3)
{
arr[0] = p1;
arr[1] = p2;
arr[2] = p3;
}
static int xdf_maps_initialized = 0;
static void initialize_xdf_maps()
{
// XDF 5.25" 2HD
/* Adds, in this order: sectors per FAT, sectors per each side of track 0, difference between that and virtual sector number specified in BPB. */
add_to_map(xdf_track0[0], 9, 17, 2);
xdf_spt[0] = 3;
/* Adds, in this order: side, sequential order (not used in PCem), sector size. */
add_to_map(xdf_map[0][0], 0, 0, 3);
add_to_map(xdf_map[0][1], 0, 2, 6);
add_to_map(xdf_map[0][2], 1, 0, 2);
add_to_map(xdf_map[0][3], 0, 1, 2);
add_to_map(xdf_map[0][4], 1, 2, 6);
add_to_map(xdf_map[0][5], 1, 1, 3);
// XDF 3.5" 2HD
add_to_map(xdf_track0[1], 11, 19, 4);
xdf_spt[1] = 4;
add_to_map(xdf_map[1][0], 0, 0, 3);
add_to_map(xdf_map[1][1], 0, 2, 4);
add_to_map(xdf_map[1][2], 1, 3, 6);
add_to_map(xdf_map[1][3], 0, 1, 2);
add_to_map(xdf_map[1][4], 1, 1, 2);
add_to_map(xdf_map[1][5], 0, 3, 6);
add_to_map(xdf_map[1][6], 1, 0, 4);
add_to_map(xdf_map[1][7], 1, 2, 3);
// XDF 3.5" 2ED
add_to_map(xdf_track0[2], 22, 37, 9);
xdf_spt[2] = 4;
add_to_map(xdf_map[2][0], 0, 0, 3);
add_to_map(xdf_map[2][1], 0, 1, 4);
add_to_map(xdf_map[2][2], 0, 2, 5);
add_to_map(xdf_map[2][3], 0, 3, 7);
add_to_map(xdf_map[2][4], 1, 0, 3);
add_to_map(xdf_map[2][5], 1, 1, 4);
add_to_map(xdf_map[2][6], 1, 2, 5);
add_to_map(xdf_map[2][7], 1, 3, 7);
// XXDF 3.5" 2HD
add_to_map(xdf_track0[3], 12, 20, 4);
xdf_spt[3] = 2;
add_to_map(xdf_map[3][0], 0, 0, 5);
add_to_map(xdf_map[3][1], 1, 1, 6);
add_to_map(xdf_map[3][2], 0, 1, 6);
add_to_map(xdf_map[3][3], 1, 0, 5);
// XXDF 3.5" 2ED
add_to_map(xdf_track0[4], 21, 39, 9);
xdf_spt[4] = 2;
add_to_map(xdf_map[4][0], 0, 0, 6);
add_to_map(xdf_map[4][1], 1, 1, 7);
add_to_map(xdf_map[4][2], 0, 1, 7);
add_to_map(xdf_map[4][3], 1, 0, 6);
xdf_maps_initialized = 1;
}
void img_load(int drive, char *fn)
{
int size;
double bit_rate_300;
uint16_t bpb_bps;
uint16_t bpb_total;
uint8_t bpb_mid; /* Media type ID. */
uint8_t bpb_sectors;
uint8_t bpb_sides;
uint32_t bpt;
uint8_t max_spt; /* Used for XDF detection. */
if (!xdf_maps_initialized) initialize_xdf_maps(); /* Initialize XDF maps, will need them to properly register sectors in tracks. */
writeprot[drive] = 0;
img[drive].f = fopen(fn, "rb+");
@ -49,32 +142,167 @@ void img_load(int drive, char *fn)
writeprot[drive] = 1;
}
fwriteprot[drive] = writeprot[drive];
/* Read the BPB */
fseek(img[drive].f, 0x0B, SEEK_SET);
fread(&bpb_bps, 1, 2, img[drive].f);
fseek(img[drive].f, 0x13, SEEK_SET);
fread(&bpb_total, 1, 2, img[drive].f);
fseek(img[drive].f, 0x15, SEEK_SET);
bpb_mid = fgetc(img[drive].f);
fseek(img[drive].f, 0x18, SEEK_SET);
bpb_sectors = fgetc(img[drive].f);
fseek(img[drive].f, 0x1A, SEEK_SET);
bpb_sides = fgetc(img[drive].f);
fseek(img[drive].f, -1, SEEK_END);
size = ftell(img[drive].f) + 1;
img[drive].sides = 2;
img[drive].sector_size = 512;
if (size <= (160*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; img[drive].sides = 1; img[drive].rate = 2; }
else if (size <= (180*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; img[drive].sides = 1; img[drive].rate = 2; }
else if (size <= (320*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; img[drive].rate = 2; }
else if (size <= (360*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; img[drive].rate = 2; } /*Double density*/
else if (size < (1024*1024)) { img[drive].sectors = 9; img[drive].tracks = 80; img[drive].rate = 2; } /*Double density*/
else if (size <= 1228800) { img[drive].sectors = 15; img[drive].tracks = 80; img[drive].rate = 0; } /*High density 1.2MB*/
else if (size <= (0x1A4000-1)) { img[drive].sectors = 18; img[drive].tracks = 80; img[drive].rate = 0; } /*High density (not supported by Tandy 1000)*/
else if (size == 1884160) { img[drive].sectors = 23; img[drive].tracks = 80; img[drive].rate = 0; } /*XDF format - used by OS/2 Warp*/
else if (size == 1763328) { img[drive].sectors = 21; img[drive].tracks = 82; img[drive].rate = 0; } /*XDF format - used by OS/2 Warp*/
else if (size < (2048*1024)) { img[drive].sectors = 21; img[drive].tracks = 80; img[drive].rate = 0; } /*DMF format - used by Windows 95*/
else { img[drive].sectors = 36; img[drive].tracks = 80; img[drive].rate = 3; } /*E density*/
pclog("BPB reports %i sides and %i bytes per sector\n", bpb_sides, bpb_bps);
if ((bpb_sides < 1) || (bpb_sides > 2) || (bpb_bps < 128) || (bpb_bps > 2048))
{
/* The BPB is giving us a wacky number of sides and/or bytes per sector, therefore it is most probably
not a BPB at all, so we have to guess the parameters from file size. */
if (size <= (160*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; img[drive].sides = 1; bit_rate_300 = 250; }
else if (size <= (180*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; img[drive].sides = 1; bit_rate_300 = 250; }
else if (size <= (320*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; bit_rate_300 = 250; }
else if (size <= (360*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; bit_rate_300 = 250; } /*Double density*/
else if (size < (1024*1024)) { img[drive].sectors = 9; img[drive].tracks = 80; bit_rate_300 = 250; } /*Double density*/
else if (size <= 1228800) { img[drive].sectors = 15; img[drive].tracks = 80; bit_rate_300 = (500.0 * 300.0) / 360.0; } /*High density 1.2MB*/
else if (size <= (0x1A4000-1)) { img[drive].sectors = 18; img[drive].tracks = 80; bit_rate_300 = 500; } /*High density (not supported by Tandy 1000)*/
// else if (size == 1884160) { img[drive].sectors = 23; img[drive].tracks = 80; bit_rate_300 = 500; } /*XDF format - used by OS/2 Warp*/
// else if (size == 1763328) { img[drive].sectors = 21; img[drive].tracks = 82; bit_rate_300 = 500; } /*XDF format - used by OS/2 Warp*/
else if (size <= 2000000) { img[drive].sectors = 21; img[drive].tracks = 80; bit_rate_300 = 500; } /*DMF format - used by Windows 95 - changed by OBattler to 2000000, ie. the real unformatted capacity @ 500 kbps and 300 rpm */
else { img[drive].sectors = 36; img[drive].tracks = 80; bit_rate_300 = 1000; } /*E density*/
img[drive].xdf_type = 0;
}
else
{
/* The BPB readings appear to be valid, so let's set the values. */
/* Number of tracks = number of total sectors divided by sides times sectors per track. */
img[drive].tracks = ((uint32_t) bpb_total) / (((uint32_t) bpb_sides) * ((uint32_t) bpb_sectors));
/* The rest we just set directly from the BPB. */
img[drive].sectors = bpb_sectors;
img[drive].sides = bpb_sides;
/* Now we calculate bytes per track, which is bpb_sectors * bpb_bps. */
bpt = (uint32_t) bpb_sectors * (uint32_t) bpb_bps;
/* Now we should be able to calculate the bit rate. */
pclog("The image has %i bytes per track\n", bpt);
if (bpt <= 6250)
bit_rate_300 = 250; /* Double-density */
else if (bpt <= 7500)
bit_rate_300 = 300; /* Double-density, 300 kbps @ 300 rpm */
else if (bpt <= 10416)
{
bit_rate_300 = (bpb_mid == 0xF0) ? 500 : ((500.0 * 300.0) / 360.0); /* High-density @ 300 or 360 rpm, depending on media type ID */
max_spt = (bpb_mid == 0xF0) ? 22 : 18;
}
else if (bpt <= 12500) /* High-density @ 300 rpm */
{
bit_rate_300 = 500;
max_spt = 22;
}
else if (bpt <= 25000) /* Extended density @ 300 rpm */
{
bit_rate_300 = 1000;
max_spt = 45;
}
else /* Image too big, eject */
{
pclog("Image has more than 25000 bytes per track, ejecting...\n");
fclose(img[drive].f);
return;
}
if (bpb_bps == 512) /* BPB reports 512 bytes per sector, let's see if it's XDF or not */
{
if (bit_rate_300 <= 300) /* Double-density disk, not XDF */
{
img[drive].xdf_type = 0;
}
else
{
if (bpb_sectors > max_spt)
{
switch(bpb_sectors)
{
case 19: /* High density XDF @ 360 rpm */
img[drive].xdf_type = 1;
break;
case 23: /* High density XDF @ 300 rpm */
img[drive].xdf_type = 2;
break;
case 24: /* High density XXDF @ 300 rpm */
img[drive].xdf_type = 4;
break;
case 46: /* Extended density XDF */
img[drive].xdf_type = 3;
break;
case 48: /* Extended density XXDF */
img[drive].xdf_type = 5;
break;
default: /* Unknown, as we're beyond maximum sectors, get out */
fclose(img[drive].f);
return;
}
}
else /* Amount of sectors per track that fits into a track, therefore not XDF */
{
img[drive].xdf_type = 0;
}
}
}
else /* BPB reports sector size other than 512, can't possibly be XDF */
{
img[drive].xdf_type = 0;
}
}
if ((bit_rate_300 == 250) || (bit_rate_300 == 300))
{
img[drive].hole = 0;
}
else if (bit_rate_300 == 1000)
{
img[drive].hole = 2;
}
else
{
img[drive].hole = 1;
}
if (img[drive].xdf_type) /* In case of XDF-formatted image, write-protect */
{
writeprot[drive] = 1;
fwriteprot[drive] = writeprot[drive];
}
drives[drive].seek = img_seek;
drives[drive].readsector = img_readsector;
drives[drive].writesector = img_writesector;
drives[drive].readaddress = img_readaddress;
drives[drive].poll = img_poll;
drives[drive].format = img_format;
// pclog("img_load %d %p sectors=%i tracks=%i sides=%i sector_size=%i\n", drive, drives, img[drive].sectors, img[drive].tracks, img[drive].sides, img[drive].sector_size);
drives[drive].readsector = disc_sector_readsector;
drives[drive].writesector = disc_sector_writesector;
drives[drive].readaddress = disc_sector_readaddress;
drives[drive].hole = img_hole;
drives[drive].poll = disc_sector_poll;
drives[drive].format = disc_sector_format;
disc_sector_writeback[drive] = img_writeback;
img[drive].bitcell_period_300rpm = 1000000.0 / bit_rate_300*2.0;
pclog("bit_rate_300=%g\n", bit_rate_300);
pclog("bitcell_period_300=%g\n", img[drive].bitcell_period_300rpm);
// img[drive].bitcell_period_300rpm = disc_get_bitcell_period(img[drive].rate);
pclog("img_load %d %p sectors=%i tracks=%i sides=%i sector_size=%i hole=%i\n", drive, drives, img[drive].sectors, img[drive].tracks, img[drive].sides, img[drive].sector_size, img[drive].hole);
}
int img_hole(int drive)
{
return img[drive].hole;
}
void img_close(int drive)
{
@ -85,13 +313,19 @@ void img_close(int drive)
void img_seek(int drive, int track)
{
int side;
int current_xdft = img[drive].xdf_type - 1;
uint8_t sectors_fat, effective_sectors, sector_gap; /* Needed for XDF */
if (!img[drive].f)
return;
// pclog("Seek drive=%i track=%i sectors=%i sector_size=%i sides=%i\n", drive, track, img[drive].sectors,img[drive].sector_size, img[drive].sides);
if (drive_type[drive] && img[drive].tracks == 40)
pclog("Seek drive=%i track=%i sectors=%i sector_size=%i sides=%i\n", drive, track, img[drive].sectors,img[drive].sector_size, img[drive].sides);
// pclog(" %i %i\n", drive_type[drive], img[drive].tracks);
if (img[drive].tracks <= 41 && fdd_doublestep_40(drive))
track /= 2;
pclog("Disk seeked to track %i\n", track);
disc_track[drive] = track;
if (img[drive].sides == 2)
@ -105,12 +339,99 @@ void img_seek(int drive, int track)
fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size, SEEK_SET);
fread(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f);
}
disc_sector_reset(drive, 0);
disc_sector_reset(drive, 1);
int sector, current_pos;
if (img[drive].xdf_type)
{
sectors_fat = xdf_track0[current_xdft][0];
effective_sectors = xdf_track0[current_xdft][1];
sector_gap = xdf_track0[current_xdft][2];
if (!track)
{
/* Track 0, register sectors according to track 0 map. */
/* First, the "Side 0" buffer, will also contain one sector from side 1. */
current_pos = 0;
for (sector = 0; sector < sectors_fat; sector++)
{
disc_sector_add(drive, 0, track, 0, sector+0x81, 2,
img[drive].bitcell_period_300rpm,
&img[drive].track_data[0][current_pos]);
current_pos += 512;
}
disc_sector_add(drive, 1, track, 1, 0x81, 2,
img[drive].bitcell_period_300rpm,
&img[drive].track_data[0][current_pos]);
current_pos += 512;
for (sector = 0; sector < 7; sector++)
{
disc_sector_add(drive, 0, track, 0, sector+1, 2,
img[drive].bitcell_period_300rpm,
&img[drive].track_data[0][current_pos]);
current_pos += 512;
}
/* Now the "Side 1" buffer, will also contain one sector from side 0. */
current_pos = 0;
for (sector = 0; (sector < effective_sectors - 1); sector++)
{
disc_sector_add(drive, 1, track, 1, sector+0x82, 2,
img[drive].bitcell_period_300rpm,
&img[drive].track_data[1][current_pos]);
current_pos += 512;
}
disc_sector_add(drive, 0, track, 0, 8, 2,
img[drive].bitcell_period_300rpm,
&img[drive].track_data[1][current_pos]);
current_pos += 512;
}
else
{
/* Non-zero track, this will have sectors of various sizes. */
/* First, the "Side 0" buffer. */
current_pos = 0;
for (sector = 0; sector < xdf_spt[current_xdft]; sector++)
{
disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0],
xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2],
img[drive].bitcell_period_300rpm,
&img[drive].track_data[0][current_pos]);
current_pos += (128 << xdf_map[current_xdft][sector][2]);
}
/* Then, the "Side 1" buffer. */
current_pos = 0;
for (sector = xdf_spt[current_xdft]; sector < (xdf_spt[current_xdft] << 1); sector++)
{
disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0],
xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2],
img[drive].bitcell_period_300rpm,
&img[drive].track_data[1][current_pos]);
current_pos += (128 << xdf_map[current_xdft][sector][2]);
}
}
}
else
{
for (side = 0; side < img[drive].sides; side++)
{
for (sector = 0; sector < img[drive].sectors; sector++)
disc_sector_add(drive, side, track, side, sector+1, img_sector_size_code(drive),
img[drive].bitcell_period_300rpm,
&img[drive].track_data[side][sector * img->sector_size]);
}
}
}
void img_writeback(int drive, int track)
{
if (!img[drive].f)
return;
if (img[drive].xdf_type)
return; /*Should never happen*/
if (img[drive].sides == 2)
{
fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size * 2, SEEK_SET);
@ -124,215 +445,3 @@ void img_writeback(int drive, int track)
}
}
void img_readsector(int drive, int sector, int track, int side, int rate)
{
if (drive_type[drive] && rate == 1)
rate = 2;
if (sector == SECTOR_FIRST)
{
img_sector = 1 - 1;
img_sector_next = 2;
}
else if (sector == SECTOR_NEXT)
{
img_sector = img_sector_next - 1;
img_sector_next++;
}
else
img_sector = sector - 1;
img_track = track;
img_side = side;
img_drive = drive;
// pclog("imgS Read sector drive=%i side=%i track=%i sector=%i rate=%i\n",drive,side,track,sector, rate);
if (!img[drive].f || (side && img[drive].sides == 1) ||
(rate != img[drive].rate) || (track != disc_track[drive]) ||
img_sector > img[drive].sectors)
{
// pclog("Sector not found rate %i,%i track %i,%i\n", rate, img[drive].rate, track, disc_track[drive]);
img_notfound=500;
return;
}
// printf("Found\n");
img_inread = 1;
img_readpos = 0;
img_pause = 32;
}
void img_writesector(int drive, int sector, int track, int side, int rate)
{
if (drive_type[drive] && rate == 1)
rate = 2;
// if (imgdblstep[drive]) track/=2;
img_sector = sector - 1;
img_track = track;
img_side = side;
img_drive = drive;
// printf("imgS Write sector %i %i %i %i\n",drive,side,track,sector);
if (!img[drive].f || (side && img[drive].sides == 1) ||
(rate != img[drive].rate) || (track != disc_track[drive]) ||
sector > img[drive].sectors)
{
img_notfound = 500;
return;
}
img_inwrite = 1;
img_readpos = 0;
img_pause = 32;
}
void img_readaddress(int drive, int track, int side, int rate)
{
if (drive_type[drive] && rate == 1)
rate = 2;
img_drive = drive;
img_track = disc_track[drive];
img_side = side;
// pclog("Read address %i %i %i %i\n",drive,side,track, rate);
if (!img[drive].f || (side && img[drive].sides == 1) ||
(rate != img[drive].rate))
{
// pclog("Address not found rate %i,%i track %i,%i\n", rate, img[drive].rate, track, disc_track[drive]);
img_notfound=500;
return;
}
img_inreadaddr = 1;
img_readpos = 0;
img_pause = 100;//500;
img_pause = 32;
}
void img_format(int drive, int track, int side, int rate)
{
if (drive_type[drive] && rate == 1)
rate = 2;
img_drive = drive;
img_track = track;
img_side = side;
if (!img[drive].f || (side && img[drive].sides == 1) ||
(rate != img[drive].rate) || (track != disc_track[drive]))
{
img_notfound = 500;
return;
}
img_sector = 0;
img_readpos = 0;
img_informat = 1;
img_pause = 32;
}
void img_stop()
{
img_pause = img_notfound = img_inread = img_inwrite = img_inreadaddr = img_informat = 0;
}
void img_poll()
{
// pclog("img_poll %i %i %p\n", img_inread, img_readpos, img[img_drive].f);
img_index--;
if (!img_index)
{
img_index = 6250;
fdc_indexpulse();
}
if (img_pause)
{
img_pause--;
if (img_pause)
return;
}
if (img_notfound)
{
img_notfound--;
if (!img_notfound)
{
// pclog("Not found!\n");
fdc_notfound();
}
}
if (img_inread && img[img_drive].f)
{
// pclog("Read pos %i\n", img_readpos);
// if (!imgreadpos) pclog("%i\n",imgsector*imgsize[imgdrive]);
if (fdc_data(img[img_drive].track_data[img_side][(img_sector * img[img_drive].sector_size) + img_readpos]))
return;
img_readpos++;
if (img_readpos == img[img_drive].sector_size)
{
// pclog("Read %i bytes\n",img_readpos);
img_inread = 0;
fdc_finishread();
}
}
if (img_inwrite && img[img_drive].f)
{
int data;
if (writeprot[img_drive])
{
// pclog("writeprotect\n");
fdc_writeprotect();
img_inwrite = 0;
return;
}
// pclog("Write data %i\n",img_readpos);
data = fdc_getdata(img_readpos == (img[img_drive].sector_size - 1));
if (data == -1)
return;
img[img_drive].track_data[img_side][(img_sector * img[img_drive].sector_size) + img_readpos] = data;
img_readpos++;
if (img_readpos == img[img_drive].sector_size)
{
// pclog("write over\n");
img_inwrite = 0;
fdc_finishread();
img_writeback(img_drive, img_track);
}
}
if (img_inreadaddr && img[img_drive].f)
{
// pclog("img_inreadaddr %08X\n", fdc_sectorid);
fdc_sectorid(img_track, img_side,
img_rsector + ((img[img_drive].sector_size == 512) ? 1 : 0), (img[img_drive].sector_size == 256) ? 1 : ((img[img_drive].sector_size == 512) ? 2 : 3), 0, 0);
img_inreadaddr = 0;
img_rsector++;
if (img_rsector == img[img_drive].sectors)
{
img_rsector=0;
// pclog("img_rsector reset\n");
}
}
if (img_informat && img[img_drive].f)
{
if (writeprot[img_drive])
{
fdc_writeprotect();
img_informat = 0;
return;
}
img[img_drive].track_data[img_side][(img_sector * img[img_drive].sector_size) + img_readpos] = 0;
img_readpos++;
if (img_readpos == img[img_drive].sector_size)
{
img_readpos = 0;
img_sector++;
if (img_sector == img[img_drive].sectors)
{
img_informat = 0;
fdc_finishread();
img_writeback(img_drive, img_track);
}
}
}
}

View file

@ -6,5 +6,6 @@ void img_readsector(int drive, int sector, int track, int side, int density);
void img_writesector(int drive, int sector, int track, int side, int density);
void img_readaddress(int drive, int sector, int side, int density);
void img_format(int drive, int sector, int side, int density);
int img_hole(int drive);
void img_stop();
void img_poll();

385
src/disc_sector.c Normal file
View file

@ -0,0 +1,385 @@
#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, int track);
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;
static int disc_sector_track;
static int disc_sector_side;
static int disc_sector_drive;
static int disc_sector_sector;
static int disc_sector_n;
static int disc_intersector_delay = 0;
static uint8_t disc_sector_fill;
static int cur_sector, cur_byte;
static int index_count;
void disc_sector_reset(int drive, int side)
{
disc_sector_count[drive][side] = 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()
{
return (disc_sector_data[disc_sector_drive][disc_sector_side][cur_sector].rate * 300) / fdd_getrpm(disc_sector_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(), rate, sector, track, side);
if (sector == SECTOR_FIRST)
disc_sector_state = STATE_READ_FIND_FIRST_SECTOR;
else if (sector == SECTOR_NEXT)
disc_sector_state = STATE_READ_FIND_NEXT_SECTOR;
else
disc_sector_state = STATE_READ_FIND_SECTOR;
disc_sector_track = track;
disc_sector_side = side;
disc_sector_drive = drive;
disc_sector_sector = sector;
disc_sector_n = sector_size;
index_count = 0;
}
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_state = STATE_WRITE_FIND_SECTOR;
disc_sector_track = track;
disc_sector_side = side;
disc_sector_drive = drive;
disc_sector_sector = sector;
disc_sector_n = sector_size;
index_count = 0;
}
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_state = STATE_READ_FIND_ADDRESS;
disc_sector_track = track;
disc_sector_side = side;
disc_sector_drive = drive;
index_count = 0;
}
void disc_sector_format(int drive, int track, int side, int rate, uint8_t fill)
{
disc_sector_state = STATE_FORMAT_FIND;
disc_sector_track = track;
disc_sector_side = side;
disc_sector_drive = drive;
disc_sector_fill = fill;
index_count = 0;
}
void disc_sector_stop()
{
disc_sector_state = STATE_IDLE;
}
static void advance_byte()
{
if (disc_intersector_delay)
{
disc_intersector_delay--;
return;
}
cur_byte++;
if (cur_byte >= (128 << disc_sector_data[disc_sector_drive][disc_sector_side][cur_sector].n))
{
cur_byte = 0;
cur_sector++;
if (cur_sector >= disc_sector_count[disc_sector_drive][disc_sector_side])
{
cur_sector = 0;
fdc_indexpulse();
index_count++;
}
disc_intersector_delay = 40;
}
}
void disc_sector_poll()
{
sector_t *s;
int data;
if (cur_sector >= disc_sector_count[disc_sector_drive][disc_sector_side])
cur_sector = 0;
if (cur_byte >= (128 << disc_sector_data[disc_sector_drive][disc_sector_side][cur_sector].n))
cur_byte = 0;
s = &disc_sector_data[disc_sector_drive][disc_sector_side][cur_sector];
switch (disc_sector_state)
{
case STATE_IDLE:
break;
case STATE_READ_FIND_SECTOR:
/* pclog("STATE_READ_FIND_SECTOR: cur_sector=%i cur_byte=%i sector=%i,%i side=%i,%i track=%i,%i period=%i,%i\n",
cur_sector, cur_byte,
disc_sector_sector, s->r,
disc_sector_side, s->h,
disc_sector_track, s->c,
fdc_get_bitcell_period(), get_bitcell_period());*/
if (index_count > 1)
{
// pclog("Find sector not found\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
/* pclog("%i %i %i %i %i\n", cur_byte, disc_sector_track != s->c,
disc_sector_side != s->h,
disc_sector_sector != s->r,
fdc_get_bitcell_period() != get_bitcell_period());*/
if (cur_byte || disc_sector_track != s->c ||
disc_sector_side != s->h ||
disc_sector_sector != s->r ||
disc_sector_n != s->n ||
fdc_get_bitcell_period() != get_bitcell_period() ||
!fdd_can_read_medium(disc_sector_drive ^ fdd_swap) ||
disc_intersector_delay)
{
advance_byte();
break;
}
disc_sector_state = STATE_READ_SECTOR;
case STATE_READ_SECTOR:
// pclog("STATE_READ_SECTOR: cur_byte=%i %i\n", cur_byte, disc_intersector_delay);
if (fdc_data(s->data[cur_byte]))
{
// pclog("fdc_data failed\n");
return;
}
advance_byte();
if (!cur_byte)
{
disc_sector_state = STATE_IDLE;
fdc_finishread();
}
break;
case STATE_READ_FIND_FIRST_SECTOR:
if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap)))
{
// pclog("Medium is of a density not supported by the drive\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
if (cur_byte || !index_count || fdc_get_bitcell_period() != get_bitcell_period() ||
disc_intersector_delay)
{
advance_byte();
break;
}
disc_sector_state = STATE_READ_FIRST_SECTOR;
case STATE_READ_FIRST_SECTOR:
if (fdc_data(s->data[cur_byte]))
return;
advance_byte();
if (!cur_byte)
{
disc_sector_state = STATE_IDLE;
fdc_finishread();
}
break;
case STATE_READ_FIND_NEXT_SECTOR:
if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap)))
{
// pclog("Medium is of a density not supported by the drive\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
if (index_count)
{
// pclog("Find next sector hit end of track\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
if (cur_byte || fdc_get_bitcell_period() != get_bitcell_period() ||
disc_intersector_delay)
{
advance_byte();
break;
}
disc_sector_state = STATE_READ_NEXT_SECTOR;
case STATE_READ_NEXT_SECTOR:
if (fdc_data(s->data[cur_byte]))
break;
advance_byte();
if (!cur_byte)
{
disc_sector_state = STATE_IDLE;
fdc_finishread();
}
break;
case STATE_WRITE_FIND_SECTOR:
if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap)))
{
// pclog("Medium is of a density not supported by the drive\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
if (writeprot[disc_sector_drive])
{
fdc_writeprotect();
return;
}
if (index_count > 1)
{
// pclog("Write find sector not found\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
if (cur_byte || disc_sector_track != s->c ||
disc_sector_side != s->h ||
disc_sector_sector != s->r ||
disc_sector_n != s->n ||
fdc_get_bitcell_period() != get_bitcell_period() ||
disc_intersector_delay)
{
advance_byte();
break;
}
disc_sector_state = STATE_WRITE_SECTOR;
case STATE_WRITE_SECTOR:
data = fdc_getdata(cur_byte == ((128 << s->n) - 1));
if (data == -1)
break;
s->data[cur_byte] = data;
advance_byte();
if (!cur_byte)
{
disc_sector_state = STATE_IDLE;
disc_sector_writeback[disc_sector_drive](disc_sector_drive, disc_sector_track);
fdc_finishread();
}
break;
case STATE_READ_FIND_ADDRESS:
if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap)))
{
// pclog("Medium is of a density not supported by the drive\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
if (index_count)
{
// pclog("Find next sector hit end of track\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
if (cur_byte || fdc_get_bitcell_period() != get_bitcell_period() ||
disc_intersector_delay)
{
advance_byte();
break;
}
disc_sector_state = STATE_READ_ADDRESS;
case STATE_READ_ADDRESS:
fdc_sectorid(s->c, s->h, s->r, s->n, 0, 0);
disc_sector_state = STATE_IDLE;
break;
case STATE_FORMAT_FIND:
if (writeprot[disc_sector_drive])
{
fdc_writeprotect();
return;
}
if (!index_count || fdc_get_bitcell_period() != get_bitcell_period() ||
disc_intersector_delay)
{
advance_byte();
break;
}
if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap)))
{
// pclog("Medium is of a density not supported by the drive\n");
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
if (fdc_get_bitcell_period() != get_bitcell_period())
{
fdc_notfound();
disc_sector_state = STATE_IDLE;
break;
}
disc_sector_state = STATE_FORMAT;
case STATE_FORMAT:
if (!disc_intersector_delay && fdc_get_bitcell_period() == get_bitcell_period())
s->data[cur_byte] = disc_sector_fill;
advance_byte();
if (index_count == 2)
{
disc_sector_writeback[disc_sector_drive](disc_sector_drive, disc_sector_track);
fdc_finishread();
disc_sector_state = STATE_IDLE;
}
break;
}
}

11
src/disc_sector.h Normal file
View file

@ -0,0 +1,11 @@
void disc_sector_reset(int drive, int side);
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);
void disc_sector_readsector(int drive, int sector, int track, int side, int density, int sector_size);
void disc_sector_writesector(int drive, int sector, int track, int side, int density, int sector_size);
void disc_sector_readaddress(int drive, int sector, int side, int density);
void disc_sector_format(int drive, int sector, int side, int density, uint8_t fill);
void disc_sector_stop();
void disc_sector_poll();
void disc_sector_stop();
extern void (*disc_sector_writeback[2])(int drive, int track);

453
src/fdc.c
View file

@ -4,6 +4,7 @@
#include "disc.h"
#include "dma.h"
#include "fdd.h"
#include "io.h"
#include "pic.h"
#include "timer.h"
@ -16,6 +17,7 @@ typedef struct FDC
{
uint8_t dor,stat,command,dat,st0;
int head,track[256],sector,drive,lastdrive;
int rw_track;
int pos;
uint8_t params[256];
uint8_t res[256];
@ -42,6 +44,22 @@ typedef struct FDC
int dskchg_activelow;
int enable_3f1;
int bitcell_period;
int is_nsc; /* 1 = FDC is on a National Semiconductor Super I/O chip, 0 = other FDC. This is needed,
because the National Semiconductor Super I/O chips add some FDC commands. */
int enh_mode;
int rwc[2];
int boot_drive;
int densel_polarity;
int densel_force;
int drvrate[2];
int dma;
int fifo, tfifo;
int fifobufpos;
uint8_t fifobuf[16];
} FDC;
static FDC fdc;
@ -65,11 +83,59 @@ void fdc_reset()
fdc.head = 0;
fdc.abort = 0;
if (!AT)
fdc.rate=2;
{
fdc.rate = 2;
// fdc_update_rate();
}
// pclog("Reset FDC\n");
}
int ins;
void fdc_reset_fifo_buf()
{
int i = 0;
memset(fdc.fifobuf, 0, 16);
fdc.fifobufpos = 0;
}
void fdc_fifo_buf_write(int val)
{
if (fdc.fifobufpos < fdc.tfifo)
{
fdc.fifobuf[fdc.fifobufpos] = val;
fdc.fifobufpos++;
fdc.fifobufpos %= fdc.tfifo;
// pclog("FIFO buffer position = %02X\n", fdc.fifobufpos);
if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0;
}
}
int fdc_fifo_buf_read()
{
int temp = 0;
if (fdc.fifobufpos < fdc.tfifo)
{
temp = fdc.fifobuf[fdc.fifobufpos];
fdc.fifobufpos++;
fdc.fifobufpos %= fdc.tfifo;
// pclog("FIFO buffer position = %02X\n", fdc.fifobufpos);
if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0;
}
return temp;
}
/* For DMA mode, just goes ahead in FIFO buffer but doesn't actually read or write anything. */
void fdc_fifo_buf_dummy()
{
if (fdc.fifobufpos < fdc.tfifo)
{
fdc.fifobufpos++;
fdc.fifobufpos %= fdc.tfifo;
// pclog("FIFO buffer position = %02X\n", fdc.fifobufpos);
if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0;
}
}
static void fdc_int()
{
if (!fdc.pcjr)
@ -93,9 +159,164 @@ static void fdc_watchdog_poll(void *p)
}
}
/* fdc.rwc per Winbond W83877F datasheet:
0 = normal;
1 = 500 kbps, 360 rpm;
2 = 500 kbps, 300 rpm;
3 = 250 kbps
Drive is only aware of selected rate and densel, so on real hardware, the rate expected by FDC and the rate actually being
processed by drive can mismatch, in which case the FDC won't receive the correct data.
*/
int bit_rate = 250;
void fdc_update_is_nsc(int is_nsc)
{
fdc.is_nsc = is_nsc;
}
void fdc_update_enh_mode(int enh_mode)
{
fdc.enh_mode = enh_mode;
}
int fdc_get_rwc(int drive)
{
return fdc.rwc[drive];
}
void fdc_update_rwc(int drive, int rwc)
{
fdc.rwc[drive] = rwc;
}
int fdc_get_boot_drive()
{
return fdc.boot_drive;
}
void fdc_update_boot_drive(int boot_drive)
{
fdc.boot_drive = boot_drive;
}
void fdc_update_densel_polarity(int densel_polarity)
{
fdc.densel_polarity = densel_polarity;
}
void fdc_update_densel_force(int densel_force)
{
fdc.densel_force = densel_force;
}
void fdc_update_drvrate(int drive, int drvrate)
{
fdc.drvrate[drive] = drvrate;
}
void fdc_update_rate(int drive)
{
if ((fdc.rwc[drive] == 1) || (fdc.rwc[drive] == 2))
{
bit_rate = 500;
}
else if (fdc.rwc[drive] == 3)
{
bit_rate = 250;
}
else switch (fdc.rate)
{
case 0: /*High density*/
bit_rate = 500;
break;
case 1: /*Double density (360 rpm)*/
switch(fdc.drvrate[drive])
{
case 0:
bit_rate = 300;
break;
case 1:
bit_rate = 500;
break;
case 2:
bit_rate = 2000;
break;
}
break;
case 2: /*Double density*/
bit_rate = 250;
break;
case 3: /*Extended density*/
bit_rate = 1000;
break;
}
fdc.bitcell_period = 1000000 / bit_rate*2; /*Bitcell period in ns*/
// pclog("fdc_update_rate: rate=%i bit_rate=%i bitcell_period=%i\n", fdc.rate, bit_rate, fdc.bitcell_period);
}
int fdc_get_bitcell_period()
{
return fdc.bitcell_period;
}
static int fdc_get_densel(int drive)
{
switch (fdc.rwc[drive])
{
case 1:
case 3:
return 0;
case 2:
return 1;
}
if (!fdc.is_nsc)
{
switch (fdc.densel_force)
{
case 2:
return 1;
case 3:
return 0;
}
}
else
{
switch (fdc.densel_force)
{
case 0:
return 0;
case 1:
return 1;
}
}
switch (fdc.rate)
{
case 0:
case 3:
return fdc.densel_polarity ? 1 : 0;
case 1:
case 2:
return fdc.densel_polarity ? 0 : 1;
}
}
static void fdc_rate(int drive)
{
fdc_update_rate(drive);
disc_set_rate(drive, fdc.drvrate[drive], fdc.rate);
fdd_set_densel(fdc_get_densel(drive));
}
void fdc_write(uint16_t addr, uint8_t val, void *priv)
{
// pclog("Write FDC %04X %02X %04X:%04X %i %02X %i rate=%i %i\n",addr,val,cs>>4,pc,ins,fdc.st0,ins,fdc.rate, fdc.data_ready);
int drive;
switch (addr&7)
{
case 1: return;
@ -149,6 +370,14 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
fdc.dor=val;
// printf("DOR now %02X\n",val);
return;
case 3:
/* TDR */
if (fdc.enh_mode)
{
drive = (fdc.dor & 1) ^ fdd_swap;
fdc.rwc[drive] = (val & 0x30) >> 4;
}
return;
case 4:
if (val & 0x80)
{
@ -162,8 +391,16 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
case 5: /*Command register*/
if ((fdc.stat & 0xf0) == 0xb0)
{
fdc.dat = val;
fdc.stat &= ~0x80;
if (fdc.pcjr || !fdc.fifo)
{
fdc.dat = val;
fdc.stat &= ~0x80;
}
else
{
fdc_fifo_buf_write(val);
if (fdc.fifobufpos == 0) fdc.stat &= ~0x80;
}
break;
}
// if (fdc.inread)
@ -178,6 +415,15 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
// pclog("Starting FDC command %02X\n",fdc.command);
switch (fdc.command&0x1F)
{
case 1: /*Mode*/
if (!fdc.is_nsc) goto bad_command;
fdc.pnum=0;
fdc.ptot=4;
fdc.stat=0x90;
fdc.pos=0;
fdc.format_state = 0;
break;
case 2: /*Read track*/
fdc.pnum=0;
fdc.ptot=8;
@ -273,13 +519,19 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0x18:
fdc.stat = 0x10;
discint = 0xfc;
if (!fdc.is_nsc) goto bad_command;
fdc.lastdrive = fdc.drive;
discint = 0x10;
fdc.pos = 0;
fdc_callback();
/* fdc.stat = 0x10;
discint = 0xfc;
fdc_callback(); */
break;
default:
fatal("Bad FDC command %02X\n",val);
bad_command:
// fatal("Bad FDC command %02X\n",val);
// dumpregs();
// exit(-1);
fdc.stat=0x10;
@ -304,31 +556,35 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
// fdc.drive = fdc.params[0] & 3;
disc_drivesel = fdc.drive & 1;
fdc_reset_stat = 0;
disc_set_drivesel(fdc.drive & 1);
switch (discint)
{
case 2: /*Read a track*/
fdc.track[fdc.drive]=fdc.params[1];
fdc_rate(fdc.drive);
fdc.head=fdc.params[2];
fdc.sector=fdc.params[3];
fdc.eot[fdc.drive] = fdc.params[5];
if (fdc.config & 0x40)
disc_seek(fdc.drive, fdc.track[fdc.drive]);
fdd_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]);
fdc.track[fdc.drive]=fdc.params[1];
// pclog("Read a track track=%i head=%i sector=%i eot=%i\n", fdc.track[fdc.drive], fdc.head, fdc.sector, fdc.eot[fdc.drive]);
disc_readsector(fdc.drive, SECTOR_FIRST, fdc.track[fdc.drive], fdc.head, fdc.rate);
disc_readsector(fdc.drive, SECTOR_FIRST, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]);
disctime = 0;
readflash = 1;
fdc.inread = 1;
break;
case 5: /*Write data*/
fdc.track[fdc.drive]=fdc.params[1];
fdc_rate(fdc.drive);
fdc.head=fdc.params[2];
fdc.sector=fdc.params[3];
fdc.eot[fdc.drive] = fdc.params[4];
fdc.eot[fdc.drive] = fdc.params[5];
if (fdc.config & 0x40)
disc_seek(fdc.drive, fdc.track[fdc.drive]);
fdd_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]);
fdc.track[fdc.drive]=fdc.params[1];
fdc.rw_track = fdc.params[1];
disc_writesector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate);
disc_writesector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]);
disctime = 0;
fdc.written = 0;
readflash = 1;
@ -339,14 +595,16 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
break;
case 6: /*Read data*/
fdc.track[fdc.drive]=fdc.params[1];
fdc_rate(fdc.drive);
fdc.head=fdc.params[2];
fdc.sector=fdc.params[3];
fdc.eot[fdc.drive] = fdc.params[4];
fdc.eot[fdc.drive] = fdc.params[5];
if (fdc.config & 0x40)
disc_seek(fdc.drive, fdc.track[fdc.drive]);
fdd_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]);
fdc.track[fdc.drive]=fdc.params[1];
fdc.rw_track = fdc.params[1];
disc_readsector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate);
disc_readsector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]);
disctime = 0;
readflash = 1;
fdc.inread = 1;
@ -355,10 +613,12 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
case 7: /*Recalibrate*/
fdc.stat = 1 << fdc.drive;
disctime = 0;
disc_seek(fdc.drive, 0);
fdd_seek(fdc.drive, SEEK_RECALIBRATE);
break;
case 0x0d: /*Format*/
fdc_rate(fdc.drive);
fdc.head = (fdc.params[0] & 4) ? 1 : 0;
fdc.format_state = 1;
fdc.pos = 0;
fdc.stat = 0x30;
@ -368,13 +628,15 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
fdc.stat = 1 << fdc.drive;
fdc.head = (fdc.params[0] & 4) ? 1 : 0;
disctime = 0;
disc_seek(fdc.drive, fdc.params[1]);
fdd_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]);
// pclog("Seek to %i\n", fdc.params[1]);
break;
case 10: /*Read sector ID*/
fdc_rate(fdc.drive);
disctime = 0;
fdc.head = (fdc.params[0] & 4) ? 1 : 0;
// rpclog("Read sector ID %i %i\n", fdc.rate, fdc.drive);
// pclog("Read sector ID %i %i\n", fdc.rate, fdc.drive);
disc_readaddress(fdc.drive, fdc.track[fdc.drive], fdc.head, fdc.rate);
break;
}
@ -384,7 +646,6 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv)
case 7:
if (!AT) return;
fdc.rate=val&3;
disc_set_rate(fdc.rate);
disc_3f7=val;
return;
@ -398,21 +659,28 @@ int paramstogo=0;
uint8_t fdc_read(uint16_t addr, void *priv)
{
uint8_t temp;
int drive;
// /*if (addr!=0x3f4) */printf("Read FDC %04X %04X:%04X %04X %i %02X %02x %i ",addr,cs>>4,pc,BX,fdc.pos,fdc.st0,fdc.stat,ins);
switch (addr&7)
{
case 1: /*???*/
drive = (fdc.dor & 1) ^ fdd_swap;
if (!fdc.enable_3f1)
return 0xff;
// temp=0x50;
temp = 0x70;
if (fdc.dor & 1)
if (drive)
temp &= ~0x40;
else
temp &= ~0x20;
break;
case 3:
temp = 0x20;
if (!fdc.enh_mode)
temp = 0x20;
else
{
temp = fdc.rwc[drive] << 4;
}
break;
case 4: /*Status*/
temp=fdc.stat;
@ -421,7 +689,12 @@ uint8_t fdc_read(uint16_t addr, void *priv)
fdc.stat&=~0x80;
if ((fdc.stat & 0xf0) == 0xf0)
{
temp = fdc.dat;
if (fdc.pcjr || !fdc.fifo)
temp = fdc.dat;
else
{
temp = fdc_fifo_buf_read();
}
break;
}
if (paramstogo)
@ -457,8 +730,9 @@ uint8_t fdc_read(uint16_t addr, void *priv)
fdc.stat &= 0xf0;
break;
case 7: /*Disk change*/
if (fdc.dor & (0x10 << (fdc.dor & 1)))
temp = (disc_changed[fdc.drive] || drive_empty[fdc.drive]) ? 0x80 : 0;
drive = (fdc.dor & 1) ^ fdd_swap;
if (fdc.dor & (0x10 << drive))
temp = (disc_changed[drive] || drive_empty[drive])?0x80:0;
else
temp = 0;
if (fdc.dskchg_activelow) /*PC2086/3086 seem to reverse this bit*/
@ -497,6 +771,11 @@ void fdc_callback()
fdc_int();
fdc_reset_stat = 4;
return;
case 1: /*Mode*/
fdc.stat=0x80;
fdc.densel_force = (fdc.params[2] & 0xC0) >> 6;
return;
case 2: /*Read track*/
readflash = 1;
fdc.eot[fdc.drive]--;
@ -518,17 +797,18 @@ void fdc_callback()
return;
}
else
disc_readsector(fdc.drive, SECTOR_NEXT, fdc.track[fdc.drive], fdc.head, fdc.rate);
disc_readsector(fdc.drive, SECTOR_NEXT, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]);
fdc.inread = 1;
return;
case 3: /*Specify*/
fdc.stat=0x80;
fdc.specify[0] = fdc.params[0];
fdc.specify[1] = fdc.params[1];
fdc.dma = (fdc.specify[1] & 1) ^ 1;
return;
case 4: /*Sense drive status*/
fdc.res[10] = (fdc.params[0] & 7) | 0x28;
if (!fdc.track[fdc.drive])
if (fdd_track0(fdc.drive))
fdc.res[10] |= 0x10;
if (writeprot[fdc.drive])
fdc.res[10] |= 0x40;
@ -549,7 +829,8 @@ void fdc_callback()
fdc.head ^= 1;
if (!fdc.head)
{
fdc.track[fdc.drive]++;
fdc.rw_track++;
// fdc.track[fdc.drive]++;
/* if (fdc.track[fdc.drive] >= 79)
{
fdc.track[fdc.drive] = 79;
@ -559,7 +840,8 @@ void fdc_callback()
}
else
{
fdc.track[fdc.drive]++;
fdc.rw_track++;
// fdc.track[fdc.drive]++;
fdc.tc = 1;
}
}
@ -570,14 +852,14 @@ void fdc_callback()
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[7]=fdc.rw_track;
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
return;
}
disc_writesector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate);
disc_writesector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]);
// ioc_fiq(IOC_FIQ_DISC_DATA);
return;
case 6: /*Read data*/
@ -592,7 +874,8 @@ void fdc_callback()
fdc.head ^= 1;
if (!fdc.head)
{
fdc.track[fdc.drive]++;
fdc.rw_track++;
// fdc.track[fdc.drive]++;
/* if (fdc.track[fdc.drive] >= 79)
{
fdc.track[fdc.drive] = 79;
@ -602,7 +885,8 @@ void fdc_callback()
}
else
{
fdc.track[fdc.drive]++;
fdc.rw_track++;
// fdc.track[fdc.drive]++;
fdc.tc = 1;
}
}
@ -614,14 +898,14 @@ void fdc_callback()
fdc.stat=0xD0;
fdc.res[4]=(fdc.head?4:0)|fdc.drive;
fdc.res[5]=fdc.res[6]=0;
fdc.res[7]=fdc.track[fdc.drive];
fdc.res[7]=fdc.rw_track;
fdc.res[8]=fdc.head;
fdc.res[9]=fdc.sector;
fdc.res[10]=fdc.params[4];
paramstogo=7;
return;
}
disc_readsector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate);
disc_readsector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]);
fdc.inread = 1;
return;
@ -686,10 +970,10 @@ void fdc_callback()
disctime = 128 * (1 << TIMER_SHIFT);
timer_update_outstanding();
}
else if (fdc.format_state == 4)
else if (fdc.format_state == 3)
{
// rpclog("Format next stage\n");
disc_format(fdc.drive, fdc.track[fdc.drive], fdc.head, fdc.rate);
// pclog("Format next stage track %i head %i\n", fdc.track[fdc.drive], fdc.head);
disc_format(fdc.drive, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]);
fdc.format_state = 4;
}
else
@ -756,6 +1040,9 @@ void fdc_callback()
case 0x13: /*Configure*/
fdc.config = fdc.params[1];
fdc.pretrk = fdc.params[2];
fdc.fifo = (fdc.params[1] & 0x20) ? 0 : 1;
fdc.tfifo = (fdc.params[1] & 0xF) + 1;
pclog("FIFO is now %02X, threshold is %02X\n", fdc.fifo, fdc.tfifo);
fdc.stat = 0x80;
disctime = 0;
// picint(0x40);
@ -777,6 +1064,13 @@ void fdc_callback()
disctime = 0;
return;
case 0x18: /*NSC*/
fdc.stat = (fdc.stat & 0xf) | 0xd0;
fdc.res[10] = 0x73;
paramstogo=1;
discint=0;
disctime = 0;
return;
case 0xfc: /*Invalid*/
fdc.dat = fdc.st0 = 0x80;
@ -797,7 +1091,7 @@ void fdc_callback()
void fdc_overrun()
{
img_stop();
disc_sector_stop();
disctime = 0;
fdc_int();
@ -817,7 +1111,7 @@ int fdc_data(uint8_t data)
if (fdc.tc)
return 0;
if (fdc.pcjr)
if (fdc.pcjr || !fdc.dma)
{
if (fdc.data_ready)
{
@ -826,15 +1120,44 @@ int fdc_data(uint8_t data)
return -1;
}
fdc.dat = data;
fdc.data_ready = 1;
fdc.stat = 0xf0;
// pclog("fdc_data\n");
if (fdc.pcjr || !fdc.fifo)
{
fdc.dat = data;
fdc.data_ready = 1;
fdc.stat = 0xf0;
}
else
{
// FIFO enabled
fdc_fifo_buf_write(data);
if (fdc.fifobufpos == 0)
{
// We have wrapped around, means FIFO is over
fdc.data_ready = 1;
fdc.stat = 0xf0;
}
}
}
else
{
if (dma_channel_write(2, data) & DMA_OVER)
fdc.tc = 1;
if (!fdc.fifo)
{
fdc.data_ready = 1;
fdc.stat = 0xd0;
}
else
{
fdc_fifo_buf_dummy();
if (fdc.fifobufpos == 0)
{
// We have wrapped around, means FIFO is over
fdc.data_ready = 1;
fdc.stat = 0xd0;
}
}
}
return 0;
@ -918,7 +1241,7 @@ int fdc_getdata(int last)
{
int data;
if (fdc.pcjr)
if (fdc.pcjr || !fdc.dma)
{
if (fdc.written)
{
@ -926,14 +1249,38 @@ int fdc_getdata(int last)
// pclog("Overrun\n");
return -1;
}
data = fdc.dat;
if (!last)
fdc.stat = 0xb0;
if (fdc.pcjr || !fdc.fifo)
{
data = fdc.dat;
if (!last)
fdc.stat = 0xb0;
}
else
{
data = fdc_fifo_buf_read();
if (!last && (fdc.fifobufpos == 0))
fdc.stat = 0xb0;
}
}
else
{
data = dma_channel_read(2);
if (!fdc.fifo)
{
if (!last)
fdc.stat = 0x90;
}
else
{
fdc_fifo_buf_dummy();
if (!last && (fdc.fifobufpos == 0))
fdc.stat = 0x90;
}
if (data & DMA_OVER)
fdc.tc = 1;
}
@ -968,6 +1315,14 @@ void fdc_init()
timer_add(fdc_callback, &disctime, &disctime, NULL);
fdc.dskchg_activelow = 0;
fdc.enable_3f1 = 1;
fdc_update_enh_mode(0);
fdc_update_densel_polarity(1);
fdc_update_rwc(0, 0);
fdc_update_rwc(1, 0);
fdc_update_densel_force(0);
fdc.fifo = fdc.tfifo = 0;
}
void fdc_add()

View file

@ -9,3 +9,15 @@ void fdc_abort();
void fdc_discchange_clear(int drive);
void fdc_set_dskchg_activelow();
void fdc_3f1_enable(int enable);
int fdc_get_bitcell_period();
/* A few functions to communicate between Super I/O chips and the FDC. */
void fdc_update_is_nsc(int is_nsc);
void fdc_update_enh_mode(int enh_mode);
int fdc_get_rwc(int drive);
void fdc_update_rwc(int drive, int rwc);
int fdc_get_boot_drive();
void fdc_update_boot_drive(int boot_drive);
void fdc_update_densel_polarity(int densel_polarity);
void fdc_update_densel_force(int densel_force);
void fdc_update_drvrate(int drive, int drvrate);

View file

@ -1,6 +1,7 @@
#include "ibm.h"
#include "fdc.h"
#include "fdd.h"
#include "io.h"
#include "lpt.h"
#include "serial.h"
@ -109,6 +110,11 @@ void fdc37c665_write(uint16_t port, uint8_t val, void *priv)
lpt1_init(0x278);
break;
}
fdc_update_enh_mode((fdc37c665_regs[3] & 2) ? 1 : 0);
fdc_update_densel_force((fdc37c665_regs[5] & 0x18) >> 3);
fdd_swap = ((fdc37c665_regs[5] & 0x20) >> 5);
}
}
else
@ -133,6 +139,8 @@ void fdc37c665_init()
{
io_sethandler(0x03f0, 0x0002, fdc37c665_read, NULL, NULL, fdc37c665_write, NULL, NULL, NULL);
fdc_update_is_nsc(0);
fdc37c665_lock[0] = fdc37c665_lock[1] = 0;
fdc37c665_regs[0x0] = 0x3b;
fdc37c665_regs[0x1] = 0x9f;
@ -150,4 +158,8 @@ void fdc37c665_init()
fdc37c665_regs[0xd] = 0x65;
fdc37c665_regs[0xe] = 0x01;
fdc37c665_regs[0xf] = 0x00;
fdc_update_densel_polarity(1);
fdc_update_densel_force(0);
fdd_swap = 0;
}

183
src/fdd.c Normal file
View file

@ -0,0 +1,183 @@
#include "ibm.h"
#include "disc.h"
#include "fdc.h"
#include "fdd.h"
static struct
{
int type;
int track;
int densel;
int drate;
int kbps;
int fdc_kbps;
} fdd[2];
/* Flags:
Bit 0: 300 rpm supported;
Bit 1: 360 rpm supported;
Bit 2: size (0 = 3.5", 1 = 5.25");
Bit 3: double density supported;
Bit 4: high density supported;
Bit 5: extended density supported;
Bit 6: double step for 40-track media;
*/
#define FLAG_RPM_300 1
#define FLAG_RPM_360 2
#define FLAG_525 4
#define FLAG_HOLE0 8
#define FLAG_HOLE1 16
#define FLAG_HOLE2 32
#define FLAG_DOUBLE_STEP 64
static struct
{
int max_track;
int flags;
} drive_types[] =
{
{ /*None*/
.max_track = 0,
.flags = 0
},
{ /*5.25" DD*/
.max_track = 41,
.flags = FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0
},
{ /*5.25" HD*/
.max_track = 82,
.flags = FLAG_RPM_360 | FLAG_525 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP
},
{ /*5.25" HD Dual RPM*/
.max_track = 82,
.flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP
},
{ /*3.5" DD*/
.max_track = 82,
.flags = FLAG_RPM_300 | FLAG_HOLE0
},
{ /*3.5" HD*/
.max_track = 82,
.flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1
},
{ /*3.5" HD 3-Mode*/
.max_track = 82,
.flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_HOLE0 | FLAG_HOLE1
},
{ /*3.5" ED*/
.max_track = 82,
.flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2
}
};
int fdd_swap = 0;
void fdd_seek(int drive, int track_diff)
{
int old_track;
drive ^= fdd_swap;
old_track = fdd[drive].track;
fdd[drive].track += track_diff;
if (fdd[drive].track < 0)
fdd[drive].track = 0;
if (fdd[drive].track > drive_types[fdd[drive].type].max_track)
fdd[drive].track = drive_types[fdd[drive].type].max_track;
// pclog("fdd_seek: drive=%i track_diff=%i old_track=%i track=%i\n", drive, track_diff, old_track, fdd[drive].track);
if (fdd[drive].track != old_track)
fdc_discchange_clear(drive);
disc_seek(drive, fdd[drive].track);
disctime = 5000;
}
int fdd_track0(int drive)
{
drive ^= fdd_swap;
/* If drive is disabled, TRK0 never gets set. */
if (!drive_types[fdd[drive].type].max_track) return 0;
return !fdd[drive].track;
}
void fdd_set_densel(int densel)
{
fdd[0].densel = densel;
fdd[1].densel = densel;
}
int fdd_getrpm(int drive)
{
int hole = disc_hole(drive);
drive ^= fdd_swap;
if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) return 300;
if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) return 360;
if (drive_types[fdd[drive].type].flags & FLAG_525)
{
return fdd[drive].densel ? 360 : 300;
}
else
{
/* disc_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */
if (hole == 1)
{
return fdd[drive].densel ? 300 : 360;
}
else
{
return 300;
}
}
switch (fdd[drive].type)
{
case 0:
return 300;
case 1:
return 360;
}
}
void fdd_setswap(int swap)
{
fdd_swap = swap ? 1 : 0;
}
int fdd_can_read_medium(int drive)
{
int hole = disc_hole(drive);
drive ^= fdd_swap;
hole = 1 << (hole + 3);
// pclog("Drive %02X, type %02X, hole flag %02X, flags %02X, result %02X\n", drive, fdd[drive].type, hole, drive_types[fdd[drive].type].flags, drive_types[fdd[drive].type].flags & hole);
return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0;
}
int fdd_doublestep_40(int drive)
{
return drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP;
}
void fdd_set_type(int drive, int type)
{
fdd[drive].type = type;
}
int fdd_get_type(int drive)
{
return fdd[drive].type;
}

12
src/fdd.h Normal file
View file

@ -0,0 +1,12 @@
#define SEEK_RECALIBRATE -999
void fdd_seek(int drive, int track_diff);
int fdd_track0(int drive);
int fdd_getrpm(int drive);
void fdd_set_densel(int densel);
int fdd_can_read_medium(int drive);
int fdd_doublestep_40(int drive);
void fdd_set_type(int drive, int type);
int fdd_get_type(int drive);
extern int fdd_swap;

View file

@ -16,6 +16,7 @@
#include "cpu.h"
#include "dma.h"
#include "fdc.h"
#include "fdd.h"
#include "sound_gus.h"
#include "ide.h"
#include "keyboard.h"
@ -596,8 +597,8 @@ void loadconfig(char *fn)
if (p) strcpy(ide_fn[3], p);
else strcpy(ide_fn[3], "");
drive_type[0] = config_get_int(NULL, "drive_a_type", 0);
drive_type[1] = config_get_int(NULL, "drive_b_type", 0);
fdd_set_type(0, config_get_int(NULL, "drive_a_type", 0));
fdd_set_type(1, config_get_int(NULL, "drive_b_type", 0));
}
void saveconfig()
@ -647,8 +648,8 @@ void saveconfig()
config_set_int(NULL, "hdf_cylinders", hdc[3].tracks);
config_set_string(NULL, "hdf_fn", ide_fn[3]);
config_set_int(NULL, "drive_a_type", drive_type[0]);
config_set_int(NULL, "drive_b_type", drive_type[1]);
config_set_int(NULL, "drive_a_type", fdd_get_type(0));
config_set_int(NULL, "drive_b_type", fdd_get_type(1));
config_save(config_file_default);
}

View file

@ -8,7 +8,7 @@
#include "ibm.h"
#include "cpu.h"
#include "device.h"
#include "disc.h"
#include "fdd.h"
#include "model.h"
#include "resources.h"
#include "sound.h"
@ -30,6 +30,8 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
int temp_GAMEBLASTER, temp_GUS, temp_SSI2001, temp_voodoo, temp_sound_card_current;
int temp_dynarec;
int cpu_flags;
int temp_fda_type, temp_fdb_type;
UDACCEL accel;
// pclog("Dialog msg %i %08X\n",message,message);
switch (message)
@ -190,13 +192,25 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
EnableWindow(h, FALSE);
h = GetDlgItem(hdlg, IDC_COMBODRA);
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k / 3.5\"");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M");
SendMessage(h, CB_SETCURSEL, drive_type[0], 0);
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M");
SendMessage(h, CB_SETCURSEL, fdd_get_type(0), 0);
h = GetDlgItem(hdlg, IDC_COMBODRB);
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k / 3.5\"");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M");
SendMessage(h, CB_SETCURSEL, drive_type[1], 0);
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode");
SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M");
SendMessage(h, CB_SETCURSEL, fdd_get_type(1), 0);
h = GetDlgItem(hdlg, IDC_TEXT_MB);
if (models[model].is_at)
@ -251,10 +265,16 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
h = GetDlgItem(hdlg, IDC_CHECKDYNAREC);
temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0);
h = GetDlgItem(hdlg, IDC_COMBODRA);
temp_fda_type = SendMessage(h, CB_GETCURSEL, 0, 0);
h = GetDlgItem(hdlg, IDC_COMBODRB);
temp_fdb_type = SendMessage(h, CB_GETCURSEL, 0, 0);
if (temp_model != model || gfx != gfxcard || mem != mem_size ||
fpu != hasfpu || temp_GAMEBLASTER != GAMEBLASTER || temp_GUS != GUS ||
temp_SSI2001 != SSI2001 || temp_sound_card_current != sound_card_current ||
temp_voodoo != voodoo_enabled || temp_dynarec != cpu_use_dynarec)
temp_voodoo != voodoo_enabled || temp_dynarec != cpu_use_dynarec ||
temp_fda_type != fdd_get_type(0) || temp_fdb_type != fdd_get_type(1))
{
if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL)==IDOK)
{
@ -271,6 +291,9 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
voodoo_enabled = temp_voodoo;
cpu_use_dynarec = temp_dynarec;
fdd_set_type(0, temp_fda_type);
fdd_set_type(1, temp_fdb_type);
mem_resize();
loadbios();
resetpchard();
@ -297,11 +320,6 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR
cache=SendMessage(h, CB_GETCURSEL, 0, 0);
mem_updatecache();
h = GetDlgItem(hdlg, IDC_COMBODRA);
drive_type[0] = SendMessage(h, CB_GETCURSEL, 0, 0);
h = GetDlgItem(hdlg, IDC_COMBODRB);
drive_type[1] = SendMessage(h, CB_GETCURSEL, 0, 0);
saveconfig();
speedchanged();