|
|
1.1 ! root 1: /* ! 2: * UAE - The Un*x Amiga Emulator ! 3: * ! 4: * Floppy disk emulation ! 5: * ! 6: * (c) 1995 Bernd Schmidt, Hannu Rummukainen ! 7: */ ! 8: ! 9: #include <string.h> ! 10: #include <stdio.h> ! 11: ! 12: #include "config.h" ! 13: #include "amiga.h" ! 14: #include "options.h" ! 15: #include "memory.h" ! 16: #include "ersatz.h" ! 17: #include "disk.h" ! 18: ! 19: int indexpulse = 0; ! 20: ! 21: UWORD* mfmwrite; ! 22: static UWORD mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */ ! 23: ! 24: static int side, direction, step; ! 25: static UBYTE selected = 15; ! 26: static bool dskready; ! 27: static bool need_read = false; ! 28: ! 29: typedef struct { ! 30: UWORD sync; ! 31: UWORD len; ! 32: ULONG offs; ! 33: } trackid; ! 34: ! 35: typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype; ! 36: typedef struct { ! 37: FILE *diskfile; ! 38: drive_filetype filetype; ! 39: trackid trackdata[164]; ! 40: unsigned int track; ! 41: bool motoroff; ! 42: bool wrprot; ! 43: unsigned int trackoffs,insecpos; ! 44: bool secok; ! 45: UBYTE secbuf[544]; ! 46: UWORD mfmbuf[544]; ! 47: } drive; ! 48: ! 49: drive floppy[4]; ! 50: ! 51: static void drive_insert(drive *drv, char *fname) ! 52: { ! 53: unsigned char buffer[10]; ! 54: ! 55: drv->diskfile = fopen(fname,"r+b"); ! 56: if (drv->diskfile) { ! 57: drv->wrprot = false; ! 58: } else { ! 59: drv->wrprot = true; ! 60: drv->diskfile = fopen(fname, "rb"); ! 61: if (!drv->diskfile) return; ! 62: } ! 63: fread(buffer,sizeof(char),8,drv->diskfile); ! 64: if (strncmp((char *)buffer,"UAE--ADF",8) == 0) { ! 65: int offs = 160*4+8; ! 66: int i; ! 67: ! 68: drv->filetype = ADF_EXT1; ! 69: drv->wrprot = true; /* write to adf_ext1 not implemented */ ! 70: for(i=0; i<160; i++) { ! 71: fread(buffer, 4, 1, drv->diskfile); ! 72: drv->trackdata[i].sync = buffer[0]*256 + buffer[1]; ! 73: drv->trackdata[i].len = buffer[2]*256 + buffer[3]; ! 74: drv->trackdata[i].offs = offs; ! 75: offs += drv->trackdata[i].len; ! 76: } ! 77: } else { ! 78: int i; ! 79: drv->filetype = ADF_NORMAL; ! 80: for(i=0; i<160; i++) { ! 81: drv->trackdata[i].len = 512 * 11; ! 82: drv->trackdata[i].sync = 0; ! 83: drv->trackdata[i].offs = i*512*11; ! 84: } ! 85: } ! 86: } ! 87: ! 88: ! 89: static void drive_step(drive *drv) ! 90: { ! 91: if (direction) { ! 92: if (drv->track) drv->track--; ! 93: } else { ! 94: if (drv->track < 85) drv->track++; ! 95: } ! 96: } ! 97: ! 98: ! 99: static bool drive_track0(drive *drv) ! 100: { ! 101: return drv->track == 0; ! 102: } ! 103: ! 104: static bool drive_writeprotected(drive *drv) ! 105: { ! 106: return drv->wrprot || drv->diskfile == NULL; ! 107: } ! 108: ! 109: static bool drive_empty(drive *drv) ! 110: { ! 111: return drv->diskfile == 0; ! 112: } ! 113: ! 114: static bool drive_running(drive *drv) ! 115: { ! 116: return !drv->motoroff; ! 117: } ! 118: ! 119: static void drive_index(drive *drv) ! 120: { ! 121: drv->trackoffs = 0; ! 122: drv->insecpos = 0; ! 123: } ! 124: ! 125: static void drive_motor(drive *drv, bool off) ! 126: { ! 127: if (drv->motoroff && !off) { ! 128: drv->trackoffs = 0; ! 129: drv->insecpos = 0; ! 130: drv->secok = false; ! 131: } ! 132: drv->motoroff = off; ! 133: } ! 134: ! 135: static ULONG drive_getmfmulong(drive *drv, unsigned int offs) ! 136: { ! 137: return (drv->mfmbuf[offs] << 16) | drv->mfmbuf[offs+1]; ! 138: } ! 139: ! 140: static ULONG drive_getseculong(drive *drv, unsigned int offs) ! 141: { ! 142: return ((drv->secbuf[offs] << 24) | (drv->secbuf[offs+1] << 16) ! 143: | (drv->secbuf[offs+2] << 8) | (drv->secbuf[offs+3])); ! 144: } ! 145: ! 146: static void drive_readsec(drive *drv) ! 147: { ! 148: ULONG deven,dodd; ! 149: ULONG hck=0,dck=0; ! 150: int i; ! 151: ! 152: if (!drv->diskfile) return; ! 153: ! 154: drv->secbuf[0] = drv->secbuf[1] = 0x00; ! 155: drv->secbuf[2] = drv->secbuf[3] = 0xa1; ! 156: drv->secbuf[4] = 0xff; ! 157: drv->secbuf[5] = drv->track*2 + side; ! 158: drv->secbuf[6] = drv->trackoffs; ! 159: drv->secbuf[7] = 11-drv->trackoffs; ! 160: ! 161: for(i = 8; i < 24; i++) ! 162: drv->secbuf[i] = 0; ! 163: ! 164: fseek(drv->diskfile, ! 165: drv->trackdata[drv->track*2 + side].offs + drv->trackoffs*512, ! 166: SEEK_SET); ! 167: fread(&drv->secbuf[32],sizeof(UBYTE),512,drv->diskfile); ! 168: ! 169: drv->mfmbuf[0] = drv->mfmbuf[1] = 0xaaaa; ! 170: drv->mfmbuf[2] = drv->mfmbuf[3] = 0x4489; ! 171: ! 172: deven = drive_getseculong(drv, 4); dodd = deven >> 1; ! 173: deven &= 0x55555555; dodd &= 0x55555555; ! 174: ! 175: drv->mfmbuf[4] = dodd >> 16; ! 176: drv->mfmbuf[5] = dodd; ! 177: drv->mfmbuf[6] = deven>> 16; ! 178: drv->mfmbuf[7] = deven; ! 179: ! 180: for (i = 8; i < 48; i++) ! 181: drv->mfmbuf[i] = 0; ! 182: for (i = 0; i < 512; i += 4){ ! 183: deven = drive_getseculong(drv, i + 32); ! 184: dodd = deven >> 1; ! 185: deven &= 0x55555555; dodd &= 0x55555555; ! 186: drv->mfmbuf[(i>>1)+32] = dodd >> 16; ! 187: drv->mfmbuf[(i>>1)+33] = dodd; ! 188: drv->mfmbuf[(i>>1)+256+32] = deven>> 16; ! 189: drv->mfmbuf[(i>>1)+256+33] = deven; ! 190: } ! 191: ! 192: for(i = 4; i < 24; i += 2) ! 193: hck ^= drive_getmfmulong(drv, i); ! 194: ! 195: deven = dodd = hck; dodd >>= 1; ! 196: drv->mfmbuf[24] = dodd >> 16; drv->mfmbuf[25] = dodd; ! 197: drv->mfmbuf[26] = deven>> 16; drv->mfmbuf[27] = deven; ! 198: ! 199: for(i = 32; i < 544; i += 2) ! 200: dck ^= drive_getmfmulong(drv, i); ! 201: ! 202: deven = dodd = dck; dodd >>= 1; ! 203: drv->mfmbuf[28] = dodd >> 16; drv->mfmbuf[29] = dodd; ! 204: drv->mfmbuf[30] = deven>> 16; drv->mfmbuf[31] = deven; ! 205: ! 206: drv->secok = true; ! 207: need_read = false; ! 208: drv->insecpos = 0; ! 209: } ! 210: ! 211: static void drive_get_data(drive *drv, UWORD *mfm, UWORD *byt) ! 212: { ! 213: if (drv->trackdata[drv->track*2 + side].sync == 0) { ! 214: /* Normal AmigaDOS format track */ ! 215: if (!drv->secok || need_read) ! 216: drive_readsec(drv); ! 217: *mfm = drv->mfmbuf[drv->insecpos]; ! 218: *byt = drv->secbuf[drv->insecpos++]; ! 219: ! 220: if (drv->insecpos == 544){ ! 221: drv->insecpos = 0; ! 222: drv->secok = false; ! 223: if (++drv->trackoffs == 11) ! 224: drv->trackoffs = 0; ! 225: } ! 226: } else { ! 227: /* Raw MFM track */ ! 228: if (drv->insecpos > drv->trackdata[drv->track*2+side].len) ! 229: drv->insecpos = 0; ! 230: if (drv->insecpos == 0) { ! 231: *mfm = drv->trackdata[drv->track*2 + side].sync; ! 232: } else { ! 233: unsigned char data[2]; ! 234: fseek(drv->diskfile, ! 235: drv->insecpos*2 - 2 + drv->trackdata[drv->track*2+side].offs, ! 236: SEEK_SET); ! 237: fread(data, 2, 1, drv->diskfile); ! 238: *mfm = data[0]*256 + data[1]; ! 239: /* ??? how does this work? */ ! 240: *byt = (data[0] & 0x55) | ((data[1] & 0x55)*2); ! 241: } ! 242: drv->insecpos++; ! 243: } ! 244: } ! 245: ! 246: #define MFMMASK 0x55555555 ! 247: static __inline__ ULONG getmfmlong(UWORD* mbuf) ! 248: { ! 249: return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK; ! 250: } ! 251: ! 252: static void drive_write_data(drive *drv, UWORD *mbuf, UWORD *mend) ! 253: { ! 254: int i, secwritten = 0; ! 255: ULONG odd, even, chksum, id, dlong; ! 256: UBYTE* secdata; ! 257: ! 258: if (drive_writeprotected(drv)) return; ! 259: mend -= (4 + 16 + 8 + 512); ! 260: while (mbuf < mend) { ! 261: do { ! 262: while (*mbuf++ != 0x4489) { ! 263: if (mbuf >= mend) return; ! 264: } ! 265: } while (*mbuf++ != 0x4489); ! 266: ! 267: odd = getmfmlong(mbuf); ! 268: even = getmfmlong(mbuf+2); ! 269: mbuf += 4; ! 270: id = (odd << 1) | even; ! 271: ! 272: drv->trackoffs = (id & 0xff00) >> 8; ! 273: if (drv->trackoffs > 10) { ! 274: printf("Disk write: weird sector number %d\n", drv->trackoffs); ! 275: continue; ! 276: } ! 277: chksum = odd ^ even; ! 278: for (i=0; i<4; i++) { ! 279: odd = getmfmlong(mbuf); ! 280: even = getmfmlong(mbuf+8); ! 281: mbuf += 2; ! 282: ! 283: dlong = (odd << 1) | even; ! 284: if (dlong) secwritten = -200; ! 285: chksum ^= odd ^ even; ! 286: } /* could check here if the label is nonstandard */ ! 287: mbuf += 8; ! 288: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4; ! 289: if ((((odd << 1) | even) != chksum) || ! 290: (((id & 0x00ff0000) >> 16) != drv->track*2 + side)) { ! 291: printf("Disk write: checksum error on sector header\n"); ! 292: continue; ! 293: } ! 294: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4; ! 295: chksum = (odd << 1) | even; ! 296: secdata = drv->secbuf + 32; ! 297: for (i=0; i<128; i++) { ! 298: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+256); mbuf += 2; ! 299: dlong = (odd << 1) | even; ! 300: *secdata++ = dlong >> 24; *secdata++ = (dlong >> 16) & 0xff; ! 301: *secdata++ = dlong >> 8; *secdata++ = dlong; ! 302: chksum ^= odd ^ even; ! 303: } ! 304: mbuf += 256; ! 305: if (chksum) { ! 306: printf("Disk write: data checksum error\n"); ! 307: continue; ! 308: } ! 309: secwritten++; ! 310: fseek(drv->diskfile, ! 311: drv->trackdata[drv->track*2 + side].offs + drv->trackoffs*512, ! 312: SEEK_SET); ! 313: fwrite(drv->secbuf+32, sizeof(UBYTE), 512, drv->diskfile); ! 314: } ! 315: if (++drv->trackoffs == 11) drv->trackoffs = 0; ! 316: drv->insecpos = 0; ! 317: drv->secok = false; ! 318: ! 319: if (secwritten == 0) ! 320: printf("Disk write in unsupported format\n"); ! 321: if (secwritten < 0) ! 322: printf("Disk write: sector labels ignored\n"); ! 323: } ! 324: ! 325: static void drive_init(drive *drv, char *fname) ! 326: { ! 327: drv->diskfile = 0; ! 328: if (fname != 0) drive_insert(drv, fname); ! 329: drv->track = 0; ! 330: drv->motoroff = true; ! 331: } ! 332: ! 333: static void drive_eject(drive *drv) ! 334: { ! 335: if (!drive_empty(drv)) fclose(drv->diskfile); ! 336: drv->diskfile = 0; ! 337: } ! 338: ! 339: /* We use this function if we have no Kickstart ROM. */ ! 340: void DISK_ersatz_read (int tr, int sec, CPTR dest) ! 341: { ! 342: int i; ! 343: ! 344: floppy[0].trackoffs = sec; ! 345: floppy[0].insecpos = 0; ! 346: ! 347: side = tr & 1; ! 348: floppy[0].track = tr >> 1; ! 349: drive_readsec(floppy); ! 350: for (i = 0; i < 512; i++) { ! 351: put_byte (dest + i, floppy[0].secbuf[32+i]); ! 352: } ! 353: ! 354: } ! 355: ! 356: void DISK_init() ! 357: { ! 358: drive_insert(floppy, "df0.adf"); ! 359: drive_insert(floppy + 1, "df1.adf"); ! 360: drive_insert(floppy + 2, "df2.adf"); ! 361: drive_insert(floppy + 3, "df3.adf"); ! 362: } ! 363: ! 364: void DISK_Index() ! 365: { ! 366: int i; ! 367: for(i=0; i<4; i++) { ! 368: drive_index(floppy + i); ! 369: } ! 370: } ! 371: ! 372: void DISK_select(UBYTE data) ! 373: { ! 374: int step_pulse; ! 375: int dr; ! 376: ! 377: if (selected != ((data >> 3) & 15)) dskready = false; ! 378: selected = (data >> 3) & 15; ! 379: if (side != 1 - ((data >> 2) & 1)) { ! 380: side = 1 - ((data >> 2) & 1); ! 381: need_read = true; ! 382: } ! 383: direction = (data >> 1) & 1; ! 384: step_pulse = data & 1; ! 385: if (step != step_pulse) { ! 386: step = step_pulse; ! 387: if (step == 0){ ! 388: for (dr = 0; dr < 4; dr++){ ! 389: if (!(selected & (1 << dr))) { ! 390: drive_step(floppy + dr); ! 391: } ! 392: } ! 393: } ! 394: } ! 395: for (dr = 0; dr < 4; dr++){ ! 396: if (!(selected & (1<<dr))) { ! 397: drive_motor(floppy + dr, data >> 7); ! 398: } ! 399: } ! 400: } ! 401: ! 402: UBYTE DISK_status() ! 403: { ! 404: UBYTE st = 0x3c; ! 405: int dr; ! 406: ! 407: for (dr = 0; dr < 4; dr++){ ! 408: if (!(selected & (1 << dr))) { ! 409: if (drive_running(floppy + dr)){ ! 410: if (dskready) st &= ~0x20; ! 411: dskready = true; ! 412: } else { ! 413: st &= ~0x20; /* report drive ID */ ! 414: } ! 415: ! 416: if (drive_track0(floppy + dr)) { st &= ~0x10; } ! 417: if (drive_writeprotected(floppy + dr)) { st &= ~8; } ! 418: if (drive_empty(floppy + dr)) { st &= ~0x4; } ! 419: } ! 420: } ! 421: return st; ! 422: } ! 423: ! 424: void DISK_GetData(UWORD *mfm,UWORD *byt) ! 425: { ! 426: int dr; ! 427: for (dr = 0; dr < 4; dr++){ ! 428: if (!(selected & (1<<dr))) { ! 429: drive_get_data (floppy + dr, mfm, byt); ! 430: } ! 431: } ! 432: } ! 433: ! 434: void DISK_InitWrite() ! 435: { ! 436: mfmwrite = mfmwrbuffer; ! 437: } ! 438: ! 439: void DISK_WriteData() ! 440: { ! 441: int dr; ! 442: for (dr=0;dr<4;dr++){ ! 443: if (!(selected & (1<<dr))) { ! 444: drive_write_data(floppy + dr, mfmwrbuffer, mfmwrite); ! 445: } ! 446: } ! 447: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.