--- uae/src/disk.c 2018/04/24 16:59:57 1.1.1.11 +++ uae/src/disk.c 2018/04/24 17:21:42 1.1.1.21 @@ -16,9 +16,8 @@ #include "sysconfig.h" #include "sysdeps.h" -#include "config.h" #include "options.h" -#include "threaddep/penguin.h" +#include "threaddep/thread.h" #include "memory.h" #include "events.h" #include "custom.h" @@ -32,13 +31,23 @@ #include "osemu.h" #include "execlib.h" #include "savestate.h" +#include "crc32.h" -#define FLOPPY_GAP_LEN 360 +/* support HD floppies */ +#define FLOPPY_DRIVE_HD /* writable track length with normal 2us bitcell/300RPM motor */ -#define FLOPPY_WRITE_LEN 6250 +#define FLOPPY_WRITE_LEN (12650 / 2) +/* This works out to 341 */ +#define FLOPPY_GAP_LEN (FLOPPY_WRITE_LEN - 11 * 544) /* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1830 */ #define NORMAL_FLOPPY_SPEED 1830 +#ifdef FLOPPY_DRIVE_HD +#define DDHDMULT 2 +#else +#define DDHDMULT 1 +#endif + static int floppy_speed = NORMAL_FLOPPY_SPEED; #undef DISK_DEBUG @@ -55,36 +64,46 @@ static int floppy_speed = NORMAL_FLOPPY_ */ static int side, direction, writing; -static uae_u8 selected = 15; +static uae_u8 selected = 15, disabled; -static uae_u8 *writebuffer[544 * 22]; +static uae_u8 writebuffer[544 * 22 * DDHDMULT]; -typedef enum { TRACK_AMIGADOS, TRACK_RAW, TRACK_RAW1 } image_tracktype; +typedef enum { TRACK_AMIGADOS, TRACK_RAW, TRACK_RAW1, TRACK_PCDOS } image_tracktype; typedef struct { - uae_u16 len; uae_u32 offs; - int bitlen; + int bitlen, track; unsigned int sync; image_tracktype type; + uae_u16 len; } trackid; #define MAX_TRACKS 328 -#define DRIVE_ID_NONE 0xFFFFFFFF -#define DRIVE_ID_35DD 0x00000000 +/* We have three kinds of Amiga floppy drives + * - internal A500/A2000 drive: + * ID is always DRIVE_ID_NONE (S.T.A.G expects this) + * - HD drive (A3000/A4000): + * ID is DRIVE_ID_35DD if DD floppy is inserted or drive is empty + * ID is DRIVE_ID_35HD if HD floppy is inserted + * - regular external drive: + * ID is always DRIVE_ID_35DD + */ + +#define DRIVE_ID_NONE 0x00000000 +#define DRIVE_ID_35DD 0xFFFFFFFF #define DRIVE_ID_35HD 0xAAAAAAAA -#define DRIVE_ID_525DD 0x55555555 /* 40 track 5.25 drive , kickstart does not recognize this */ +#define DRIVE_ID_525SD 0x55555555 /* 40 track 5.25 drive , kickstart does not recognize this */ typedef enum { ADF_NORMAL, ADF_EXT1, ADF_EXT2 } drive_filetype; typedef struct { - FILE *diskfile; + drive_type type; + struct zfile *diskfile; drive_filetype filetype; trackid trackdata[MAX_TRACKS]; int buffered_cyl, buffered_side; int cyl; int motoroff; int state; - int disabled; int wrprot; uae_u16 bigmfmbuf[0x8000]; int mfmpos; @@ -92,13 +111,7 @@ typedef struct { int trackspeed; int dmalen; int num_tracks, num_secs; - /* dskchange is set to a small number when a disk is removed. At a step - * impulse, it is reset if there is a new disk in the drive or counted - * down to 1 if the drive contains a disk. DISK_check_change will only - * insert a new disk when dskchange is 1, or if the dskchange_time timer - * expires. The last condition can happen if AmigaOS isn't running and a - * game/demo doesn't use the step motor to check for a new disk. - */ + int hard_num_cyls; int dskchange; int dskchange_time; int dskready; @@ -106,7 +119,9 @@ typedef struct { int steplimit; int ddhd; /* 1=DD 2=HD */ int drive_id_scnt; /* drive id shift counter */ + int idbit; unsigned long drive_id; /* drive id to be reported */ + char newname[256]; /* storage space for new filename during eject delay */ } drive; static drive floppy[4]; @@ -119,37 +134,56 @@ static drive floppy[4]; static int disk_data_used; #ifdef DEBUG_DRIVE_ID -static char *drive_id_name(drive *drv) +static char *drive_id_name (drive *drv) { - switch(drv->drive_id) + switch (drv->drive_id) { case DRIVE_ID_35HD : return "3.5HD"; case DRIVE_ID_525DD: return "5.25DD"; case DRIVE_ID_35DD : return "3.5DD"; } - return "UNKNOWN"; + return "UNKNOWN"; } #endif -/* Simulate exact behaviour of an A3000T 3.5 HD disk drive. +/* Simulate exact behaviour of an A3000T 3.5 HD disk drive. * The drive reports to be a 3.5 DD drive whenever there is no * disk or a 3.5 DD disk is inserted. Only 3.5 HD drive id is reported * when a real 3.5 HD disk is inserted. -Adil */ -static void drive_settype_id(drive *drv) +static void drive_settype_id (drive *drv) { - if (!drv->diskfile || drv->num_secs == 11) { - /* Double density */ + int t = drv->type; + + switch (t) + { + case DRV_35_HD: +#ifdef FLOPPY_DRIVE_HD + if (!drv->diskfile || drv->ddhd <= 1) + drv->drive_id = DRIVE_ID_35DD; + else + drv->drive_id = DRIVE_ID_35HD; +#else drv->drive_id = DRIVE_ID_35DD; - drv->ddhd = 1; - } else { - /* High density */ - drv->drive_id = DRIVE_ID_35HD; - drv->ddhd = 2; +#endif + break; + case DRV_35_DD_ESCOM: + case DRV_35_DD: + default: + drv->drive_id = DRIVE_ID_35DD; + break; + case DRV_525_SD: + drv->drive_id = DRIVE_ID_525SD; + break; + case DRV_NONE: + drv->drive_id = DRIVE_ID_NONE; + break; } - drv->drive_id_scnt = 0; #ifdef DEBUG_DRIVE_ID - write_log("drive_settype_id: DF%d: set to %s\n",drv-floppy, drive_id_name(drv)); + write_log ("drive_settype_id: DF%d: set to %s\n", drv-floppy, drive_id_name (drv)); +#endif +#ifdef DEBUG_DRIVE_ID + write_log ("drive_settype_id: DF%d: set to %s\n", drv-floppy, drive_id_name (drv)); #endif } @@ -174,11 +208,20 @@ static void update_drive_gui (int num) gui_led (num + 1, gui_data.drive_motor[num]); } -static void drive_fill_bigbuf (drive * drv); +static void drive_fill_bigbuf (drive *drv); -FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot) +static void drive_image_free (drive *drv) { - FILE *f = zfile_open (fname, "r+b"); + drv->filetype = -1; + if (!drv->diskfile) + return; + zfile_fclose (drv->diskfile); + drv->diskfile = 0; +} + +struct zfile *DISK_validate_filename (const char *fname, int leave_open, int *wrprot) +{ + struct zfile *f = zfile_open (fname, "r+b"); if (f) { if (wrprot) *wrprot = 0; @@ -188,19 +231,62 @@ FILE *DISK_validate_filename (const char f = zfile_open (fname, "rb"); } if (!leave_open) - zfile_close (f); + zfile_fclose (f); return f; } -static int drive_insert (drive * drv, int dnum, const char *fname) +static void track_reset (drive *drv) +{ + drv->tracklen = FLOPPY_WRITE_LEN * 2 * 8; + drv->trackspeed = floppy_speed; + drv->buffered_side = -1; + memset (drv->bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN * 2 * drv->ddhd); +} + +static int read_header_ext2 (struct zfile *diskfile, trackid *trackdata, int *num_tracks, int *ddhd) +{ + uae_u8 buffer[2 + 2 + 4 + 4]; + int offs; + int i; + + zfile_fseek (diskfile, 0, SEEK_SET); + zfile_fread (buffer, 1, 8, diskfile); + if (strncmp ((char *)buffer, "UAE-1ADF", 8)) + return 0; + + zfile_fread (buffer, 1, 4, diskfile); + *num_tracks = buffer[2] * 256 + buffer[3]; + offs = 8 + 2 + 2 + *num_tracks * (2 + 2 + 4 + 4); + + for (i = 0; i < *num_tracks; i++) { + trackid *tid = trackdata + i; + zfile_fread (buffer, 2 + 2 + 4 + 4, 1, diskfile); + tid->type = buffer[2] * 256 + buffer[3]; + tid->len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7]; + tid->bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11]; + tid->offs = offs; + if (tid->len > 20000 && ddhd) + *ddhd = 2; + tid->track = i; + offs += tid->len; + } + return 1; +} + +static int drive_insert (drive *drv, int dnum, const char *fname) { unsigned char buffer[2 + 2 + 4 + 4]; trackid *tid; + int size; + drive_image_free (drv); drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot); + drv->ddhd = 1; + drv->num_secs = 0; + drv->hard_num_cyls = drv->type == DRV_525_SD ? 40 : 80; + if (drv->diskfile == 0) { - drv->tracklen = FLOPPY_WRITE_LEN * 2 * 8; - drv->trackspeed = floppy_speed; + track_reset (drv); return 0; } strncpy (currprefs.df[dnum], fname, 255); @@ -209,30 +295,22 @@ static int drive_insert (drive * drv, in changed_prefs.df[dnum][255] = 0; gui_filename (dnum, fname); - fread (buffer, sizeof (char), 8, drv->diskfile); + memset (buffer, 0, sizeof (buffer)); + size = 0; + if (drv->diskfile) { + zfile_fread (buffer, sizeof (char), 8, drv->diskfile); + zfile_fseek (drv->diskfile, 0, SEEK_END); + size = zfile_ftell (drv->diskfile); + zfile_fseek (drv->diskfile, 0, SEEK_SET); + } + if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) { - int offs; - int i; + read_header_ext2 (drv->diskfile, drv->trackdata, &drv->num_tracks, &drv->ddhd); - fread (buffer, 1, 4, drv->diskfile); - drv->num_tracks = buffer[2] * 256 + buffer[3]; drv->filetype = ADF_EXT2; drv->num_secs = 11; - offs = 8 + 2 + 2 + drv->num_tracks * (2 + 2 + 4 + 4); - - for (i = 0; i < drv->num_tracks; i++) { - tid = &drv->trackdata[i]; - fread (buffer, 2 + 2 + 4 + 4, 1, drv->diskfile); - tid->type = buffer[2] * 256 + buffer[3]; - tid->len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7]; - tid->bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11]; - tid->offs = offs; - if (tid->type == TRACK_AMIGADOS) { - if (tid->len > 20000) - drv->num_secs = 22; - } - offs += tid->len; - } + if (drv->ddhd > 1) + drv->num_secs = 22; } else if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) { int offs = 160 * 4 + 8; int i; @@ -241,10 +319,12 @@ static int drive_insert (drive * drv, in drv->num_tracks = 160; drv->num_secs = 11; + zfile_fseek (drv->diskfile, 8, SEEK_SET); + drv->wrprot = 1; /* write to adf_ext1 not implemented */ for (i = 0; i < 160; i++) { tid = &drv->trackdata[i]; - fread (buffer, 4, 1, drv->diskfile); + zfile_fread (buffer, 4, 1, drv->diskfile); tid->sync = buffer[0] * 256 + buffer[1]; tid->len = buffer[2] * 256 + buffer[3]; tid->offs = offs; @@ -259,18 +339,14 @@ static int drive_insert (drive * drv, in } } else { int i; - drv->filetype = ADF_NORMAL; - fseek (drv->diskfile, 0, SEEK_END); - i = ftell (drv->diskfile); - fseek (drv->diskfile, 0, SEEK_SET); - /* High-density disk? */ - if (i >= 160 * 22 * 512) - drv->num_tracks = i / (512 * (drv->num_secs = 22)); - else - drv->num_tracks = i / (512 * (drv->num_secs = 11)); + if (size >= 160 * 22 * 512) { + drv->num_tracks = size / (512 * (drv->num_secs = 22)); + drv->ddhd = 2; + } else + drv->num_tracks = size / (512 * (drv->num_secs = 11)); if (drv->num_tracks > MAX_TRACKS) write_log ("Your diskfile is too big!\n"); @@ -282,7 +358,7 @@ static int drive_insert (drive * drv, in tid->offs = i * 512 * drv->num_secs; } } - drive_settype_id(drv); /* Set DD or HD drive */ + drive_settype_id (drv); /* Set DD or HD drive */ drv->buffered_side = 2; /* will force read */ drive_fill_bigbuf (drv); return 1; @@ -295,12 +371,6 @@ static int drive_empty (drive * drv) static void drive_step (drive * drv) { - if (!drive_empty (drv)) - drv->dskchange = 0; - else if (drv->dskchange > 1) { -/* printf("Stepping...\n"); - drv->dskchange--;*/ - } if (drv->steplimit) return; /* A1200's floppy drive needs at least 30 raster lines between steps @@ -308,18 +378,20 @@ static void drive_step (drive * drv) * (stupid trackloaders with CPU delay loops) */ drv->steplimit = 2; + if (!drive_empty (drv)) + drv->dskchange = 0; if (direction) { if (drv->cyl) drv->cyl--; /* else - write_log("program tried to step beyond track zero\n"); + write_log ("program tried to step beyond track zero\n"); "no-click" programs does that */ } else { if (drv->cyl < 83) drv->cyl++; else - write_log("program tried to step over track 83\n"); + write_log ("program tried to step over track 83\n"); } #if 0 && defined DISK_DEBUG @@ -344,20 +416,19 @@ static int drive_running (drive * drv) static void drive_motor (drive * drv, int off) { - if (drv->disabled) - off = 1; - /* A value of 2 works out to a guaranteed delay of 1/10 of a second - (which is the frequency with which DISK_check_change is called). + /* A value of 5 works out to a guaranteed delay of 1/2 of a second Higher values are dangerous, e.g. a value of 8 breaks the RSI demo. */ if (drv->motoroff && !off) { - drv->dskready_time = 2; + drv->dskready_time = 5; disk_data_used = 0; - drv->drive_id_scnt = 0; /* Reset id shift reg counter */ #ifdef DEBUG_DRIVE_ID - write_log("drive_motor: Selected DF%d: reset id shift reg.\n",drv-floppy); + write_log ("drive_motor: Selected DF%d: reset id shift reg.\n", drv-floppy); #endif } + if (!drv->motoroff && off) { + drv->drive_id_scnt = 0; /* Reset id shift reg counter */ + } drv->motoroff = off; if (drv->motoroff) { drv->dskready = 0; @@ -365,13 +436,120 @@ static void drive_motor (drive * drv, in } } -static void read_floppy_data (drive * drv, int track, int offset, unsigned char *dst, int len) +static void read_floppy_data (struct zfile *diskfile, trackid *ti, int offset, unsigned char *dst, int len) { - trackid *ti; + zfile_fseek (diskfile, ti->offs + offset, SEEK_SET); + zfile_fread (dst, 1, len, diskfile); +} - ti = &drv->trackdata[track]; - fseek (drv->diskfile, ti->offs + offset, SEEK_SET); - fread (dst, 1, len, drv->diskfile); +static void reset_drive (int i) +{ + drive *drv = &floppy[i]; + drive_image_free (drv); + drv->motoroff = 1; + disabled &= ~(1 << i); + if (currprefs.dfxtype[i] < 0) + disabled |= 1 << i; + + drv->dskchange_time = 0; + drv->buffered_cyl = -1; + drv->buffered_side = -1; + gui_led (i + 1, 0); + drive_settype_id (drv); + strcpy (currprefs.df[i], changed_prefs.df[i]); + drv->newname[0] = 0; + if (!drive_insert (drv, i, currprefs.df[i])) + disk_eject (i); +} + +static uae_u8 mfmencodetable[16] = { + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 +}; + + +static uae_u16 dos_encode_byte (uae_u8 byte) +{ + uae_u8 b2, b1; + uae_u16 word; + + b1 = byte; + b2 = b1 >> 4; + b1 &= 15; + word = mfmencodetable[b2] <<8 | mfmencodetable[b1]; + return (word | ((word & (256 | 64)) ? 0 : 128)); +} + +static uae_u16 *mfmcoder (uae_u8 *src, uae_u16 *dest, int len) +{ + int i; + + for (i = 0; i < len; i++) { + *dest = dos_encode_byte (*src++); + *dest |= ((dest[-1] & 1)|| (*dest & 0x4000)) ? 0: 0x8000; + dest++; + } + return dest; +} + +static void decode_pcdos (drive *drv) +{ + int i; + int tr = drv->cyl * 2 + side; + uae_u16 *dstmfmbuf, *mfm2; + uae_u8 secbuf[700]; + uae_u16 crc16; + trackid *ti = drv->trackdata + tr; + + mfm2 = drv->bigmfmbuf; + *mfm2++ = 0x9254; + memset (secbuf, 0x4e, 80); // 94 + memset (secbuf + 80, 0x00, 12); // 12 + secbuf[92] = 0xc2; + secbuf[93] = 0xc2; + secbuf[94] = 0xc2; + secbuf[95] = 0xfc; + memset (secbuf + 96, 0x4e, 50); // 50 + dstmfmbuf = mfmcoder (secbuf, mfm2, 146); + mfm2[92] = 0x5224; + mfm2[93] = 0x5224; + mfm2[94] = 0x5224; + for (i = 0; i < drv->num_secs; i++) { + mfm2 = dstmfmbuf; + memset (secbuf, 0x00, 12); + secbuf[12] = 0xa1; + secbuf[13] = 0xa1; + secbuf[14] = 0xa1; + secbuf[15] = 0xfe; + secbuf[16] = drv->cyl; + secbuf[17] = side; + secbuf[18] = 1 + i; + secbuf[19] = 2; // 128 << 2 = 512 + crc16 = get_crc16 (secbuf + 12, 3 + 1 + 4); + secbuf[20] = crc16 >> 8; + secbuf[21] = crc16 & 0xff; + memset (secbuf + 22, 0x4e, 22); + memset (secbuf + 44, 0x00, 12); + secbuf[56] = 0xa1; + secbuf[57] = 0xa1; + secbuf[58] = 0xa1; + secbuf[59] = 0xfb; + read_floppy_data (drv->diskfile, ti, i * 512, &secbuf[60], 512); + crc16 = get_crc16 (secbuf + 56, 3 + 1 + 512); + secbuf[60 + 512] = crc16 >> 8; + secbuf[61 + 512] = crc16 & 0xff; + memset (secbuf + 512 + 62, 0x4e, 76 / drv->ddhd); + dstmfmbuf = mfmcoder (secbuf, mfm2, 60 + 512 + 2 + 76 / drv->ddhd); + mfm2[12] = 0x4489; + mfm2[13] = 0x4489; + mfm2[14] = 0x4489; + mfm2[56] = 0x4489; + mfm2[57] = 0x4489; + mfm2[58] = 0x4489; + } + for (i = 0; i < 200; i++) + *dstmfmbuf++ = 0x9254; + drv->tracklen = (dstmfmbuf - drv->bigmfmbuf) * 16; } /* Megalomania does not like zero MFM words... */ @@ -390,6 +568,98 @@ static void mfmcode (uae_u16 * mfm, int } } +static void decode_amigados (drive *drv) +{ + /* Normal AmigaDOS format track */ + int tr = drv->cyl * 2 + side; + int sec; + int dstmfmoffset = 0; + uae_u16 *dstmfmbuf = drv->bigmfmbuf; + int len = drv->num_secs * 544 + FLOPPY_GAP_LEN; + trackid *ti = drv->trackdata + tr; + + memset (dstmfmbuf, 0xaa, len * 2); + dstmfmoffset += FLOPPY_GAP_LEN; + drv->tracklen = len * 2 * 8; + + for (sec = 0; sec < drv->num_secs; sec++) { + uae_u8 secbuf[544]; + uae_u16 mfmbuf[544]; + int i; + uae_u32 deven, dodd; + uae_u32 hck = 0, dck = 0; + + secbuf[0] = secbuf[1] = 0x00; + secbuf[2] = secbuf[3] = 0xa1; + secbuf[4] = 0xff; + secbuf[5] = tr; + secbuf[6] = sec; + secbuf[7] = drv->num_secs - sec; + + for (i = 8; i < 24; i++) + secbuf[i] = 0; + + read_floppy_data (drv->diskfile, ti, sec * 512, &secbuf[32], 512); + + mfmbuf[0] = mfmbuf[1] = 0xaaaa; + mfmbuf[2] = mfmbuf[3] = 0x4489; + + deven = ((secbuf[4] << 24) | (secbuf[5] << 16) + | (secbuf[6] << 8) | (secbuf[7])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + + mfmbuf[4] = dodd >> 16; + mfmbuf[5] = dodd; + mfmbuf[6] = deven >> 16; + mfmbuf[7] = deven; + + for (i = 8; i < 48; i++) + mfmbuf[i] = 0xaaaa; + for (i = 0; i < 512; i += 4) { + deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16) + | (secbuf[i + 34] << 8) | (secbuf[i + 35])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 32] = dodd >> 16; + mfmbuf[(i >> 1) + 33] = dodd; + mfmbuf[(i >> 1) + 256 + 32] = deven >> 16; + mfmbuf[(i >> 1) + 256 + 33] = deven; + } + + for (i = 4; i < 24; i += 2) + hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + + deven = dodd = hck; + dodd >>= 1; + mfmbuf[24] = dodd >> 16; + mfmbuf[25] = dodd; + mfmbuf[26] = deven >> 16; + mfmbuf[27] = deven; + + for (i = 32; i < 544; i += 2) + dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + + deven = dodd = dck; + dodd >>= 1; + mfmbuf[28] = dodd >> 16; + mfmbuf[29] = dodd; + mfmbuf[30] = deven >> 16; + mfmbuf[31] = deven; + mfmcode (mfmbuf + 4, 544 - 4); + + for (i = 0; i < 544; i++) { + dstmfmbuf[dstmfmoffset % len] = mfmbuf[i]; + dstmfmoffset++; + } + } +#ifdef DISK_DEBUG + write_log ("amigados read track %d\n", tr); +#endif +} + static void drive_fill_bigbuf (drive * drv) { int tr = drv->cyl * 2 + side; @@ -404,89 +674,17 @@ static void drive_fill_bigbuf (drive * d if (drv->buffered_cyl == drv->cyl && drv->buffered_side == side) return; - if (ti->type == TRACK_AMIGADOS) { - /* Normal AmigaDOS format track */ - int sec; - drv->tracklen = (drv->num_secs * 544 + FLOPPY_GAP_LEN) * 2 * 8; - memset (drv->bigmfmbuf, 0xaa, FLOPPY_GAP_LEN * 2); - - for (sec = 0; sec < drv->num_secs; sec++) { - uae_u8 secbuf[544]; - int i; - uae_u16 *mfmbuf = drv->bigmfmbuf + 544 * sec + FLOPPY_GAP_LEN; - uae_u32 deven, dodd; - uae_u32 hck = 0, dck = 0; - - secbuf[0] = secbuf[1] = 0x00; - secbuf[2] = secbuf[3] = 0xa1; - secbuf[4] = 0xff; - secbuf[5] = tr; - secbuf[6] = sec; - secbuf[7] = drv->num_secs - sec; - - for (i = 8; i < 24; i++) - secbuf[i] = 0; - - read_floppy_data (drv, tr, sec * 512, &secbuf[32], 512); - - mfmbuf[0] = mfmbuf[1] = 0xaaaa; - mfmbuf[2] = mfmbuf[3] = 0x4489; - - deven = ((secbuf[4] << 24) | (secbuf[5] << 16) - | (secbuf[6] << 8) | (secbuf[7])); - dodd = deven >> 1; - deven &= 0x55555555; - dodd &= 0x55555555; - - mfmbuf[4] = dodd >> 16; - mfmbuf[5] = dodd; - mfmbuf[6] = deven >> 16; - mfmbuf[7] = deven; - - for (i = 8; i < 48; i++) - mfmbuf[i] = 0xaaaa; - for (i = 0; i < 512; i += 4) { - deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16) - | (secbuf[i + 34] << 8) | (secbuf[i + 35])); - dodd = deven >> 1; - deven &= 0x55555555; - dodd &= 0x55555555; - mfmbuf[(i >> 1) + 32] = dodd >> 16; - mfmbuf[(i >> 1) + 33] = dodd; - mfmbuf[(i >> 1) + 256 + 32] = deven >> 16; - mfmbuf[(i >> 1) + 256 + 33] = deven; - } - - for (i = 4; i < 24; i += 2) - hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + if (ti->type == TRACK_PCDOS) { + decode_pcdos (drv); - deven = dodd = hck; - dodd >>= 1; - mfmbuf[24] = dodd >> 16; - mfmbuf[25] = dodd; - mfmbuf[26] = deven >> 16; - mfmbuf[27] = deven; - - for (i = 32; i < 544; i += 2) - dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; - - deven = dodd = dck; - dodd >>= 1; - mfmbuf[28] = dodd >> 16; - mfmbuf[29] = dodd; - mfmbuf[30] = deven >> 16; - mfmbuf[31] = deven; - mfmcode (mfmbuf + 4, 544 - 4); - } -#ifdef DISK_DEBUG - write_log ("amigados read track %d\n", tr); -#endif + } else if (ti->type == TRACK_AMIGADOS) { + decode_amigados (drv); } else { int i; int base_offset = ti->type == TRACK_RAW ? 0 : 1; drv->tracklen = ti->bitlen + 16 * base_offset; drv->bigmfmbuf[0] = ti->sync; - read_floppy_data (drv, tr, 0, (char *) (drv->bigmfmbuf + base_offset), (ti->bitlen + 7) / 8); + read_floppy_data (drv->diskfile, ti, 0, (unsigned char *) (drv->bigmfmbuf + base_offset), (ti->bitlen + 7) / 8); for (i = base_offset; i < (drv->tracklen + 15) / 16; i++) { uae_u16 *mfm = drv->bigmfmbuf + i; uae_u8 *data = (uae_u8 *) mfm; @@ -514,18 +712,18 @@ static void diskfile_update (drive * drv track = drv->cyl * 2 + side; ti = &drv->trackdata[track]; ti->bitlen = len; - fseek (drv->diskfile, 8 + 4 + (2 + 2 + 4 + 4) * track, SEEK_SET); + zfile_fseek (drv->diskfile, 8 + 4 + (2 + 2 + 4 + 4) * track, SEEK_SET); memset (buf, 0, sizeof buf); ti->type = type; buf[3] = ti->type; do_put_mem_long ((uae_u32 *) (buf + 4), ti->len); do_put_mem_long ((uae_u32 *) (buf + 8), ti->bitlen); - fwrite (buf, sizeof (buf), 1, drv->diskfile); + zfile_fwrite (buf, sizeof (buf), 1, drv->diskfile); if (ti->len > (len + 7) / 8) { zerobuf = malloc (ti->len); memset (zerobuf, 0, ti->len); - fseek (drv->diskfile, ti->offs, SEEK_SET); - fwrite (zerobuf, 1, ti->len, drv->diskfile); + zfile_fseek (drv->diskfile, ti->offs, SEEK_SET); + zfile_fwrite (zerobuf, 1, ti->len, drv->diskfile); free (zerobuf); } #ifdef DISK_DEBUG @@ -636,8 +834,8 @@ static int drive_write_adf_amigados (dri diskfile_update (drv, drvsec * 512 * 8, TRACK_AMIGADOS); for (i = 0; i < drvsec; i++) { - fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + side].offs + i * 512, SEEK_SET); - fwrite (writebuffer + i * 512, sizeof (uae_u8), 512, drv->diskfile); + zfile_fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + side].offs + i * 512, SEEK_SET); + zfile_fwrite (writebuffer + i * 512, sizeof (uae_u8), 512, drv->diskfile); } return 0; @@ -662,8 +860,8 @@ static int drive_write_ext2 (drive * drv uae_u8 *data = (uae_u8 *) mfm; *mfm = 256 * *data + *(data + 1); } - fseek (drv->diskfile, ti->offs, SEEK_SET); - fwrite (drv->bigmfmbuf, 1, len, drv->diskfile); + zfile_fseek (drv->diskfile, ti->offs, SEEK_SET); + zfile_fwrite (drv->bigmfmbuf, 1, len, drv->diskfile); return 1; } @@ -682,7 +880,7 @@ static void drive_write_data (drive * dr case ADF_EXT2: ret = drive_write_adf_amigados (drv); if (ret) { - /*write_log("not an amigados track (error %d), writing as raw track\n",ret); */ + /*write_log ("not an amigados track (error %d), writing as raw track\n", ret); */ drive_write_ext2 (drv); } break; @@ -692,14 +890,16 @@ static void drive_write_data (drive * dr static void drive_eject (drive * drv) { - if (!drive_empty (drv)) - zfile_close (drv->diskfile); - - drv->dskchange = 4; - drv->dskchange_time = 20; -/* printf("setting changed bit %d\n", drv-floppy);*/ - drv->diskfile = 0; - drive_settype_id(drv); /* Back to 35 DD */ + drive_image_free (drv); + drv->dskchange = 1; + drv->ddhd = 1; + drv->dskchange_time = 0; + drv->dskready = 0; + drv->dskready_time = 0; + drive_settype_id (drv); /* Back to 35 DD */ +#ifdef DISK_DEBUG + write_log ("eject drive %d\n", drv - &floppy[0]); +#endif } /* We use this function if we have no Kickstart ROM. @@ -707,8 +907,8 @@ static void drive_eject (drive * drv) void DISK_ersatz_read (int tr, int sec, uaecptr dest) { uae_u8 *dptr = get_real_address (dest); - fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec * 512, SEEK_SET); - fread (dptr, 1, 512, floppy[0].diskfile); + zfile_fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec * 512, SEEK_SET); + zfile_fread (dptr, 1, 512, floppy[0].diskfile); } void disk_eject (int num) @@ -716,43 +916,61 @@ void disk_eject (int num) gui_filename (num, ""); drive_eject (floppy + num); *currprefs.df[num] = *changed_prefs.df[num] = 0; + floppy[num].newname[0] = 0; } void disk_insert (int num, const char *name) { - /* just to be sure */ - drive_eject (floppy + num); - drive_insert (floppy + num, num, name); + drive *drv = floppy + num; + + if (!strcmp (currprefs.df[num], name)) + return; + strcpy (drv->newname, name); + strcpy (currprefs.df[num], name); + + if (name[0] == 0) { + disk_eject (num); + } else if (!drive_empty (drv) || drv->dskchange_time > 0) { + drive_eject (drv); + /* set dskchange_time, disk_insert () will be + * called from DISK_check_change () after 1 second delay + * this makes sure that all programs detect disk change correctly + */ + drv->dskchange_time = 10; /* 1 second disk change delay */ + } else { + drv->dskchange_time = 1; + } } void DISK_check_change (void) { int i; - static int count = 0; - count++; for (i = 0; i < 4; i++) { - /* emulate drive motor turn on time */ - if (floppy[i].dskready_time) { - floppy[i].dskready_time--; - if (floppy[i].dskready_time == 0) { - floppy[i].dskready = 1; - } - } - if (strcmp (currprefs.df[i], changed_prefs.df[i]) != 0) { - if (currprefs.df[i][0] != '\0') { - drive_eject (floppy + i); - currprefs.df[i][0] = '\0'; - gui_filename (i, ""); - } else if (floppy[i].dskchange == 1) { - /* In theory, it should work without the dskchange test. - * In practice, it doesn't. */ - drive_insert (floppy + i, i, changed_prefs.df[i]); - } else if (floppy[i].dskchange > 1 && floppy[i].dskchange_time > 0) { - /* Force the dskchange bit to go to 1 after a given timeout */ - if (--floppy[i].dskchange_time == 0) { - floppy[i].dskchange = 1; - } + drive *drv = floppy + i; + gui_lock (); + if (currprefs.dfxtype[i] != changed_prefs.dfxtype[i]) { + drv->type = currprefs.dfxtype[i] = changed_prefs.dfxtype[i]; + reset_drive (i); + } + if (drv->dskchange_time == 0 && strcmp (currprefs.df[i], changed_prefs.df[i])) + disk_insert (i, changed_prefs.df[i]); + gui_unlock (); + /* emulate drive motor turn on time */ + if (drv->dskready_time && !drive_empty (drv)) { + drv->dskready_time--; + if (drv->dskready_time == 0) + drv->dskready = 1; + } + /* delay until new disk image is inserted */ + if (drv->dskchange_time) { + drv->dskchange_time--; + if (drv->dskchange_time == 0) { + drive_insert (drv, i, drv->newname); +#ifdef DISK_DEBUG + write_log ("delayed insert, drive %d, image '%s'\n", i, drv->newname); +#endif + drv->newname[0] = 0; } } } @@ -771,10 +989,11 @@ void DISK_select (uae_u8 data) int dr; static uae_u8 prevdata; - if (selected != lastselected) - disk_data_used = 1; lastselected = selected; selected = (data >> 3) & 15; + selected |= disabled; + if (selected != lastselected) + disk_data_used = 1; side = 1 - ((data >> 2) & 1); direction = (data >> 1) & 1; @@ -783,25 +1002,31 @@ void DISK_select (uae_u8 data) step = step_pulse; if (step) { for (dr = 0; dr < 4; dr++) { - if (!(selected & (1 << dr))) { + if (!((selected | disabled) & (1 << dr))) { drive_step (floppy + dr); } } } } - for (dr = 0; dr < 4; dr++) { - /* motor on/off workings tested with small assembler code on real Amiga 1200. */ - /* motor flipflop is set only when drive select goes from high to low */ - if (!(selected & (1 << dr)) && (lastselected & (1 << dr)) ) { - if (floppy[dr].motoroff) { - /* motor off: if motor bit = 0 in prevdata or data -> turn motor on */ - if ((prevdata & 0x80) == 0 || (data & 0x80) == 0) - drive_motor (floppy + dr, 0); - } else { - /* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect) - -> turn motor off */ - if (prevdata & 0x80) - drive_motor (floppy + dr, 1); + if (!savestate_state) { + for (dr = 0; dr < 4; dr++) { + drive *drv = floppy + dr; + /* motor on/off workings tested with small assembler code on real Amiga 1200. */ + /* motor/id flipflop is set only when drive select goes from high to low */ + if (!(selected & (1 << dr)) && (lastselected & (1 << dr)) ) { + drv->drive_id_scnt++; + drv->drive_id_scnt &= 31; + drv->idbit = (drv->drive_id & (1L << (31 - drv->drive_id_scnt))) ? 1 : 0; + if (!(disabled & (1 << dr))) { + if ((prevdata & 0x80) == 0 || (data & 0x80) == 0) { + /* motor off: if motor bit = 0 in prevdata or data -> turn motor on */ + drive_motor (drv, 0); + } else if (prevdata & 0x80) { + /* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect) + -> turn motor off */ + drive_motor (drv, 1); + } + } } } } @@ -819,36 +1044,28 @@ uae_u8 DISK_status (void) for (dr = 0; dr < 4; dr++) { drive *drv = floppy + dr; - if (!(selected & (1 << dr))) { + if (!((selected | disabled) & (1 << dr))) { if (drive_running (drv)) { if (drv->dskready) st &= ~0x20; - } else if (!drv->disabled) { + } else { /* report drive ID */ - if (drv->drive_id & (1L << (31 - drv->drive_id_scnt))) - st |= 0x20; - else + if (drv->idbit && currprefs.dfxtype[dr] != DRV_35_DD_ESCOM) st &= ~0x20; -#ifdef DEBUG_DRIVE_ID - write_log("DISK_status: sel %d id %s [0x%08lx, bit #%02d: %d]\n", - dr,drive_id_name(drv), drv->drive_id << drv->drive_id_scnt, 31 - drv->drive_id_scnt, st & 0x20 ? 1:0); -#endif - /* Left shift id reg bit should be done with each LH transition of drv_sel */ - drv->drive_id_scnt++; - drv->drive_id_scnt &= 31; +#ifdef DEBUG_DRIVE_ID + write_log ("DISK_status: sel %d id %s [0x%08lx, bit #%02d: %d]\n", + dr, drive_id_name (drv), drv->drive_id << drv->drive_id_scnt, 31 - drv->drive_id_scnt, st & 0x20 ? 1:0); +#endif } - if (drive_track0 (drv)) { + if (drive_track0 (drv)) st &= ~0x10; - } - if (drive_writeprotected (drv)) { + if (drive_writeprotected (drv)) st &= ~8; - } - if (drv->dskchange) { - /*printf("changed bit set: %d\n",dr); */ - st &= ~0x4; - if (drv->dskchange > 1) - drv->dskchange--; - } + if (drv->dskchange) + st &= ~4; + } else if (!(selected & (1 << dr))) { + if (drv->idbit) + st &= ~0x20; } } return st; @@ -872,11 +1089,11 @@ static uae_u32 dskpt; static void disk_dmafinished (void) { INTREQ (0x8002); - dskdmaen = 0; + dskdmaen = 0; /* ??? */ #ifdef DISK_DEBUG - write_log("disk dma finished\n"); + write_log ("disk dma finished %08.8X\n", dskpt); #endif -} +} static void disk_events (int last) { @@ -892,8 +1109,6 @@ static void disk_events (int last) } } -extern void cia_diskindex (void); - void DISK_handler (void) { eventtab[ev_disk].active = 0; @@ -905,7 +1120,8 @@ void DISK_handler (void) disk_events (disk_sync_cycle); } -static int syncfound, dmaon, word, bitoffset; +static int dma_enable, bitoffset; +static uae_u32 word; /* Always carried through to the next line. */ static int disk_hpos; @@ -940,7 +1156,7 @@ static void disk_doupdate_write (drive * } /* get one bit from MFM bit stream */ -static uae_u16 getonebit (uae_u16 * mfmbuf, int mfmpos, uae_u16 word) +static uae_u32 getonebit (uae_u16 * mfmbuf, int mfmpos, uae_u32 word) { uae_u16 *buf; @@ -956,8 +1172,9 @@ static uae_u16 getonebit (uae_u16 * mfmb static void disk_doupdate_read (drive * drv) { int hpos = disk_hpos; - int is_sync = 0, dmaon; + int is_sync = 0; int j = 0, k = 1, l = 0; + uae_u16 synccheck; static int dskbytr_last = 0, wordsync_last = -1; dskbytr_tab[0] = dskbytr_tab[dskbytr_last]; @@ -973,39 +1190,37 @@ static void disk_doupdate_read (drive * word <<= 1; drv->mfmpos++; drv->mfmpos %= drv->tracklen; - if (!drv->mfmpos) { + if (!drv->mfmpos) { disk_sync[hpos >> 8] |= DISK_INDEXSYNC; is_sync = 1; } - if (bitoffset == 15 && (!(adkcon & 0x400) || syncfound)) - dmaon = 1; - else - dmaon = 0; - if (word == dsksync) { - if (adkcon & 0x400) { - if (!syncfound) bitoffset = -1; - syncfound = 1; - } - wordsync_last = l; - wordsync_cycle[l++] = hpos >> 8; - disk_sync[hpos >> 8] |= DISK_WORDSYNC; - is_sync = 1; - } - if (dmaon) { - dma_tab[j++] = word; + if (bitoffset == 31 && dma_enable) { + dma_tab[j++] = (word >> 16) & 0xffff; if (j == MAX_DISK_WORDS_PER_LINE - 1) { write_log ("Bug: Disk DMA buffer overflow!\n"); j--; } } - if (bitoffset == 7 || bitoffset == 15) { - dskbytr_tab[k] = word & 0xff; + if (bitoffset == 15 || bitoffset == 23 || bitoffset == 31) { + dskbytr_tab[k] = (word >> 8) & 0xff; dskbytr_tab[k] |= 0x8000; dskbytr_last = k; dskbytr_cycle[k++] = hpos >> 8; } + synccheck = (word >> 8) & 0xffff; + if (synccheck == dsksync) { + if (adkcon & 0x400) { + if (bitoffset != 23 || !dma_enable) + bitoffset = 7; + dma_enable = 1; + } + wordsync_last = l; + wordsync_cycle[l++] = hpos >> 8; + disk_sync[hpos >> 8] |= DISK_WORDSYNC; + is_sync = 1; + } bitoffset++; - bitoffset &= 15; + if (bitoffset == 32) bitoffset = 16; hpos += drv->trackspeed; } dma_tab[j] = 0xffffffff; @@ -1020,6 +1235,9 @@ static void disk_doupdate_read (drive * /* disk DMA fetch happens on real Amiga at the beginning of next horizontal line (cycles 9, 11 and 13 according to hardware manual) We transfer all DMA'd data at cycle 0. I don't think any program cares about this small difference. + + We must handle dsklength = 0 because some copy protections use it to detect + wordsync without transferring any data. */ static void dodmafetch (void) { @@ -1027,18 +1245,48 @@ static void dodmafetch (void) i = 0; while (dma_tab[i] != 0xffffffff && dskdmaen == 2 && (dmacon & 0x210) == 0x210) { - put_word (dskpt, dma_tab[i]); - dskpt += 2; - dsklength--; + if (dsklength > 0) { + put_word (dskpt, dma_tab[i++]); + dskpt += 2; + dsklength--; + } if (dsklength == 0) { disk_dmafinished (); break; } - i++; } dma_tab[0] = 0xffffffff; } +/* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */ + +uae_u16 DSKBYTR (int hpos) +{ + uae_u16 v; + int i; + + i = 0; + while (hpos > dskbytr_cycle[i + 1]) + i++; + v = dskbytr_tab[i]; + dskbytr_tab[i] &= ~0x8000; + if (wordsync_cycle[0] != 255) { + i = 0; + while (hpos < wordsync_cycle[i]) + i++; + if (hpos - wordsync_cycle[i] <= WORDSYNC_CYCLES) + v |= 0x1000; + } + if (dskdmaen && (dmacon & 0x210) == 0x210) + v |= 0x4000; + if (dskdmaen == 3) + v |= 0x2000; + + disk_data_used = 0; + + return v; +} + static void DISK_start (void) { int dr; @@ -1056,11 +1304,10 @@ static void DISK_start (void) /* Ugh. A nasty hack. Assume ADF_EXT1 tracks are always read from the start. */ if (ti->type == TRACK_RAW1) - drv->mfmpos = 0; + drv->mfmpos = 0; } } - syncfound = 0; - dmaon = 0; + dma_enable = (adkcon & 0x400) ? 0 : 1; word = 0; bitoffset = 0; dma_tab[0] = 0xffffffff; @@ -1071,7 +1318,7 @@ static int linecounter; void DISK_update (void) { int dr; - + for (dr = 0; dr < 4; dr++) { drive *drv = &floppy[dr]; if (drv->steplimit) @@ -1102,7 +1349,7 @@ void DISK_update (void) if (dskdmaen == 3) disk_doupdate_write (drv); - else if (disk_data_used < 50 * 2) { + else if (1 || disk_data_used < MAXVPOS * 50 * 2) { disk_data_used++; disk_doupdate_read (drv); } @@ -1124,7 +1371,7 @@ void DSKLEN (uae_u16 v, int hpos) write_log ("warning: Disk write DMA aborted, %d words left\n", dsklength); dskdmaen = 0; } - dsklength = v & 0x3fff; + dsklength = v & 0x3ffe; if (dskdmaen <= 1) return; if (v & 0x4000) @@ -1175,7 +1422,7 @@ void DSKLEN (uae_u16 v, int hpos) pos %= drv->tracklen; if (drv->bigmfmbuf[pos >> 4] == dsksync) { /* must skip first disk sync marker */ - pos += 16; + pos += 16; pos %= drv->tracklen; break; } @@ -1198,35 +1445,6 @@ void DSKLEN (uae_u16 v, int hpos) } } -/* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */ - -uae_u16 DSKBYTR (int hpos) -{ - uae_u16 v; - int i; - - i = 0; - while (hpos > dskbytr_cycle[i + 1]) - i++; - v = dskbytr_tab[i]; - dskbytr_tab[i] &= ~0x8000; - if (wordsync_cycle[0] != 255) { - i = 0; - while (hpos < wordsync_cycle[i]) - i++; - if (hpos - wordsync_cycle[i] <= WORDSYNC_CYCLES) - v |= 0x1000; - } - if (dskdmaen && (dmacon & 0x210) == 0x210) - v |= 0x4000; - if (dskdmaen == 3) - v |= 0x2000; - - disk_data_used = 0; - - return v; -} - /* not a real hardware register */ uae_u16 DSKDATR (int hpos) { @@ -1270,11 +1488,9 @@ void DISK_init (void) wordsync_cycle[0] = 255; for (dr = 0; dr < 4; dr++) { - drive *drv = &floppy[dr]; - /* reset all drive types to 3.5 DD */ - drive_settype_id (drv); - if (!drive_insert (drv, dr, currprefs.df[dr])) - disk_eject (dr); + drive *drv = floppy + dr; + drv->type = currprefs.dfxtype[dr]; + reset_drive (dr); } if (disk_empty (0)) write_log ("No disk in drive 0.\n"); @@ -1283,12 +1499,16 @@ void DISK_init (void) void DISK_reset (void) { int i; + + if (savestate_state) + return; + disk_hpos = 0; disk_data_used = 0; + dskdmaen = 0; + disabled = 0; for (i = 0; i < 4; i++) { - floppy[i].disabled = 0; - if (i >= currprefs.nr_floppies) - floppy[i].disabled = 1; + reset_drive (i); } } @@ -1305,11 +1525,11 @@ void dumpdisk (void) void DISK_save_custom (uae_u32 *pdskpt, uae_u16 *pdsklength, uae_u16 *pdsksync, uae_u16 *pdskdatr, uae_u16 *pdskbytr) { - if(pdskpt) *pdskpt = dskpt; - if(pdsklength) *pdsklength = dsklength; - if(pdsksync) *pdsksync = dsksync; - if(pdskdatr) *pdskdatr = 0; - if(pdskbytr) *pdskbytr = dskbytr_tab[0]; + if (pdskpt) *pdskpt = dskpt; + if (pdsklength) *pdsklength = dsklength; + if (pdsksync) *pdsksync = dsksync; + if (pdskdatr) *pdskdatr = 0; + if (pdskbytr) *pdskbytr = dskbytr_tab[0]; } void DISK_restore_custom (uae_u32 pdskpt, uae_u16 pdsklength, uae_u16 pdskdatr, uae_u16 pdskbytr) @@ -1319,40 +1539,88 @@ void DISK_restore_custom (uae_u32 pdskpt dskbytr_tab[0] = pdskbytr; } -uae_u8 *restore_disk(int num,uae_u8 *src) +const uae_u8 *restore_disk (int num, const uae_u8 *src) { drive *drv; + int state; + int newis; drv = &floppy[num]; + disabled &= ~(1 << num); drv->drive_id = restore_u32 (); - drv->motoroff = restore_u8 () ? 0 : 1; + drv->motoroff = 1; + drv->idbit = 0; + state = restore_u8 (); + if (state & 2) { + disabled |= 1 << num; + if (changed_prefs.nr_floppies > num) + changed_prefs.nr_floppies = num; + changed_prefs.dfxtype[num] = -1; + } else { + drive_type dfxtype; + drv->motoroff = (state & 1) ? 0 : 1; + drv->idbit = (state & 4) ? 1 : 0; + if (changed_prefs.nr_floppies < num) + changed_prefs.nr_floppies = num; + switch (drv->drive_id) + { + case DRIVE_ID_35HD: + dfxtype = DRV_35_HD; + break; + case DRIVE_ID_525SD: + dfxtype = DRV_525_SD; + break; + default: + dfxtype = DRV_35_DD; + break; + } + changed_prefs.dfxtype[num] = dfxtype; + } + drv->type = changed_prefs.dfxtype[num]; + drv->buffered_cyl = -1; + drv->buffered_side = -1; drv->cyl = restore_u8 (); drv->dskready = restore_u8 (); drv->drive_id_scnt = restore_u8 (); drv->mfmpos = restore_u32 (); + drv->dskchange = 0; + drv->dskchange_time = 0; restore_u32 (); - strncpy(currprefs.df[num],src,255); - src+=strlen(src)+1; + strncpy (changed_prefs.df[num], src, 255); + changed_prefs.df[num][255] = 0; + newis = changed_prefs.df[num][0] ? 1 : 0; + src += strlen (src) + 1; + + if (!(disabled & (1 << num))) { + if (!newis) { + drv->dskchange = 1; + } else { + drive_insert (floppy + num, num, changed_prefs.df[num]); + } + } return src; } -uae_u8 *save_disk(int num,int *len) +uae_u8 *save_disk (int num, int *len, uae_u8 *dstptr) { uae_u8 *dstbak,*dst; drive *drv; drv = &floppy[num]; - dstbak = dst = malloc (2+1+1+1+1+4+4+256); + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc (2+1+1+1+1+4+4+256); save_u32 (drv->drive_id); /* drive type ID */ - save_u8 (drv->motoroff ? 0:1); /* motor state */ + save_u8 ((drv->motoroff ? 0:1) | ((disabled & (1 << num)) ? 2 : 0) | (drv->idbit ? 4 : 0) | (drv->dskchange ? 8 : 0)); save_u8 (drv->cyl); /* cylinder */ save_u8 (drv->dskready); /* dskready */ save_u8 (drv->drive_id_scnt); /* id mode position */ save_u32 (drv->mfmpos); /* disk position */ save_u32 (0); /* CRC of disk image */ strcpy (dst, currprefs.df[num]);/* image name */ - dst += strlen(dst) + 1; + dst += strlen (dst) + 1; *len = dst - dstbak; return dstbak; @@ -1360,30 +1628,35 @@ uae_u8 *save_disk(int num,int *len) /* internal floppy controller variables */ -uae_u8 *restore_floppy(uae_u8 *src) +const uae_u8 *restore_floppy (const uae_u8 *src) { - word = restore_u16(); - bitoffset = restore_u8(); - syncfound = restore_u8(); - disk_hpos = restore_u8(); - dskdmaen = restore_u8(); + word = restore_u16 (); + bitoffset = restore_u8 (); + dma_enable = restore_u8 (); + disk_hpos = restore_u8 (); + dskdmaen = restore_u8 (); + word |= restore_u16 () << 16; return src; } -uae_u8 *save_floppy(int *len) +uae_u8 *save_floppy (int *len, uae_u8 *dstptr) { uae_u8 *dstbak, *dst; /* flush dma buffer before saving */ - dodmafetch(); + dodmafetch (); - dstbak = dst = malloc(2+1+1+1+1); - save_u16 (word); /* current word */ + if (dstptr) + dstbak = dst = dstptr; + else + dstbak = dst = malloc (2+1+1+1+1+2); + save_u16 (word); /* current fifo (low word) */ save_u8 (bitoffset); /* dma bit offset */ - save_u8 (syncfound); /* disk sync found */ + save_u8 (dma_enable); /* disk sync found */ save_u8 (disk_hpos); /* next bit read position */ save_u8 (dskdmaen); /* dma status */ + save_u16 (word >> 16); /* current fifo (high word) */ *len = dst - dstbak; return dstbak;