--- uae/src/disk.c 2018/04/24 17:01:46 1.1.1.12 +++ uae/src/disk.c 2018/04/24 17:21:42 1.1.1.21 @@ -16,7 +16,6 @@ #include "sysconfig.h" #include "sysdeps.h" -#include "config.h" #include "options.h" #include "threaddep/thread.h" #include "memory.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 @@ -57,27 +66,38 @@ static int floppy_speed = NORMAL_FLOPPY_ static int side, direction, writing; 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; @@ -91,6 +111,7 @@ typedef struct { int trackspeed; int dmalen; int num_tracks, num_secs; + int hard_num_cyls; int dskchange; int dskchange_time; int dskready; @@ -98,6 +119,7 @@ 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; @@ -112,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 } @@ -167,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); + +static void drive_image_free (drive *drv) +{ + drv->filetype = -1; + if (!drv->diskfile) + return; + zfile_fclose (drv->diskfile); + drv->diskfile = 0; +} -FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot) +struct zfile *DISK_validate_filename (const char *fname, int leave_open, int *wrprot) { - FILE *f = zfile_open (fname, "r+b"); + struct zfile *f = zfile_open (fname, "r+b"); if (f) { if (wrprot) *wrprot = 0; @@ -181,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); @@ -202,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; @@ -234,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; @@ -252,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"); @@ -275,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; @@ -301,14 +384,14 @@ static void drive_step (drive * drv) 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 @@ -339,11 +422,13 @@ static void drive_motor (drive * drv, in if (drv->motoroff && !off) { 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; @@ -351,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... */ @@ -376,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; @@ -390,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; - } + if (ti->type == TRACK_PCDOS) { + decode_pcdos (drv); - 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); - } -#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; @@ -500,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 @@ -622,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; @@ -648,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; } @@ -668,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; @@ -678,11 +890,13 @@ static void drive_write_data (drive * dr static void drive_eject (drive * drv) { - if (!drive_empty (drv)) - zfile_close (drv->diskfile); - drv->diskfile = 0; + drive_image_free (drv); drv->dskchange = 1; - drive_settype_id(drv); /* Back to 35 DD */ + 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 @@ -693,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) @@ -708,19 +922,23 @@ void disk_eject (int num) void disk_insert (int num, const char *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) { + } 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 + /* 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 */ - strcpy (drv->newname, name); drv->dskchange_time = 10; /* 1 second disk change delay */ } else { - /* no delayed insert if drive is already empty */ - drive_insert (drv, num, name); + drv->dskchange_time = 1; } } @@ -730,12 +948,16 @@ void DISK_check_change (void) for (i = 0; i < 4; i++) { drive *drv = floppy + i; - if (strcmp (currprefs.df[i], changed_prefs.df[i])) { - strcpy (currprefs.df[i], changed_prefs.df[i]); - disk_insert (i, currprefs.df[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) { + if (drv->dskready_time && !drive_empty (drv)) { drv->dskready_time--; if (drv->dskready_time == 0) drv->dskready = 1; @@ -780,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); + } + } } } } @@ -816,23 +1044,18 @@ 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 { /* 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); +#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; } if (drive_track0 (drv)) st &= ~0x10; @@ -840,7 +1063,10 @@ uae_u8 DISK_status (void) st &= ~8; if (drv->dskchange) st &= ~4; - } + } else if (!(selected & (1 << dr))) { + if (drv->idbit) + st &= ~0x20; + } } return st; } @@ -863,11 +1089,11 @@ static uae_u32 dskpt; static void disk_dmafinished (void) { INTREQ (0x8002); - dskdmaen = 1; /* surprise, it isn't set to zero! */ + dskdmaen = 0; /* ??? */ #ifdef DISK_DEBUG - write_log("disk dma finished %08.8X\n", dskpt); + write_log ("disk dma finished %08.8X\n", dskpt); #endif -} +} static void disk_events (int last) { @@ -883,8 +1109,6 @@ static void disk_events (int last) } } -extern void cia_diskindex (void); - void DISK_handler (void) { eventtab[ev_disk].active = 0; @@ -1034,6 +1258,35 @@ static void dodmafetch (void) 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; @@ -1065,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) @@ -1192,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) { @@ -1264,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"); @@ -1277,14 +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++) { - if (i >= currprefs.nr_floppies) { - disabled |= 1 << i; - floppy[i].motoroff = 1; - } + reset_drive (i); } } @@ -1301,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) @@ -1315,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; @@ -1356,26 +1628,29 @@ 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(); - dma_enable = restore_u8(); - disk_hpos = restore_u8(); - dskdmaen = restore_u8(); - word |= restore_u16() << 16; + 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+2); + 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 (dma_enable); /* disk sync found */