From eebdc165b2f83642215c4ff6b3d22166cd2895e1 Mon Sep 17 00:00:00 2001 From: TomW Date: Sat, 12 Dec 2015 16:31:08 +0000 Subject: [PATCH] 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 --- src/Makefile.mingw | 2 +- src/disc.c | 93 ++++++- src/disc.h | 17 +- src/disc_fdi.c | 26 +- src/disc_fdi.h | 7 +- src/disc_img.c | 603 ++++++++++++++++++++++++++------------------- src/disc_img.h | 1 + src/disc_sector.c | 385 +++++++++++++++++++++++++++++ src/disc_sector.h | 11 + src/fdc.c | 457 ++++++++++++++++++++++++++++++---- src/fdc.h | 12 + src/fdc37c665.c | 12 + src/fdd.c | 183 ++++++++++++++ src/fdd.h | 12 + src/pc.c | 9 +- src/win-config.c | 40 ++- 16 files changed, 1530 insertions(+), 340 deletions(-) create mode 100644 src/disc_sector.c create mode 100644 src/disc_sector.h create mode 100644 src/fdd.c create mode 100644 src/fdd.h diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 60cfbf4..e6923b4 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -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 \ diff --git a/src/disc.c b/src/disc.c index 3e36d38..c667a02 100644 --- a/src/disc.c +++ b/src/disc.c @@ -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; +} diff --git a/src/disc.h b/src/disc.h index 190b956..ab6ab72 100644 --- a/src/disc.h +++ b/src/disc.h @@ -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; diff --git a/src/disc_fdi.c b/src/disc_fdi.c index 670e243..c9a0a80 100644 --- a/src/disc_fdi.c +++ b/src/disc_fdi.c @@ -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); diff --git a/src/disc_fdi.h b/src/disc_fdi.h index 9877a5b..b28532d 100644 --- a/src/disc_fdi.h +++ b/src/disc_fdi.h @@ -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(); diff --git a/src/disc_img.c b/src/disc_img.c index e099ea2..d6afe63 100644 --- a/src/disc_img.c +++ b/src/disc_img.c @@ -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,11 +339,98 @@ 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) { @@ -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); - } - } - } -} diff --git a/src/disc_img.h b/src/disc_img.h index 9d694bd..b186950 100644 --- a/src/disc_img.h +++ b/src/disc_img.h @@ -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(); diff --git a/src/disc_sector.c b/src/disc_sector.c new file mode 100644 index 0000000..ac01fab --- /dev/null +++ b/src/disc_sector.c @@ -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; + } +} diff --git a/src/disc_sector.h b/src/disc_sector.h new file mode 100644 index 0000000..053d030 --- /dev/null +++ b/src/disc_sector.h @@ -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); diff --git a/src/fdc.c b/src/fdc.c index 3128865..7ffabbd 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -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]); - - disc_writesector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate); + 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, 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]); - - disc_readsector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate); + 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, 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,13 +1249,37 @@ 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() diff --git a/src/fdc.h b/src/fdc.h index 15d63fa..491c8e7 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -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); diff --git a/src/fdc37c665.c b/src/fdc37c665.c index 216e871..46cf1a2 100644 --- a/src/fdc37c665.c +++ b/src/fdc37c665.c @@ -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; } diff --git a/src/fdd.c b/src/fdd.c new file mode 100644 index 0000000..bd47ec5 --- /dev/null +++ b/src/fdd.c @@ -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; +} diff --git a/src/fdd.h b/src/fdd.h new file mode 100644 index 0000000..ef68df5 --- /dev/null +++ b/src/fdd.h @@ -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; diff --git a/src/pc.c b/src/pc.c index 089c48f..28943b1 100644 --- a/src/pc.c +++ b/src/pc.c @@ -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); } diff --git a/src/win-config.c b/src/win-config.c index bba6bca..bfc6258 100644 --- a/src/win-config.c +++ b/src/win-config.c @@ -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) { @@ -270,6 +290,9 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR sound_card_current = temp_sound_card_current; 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(); @@ -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();