home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / kernel-s / v1.1 / scsi / 274x / aha274x / aic7770.c < prev    next >
C/C++ Source or Header  |  1995-10-10  |  12KB  |  585 lines

  1. /*
  2.  * Adaptec 274x device driver for Linux.
  3.  * Copyright (c) 1994 The University of Calgary Department of Computer Science.
  4.  * 
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  * 
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  Comments are started by `#' and continue to the end of the line; lines
  20.  *  may be of the form:
  21.  *
  22.  *    <label>*
  23.  *    <label>*  <undef-sym> = <value>
  24.  *    <label>*  <opcode> <operand>*
  25.  *
  26.  *  A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
  27.  *  are token separators.
  28.  */
  29.  
  30. #define _POSIX_SOURCE    1
  31. #define _POSIX_C_SOURCE    2
  32.  
  33. #include <ctype.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #include <unistd.h>
  38.  
  39. #define MEMORY        512        /* 2^9 29-bit words */
  40. #define MAXLINE        1024
  41. #define MAXTOKEN    32
  42. #define ADOTOUT        "a.out"
  43. #define NOVALUE        -1
  44.  
  45. /*
  46.  *  AIC-7770 register definitions
  47.  */
  48. #define R_SINDEX    0x65
  49. #define R_ALLONES    0x69
  50. #define R_ALLZEROS    0x6a
  51. #define R_NONE        0x6a
  52.  
  53. static
  54. char sccsid[] =
  55.     "@(#)aic7770.c 1.10 94/07/22 jda";
  56.  
  57. int debug;
  58. int lineno, LC;
  59. char *filename;
  60. FILE *ifp, *ofp;
  61. unsigned char M[MEMORY][4];
  62.  
  63. void error(char *s)
  64. {
  65.     fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
  66.     exit(EXIT_FAILURE);
  67. }
  68.  
  69. void *Malloc(size_t size)
  70. {
  71.     void *p = malloc(size);
  72.     if (!p)
  73.         error("out of memory");
  74.     return(p);
  75. }
  76.  
  77. void *Realloc(void *ptr, size_t size)
  78. {
  79.     void *p = realloc(ptr, size);
  80.     if (!p)
  81.         error("out of memory");
  82.     return(p);
  83. }
  84.  
  85. char *Strdup(char *s)
  86. {
  87.     char *p = (char *)Malloc(strlen(s) + 1);
  88.     strcpy(p, s);
  89.     return(p);
  90. }
  91.  
  92. typedef struct sym_t {
  93.     struct sym_t *next;        /* MUST BE FIRST */
  94.     char *name;
  95.     int value;
  96.     int npatch, *patch;
  97. } sym_t;
  98.  
  99. sym_t *head;
  100.  
  101. void define(char *name, int value)
  102. {
  103.     sym_t *p, *q;
  104.  
  105.     for (p = head, q = (sym_t *)&head; p; p = p->next) {
  106.         if (!strcmp(p->name, name))
  107.             error("redefined symbol");
  108.         q = p;
  109.     }
  110.  
  111.     p = q->next = (sym_t *)Malloc(sizeof(sym_t));
  112.     p->next = NULL;
  113.     p->name = Strdup(name);
  114.     p->value = value;
  115.     p->npatch = 0;
  116.     p->patch = NULL;
  117.  
  118.     if (debug) {
  119.         fprintf(stderr, "\"%s\" ", p->name);
  120.         if (p->value != NOVALUE)
  121.             fprintf(stderr, "defined as 0x%x\n", p->value);
  122.         else
  123.             fprintf(stderr, "undefined\n");
  124.     }
  125. }
  126.  
  127. sym_t *lookup(char *name)
  128. {
  129.     sym_t *p;
  130.  
  131.     for (p = head; p; p = p->next)
  132.         if (!strcmp(p->name, name))
  133.             return(p);
  134.     return(NULL);
  135. }
  136.  
  137. void patch(sym_t *p, int location)
  138. {
  139.     p->npatch += 1;
  140.     p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
  141.  
  142.     p->patch[p->npatch - 1] = location;
  143. }
  144.  
  145. void backpatch(void)
  146. {
  147.     int i;
  148.     sym_t *p;
  149.  
  150.     for (p = head; p; p = p->next) {
  151.  
  152.         if (p->value == NOVALUE) {
  153.             fprintf(stderr,
  154.                 "%s: undefined symbol \"%s\"\n",
  155.                 filename, p->name);
  156.             exit(EXIT_FAILURE);
  157.         }
  158.  
  159.         if (p->npatch) {
  160.             if (debug)
  161.                 fprintf(stderr,
  162.                     "\"%s\" (0x%x) patched at",
  163.                     p->name, p->value);
  164.  
  165.             for (i = 0; i < p->npatch; i++) {
  166.                 M[p->patch[i]][0] &= ~1;
  167.                 M[p->patch[i]][0] |= ((p->value >> 8) & 1);
  168.                 M[p->patch[i]][1] = p->value & 0xff;
  169.  
  170.                 if (debug)
  171.                     fprintf(stderr, " 0x%x", p->patch[i]);
  172.             }
  173.  
  174.             if (debug)
  175.                 fputc('\n', stderr);
  176.         }
  177.     }
  178. }
  179.  
  180. /*
  181.  *  Output words in byte-reversed order (least significant first)
  182.  *  since the sequencer RAM is loaded that way.
  183.  */
  184. void output(FILE *fp)
  185. {
  186.     int i;
  187.  
  188.     for (i = 0; i < LC; i++)
  189.         fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
  190.             M[i][3],
  191.             M[i][2],
  192.             M[i][1],
  193.             M[i][0]);
  194. }
  195.  
  196. char **getl(int *n)
  197. {
  198.     int i;
  199.     char *p;
  200.     static char buf[MAXLINE];
  201.     static char *a[MAXTOKEN];
  202.  
  203.     i = 0;
  204.  
  205.     while (fgets(buf, sizeof(buf), ifp)) {
  206.  
  207.         lineno += 1;
  208.  
  209.         if (buf[strlen(buf)-1] != '\n')
  210.             error("line too long");
  211.  
  212.         p = strchr(buf, '#');
  213.         if (p)
  214.             *p = '\0';
  215.  
  216.         for (p = strtok(buf, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
  217.             if (i < MAXTOKEN-1)
  218.                 a[i++] = p;
  219.             else
  220.                 error("too many tokens");
  221.         if (i) {
  222.             *n = i;
  223.             return(a);
  224.         }
  225.     }
  226.     return(NULL);
  227. }
  228.  
  229. #define A    0x8000        /* `A'ccumulator ok */
  230. #define I    0x4000        /* use as immediate value */
  231. #define SL    0x2000        /* shift left */
  232. #define SR    0x1000        /* shift right */
  233. #define RL    0x0800        /* rotate left */
  234. #define RR    0x0400        /* rotate right */
  235. #define LO    0x8000        /* lookup: ori-{jmp,jc,jnc,call} */
  236. #define LA    0x4000        /* lookup: and-{jz,jnz} */
  237. #define LX    0x2000        /* lookup: xor-{je,jne} */
  238. #define NA    -1        /* not applicable */
  239.  
  240. struct {
  241.     char *name;
  242.     int n;            /* number of operands, including opcode */
  243.     unsigned int op;    /* immediate or L?|pos_from_0 */
  244.     unsigned int dest;    /* NA, pos_from_0, or I|immediate */
  245.     unsigned int src;    /* NA, pos_from_0, or I|immediate */
  246.     unsigned int imm;    /* pos_from_0, A|pos_from_0, or I|immediate */
  247.     unsigned int addr;    /* NA or pos_from_0 */
  248.     int fmt;        /* instruction format - 1, 2, or 3 */
  249. } instr[] = {
  250. /*
  251.  *        N  OP     DEST        SRC        IMM    ADDR FMT
  252.  */
  253.     "mov",    3, 1,     1,        2,        I|0xff,    NA,  1,
  254.     "mov",    4, LO|2, NA,        1,        I|0,    3,   3,
  255.     "mvi",    3, 0,     1,        I|R_ALLZEROS,    A|2,    NA,  1,
  256.     "mvi",    4, LO|2, NA,        I|R_ALLZEROS,    1,    3,   3,
  257.     "not",    2, 2,     1,        1,        I|0xff,    NA,  1,
  258.     "not",    3, 2,     1,        2,        I|0xff,    NA,  1,
  259.     "and",    3, 1,     1,        1,        A|2,    NA,  1,
  260.     "and",  4, 1,     1,        3,        A|2,    NA,  1,
  261.     "or",    3, 0,     1,        1,        A|2,    NA,  1,
  262.     "or",    4, 0,     1,        3,        A|2,    NA,  1,
  263.     "or",    5, LO|3, NA,        1,        2,    4,   3,
  264.     "xor",    3, 2,     1,        1,        A|2,    NA,  1,
  265.     "xor",    4, 2,     1,        3,        A|2,    NA,  1,
  266.     "nop",    1, 1,     I|R_NONE,    I|R_ALLZEROS,    I|0xff,    NA,  1,
  267.     "inc",    2, 3,     1,        1,        I|1,    NA,  1,
  268.     "inc",    3, 3,     1,        2,        I|1,    NA,  1,
  269.     "dec",    2, 3,     1,        1,        I|0xff,    NA,  1,
  270.     "dec",    3, 3,     1,        2,        I|0xff,    NA,  1,
  271.     "jmp",    2, LO|0, NA,        I|R_SINDEX,    I|0,    1,   3,
  272.     "jc",    2, LO|0, NA,        I|R_SINDEX,    I|0,    1,   3,
  273.     "jnc",    2, LO|0, NA,        I|R_SINDEX,    I|0,    1,   3,
  274.     "call",    2, LO|0, NA,        I|R_SINDEX,    I|0,    1,   3,
  275.     "test",    5, LA|3, NA,        1,        A|2,    4,   3,
  276.     "cmp",    5, LX|3, NA,        1,        A|2,    4,   3,
  277.     "ret",    1, 1,     I|R_NONE,    I|R_ALLZEROS,    I|0xff,    NA,  1,
  278.     "clc",    1, 3,     I|R_NONE,    I|R_ALLZEROS,    I|1,    NA,  1,
  279.     "clc",    4, 3,     2,        I|R_ALLZEROS,    A|3,    NA,  1,
  280.     "stc",    1, 3,     I|R_NONE,    I|R_ALLONES,    I|1,    NA,  1,
  281.     "stc",    2, 3,     1,        I|R_ALLONES,    I|1,    NA,  1,
  282.     "add",    3, 3,     1,        1,        A|2,    NA,  1,
  283.     "add",    4, 3,     1,        3,        A|2,    NA,  1,
  284.     "adc",    3, 4,     1,        1,        A|2,    NA,  1,
  285.     "adc",    4, 4,     1,        3,        A|2,    NA,  1,
  286.     "shl",    3, 5,     1,        1,        SL|2,    NA,  2,
  287.     "shl",    4, 5,     1,        2,        SL|3,    NA,  2,
  288.     "shr",    3, 5,     1,        1,        SR|2,    NA,  2,
  289.     "shr",    4, 5,     1,        2,        SR|3,    NA,  2,
  290.     "rol",    3, 5,     1,        1,        RL|2,    NA,  2,
  291.     "rol",    4, 5,     1,        2,        RL|3,    NA,  2,
  292.     "ror",    3, 5,     1,        1,        RR|2,    NA,  2,
  293.     "ror",    4, 5,     1,        2,        RR|3,    NA,  2,
  294.     /*
  295.      *  Extensions (note also that mvi allows A)
  296.      */
  297.      "clr",    2, 1,     1,        I|R_ALLZEROS,    I|0xff,    NA,  1,
  298.     0
  299. };
  300.  
  301. int eval_operand(char **a, int spec)
  302. {
  303.     int i;
  304.     unsigned int want = spec & (LO|LA|LX);
  305.  
  306.     static struct {
  307.         unsigned int what;
  308.         char *name;
  309.         int value;
  310.     } jmptab[] = {
  311.         LO,    "jmp",        8,
  312.         LO,    "jc",        9,
  313.         LO,    "jnc",        10,
  314.         LO,    "call",        11,
  315.         LA,    "jz",        15,
  316.         LA,    "jnz",        13,
  317.         LX,    "je",        14,
  318.         LX,    "jne",        12,
  319.     };
  320.  
  321.     spec &= ~(LO|LA|LX);
  322.  
  323.     for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
  324.         if (jmptab[i].what == want &&
  325.             !strcmp(jmptab[i].name, a[spec]))
  326.         {
  327.             return(jmptab[i].value);
  328.         }
  329.  
  330.     if (want)
  331.         error("invalid jump");
  332.  
  333.     return(spec);        /* "case 0" - no flags set */
  334. }
  335.  
  336. int eval_sdi(char **a, int spec)
  337. {
  338.     sym_t *p;
  339.     unsigned val;
  340.  
  341.     if (spec == NA)
  342.         return(NA);
  343.  
  344.     switch (spec & (A|I|SL|SR|RL|RR)) {
  345.         case SL:
  346.         case SR:
  347.         case RL:
  348.         case RR:
  349.         if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
  350.             val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
  351.         else {
  352.             p = lookup(a[spec &~ (SL|SR|RL|RR)]);
  353.             if (!p)
  354.                 error("undefined symbol used");
  355.             val = p->value;
  356.         }
  357.  
  358.         switch (spec & (SL|SR|RL|RR)) {        /* blech */
  359.             case SL:
  360.             if (val > 7)
  361.                 return(0xf0);
  362.             return(((val % 8) << 4) |
  363.                    (val % 8));
  364.             case SR:
  365.             if (val > 7)
  366.                 return(0xf0);
  367.             return(((val % 8) << 4) |
  368.                    (1 << 3) |
  369.                    ((8 - (val % 8)) % 8));
  370.             case RL:
  371.             return(val % 8);
  372.             case RR:
  373.             return((8 - (val % 8)) % 8);
  374.         }
  375.         case I:
  376.         return(spec &~ I);
  377.         case A:
  378.         /*
  379.          *  An immediate field of zero selects
  380.          *  the accumulator.  Vigorously object
  381.          *  if zero is given otherwise - it's
  382.          *  most likely an error.
  383.          */
  384.         spec &= ~A;
  385.         if (!strcmp("A", a[spec]))
  386.             return(0);
  387.         if (isdigit(*a[spec]) &&
  388.             strtol(a[spec], NULL, 0) == 0)
  389.         {
  390.             error("immediate value of zero selects accumulator");
  391.         }
  392.         /* falls through */
  393.         case 0:
  394.         if (isdigit(*a[spec]))
  395.             return(strtol(a[spec], NULL, 0));
  396.         p = lookup(a[spec]);
  397.         if (p)
  398.             return(p->value);
  399.         error("undefined symbol used");
  400.     }
  401.  
  402.     return(NA);        /* shut the compiler up */
  403. }
  404.  
  405. int eval_addr(char **a, int spec)
  406. {
  407.     sym_t *p;
  408.  
  409.     if (spec == NA)
  410.         return(NA);
  411.     if (isdigit(*a[spec]))
  412.         return(strtol(a[spec], NULL, 0));
  413.  
  414.     p = lookup(a[spec]);
  415.  
  416.     if (p) {
  417.         if (p->value != NOVALUE)
  418.             return(p->value);
  419.         patch(p, LC);
  420.     } else {
  421.         define(a[spec], NOVALUE);
  422.         p = lookup(a[spec]);
  423.         patch(p, LC);
  424.     }
  425.  
  426.     return(NA);        /* will be patched in later */
  427. }
  428.  
  429. int crack(char **a, int n)
  430. {
  431.     int i;
  432.     int I_imm, I_addr;
  433.     int I_op, I_dest, I_src, I_ret;
  434.  
  435.     /*
  436.      *  Check for "ret" at the end of the line; remove
  437.      *  it unless it's "ret" alone - we still want to
  438.      *  look it up in the table.
  439.      */
  440.     I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
  441.     if (I_ret && n > 1)
  442.         n -= 1;
  443.  
  444.     for (i = 0; instr[i].name; i++) {
  445.         /*
  446.          *  Look for match in table given constraints,
  447.          *  currently just the name and the number of
  448.          *  operands.
  449.          */
  450.         if (!strcmp(instr[i].name, *a) && instr[i].n == n)
  451.             break;
  452.     }
  453.     if (!instr[i].name)
  454.         error("unknown opcode or wrong number of operands");
  455.  
  456.     I_op    = eval_operand(a, instr[i].op);
  457.     I_src    = eval_sdi(a, instr[i].src);
  458.     I_imm    = eval_sdi(a, instr[i].imm);
  459.     I_dest    = eval_sdi(a, instr[i].dest);
  460.     I_addr    = eval_addr(a, instr[i].addr);
  461.  
  462.     switch (instr[i].fmt) {
  463.         case 1:
  464.         case 2:
  465.         M[LC][0] = (I_op << 1) | I_ret;
  466.         M[LC][1] = I_dest;
  467.         M[LC][2] = I_src;
  468.         M[LC][3] = I_imm;
  469.         break;
  470.         case 3:
  471.         if (I_ret)
  472.             error("illegal use of \"ret\"");
  473.         M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
  474.         M[LC][1] = I_addr & 0xff;
  475.         M[LC][2] = I_src;
  476.         M[LC][3] = I_imm;
  477.         break;
  478.     }
  479.  
  480.     return(1);        /* no two-byte instructions yet */
  481. }
  482.  
  483. #undef SL
  484. #undef SR
  485. #undef RL
  486. #undef RR
  487. #undef LX
  488. #undef LA
  489. #undef LO
  490. #undef I
  491. #undef A
  492.  
  493. void assemble(void)
  494. {
  495.     int n;
  496.     char **a;
  497.     sym_t *p;
  498.  
  499.     while ((a = getl(&n))) {
  500.  
  501.         while (a[0][strlen(*a)-1] == ':') {
  502.             a[0][strlen(*a)-1] = '\0';
  503.             p = lookup(*a);
  504.             if (p)
  505.                 p->value = LC;
  506.             else
  507.                 define(*a, LC);
  508.             a += 1;
  509.             n -= 1;
  510.         }
  511.  
  512.         if (!n)            /* line was all labels */
  513.             continue;
  514.  
  515.         if (n == 3 && !strcmp("VERSION", *a))
  516.             fprintf(ofp, "#define %s \"%s\"\n", a[1], a[2]);
  517.         else {
  518.             if (n == 3 && !strcmp("=", a[1]))
  519.                 define(*a, strtol(a[2], NULL, 0));
  520.             else
  521.                 LC += crack(a, n);
  522.         }
  523.     }
  524.  
  525.     backpatch();
  526.     output(ofp);
  527.  
  528.     if (debug)
  529.         output(stderr);
  530. }
  531.  
  532. int main(int argc, char **argv)
  533. {
  534.     int c;
  535.  
  536.     while ((c = getopt(argc, argv, "dho:")) != EOF) {
  537.         switch (c) {
  538.             case 'd':
  539.             debug = !0;
  540.             break;
  541.             case 'o':
  542.                 ofp = fopen(optarg, "w");
  543.             if (!ofp) {
  544.                 perror(optarg);
  545.                 exit(EXIT_FAILURE);
  546.             }
  547.             break;
  548.             case 'h':
  549.             printf("usage: %s [-d] [-ooutput] input\n", *argv);
  550.             exit(EXIT_SUCCESS);
  551.             case NULL:
  552.             /*
  553.              *  An impossible option to shut the compiler
  554.              *  up about sccsid[].
  555.              */
  556.             exit((int)sccsid);
  557.             default:
  558.             exit(EXIT_FAILURE);
  559.         }
  560.     }
  561.  
  562.     if (argc - optind != 1) {
  563.         fprintf(stderr, "%s: must have one input file\n", *argv);
  564.         exit(EXIT_FAILURE);
  565.     }
  566.     filename = argv[optind];
  567.  
  568.     ifp = fopen(filename, "r");
  569.     if (!ifp) {
  570.         perror(filename);
  571.         exit(EXIT_FAILURE);
  572.     }
  573.  
  574.     if (!ofp) {
  575.         ofp = fopen(ADOTOUT, "w");
  576.         if (!ofp) {
  577.             perror(ADOTOUT);
  578.             exit(EXIT_FAILURE);
  579.         }
  580.     }
  581.  
  582.     assemble();
  583.     exit(EXIT_SUCCESS);
  584. }
  585.