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

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

unix.superglobalmegacorp.com

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