home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD1.iso / Emulatoren / UAE061.LZH / uae-0.6.1 / disk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  12.0 KB  |  528 lines

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