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