Annotation of uae/src/disk.c, revision 1.1.1.19

1.1.1.2   root        1:  /*
1.1       root        2:   * UAE - The Un*x Amiga Emulator
1.1.1.2   root        3:   *
1.1       root        4:   * Floppy disk emulation
                      5:   *
1.1.1.11  root        6:   * Copyright 1995 Hannu Rummukainen
                      7:   * Copyright 1995-2001 Bernd Schmidt
                      8:   * Copyright 2000, 2001 Toni Wilen
                      9:   *
                     10:   * High Density Drive Handling by Dr. Adil Temel (C) 2001 [[email protected]]
                     11:   *
1.1       root       12:   */
                     13: 
1.1.1.2   root       14: #include <stdio.h>
                     15: 
1.1       root       16: #include "sysconfig.h"
                     17: #include "sysdeps.h"
                     18: 
                     19: #include "options.h"
1.1.1.12  root       20: #include "threaddep/thread.h"
1.1       root       21: #include "memory.h"
                     22: #include "events.h"
                     23: #include "custom.h"
                     24: #include "ersatz.h"
                     25: #include "disk.h"
                     26: #include "gui.h"
                     27: #include "zfile.h"
1.1.1.2   root       28: #include "autoconf.h"
                     29: #include "newcpu.h"
                     30: #include "xwin.h"
                     31: #include "osemu.h"
                     32: #include "execlib.h"
1.1.1.11  root       33: #include "savestate.h"
1.1.1.2   root       34: 
1.1.1.7   root       35: /* writable track length with normal 2us bitcell/300RPM motor */
1.1.1.13  root       36: #define FLOPPY_WRITE_LEN (12650 / 2)
                     37: /* This works out to 341 */
                     38: #define FLOPPY_GAP_LEN (FLOPPY_WRITE_LEN - 11 * 544)
1.1.1.7   root       39: /* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1830 */
                     40: #define NORMAL_FLOPPY_SPEED 1830
                     41: 
                     42: static int floppy_speed = NORMAL_FLOPPY_SPEED;
                     43: 
                     44: #undef DISK_DEBUG
1.1.1.11  root       45: #undef DEBUG_DRIVE_ID
1.1.1.7   root       46: 
                     47: /* UAE-1ADF (ADF_EXT2)
                     48:  * W   reserved
                     49:  * W   number of tracks (default 2*80=160)
                     50:  *
                     51:  * W   reserved
                     52:  * W   type, 0=normal AmigaDOS track, 1 = raw MFM
                     53:  * L   available space for track in bytes
                     54:  * L   track length in bits
                     55:  */
1.1       root       56: 
1.1.1.11  root       57: static int side, direction, writing;
1.1.1.12  root       58: static uae_u8 selected = 15, disabled;
1.1       root       59: 
1.1.1.11  root       60: static uae_u8 *writebuffer[544 * 22];
1.1.1.7   root       61: 
                     62: typedef enum { TRACK_AMIGADOS, TRACK_RAW, TRACK_RAW1 } image_tracktype;
1.1       root       63: typedef struct {
1.1.1.3   root       64:     uae_u16 len;
                     65:     uae_u32 offs;
1.1.1.7   root       66:     int bitlen;
                     67:     unsigned int sync;
                     68:     image_tracktype type;
1.1       root       69: } trackid;
                     70: 
1.1.1.2   root       71: #define MAX_TRACKS 328
                     72: 
1.1.1.11  root       73: #define DRIVE_ID_NONE  0xFFFFFFFF
                     74: #define DRIVE_ID_35DD  0x00000000
                     75: #define DRIVE_ID_35HD  0xAAAAAAAA
                     76: #define DRIVE_ID_525DD 0x55555555 /* 40 track 5.25 drive , kickstart does not recognize this */
                     77: 
1.1.1.7   root       78: typedef enum { ADF_NORMAL, ADF_EXT1, ADF_EXT2 } drive_filetype;
1.1       root       79: typedef struct {
                     80:     FILE *diskfile;
                     81:     drive_filetype filetype;
1.1.1.2   root       82:     trackid trackdata[MAX_TRACKS];
1.1.1.7   root       83:     int buffered_cyl, buffered_side;
                     84:     int cyl;
1.1       root       85:     int motoroff;
1.1.1.7   root       86:     int state;
1.1       root       87:     int wrprot;
1.1.1.11  root       88:     uae_u16 bigmfmbuf[0x8000];
1.1       root       89:     int mfmpos;
1.1.1.7   root       90:     int tracklen;
                     91:     int trackspeed;
                     92:     int dmalen;
                     93:     int num_tracks, num_secs;
1.1.1.3   root       94:     int dskchange;
                     95:     int dskchange_time;
1.1.1.10  root       96:     int dskready;
                     97:     int dskready_time;
1.1.1.11  root       98:     int steplimit;
                     99:     int ddhd; /* 1=DD 2=HD */
                    100:     int drive_id_scnt; /* drive id shift counter */
                    101:     unsigned long drive_id; /* drive id to be reported */
1.1.1.12  root      102:     char newname[256]; /* storage space for new filename during eject delay */
1.1       root      103: } drive;
                    104: 
1.1.1.11  root      105: static drive floppy[4];
                    106: 
                    107: /* Keeps track of whether the Amiga program seems to be using the data coming
                    108:    in from the disk; if this remains 0 for several seconds, we stop calling
                    109:    disk_doupdate_read, even if the motor is still on.  This is a rather large
                    110:    performance win.  This contains the number of frames since we last accessed
                    111:    the disk.  */
                    112: static int disk_data_used;
                    113: 
                    114: #ifdef DEBUG_DRIVE_ID
                    115: static char *drive_id_name(drive *drv)
                    116: {
                    117:     switch(drv->drive_id)
                    118:     {
                    119:     case DRIVE_ID_35HD : return "3.5HD";
                    120:     case DRIVE_ID_525DD: return "5.25DD";
                    121:     case DRIVE_ID_35DD : return "3.5DD";
                    122:     }
1.1.1.18  root      123:     return "UNKNOWN";
1.1.1.11  root      124: }
                    125: #endif
                    126: 
1.1.1.18  root      127: /* Simulate exact behaviour of an A3000T 3.5 HD disk drive.
1.1.1.11  root      128:  * The drive reports to be a 3.5 DD drive whenever there is no
                    129:  * disk or a 3.5 DD disk is inserted. Only 3.5 HD drive id is reported
                    130:  * when a real 3.5 HD disk is inserted. -Adil
                    131:  */
                    132: static void drive_settype_id(drive *drv)
                    133: {
                    134:     if (!drv->diskfile || drv->num_secs == 11) {
                    135:        /* Double density */
                    136:        drv->drive_id = DRIVE_ID_35DD;
                    137:        drv->ddhd = 1;
                    138:     } else {
                    139:        /* High density */
                    140:        drv->drive_id = DRIVE_ID_35HD;
                    141:        drv->ddhd = 2;
                    142:     }
                    143:     drv->drive_id_scnt = 0;
                    144: #ifdef DEBUG_DRIVE_ID
                    145:     write_log("drive_settype_id: DF%d: set to %s\n",drv-floppy, drive_id_name(drv));
                    146: #endif
                    147: }
1.1       root      148: 
1.1.1.7   root      149: /* code for track display */
1.1.1.8   root      150: static void update_drive_gui (int num)
1.1.1.7   root      151: {
1.1.1.8   root      152:     drive *drv = floppy + num;
                    153: 
1.1.1.7   root      154:     if (drv->state == gui_data.drive_motor[num]
                    155:        && drv->cyl == gui_data.drive_track[num]
                    156:        && ((writing && gui_data.drive_writing[num])
                    157:            || (!writing && !gui_data.drive_writing[num]))) {
                    158:        return;
                    159:     }
                    160:     gui_data.drive_motor[num] = drv->state;
                    161:     gui_data.drive_track[num] = drv->cyl;
                    162:     if (!gui_data.drive_writing[num])
                    163:        gui_data.drive_writing[num] = writing;
1.1.1.8   root      164:     gui_ledstate &= ~(2 << num);
                    165:     if (drv->state)
                    166:        gui_ledstate |= 2 << num;
1.1.1.7   root      167:     gui_led (num + 1, gui_data.drive_motor[num]);
                    168: }
                    169: 
                    170: static void drive_fill_bigbuf (drive * drv);
1.1       root      171: 
1.1.1.3   root      172: FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot)
1.1       root      173: {
1.1.1.4   root      174:     FILE *f = zfile_open (fname, "r+b");
1.1.1.3   root      175:     if (f) {
                    176:        if (wrprot)
                    177:            *wrprot = 0;
1.1       root      178:     } else {
1.1.1.3   root      179:        if (wrprot)
                    180:            *wrprot = 1;
1.1.1.4   root      181:        f = zfile_open (fname, "rb");
1.1       root      182:     }
1.1.1.3   root      183:     if (!leave_open)
1.1.1.4   root      184:        zfile_close (f);
1.1.1.3   root      185:     return f;
                    186: }
                    187: 
1.1.1.7   root      188: static int drive_insert (drive * drv, int dnum, const char *fname)
1.1.1.3   root      189: {
1.1.1.7   root      190:     unsigned char buffer[2 + 2 + 4 + 4];
                    191:     trackid *tid;
1.1.1.3   root      192: 
                    193:     drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot);
1.1.1.6   root      194:     if (drv->diskfile == 0) {
1.1.1.7   root      195:        drv->tracklen = FLOPPY_WRITE_LEN * 2 * 8;
                    196:        drv->trackspeed = floppy_speed;
1.1.1.3   root      197:        return 0;
1.1.1.6   root      198:     }
1.1.1.3   root      199:     strncpy (currprefs.df[dnum], fname, 255);
                    200:     currprefs.df[dnum][255] = 0;
                    201:     strncpy (changed_prefs.df[dnum], fname, 255);
                    202:     changed_prefs.df[dnum][255] = 0;
1.1.1.7   root      203:     gui_filename (dnum, fname);
1.1.1.3   root      204: 
1.1.1.7   root      205:     fread (buffer, sizeof (char), 8, drv->diskfile);
                    206:     if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) {
                    207:        int offs;
                    208:        int i;
                    209: 
                    210:        fread (buffer, 1, 4, drv->diskfile);
                    211:        drv->num_tracks = buffer[2] * 256 + buffer[3];
                    212:        drv->filetype = ADF_EXT2;
                    213:        drv->num_secs = 11;
1.1.1.10  root      214:        offs = 8 + 2 + 2 + drv->num_tracks * (2 + 2 + 4 + 4);
1.1.1.7   root      215: 
                    216:        for (i = 0; i < drv->num_tracks; i++) {
                    217:            tid = &drv->trackdata[i];
                    218:            fread (buffer, 2 + 2 + 4 + 4, 1, drv->diskfile);
                    219:            tid->type = buffer[2] * 256 + buffer[3];
                    220:            tid->len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7];
                    221:            tid->bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11];
                    222:            tid->offs = offs;
                    223:            if (tid->type == TRACK_AMIGADOS) {
                    224:                if (tid->len > 20000)
                    225:                    drv->num_secs = 22;
                    226:            }
                    227:            offs += tid->len;
                    228:        }
                    229:     } else if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) {
                    230:        int offs = 160 * 4 + 8;
1.1       root      231:        int i;
1.1.1.3   root      232: 
                    233:        drv->filetype = ADF_EXT1;
1.1.1.2   root      234:        drv->num_tracks = 160;
                    235:        drv->num_secs = 11;
1.1.1.3   root      236: 
1.1.1.7   root      237:        drv->wrprot = 1;        /* write to adf_ext1 not implemented */
                    238:        for (i = 0; i < 160; i++) {
                    239:            tid = &drv->trackdata[i];
                    240:            fread (buffer, 4, 1, drv->diskfile);
                    241:            tid->sync = buffer[0] * 256 + buffer[1];
                    242:            tid->len = buffer[2] * 256 + buffer[3];
                    243:            tid->offs = offs;
                    244:            if (tid->sync == 0) {
                    245:                tid->type = TRACK_AMIGADOS;
                    246:                tid->bitlen = 0;
                    247:            } else {
                    248:                tid->type = TRACK_RAW1;
                    249:                tid->bitlen = tid->len * 8;
                    250:            }
                    251:            offs += tid->len;
1.1       root      252:        }
                    253:     } else {
1.1.1.7   root      254:        int i;
1.1.1.3   root      255: 
                    256:        drv->filetype = ADF_NORMAL;
1.1.1.2   root      257: 
1.1.1.7   root      258:        fseek (drv->diskfile, 0, SEEK_END);
1.1.1.4   root      259:        i = ftell (drv->diskfile);
1.1.1.7   root      260:        fseek (drv->diskfile, 0, SEEK_SET);
1.1.1.3   root      261: 
1.1.1.2   root      262:        /* High-density disk? */
1.1.1.7   root      263:        if (i >= 160 * 22 * 512)
                    264:            drv->num_tracks = i / (512 * (drv->num_secs = 22));
1.1.1.2   root      265:        else
1.1.1.7   root      266:            drv->num_tracks = i / (512 * (drv->num_secs = 11));
1.1.1.3   root      267: 
1.1.1.2   root      268:        if (drv->num_tracks > MAX_TRACKS)
1.1.1.3   root      269:            write_log ("Your diskfile is too big!\n");
1.1.1.7   root      270:        for (i = 0; i < drv->num_tracks; i++) {
                    271:            tid = &drv->trackdata[i];
                    272:            tid->type = TRACK_AMIGADOS;
                    273:            tid->len = 512 * drv->num_secs;
                    274:            tid->bitlen = 0;
                    275:            tid->offs = i * 512 * drv->num_secs;
1.1       root      276:        }
                    277:     }
1.1.1.11  root      278:     drive_settype_id(drv);     /* Set DD or HD drive */
1.1.1.7   root      279:     drv->buffered_side = 2;    /* will force read */
1.1.1.6   root      280:     drive_fill_bigbuf (drv);
1.1.1.3   root      281:     return 1;
1.1       root      282: }
                    283: 
1.1.1.7   root      284: static int drive_empty (drive * drv)
1.1.1.2   root      285: {
1.1.1.3   root      286:     return drv->diskfile == 0;
1.1.1.2   root      287: }
                    288: 
1.1.1.7   root      289: static void drive_step (drive * drv)
1.1       root      290: {
1.1.1.11  root      291:     if (drv->steplimit)
                    292:        return;
                    293:     /* A1200's floppy drive needs at least 30 raster lines between steps
                    294:      * but we'll use very small value for better compatibility with faster CPU emulation
                    295:      * (stupid trackloaders with CPU delay loops)
                    296:      */
                    297:     drv->steplimit = 2;
1.1.1.12  root      298:     if (!drive_empty (drv))
                    299:        drv->dskchange = 0;
1.1       root      300:     if (direction) {
1.1.1.7   root      301:        if (drv->cyl)
                    302:            drv->cyl--;
1.1.1.11  root      303: /*     else
                    304:            write_log("program tried to step beyond track zero\n");
                    305:            "no-click" programs does that
                    306: */
                    307:   } else {
1.1.1.7   root      308:        if (drv->cyl < 83)
                    309:            drv->cyl++;
1.1.1.11  root      310:        else
                    311:            write_log("program tried to step over track 83\n");
1.1       root      312:     }
                    313: 
1.1.1.7   root      314: #if 0 && defined DISK_DEBUG
                    315:     write_log ("track %d\n", drv->cyl);
                    316: #endif
                    317: }
1.1       root      318: 
1.1.1.7   root      319: static int drive_track0 (drive * drv)
1.1       root      320: {
1.1.1.3   root      321:     return drv->cyl == 0;
1.1       root      322: }
                    323: 
1.1.1.7   root      324: static int drive_writeprotected (drive * drv)
1.1       root      325: {
1.1.1.3   root      326:     return drv->wrprot || drv->diskfile == NULL;
1.1       root      327: }
                    328: 
1.1.1.7   root      329: static int drive_running (drive * drv)
1.1       root      330: {
1.1.1.3   root      331:     return !drv->motoroff;
1.1       root      332: }
                    333: 
1.1.1.7   root      334: static void drive_motor (drive * drv, int off)
1.1       root      335: {
1.1.1.12  root      336:     /* A value of 5 works out to a guaranteed delay of 1/2 of a second
1.1.1.10  root      337:        Higher values are dangerous, e.g. a value of 8 breaks the RSI
                    338:        demo.  */
1.1.1.11  root      339:     if (drv->motoroff && !off) {
1.1.1.12  root      340:        drv->dskready_time = 5;
1.1.1.11  root      341:        disk_data_used = 0;
                    342:        drv->drive_id_scnt = 0; /* Reset id shift reg counter */
                    343: #ifdef DEBUG_DRIVE_ID
                    344:        write_log("drive_motor: Selected DF%d: reset id shift reg.\n",drv-floppy);
                    345: #endif
                    346:     }
1.1       root      347:     drv->motoroff = off;
1.1.1.10  root      348:     if (drv->motoroff) {
                    349:        drv->dskready = 0;
                    350:        drv->dskready_time = 0;
                    351:     }
1.1       root      352: }
                    353: 
1.1.1.7   root      354: static void read_floppy_data (drive * drv, int track, int offset, unsigned char *dst, int len)
                    355: {
                    356:     trackid *ti;
                    357: 
                    358:     ti = &drv->trackdata[track];
                    359:     fseek (drv->diskfile, ti->offs + offset, SEEK_SET);
                    360:     fread (dst, 1, len, drv->diskfile);
                    361: }
                    362: 
                    363: /* Megalomania does not like zero MFM words... */
                    364: static void mfmcode (uae_u16 * mfm, int words)
                    365: {
1.1.1.8   root      366:     uae_u32 lastword = 0;
1.1.1.7   root      367: 
                    368:     while (words--) {
1.1.1.8   root      369:        uae_u32 v = *mfm;
                    370:        uae_u32 lv = (lastword << 16) | v;
                    371:        uae_u32 nlv = 0x55555555 & ~lv;
                    372:        uae_u32 mfmbits = (nlv << 1) & (nlv >> 1);
                    373: 
                    374:        *mfm++ = v | mfmbits;
                    375:        lastword = v;
1.1.1.7   root      376:     }
                    377: }
                    378: 
                    379: static void drive_fill_bigbuf (drive * drv)
1.1       root      380: {
1.1.1.7   root      381:     int tr = drv->cyl * 2 + side;
                    382:     trackid *ti = drv->trackdata + tr;
1.1.1.3   root      383: 
1.1.1.7   root      384:     if (!drv->diskfile || tr >= drv->num_tracks) {
1.1.1.11  root      385:        drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 2 * 8;
1.1.1.7   root      386:        drv->trackspeed = floppy_speed;
1.1.1.11  root      387:        memset (drv->bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN * 2 * drv->ddhd);
1.1.1.2   root      388:        return;
                    389:     }
1.1.1.3   root      390:     if (drv->buffered_cyl == drv->cyl && drv->buffered_side == side)
                    391:        return;
                    392: 
1.1.1.7   root      393:     if (ti->type == TRACK_AMIGADOS) {
1.1       root      394:        /* Normal AmigaDOS format track */
1.1.1.7   root      395:        int sec;
                    396:        drv->tracklen = (drv->num_secs * 544 + FLOPPY_GAP_LEN) * 2 * 8;
                    397:        memset (drv->bigmfmbuf, 0xaa, FLOPPY_GAP_LEN * 2);
1.1.1.2   root      398: 
                    399:        for (sec = 0; sec < drv->num_secs; sec++) {
1.1.1.3   root      400:            uae_u8 secbuf[544];
1.1       root      401:            int i;
1.1.1.7   root      402:            uae_u16 *mfmbuf = drv->bigmfmbuf + 544 * sec + FLOPPY_GAP_LEN;
                    403:            uae_u32 deven, dodd;
                    404:            uae_u32 hck = 0, dck = 0;
1.1.1.3   root      405: 
1.1       root      406:            secbuf[0] = secbuf[1] = 0x00;
                    407:            secbuf[2] = secbuf[3] = 0xa1;
                    408:            secbuf[4] = 0xff;
                    409:            secbuf[5] = tr;
                    410:            secbuf[6] = sec;
1.1.1.7   root      411:            secbuf[7] = drv->num_secs - sec;
1.1       root      412: 
1.1.1.7   root      413:            for (i = 8; i < 24; i++)
1.1       root      414:                secbuf[i] = 0;
1.1.1.3   root      415: 
1.1.1.7   root      416:            read_floppy_data (drv, tr, sec * 512, &secbuf[32], 512);
1.1.1.3   root      417: 
1.1       root      418:            mfmbuf[0] = mfmbuf[1] = 0xaaaa;
                    419:            mfmbuf[2] = mfmbuf[3] = 0x4489;
1.1.1.3   root      420: 
                    421:            deven = ((secbuf[4] << 24) | (secbuf[5] << 16)
1.1       root      422:                     | (secbuf[6] << 8) | (secbuf[7]));
                    423:            dodd = deven >> 1;
1.1.1.7   root      424:            deven &= 0x55555555;
                    425:            dodd &= 0x55555555;
1.1.1.3   root      426: 
1.1       root      427:            mfmbuf[4] = dodd >> 16;
                    428:            mfmbuf[5] = dodd;
1.1.1.7   root      429:            mfmbuf[6] = deven >> 16;
1.1       root      430:            mfmbuf[7] = deven;
1.1.1.3   root      431: 
1.1       root      432:            for (i = 8; i < 48; i++)
1.1.1.6   root      433:                mfmbuf[i] = 0xaaaa;
1.1.1.7   root      434:            for (i = 0; i < 512; i += 4) {
                    435:                deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16)
                    436:                         | (secbuf[i + 34] << 8) | (secbuf[i + 35]));
1.1       root      437:                dodd = deven >> 1;
1.1.1.7   root      438:                deven &= 0x55555555;
                    439:                dodd &= 0x55555555;
                    440:                mfmbuf[(i >> 1) + 32] = dodd >> 16;
                    441:                mfmbuf[(i >> 1) + 33] = dodd;
                    442:                mfmbuf[(i >> 1) + 256 + 32] = deven >> 16;
                    443:                mfmbuf[(i >> 1) + 256 + 33] = deven;
                    444:            }
                    445: 
                    446:            for (i = 4; i < 24; i += 2)
                    447:                hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
                    448: 
                    449:            deven = dodd = hck;
                    450:            dodd >>= 1;
                    451:            mfmbuf[24] = dodd >> 16;
                    452:            mfmbuf[25] = dodd;
                    453:            mfmbuf[26] = deven >> 16;
                    454:            mfmbuf[27] = deven;
                    455: 
                    456:            for (i = 32; i < 544; i += 2)
                    457:                dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
                    458: 
                    459:            deven = dodd = dck;
                    460:            dodd >>= 1;
                    461:            mfmbuf[28] = dodd >> 16;
                    462:            mfmbuf[29] = dodd;
                    463:            mfmbuf[30] = deven >> 16;
                    464:            mfmbuf[31] = deven;
                    465:            mfmcode (mfmbuf + 4, 544 - 4);
1.1       root      466:        }
1.1.1.7   root      467: #ifdef DISK_DEBUG
                    468:        write_log ("amigados read track %d\n", tr);
                    469: #endif
1.1       root      470:     } else {
                    471:        int i;
1.1.1.7   root      472:        int base_offset = ti->type == TRACK_RAW ? 0 : 1;
                    473:        drv->tracklen = ti->bitlen + 16 * base_offset;
                    474:        drv->bigmfmbuf[0] = ti->sync;
1.1.1.10  root      475:        read_floppy_data (drv, tr, 0, (char *) (drv->bigmfmbuf + base_offset), (ti->bitlen + 7) / 8);
                    476:        for (i = base_offset; i < (drv->tracklen + 15) / 16; i++) {
1.1.1.7   root      477:            uae_u16 *mfm = drv->bigmfmbuf + i;
                    478:            uae_u8 *data = (uae_u8 *) mfm;
                    479:            *mfm = 256 * *data + *(data + 1);
1.1       root      480:        }
1.1.1.7   root      481: #if 0 && defined DISK_DEBUG
                    482:        write_log ("rawtrack %d\n", tr);
                    483: #endif
1.1       root      484:     }
1.1.1.3   root      485:     drv->buffered_side = side;
                    486:     drv->buffered_cyl = drv->cyl;
1.1.1.7   root      487:     drv->trackspeed = floppy_speed * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN);
1.1       root      488: }
                    489: 
1.1.1.7   root      490: /* Update ADF_EXT2 track header */
                    491: static void diskfile_update (drive * drv, int len, uae_u8 type)
1.1       root      492: {
1.1.1.7   root      493:     trackid *ti;
                    494:     int track;
                    495:     uae_u8 buf[2 + 2 + 4 + 4], *zerobuf;
1.1.1.3   root      496: 
1.1.1.7   root      497:     if (drv->filetype != ADF_EXT2)
                    498:        return;
1.1.1.6   root      499: 
1.1.1.7   root      500:     track = drv->cyl * 2 + side;
                    501:     ti = &drv->trackdata[track];
                    502:     ti->bitlen = len;
                    503:     fseek (drv->diskfile, 8 + 4 + (2 + 2 + 4 + 4) * track, SEEK_SET);
                    504:     memset (buf, 0, sizeof buf);
                    505:     ti->type = type;
                    506:     buf[3] = ti->type;
                    507:     do_put_mem_long ((uae_u32 *) (buf + 4), ti->len);
                    508:     do_put_mem_long ((uae_u32 *) (buf + 8), ti->bitlen);
                    509:     fwrite (buf, sizeof (buf), 1, drv->diskfile);
                    510:     if (ti->len > (len + 7) / 8) {
                    511:        zerobuf = malloc (ti->len);
                    512:        memset (zerobuf, 0, ti->len);
                    513:        fseek (drv->diskfile, ti->offs, SEEK_SET);
                    514:        fwrite (zerobuf, 1, ti->len, drv->diskfile);
                    515:        free (zerobuf);
                    516:     }
                    517: #ifdef DISK_DEBUG
                    518:     write_log ("track %d, raw track length %d written (total size %d)\n", track, (ti->bitlen + 7) / 8, ti->len);
                    519: #endif
1.1       root      520: }
                    521: 
                    522: #define MFMMASK 0x55555555
1.1.1.7   root      523: static uae_u32 getmfmlong (uae_u16 * mbuf)
1.1       root      524: {
                    525:     return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
                    526: }
                    527: 
1.1.1.7   root      528: static int drive_write_adf_amigados (drive * drv)
1.1       root      529: {
                    530:     int i, secwritten = 0;
1.1.1.11  root      531:     int fwlen = FLOPPY_WRITE_LEN * drv->ddhd;
                    532:     int length = 2 * fwlen;
                    533:     int drvsec= drv->num_secs;
1.1.1.3   root      534:     uae_u32 odd, even, chksum, id, dlong;
1.1.1.7   root      535:     uae_u8 *secdata;
1.1.1.3   root      536:     uae_u8 secbuf[544];
1.1.1.7   root      537:     uae_u16 *mbuf = drv->bigmfmbuf;
1.1.1.3   root      538:     uae_u16 *mend = mbuf + length;
1.1.1.11  root      539:     char sectable[22];
1.1.1.7   root      540:     memset (sectable, 0, sizeof (sectable));
1.1.1.11  root      541:     memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16));
1.1       root      542:     mend -= (4 + 16 + 8 + 512);
1.1.1.11  root      543:     while (secwritten < drvsec) {
1.1       root      544:        int trackoffs;
1.1.1.3   root      545: 
1.1       root      546:        do {
                    547:            while (*mbuf++ != 0x4489) {
1.1.1.4   root      548:                if (mbuf >= mend)
1.1.1.7   root      549:                    return 1;
1.1       root      550:            }
                    551:        } while (*mbuf++ != 0x4489);
1.1.1.3   root      552: 
1.1.1.4   root      553:        odd = getmfmlong (mbuf);
                    554:        even = getmfmlong (mbuf + 2);
1.1.1.3   root      555:        mbuf += 4;
1.1       root      556:        id = (odd << 1) | even;
1.1.1.3   root      557: 
1.1       root      558:        trackoffs = (id & 0xff00) >> 8;
1.1.1.11  root      559:        if (trackoffs + 1 > drvsec) {
1.1.1.7   root      560:            if (drv->filetype == ADF_EXT2)
                    561:                return 2;
1.1.1.5   root      562:            write_log ("Disk write: weird sector number %d\n", trackoffs);
1.1       root      563:            continue;
                    564:        }
                    565:        chksum = odd ^ even;
1.1.1.4   root      566:        for (i = 0; i < 4; i++) {
1.1.1.7   root      567:            odd = getmfmlong (mbuf);
                    568:            even = getmfmlong (mbuf + 8);
1.1       root      569:            mbuf += 2;
1.1.1.3   root      570: 
1.1       root      571:            dlong = (odd << 1) | even;
1.1.1.7   root      572:            if (dlong) {
                    573:                if (drv->filetype == ADF_EXT2)
                    574:                    return 6;
1.1.1.4   root      575:                secwritten = -200;
1.1.1.7   root      576:            }
1.1       root      577:            chksum ^= odd ^ even;
1.1.1.7   root      578:        }                       /* could check here if the label is nonstandard */
1.1       root      579:        mbuf += 8;
1.1.1.7   root      580:        odd = getmfmlong (mbuf);
                    581:        even = getmfmlong (mbuf + 2);
                    582:        mbuf += 4;
                    583:        if (((odd << 1) | even) != chksum || ((id & 0x00ff0000) >> 16) != drv->cyl * 2 + side) {
                    584:            if (drv->filetype == ADF_EXT2)
                    585:                return 3;
                    586:            write_log ("Disk write: checksum error on sector %d header\n", trackoffs);
1.1       root      587:            continue;
                    588:        }
1.1.1.7   root      589:        odd = getmfmlong (mbuf);
                    590:        even = getmfmlong (mbuf + 2);
                    591:        mbuf += 4;
1.1       root      592:        chksum = (odd << 1) | even;
                    593:        secdata = secbuf + 32;
1.1.1.7   root      594:        for (i = 0; i < 128; i++) {
                    595:            odd = getmfmlong (mbuf);
                    596:            even = getmfmlong (mbuf + 256);
                    597:            mbuf += 2;
1.1       root      598:            dlong = (odd << 1) | even;
1.1.1.7   root      599:            *secdata++ = dlong >> 24;
                    600:            *secdata++ = dlong >> 16;
                    601:            *secdata++ = dlong >> 8;
                    602:            *secdata++ = dlong;
1.1       root      603:            chksum ^= odd ^ even;
                    604:        }
                    605:        mbuf += 256;
                    606:        if (chksum) {
1.1.1.7   root      607:            if (drv->filetype == ADF_EXT2)
                    608:                return 4;
                    609:            write_log ("Disk write: sector %d, data checksum error\n", trackoffs);
1.1       root      610:            continue;
                    611:        }
1.1.1.7   root      612:        sectable[trackoffs] = 1;
1.1       root      613:        secwritten++;
1.1.1.7   root      614:        memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512);
1.1       root      615:     }
1.1.1.7   root      616:     if (drv->filetype == ADF_EXT2 && (secwritten == 0 || secwritten < 0))
                    617:        return 5;
1.1.1.3   root      618:     if (secwritten == 0)
                    619:        write_log ("Disk write in unsupported format\n");
1.1       root      620:     if (secwritten < 0)
1.1.1.3   root      621:        write_log ("Disk write: sector labels ignored\n");
1.1.1.7   root      622: 
1.1.1.11  root      623:     diskfile_update (drv, drvsec * 512 * 8, TRACK_AMIGADOS);
                    624:     for (i = 0; i < drvsec; i++) {
1.1.1.7   root      625:        fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + side].offs + i * 512, SEEK_SET);
                    626:        fwrite (writebuffer + i * 512, sizeof (uae_u8), 512, drv->diskfile);
                    627:     }
                    628: 
                    629:     return 0;
1.1       root      630: }
                    631: 
1.1.1.7   root      632: /* write raw track to disk file */
                    633: static int drive_write_ext2 (drive * drv)
                    634: {
                    635:     trackid *ti;
                    636:     int len, track, i;
1.1       root      637: 
1.1.1.7   root      638:     track = drv->cyl * 2 + side;
                    639:     ti = &drv->trackdata[track];
                    640:     len = (drv->tracklen + 7) / 8;
                    641:     if (len > ti->len) {
                    642:        write_log ("disk raw write: image file's track %d is too small (%d < %d)!\n", track, ti->len, len);
                    643:        return 0;
                    644:     }
                    645:     diskfile_update (drv, drv->tracklen, TRACK_RAW);
                    646:     for (i = 0; i < drv->trackdata[track].len / 2; i++) {
                    647:        uae_u16 *mfm = drv->bigmfmbuf + i;
                    648:        uae_u8 *data = (uae_u8 *) mfm;
                    649:        *mfm = 256 * *data + *(data + 1);
                    650:     }
                    651:     fseek (drv->diskfile, ti->offs, SEEK_SET);
                    652:     fwrite (drv->bigmfmbuf, 1, len, drv->diskfile);
                    653:     return 1;
                    654: }
                    655: 
                    656: static void drive_write_data (drive * drv)
1.1       root      657: {
1.1.1.7   root      658:     int ret;
                    659:     if (drive_writeprotected (drv))
                    660:        return;
                    661:     switch (drv->filetype) {
                    662:     case ADF_NORMAL:
                    663:        drive_write_adf_amigados (drv);
                    664:        break;
                    665:     case ADF_EXT1:
                    666:        write_log ("writing to ADF_EXT1 not supported\n");
                    667:        return;
                    668:     case ADF_EXT2:
                    669:        ret = drive_write_adf_amigados (drv);
                    670:        if (ret) {
                    671:            /*write_log("not an amigados track (error %d), writing as raw track\n",ret); */
                    672:            drive_write_ext2 (drv);
                    673:        }
                    674:        break;
                    675:     }
                    676:     drv->buffered_side = 2;    /* will force read */
                    677: }
                    678: 
                    679: static void drive_eject (drive * drv)
                    680: {
                    681:     if (!drive_empty (drv))
1.1.1.4   root      682:        zfile_close (drv->diskfile);
1.1       root      683:     drv->diskfile = 0;
1.1.1.12  root      684:     drv->dskchange = 1;
1.1.1.11  root      685:     drive_settype_id(drv); /* Back to 35 DD */
1.1.1.12  root      686: #ifdef DISK_DEBUG
                    687:     write_log ("eject drive %d\n", drv - &floppy[0]);
                    688: #endif
1.1       root      689: }
                    690: 
1.1.1.3   root      691: /* We use this function if we have no Kickstart ROM.
1.1       root      692:  * No error checking - we trust our luck. */
1.1.1.3   root      693: void DISK_ersatz_read (int tr, int sec, uaecptr dest)
1.1       root      694: {
1.1.1.7   root      695:     uae_u8 *dptr = get_real_address (dest);
                    696:     fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec * 512, SEEK_SET);
1.1.1.3   root      697:     fread (dptr, 1, 512, floppy[0].diskfile);
1.1       root      698: }
                    699: 
1.1.1.4   root      700: void disk_eject (int num)
1.1       root      701: {
1.1.1.7   root      702:     gui_filename (num, "");
                    703:     drive_eject (floppy + num);
1.1.1.3   root      704:     *currprefs.df[num] = *changed_prefs.df[num] = 0;
1.1.1.12  root      705:     floppy[num].newname[0] = 0;
1.1       root      706: }
                    707: 
1.1.1.4   root      708: void disk_insert (int num, const char *name)
1.1       root      709: {
1.1.1.12  root      710:     drive *drv = floppy + num;
                    711:     if (name[0] == 0) {
                    712:        disk_eject (num);
                    713:     } else if (!drive_empty(drv) || drv->dskchange_time > 0) {
                    714:        drive_eject (drv);
                    715:        /* set dskchange_time, disk_insert() will be
                    716:         * called from DISK_check_change() after 1 second delay
                    717:         * this makes sure that all programs detect disk change correctly
                    718:         */
                    719:        strcpy (drv->newname, name);
                    720:        drv->dskchange_time = 10; /* 1 second disk change delay */
                    721:     } else {
                    722:        /* no delayed insert if drive is already empty */
                    723:        drive_insert (drv, num, name);
                    724:     }
1.1       root      725: }
                    726: 
1.1.1.3   root      727: void DISK_check_change (void)
                    728: {
                    729:     int i;
                    730: 
                    731:     for (i = 0; i < 4; i++) {
1.1.1.12  root      732:        drive *drv = floppy + i;
1.1.1.14  root      733:        gui_lock ();
1.1.1.12  root      734:        if (strcmp (currprefs.df[i], changed_prefs.df[i])) {
                    735:            strcpy (currprefs.df[i], changed_prefs.df[i]);
                    736:            disk_insert (i, currprefs.df[i]);
                    737:        }
1.1.1.14  root      738:        gui_unlock ();
1.1.1.12  root      739:        /* emulate drive motor turn on time */
                    740:        if (drv->dskready_time) {
                    741:            drv->dskready_time--;
                    742:            if (drv->dskready_time == 0)
                    743:                drv->dskready = 1;
                    744:        }
                    745:        /* delay until new disk image is inserted */
                    746:        if (drv->dskchange_time) {
                    747:            drv->dskchange_time--;
                    748:            if (drv->dskchange_time == 0) {
                    749:                drive_insert (drv, i, drv->newname);
                    750: #ifdef DISK_DEBUG
                    751:                write_log ("delayed insert, drive %d, image '%s'\n", i, drv->newname);
                    752: #endif
                    753:                drv->newname[0] = 0;
1.1.1.3   root      754:            }
                    755:        }
                    756:     }
                    757: }
                    758: 
1.1.1.4   root      759: int disk_empty (int num)
1.1       root      760: {
1.1.1.4   root      761:     return drive_empty (floppy + num);
1.1       root      762: }
                    763: 
1.1.1.11  root      764: static int step;
1.1.1.10  root      765: 
1.1.1.4   root      766: void DISK_select (uae_u8 data)
1.1       root      767: {
1.1.1.11  root      768:     int step_pulse, lastselected;
1.1       root      769:     int dr;
1.1.1.11  root      770:     static uae_u8 prevdata;
1.1.1.3   root      771: 
1.1.1.10  root      772:     lastselected = selected;
1.1       root      773:     selected = (data >> 3) & 15;
1.1.1.12  root      774:     selected |= disabled;
                    775:     if (selected != lastselected)
                    776:        disk_data_used = 1;
1.1.1.3   root      777:     side = 1 - ((data >> 2) & 1);
                    778: 
1.1       root      779:     direction = (data >> 1) & 1;
                    780:     step_pulse = data & 1;
                    781:     if (step != step_pulse) {
                    782:        step = step_pulse;
1.1.1.11  root      783:        if (step) {
1.1.1.7   root      784:            for (dr = 0; dr < 4; dr++) {
1.1       root      785:                if (!(selected & (1 << dr))) {
1.1.1.4   root      786:                    drive_step (floppy + dr);
1.1       root      787:                }
                    788:            }
                    789:        }
                    790:     }
1.1.1.7   root      791:     for (dr = 0; dr < 4; dr++) {
1.1.1.11  root      792:        /* motor on/off workings tested with small assembler code on real Amiga 1200. */
1.1.1.18  root      793:        /* motor flipflop is set only when drive select goes from high to low */
1.1.1.11  root      794:        if (!(selected & (1 << dr)) && (lastselected & (1 << dr)) ) {
                    795:            if (floppy[dr].motoroff) {
1.1.1.12  root      796:                /* motor off: if motor bit = 0 in prevdata or data -> turn motor on */
1.1.1.11  root      797:                if ((prevdata & 0x80) == 0 || (data & 0x80) == 0)
                    798:                    drive_motor (floppy + dr, 0);
                    799:            } else {
                    800:                /* motor on: if motor bit = 1 in prevdata only (motor flag state in data has no effect)
                    801:                   -> turn motor off */
                    802:                if (prevdata & 0x80)
                    803:                    drive_motor (floppy + dr, 1);
                    804:            }
1.1       root      805:        }
                    806:     }
                    807:     for (dr = 0; dr < 4; dr++) {
1.1.1.7   root      808:        floppy[dr].state = (!(selected & (1 << dr))) | !floppy[dr].motoroff;
1.1.1.8   root      809:        update_drive_gui (dr);
1.1       root      810:     }
1.1.1.11  root      811:     prevdata = data;
1.1       root      812: }
                    813: 
1.1.1.4   root      814: uae_u8 DISK_status (void)
1.1       root      815: {
1.1.1.3   root      816:     uae_u8 st = 0x3c;
1.1       root      817:     int dr;
1.1.1.3   root      818: 
1.1.1.7   root      819:     for (dr = 0; dr < 4; dr++) {
1.1.1.3   root      820:        drive *drv = floppy + dr;
1.1       root      821:        if (!(selected & (1 << dr))) {
1.1.1.7   root      822:            if (drive_running (drv)) {
1.1.1.11  root      823:                if (drv->dskready)
1.1.1.7   root      824:                    st &= ~0x20;
1.1.1.12  root      825:            } else {
1.1.1.11  root      826:                /* report drive ID */
                    827:                if (drv->drive_id & (1L << (31 - drv->drive_id_scnt)))
                    828:                    st |= 0x20;
                    829:                else
                    830:                    st &= ~0x20;
1.1.1.18  root      831: #ifdef DEBUG_DRIVE_ID
1.1.1.11  root      832:                write_log("DISK_status: sel %d id %s [0x%08lx, bit #%02d: %d]\n",
                    833:                    dr,drive_id_name(drv), drv->drive_id << drv->drive_id_scnt, 31 - drv->drive_id_scnt, st & 0x20 ? 1:0);
1.1.1.12  root      834: #endif
1.1.1.11  root      835:                /* Left shift id reg bit should be done with each LH transition of drv_sel */
                    836:                drv->drive_id_scnt++;
                    837:                drv->drive_id_scnt &= 31;
1.1       root      838:            }
1.1.1.12  root      839:            if (drive_track0 (drv))
1.1.1.7   root      840:                st &= ~0x10;
1.1.1.12  root      841:            if (drive_writeprotected (drv))
1.1.1.7   root      842:                st &= ~8;
1.1.1.12  root      843:            if (drv->dskchange)
                    844:                st &= ~4;
1.1.1.18  root      845:        }
1.1       root      846:     }
                    847:     return st;
                    848: }
                    849: 
1.1.1.7   root      850: #define MAX_DISK_WORDS_PER_LINE 50     /* depends on floppy_speed */
                    851: 
                    852: #define DISK_INDEXSYNC 1
                    853: #define DISK_WORDSYNC 2
                    854: 
                    855: static uae_u16 dskbytr_tab[MAX_DISK_WORDS_PER_LINE * 2 + 1];
                    856: static uae_u8 dskbytr_cycle[MAX_DISK_WORDS_PER_LINE * 2 + 1];
1.1.1.11  root      857: static short wordsync_cycle[MAX_DISK_WORDS_PER_LINE * 2 + 1];
1.1.1.7   root      858: static uae_u32 dma_tab[MAX_DISK_WORDS_PER_LINE + 1];
                    859: static uae_u8 disk_sync[MAXHPOS];
                    860: static int disk_sync_cycle;
                    861: static int dskdmaen, dsklength;
                    862: static uae_u16 dsksync;
                    863: static uae_u32 dskpt;
                    864: 
                    865: static void disk_dmafinished (void)
                    866: {
                    867:     INTREQ (0x8002);
1.1.1.15  root      868:     dskdmaen = 0; /* ??? */
1.1.1.11  root      869: #ifdef DISK_DEBUG
1.1.1.12  root      870:     write_log("disk dma finished %08.8X\n", dskpt);
1.1.1.11  root      871: #endif
1.1.1.18  root      872: }
1.1.1.7   root      873: 
                    874: static void disk_events (int last)
                    875: {
                    876:     eventtab[ev_disk].active = 0;
1.1.1.11  root      877:     for (disk_sync_cycle = last; disk_sync_cycle < maxhpos; disk_sync_cycle++) {
1.1.1.7   root      878:        if (disk_sync[disk_sync_cycle]) {
1.1.1.10  root      879:            eventtab[ev_disk].oldcycles = get_cycles ();
                    880:            eventtab[ev_disk].evtime = get_cycles () + (disk_sync_cycle - last) * CYCLE_UNIT;
1.1.1.7   root      881:            eventtab[ev_disk].active = 1;
                    882:            events_schedule ();
                    883:            return;
1.1       root      884:        }
                    885:     }
                    886: }
                    887: 
1.1.1.7   root      888: extern void cia_diskindex (void);
1.1.1.3   root      889: 
1.1.1.7   root      890: void DISK_handler (void)
                    891: {
                    892:     eventtab[ev_disk].active = 0;
1.1.1.11  root      893:     if (disk_sync[disk_sync_cycle] & DISK_WORDSYNC)
1.1.1.7   root      894:        INTREQ (0x9000);
1.1.1.11  root      895:     if (disk_sync[disk_sync_cycle] & DISK_INDEXSYNC)
1.1.1.7   root      896:        cia_diskindex ();
                    897:     disk_sync[disk_sync_cycle] = 0;
                    898:     disk_events (disk_sync_cycle);
                    899: }
1.1.1.3   root      900: 
1.1.1.12  root      901: static int dma_enable, bitoffset;
                    902: static uae_u32 word;
1.1       root      903: 
1.1.1.7   root      904: /* Always carried through to the next line.  */
                    905: static int disk_hpos;
1.1.1.2   root      906: 
1.1.1.7   root      907: /* emulate disk write dma for full horizontal line */
                    908: static void disk_doupdate_write (drive * drv)
                    909: {
                    910:     int hpos = disk_hpos;
1.1.1.11  root      911:     while (hpos < (maxhpos << 8)) {
1.1.1.7   root      912:        drv->mfmpos++;
                    913:        drv->mfmpos %= drv->tracklen;
                    914:        if (!drv->mfmpos) {
                    915:            disk_sync[hpos >> 8] |= DISK_INDEXSYNC;
                    916:            disk_events (0);
                    917:        }
                    918:        if ((dmacon & 0x210) == 0x210 && dskdmaen == 3) {
                    919:            bitoffset++;
                    920:            bitoffset &= 15;
                    921:            if (!bitoffset) {
                    922:                drv->bigmfmbuf[drv->mfmpos >> 4] = get_word (dskpt);
                    923:                dskpt += 2;
                    924:                dsklength--;
                    925:                if (dsklength == 0) {
                    926:                    disk_dmafinished ();
                    927:                    drive_write_data (drv);
                    928:                }
1.1       root      929:            }
                    930:        }
1.1.1.7   root      931:        hpos += drv->trackspeed;
1.1       root      932:     }
1.1.1.11  root      933:     disk_hpos = hpos - (maxhpos << 8);
1.1       root      934: }
                    935: 
1.1.1.7   root      936: /* get one bit from MFM bit stream */
1.1.1.12  root      937: static uae_u32 getonebit (uae_u16 * mfmbuf, int mfmpos, uae_u32 word)
1.1       root      938: {
1.1.1.7   root      939:     uae_u16 *buf;
1.1       root      940: 
1.1.1.7   root      941:     buf = &mfmbuf[mfmpos >> 4];
                    942:     word <<= 1;
                    943:     word |= (buf[0] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0;
                    944:     return word;
1.1       root      945: }
                    946: 
1.1.1.11  root      947: #define WORDSYNC_CYCLES 7 /* (~7 * 280ns = 2us) */
                    948: 
1.1.1.7   root      949: /* emulate disk read dma for full horizontal line */
                    950: static void disk_doupdate_read (drive * drv)
                    951: {
                    952:     int hpos = disk_hpos;
1.1.1.12  root      953:     int is_sync = 0;
1.1.1.11  root      954:     int j = 0, k = 1, l = 0;
1.1.1.12  root      955:     uae_u16 synccheck;
1.1.1.11  root      956:     static int dskbytr_last = 0, wordsync_last = -1;
1.1.1.7   root      957: 
1.1.1.11  root      958:     dskbytr_tab[0] = dskbytr_tab[dskbytr_last];
                    959: 
                    960:     if (wordsync_last >= 0 && maxhpos - wordsync_cycle[wordsync_last] < WORDSYNC_CYCLES)
                    961:        wordsync_cycle[l++] = (maxhpos - wordsync_cycle[wordsync_last]) - WORDSYNC_CYCLES;
                    962:     wordsync_last = -1;
                    963: 
                    964:     while (hpos < (maxhpos << 8)) {
                    965:        if (drv->dskready)
                    966:            word = getonebit (drv->bigmfmbuf, drv->mfmpos, word);
                    967:        else
                    968:            word <<= 1;
1.1.1.7   root      969:        drv->mfmpos++;
                    970:        drv->mfmpos %= drv->tracklen;
1.1.1.12  root      971:        if (!drv->mfmpos) {
1.1.1.7   root      972:            disk_sync[hpos >> 8] |= DISK_INDEXSYNC;
                    973:            is_sync = 1;
                    974:        }
1.1.1.12  root      975:        if (bitoffset == 31 && dma_enable) {
                    976:            dma_tab[j++] = (word >> 16) & 0xffff;
1.1.1.7   root      977:            if (j == MAX_DISK_WORDS_PER_LINE - 1) {
                    978:                write_log ("Bug: Disk DMA buffer overflow!\n");
                    979:                j--;
                    980:            }
                    981:        }
1.1.1.12  root      982:        if (bitoffset == 15 || bitoffset == 23 || bitoffset == 31) {
                    983:            dskbytr_tab[k] = (word >> 8) & 0xff;
1.1.1.11  root      984:            dskbytr_tab[k] |= 0x8000;
                    985:            dskbytr_last = k;
1.1.1.7   root      986:            dskbytr_cycle[k++] = hpos >> 8;
                    987:        }
1.1.1.12  root      988:        synccheck = (word >> 8) & 0xffff;
                    989:        if (synccheck == dsksync) {
                    990:            if (adkcon & 0x400) {
                    991:                if (bitoffset != 23 || !dma_enable)
                    992:                    bitoffset = 7;
                    993:                dma_enable = 1;
                    994:            }
                    995:            wordsync_last = l;
                    996:            wordsync_cycle[l++] = hpos >> 8;
                    997:            disk_sync[hpos >> 8] |= DISK_WORDSYNC;
                    998:            is_sync = 1;
                    999:        }
1.1.1.11  root     1000:        bitoffset++;
1.1.1.12  root     1001:        if (bitoffset == 32) bitoffset = 16;
1.1.1.7   root     1002:        hpos += drv->trackspeed;
                   1003:     }
                   1004:     dma_tab[j] = 0xffffffff;
1.1.1.11  root     1005:     dskbytr_cycle[k] = 255;
                   1006:     wordsync_cycle[l] = 255;
1.1.1.7   root     1007:     if (is_sync)
                   1008:        disk_events (0);
                   1009: 
1.1.1.11  root     1010:     disk_hpos = hpos - (maxhpos << 8);
1.1.1.7   root     1011: }
                   1012: 
                   1013: /* disk DMA fetch happens on real Amiga at the beginning of next horizontal line
                   1014:    (cycles 9, 11 and 13 according to hardware manual) We transfer all DMA'd
                   1015:    data at cycle 0. I don't think any program cares about this small difference.
1.1.1.12  root     1016: 
                   1017:    We must handle dsklength = 0 because some copy protections use it to detect
                   1018:    wordsync without transferring any data.
1.1.1.7   root     1019: */
                   1020: static void dodmafetch (void)
1.1       root     1021: {
1.1.1.7   root     1022:     int i;
                   1023: 
                   1024:     i = 0;
                   1025:     while (dma_tab[i] != 0xffffffff && dskdmaen == 2 && (dmacon & 0x210) == 0x210) {
1.1.1.12  root     1026:        if (dsklength > 0) {
                   1027:            put_word (dskpt, dma_tab[i++]);
                   1028:            dskpt += 2;
                   1029:            dsklength--;
                   1030:        }
1.1.1.7   root     1031:        if (dsklength == 0) {
                   1032:            disk_dmafinished ();
                   1033:            break;
                   1034:        }
                   1035:     }
                   1036:     dma_tab[0] = 0xffffffff;
1.1       root     1037: }
                   1038: 
1.1.1.17  root     1039: /* this is very unoptimized. DSKBYTR is used very rarely, so it should not matter. */
                   1040: 
                   1041: uae_u16 DSKBYTR (int hpos)
                   1042: {
                   1043:     uae_u16 v;
                   1044:     int i;
                   1045: 
                   1046:     i = 0;
                   1047:     while (hpos > dskbytr_cycle[i + 1])
                   1048:        i++;
                   1049:     v = dskbytr_tab[i];
                   1050:     dskbytr_tab[i] &= ~0x8000;
                   1051:     if (wordsync_cycle[0] != 255) {
                   1052:        i = 0;
                   1053:        while (hpos < wordsync_cycle[i])
                   1054:            i++;
                   1055:        if (hpos - wordsync_cycle[i] <= WORDSYNC_CYCLES)
                   1056:            v |= 0x1000;
                   1057:     }
                   1058:     if (dskdmaen && (dmacon & 0x210) == 0x210)
                   1059:        v |= 0x4000;
                   1060:     if (dskdmaen == 3)
                   1061:        v |= 0x2000;
                   1062: 
                   1063:     disk_data_used = 0;
                   1064: 
                   1065:     return v;
                   1066: }
                   1067: 
1.1.1.7   root     1068: static void DISK_start (void)
1.1.1.6   root     1069: {
                   1070:     int dr;
1.1.1.7   root     1071: 
1.1.1.6   root     1072:     for (dr = 0; dr < 4; dr++) {
1.1.1.7   root     1073:        drive *drv = &floppy[dr];
                   1074:        if (!(selected & (1 << dr))) {
                   1075:            int tr = drv->cyl * 2 + side;
                   1076:            trackid *ti = drv->trackdata + tr;
                   1077: 
                   1078:            if (dskdmaen == 3) {
1.1.1.11  root     1079:                drv->tracklen = FLOPPY_WRITE_LEN * drv->ddhd * 8 * 2;
1.1.1.7   root     1080:                drv->trackspeed = floppy_speed;
                   1081:            }
                   1082:            /* Ugh.  A nasty hack.  Assume ADF_EXT1 tracks are always read
                   1083:               from the start.  */
                   1084:            if (ti->type == TRACK_RAW1)
1.1.1.12  root     1085:                drv->mfmpos = 0;
1.1.1.6   root     1086:        }
                   1087:     }
1.1.1.12  root     1088:     dma_enable = (adkcon & 0x400) ? 0 : 1;
1.1.1.7   root     1089:     word = 0;
                   1090:     bitoffset = 0;
                   1091:     dma_tab[0] = 0xffffffff;
1.1.1.6   root     1092: }
                   1093: 
1.1.1.7   root     1094: static int linecounter;
                   1095: 
                   1096: void DISK_update (void)
1.1       root     1097: {
                   1098:     int dr;
1.1.1.18  root     1099: 
1.1.1.6   root     1100:     for (dr = 0; dr < 4; dr++) {
1.1.1.7   root     1101:        drive *drv = &floppy[dr];
1.1.1.11  root     1102:        if (drv->steplimit)
                   1103:            drv->steplimit--;
1.1.1.7   root     1104:     }
                   1105:     if (linecounter) {
                   1106:        linecounter--;
                   1107:        if (! linecounter)
                   1108:            disk_dmafinished ();
                   1109:        return;
                   1110:     }
                   1111: 
                   1112:     dodmafetch ();
                   1113: 
                   1114:     for (dr = 0; dr < 4; dr++) {
                   1115:        drive *drv = &floppy[dr];
                   1116:        if (drv->motoroff)
                   1117:            continue;
                   1118:        if (selected & (1 << dr)) {
1.1.1.11  root     1119:            drv->mfmpos += (maxhpos << 8) / drv->trackspeed;
1.1.1.7   root     1120:            drv->mfmpos %= drv->tracklen;
                   1121:            continue;
1.1       root     1122:        }
1.1.1.11  root     1123:        drive_fill_bigbuf (drv);
                   1124:        drv->mfmpos %= drv->tracklen;
                   1125:        if (dskdmaen > 1)
                   1126:            disk_data_used = 0;
                   1127: 
1.1.1.7   root     1128:        if (dskdmaen == 3)
                   1129:            disk_doupdate_write (drv);
1.1.1.12  root     1130:        else if (1 || disk_data_used < MAXVPOS * 50 * 2) {
1.1.1.11  root     1131:            disk_data_used++;
1.1.1.7   root     1132:            disk_doupdate_read (drv);
1.1.1.11  root     1133:        }
1.1.1.7   root     1134:        return;
1.1       root     1135:     }
                   1136: }
1.1.1.6   root     1137: 
1.1.1.7   root     1138: void DSKLEN (uae_u16 v, int hpos)
1.1.1.6   root     1139: {
1.1.1.7   root     1140:     if (v & 0x8000) {
                   1141:        dskdmaen = dskdmaen == 1 ? 2 : 1;
                   1142:     } else {
                   1143:        /* Megalomania does this */
                   1144: #if 0
                   1145:        if (dskdmaen == 2)
                   1146:            write_log ("warning: Disk read DMA aborted, %d words left\n", dsklength);
                   1147: #endif
                   1148:        if (dskdmaen == 3)
                   1149:            write_log ("warning: Disk write DMA aborted, %d words left\n", dsklength);
                   1150:        dskdmaen = 0;
                   1151:     }
1.1.1.12  root     1152:     dsklength = v & 0x3ffe;
1.1.1.7   root     1153:     if (dskdmaen <= 1)
                   1154:        return;
                   1155:     if (v & 0x4000)
                   1156:        dskdmaen = 3;
                   1157: #ifdef DISK_DEBUG
                   1158:     {
                   1159:        int dr;
                   1160:        for (dr = 0; dr < 4; dr++) {
                   1161:            drive *drv = &floppy[dr];
                   1162:            if (drv->motoroff)
                   1163:                continue;
                   1164:            if ((selected & (1 << dr)) == 0)
                   1165:                break;
                   1166:        }
                   1167:        if (dr == 4)
                   1168:            write_log ("disk DMA started, but no drive ready!\n");
                   1169:        else
                   1170:            write_log ("disk %s DMA started for %d words (%08.8X) sync=%04.4X track %d\n",
                   1171:                       dskdmaen == 3 ? "write" : "read", dsklength, dskpt,
                   1172:                       (adkcon & 0x400) ? dsksync : 0xffff,
                   1173:                       floppy[dr].cyl * 2 + side);
                   1174:     }
                   1175: #endif
                   1176:     /* Megalomania does not work if DSKLEN write is delayed to next horizontal line,
                   1177:        also it seems some copy protections require this fix */
                   1178:     DISK_start ();
1.1.1.6   root     1179: 
1.1.1.7   root     1180:     /* Try to make floppy access from Kickstart faster.  */
                   1181:     if (dskdmaen != 2)
                   1182:        return;
                   1183:     {
                   1184:        int dr;
                   1185:        uaecptr pc = m68k_getpc ();
                   1186:        if ((pc & 0xF80000) != 0xF80000)
                   1187:            return;
                   1188:        for (dr = 0; dr < 4; dr++) {
                   1189:            drive *drv = &floppy[dr];
                   1190:            if (drv->motoroff)
                   1191:                continue;
                   1192:            if ((selected & (1 << dr)) == 0) {
                   1193:                int pos = drv->mfmpos & ~15;
                   1194:                int i;
                   1195: 
1.1.1.11  root     1196:                drive_fill_bigbuf (drv);
1.1.1.7   root     1197:                if (adkcon & 0x400) {
                   1198:                    for (i = 0; i < drv->tracklen; i += 16) {
                   1199:                        pos += 16;
                   1200:                        pos %= drv->tracklen;
1.1.1.11  root     1201:                        if (drv->bigmfmbuf[pos >> 4] == dsksync) {
                   1202:                            /* must skip first disk sync marker */
1.1.1.12  root     1203:                            pos += 16;
1.1.1.11  root     1204:                            pos %= drv->tracklen;
1.1.1.7   root     1205:                            break;
1.1.1.11  root     1206:                        }
1.1.1.7   root     1207:                    }
                   1208:                    if (i >= drv->tracklen)
                   1209:                        return;
                   1210:                }
                   1211:                while (dsklength-- > 0) {
                   1212:                    put_word (dskpt, drv->bigmfmbuf[pos >> 4]);
                   1213:                    dskpt += 2;
                   1214:                    pos += 16;
                   1215:                    pos %= drv->tracklen;
1.1.1.6   root     1216:                }
1.1.1.7   root     1217:                INTREQ (0x9000);
                   1218:                linecounter = 2;
                   1219:                dskdmaen = 0;
                   1220:                return;
1.1.1.6   root     1221:            }
                   1222:        }
1.1.1.7   root     1223:     }
1.1.1.6   root     1224: }
                   1225: 
1.1.1.11  root     1226: /* not a real hardware register */
1.1.1.7   root     1227: uae_u16 DSKDATR (int hpos)
                   1228: {
1.1.1.11  root     1229:     return 0;
1.1.1.7   root     1230: }
                   1231: 
                   1232: void DSKSYNC (uae_u16 v)
                   1233: {
                   1234:     dsksync = v;
                   1235: }
                   1236: 
                   1237: void DSKDAT (uae_u16 v)
                   1238: {
                   1239:     static int count = 0;
                   1240:     if (count < 5) {
                   1241:        count++;
                   1242:        write_log ("DSKDAT written. Not good.");
                   1243:        if (count == 5)
                   1244:            write_log ("(further messages suppressed)");
                   1245: 
                   1246:        write_log ("\n");
1.1.1.6   root     1247:     }
                   1248: }
1.1.1.7   root     1249: void DSKPTH (uae_u16 v)
                   1250: {
                   1251:     dskpt = (dskpt & 0xffff) | ((uae_u32) v << 16);
                   1252: }
1.1.1.6   root     1253: 
1.1.1.7   root     1254: void DSKPTL (uae_u16 v)
1.1.1.6   root     1255: {
1.1.1.7   root     1256:     dskpt = (dskpt & ~0xffff) | (v);
1.1.1.6   root     1257: }
                   1258: 
1.1.1.7   root     1259: void DISK_init (void)
                   1260: {
1.1.1.11  root     1261:     int dr;
1.1.1.7   root     1262: 
                   1263:     dma_tab[0] = 0xffffffff;
1.1.1.11  root     1264:     dskbytr_cycle[0] = 0;
                   1265:     dskbytr_cycle[1] = 255;
                   1266:     wordsync_cycle[0] = 255;
1.1.1.7   root     1267: 
1.1.1.11  root     1268:     for (dr = 0; dr < 4; dr++) {
                   1269:        drive *drv = &floppy[dr];
1.1.1.12  root     1270:        /* reset all drive types to 3.5 DD */
1.1.1.11  root     1271:        drive_settype_id (drv);
                   1272:        if (!drive_insert (drv, dr, currprefs.df[dr]))
                   1273:            disk_eject (dr);
1.1.1.8   root     1274:     }
1.1.1.7   root     1275:     if (disk_empty (0))
                   1276:        write_log ("No disk in drive 0.\n");
                   1277: }
                   1278: 
1.1.1.8   root     1279: void DISK_reset (void)
                   1280: {
                   1281:     int i;
1.1.1.13  root     1282: 
                   1283:     if (savestate_state)
                   1284:        return;
                   1285: 
1.1.1.8   root     1286:     disk_hpos = 0;
1.1.1.11  root     1287:     disk_data_used = 0;
1.1.1.12  root     1288:     disabled = 0;
1.1.1.8   root     1289:     for (i = 0; i < 4; i++) {
1.1.1.12  root     1290:        if (i >= currprefs.nr_floppies) {
                   1291:            disabled |= 1 << i;
                   1292:            floppy[i].motoroff = 1;
                   1293:        }
1.1.1.8   root     1294:     }
                   1295: }
                   1296: 
1.1.1.7   root     1297: void dumpdisk (void)
                   1298: {
                   1299:     int i;
                   1300:     for (i = 0; i < 4; i++) {
                   1301:        drive *drv = &floppy[i];
                   1302:        printf ("Drive %d: motor %s cylinder %2d selected %d\n", i, drv->motoroff ? "off" : " on", drv->cyl, selected & (1 << i));
                   1303:     }
                   1304: }
1.1.1.11  root     1305: 
                   1306: /* Disk save/restore code */
                   1307: 
                   1308: void DISK_save_custom (uae_u32 *pdskpt, uae_u16 *pdsklength, uae_u16 *pdsksync, uae_u16 *pdskdatr, uae_u16 *pdskbytr)
                   1309: {
                   1310:     if(pdskpt) *pdskpt = dskpt;
                   1311:     if(pdsklength) *pdsklength = dsklength;
                   1312:     if(pdsksync) *pdsksync = dsksync;
                   1313:     if(pdskdatr) *pdskdatr = 0;
                   1314:     if(pdskbytr) *pdskbytr = dskbytr_tab[0];
                   1315: }
                   1316: 
                   1317: void DISK_restore_custom (uae_u32 pdskpt, uae_u16 pdsklength, uae_u16 pdskdatr, uae_u16 pdskbytr)
                   1318: {
                   1319:     dskpt = pdskpt;
                   1320:     dsklength = pdsklength;
                   1321:     dskbytr_tab[0] = pdskbytr;
                   1322: }
                   1323: 
1.1.1.19! root     1324: const uae_u8 *restore_disk (int num, const uae_u8 *src)
1.1.1.11  root     1325: {
                   1326:     drive *drv;
1.1.1.13  root     1327:     int state;
1.1.1.11  root     1328: 
                   1329:     drv = &floppy[num];
1.1.1.13  root     1330:     disabled &= ~(1 << num);
1.1.1.11  root     1331:     drv->drive_id = restore_u32 ();
1.1.1.13  root     1332:     state = restore_u8 ();
                   1333:     if (state & 2)
                   1334:        disabled |= 1 << num;
                   1335:     else
                   1336:        drv->motoroff = (state & 1) ? 0 : 1;
1.1.1.11  root     1337:     drv->cyl = restore_u8 ();
                   1338:     drv->dskready = restore_u8 ();
                   1339:     drv->drive_id_scnt = restore_u8 ();
                   1340:     drv->mfmpos = restore_u32 ();
                   1341:     restore_u32 ();
1.1.1.16  root     1342:     strncpy(changed_prefs.df[num],src,255);
                   1343:     changed_prefs.df[num][255] = 0;
                   1344:     src += strlen(src) + 1;
1.1.1.11  root     1345: 
                   1346:     return src;
                   1347: }
                   1348: 
1.1.1.19! root     1349: uae_u8 *save_disk (int num, int *len, uae_u8 *dstptr)
1.1.1.11  root     1350: {
                   1351:     uae_u8 *dstbak,*dst;
                   1352:     drive *drv;
                   1353: 
                   1354:     drv = &floppy[num];
1.1.1.18  root     1355:     if (dstptr)
                   1356:        dstbak = dst = dstptr;
                   1357:     else
                   1358:        dstbak = dst = malloc (2+1+1+1+1+4+4+256);
1.1.1.11  root     1359:     save_u32 (drv->drive_id);      /* drive type ID */
1.1.1.13  root     1360:     save_u8 ((drv->motoroff ? 0:1) | ((disabled & (1 << num)) ? 2 : 0));  /* state */
1.1.1.11  root     1361:     save_u8 (drv->cyl);                    /* cylinder */
                   1362:     save_u8 (drv->dskready);       /* dskready */
                   1363:     save_u8 (drv->drive_id_scnt);   /* id mode position */
                   1364:     save_u32 (drv->mfmpos);        /* disk position */
                   1365:     save_u32 (0);                  /* CRC of disk image */
                   1366:     strcpy (dst, currprefs.df[num]);/* image name */
                   1367:     dst += strlen(dst) + 1;
                   1368: 
                   1369:     *len = dst - dstbak;
                   1370:     return dstbak;
                   1371: }
                   1372: 
                   1373: /* internal floppy controller variables */
                   1374: 
1.1.1.19! root     1375: const uae_u8 *restore_floppy (const uae_u8 *src)
1.1.1.11  root     1376: {
                   1377:     word = restore_u16();
                   1378:     bitoffset = restore_u8();
1.1.1.12  root     1379:     dma_enable = restore_u8();
1.1.1.11  root     1380:     disk_hpos = restore_u8();
                   1381:     dskdmaen = restore_u8();
1.1.1.12  root     1382:     word |= restore_u16() << 16;
1.1.1.11  root     1383: 
                   1384:     return src;
                   1385: }
                   1386: 
1.1.1.19! root     1387: uae_u8 *save_floppy (int *len, uae_u8 *dstptr)
1.1.1.11  root     1388: {
                   1389:     uae_u8 *dstbak, *dst;
                   1390: 
                   1391:     /* flush dma buffer before saving */
                   1392:     dodmafetch();
                   1393: 
1.1.1.18  root     1394:     if (dstptr)
                   1395:        dstbak = dst = dstptr;
                   1396:     else
                   1397:        dstbak = dst = malloc(2+1+1+1+1+2);
1.1.1.12  root     1398:     save_u16 (word);           /* current fifo (low word) */
1.1.1.11  root     1399:     save_u8 (bitoffset);       /* dma bit offset */
1.1.1.12  root     1400:     save_u8 (dma_enable);      /* disk sync found */
1.1.1.11  root     1401:     save_u8 (disk_hpos);       /* next bit read position */
                   1402:     save_u8 (dskdmaen);                /* dma status */
1.1.1.12  root     1403:     save_u16 (word >> 16);     /* current fifo (high word) */
1.1.1.11  root     1404: 
                   1405:     *len = dst - dstbak;
                   1406:     return dstbak;
                   1407: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.