--- uae/src/disk.c 2018/04/24 16:38:39 1.1 +++ uae/src/disk.c 2018/04/24 16:41:59 1.1.1.4 @@ -1,16 +1,19 @@ - /* + /* * UAE - The Un*x Amiga Emulator - * + * * Floppy disk emulation * - * (c) 1995 Bernd Schmidt, Hannu Rummukainen + * Copyright 1995 Bernd Schmidt, Hannu Rummukainen */ +#include + #include "sysconfig.h" #include "sysdeps.h" #include "config.h" #include "options.h" +#include "threaddep/penguin.h" #include "memory.h" #include "events.h" #include "custom.h" @@ -18,70 +21,101 @@ #include "disk.h" #include "gui.h" #include "zfile.h" +#include "autoconf.h" +#include "readcpu.h" +#include "newcpu.h" +#include "xwin.h" +#include "osemu.h" +#include "execlib.h" -#define FLOPPY_SPEED 5 +#define FLOPPY_GAP_LEN 360 -UWORD* mfmwrite; -static UWORD mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */ +#define FLOPPY_SPEED 4 + +uae_u16* mfmwrite; +static uae_u16 mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */ static int side, direction, step; -static UBYTE selected = 15; +static uae_u8 selected = 15; static int dskready; -static int need_read = 0; typedef struct { - UWORD sync; - UWORD len; - ULONG offs; + uae_u16 sync; + uae_u16 len; + uae_u32 offs; } trackid; +#define MAX_TRACKS 328 + typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype; typedef struct { FILE *diskfile; drive_filetype filetype; - trackid trackdata[164]; - unsigned int track; + trackid trackdata[MAX_TRACKS]; + unsigned int buffered_cyl, buffered_side; + unsigned int cyl; + int side; int motoroff; int wrprot; - UWORD bigmfmbuf[0x2000]; + uae_u16 bigmfmbuf[0x4000]; int tracklen; unsigned long last_cycles; int mfmpos; + unsigned 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 dskchange; + int dskchange_time; } drive; drive floppy[4]; -static void drive_fill_bigbuf(drive *drv); +static void drive_fill_bigbuf (drive *drv); -static void drive_insert(drive *drv, int dnum, char *fname) +FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot) { - unsigned char buffer[10]; - - drv->diskfile = zfile_open(fname,"r+b"); - if (drv->diskfile) { - drv->wrprot = 0; + FILE *f = zfile_open (fname, "r+b"); + if (f) { + if (wrprot) + *wrprot = 0; } else { - drv->wrprot = 1; - drv->diskfile = zfile_open(fname, "rb"); - if (!drv->diskfile) { - gui_filename(dnum, ""); - return; - } - } - switch (dnum) { - case 0: strcpy((char *)df0, fname); break; - case 1: strcpy((char *)df1, fname); break; - case 2: strcpy((char *)df2, fname); break; - case 3: strcpy((char *)df3, fname); break; - case 4: break; + if (wrprot) + *wrprot = 1; + f = zfile_open (fname, "rb"); } + if (!leave_open) + zfile_close (f); + return f; +} + +static int drive_insert (drive *drv, int dnum, const char *fname) +{ + unsigned char buffer[10]; + + drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot); + if (drv->diskfile == 0) + return 0; + + strncpy (currprefs.df[dnum], fname, 255); + currprefs.df[dnum][255] = 0; + strncpy (changed_prefs.df[dnum], fname, 255); + changed_prefs.df[dnum][255] = 0; gui_filename(dnum, fname); - fread(buffer,sizeof(char),8,drv->diskfile); - if (strncmp((char *)buffer,"UAE--ADF",8) == 0) { + + fread (buffer, sizeof(char), 8, drv->diskfile); + if (strncmp((char *)buffer,"UAE--ADF",8) == 0) { int offs = 160*4+8; int i; - - drv->filetype = ADF_EXT1; + + drv->filetype = ADF_EXT1; + drv->num_tracks = 160; + drv->num_secs = 11; + drv->wrprot = 1; /* write to adf_ext1 not implemented */ for(i=0; i<160; i++) { fread(buffer, 4, 1, drv->diskfile); @@ -91,49 +125,69 @@ static void drive_insert(drive *drv, int offs += drv->trackdata[i].len; } } else { - int i; - drv->filetype = ADF_NORMAL; - for(i=0; i<160; i++) { - drv->trackdata[i].len = 512 * 11; + unsigned 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 (drv->num_tracks > MAX_TRACKS) + write_log ("Your diskfile is too big!\n"); + for(i = 0; i < drv->num_tracks; i++) { + drv->trackdata[i].len = 512 * drv->num_secs; drv->trackdata[i].sync = 0; - drv->trackdata[i].offs = i*512*11; + drv->trackdata[i].offs = i * 512 * drv->num_secs; } } - drive_fill_bigbuf(drv); + drv->buffered_side = 2; /* will force read */ + return 1; } -static void drive_step(drive *drv) +static int drive_empty (drive *drv) { + return drv->diskfile == 0; +} + +static void drive_step (drive *drv) +{ + if (!drive_empty(drv)) + drv->dskchange = 0; + else if (drv->dskchange > 1) { +/* printf("Stepping...\n"); + drv->dskchange--;*/ + } if (direction) { - if (drv->track) drv->track--; + if (drv->cyl) drv->cyl--; } else { - if (drv->track < 85) drv->track++; + if (drv->cyl < drv->num_tracks/2) drv->cyl++; } - drive_fill_bigbuf(drv); } -static int drive_track0(drive *drv) +static int drive_track0 (drive *drv) { - return drv->track == 0; + return drv->cyl == 0; } -static int drive_writeprotected(drive *drv) +static int drive_writeprotected (drive *drv) { - return drv->wrprot || drv->diskfile == NULL; + return drv->wrprot || drv->diskfile == NULL; } -static int drive_empty(drive *drv) +static int drive_running (drive *drv) { - return drv->diskfile == 0; + return !drv->motoroff; } -static int drive_running(drive *drv) -{ - return !drv->motoroff; -} - -static void drive_motor(drive *drv, int off) +static void drive_motor (drive *drv, int off) { if (drv->motoroff && !off) { drv->last_cycles = cycles; @@ -147,57 +201,66 @@ static void drive_motor(drive *drv, int } else if (off) eventtab[ev_diskindex].active = 0; drv->motoroff = off; - events_schedule(); - + events_schedule (); } static void drive_fill_bigbuf(drive *drv) { - int tr = drv->track*2 + side; - - if (!drv->diskfile) return; + int tr = drv->cyl*2 + side; + + if (!drv->diskfile) { + drv->tracklen = 10; + memset (drv->bigmfmbuf,0xaa,drv->tracklen*2); + return; + } + if (drv->buffered_cyl == drv->cyl && drv->buffered_side == side) + return; + +/* if (drv->num_tracks <= tr) { + write_log ("Access beyond end of floppy image!\n"); + }*/ if (drv->trackdata[tr].sync == 0) { /* Normal AmigaDOS format track */ - int sec; - drv->tracklen = 11*544 + 300; - memset(drv->bigmfmbuf,0xaa,300*2); - - for (sec = 0; sec < 11; sec++) { - UBYTE secbuf[544]; + unsigned int sec; + drv->tracklen = drv->num_secs*544 + FLOPPY_GAP_LEN; + memset(drv->bigmfmbuf,0xaa,FLOPPY_GAP_LEN*2); + + for (sec = 0; sec < drv->num_secs; sec++) { + uae_u8 secbuf[544]; int i; - UWORD *mfmbuf = drv->bigmfmbuf + 544*sec + 300; - ULONG deven,dodd; - ULONG hck=0,dck=0; - + 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] = 11-sec; + secbuf[7] = drv->num_secs-sec; for(i = 8; i < 24; i++) secbuf[i] = 0; - - fseek(drv->diskfile, - drv->trackdata[tr].offs + sec*512, - SEEK_SET); - fread(&secbuf[32],1,512,drv->diskfile); - + + fseek (drv->diskfile, + drv->trackdata[tr].offs + sec*512, + SEEK_SET); + fread (&secbuf[32],1,512,drv->diskfile); + mfmbuf[0] = mfmbuf[1] = 0xaaaa; mfmbuf[2] = mfmbuf[3] = 0x4489; - - deven = ((secbuf[4] << 24) | (secbuf[5] << 16) + + 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[6] = deven>> 16; mfmbuf[7] = deven; - + for (i = 8; i < 48; i++) mfmbuf[i] = 0; for (i = 0; i < 512; i += 4){ @@ -205,50 +268,50 @@ static void drive_fill_bigbuf(drive *drv | (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; + 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; - + 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; + mfmbuf[30] = deven >> 16; mfmbuf[31] = deven; } } else { int i; drv->tracklen = drv->trackdata[tr].len/2 + 1; drv->bigmfmbuf[0] = drv->trackdata[tr].sync; fseek(drv->diskfile, drv->trackdata[tr].offs, SEEK_SET); - fread(drv->bigmfmbuf+1, 1, drv->trackdata[tr].len, drv->diskfile); + fread((char *)(drv->bigmfmbuf + 1), 1, drv->trackdata[tr].len, drv->diskfile); for (i = 0; i < drv->trackdata[tr].len/2; i++) { - UWORD *mfm = drv->bigmfmbuf + i + 1; - UBYTE *data = (UBYTE *)mfm; - + uae_u16 *mfm = drv->bigmfmbuf + i + 1; + uae_u8 *data = (uae_u8 *)mfm; + *mfm = 256 * *data + *(data+1); } } - need_read = 0; + drv->buffered_side = side; + drv->buffered_cyl = drv->cyl; drv->last_cycles = cycles; drv->mfmpos = 0; } -static int drive_get_data(drive *drv, UWORD *mfm, UWORD *byt) +static int drive_get_data (drive *drv, uae_u16 *mfm, uae_u16 *byt) { int offset,mfmpos; - if (need_read) { - drive_fill_bigbuf(drv); - } + + drive_fill_bigbuf(drv); offset = (cycles - drv->last_cycles) / FLOPPY_SPEED; mfmpos = (drv->mfmpos + offset) % drv->tracklen; drv->last_cycles += offset*FLOPPY_SPEED; @@ -258,55 +321,61 @@ static int drive_get_data(drive *drv, UW } #define MFMMASK 0x55555555 -static __inline__ ULONG getmfmlong(UWORD* mbuf) +static __inline__ uae_u32 getmfmlong (uae_u16* mbuf) { return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK; } -static void drive_write_data(drive *drv, UWORD *mbuf, int length) +static void drive_write_data (drive *drv, uae_u16 *mbuf, int length) { int i, secwritten = 0; - ULONG odd, even, chksum, id, dlong; - UBYTE* secdata; - UBYTE secbuf[544]; - UWORD *mend = mbuf + length; - - if (drive_writeprotected(drv)) return; + uae_u32 odd, even, chksum, id, dlong; + uae_u8* secdata; + uae_u8 secbuf[544]; + uae_u16 *mend = mbuf + length; + + if (drive_writeprotected (drv)) + return; + + drive_fill_bigbuf (drv); mend -= (4 + 16 + 8 + 512); while (length > 0) { int trackoffs; - + do { while (*mbuf++ != 0x4489) { - if (mbuf >= mend) return; + if (mbuf >= mend) + return; } } while (*mbuf++ != 0x4489); - - odd = getmfmlong(mbuf); - even = getmfmlong(mbuf+2); - mbuf += 4; + + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2); + mbuf += 4; id = (odd << 1) | even; - + trackoffs = (id & 0xff00) >> 8; if (trackoffs > 10) { - printf("Disk write: weird sector number %d\n", trackoffs); + printf ("Disk write: weird sector number %d\n", trackoffs); continue; } chksum = odd ^ even; - for (i=0; i<4; i++) { + for (i = 0; i < 4; i++) { odd = getmfmlong(mbuf); even = getmfmlong(mbuf+8); mbuf += 2; - + dlong = (odd << 1) | even; - if (dlong) secwritten = -200; + if (dlong) + secwritten = -200; chksum ^= odd ^ even; } /* could check here if the label is nonstandard */ mbuf += 8; - odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4; - if ((((odd << 1) | even) != chksum) || - (((id & 0x00ff0000) >> 16) != drv->track*2 + side)) { - printf("Disk write: checksum error on sector header\n"); + odd = getmfmlong (mbuf); even = getmfmlong (mbuf+2); mbuf += 4; + if (((odd << 1) | even) != chksum + || ((id & 0x00ff0000) >> 16) != drv->cyl*2 + side) + { + write_log ("Disk write: checksum error on sector header\n"); continue; } odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4; @@ -321,82 +390,112 @@ static void drive_write_data(drive *drv, } mbuf += 256; if (chksum) { - printf("Disk write: data checksum error\n"); + write_log ("Disk write: data checksum error\n"); continue; } secwritten++; - fseek(drv->diskfile, - drv->trackdata[drv->track*2 + side].offs + trackoffs*512, - SEEK_SET); - fwrite(secbuf+32, sizeof(UBYTE), 512, drv->diskfile); + fseek (drv->diskfile, + drv->trackdata[drv->cyl*2 + side].offs + trackoffs*512, + SEEK_SET); + fwrite (secbuf+32, sizeof (uae_u8), 512, drv->diskfile); } - need_read = 1; - - if (secwritten == 0) - printf("Disk write in unsupported format\n"); + drv->buffered_side = 2; /* will force read */ + + if (secwritten == 0) + write_log ("Disk write in unsupported format\n"); if (secwritten < 0) - printf("Disk write: sector labels ignored\n"); + write_log ("Disk write: sector labels ignored\n"); } -static void drive_eject(drive *drv) +static void drive_eject (drive *drv) { - if (!drive_empty(drv)) zfile_close(drv->diskfile); + 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; } -/* We use this function if we have no Kickstart ROM. +/* We use this function if we have no Kickstart ROM. * No error checking - we trust our luck. */ -void DISK_ersatz_read (int tr, int sec, CPTR dest) +void DISK_ersatz_read (int tr, int sec, uaecptr dest) { - int i; - UBYTE *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); + 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); } -void disk_eject(int num) +void disk_eject (int num) { gui_filename(num, ""); drive_eject(floppy + num); + *currprefs.df[num] = *changed_prefs.df[num] = 0; } -void disk_insert(int num, char *name) +void disk_insert (int num, const char *name) { /* just to be sure */ - drive_eject(floppy + num); - drive_insert(floppy + num, num, name); + drive_eject (floppy + num); + drive_insert (floppy + num, num, name); } -int disk_empty(int num) +void DISK_check_change (void) { - return drive_empty(floppy + num); + int i; + static int count = 0; + count++; + + for (i = 0; i < 4; i++) { + 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; + } + } + } + } } -void DISK_init() +int disk_empty (int num) { - drive_insert(floppy, 0, df0); - if (disk_empty(0)) - fprintf(stderr, "No floppy in drive 0.\n"); - drive_insert(floppy + 1, 1, df1); - drive_insert(floppy + 2, 2, df2); - drive_insert(floppy + 3, 3, df3); + return drive_empty (floppy + num); +} + +void DISK_init (void) +{ + int i; + for (i = 0; i < 4; i++) + if (!drive_insert (floppy+i, i, currprefs.df[i])) + disk_eject (i); + + if (disk_empty (0)) + write_log ("No disk in drive 0.\n"); } static int ledstate[] = { 0,0,0,0 }; -void DISK_select(UBYTE data) +void DISK_select (uae_u8 data) { int step_pulse; int dr; - - if (selected != ((data >> 3) & 15)) + + if (selected != ((data >> 3) & 15)) dskready = 0; selected = (data >> 3) & 15; - if (side != 1 - ((data >> 2) & 1)) { - side = 1 - ((data >> 2) & 1); - need_read = 1; - } + side = 1 - ((data >> 2) & 1); + direction = (data >> 1) & 1; step_pulse = data & 1; if (step != step_pulse) { @@ -404,7 +503,7 @@ void DISK_select(UBYTE data) if (step == 0){ for (dr = 0; dr < 4; dr++){ if (!(selected & (1 << dr))) { - drive_step(floppy + dr); + drive_step (floppy + dr); } } } @@ -416,35 +515,44 @@ void DISK_select(UBYTE data) } for (dr = 0; dr < 4; dr++) { int state = (!(selected & (1<dskchange) { + /*printf("changed bit set: %d\n",dr); */ + st &= ~0x4; + if (drv->dskchange > 1) + drv->dskchange--; + } } } return st; } -int DISK_GetData(UWORD *mfm,UWORD *byt) +int DISK_GetData (uae_u16 *mfm, uae_u16 *byt) { int dr; for (dr = 0; dr < 4; dr++){ @@ -455,26 +563,24 @@ int DISK_GetData(UWORD *mfm,UWORD *byt) return 0; } -static UWORD mfm_read_buffer[0x4000]; +static uae_u16 mfm_read_buffer[0x4000]; static int mfm_read_length; -int DISK_PrepareReadMFM(int length, UWORD sync, int use_sync) +int DISK_PrepareReadMFM (int length, uae_u16 sync, int use_sync) { int dr; - + mfm_read_length = 0; - + for (dr = 0; dr < 4; dr++) { if (!(selected & (1<last_cycles) / FLOPPY_SPEED; mfmpos = (drv->mfmpos + offset) % drv->tracklen; drv->last_cycles += offset*FLOPPY_SPEED; @@ -482,13 +588,13 @@ int DISK_PrepareReadMFM(int length, UWOR mfmpos++; mfmpos %= drv->tracklen; while (drv->bigmfmbuf[mfmpos] != sync && mfmpos != drv->mfmpos && use_sync) mfmpos = (mfmpos + 1) % drv->tracklen, time++; - + if (drv->bigmfmbuf[mfmpos] != sync && use_sync) { - fprintf(stderr, "warning: sync not found on disk read\n"); + write_log ("warning: sync not found on disk read\n"); return 0; } else mfmpos++; - + mfm_read_length = length; while (length--) { @@ -500,16 +606,16 @@ int DISK_PrepareReadMFM(int length, UWOR return time*FLOPPY_SPEED; } } - return 0; + return 0; } -int DISK_ReadMFM(CPTR target) +int DISK_ReadMFM (uaecptr target) { int i; - UBYTE *mfmp = get_real_address(target); - + uae_u8 *mfmp = get_real_address(target); + if (!chipmem_bank.check(target, mfm_read_length * 2)) { - fprintf(stderr, "warning: Bad disk DMA read pointer\n"); + write_log ("warning: Bad disk DMA read pointer\n"); return 0; } @@ -520,15 +626,15 @@ int DISK_ReadMFM(CPTR target) return 1; } -void DISK_InitWrite() +void DISK_InitWrite (void) { mfmwrite = mfmwrbuffer; } -void DISK_WriteData(int length) +void DISK_WriteData (int length) { int dr; - for (dr=0;dr<4;dr++){ + for (dr = 0; dr < 4; dr++){ if (!(selected & (1<