home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 5 / MA_Cover_5.iso / ppc / atari / atari800-0.8.6 / sio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-05-10  |  17.5 KB  |  565 lines

  1. /*
  2.  
  3.  * All Input is assumed to be going to RAM
  4.  * All Output is assumed to be coming from either RAM or ROM
  5.  *
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10.  
  11. #ifdef VMS
  12. #include <unixio.h>
  13. #include <file.h>
  14. #else
  15. #include <fcntl.h>
  16. #ifndef AMIGA
  17. #include <unistd.h>
  18. #endif
  19. #endif
  20.  
  21. #ifdef DJGPP
  22. #include "djgpp.h"
  23. #endif
  24.  
  25. static char *rcsid = "$Id: sio.c,v 1.9 1998/02/21 14:55:21 david Exp $";
  26.  
  27. #define FALSE   0
  28. #define TRUE    1
  29.  
  30. #include "atari.h"
  31. #include "cpu.h"
  32. #include "sio.h"
  33.  
  34. #define MAGIC1  0x96
  35. #define MAGIC2  0x02
  36.  
  37. #undef ORIGINAL_XFD_CODE                /* new code should support DD XFD images - PS */
  38.  
  39. struct ATR_Header {
  40.         unsigned char magic1;
  41.         unsigned char magic2;
  42.         unsigned char seccountlo;
  43.         unsigned char seccounthi;
  44.         unsigned char secsizelo;
  45.         unsigned char secsizehi;
  46.         unsigned char hiseccountlo;
  47.         unsigned char hiseccounthi;
  48.         unsigned char gash[8];
  49. };
  50.  
  51. typedef enum Format {
  52.         XFD, ATR
  53. } Format;
  54.  
  55. static Format format[MAX_DRIVES];
  56. static int disk[MAX_DRIVES] =
  57. {-1, -1, -1, -1, -1, -1, -1, -1};
  58. static int sectorcount[MAX_DRIVES];
  59. static int sectorsize[MAX_DRIVES];
  60.  
  61. static enum DriveStatus {
  62.         Off,
  63.         NoDisk,
  64.         ReadOnly,
  65.         ReadWrite
  66. } drive_status[MAX_DRIVES];
  67.  
  68. char sio_status[256];
  69. char sio_filename[MAX_DRIVES][FILENAME_LEN];
  70.  
  71. void SIO_Initialise(int *argc, char *argv[])
  72. {
  73.         int i;
  74.  
  75.         for (i = 0; i < MAX_DRIVES; i++)
  76.                 strcpy(sio_filename[i], "Empty");
  77. }
  78.  
  79. int SIO_Mount(int diskno, char *filename)
  80. {
  81.         struct ATR_Header header;
  82.  
  83.         int fd;
  84.  
  85.         drive_status[diskno - 1] = ReadWrite;
  86.         strcpy(sio_filename[diskno - 1], "Empty");
  87.  
  88.         fd = open(filename, O_RDWR, 0777);
  89.         if (fd == -1) {
  90.                 fd = open(filename, O_RDONLY, 0777);
  91.                 drive_status[diskno - 1] = ReadOnly;
  92.         }
  93.  
  94.         if (fd >= 0) {
  95.                 int status;
  96.  
  97.                 status = read(fd, &header, sizeof(struct ATR_Header));
  98.                 if (status == -1) {
  99.                         close(fd);
  100.                         disk[diskno - 1] = -1;
  101.                         return FALSE;
  102.                 }
  103.  
  104.                 strcpy(sio_filename[diskno - 1], filename);
  105.  
  106.                 if ((header.magic1 == MAGIC1) && (header.magic2 == MAGIC2)) {
  107.                         sectorcount[diskno - 1] = header.hiseccounthi << 24 |
  108.                                 header.hiseccountlo << 16 |
  109.                                 header.seccounthi << 8 |
  110.                                 header.seccountlo;
  111.  
  112.                         sectorsize[diskno - 1] = header.secsizehi << 8 |
  113.                                 header.secsizelo;
  114.  
  115.                         sectorcount[diskno - 1] /= 8;
  116.                         if (sectorsize[diskno - 1] == 256) {
  117.                                 sectorcount[diskno - 1] += 3;   /* Compensate for first 3 sectors */
  118.                                 sectorcount[diskno - 1] /= 2;
  119.                         }
  120.  
  121. #ifdef DEBUG
  122.                         printf("ATR: sectorcount = %d, sectorsize = %d\n",
  123.                                    sectorcount[diskno - 1],
  124.                                    sectorsize[diskno - 1]);
  125. #endif
  126.  
  127.                         format[diskno - 1] = ATR;
  128.                 }
  129.                 else {
  130.                         ULONG file_length = lseek(fd, 0L, SEEK_END);
  131.                         format[diskno - 1] = XFD;
  132. #ifndef ORIGINAL_XFD_CODE
  133.                         /* XFD might be of double density ! (PS) */
  134.                         sectorsize[diskno - 1] = (file_length > (1040 * 128)) ? 256 : 128;
  135.                         sectorcount[diskno - 1] = file_length / sectorsize[diskno - 1];
  136. #endif
  137.                 }
  138.         }
  139.         else {
  140.                 drive_status[diskno - 1] = NoDisk;
  141.         }
  142.  
  143.         disk[diskno - 1] = fd;
  144.  
  145.         return (disk[diskno - 1] != -1) ? TRUE : FALSE;
  146. }
  147.  
  148. void SIO_Dismount(int diskno)
  149. {
  150.         if (disk[diskno - 1] != -1) {
  151.                 close(disk[diskno - 1]);
  152.                 disk[diskno - 1] = -1;
  153.                 drive_status[diskno - 1] = NoDisk;
  154.                 strcpy(sio_filename[diskno - 1], "Empty");
  155.         }
  156. }
  157.  
  158. void SIO_DisableDrive(int diskno)
  159. {
  160.         drive_status[diskno - 1] = Off;
  161.         strcpy(sio_filename[diskno - 1], "Off");
  162. }
  163.  
  164. void SeekSector(int dskno, int sector)
  165. {
  166.         int offset;
  167.  
  168.         sprintf(sio_status, "%d: %d", dskno + 1, sector);
  169.  
  170.         switch (format[dskno]) {
  171.         case XFD:
  172. #ifdef ORIGINAL_XFD_CODE                /* does not support double density XFD disks */
  173.                 offset = (sector - 1) * 128;
  174. #else
  175.                 offset = (sector - 1) * sectorsize[dskno] + 0;
  176. #endif
  177.                 break;
  178.  
  179.         case ATR:
  180.                 if (sector < 4)
  181.                         offset = (sector - 1) * 128 + 16;
  182.                 else
  183.                         offset = (sector - 1) * sectorsize[dskno] + 16;
  184. /*
  185.    offset = 3*128 + (sector-4) * sectorsize[dskno] + 16;
  186.  */
  187.                 break;
  188.         default:
  189.                 printf("Fatal Error in atari_sio.c\n");
  190.                 Atari800_Exit(FALSE);
  191.                 exit(1);
  192.         }
  193.  
  194.         if (offset > lseek(disk[dskno], 0L, SEEK_END)) {
  195. /*
  196.    printf("Seek after end of file\n");
  197.    Atari800_Exit(FALSE);
  198.    exit(1);
  199.  */
  200.         }
  201.         else
  202.                 lseek(disk[dskno], offset, SEEK_SET);
  203. }
  204.  
  205. void SIO(void)
  206. {
  207.         /* UBYTE DDEVIC = memory[0x0300]; */
  208.         UBYTE DUNIT = memory[0x0301];
  209.         UBYTE DCOMND = memory[0x0302];
  210.         /* UBYTE DSTATS = memory[0x0303]; */
  211.         UBYTE DBUFLO = memory[0x0304];
  212.         UBYTE DBUFHI = memory[0x0305];
  213.         /* UBYTE DTIMLO = memory[0x0306]; */
  214.         UBYTE DBYTLO = memory[0x0308];
  215.         UBYTE DBYTHI = memory[0x0309];
  216.         UBYTE DAUX1 = memory[0x030a];
  217.         UBYTE DAUX2 = memory[0x030b];
  218.  
  219.         int sector;
  220.         int buffer;
  221.         int count;
  222.         int i;
  223.  
  224.         if (drive_status[DUNIT - 1] != Off) {
  225.                 if (disk[DUNIT - 1] != -1) {
  226.                         int offset;
  227.  
  228.                         sector = DAUX1 + DAUX2 * 256;
  229.                         buffer = DBUFLO + DBUFHI * 256;
  230.                         count = DBYTLO + DBYTHI * 256;
  231.  
  232.                         switch (format[DUNIT - 1]) {
  233.                         case XFD:
  234. #ifdef ORIGINAL_XFD_CODE
  235.                                 offset = (sector - 1) * 128 + 0;
  236. #else
  237.                                 offset = (sector - 1) * sectorsize[DUNIT - 1] + 0;
  238. #endif
  239.                                 break;
  240.                         case ATR:
  241.                                 if (sector < 4)
  242.                                         offset = (sector - 1) * 128 + 16;
  243.                                 else
  244.                                         offset = (sector - 1) * sectorsize[DUNIT - 1] + 16;
  245. /*
  246.    offset = 3*128 + (sector-4) * sectorsize[DUNIT-1] + 16;
  247.  */
  248.                                 break;
  249.                         default:
  250.                                 printf("Fatal Error in atari_sio.c\n");
  251.                                 Atari800_Exit(FALSE);
  252.                                 exit(1);
  253.                         }
  254.  
  255.                         if (offset > lseek(disk[DUNIT - 1], 0L, SEEK_END)) {
  256. /*
  257.    printf("Seek after end of file\n");
  258.    Atari800_Exit(FALSE);
  259.    exit(1);
  260.  */
  261.                         }
  262.                         else
  263.                                 lseek(disk[DUNIT - 1], offset, SEEK_SET);
  264.  
  265. #ifdef DEBUG
  266.                         printf("SIO: DCOMND = %x, SECTOR = %d, BUFADR = %x, BUFLEN = %d\n",
  267.                                    DCOMND, sector, buffer, count);
  268. #endif
  269.  
  270.                         switch (DCOMND) {
  271.                         case 0x50:
  272.                         case 0x57:
  273.                                 if (drive_status[DUNIT - 1] == ReadWrite) {
  274.                                         write(disk[DUNIT - 1], &memory[buffer], count);
  275.                                         regY = 1;
  276.                                         ClrN;
  277.                                 }
  278.                                 else {
  279.                                         regY = 146;
  280.                                         SetN;
  281.                                 }
  282.                                 break;
  283.                         case 0x52:
  284.                                 read(disk[DUNIT - 1], &memory[buffer], count);
  285.                                 regY = 1;
  286.                                 ClrN;
  287.                                 break;
  288.                         case 0x21:                      /* Single Density Format */
  289.                         case 0x22:                      /* Duel Density Format */
  290.                         case 0x66:                      /* US Doubler Format - I think! */
  291.                                 regY = 1;
  292.                                 ClrN;
  293.                                 break;
  294. /*
  295.    Status Request from Atari 400/800 Technical Reference Notes
  296.  
  297.    DVSTAT + 0   Command Status
  298.    DVSTAT + 1   Hardware Status
  299.    DVSTAT + 2   Timeout
  300.    DVSTAT + 3   Unused
  301.  
  302.    Command Status Bits
  303.  
  304.    Bit 0 = 1 indicates an invalid command frame was received
  305.    Bit 1 = 1 indicates an invalid data frame was received
  306.    Bit 2 = 1 indicates that a PUT operation was unsuccessful
  307.    Bit 3 = 1 indicates that the diskete is write protected
  308.    Bit 4 = 1 indicates active/standby
  309.  
  310.    plus
  311.  
  312.    Bit 5 = 1 indicates double density
  313.    Bit 7 = 1 indicates duel density disk (1050 format)
  314.  */
  315.                         case 0x53:                      /* Get Status */
  316.                                 for (i = 0; i < count; i++) {
  317.                                         if (sectorsize[DUNIT - 1] == 256)
  318.                                                 memory[buffer + i] = 32 + 16;
  319.                                         else
  320.                                                 memory[buffer + i] = 16;
  321.                                 }
  322.                                 regY = 1;
  323.                                 ClrN;
  324.                                 break;
  325.                         default:
  326.                                 printf("SIO: DCOMND = %0x\n", DCOMND);
  327.                                 regY = 146;
  328.                                 SetN;
  329.                                 break;
  330.                         }
  331.                 }
  332.                 else {
  333.                         regY = 146;
  334.                         SetN;
  335.                 }
  336.         }
  337.         else {
  338.                 regY = 138;
  339.                 SetN;
  340.         }
  341.  
  342.         memory[0x0303] = regY;
  343. }
  344.  
  345. static unsigned char cmd_frame[5];
  346. static int ncmd = 0;
  347. static int checksum = 0;
  348.  
  349. static unsigned char data[256];
  350. static int offst;
  351.  
  352. static int buffer_offset;
  353. static int buffer_size;
  354.  
  355. extern int DELAYED_SERIN_IRQ;
  356. extern int DELAYED_SEROUT_IRQ;
  357. extern int DELAYED_XMTDONE_IRQ;
  358.  
  359. typedef enum {
  360.         SIO_Normal,
  361.         SIO_Put
  362. } SIO_State;
  363.  
  364. static SIO_State sio_state = SIO_Normal;
  365.  
  366. void Command_Frame(void)
  367. {
  368.         sio_state = SIO_Normal;
  369.  
  370.         switch (cmd_frame[1]) {
  371.         case 'R':                                       /* Read */
  372. #ifdef DEBUG
  373.                 printf("Read command\n");
  374. #endif
  375.                 {
  376.                         int sector;
  377.                         int dskno;
  378.                         int i;
  379.  
  380.                         dskno = cmd_frame[0] - 0x31;
  381.                         sector = cmd_frame[2] + cmd_frame[3] * 256;
  382. #ifdef DEBUG
  383.                         printf("Sector: %d(%x)\n", sector, sector);
  384. #endif
  385.                         SeekSector(dskno, sector);
  386.  
  387.                         data[0] = 0x41;         /* ACK */
  388.                         data[1] = 0x43;         /* OPERATION COMPLETE */
  389.  
  390.                         read(disk[dskno], &data[2], 128);
  391.                         checksum = 0;
  392.                         for (i = 2; i < 130; i++) {
  393.                                 checksum += (unsigned char) data[i];
  394.                                 while (checksum > 255)
  395.                                         checksum = checksum - 255;
  396.                         }
  397.                         data[130] = checksum;
  398.  
  399.                         buffer_offset = 0;
  400.                         buffer_size = 131;
  401.  
  402.                         DELAYED_SEROUT_IRQ = 1;
  403.                         DELAYED_XMTDONE_IRQ = 3;
  404.                         DELAYED_SERIN_IRQ = 150;        /* BEFORE 7 */
  405.                 }
  406.                 break;
  407.         case 'S':                                       /* Status */
  408. #ifdef DEBUG
  409.                 printf("Status command\n");
  410. #endif
  411.                 data[0] = 0x41;                 /* ACK */
  412.                 data[1] = 0x43;                 /* OPERATION COMPLETE */
  413.                 data[2] = 0x10;                 /* 2ea */
  414.                 data[3] = 0x00;                 /* 2eb */
  415.                 data[4] = 0x01;                 /* 2ec */
  416.                 data[5] = 0x00;                 /* 2ed */
  417.                 data[6] = 0x11;                 /* Checksum */
  418.                 buffer_offset = 0;
  419.                 buffer_size = 7;
  420.  
  421.                 DELAYED_SEROUT_IRQ = 1;
  422.                 DELAYED_XMTDONE_IRQ = 5;
  423.                 DELAYED_SERIN_IRQ = 150;
  424.                 break;
  425.         case 'W':                                       /* Write with verify */
  426.         case 'P':                                       /* Put without verify */
  427. #ifdef DEBUG
  428.                 printf("Put or Write command\n");
  429. #endif
  430.                 data[0] = 0x41;                 /* ACK */
  431.                 buffer_offset = 0;
  432.                 buffer_size = 1;
  433.                 DELAYED_SEROUT_IRQ = 1;
  434.                 DELAYED_XMTDONE_IRQ = 3;
  435.                 DELAYED_SERIN_IRQ = 150;        /* BEFORE 7 */
  436.                 sio_state = SIO_Put;
  437.                 break;
  438.         case '!':                                       /* Format */
  439.                 printf("Format command\n");
  440.                 break;
  441.         case 'T':                                       /* Read Address */
  442.                 printf("Read Address command\n");
  443.                 break;
  444.         case 'Q':                                       /* Read Spin */
  445.                 printf("Read Spin command\n");
  446.                 break;
  447.         case 'U':                                       /* Motor On */
  448.                 printf("Motor On command\n");
  449.                 break;
  450.         case 'V':                                       /* Verify Sector */
  451.                 printf("Verify Sector\n");
  452.                 break;
  453.         default:
  454.                 printf("Unknown command: %02x\n", cmd_frame[1]);
  455.                 printf("Command frame: %02x %02x %02x %02x %02x\n",
  456.                            cmd_frame[0], cmd_frame[1], cmd_frame[2],
  457.                            cmd_frame[3], cmd_frame[4]);
  458.                 buffer_offset = 0;
  459.                 buffer_size = 0;
  460.                 DELAYED_XMTDONE_IRQ = 3;
  461.                 break;
  462.         }
  463. }
  464.  
  465. void SIO_SEROUT(unsigned char byte, int cmd)
  466. {
  467.         checksum += (unsigned char) byte;
  468.         while (checksum > 255)
  469.                 checksum = checksum - 255;
  470.  
  471. #ifdef DEBUG
  472.         printf("SIO_SEROUT: byte = %x, checksum = %x, cmd = %d\n",
  473.                    byte, checksum, cmd);
  474. #endif
  475.  
  476.         if (cmd) {
  477.                 cmd_frame[ncmd++] = byte;
  478.                 if (ncmd == 5) {
  479.                         Command_Frame();
  480.  
  481.                         offst = 0;
  482.                         checksum = 0;
  483.                         ncmd = 0;
  484.                 }
  485.                 else {
  486.                         DELAYED_SEROUT_IRQ = 1;
  487.                 }
  488.  
  489.                 if (cmd_frame[0] == 0)
  490.                         ncmd = 0;
  491.         }
  492.         else if (sio_state == SIO_Put) {
  493.                 data[buffer_offset++] = byte;
  494.                 if (buffer_offset == 130) {
  495.                         int sector;
  496.                         int dskno;
  497.                         int i;
  498.  
  499.                         checksum = 0;
  500.  
  501.                         for (i = 1; i < 129; i++) {
  502.                                 checksum += (unsigned char) data[i];
  503.                                 while (checksum > 255)
  504.                                         checksum = checksum - 255;
  505.                         }
  506.  
  507.                         if (checksum != data[129]) {
  508.                                 printf("Direct SIO Write Error\n");
  509.                                 printf("Calculated Checksum = %x\n", checksum);
  510.                                 printf("Actual Checksum = %x\n", data[129]);
  511.                                 exit(1);
  512.                         }
  513.  
  514.                         dskno = cmd_frame[0] - 0x31;
  515.                         sector = cmd_frame[2] + cmd_frame[3] * 256;
  516.  
  517. #ifdef DEBUG
  518.                         printf("Sector: %d(%x)\n", sector, sector);
  519. #endif
  520.  
  521.                         SeekSector(dskno, sector);
  522.  
  523.                         write(disk[dskno], &data[1], 128);
  524.                         data[buffer_offset] = 0x41;             /* ACK */
  525.                         data[buffer_offset + 1] = 0x43;         /* OPERATION COMPLETE */
  526.                         buffer_size = buffer_offset + 2;
  527.                         DELAYED_SEROUT_IRQ = 1;
  528.                         DELAYED_XMTDONE_IRQ = 3;
  529.                         DELAYED_SERIN_IRQ = 7;
  530.                         DELAYED_XMTDONE_IRQ = 5;
  531.                         DELAYED_SERIN_IRQ = 150;
  532.                 }
  533.                 else {
  534.                         DELAYED_SEROUT_IRQ = 4;
  535.                 }
  536.         }
  537.         else {
  538.                 DELAYED_SEROUT_IRQ = 1;
  539.                 ncmd = 0;
  540.         }
  541. }
  542.  
  543. int SIO_SERIN(void)
  544. {
  545.         int byte = 0;                           /* initialise the value, just for sure */
  546.  
  547.         if (buffer_offset < buffer_size) {
  548.                 byte = (int) data[buffer_offset++];
  549.  
  550. #ifdef DEBUG
  551.                 printf("SERIN: byte = %x\n", byte);
  552. #endif
  553.  
  554.                 if (buffer_offset < buffer_size) {
  555. #ifdef DEBUG
  556.                         printf("Setting SERIN Interrupt again\n");
  557. #endif
  558.                         DELAYED_SERIN_IRQ = 3;
  559.                         DELAYED_SERIN_IRQ = 4;
  560.                 }
  561.         }
  562.  
  563.         return byte;
  564. }
  565.