|
|
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.4 root 6: * Copyright 1995 Bernd Schmidt, Hannu Rummukainen
1.1 root 7: */
8:
1.1.1.2 root 9: #include <stdio.h>
10:
1.1 root 11: #include "sysconfig.h"
12: #include "sysdeps.h"
13:
14: #include "config.h"
15: #include "options.h"
1.1.1.3 root 16: #include "threaddep/penguin.h"
1.1 root 17: #include "memory.h"
18: #include "events.h"
19: #include "custom.h"
20: #include "ersatz.h"
21: #include "disk.h"
22: #include "gui.h"
23: #include "zfile.h"
1.1.1.2 root 24: #include "autoconf.h"
25: #include "readcpu.h"
26: #include "newcpu.h"
27: #include "xwin.h"
28: #include "osemu.h"
29: #include "execlib.h"
30:
1.1.1.3 root 31: #define FLOPPY_GAP_LEN 360
1.1.1.7 root 32: /* writable track length with normal 2us bitcell/300RPM motor */
33: #define FLOPPY_WRITE_LEN 6250
34: /* (cycles/bitcell) << 8, normal = ((2us/280ns)<<8) = ~1830 */
35: #define NORMAL_FLOPPY_SPEED 1830
36:
37: static int floppy_speed = NORMAL_FLOPPY_SPEED;
38:
39: #undef DISK_DEBUG
40:
41: /* UAE-1ADF (ADF_EXT2)
42: * W reserved
43: * W number of tracks (default 2*80=160)
44: *
45: * W reserved
46: * W type, 0=normal AmigaDOS track, 1 = raw MFM
47: * L available space for track in bytes
48: * L track length in bits
49: */
1.1 root 50:
1.1.1.7 root 51: static int side, direction, step, writing;
1.1.1.3 root 52: static uae_u8 selected = 15;
1.1 root 53: static int dskready;
54:
1.1.1.7 root 55: static uae_u8 *writebuffer[544 * 11];
56:
57: typedef enum { TRACK_AMIGADOS, TRACK_RAW, TRACK_RAW1 } image_tracktype;
1.1 root 58: typedef struct {
1.1.1.3 root 59: uae_u16 len;
60: uae_u32 offs;
1.1.1.7 root 61: int bitlen;
62: unsigned int sync;
63: image_tracktype type;
1.1 root 64: } trackid;
65:
1.1.1.2 root 66: #define MAX_TRACKS 328
67:
1.1.1.7 root 68: typedef enum { ADF_NORMAL, ADF_EXT1, ADF_EXT2 } drive_filetype;
1.1 root 69: typedef struct {
70: FILE *diskfile;
71: drive_filetype filetype;
1.1.1.2 root 72: trackid trackdata[MAX_TRACKS];
1.1.1.7 root 73: int buffered_cyl, buffered_side;
74: int cyl;
1.1 root 75: int motoroff;
1.1.1.7 root 76: int state;
77: int disabled;
1.1 root 78: int wrprot;
1.1.1.3 root 79: uae_u16 bigmfmbuf[0x4000];
1.1 root 80: int mfmpos;
1.1.1.7 root 81: int mfmpos_hsync;
82: int tracklen;
83: int trackspeed;
84: int dmalen;
85: int num_tracks, num_secs;
1.1.1.3 root 86: /* dskchange is set to a small number when a disk is removed. At a step
87: * impulse, it is reset if there is a new disk in the drive or counted
88: * down to 1 if the drive contains a disk. DISK_check_change will only
89: * insert a new disk when dskchange is 1, or if the dskchange_time timer
90: * expires. The last condition can happen if AmigaOS isn't running and a
91: * game/demo doesn't use the step motor to check for a new disk.
92: */
93: int dskchange;
94: int dskchange_time;
1.1 root 95: } drive;
96:
97: drive floppy[4];
98:
1.1.1.7 root 99: /* code for track display */
1.1.1.8 ! root 100: static void update_drive_gui (int num)
1.1.1.7 root 101: {
1.1.1.8 ! root 102: drive *drv = floppy + num;
! 103:
1.1.1.7 root 104: if (drv->state == gui_data.drive_motor[num]
105: && drv->cyl == gui_data.drive_track[num]
106: && ((writing && gui_data.drive_writing[num])
107: || (!writing && !gui_data.drive_writing[num]))) {
108: return;
109: }
110: gui_data.drive_motor[num] = drv->state;
111: gui_data.drive_track[num] = drv->cyl;
112: if (!gui_data.drive_writing[num])
113: gui_data.drive_writing[num] = writing;
1.1.1.8 ! root 114: gui_ledstate &= ~(2 << num);
! 115: if (drv->state)
! 116: gui_ledstate |= 2 << num;
1.1.1.7 root 117: gui_led (num + 1, gui_data.drive_motor[num]);
118: }
119:
120: static void drive_fill_bigbuf (drive * drv);
1.1 root 121:
1.1.1.3 root 122: FILE *DISK_validate_filename (const char *fname, int leave_open, int *wrprot)
1.1 root 123: {
1.1.1.4 root 124: FILE *f = zfile_open (fname, "r+b");
1.1.1.3 root 125: if (f) {
126: if (wrprot)
127: *wrprot = 0;
1.1 root 128: } else {
1.1.1.3 root 129: if (wrprot)
130: *wrprot = 1;
1.1.1.4 root 131: f = zfile_open (fname, "rb");
1.1 root 132: }
1.1.1.3 root 133: if (!leave_open)
1.1.1.4 root 134: zfile_close (f);
1.1.1.3 root 135: return f;
136: }
137:
1.1.1.7 root 138: static int drive_insert (drive * drv, int dnum, const char *fname)
1.1.1.3 root 139: {
1.1.1.7 root 140: unsigned char buffer[2 + 2 + 4 + 4];
141: trackid *tid;
1.1.1.3 root 142:
143: drv->diskfile = DISK_validate_filename (fname, 1, &drv->wrprot);
1.1.1.6 root 144: if (drv->diskfile == 0) {
1.1.1.7 root 145: drv->tracklen = FLOPPY_WRITE_LEN * 2 * 8;
146: drv->trackspeed = floppy_speed;
1.1.1.3 root 147: return 0;
1.1.1.6 root 148: }
1.1.1.3 root 149: strncpy (currprefs.df[dnum], fname, 255);
150: currprefs.df[dnum][255] = 0;
151: strncpy (changed_prefs.df[dnum], fname, 255);
152: changed_prefs.df[dnum][255] = 0;
1.1.1.7 root 153: gui_filename (dnum, fname);
1.1.1.3 root 154:
1.1.1.7 root 155: fread (buffer, sizeof (char), 8, drv->diskfile);
156: if (strncmp ((char *) buffer, "UAE-1ADF", 8) == 0) {
157: int offs;
158: int i;
159:
160: fread (buffer, 1, 4, drv->diskfile);
161: drv->num_tracks = buffer[2] * 256 + buffer[3];
162: drv->filetype = ADF_EXT2;
163: drv->num_secs = 11;
164: offs = 8 + drv->num_tracks * (2 + 2 + 4 + 4);
165:
166: for (i = 0; i < drv->num_tracks; i++) {
167: tid = &drv->trackdata[i];
168: fread (buffer, 2 + 2 + 4 + 4, 1, drv->diskfile);
169: tid->type = buffer[2] * 256 + buffer[3];
170: tid->len = buffer[5] * 65536 + buffer[6] * 256 + buffer[7];
171: tid->bitlen = buffer[9] * 65536 + buffer[10] * 256 + buffer[11];
172: tid->offs = offs;
173: if (tid->type == TRACK_AMIGADOS) {
174: if (tid->len > 20000)
175: drv->num_secs = 22;
176: }
177: offs += tid->len;
178: }
179: } else if (strncmp ((char *) buffer, "UAE--ADF", 8) == 0) {
180: int offs = 160 * 4 + 8;
1.1 root 181: int i;
1.1.1.3 root 182:
183: drv->filetype = ADF_EXT1;
1.1.1.2 root 184: drv->num_tracks = 160;
185: drv->num_secs = 11;
1.1.1.3 root 186:
1.1.1.7 root 187: drv->wrprot = 1; /* write to adf_ext1 not implemented */
188: for (i = 0; i < 160; i++) {
189: tid = &drv->trackdata[i];
190: fread (buffer, 4, 1, drv->diskfile);
191: tid->sync = buffer[0] * 256 + buffer[1];
192: tid->len = buffer[2] * 256 + buffer[3];
193: tid->offs = offs;
194: if (tid->sync == 0) {
195: tid->type = TRACK_AMIGADOS;
196: tid->bitlen = 0;
197: } else {
198: tid->type = TRACK_RAW1;
199: tid->bitlen = tid->len * 8;
200: }
201: offs += tid->len;
1.1 root 202: }
203: } else {
1.1.1.7 root 204: int i;
1.1.1.3 root 205:
206: drv->filetype = ADF_NORMAL;
1.1.1.2 root 207:
1.1.1.7 root 208: fseek (drv->diskfile, 0, SEEK_END);
1.1.1.4 root 209: i = ftell (drv->diskfile);
1.1.1.7 root 210: fseek (drv->diskfile, 0, SEEK_SET);
1.1.1.3 root 211:
1.1.1.2 root 212: /* High-density disk? */
1.1.1.7 root 213: if (i >= 160 * 22 * 512)
214: drv->num_tracks = i / (512 * (drv->num_secs = 22));
1.1.1.2 root 215: else
1.1.1.7 root 216: drv->num_tracks = i / (512 * (drv->num_secs = 11));
1.1.1.3 root 217:
1.1.1.2 root 218: if (drv->num_tracks > MAX_TRACKS)
1.1.1.3 root 219: write_log ("Your diskfile is too big!\n");
1.1.1.7 root 220: for (i = 0; i < drv->num_tracks; i++) {
221: tid = &drv->trackdata[i];
222: tid->type = TRACK_AMIGADOS;
223: tid->len = 512 * drv->num_secs;
224: tid->bitlen = 0;
225: tid->offs = i * 512 * drv->num_secs;
1.1 root 226: }
227: }
1.1.1.7 root 228: drv->buffered_side = 2; /* will force read */
1.1.1.6 root 229: drive_fill_bigbuf (drv);
1.1.1.3 root 230: return 1;
1.1 root 231: }
232:
1.1.1.7 root 233: static int drive_empty (drive * drv)
1.1.1.2 root 234: {
1.1.1.3 root 235: return drv->diskfile == 0;
1.1.1.2 root 236: }
237:
1.1.1.7 root 238: static void drive_step (drive * drv)
1.1 root 239: {
1.1.1.7 root 240: if (!drive_empty (drv))
1.1.1.3 root 241: drv->dskchange = 0;
242: else if (drv->dskchange > 1) {
243: /* printf("Stepping...\n");
244: drv->dskchange--;*/
245: }
1.1 root 246: if (direction) {
1.1.1.7 root 247: if (drv->cyl)
248: drv->cyl--;
1.1 root 249: } else {
1.1.1.7 root 250: if (drv->cyl < 83)
251: drv->cyl++;
1.1 root 252: }
253:
1.1.1.7 root 254: #if 0 && defined DISK_DEBUG
255: write_log ("track %d\n", drv->cyl);
256: #endif
257: }
1.1 root 258:
1.1.1.7 root 259: static int drive_track0 (drive * drv)
1.1 root 260: {
1.1.1.3 root 261: return drv->cyl == 0;
1.1 root 262: }
263:
1.1.1.7 root 264: static int drive_writeprotected (drive * drv)
1.1 root 265: {
1.1.1.3 root 266: return drv->wrprot || drv->diskfile == NULL;
1.1 root 267: }
268:
1.1.1.7 root 269: static int drive_running (drive * drv)
1.1 root 270: {
1.1.1.3 root 271: return !drv->motoroff;
1.1 root 272: }
273:
1.1.1.7 root 274: static void drive_motor (drive * drv, int off)
1.1 root 275: {
276: drv->motoroff = off;
277: }
278:
1.1.1.7 root 279: static void read_floppy_data (drive * drv, int track, int offset, unsigned char *dst, int len)
280: {
281: trackid *ti;
282:
283: ti = &drv->trackdata[track];
284: fseek (drv->diskfile, ti->offs + offset, SEEK_SET);
285: fread (dst, 1, len, drv->diskfile);
286: }
287:
288: /* Megalomania does not like zero MFM words... */
289: static void mfmcode (uae_u16 * mfm, int words)
290: {
1.1.1.8 ! root 291: uae_u32 lastword = 0;
1.1.1.7 root 292:
293: while (words--) {
1.1.1.8 ! root 294: uae_u32 v = *mfm;
! 295: uae_u32 lv = (lastword << 16) | v;
! 296: uae_u32 nlv = 0x55555555 & ~lv;
! 297: uae_u32 mfmbits = (nlv << 1) & (nlv >> 1);
! 298:
! 299: *mfm++ = v | mfmbits;
! 300: lastword = v;
1.1.1.7 root 301: }
302: }
303:
304: static void drive_fill_bigbuf (drive * drv)
1.1 root 305: {
1.1.1.7 root 306: int tr = drv->cyl * 2 + side;
307: trackid *ti = drv->trackdata + tr;
1.1.1.3 root 308:
1.1.1.7 root 309: if (!drv->diskfile || tr >= drv->num_tracks) {
310: drv->tracklen = FLOPPY_WRITE_LEN * 2 * 8;
311: drv->trackspeed = floppy_speed;
312: memset (drv->bigmfmbuf, 0xaa, FLOPPY_WRITE_LEN * 2);
1.1.1.2 root 313: return;
314: }
1.1.1.3 root 315: if (drv->buffered_cyl == drv->cyl && drv->buffered_side == side)
316: return;
317:
1.1.1.7 root 318: if (ti->type == TRACK_AMIGADOS) {
1.1 root 319: /* Normal AmigaDOS format track */
1.1.1.7 root 320: int sec;
321: drv->tracklen = (drv->num_secs * 544 + FLOPPY_GAP_LEN) * 2 * 8;
322: memset (drv->bigmfmbuf, 0xaa, FLOPPY_GAP_LEN * 2);
1.1.1.2 root 323:
324: for (sec = 0; sec < drv->num_secs; sec++) {
1.1.1.3 root 325: uae_u8 secbuf[544];
1.1 root 326: int i;
1.1.1.7 root 327: uae_u16 *mfmbuf = drv->bigmfmbuf + 544 * sec + FLOPPY_GAP_LEN;
328: uae_u32 deven, dodd;
329: uae_u32 hck = 0, dck = 0;
1.1.1.3 root 330:
1.1 root 331: secbuf[0] = secbuf[1] = 0x00;
332: secbuf[2] = secbuf[3] = 0xa1;
333: secbuf[4] = 0xff;
334: secbuf[5] = tr;
335: secbuf[6] = sec;
1.1.1.7 root 336: secbuf[7] = drv->num_secs - sec;
1.1 root 337:
1.1.1.7 root 338: for (i = 8; i < 24; i++)
1.1 root 339: secbuf[i] = 0;
1.1.1.3 root 340:
1.1.1.7 root 341: read_floppy_data (drv, tr, sec * 512, &secbuf[32], 512);
1.1.1.3 root 342:
1.1 root 343: mfmbuf[0] = mfmbuf[1] = 0xaaaa;
344: mfmbuf[2] = mfmbuf[3] = 0x4489;
1.1.1.3 root 345:
346: deven = ((secbuf[4] << 24) | (secbuf[5] << 16)
1.1 root 347: | (secbuf[6] << 8) | (secbuf[7]));
348: dodd = deven >> 1;
1.1.1.7 root 349: deven &= 0x55555555;
350: dodd &= 0x55555555;
1.1.1.3 root 351:
1.1 root 352: mfmbuf[4] = dodd >> 16;
353: mfmbuf[5] = dodd;
1.1.1.7 root 354: mfmbuf[6] = deven >> 16;
1.1 root 355: mfmbuf[7] = deven;
1.1.1.3 root 356:
1.1 root 357: for (i = 8; i < 48; i++)
1.1.1.6 root 358: mfmbuf[i] = 0xaaaa;
1.1.1.7 root 359: for (i = 0; i < 512; i += 4) {
360: deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16)
361: | (secbuf[i + 34] << 8) | (secbuf[i + 35]));
1.1 root 362: dodd = deven >> 1;
1.1.1.7 root 363: deven &= 0x55555555;
364: dodd &= 0x55555555;
365: mfmbuf[(i >> 1) + 32] = dodd >> 16;
366: mfmbuf[(i >> 1) + 33] = dodd;
367: mfmbuf[(i >> 1) + 256 + 32] = deven >> 16;
368: mfmbuf[(i >> 1) + 256 + 33] = deven;
369: }
370:
371: for (i = 4; i < 24; i += 2)
372: hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
373:
374: deven = dodd = hck;
375: dodd >>= 1;
376: mfmbuf[24] = dodd >> 16;
377: mfmbuf[25] = dodd;
378: mfmbuf[26] = deven >> 16;
379: mfmbuf[27] = deven;
380:
381: for (i = 32; i < 544; i += 2)
382: dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
383:
384: deven = dodd = dck;
385: dodd >>= 1;
386: mfmbuf[28] = dodd >> 16;
387: mfmbuf[29] = dodd;
388: mfmbuf[30] = deven >> 16;
389: mfmbuf[31] = deven;
390: mfmcode (mfmbuf + 4, 544 - 4);
1.1 root 391: }
1.1.1.7 root 392: #ifdef DISK_DEBUG
393: write_log ("amigados read track %d\n", tr);
394: #endif
1.1 root 395: } else {
396: int i;
1.1.1.7 root 397: int base_offset = ti->type == TRACK_RAW ? 0 : 1;
398: drv->tracklen = ti->bitlen + 16 * base_offset;
399: read_floppy_data (drv, tr, 0, (char *) (drv->bigmfmbuf + base_offset), (ti->bitlen + 7) / 8);
400: drv->bigmfmbuf[0] = ti->sync;
401: for (i = base_offset; i < drv->tracklen / 16; i++) {
402: uae_u16 *mfm = drv->bigmfmbuf + i;
403: uae_u8 *data = (uae_u8 *) mfm;
404: *mfm = 256 * *data + *(data + 1);
1.1 root 405: }
1.1.1.7 root 406: #if 0 && defined DISK_DEBUG
407: write_log ("rawtrack %d\n", tr);
408: #endif
1.1 root 409: }
1.1.1.3 root 410: drv->buffered_side = side;
411: drv->buffered_cyl = drv->cyl;
1.1.1.7 root 412: drv->trackspeed = floppy_speed * drv->tracklen / (2 * 8 * FLOPPY_WRITE_LEN);
1.1 root 413: }
414:
1.1.1.7 root 415: /* Update ADF_EXT2 track header */
416: static void diskfile_update (drive * drv, int len, uae_u8 type)
1.1 root 417: {
1.1.1.7 root 418: trackid *ti;
419: int track;
420: uae_u8 buf[2 + 2 + 4 + 4], *zerobuf;
1.1.1.3 root 421:
1.1.1.7 root 422: if (drv->filetype != ADF_EXT2)
423: return;
1.1.1.6 root 424:
1.1.1.7 root 425: track = drv->cyl * 2 + side;
426: ti = &drv->trackdata[track];
427: ti->bitlen = len;
428: fseek (drv->diskfile, 8 + 4 + (2 + 2 + 4 + 4) * track, SEEK_SET);
429: memset (buf, 0, sizeof buf);
430: ti->type = type;
431: buf[3] = ti->type;
432: do_put_mem_long ((uae_u32 *) (buf + 4), ti->len);
433: do_put_mem_long ((uae_u32 *) (buf + 8), ti->bitlen);
434: fwrite (buf, sizeof (buf), 1, drv->diskfile);
435: if (ti->len > (len + 7) / 8) {
436: zerobuf = malloc (ti->len);
437: memset (zerobuf, 0, ti->len);
438: fseek (drv->diskfile, ti->offs, SEEK_SET);
439: fwrite (zerobuf, 1, ti->len, drv->diskfile);
440: free (zerobuf);
441: }
442: #ifdef DISK_DEBUG
443: write_log ("track %d, raw track length %d written (total size %d)\n", track, (ti->bitlen + 7) / 8, ti->len);
444: #endif
1.1 root 445: }
446:
447: #define MFMMASK 0x55555555
1.1.1.7 root 448: static uae_u32 getmfmlong (uae_u16 * mbuf)
1.1 root 449: {
450: return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
451: }
452:
1.1.1.7 root 453: static int drive_write_adf_amigados (drive * drv)
1.1 root 454: {
455: int i, secwritten = 0;
1.1.1.7 root 456: int length = 2 * FLOPPY_WRITE_LEN;
1.1.1.3 root 457: uae_u32 odd, even, chksum, id, dlong;
1.1.1.7 root 458: uae_u8 *secdata;
1.1.1.3 root 459: uae_u8 secbuf[544];
1.1.1.7 root 460: uae_u16 *mbuf = drv->bigmfmbuf;
1.1.1.3 root 461: uae_u16 *mend = mbuf + length;
1.1.1.7 root 462: char sectable[11];
1.1.1.3 root 463:
1.1.1.7 root 464: memset (sectable, 0, sizeof (sectable));
465: memcpy (mbuf + FLOPPY_WRITE_LEN, mbuf, FLOPPY_WRITE_LEN * sizeof (uae_u16));
1.1 root 466: mend -= (4 + 16 + 8 + 512);
1.1.1.7 root 467: while (secwritten < 11) {
1.1 root 468: int trackoffs;
1.1.1.3 root 469:
1.1 root 470: do {
471: while (*mbuf++ != 0x4489) {
1.1.1.4 root 472: if (mbuf >= mend)
1.1.1.7 root 473: return 1;
1.1 root 474: }
475: } while (*mbuf++ != 0x4489);
1.1.1.3 root 476:
1.1.1.4 root 477: odd = getmfmlong (mbuf);
478: even = getmfmlong (mbuf + 2);
1.1.1.3 root 479: mbuf += 4;
1.1 root 480: id = (odd << 1) | even;
1.1.1.3 root 481:
1.1 root 482: trackoffs = (id & 0xff00) >> 8;
483: if (trackoffs > 10) {
1.1.1.7 root 484: if (drv->filetype == ADF_EXT2)
485: return 2;
1.1.1.5 root 486: write_log ("Disk write: weird sector number %d\n", trackoffs);
1.1 root 487: continue;
488: }
489: chksum = odd ^ even;
1.1.1.4 root 490: for (i = 0; i < 4; i++) {
1.1.1.7 root 491: odd = getmfmlong (mbuf);
492: even = getmfmlong (mbuf + 8);
1.1 root 493: mbuf += 2;
1.1.1.3 root 494:
1.1 root 495: dlong = (odd << 1) | even;
1.1.1.7 root 496: if (dlong) {
497: if (drv->filetype == ADF_EXT2)
498: return 6;
1.1.1.4 root 499: secwritten = -200;
1.1.1.7 root 500: }
1.1 root 501: chksum ^= odd ^ even;
1.1.1.7 root 502: } /* could check here if the label is nonstandard */
1.1 root 503: mbuf += 8;
1.1.1.7 root 504: odd = getmfmlong (mbuf);
505: even = getmfmlong (mbuf + 2);
506: mbuf += 4;
507: if (((odd << 1) | even) != chksum || ((id & 0x00ff0000) >> 16) != drv->cyl * 2 + side) {
508: if (drv->filetype == ADF_EXT2)
509: return 3;
510: write_log ("Disk write: checksum error on sector %d header\n", trackoffs);
1.1 root 511: continue;
512: }
1.1.1.7 root 513: odd = getmfmlong (mbuf);
514: even = getmfmlong (mbuf + 2);
515: mbuf += 4;
1.1 root 516: chksum = (odd << 1) | even;
517: secdata = secbuf + 32;
1.1.1.7 root 518: for (i = 0; i < 128; i++) {
519: odd = getmfmlong (mbuf);
520: even = getmfmlong (mbuf + 256);
521: mbuf += 2;
1.1 root 522: dlong = (odd << 1) | even;
1.1.1.7 root 523: *secdata++ = dlong >> 24;
524: *secdata++ = dlong >> 16;
525: *secdata++ = dlong >> 8;
526: *secdata++ = dlong;
1.1 root 527: chksum ^= odd ^ even;
528: }
529: mbuf += 256;
530: if (chksum) {
1.1.1.7 root 531: if (drv->filetype == ADF_EXT2)
532: return 4;
533: write_log ("Disk write: sector %d, data checksum error\n", trackoffs);
1.1 root 534: continue;
535: }
1.1.1.7 root 536: sectable[trackoffs] = 1;
1.1 root 537: secwritten++;
1.1.1.7 root 538: memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512);
1.1 root 539: }
1.1.1.7 root 540: if (drv->filetype == ADF_EXT2 && (secwritten == 0 || secwritten < 0))
541: return 5;
1.1.1.3 root 542: if (secwritten == 0)
543: write_log ("Disk write in unsupported format\n");
1.1 root 544: if (secwritten < 0)
1.1.1.3 root 545: write_log ("Disk write: sector labels ignored\n");
1.1.1.7 root 546:
547: diskfile_update (drv, 11 * 512 * 8, TRACK_AMIGADOS);
548: for (i = 0; i < 11; i++) {
549: fseek (drv->diskfile, drv->trackdata[drv->cyl * 2 + side].offs + i * 512, SEEK_SET);
550: fwrite (writebuffer + i * 512, sizeof (uae_u8), 512, drv->diskfile);
551: }
552:
553: return 0;
1.1 root 554: }
555:
1.1.1.7 root 556: /* write raw track to disk file */
557: static int drive_write_ext2 (drive * drv)
558: {
559: trackid *ti;
560: int len, track, i;
1.1 root 561:
1.1.1.7 root 562: track = drv->cyl * 2 + side;
563: ti = &drv->trackdata[track];
564: len = (drv->tracklen + 7) / 8;
565: if (len > ti->len) {
566: write_log ("disk raw write: image file's track %d is too small (%d < %d)!\n", track, ti->len, len);
567: return 0;
568: }
569: diskfile_update (drv, drv->tracklen, TRACK_RAW);
570: for (i = 0; i < drv->trackdata[track].len / 2; i++) {
571: uae_u16 *mfm = drv->bigmfmbuf + i;
572: uae_u8 *data = (uae_u8 *) mfm;
573: *mfm = 256 * *data + *(data + 1);
574: }
575: fseek (drv->diskfile, ti->offs, SEEK_SET);
576: fwrite (drv->bigmfmbuf, 1, len, drv->diskfile);
577: return 1;
578: }
579:
580: static void drive_write_data (drive * drv)
1.1 root 581: {
1.1.1.7 root 582: int ret;
583: if (drive_writeprotected (drv))
584: return;
585: switch (drv->filetype) {
586: case ADF_NORMAL:
587: drive_write_adf_amigados (drv);
588: break;
589: case ADF_EXT1:
590: write_log ("writing to ADF_EXT1 not supported\n");
591: return;
592: case ADF_EXT2:
593: ret = drive_write_adf_amigados (drv);
594: if (ret) {
595: /*write_log("not an amigados track (error %d), writing as raw track\n",ret); */
596: drive_write_ext2 (drv);
597: }
598: break;
599: }
600: drv->buffered_side = 2; /* will force read */
601: }
602:
603: static void drive_eject (drive * drv)
604: {
605: if (!drive_empty (drv))
1.1.1.4 root 606: zfile_close (drv->diskfile);
1.1.1.3 root 607:
608: drv->dskchange = 4;
609: drv->dskchange_time = 20;
610: /* printf("setting changed bit %d\n", drv-floppy);*/
1.1 root 611: drv->diskfile = 0;
612: }
613:
1.1.1.3 root 614: /* We use this function if we have no Kickstart ROM.
1.1 root 615: * No error checking - we trust our luck. */
1.1.1.3 root 616: void DISK_ersatz_read (int tr, int sec, uaecptr dest)
1.1 root 617: {
1.1.1.7 root 618: uae_u8 *dptr = get_real_address (dest);
619: fseek (floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec * 512, SEEK_SET);
1.1.1.3 root 620: fread (dptr, 1, 512, floppy[0].diskfile);
1.1 root 621: }
622:
1.1.1.4 root 623: void disk_eject (int num)
1.1 root 624: {
1.1.1.7 root 625: gui_filename (num, "");
626: drive_eject (floppy + num);
1.1.1.3 root 627: *currprefs.df[num] = *changed_prefs.df[num] = 0;
1.1 root 628: }
629:
1.1.1.4 root 630: void disk_insert (int num, const char *name)
1.1 root 631: {
632: /* just to be sure */
1.1.1.4 root 633: drive_eject (floppy + num);
634: drive_insert (floppy + num, num, name);
1.1 root 635: }
636:
1.1.1.3 root 637: void DISK_check_change (void)
638: {
639: int i;
640: static int count = 0;
641: count++;
642:
643: for (i = 0; i < 4; i++) {
644: if (strcmp (currprefs.df[i], changed_prefs.df[i]) != 0) {
645: if (currprefs.df[i][0] != '\0') {
1.1.1.7 root 646: drive_eject (floppy + i);
1.1.1.3 root 647: currprefs.df[i][0] = '\0';
1.1.1.7 root 648: gui_filename (i, "");
1.1.1.3 root 649: } else if (floppy[i].dskchange == 1) {
650: /* In theory, it should work without the dskchange test.
651: * In practice, it doesn't. */
652: drive_insert (floppy + i, i, changed_prefs.df[i]);
653: } else if (floppy[i].dskchange > 1 && floppy[i].dskchange_time > 0) {
654: /* Force the dskchange bit to go to 1 after a given timeout */
655: if (--floppy[i].dskchange_time == 0) {
656: floppy[i].dskchange = 1;
657: }
658: }
659: }
660: }
661: }
662:
1.1.1.4 root 663: int disk_empty (int num)
1.1 root 664: {
1.1.1.4 root 665: return drive_empty (floppy + num);
1.1 root 666: }
667:
1.1.1.4 root 668: void DISK_select (uae_u8 data)
1.1 root 669: {
670: int step_pulse;
671: int dr;
1.1.1.3 root 672:
673: if (selected != ((data >> 3) & 15))
1.1 root 674: dskready = 0;
675: selected = (data >> 3) & 15;
1.1.1.3 root 676: side = 1 - ((data >> 2) & 1);
677:
1.1 root 678: direction = (data >> 1) & 1;
679: step_pulse = data & 1;
680: if (step != step_pulse) {
681: step = step_pulse;
1.1.1.7 root 682: if (step == 0) {
683: for (dr = 0; dr < 4; dr++) {
1.1 root 684: if (!(selected & (1 << dr))) {
1.1.1.4 root 685: drive_step (floppy + dr);
1.1 root 686: }
687: }
688: }
689: }
1.1.1.7 root 690: for (dr = 0; dr < 4; dr++) {
691: if (!(selected & (1 << dr))) {
692: drive_motor (floppy + dr, data >> 7);
1.1 root 693: }
694: }
695: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 696: floppy[dr].state = (!(selected & (1 << dr))) | !floppy[dr].motoroff;
1.1.1.8 ! root 697: update_drive_gui (dr);
1.1 root 698: }
699: }
700:
1.1.1.4 root 701: uae_u8 DISK_status (void)
1.1 root 702: {
1.1.1.3 root 703: uae_u8 st = 0x3c;
1.1 root 704: int dr;
1.1.1.3 root 705:
1.1.1.7 root 706: for (dr = 0; dr < 4; dr++) {
1.1.1.3 root 707: drive *drv = floppy + dr;
1.1 root 708: if (!(selected & (1 << dr))) {
1.1.1.7 root 709: if (drive_running (drv)) {
710: if (dskready)
711: st &= ~0x20;
1.1 root 712: dskready = 1;
1.1.1.7 root 713: } else if (!drv->disabled) {
714: st &= ~0x20; /* report drive ID */
1.1 root 715: }
1.1.1.3 root 716:
1.1.1.7 root 717: if (drive_track0 (drv)) {
718: st &= ~0x10;
719: }
720: if (drive_writeprotected (drv)) {
721: st &= ~8;
722: }
1.1.1.3 root 723: if (drv->dskchange) {
724: /*printf("changed bit set: %d\n",dr); */
725: st &= ~0x4;
726: if (drv->dskchange > 1)
727: drv->dskchange--;
728: }
1.1 root 729: }
730: }
731: return st;
732: }
733:
1.1.1.7 root 734: #define MAX_DISK_WORDS_PER_LINE 50 /* depends on floppy_speed */
735:
736: #define DISK_INDEXSYNC 1
737: #define DISK_WORDSYNC 2
738:
739: static uae_u16 dskbytr_tab[MAX_DISK_WORDS_PER_LINE * 2 + 1];
740: static uae_u8 dskbytr_cycle[MAX_DISK_WORDS_PER_LINE * 2 + 1];
741: static uae_u16 dskdatr_tab[MAX_DISK_WORDS_PER_LINE + 1];
742: static uae_u8 dskdatr_cycle[MAX_DISK_WORDS_PER_LINE + 1];
743: static uae_u32 dma_tab[MAX_DISK_WORDS_PER_LINE + 1];
744: static uae_u8 disk_sync[MAXHPOS];
745: static int disk_sync_cycle;
746: static int indexsync_last_cycle;
747: static int dskdmaen, dsklength;
748: static uae_u16 dsksync;
749: static uae_u32 dskpt;
750:
751: static void disk_dmafinished (void)
752: {
753: INTREQ (0x8002);
754: dskdmaen = 0;
755: }
756:
757: static void disk_events (int last)
758: {
759: eventtab[ev_disk].active = 0;
760: for (disk_sync_cycle = last; disk_sync_cycle < MAXHPOS; disk_sync_cycle++) {
761: if (disk_sync[disk_sync_cycle]) {
762: eventtab[ev_disk].oldcycles = cycles;
763: eventtab[ev_disk].evtime = cycles + (disk_sync_cycle - last);
764: eventtab[ev_disk].active = 1;
765: events_schedule ();
766: return;
1.1 root 767: }
768: }
769: }
770:
1.1.1.7 root 771: extern void cia_diskindex (void);
1.1.1.3 root 772:
1.1.1.7 root 773: void DISK_handler (void)
774: {
775: eventtab[ev_disk].active = 0;
776: if (disk_sync[disk_sync_cycle] & DISK_WORDSYNC) {
777: INTREQ (0x9000);
778: indexsync_last_cycle = disk_sync_cycle + ((floppy_speed + 255) >> 8);
779: }
780: if (disk_sync[disk_sync_cycle] & DISK_INDEXSYNC) {
781: cia_diskindex ();
782: }
783: disk_sync[disk_sync_cycle] = 0;
784: disk_events (disk_sync_cycle);
785: }
1.1.1.3 root 786:
1.1.1.7 root 787: static int syncfound, dmaon, word, bitoffset;
1.1 root 788:
1.1.1.7 root 789: /* Always carried through to the next line. */
790: static int disk_hpos;
1.1.1.2 root 791:
1.1.1.7 root 792: /* emulate disk write dma for full horizontal line */
793: static void disk_doupdate_write (drive * drv)
794: {
795: int hpos = disk_hpos;
796: while (hpos < (MAXHPOS << 8)) {
797: drv->mfmpos++;
798: drv->mfmpos %= drv->tracklen;
799: if (!drv->mfmpos) {
800: disk_sync[hpos >> 8] |= DISK_INDEXSYNC;
801: disk_events (0);
802: }
803: if ((dmacon & 0x210) == 0x210 && dskdmaen == 3) {
804: bitoffset++;
805: bitoffset &= 15;
806: if (!bitoffset) {
807: drv->bigmfmbuf[drv->mfmpos >> 4] = get_word (dskpt);
808: dskpt += 2;
809: dsklength--;
810: if (dsklength == 0) {
811: disk_dmafinished ();
812: drive_write_data (drv);
813: }
1.1 root 814: }
815: }
1.1.1.7 root 816: hpos += drv->trackspeed;
1.1 root 817: }
1.1.1.7 root 818: disk_hpos = hpos - (MAXHPOS << 8);
1.1 root 819: }
820:
1.1.1.7 root 821: /* get one bit from MFM bit stream */
822: static uae_u16 getonebit (uae_u16 * mfmbuf, int mfmpos, uae_u16 word)
1.1 root 823: {
1.1.1.7 root 824: uae_u16 *buf;
1.1 root 825:
1.1.1.7 root 826: buf = &mfmbuf[mfmpos >> 4];
827: word <<= 1;
828: word |= (buf[0] & (1 << (15 - (mfmpos & 15)))) ? 1 : 0;
829: return word;
1.1 root 830: }
831:
1.1.1.7 root 832: /* emulate disk read dma for full horizontal line */
833: static void disk_doupdate_read (drive * drv)
834: {
835: int hpos = disk_hpos;
836: int is_sync = 0, dmaon;
837: int j = 0, l = 0, k = 0;
838:
839: while (hpos < (MAXHPOS << 8)) {
840: word = getonebit (drv->bigmfmbuf, drv->mfmpos, word);
841: drv->mfmpos++;
842: drv->mfmpos %= drv->tracklen;
843: if (!drv->mfmpos) {
844: disk_sync[hpos >> 8] |= DISK_INDEXSYNC;
845: is_sync = 1;
846: }
847: bitoffset++;
848: bitoffset &= 15;
849: if (bitoffset == 0 && (!(adkcon & 0x400) || syncfound))
850: dmaon = 1;
851: else
852: dmaon = 0;
853: if (word == dsksync) {
854: if ((adkcon & 0x400) == 0x400 && ! syncfound) {
855: syncfound = 1;
856: bitoffset = 0;
857: }
858: disk_sync[hpos >> 8] |= DISK_WORDSYNC;
859: is_sync = 1;
860: }
861: if (dmaon) {
862: dma_tab[j++] = word;
863: if (j == MAX_DISK_WORDS_PER_LINE - 1) {
864: write_log ("Bug: Disk DMA buffer overflow!\n");
865: j--;
866: }
867: }
868: if (bitoffset == 0 || bitoffset == 8) {
869: dskbytr_tab[k] = (word & 0xff) | 0x8000;
870: dskbytr_cycle[k++] = hpos >> 8;
871: if (bitoffset == 0) {
872: dskdatr_tab[l] = word;
873: dskdatr_cycle[l++] = hpos >> 8;
874: }
875: }
876: hpos += drv->trackspeed;
877: }
878: dma_tab[j] = 0xffffffff;
879: if (is_sync)
880: disk_events (0);
881: dskbytr_cycle[k] = 255;
882: dskdatr_cycle[l] = 255;
883:
884: disk_hpos = hpos - (MAXHPOS << 8);
885: }
886:
887: /* disk DMA fetch happens on real Amiga at the beginning of next horizontal line
888: (cycles 9, 11 and 13 according to hardware manual) We transfer all DMA'd
889: data at cycle 0. I don't think any program cares about this small difference.
890: */
891: static void dodmafetch (void)
1.1 root 892: {
1.1.1.7 root 893: int i;
894:
895: i = 0;
896: while (dma_tab[i] != 0xffffffff && dskdmaen == 2 && (dmacon & 0x210) == 0x210) {
897: put_word (dskpt, dma_tab[i]);
898: dskpt += 2;
899: dsklength--;
900: if (dsklength == 0) {
901: disk_dmafinished ();
902: break;
903: }
904: i++;
905: }
906: dma_tab[0] = 0xffffffff;
1.1 root 907: }
908:
1.1.1.7 root 909: static void DISK_start (void)
1.1.1.6 root 910: {
911: int dr;
1.1.1.7 root 912:
1.1.1.6 root 913: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 914: drive *drv = &floppy[dr];
915: if (!(selected & (1 << dr))) {
916: int tr = drv->cyl * 2 + side;
917: trackid *ti = drv->trackdata + tr;
918:
919: drive_fill_bigbuf (drv);
920: if (dskdmaen == 3) {
921: drv->tracklen = FLOPPY_WRITE_LEN * 8 * 2;
922: drv->trackspeed = floppy_speed;
923: }
924: /* Ugh. A nasty hack. Assume ADF_EXT1 tracks are always read
925: from the start. */
926: if (ti->type == TRACK_RAW1)
927: drv->mfmpos = 0;
928: drv->mfmpos %= drv->tracklen;
1.1.1.6 root 929: }
930: }
1.1.1.7 root 931: syncfound = 0;
932: dmaon = 0;
933: word = 0;
934: bitoffset = 0;
935: dma_tab[0] = 0xffffffff;
1.1.1.6 root 936: }
937:
1.1.1.7 root 938: static int linecounter;
939:
940: void DISK_update (void)
1.1 root 941: {
942: int dr;
1.1.1.7 root 943:
1.1.1.6 root 944: for (dr = 0; dr < 4; dr++) {
1.1.1.7 root 945: drive *drv = &floppy[dr];
946: drv->mfmpos_hsync = drv->mfmpos;
947: }
948: if (linecounter) {
949: linecounter--;
950: if (! linecounter)
951: disk_dmafinished ();
952: return;
953: }
954:
955: dodmafetch ();
956: indexsync_last_cycle = -1;
957:
958: for (dr = 0; dr < 4; dr++) {
959: drive *drv = &floppy[dr];
960: if (drv->motoroff)
961: continue;
962: if (selected & (1 << dr)) {
963: drv->mfmpos += (MAXHPOS << 8) / drv->trackspeed;
964: drv->mfmpos %= drv->tracklen;
965: continue;
1.1 root 966: }
1.1.1.7 root 967: if (dskdmaen == 3)
968: disk_doupdate_write (drv);
969: else
970: disk_doupdate_read (drv);
971: return;
1.1 root 972: }
973: }
1.1.1.6 root 974:
1.1.1.7 root 975: void DSKLEN (uae_u16 v, int hpos)
1.1.1.6 root 976: {
1.1.1.7 root 977: if (v & 0x8000) {
978: dskdmaen = dskdmaen == 1 ? 2 : 1;
979: } else {
980: /* Megalomania does this */
981: #if 0
982: if (dskdmaen == 2)
983: write_log ("warning: Disk read DMA aborted, %d words left\n", dsklength);
984: #endif
985: if (dskdmaen == 3)
986: write_log ("warning: Disk write DMA aborted, %d words left\n", dsklength);
987: dskdmaen = 0;
988: }
989: dsklength = v & 0x3fff;
990: if (dskdmaen <= 1)
991: return;
992: if (v & 0x4000)
993: dskdmaen = 3;
994: #ifdef DISK_DEBUG
995: {
996: int dr;
997: for (dr = 0; dr < 4; dr++) {
998: drive *drv = &floppy[dr];
999: if (drv->motoroff)
1000: continue;
1001: if ((selected & (1 << dr)) == 0)
1002: break;
1003: }
1004: if (dr == 4)
1005: write_log ("disk DMA started, but no drive ready!\n");
1006: else
1007: write_log ("disk %s DMA started for %d words (%08.8X) sync=%04.4X track %d\n",
1008: dskdmaen == 3 ? "write" : "read", dsklength, dskpt,
1009: (adkcon & 0x400) ? dsksync : 0xffff,
1010: floppy[dr].cyl * 2 + side);
1011: }
1012: #endif
1013: /* Megalomania does not work if DSKLEN write is delayed to next horizontal line,
1014: also it seems some copy protections require this fix */
1015: DISK_start ();
1.1.1.6 root 1016:
1.1.1.7 root 1017: /* Try to make floppy access from Kickstart faster. */
1018: if (dskdmaen != 2)
1019: return;
1020: {
1021: int dr;
1022: uaecptr pc = m68k_getpc ();
1023: if ((pc & 0xF80000) != 0xF80000)
1024: return;
1025: for (dr = 0; dr < 4; dr++) {
1026: drive *drv = &floppy[dr];
1027: if (drv->motoroff)
1028: continue;
1029: if ((selected & (1 << dr)) == 0) {
1030: int pos = drv->mfmpos & ~15;
1031: int i;
1032:
1033: if (adkcon & 0x400) {
1034: for (i = 0; i < drv->tracklen; i += 16) {
1035: pos += 16;
1036: pos %= drv->tracklen;
1037: if (drv->bigmfmbuf[pos >> 4] == dsksync)
1038: break;
1039: }
1040: if (i >= drv->tracklen)
1041: return;
1042: }
1043: while (dsklength-- > 0) {
1044: put_word (dskpt, drv->bigmfmbuf[pos >> 4]);
1045: dskpt += 2;
1046: pos += 16;
1047: pos %= drv->tracklen;
1.1.1.6 root 1048: }
1.1.1.7 root 1049: INTREQ (0x9000);
1050: linecounter = 2;
1051: dskdmaen = 0;
1052: return;
1.1.1.6 root 1053: }
1054: }
1.1.1.7 root 1055: }
1.1.1.6 root 1056: }
1057:
1.1.1.7 root 1058: /* this unoptimized code should be enough (DSKBYTR and DSKDATR are used very rarely) */
1059:
1060: uae_u16 DSKBYTR (int hpos)
1.1.1.6 root 1061: {
1.1.1.7 root 1062: uae_u16 v;
1063: int i;
1064:
1065: i = 0;
1066: while (hpos > dskbytr_cycle[i])
1067: i++;
1068: v = dskbytr_tab[i];
1069: if (indexsync_last_cycle >= 0 && indexsync_last_cycle <= hpos)
1070: v |= 0x1000;
1071: dskbytr_tab[i] &= ~0x8000;
1072: if (dskdmaen && (dmacon & 0x210) == 0x210)
1073: v |= 0x4000;
1074: if (dskdmaen == 3)
1075: v |= 0x2000;
1076: return v;
1077: }
1078:
1079: uae_u16 DSKDATR (int hpos)
1080: {
1081: int i;
1082:
1083: i = 0;
1084: while (hpos > dskdatr_cycle[i])
1085: i++;
1086: return dskdatr_tab[i];
1087: }
1088:
1089: void DSKSYNC (uae_u16 v)
1090: {
1091: dsksync = v;
1092: }
1093:
1094: void DSKDAT (uae_u16 v)
1095: {
1096: static int count = 0;
1097: if (count < 5) {
1098: count++;
1099: write_log ("DSKDAT written. Not good.");
1100: if (count == 5)
1101: write_log ("(further messages suppressed)");
1102:
1103: write_log ("\n");
1.1.1.6 root 1104: }
1105: }
1.1.1.7 root 1106: void DSKPTH (uae_u16 v)
1107: {
1108: dskpt = (dskpt & 0xffff) | ((uae_u32) v << 16);
1109: }
1.1.1.6 root 1110:
1.1.1.7 root 1111: void DSKPTL (uae_u16 v)
1.1.1.6 root 1112: {
1.1.1.7 root 1113: dskpt = (dskpt & ~0xffff) | (v);
1.1.1.6 root 1114: }
1115:
1.1.1.7 root 1116: void DISK_init (void)
1117: {
1118: int i;
1119:
1120: dma_tab[0] = 0xffffffff;
1121: dskbytr_cycle[0] = 255;
1122: dskdatr_cycle[0] = 255;
1123: indexsync_last_cycle = -1;
1124:
1.1.1.8 ! root 1125: for (i = 0; i < 4; i++) {
1.1.1.7 root 1126: if (!drive_insert (floppy + i, i, currprefs.df[i]))
1127: disk_eject (i);
1.1.1.8 ! root 1128: }
1.1.1.7 root 1129: if (disk_empty (0))
1130: write_log ("No disk in drive 0.\n");
1131: }
1132:
1.1.1.8 ! root 1133: void DISK_reset (void)
! 1134: {
! 1135: int i;
! 1136: disk_hpos = 0;
! 1137: for (i = 0; i < 4; i++) {
! 1138: floppy[i].disabled = 0;
! 1139: if (i >= currprefs.nr_floppies)
! 1140: floppy[i].disabled = 1;
! 1141: }
! 1142: }
! 1143:
1.1.1.7 root 1144: void dumpdisk (void)
1145: {
1146: int i;
1147: for (i = 0; i < 4; i++) {
1148: drive *drv = &floppy[i];
1149: printf ("Drive %d: motor %s cylinder %2d selected %d\n", i, drv->motoroff ? "off" : " on", drv->cyl, selected & (1 << i));
1150: }
1151: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.