1 /* 2 * Aic7xxx SCSI host adapter firmware asssembler 3 * 4 * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions, and the following disclaimer, 12 * without modification, immediately at the beginning of the file. 13 * 2. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * Alternatively, this software may be distributed under the terms of the 17 * GNU Public License ("GPL"). 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 #include <sys/types.h> 34 #include <sys/mman.h> 35 36 #include <ctype.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <sysexits.h> 41 #include <unistd.h> 42 43 #include "aicasm.h" 44 #include "aicasm_symbol.h" 45 #include "aicasm_insformat.h" 46 47 typedef struct patch { 48 STAILQ_ENTRY(patch) links; 49 int patch_func; 50 u_int begin; 51 u_int skip_instr; 52 u_int skip_patch; 53 } patch_t; 54 55 STAILQ_HEAD(patch_list, patch) patches; 56 57 static void usage(void); 58 static void back_patch(void); 59 static void output_code(void); 60 static void output_listing(char *ifilename); 61 static void dump_scope(scope_t *scope); 62 static void emit_patch(scope_t *scope, int patch); 63 static int check_patch(patch_t **start_patch, int start_instr, 64 int *skip_addr, int *func_vals); 65 66 struct path_list search_path; 67 int includes_search_curdir; 68 char *appname; 69 FILE *ofile; 70 char *ofilename; 71 char *regfilename; 72 FILE *regfile; 73 char *listfilename; 74 FILE *listfile; 75 76 static STAILQ_HEAD(,instruction) seq_program; 77 struct scope_list scope_stack; 78 symlist_t patch_functions; 79 80 #if DEBUG 81 extern int yy_flex_debug; 82 extern int yydebug; 83 #endif 84 extern FILE *yyin; 85 extern int yyparse __P((void)); 86 87 int 88 main(argc, argv) 89 int argc; 90 char *argv[]; 91 { 92 extern char *optarg; 93 extern int optind; 94 int ch; 95 int retval; 96 char *inputfilename; 97 scope_t *sentinal; 98 99 STAILQ_INIT(&patches); 100 SLIST_INIT(&search_path); 101 STAILQ_INIT(&seq_program); 102 SLIST_INIT(&scope_stack); 103 104 /* Set Sentinal scope node */ 105 sentinal = scope_alloc(); 106 sentinal->type = SCOPE_ROOT; 107 108 includes_search_curdir = 1; 109 appname = *argv; 110 regfile = NULL; 111 listfile = NULL; 112 #if DEBUG 113 yy_flex_debug = 0; 114 yydebug = 0; 115 #endif 116 while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) { 117 switch(ch) { 118 case 'd': 119 #if DEBUG 120 if (strcmp(optarg, "s") == 0) { 121 yy_flex_debug = 1; 122 } else if (strcmp(optarg, "p") == 0) { 123 yydebug = 1; 124 } else { 125 fprintf(stderr, "%s: -d Requires either an " 126 "'s' or 'p' argument\n", appname); 127 usage(); 128 } 129 #else 130 stop("-d: Assembler not built with debugging " 131 "information", EX_SOFTWARE); 132 #endif 133 break; 134 case 'l': 135 /* Create a program listing */ 136 if ((listfile = fopen(optarg, "w")) == NULL) { 137 perror(optarg); 138 stop(NULL, EX_CANTCREAT); 139 } 140 listfilename = optarg; 141 break; 142 case 'n': 143 /* Don't complain about the -nostdinc directrive */ 144 if (strcmp(optarg, "ostdinc")) { 145 fprintf(stderr, "%s: Unknown option -%c%s\n", 146 appname, ch, optarg); 147 usage(); 148 /* NOTREACHED */ 149 } 150 break; 151 case 'o': 152 if ((ofile = fopen(optarg, "w")) == NULL) { 153 perror(optarg); 154 stop(NULL, EX_CANTCREAT); 155 } 156 ofilename = optarg; 157 break; 158 case 'r': 159 if ((regfile = fopen(optarg, "w")) == NULL) { 160 perror(optarg); 161 stop(NULL, EX_CANTCREAT); 162 } 163 regfilename = optarg; 164 break; 165 case 'I': 166 { 167 path_entry_t include_dir; 168 169 if (strcmp(optarg, "-") == 0) { 170 if (includes_search_curdir == 0) { 171 fprintf(stderr, "%s: Warning - '-I-' " 172 "specified multiple " 173 "times\n", appname); 174 } 175 includes_search_curdir = 0; 176 for (include_dir = search_path.slh_first; 177 include_dir != NULL; 178 include_dir = include_dir->links.sle_next) 179 /* 180 * All entries before a '-I-' only 181 * apply to includes specified with 182 * quotes instead of "<>". 183 */ 184 include_dir->quoted_includes_only = 1; 185 } else { 186 include_dir = 187 (path_entry_t)malloc(sizeof(*include_dir)); 188 if (include_dir == NULL) { 189 perror(optarg); 190 stop(NULL, EX_OSERR); 191 } 192 include_dir->directory = strdup(optarg); 193 if (include_dir->directory == NULL) { 194 perror(optarg); 195 stop(NULL, EX_OSERR); 196 } 197 include_dir->quoted_includes_only = 0; 198 SLIST_INSERT_HEAD(&search_path, include_dir, 199 links); 200 } 201 break; 202 } 203 case '?': 204 default: 205 usage(); 206 /* NOTREACHED */ 207 } 208 } 209 argc -= optind; 210 argv += optind; 211 212 if (argc != 1) { 213 fprintf(stderr, "%s: No input file specifiled\n", appname); 214 usage(); 215 /* NOTREACHED */ 216 } 217 218 symtable_open(); 219 inputfilename = *argv; 220 include_file(*argv, SOURCE_FILE); 221 retval = yyparse(); 222 if (retval == 0) { 223 if (SLIST_FIRST(&scope_stack) == NULL 224 || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { 225 stop("Unterminated conditional expression", 226 EX_DATAERR); 227 /* NOTREACHED */ 228 } 229 230 /* Process outmost scope */ 231 process_scope(SLIST_FIRST(&scope_stack)); 232 /* 233 * Decend the tree of scopes and insert/emit 234 * patches as appropriate. We perform a depth first 235 * tranversal, recursively handling each scope. 236 */ 237 /* start at the root scope */ 238 dump_scope(SLIST_FIRST(&scope_stack)); 239 240 /* Patch up forward jump addresses */ 241 back_patch(); 242 243 if (ofile != NULL) 244 output_code(); 245 if (regfile != NULL) { 246 symtable_dump(regfile); 247 } 248 if (listfile != NULL) 249 output_listing(inputfilename); 250 } 251 252 stop(NULL, 0); 253 /* NOTREACHED */ 254 return (0); 255 } 256 257 static void 258 usage() 259 { 260 261 (void)fprintf(stderr, 262 "usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file] 263 [-r register_output_file] [-l program_list_file] 264 input_file\n", 265 appname); 266 exit(EX_USAGE); 267 } 268 269 static void 270 back_patch() 271 { 272 struct instruction *cur_instr; 273 274 for(cur_instr = seq_program.stqh_first; 275 cur_instr != NULL; 276 cur_instr = cur_instr->links.stqe_next) { 277 if (cur_instr->patch_label != NULL) { 278 struct ins_format3 *f3_instr; 279 u_int address; 280 281 if (cur_instr->patch_label->type != LABEL) { 282 char buf[255]; 283 284 snprintf(buf, sizeof(buf), 285 "Undefined label %s", 286 cur_instr->patch_label->name); 287 stop(buf, EX_DATAERR); 288 /* NOTREACHED */ 289 } 290 f3_instr = &cur_instr->format.format3; 291 address = f3_instr->address; 292 address += cur_instr->patch_label->info.linfo->address; 293 f3_instr->address = address; 294 } 295 } 296 } 297 298 static void 299 output_code() 300 { 301 struct instruction *cur_instr; 302 patch_t *cur_patch; 303 symbol_node_t *cur_node; 304 int instrcount; 305 306 instrcount = 0; 307 fprintf(ofile, 308 "/* 309 * DO NOT EDIT - This file is automatically generated. 310 */\n"); 311 312 fprintf(ofile, "static uint8_t seqprog[] = {\n"); 313 for(cur_instr = seq_program.stqh_first; 314 cur_instr != NULL; 315 cur_instr = cur_instr->links.stqe_next) { 316 317 fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n", 318 #if BYTE_ORDER == LITTLE_ENDIAN 319 cur_instr->format.bytes[0], 320 cur_instr->format.bytes[1], 321 cur_instr->format.bytes[2], 322 cur_instr->format.bytes[3]); 323 #else 324 cur_instr->format.bytes[3], 325 cur_instr->format.bytes[2], 326 cur_instr->format.bytes[1], 327 cur_instr->format.bytes[0]); 328 #endif 329 instrcount++; 330 } 331 fprintf(ofile, "};\n\n"); 332 333 /* 334 * Output patch information. Patch functions first. 335 */ 336 for(cur_node = SLIST_FIRST(&patch_functions); 337 cur_node != NULL; 338 cur_node = SLIST_NEXT(cur_node,links)) { 339 fprintf(ofile, 340 "static int ahc_patch%d_func(struct ahc_softc *ahc); 341 342 static int 343 ahc_patch%d_func(struct ahc_softc *ahc) 344 { 345 return (%s); 346 }\n\n", 347 cur_node->symbol->info.condinfo->func_num, 348 cur_node->symbol->info.condinfo->func_num, 349 cur_node->symbol->name); 350 } 351 352 fprintf(ofile, 353 "typedef int patch_func_t __P((struct ahc_softc *)); 354 struct patch { 355 patch_func_t *patch_func; 356 uint32_t begin :10, 357 skip_instr :10, 358 skip_patch :12; 359 } patches[] = {\n"); 360 361 for(cur_patch = STAILQ_FIRST(&patches); 362 cur_patch != NULL; 363 cur_patch = STAILQ_NEXT(cur_patch,links)) { 364 fprintf(ofile, "\t{ ahc_patch%d_func, %d, %d, %d },\n", 365 cur_patch->patch_func, cur_patch->begin, 366 cur_patch->skip_instr, cur_patch->skip_patch); 367 } 368 369 fprintf(ofile, "\n};\n"); 370 371 fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); 372 } 373 374 static void 375 dump_scope(scope_t *scope) 376 { 377 scope_t *cur_scope; 378 379 /* 380 * Emit the first patch for this scope 381 */ 382 emit_patch(scope, 0); 383 384 /* 385 * Dump each scope within this one. 386 */ 387 cur_scope = TAILQ_FIRST(&scope->inner_scope); 388 389 while (cur_scope != NULL) { 390 391 dump_scope(cur_scope); 392 393 cur_scope = TAILQ_NEXT(cur_scope, scope_links); 394 } 395 396 /* 397 * Emit the second, closing, patch for this scope 398 */ 399 emit_patch(scope, 1); 400 } 401 402 void 403 emit_patch(scope_t *scope, int patch) 404 { 405 patch_info_t *pinfo; 406 patch_t *new_patch; 407 408 pinfo = &scope->patches[patch]; 409 410 if (pinfo->skip_instr == 0) 411 /* No-Op patch */ 412 return; 413 414 new_patch = (patch_t *)malloc(sizeof(*new_patch)); 415 416 if (new_patch == NULL) 417 stop("Could not malloc patch structure", EX_OSERR); 418 419 memset(new_patch, 0, sizeof(*new_patch)); 420 421 if (patch == 0) { 422 new_patch->patch_func = scope->func_num; 423 new_patch->begin = scope->begin_addr; 424 } else { 425 new_patch->patch_func = 0; 426 new_patch->begin = scope->end_addr; 427 } 428 new_patch->skip_instr = pinfo->skip_instr; 429 new_patch->skip_patch = pinfo->skip_patch; 430 STAILQ_INSERT_TAIL(&patches, new_patch, links); 431 } 432 433 void 434 output_listing(char *ifilename) 435 { 436 char buf[1024]; 437 FILE *ifile; 438 struct instruction *cur_instr; 439 patch_t *cur_patch; 440 symbol_node_t *cur_func; 441 int *func_values; 442 int instrcount; 443 int instrptr; 444 int line; 445 int func_count; 446 int skip_addr; 447 448 instrcount = 0; 449 instrptr = 0; 450 line = 1; 451 skip_addr = 0; 452 if ((ifile = fopen(ifilename, "r")) == NULL) { 453 perror(ifilename); 454 stop(NULL, EX_DATAERR); 455 } 456 457 /* 458 * Determine which options to apply to this listing. 459 */ 460 for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions); 461 cur_func != NULL; 462 cur_func = SLIST_NEXT(cur_func, links)) 463 func_count++; 464 465 if (func_count != 0) { 466 func_values = (int *)malloc(func_count * sizeof(int)); 467 468 if (func_values == NULL) 469 stop("Could not malloc", EX_OSERR); 470 471 func_values[0] = 0; /* FALSE func */ 472 func_count--; 473 474 /* 475 * Ask the user to fill in the return values for 476 * the rest of the functions. 477 */ 478 479 480 for (cur_func = SLIST_FIRST(&patch_functions); 481 cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL; 482 cur_func = SLIST_NEXT(cur_func, links), func_count--) { 483 int input; 484 485 fprintf(stdout, "\n(%s)\n", cur_func->symbol->name); 486 fprintf(stdout, 487 "Enter the return value for " 488 "this expression[T/F]:"); 489 490 while (1) { 491 492 input = getchar(); 493 input = toupper(input); 494 495 if (input == 'T') { 496 func_values[func_count] = 1; 497 break; 498 } else if (input == 'F') { 499 func_values[func_count] = 0; 500 break; 501 } 502 } 503 if (isatty(fileno(stdin)) == 0) 504 putchar(input); 505 } 506 fprintf(stdout, "\nThanks!\n"); 507 } 508 509 /* Now output the listing */ 510 cur_patch = STAILQ_FIRST(&patches); 511 for(cur_instr = STAILQ_FIRST(&seq_program); 512 cur_instr != NULL; 513 cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) { 514 515 if (check_patch(&cur_patch, instrcount, 516 &skip_addr, func_values) == 0) { 517 /* Don't count this instruction as it is in a patch 518 * that was removed. 519 */ 520 continue; 521 } 522 523 while (line < cur_instr->srcline) { 524 fgets(buf, sizeof(buf), ifile); 525 fprintf(listfile, "\t\t%s", buf); 526 line++; 527 } 528 fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, 529 #if BYTE_ORDER == LITTLE_ENDIAN 530 cur_instr->format.bytes[0], 531 cur_instr->format.bytes[1], 532 cur_instr->format.bytes[2], 533 cur_instr->format.bytes[3]); 534 #else 535 cur_instr->format.bytes[3], 536 cur_instr->format.bytes[2], 537 cur_instr->format.bytes[1], 538 cur_instr->format.bytes[0]); 539 #endif 540 fgets(buf, sizeof(buf), ifile); 541 fprintf(listfile, "\t%s", buf); 542 line++; 543 instrptr++; 544 } 545 /* Dump the remainder of the file */ 546 while(fgets(buf, sizeof(buf), ifile) != NULL) 547 fprintf(listfile, "\t\t%s", buf); 548 549 fclose(ifile); 550 } 551 552 static int 553 check_patch(patch_t **start_patch, int start_instr, 554 int *skip_addr, int *func_vals) 555 { 556 patch_t *cur_patch; 557 558 cur_patch = *start_patch; 559 560 while (cur_patch != NULL && start_instr == cur_patch->begin) { 561 if (func_vals[cur_patch->patch_func] == 0) { 562 int skip; 563 564 /* Start rejecting code */ 565 *skip_addr = start_instr + cur_patch->skip_instr; 566 for (skip = cur_patch->skip_patch; 567 skip > 0 && cur_patch != NULL; 568 skip--) 569 cur_patch = STAILQ_NEXT(cur_patch, links); 570 } else { 571 /* Accepted this patch. Advance to the next 572 * one and wait for our intruction pointer to 573 * hit this point. 574 */ 575 cur_patch = STAILQ_NEXT(cur_patch, links); 576 } 577 } 578 579 *start_patch = cur_patch; 580 if (start_instr < *skip_addr) 581 /* Still skipping */ 582 return (0); 583 584 return (1); 585 } 586 587 /* 588 * Print out error information if appropriate, and clean up before 589 * terminating the program. 590 */ 591 void 592 stop(string, err_code) 593 const char *string; 594 int err_code; 595 { 596 if (string != NULL) { 597 fprintf(stderr, "%s: ", appname); 598 if (yyfilename != NULL) { 599 fprintf(stderr, "Stopped at file %s, line %d - ", 600 yyfilename, yylineno); 601 } 602 fprintf(stderr, "%s\n", string); 603 } 604 605 if (ofile != NULL) { 606 fclose(ofile); 607 if (err_code != 0) { 608 fprintf(stderr, "%s: Removing %s due to error\n", 609 appname, ofilename); 610 unlink(ofilename); 611 } 612 } 613 614 if (regfile != NULL) { 615 fclose(regfile); 616 if (err_code != 0) { 617 fprintf(stderr, "%s: Removing %s due to error\n", 618 appname, regfilename); 619 unlink(regfilename); 620 } 621 } 622 623 if (listfile != NULL) { 624 fclose(listfile); 625 if (err_code != 0) { 626 fprintf(stderr, "%s: Removing %s due to error\n", 627 appname, listfilename); 628 unlink(listfilename); 629 } 630 } 631 632 symlist_free(&patch_functions); 633 symtable_close(); 634 635 exit(err_code); 636 } 637 638 struct instruction * 639 seq_alloc() 640 { 641 struct instruction *new_instr; 642 643 new_instr = (struct instruction *)malloc(sizeof(struct instruction)); 644 if (new_instr == NULL) 645 stop("Unable to malloc instruction object", EX_SOFTWARE); 646 memset(new_instr, 0, sizeof(*new_instr)); 647 STAILQ_INSERT_TAIL(&seq_program, new_instr, links); 648 new_instr->srcline = yylineno; 649 return new_instr; 650 } 651 652 scope_t * 653 scope_alloc() 654 { 655 scope_t *new_scope; 656 657 new_scope = (scope_t *)malloc(sizeof(scope_t)); 658 if (new_scope == NULL) 659 stop("Unable to malloc scope object", EX_SOFTWARE); 660 memset(new_scope, 0, sizeof(*new_scope)); 661 TAILQ_INIT(&new_scope->inner_scope); 662 663 if (SLIST_FIRST(&scope_stack) != NULL) { 664 TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope, 665 new_scope, scope_links); 666 } 667 /* This patch is now the current scope */ 668 SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links); 669 return new_scope; 670 } 671 672 void 673 process_scope(scope_t *scope) 674 { 675 /* 676 * We are "leaving" this scope. We should now have 677 * enough information to process the lists of scopes 678 * we encapsulate. 679 */ 680 scope_t *cur_scope; 681 u_int skip_patch_count; 682 u_int skip_instr_count; 683 684 cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq); 685 skip_patch_count = 0; 686 skip_instr_count = 0; 687 while (cur_scope != NULL) { 688 u_int patch0_patch_skip; 689 690 patch0_patch_skip = 0; 691 switch (cur_scope->type) { 692 case SCOPE_IF: 693 case SCOPE_ELSE_IF: 694 if (skip_instr_count != 0) { 695 /* Create a tail patch */ 696 patch0_patch_skip++; 697 cur_scope->patches[1].skip_patch = 698 skip_patch_count + 1; 699 cur_scope->patches[1].skip_instr = 700 skip_instr_count; 701 } 702 703 /* Count Head patch */ 704 patch0_patch_skip++; 705 706 /* Count any patches contained in our inner scope */ 707 patch0_patch_skip += cur_scope->inner_scope_patches; 708 709 cur_scope->patches[0].skip_patch = patch0_patch_skip; 710 cur_scope->patches[0].skip_instr = 711 cur_scope->end_addr - cur_scope->begin_addr; 712 713 skip_instr_count += cur_scope->patches[0].skip_instr; 714 715 skip_patch_count += patch0_patch_skip; 716 if (cur_scope->type == SCOPE_IF) { 717 scope->inner_scope_patches += skip_patch_count; 718 skip_patch_count = 0; 719 skip_instr_count = 0; 720 } 721 break; 722 case SCOPE_ELSE: 723 /* Count any patches contained in our innter scope */ 724 skip_patch_count += cur_scope->inner_scope_patches; 725 726 skip_instr_count += cur_scope->end_addr 727 - cur_scope->begin_addr; 728 break; 729 case SCOPE_ROOT: 730 stop("Unexpected scope type encountered", EX_SOFTWARE); 731 /* NOTREACHED */ 732 } 733 734 cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links); 735 } 736 } 737