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