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