|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.