The FDC is now a device_t, and the FDC code has been cleaned up;
Merged floppy.c and fdd.c and renamed floppy_*.c (the floppy image format handlers) to fdd_*.c; Reading the AT or PS/2 keyboard controller status no longer clears the transmit timeout bit, fixes error 8601 (mouse error) on the IBM PS/2 Model 80; MMU translate and DMA physical reads and writes now go through _mem_exec instead of directly to ram[], should fix the last remaining problems with remapped mappings; Implemented the Sound gain dialog; Added the resource for the "New floppy image" dialog and the needed functions for the functionality of exporting the currently mounted floppy image as 86F, both of which should be finished in the next commit; Applied the CD-ROM fixes from the PCem commit; Added the "Keep ratio" option for full screen stretch.
This commit is contained in:
415
src/floppy/fdd.c
415
src/floppy/fdd.c
@@ -8,22 +8,107 @@
|
||||
*
|
||||
* Implementation of the floppy drive emulation.
|
||||
*
|
||||
* Version: @(#)fdd.c 1.0.5 2017/11/04
|
||||
* Version: @(#)fdd.c 1.0.6 2018/01/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2008-2017 Sarah Walker.
|
||||
* Copyright 2016,2017 Miran Grca.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "floppy.h"
|
||||
#include "fdc.h"
|
||||
#include "../machine/machine.h"
|
||||
#include "../mem.h"
|
||||
#include "../rom.h"
|
||||
#include "../config.h"
|
||||
#include "../timer.h"
|
||||
#include "../plat.h"
|
||||
#include "../ui.h"
|
||||
#include "fdd.h"
|
||||
#include "fdd_86f.h"
|
||||
#include "fdd_fdi.h"
|
||||
#include "fdd_imd.h"
|
||||
#include "fdd_img.h"
|
||||
#include "fdd_json.h"
|
||||
#include "fdd_td0.h"
|
||||
#include "fdc.h"
|
||||
|
||||
|
||||
extern int driveempty[4];
|
||||
|
||||
wchar_t floppyfns[4][512];
|
||||
|
||||
int64_t fdd_poll_time[FDD_NUM] = { 16LL, 16LL, 16LL, 16LL };
|
||||
|
||||
int fdd_cur_track[FDD_NUM];
|
||||
int writeprot[FDD_NUM], fwriteprot[FDD_NUM];
|
||||
|
||||
DRIVE drives[FDD_NUM];
|
||||
int drive_type[FDD_NUM];
|
||||
|
||||
int curdrive = 0;
|
||||
|
||||
int defaultwriteprot = 0;
|
||||
|
||||
int fdc_ready;
|
||||
|
||||
int drive_empty[FDD_NUM] = {1, 1, 1, 1};
|
||||
int fdd_changed[FDD_NUM];
|
||||
|
||||
int motorspin;
|
||||
int64_t motoron[FDD_NUM];
|
||||
|
||||
int fdc_indexcount = 52;
|
||||
|
||||
fdc_t *fdd_fdc;
|
||||
|
||||
|
||||
static struct
|
||||
{
|
||||
wchar_t *ext;
|
||||
void (*load)(int drive, wchar_t *fn);
|
||||
void (*close)(int drive);
|
||||
int size;
|
||||
} loaders[]=
|
||||
{
|
||||
{L"001", img_load, img_close, -1},
|
||||
{L"002", img_load, img_close, -1},
|
||||
{L"003", img_load, img_close, -1},
|
||||
{L"004", img_load, img_close, -1},
|
||||
{L"005", img_load, img_close, -1},
|
||||
{L"006", img_load, img_close, -1},
|
||||
{L"007", img_load, img_close, -1},
|
||||
{L"008", img_load, img_close, -1},
|
||||
{L"009", img_load, img_close, -1},
|
||||
{L"010", img_load, img_close, -1},
|
||||
{L"12", img_load, img_close, -1},
|
||||
{L"144", img_load, img_close, -1},
|
||||
{L"360", img_load, img_close, -1},
|
||||
{L"720", img_load, img_close, -1},
|
||||
{L"86F", d86f_load, d86f_close, -1},
|
||||
{L"BIN", img_load, img_close, -1},
|
||||
{L"CQ", img_load, img_close, -1},
|
||||
{L"CQM", img_load, img_close, -1},
|
||||
{L"DSK", img_load, img_close, -1},
|
||||
{L"FDI", fdi_load, fdi_close, -1},
|
||||
{L"FDF", img_load, img_close, -1},
|
||||
{L"FLP", img_load, img_close, -1},
|
||||
{L"HDM", img_load, img_close, -1},
|
||||
{L"IMA", img_load, img_close, -1},
|
||||
{L"IMD", imd_load, imd_close, -1},
|
||||
{L"IMG", img_load, img_close, -1},
|
||||
{L"JSON", json_load, json_close, -1},
|
||||
{L"TD0", td0_load, td0_close, -1},
|
||||
{L"VFD", img_load, img_close, -1},
|
||||
{L"XDF", img_load, img_close, -1},
|
||||
{0,0,0}
|
||||
};
|
||||
|
||||
static int driveloaders[4];
|
||||
|
||||
|
||||
typedef struct {
|
||||
@@ -120,8 +205,6 @@ static struct
|
||||
}
|
||||
};
|
||||
|
||||
int fdd_swap = 0;
|
||||
|
||||
char *fdd_getname(int type)
|
||||
{
|
||||
return drive_types[type].name;
|
||||
@@ -146,10 +229,15 @@ int fdd_get_from_internal_name(char *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is needed for the dump as 86F feature. */
|
||||
void fdd_do_seek(int drive, int track)
|
||||
{
|
||||
if (drives[drive].seek)
|
||||
drives[drive].seek(drive, fdd[drive].track);
|
||||
}
|
||||
|
||||
void fdd_forced_seek(int drive, int track_diff)
|
||||
{
|
||||
drive = real_drive(drive);
|
||||
|
||||
fdd[drive].track += track_diff;
|
||||
|
||||
if (fdd[drive].track < 0)
|
||||
@@ -158,19 +246,13 @@ void fdd_forced_seek(int drive, int track_diff)
|
||||
if (fdd[drive].track > drive_types[fdd[drive].type].max_track)
|
||||
fdd[drive].track = drive_types[fdd[drive].type].max_track;
|
||||
|
||||
floppy_seek(drive, fdd[drive].track);
|
||||
floppytime = 5000;
|
||||
fdd_do_seek(drive, fdd[drive].track);
|
||||
}
|
||||
|
||||
void fdd_seek(int drive, int track_diff)
|
||||
{
|
||||
drive = real_drive(drive);
|
||||
|
||||
if (!track_diff)
|
||||
{
|
||||
floppytime = 5000;
|
||||
return;
|
||||
}
|
||||
|
||||
fdd[drive].track += track_diff;
|
||||
|
||||
@@ -180,22 +262,20 @@ void fdd_seek(int drive, int track_diff)
|
||||
if (fdd[drive].track > drive_types[fdd[drive].type].max_track)
|
||||
fdd[drive].track = drive_types[fdd[drive].type].max_track;
|
||||
|
||||
fdc_floppychange_clear(drive);
|
||||
floppy_seek(drive, fdd[drive].track);
|
||||
floppytime = 5000;
|
||||
fdd_changed[drive] = 0;
|
||||
|
||||
fdd_do_seek(drive, fdd[drive].track);
|
||||
}
|
||||
|
||||
int fdd_track0(int drive)
|
||||
{
|
||||
drive = real_drive(drive);
|
||||
|
||||
/* If drive is disabled, TRK0 never gets set. */
|
||||
if (!drive_types[fdd[drive].type].max_track) return 0;
|
||||
|
||||
return !fdd[drive].track;
|
||||
}
|
||||
|
||||
int fdd_track(int drive)
|
||||
int fdd_current_track(int drive)
|
||||
{
|
||||
return fdd[drive].track;
|
||||
}
|
||||
@@ -219,12 +299,10 @@ void fdd_set_densel(int densel)
|
||||
|
||||
int fdd_getrpm(int drive)
|
||||
{
|
||||
int hole = floppy_hole(drive);
|
||||
int hole = fdd_hole(drive);
|
||||
|
||||
int densel = 0;
|
||||
|
||||
drive = real_drive(drive);
|
||||
|
||||
densel = fdd[drive].densel;
|
||||
|
||||
if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL)
|
||||
@@ -241,7 +319,7 @@ int fdd_getrpm(int drive)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* floppy_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */
|
||||
/* fdd_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */
|
||||
if (hole == 1)
|
||||
{
|
||||
return densel ? 300 : 360;
|
||||
@@ -253,16 +331,9 @@ int fdd_getrpm(int drive)
|
||||
}
|
||||
}
|
||||
|
||||
void fdd_setswap(int swap)
|
||||
{
|
||||
fdd_swap = swap ? 1 : 0;
|
||||
}
|
||||
|
||||
int fdd_can_read_medium(int drive)
|
||||
{
|
||||
int hole = floppy_hole(drive);
|
||||
|
||||
drive = real_drive(drive);
|
||||
int hole = fdd_hole(drive);
|
||||
|
||||
hole = 1 << (hole + 3);
|
||||
|
||||
@@ -316,7 +387,6 @@ int fdd_is_double_sided(int drive)
|
||||
|
||||
void fdd_set_head(int drive, int head)
|
||||
{
|
||||
drive = real_drive(drive);
|
||||
fdd[drive].head = head;
|
||||
}
|
||||
|
||||
@@ -357,6 +427,279 @@ int fdd_get_densel(int drive)
|
||||
}
|
||||
}
|
||||
|
||||
void fdd_init()
|
||||
void fdd_load(int drive, wchar_t *fn)
|
||||
{
|
||||
int c = 0, size;
|
||||
wchar_t *p;
|
||||
FILE *f;
|
||||
if (!fn) return;
|
||||
p = plat_get_extension(fn);
|
||||
if (!p) return;
|
||||
f = plat_fopen(fn, L"rb");
|
||||
if (!f) return;
|
||||
fseek(f, -1, SEEK_END);
|
||||
size = ftell(f) + 1;
|
||||
fclose(f);
|
||||
while (loaders[c].ext)
|
||||
{
|
||||
if (!wcscasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1))
|
||||
{
|
||||
driveloaders[drive] = c;
|
||||
memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2);
|
||||
loaders[c].load(drive, floppyfns[drive]);
|
||||
drive_empty[drive] = 0;
|
||||
fdd_forced_seek(drive, 0);
|
||||
fdd_changed[drive] = 1;
|
||||
return;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
pclog("Couldn't load %ls %s\n",fn,p);
|
||||
drive_empty[drive] = 1;
|
||||
fdd_set_head(drive, 0);
|
||||
memset(floppyfns[drive], 0, sizeof(floppyfns[drive]));
|
||||
ui_sb_update_icon_state(drive, 1);
|
||||
}
|
||||
|
||||
void fdd_close(int drive)
|
||||
{
|
||||
if (loaders[driveloaders[drive]].close) loaders[driveloaders[drive]].close(drive);
|
||||
drive_empty[drive] = 1;
|
||||
fdd_set_head(drive, 0);
|
||||
floppyfns[drive][0] = 0;
|
||||
drives[drive].hole = NULL;
|
||||
drives[drive].poll = NULL;
|
||||
drives[drive].seek = NULL;
|
||||
drives[drive].readsector = NULL;
|
||||
drives[drive].writesector = NULL;
|
||||
drives[drive].comparesector = NULL;
|
||||
drives[drive].readaddress = NULL;
|
||||
drives[drive].format = NULL;
|
||||
drives[drive].byteperiod = NULL;
|
||||
drives[drive].stop = NULL;
|
||||
ui_sb_update_icon_state(drive, 1);
|
||||
}
|
||||
|
||||
int fdd_notfound = 0;
|
||||
static int fdd_period = 32;
|
||||
|
||||
int fdd_hole(int drive)
|
||||
{
|
||||
if (drives[drive].hole)
|
||||
{
|
||||
return drives[drive].hole(drive);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
double fdd_byteperiod(int drive)
|
||||
{
|
||||
if (drives[drive].byteperiod)
|
||||
{
|
||||
return drives[drive].byteperiod(drive);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 32.0;
|
||||
}
|
||||
}
|
||||
|
||||
double fdd_real_period(int drive)
|
||||
{
|
||||
double ddbp;
|
||||
double dusec;
|
||||
|
||||
ddbp = fdd_byteperiod(drive);
|
||||
|
||||
dusec = (double) TIMER_USEC;
|
||||
|
||||
/* This is a giant hack but until the timings become even more correct, this is needed to make floppies work right on that BIOS. */
|
||||
if (fdd_get_turbo(drive))
|
||||
{
|
||||
return (32.0 * dusec);
|
||||
}
|
||||
|
||||
if (romset == ROM_MRTHOR)
|
||||
{
|
||||
return (ddbp * dusec) / 4.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (ddbp * dusec);
|
||||
}
|
||||
}
|
||||
|
||||
void fdd_poll(int drive)
|
||||
{
|
||||
if (drive >= FDD_NUM)
|
||||
{
|
||||
fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive);
|
||||
}
|
||||
|
||||
fdd_poll_time[drive] += (int64_t) fdd_real_period(drive);
|
||||
|
||||
if (drives[drive].poll)
|
||||
drives[drive].poll(drive);
|
||||
|
||||
if (fdd_notfound)
|
||||
{
|
||||
fdd_notfound--;
|
||||
if (!fdd_notfound)
|
||||
fdc_noidam(fdd_fdc);
|
||||
}
|
||||
}
|
||||
|
||||
void fdd_poll_0(void *priv)
|
||||
{
|
||||
fdd_poll(0);
|
||||
}
|
||||
|
||||
void fdd_poll_1(void *priv)
|
||||
{
|
||||
fdd_poll(1);
|
||||
}
|
||||
|
||||
void fdd_poll_2(void *priv)
|
||||
{
|
||||
fdd_poll(2);
|
||||
}
|
||||
|
||||
void fdd_poll_3(void *priv)
|
||||
{
|
||||
fdd_poll(3);
|
||||
}
|
||||
|
||||
int fdd_get_bitcell_period(int rate)
|
||||
{
|
||||
int bit_rate = 250;
|
||||
|
||||
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 fdd_set_rate(int drive, int drvden, int rate)
|
||||
{
|
||||
switch (rate)
|
||||
{
|
||||
case 0: /*High density*/
|
||||
fdd_period = 16;
|
||||
break;
|
||||
case 1:
|
||||
switch(drvden)
|
||||
{
|
||||
case 0: /*Double density (360 rpm)*/
|
||||
fdd_period = 26;
|
||||
break;
|
||||
case 1: /*High density (360 rpm)*/
|
||||
fdd_period = 16;
|
||||
break;
|
||||
case 2:
|
||||
fdd_period = 4;
|
||||
break;
|
||||
}
|
||||
case 2: /*Double density*/
|
||||
fdd_period = 32;
|
||||
break;
|
||||
case 3: /*Extended density*/
|
||||
fdd_period = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void fdd_reset()
|
||||
{
|
||||
curdrive = 0;
|
||||
fdd_period = 32;
|
||||
timer_add(fdd_poll_0, &(fdd_poll_time[0]), &(motoron[0]), NULL);
|
||||
timer_add(fdd_poll_1, &(fdd_poll_time[1]), &(motoron[1]), NULL);
|
||||
timer_add(fdd_poll_2, &(fdd_poll_time[2]), &(motoron[2]), NULL);
|
||||
timer_add(fdd_poll_3, &(fdd_poll_time[3]), &(motoron[3]), NULL);
|
||||
}
|
||||
|
||||
int oldtrack[FDD_NUM] = {0, 0, 0, 0};
|
||||
|
||||
void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size)
|
||||
{
|
||||
if (drives[drive].readsector)
|
||||
drives[drive].readsector(drive, sector, track, side, density, sector_size);
|
||||
else
|
||||
fdd_notfound = 1000;
|
||||
}
|
||||
|
||||
void fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size)
|
||||
{
|
||||
if (drives[drive].writesector)
|
||||
drives[drive].writesector(drive, sector, track, side, density, sector_size);
|
||||
else
|
||||
fdd_notfound = 1000;
|
||||
}
|
||||
|
||||
void fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size)
|
||||
{
|
||||
if (drives[drive].comparesector)
|
||||
drives[drive].comparesector(drive, sector, track, side, density, sector_size);
|
||||
else
|
||||
fdd_notfound = 1000;
|
||||
}
|
||||
|
||||
void fdd_readaddress(int drive, int side, int density)
|
||||
{
|
||||
if (drives[drive].readaddress)
|
||||
drives[drive].readaddress(drive, side, density);
|
||||
}
|
||||
|
||||
void fdd_format(int drive, int side, int density, uint8_t fill)
|
||||
{
|
||||
if (drives[drive].format)
|
||||
drives[drive].format(drive, side, density, fill);
|
||||
else
|
||||
fdd_notfound = 1000;
|
||||
}
|
||||
|
||||
void fdd_stop(int drive)
|
||||
{
|
||||
if (drives[drive].stop)
|
||||
drives[drive].stop(drive);
|
||||
}
|
||||
|
||||
void fdd_set_fdc(void *fdc)
|
||||
{
|
||||
fdd_fdc = (fdc_t *) fdc;
|
||||
}
|
||||
|
||||
void fdd_init(void)
|
||||
{
|
||||
drives[0].poll = drives[1].poll = drives[2].poll = drives[3].poll = 0;
|
||||
drives[0].seek = drives[1].seek = drives[2].seek = drives[3].seek = 0;
|
||||
drives[0].readsector = drives[1].readsector = drives[2].readsector = drives[3].readsector = 0;
|
||||
fdd_reset();
|
||||
|
||||
img_init();
|
||||
d86f_init();
|
||||
td0_init();
|
||||
imd_init();
|
||||
|
||||
fdd_load(0, floppyfns[0]);
|
||||
fdd_load(1, floppyfns[1]);
|
||||
fdd_load(2, floppyfns[2]);
|
||||
fdd_load(3, floppyfns[3]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user