|
|
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: * 6: * (c) 1995 Bernd Schmidt, Hannu Rummukainen 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" 16: #include "memory.h" 17: #include "events.h" 18: #include "custom.h" 19: #include "ersatz.h" 20: #include "disk.h" 21: #include "gui.h" 22: #include "zfile.h" 1.1.1.2 ! root 23: #include "autoconf.h" ! 24: #include "readcpu.h" ! 25: #include "newcpu.h" ! 26: #include "xwin.h" ! 27: #include "osemu.h" ! 28: #include "execlib.h" ! 29: ! 30: #define FLOPPY_GAP_LEN 380 1.1 root 31: 32: #define FLOPPY_SPEED 5 33: 34: UWORD* mfmwrite; 35: static UWORD mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */ 36: 37: static int side, direction, step; 38: static UBYTE selected = 15; 39: static int dskready; 40: static int need_read = 0; 41: 42: typedef struct { 43: UWORD sync; 44: UWORD len; 45: ULONG offs; 46: } trackid; 47: 1.1.1.2 ! root 48: #define MAX_TRACKS 328 ! 49: 1.1 root 50: typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype; 51: typedef struct { 52: FILE *diskfile; 53: drive_filetype filetype; 1.1.1.2 ! root 54: trackid trackdata[MAX_TRACKS]; 1.1 root 55: unsigned int track; 56: int motoroff; 57: int wrprot; 1.1.1.2 ! root 58: UWORD bigmfmbuf[0x4000]; 1.1 root 59: int tracklen; 60: unsigned long last_cycles; 61: int mfmpos; 1.1.1.2 ! root 62: unsigned int num_tracks, num_secs; ! 63: int nodskchange; 1.1 root 64: } drive; 65: 66: drive floppy[4]; 67: 68: static void drive_fill_bigbuf(drive *drv); 69: 1.1.1.2 ! root 70: static void drive_insert(drive *drv, int dnum, const char *fname) 1.1 root 71: { 72: unsigned char buffer[10]; 73: 74: drv->diskfile = zfile_open(fname,"r+b"); 75: if (drv->diskfile) { 76: drv->wrprot = 0; 77: } else { 78: drv->wrprot = 1; 79: drv->diskfile = zfile_open(fname, "rb"); 80: if (!drv->diskfile) { 81: gui_filename(dnum, ""); 82: return; 83: } 84: } 85: switch (dnum) { 86: case 0: strcpy((char *)df0, fname); break; 87: case 1: strcpy((char *)df1, fname); break; 88: case 2: strcpy((char *)df2, fname); break; 89: case 3: strcpy((char *)df3, fname); break; 90: } 91: gui_filename(dnum, fname); 1.1.1.2 ! root 92: 1.1 root 93: fread(buffer,sizeof(char),8,drv->diskfile); 94: if (strncmp((char *)buffer,"UAE--ADF",8) == 0) { 95: int offs = 160*4+8; 96: int i; 97: 98: drv->filetype = ADF_EXT1; 1.1.1.2 ! root 99: drv->num_tracks = 160; ! 100: drv->num_secs = 11; ! 101: 1.1 root 102: drv->wrprot = 1; /* write to adf_ext1 not implemented */ 103: for(i=0; i<160; i++) { 104: fread(buffer, 4, 1, drv->diskfile); 105: drv->trackdata[i].sync = buffer[0]*256 + buffer[1]; 106: drv->trackdata[i].len = buffer[2]*256 + buffer[3]; 107: drv->trackdata[i].offs = offs; 108: offs += drv->trackdata[i].len; 109: } 110: } else { 1.1.1.2 ! root 111: unsigned int i; ! 112: 1.1 root 113: drv->filetype = ADF_NORMAL; 1.1.1.2 ! root 114: ! 115: fseek(drv->diskfile,0,SEEK_END); ! 116: i = ftell(drv->diskfile); ! 117: fseek(drv->diskfile,0,SEEK_SET); ! 118: ! 119: /* High-density disk? */ ! 120: if (i >= 160*22*512) ! 121: drv->num_tracks = i / (512*(drv->num_secs = 22)); ! 122: else ! 123: drv->num_tracks = i / (512*(drv->num_secs = 11)); ! 124: ! 125: if (drv->num_tracks > MAX_TRACKS) ! 126: fprintf(stderr, "Your diskfile is too big!\n"); ! 127: for(i = 0; i < drv->num_tracks; i++) { ! 128: drv->trackdata[i].len = 512 * drv->num_secs; 1.1 root 129: drv->trackdata[i].sync = 0; 1.1.1.2 ! root 130: drv->trackdata[i].offs = i * 512 * drv->num_secs; 1.1 root 131: } 132: } 133: drive_fill_bigbuf(drv); 134: } 135: 1.1.1.2 ! root 136: static int drive_empty(drive *drv) ! 137: { ! 138: return drv->diskfile == 0; ! 139: } ! 140: 1.1 root 141: static void drive_step(drive *drv) 142: { 1.1.1.2 ! root 143: if (!drive_empty (drv)) ! 144: drv->nodskchange = 1; 1.1 root 145: if (direction) { 146: if (drv->track) drv->track--; 147: } else { 1.1.1.2 ! root 148: if (drv->track < drv->num_tracks/2) drv->track++; 1.1 root 149: } 150: drive_fill_bigbuf(drv); 151: } 152: 153: 154: static int drive_track0(drive *drv) 155: { 156: return drv->track == 0; 157: } 158: 159: static int drive_writeprotected(drive *drv) 160: { 161: return drv->wrprot || drv->diskfile == NULL; 162: } 163: 164: static int drive_running(drive *drv) 165: { 166: return !drv->motoroff; 167: } 168: 169: static void drive_motor(drive *drv, int off) 170: { 171: if (drv->motoroff && !off) { 172: drv->last_cycles = cycles; 173: drv->mfmpos = 0; 174: eventtab[ev_diskindex].active = 1; 175: if (drv->tracklen) 176: eventtab[ev_diskindex].evtime = FLOPPY_SPEED * drv->tracklen + cycles; 177: else 178: eventtab[ev_diskindex].evtime = cycles + 1000; 179: eventtab[ev_diskindex].oldcycles = cycles; 180: } else if (off) 181: eventtab[ev_diskindex].active = 0; 182: drv->motoroff = off; 183: events_schedule(); 184: 185: } 186: 187: static void drive_fill_bigbuf(drive *drv) 188: { 189: int tr = drv->track*2 + side; 190: 1.1.1.2 ! root 191: if (!drv->diskfile) { ! 192: drv->tracklen = 10; ! 193: memset (drv->bigmfmbuf,0xaa,drv->tracklen*2); ! 194: return; ! 195: } 1.1 root 196: 197: if (drv->trackdata[tr].sync == 0) { 198: /* Normal AmigaDOS format track */ 1.1.1.2 ! root 199: unsigned int sec; ! 200: drv->tracklen = drv->num_secs*544 + FLOPPY_GAP_LEN; ! 201: memset(drv->bigmfmbuf,0xaa,FLOPPY_GAP_LEN*2); ! 202: ! 203: for (sec = 0; sec < drv->num_secs; sec++) { 1.1 root 204: UBYTE secbuf[544]; 205: int i; 1.1.1.2 ! root 206: UWORD *mfmbuf = drv->bigmfmbuf + 544*sec + FLOPPY_GAP_LEN; 1.1 root 207: ULONG deven,dodd; 208: ULONG hck=0,dck=0; 209: 210: secbuf[0] = secbuf[1] = 0x00; 211: secbuf[2] = secbuf[3] = 0xa1; 212: secbuf[4] = 0xff; 213: secbuf[5] = tr; 214: secbuf[6] = sec; 1.1.1.2 ! root 215: secbuf[7] = drv->num_secs-sec; 1.1 root 216: 217: for(i = 8; i < 24; i++) 218: secbuf[i] = 0; 219: 220: fseek(drv->diskfile, 221: drv->trackdata[tr].offs + sec*512, 222: SEEK_SET); 223: fread(&secbuf[32],1,512,drv->diskfile); 224: 225: mfmbuf[0] = mfmbuf[1] = 0xaaaa; 226: mfmbuf[2] = mfmbuf[3] = 0x4489; 227: 228: deven = ((secbuf[4] << 24) | (secbuf[5] << 16) 229: | (secbuf[6] << 8) | (secbuf[7])); 230: dodd = deven >> 1; 231: deven &= 0x55555555; dodd &= 0x55555555; 232: 233: mfmbuf[4] = dodd >> 16; 234: mfmbuf[5] = dodd; 235: mfmbuf[6] = deven>> 16; 236: mfmbuf[7] = deven; 237: 238: for (i = 8; i < 48; i++) 239: mfmbuf[i] = 0; 240: for (i = 0; i < 512; i += 4){ 241: deven = ((secbuf[i+32] << 24) | (secbuf[i+33] << 16) 242: | (secbuf[i+34] << 8) | (secbuf[i+35])); 243: dodd = deven >> 1; 244: deven &= 0x55555555; dodd &= 0x55555555; 245: mfmbuf[(i>>1)+32] = dodd >> 16; 246: mfmbuf[(i>>1)+33] = dodd; 247: mfmbuf[(i>>1)+256+32] = deven >> 16; 248: mfmbuf[(i>>1)+256+33] = deven; 249: } 250: 251: for(i = 4; i < 24; i += 2) 252: hck ^= (mfmbuf[i] << 16) | mfmbuf[i+1]; 253: 254: deven = dodd = hck; dodd >>= 1; 255: mfmbuf[24] = dodd >> 16; mfmbuf[25] = dodd; 256: mfmbuf[26] = deven>> 16; mfmbuf[27] = deven; 257: 258: for(i = 32; i < 544; i += 2) 259: dck ^= (mfmbuf[i] << 16) | mfmbuf[i+1]; 260: 261: deven = dodd = dck; dodd >>= 1; 262: mfmbuf[28] = dodd >> 16; mfmbuf[29] = dodd; 263: mfmbuf[30] = deven>> 16; mfmbuf[31] = deven; 264: } 265: } else { 266: int i; 267: drv->tracklen = drv->trackdata[tr].len/2 + 1; 268: drv->bigmfmbuf[0] = drv->trackdata[tr].sync; 269: fseek(drv->diskfile, drv->trackdata[tr].offs, SEEK_SET); 270: fread(drv->bigmfmbuf+1, 1, drv->trackdata[tr].len, drv->diskfile); 271: for (i = 0; i < drv->trackdata[tr].len/2; i++) { 272: UWORD *mfm = drv->bigmfmbuf + i + 1; 273: UBYTE *data = (UBYTE *)mfm; 274: 275: *mfm = 256 * *data + *(data+1); 276: } 277: } 278: need_read = 0; 279: drv->last_cycles = cycles; 280: drv->mfmpos = 0; 281: } 282: 283: static int drive_get_data(drive *drv, UWORD *mfm, UWORD *byt) 284: { 285: int offset,mfmpos; 286: if (need_read) { 287: drive_fill_bigbuf(drv); 288: } 289: offset = (cycles - drv->last_cycles) / FLOPPY_SPEED; 290: mfmpos = (drv->mfmpos + offset) % drv->tracklen; 291: drv->last_cycles += offset*FLOPPY_SPEED; 292: drv->mfmpos = mfmpos; 293: *mfm = drv->bigmfmbuf[mfmpos]; 294: return offset > 0; 295: } 296: 297: #define MFMMASK 0x55555555 298: static __inline__ ULONG getmfmlong(UWORD* mbuf) 299: { 300: return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK; 301: } 302: 303: static void drive_write_data(drive *drv, UWORD *mbuf, int length) 304: { 305: int i, secwritten = 0; 306: ULONG odd, even, chksum, id, dlong; 307: UBYTE* secdata; 308: UBYTE secbuf[544]; 309: UWORD *mend = mbuf + length; 310: 311: if (drive_writeprotected(drv)) return; 312: mend -= (4 + 16 + 8 + 512); 313: while (length > 0) { 314: int trackoffs; 315: 316: do { 317: while (*mbuf++ != 0x4489) { 318: if (mbuf >= mend) return; 319: } 320: } while (*mbuf++ != 0x4489); 321: 322: odd = getmfmlong(mbuf); 323: even = getmfmlong(mbuf+2); 324: mbuf += 4; 325: id = (odd << 1) | even; 326: 327: trackoffs = (id & 0xff00) >> 8; 328: if (trackoffs > 10) { 329: printf("Disk write: weird sector number %d\n", trackoffs); 330: continue; 331: } 332: chksum = odd ^ even; 333: for (i=0; i<4; i++) { 334: odd = getmfmlong(mbuf); 335: even = getmfmlong(mbuf+8); 336: mbuf += 2; 337: 338: dlong = (odd << 1) | even; 339: if (dlong) secwritten = -200; 340: chksum ^= odd ^ even; 341: } /* could check here if the label is nonstandard */ 342: mbuf += 8; 343: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4; 344: if ((((odd << 1) | even) != chksum) || 345: (((id & 0x00ff0000) >> 16) != drv->track*2 + side)) { 346: printf("Disk write: checksum error on sector header\n"); 347: continue; 348: } 349: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4; 350: chksum = (odd << 1) | even; 351: secdata = secbuf + 32; 352: for (i=0; i<128; i++) { 353: odd = getmfmlong(mbuf); even = getmfmlong(mbuf+256); mbuf += 2; 354: dlong = (odd << 1) | even; 355: *secdata++ = dlong >> 24; *secdata++ = (dlong >> 16) & 0xff; 356: *secdata++ = dlong >> 8; *secdata++ = dlong; 357: chksum ^= odd ^ even; 358: } 359: mbuf += 256; 360: if (chksum) { 361: printf("Disk write: data checksum error\n"); 362: continue; 363: } 364: secwritten++; 365: fseek(drv->diskfile, 366: drv->trackdata[drv->track*2 + side].offs + trackoffs*512, 367: SEEK_SET); 368: fwrite(secbuf+32, sizeof(UBYTE), 512, drv->diskfile); 369: } 370: need_read = 1; 371: 372: if (secwritten == 0) 373: printf("Disk write in unsupported format\n"); 374: if (secwritten < 0) 375: printf("Disk write: sector labels ignored\n"); 376: } 377: 378: 379: static void drive_eject(drive *drv) 380: { 381: if (!drive_empty(drv)) zfile_close(drv->diskfile); 382: drv->diskfile = 0; 383: } 384: 385: /* We use this function if we have no Kickstart ROM. 386: * No error checking - we trust our luck. */ 387: void DISK_ersatz_read (int tr, int sec, CPTR dest) 388: { 389: int i; 390: UBYTE *dptr = get_real_address(dest); 391: fseek(floppy[0].diskfile, floppy[0].trackdata[tr].offs + sec*512, SEEK_SET); 392: fread(dptr,1,512,floppy[0].diskfile); 393: } 394: 395: void disk_eject(int num) 396: { 397: gui_filename(num, ""); 398: drive_eject(floppy + num); 399: } 400: 1.1.1.2 ! root 401: void disk_insert(int num, const char *name) 1.1 root 402: { 403: /* just to be sure */ 404: drive_eject(floppy + num); 405: drive_insert(floppy + num, num, name); 406: } 407: 408: int disk_empty(int num) 409: { 410: return drive_empty(floppy + num); 411: } 412: 413: void DISK_init() 414: { 415: drive_insert(floppy, 0, df0); 416: if (disk_empty(0)) 417: fprintf(stderr, "No floppy in drive 0.\n"); 418: drive_insert(floppy + 1, 1, df1); 419: drive_insert(floppy + 2, 2, df2); 420: drive_insert(floppy + 3, 3, df3); 421: } 422: 423: static int ledstate[] = { 0,0,0,0 }; 424: 425: void DISK_select(UBYTE data) 426: { 427: int step_pulse; 428: int dr; 429: 430: if (selected != ((data >> 3) & 15)) 431: dskready = 0; 432: selected = (data >> 3) & 15; 433: if (side != 1 - ((data >> 2) & 1)) { 434: side = 1 - ((data >> 2) & 1); 435: need_read = 1; 436: } 437: direction = (data >> 1) & 1; 438: step_pulse = data & 1; 439: if (step != step_pulse) { 440: step = step_pulse; 441: if (step == 0){ 442: for (dr = 0; dr < 4; dr++){ 443: if (!(selected & (1 << dr))) { 444: drive_step(floppy + dr); 445: } 446: } 447: } 448: } 449: for (dr = 0; dr < 4; dr++){ 450: if (!(selected & (1<<dr))) { 451: drive_motor(floppy + dr, data >> 7); 452: } 453: } 454: for (dr = 0; dr < 4; dr++) { 455: int state = (!(selected & (1<<dr))) | !floppy[dr].motoroff; 456: if (state != ledstate[dr]) 457: gui_led (dr+1, state); 458: ledstate[dr] = state; 459: } 460: } 461: 462: UBYTE DISK_status() 463: { 464: UBYTE st = 0x3c; 465: int dr; 466: 467: for (dr = 0; dr < 4; dr++){ 468: if (!(selected & (1 << dr))) { 469: if (drive_running(floppy + dr)){ 470: if (dskready) st &= ~0x20; 471: dskready = 1; 472: } else { 473: st &= ~0x20; /* report drive ID */ 474: } 475: 476: if (drive_track0(floppy + dr)) { st &= ~0x10; } 477: if (drive_writeprotected(floppy + dr)) { st &= ~8; } 1.1.1.2 ! root 478: if (!floppy[dr].nodskchange) { st &= ~0x4; } 1.1 root 479: } 480: } 481: return st; 482: } 483: 484: int DISK_GetData(UWORD *mfm,UWORD *byt) 485: { 486: int dr; 487: for (dr = 0; dr < 4; dr++){ 488: if (!(selected & (1<<dr))) { 489: return drive_get_data (floppy + dr, mfm, byt); 490: } 491: } 492: return 0; 493: } 494: 495: static UWORD mfm_read_buffer[0x4000]; 496: static int mfm_read_length; 497: 498: int DISK_PrepareReadMFM(int length, UWORD sync, int use_sync) 499: { 500: int dr; 501: 502: mfm_read_length = 0; 503: 504: for (dr = 0; dr < 4; dr++) { 505: if (!(selected & (1<<dr))) { 506: int time = 0; 507: UWORD *mfmp = mfm_read_buffer; 508: drive *drv = floppy + dr; 509: int offset,mfmpos; 510: 511: if (need_read) { 512: drive_fill_bigbuf(drv); 513: } 1.1.1.2 ! root 514: 1.1 root 515: offset = (cycles - drv->last_cycles) / FLOPPY_SPEED; 516: mfmpos = (drv->mfmpos + offset) % drv->tracklen; 517: drv->last_cycles += offset*FLOPPY_SPEED; 518: drv->mfmpos = mfmpos; 519: mfmpos++; mfmpos %= drv->tracklen; 520: while (drv->bigmfmbuf[mfmpos] != sync && mfmpos != drv->mfmpos && use_sync) 521: mfmpos = (mfmpos + 1) % drv->tracklen, time++; 1.1.1.2 ! root 522: 1.1 root 523: if (drv->bigmfmbuf[mfmpos] != sync && use_sync) { 524: fprintf(stderr, "warning: sync not found on disk read\n"); 525: return 0; 526: } else 527: mfmpos++; 1.1.1.2 ! root 528: 1.1 root 529: mfm_read_length = length; 530: 531: while (length--) { 532: *mfmp++ = drv->bigmfmbuf[mfmpos]; 533: mfmpos = (mfmpos + 1) % drv->tracklen; 534: time++; 535: } 536: 537: return time*FLOPPY_SPEED; 538: } 539: } 540: return 0; 541: } 542: 543: int DISK_ReadMFM(CPTR target) 544: { 545: int i; 546: UBYTE *mfmp = get_real_address(target); 547: 548: if (!chipmem_bank.check(target, mfm_read_length * 2)) { 549: fprintf(stderr, "warning: Bad disk DMA read pointer\n"); 550: return 0; 551: } 552: 553: for (i = 0; i < mfm_read_length; i++) { 554: *mfmp++ = mfm_read_buffer[i] >> 8; 555: *mfmp++ = mfm_read_buffer[i]; 556: } 557: return 1; 558: } 559: 560: void DISK_InitWrite() 561: { 562: mfmwrite = mfmwrbuffer; 563: } 564: 565: void DISK_WriteData(int length) 566: { 567: int dr; 568: for (dr=0;dr<4;dr++){ 569: if (!(selected & (1<<dr))) { 570: drive_write_data(floppy + dr, mfmwrbuffer, length); 571: } 572: } 573: } 1.1.1.2 ! root 574: ! 575: void trackdisk_install(void) ! 576: { ! 577: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.