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