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

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