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

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