root/drivers/scsi/aic7xxx_asm.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. error
  2. Malloc
  3. Realloc
  4. Strdup
  5. define
  6. lookup
  7. patch
  8. backpatch
  9. output
  10. getl
  11. eval_operand
  12. eval_sdi
  13. eval_addr
  14. crack
  15. assemble
  16. main

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

/* [previous][next][first][last][top][bottom][index][help] */