1 /* 2 * Aic7xxx SCSI host adapter firmware asssembler 3 * 4 * Copyright (c) 1997 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 immediately at the beginning of the file, without modification, 12 * this list of conditions, and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 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 * $Id: aic7xxx_asm.c,v 1.15 1997/03/16 07:08:15 gibbs Exp $ 32 */ 33 #include <sys/types.h> 34 #include <sys/mman.h> 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <sysexits.h> 40 #include <unistd.h> 41 42 #include "aic7xxx_asm.h" 43 #include "symbol.h" 44 #include "sequencer.h" 45 46 static void usage __P((void)); 47 static void back_patch __P((void)); 48 static void output_code __P((FILE *ofile)); 49 static void output_listing __P((FILE *listfile, char *ifilename, 50 char *options)); 51 static struct patch *next_patch __P((struct patch *cur_patch, int options, 52 int instrptr)); 53 54 struct path_list search_path; 55 int includes_search_curdir; 56 char *appname; 57 FILE *ofile; 58 char *ofilename; 59 60 static STAILQ_HEAD(,instruction) seq_program; 61 static STAILQ_HEAD(, patch) patch_list; 62 symlist_t patch_options; 63 64 #if DEBUG 65 extern int yy_flex_debug; 66 extern int yydebug; 67 #endif 68 extern FILE *yyin; 69 extern int yyparse __P((void)); 70 71 int 72 main(argc, argv) 73 int argc; 74 char *argv[]; 75 { 76 extern char *optarg; 77 extern int optind; 78 int ch; 79 int retval; 80 char *inputfilename; 81 char *regfilename; 82 FILE *regfile; 83 char *listfilename; 84 FILE *listfile; 85 char *options; 86 87 SLIST_INIT(&search_path); 88 STAILQ_INIT(&seq_program); 89 STAILQ_INIT(&patch_list); 90 SLIST_INIT(&patch_options); 91 includes_search_curdir = 1; 92 appname = *argv; 93 regfile = NULL; 94 listfile = NULL; 95 options = NULL; 96 #if DEBUG 97 yy_flex_debug = 0; 98 #endif 99 while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != EOF) { 100 switch(ch) { 101 case 'd': 102 #if DEBUG 103 if (strcmp(optarg, "s") == 0) 104 yy_flex_debug = 1; 105 else if (strcmp(optarg, "p") == 0) 106 yydebug = 1; 107 #else 108 stop("-d: Assembler not built with debugging " 109 "information", EX_SOFTWARE); 110 #endif 111 break; 112 case 'l': 113 /* Create a program listing */ 114 if ((listfile = fopen(optarg, "w")) == NULL) { 115 perror(optarg); 116 stop(NULL, EX_CANTCREAT); 117 } 118 listfilename = optarg; 119 break; 120 case 'n': 121 /* Don't complain about the -nostdinc directrive */ 122 if (strcmp(optarg, "ostdinc")) { 123 fprintf(stderr, "%s: Unknown option -%c%s\n", 124 appname, ch, optarg); 125 usage(); 126 /* NOTREACHED */ 127 } 128 break; 129 case 'o': 130 if ((ofile = fopen(optarg, "w")) == NULL) { 131 perror(optarg); 132 stop(NULL, EX_CANTCREAT); 133 } 134 ofilename = optarg; 135 break; 136 case 'O': 137 /* Patches to include in the listing */ 138 options = optarg; 139 break; 140 case 'r': 141 if ((regfile = fopen(optarg, "w")) == NULL) { 142 perror(optarg); 143 stop(NULL, EX_CANTCREAT); 144 } 145 regfilename = optarg; 146 break; 147 case 'I': 148 { 149 path_entry_t include_dir; 150 151 if (strcmp(optarg, "-") == 0) { 152 if (includes_search_curdir == 0) { 153 fprintf(stderr, "%s: Warning - '-I-' " 154 "specified multiple " 155 "times\n", appname); 156 } 157 includes_search_curdir = 0; 158 for (include_dir = search_path.slh_first; 159 include_dir != NULL; 160 include_dir = include_dir->links.sle_next) 161 /* 162 * All entries before a '-I-' only 163 * apply to includes specified with 164 * quotes instead of "<>". 165 */ 166 include_dir->quoted_includes_only = 1; 167 } else { 168 include_dir = 169 (path_entry_t)malloc(sizeof(*include_dir)); 170 if (include_dir == NULL) { 171 perror(optarg); 172 stop(NULL, EX_OSERR); 173 } 174 include_dir->directory = strdup(optarg); 175 if (include_dir->directory == NULL) { 176 perror(optarg); 177 stop(NULL, EX_OSERR); 178 } 179 include_dir->quoted_includes_only = 0; 180 SLIST_INSERT_HEAD(&search_path, include_dir, 181 links); 182 } 183 break; 184 } 185 case '?': 186 default: 187 usage(); 188 /* NOTREACHED */ 189 } 190 } 191 argc -= optind; 192 argv += optind; 193 194 if (argc != 1) { 195 fprintf(stderr, "%s: No input file specifiled\n", appname); 196 usage(); 197 /* NOTREACHED */ 198 } 199 200 symtable_open(); 201 inputfilename = *argv; 202 include_file(*argv, SOURCE_FILE); 203 retval = yyparse(); 204 if (retval == 0) { 205 back_patch(); 206 if (ofile != NULL) 207 output_code(ofile); 208 if (regfile != NULL) 209 symtable_dump(regfile); 210 if (listfile != NULL) 211 output_listing(listfile, inputfilename, options); 212 } 213 214 stop(NULL, 0); 215 /* NOTREACHED */ 216 return (0); 217 } 218 219 static void 220 usage() 221 { 222 223 (void)fprintf(stderr, 224 "usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file] 225 [-r register_output_file] [-l program_list_file] 226 [-O option_name[|options_name2]] input_file\n", 227 appname); 228 exit(EX_USAGE); 229 } 230 231 static void 232 back_patch() 233 { 234 struct instruction *cur_instr; 235 236 for(cur_instr = seq_program.stqh_first; 237 cur_instr != NULL; 238 cur_instr = cur_instr->links.stqe_next) { 239 if (cur_instr->patch_label != NULL) { 240 struct ins_format3 *f3_instr; 241 u_int address; 242 243 if (cur_instr->patch_label->type != LABEL) { 244 char buf[255]; 245 246 snprintf(buf, sizeof(buf), 247 "Undefined label %s", 248 cur_instr->patch_label->name); 249 stop(buf, EX_DATAERR); 250 /* NOTREACHED */ 251 } 252 f3_instr = &cur_instr->format.format3; 253 address = ((f3_instr->opcode_addr & ADDR_HIGH_BIT) << 8) 254 | f3_instr->address; 255 address += cur_instr->patch_label->info.linfo->address; 256 f3_instr->opcode_addr &= ~ADDR_HIGH_BIT; 257 f3_instr->opcode_addr |= (address >> 8) & ADDR_HIGH_BIT; 258 f3_instr->address = address & 0xFF; 259 } 260 } 261 } 262 263 static void 264 output_code(ofile) 265 FILE *ofile; 266 { 267 struct instruction *cur_instr; 268 patch_t *cur_patch; 269 symbol_node_t *cur_node; 270 int instrcount; 271 272 instrcount = 0; 273 fprintf(ofile, 274 "/* 275 * DO NOT EDIT - This file is automatically generated. 276 */\n"); 277 278 fprintf(ofile, "static u_int8_t seqprog[] = {\n"); 279 for(cur_instr = seq_program.stqh_first; 280 cur_instr != NULL; 281 cur_instr = cur_instr->links.stqe_next) { 282 fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n", 283 cur_instr->format.bytes[0], 284 cur_instr->format.bytes[1], 285 cur_instr->format.bytes[2], 286 cur_instr->format.bytes[3]); 287 instrcount++; 288 } 289 fprintf(ofile, "};\n"); 290 291 /* 292 * Output the patch list, option definitions first. 293 */ 294 for(cur_node = patch_options.slh_first; 295 cur_node != NULL; 296 cur_node = cur_node->links.sle_next) { 297 fprintf(ofile, "#define\t%-16s\t0x%x\n", cur_node->symbol->name, 298 cur_node->symbol->info.condinfo->value); 299 } 300 301 fprintf(ofile, 302 "struct patch { 303 int options; 304 int negative; 305 int begin; 306 int end; 307 } patches[] = {\n"); 308 309 for(cur_patch = patch_list.stqh_first; 310 cur_patch != NULL; 311 cur_patch = cur_patch->links.stqe_next) 312 313 fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x },\n", 314 cur_patch->options, cur_patch->negative, cur_patch->begin, 315 cur_patch->end); 316 317 fprintf(ofile, "\t{ 0x%08x, %d, 0x%03x, 0x%03x }\n};\n", 318 0, 0, 0, 0); 319 320 fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); 321 } 322 323 void 324 output_listing(listfile, ifilename, patches) 325 FILE *listfile; 326 char *ifilename; 327 char *patches; 328 { 329 FILE *ifile; 330 int line; 331 struct instruction *cur_instr; 332 int instrcount; 333 int instrptr; 334 char buf[1024]; 335 patch_t *cur_patch; 336 char *option_spec; 337 int options; 338 339 instrcount = 0; 340 instrptr = 0; 341 line = 1; 342 options = 1; /* All code outside of patch blocks */ 343 if ((ifile = fopen(ifilename, "r")) == NULL) { 344 perror(ifilename); 345 stop(NULL, EX_DATAERR); 346 } 347 348 /* 349 * Determine which options to apply to this listing. 350 */ 351 while ((option_spec = strsep(&patches, "|")) != NULL) { 352 symbol_t *symbol; 353 354 symbol = symtable_get(option_spec); 355 if (symbol->type != CONDITIONAL) { 356 stop("Invalid option specified in patch list for " 357 "program listing", EX_USAGE); 358 /* NOTREACHED */ 359 } 360 options |= symbol->info.condinfo->value; 361 } 362 363 cur_patch = patch_list.stqh_first; 364 for(cur_instr = seq_program.stqh_first; 365 cur_instr != NULL; 366 cur_instr = cur_instr->links.stqe_next,instrcount++) { 367 368 cur_patch = next_patch(cur_patch, options, instrcount); 369 if (cur_patch 370 && cur_patch->begin <= instrcount 371 && cur_patch->end > instrcount) 372 /* Don't count this instruction as it is in a patch 373 * that was removed. 374 */ 375 continue; 376 377 while (line < cur_instr->srcline) { 378 fgets(buf, sizeof(buf), ifile); 379 fprintf(listfile, "\t\t%s", buf); 380 line++; 381 } 382 fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, 383 cur_instr->format.bytes[0], 384 cur_instr->format.bytes[1], 385 cur_instr->format.bytes[2], 386 cur_instr->format.bytes[3]); 387 fgets(buf, sizeof(buf), ifile); 388 fprintf(listfile, "\t%s", buf); 389 line++; 390 instrptr++; 391 } 392 /* Dump the remainder of the file */ 393 while(fgets(buf, sizeof(buf), ifile) != NULL) 394 fprintf(listfile, "\t\t%s", buf); 395 396 fclose(ifile); 397 } 398 399 static struct patch * 400 next_patch(cur_patch, options, instrptr) 401 struct patch *cur_patch; 402 int options; 403 int instrptr; 404 { 405 while(cur_patch != NULL) { 406 if (((cur_patch->options & options) != 0 407 && cur_patch->negative == FALSE) 408 || ((cur_patch->options & options) == 0 409 && cur_patch->negative == TRUE) 410 || (instrptr >= cur_patch->end)) { 411 /* 412 * Either we want to keep this section of code, 413 * or we have consumed this patch. Skip to the 414 * next patch. 415 */ 416 cur_patch = cur_patch->links.stqe_next; 417 } else 418 /* Found an okay patch */ 419 break; 420 } 421 return (cur_patch); 422 } 423 424 /* 425 * Print out error information if appropriate, and clean up before 426 * terminating the program. 427 */ 428 void 429 stop(string, err_code) 430 const char *string; 431 int err_code; 432 { 433 if (string != NULL) { 434 fprintf(stderr, "%s: ", appname); 435 if (yyfilename != NULL) { 436 fprintf(stderr, "Stopped at file %s, line %d - ", 437 yyfilename, yylineno); 438 } 439 fprintf(stderr, "%s\n", string); 440 } 441 442 if (ofile != NULL) { 443 fclose(ofile); 444 if (err_code != 0) { 445 fprintf(stderr, "%s: Removing %s due to error\n", 446 appname, ofilename); 447 unlink(ofilename); 448 } 449 } 450 451 symlist_free(&patch_options); 452 symtable_close(); 453 454 exit(err_code); 455 } 456 457 struct instruction * 458 seq_alloc() 459 { 460 struct instruction *new_instr; 461 462 new_instr = (struct instruction *)malloc(sizeof(struct instruction)); 463 if (new_instr == NULL) 464 stop("Unable to malloc instruction object", EX_SOFTWARE); 465 memset(new_instr, 0, sizeof(*new_instr)); 466 STAILQ_INSERT_TAIL(&seq_program, new_instr, links); 467 new_instr->srcline = yylineno; 468 return new_instr; 469 } 470 471 patch_t * 472 patch_alloc() 473 { 474 patch_t *new_patch; 475 476 new_patch = (patch_t *)malloc(sizeof(patch_t)); 477 if (new_patch == NULL) 478 stop("Unable to malloc patch object", EX_SOFTWARE); 479 memset(new_patch, 0, sizeof(*new_patch)); 480 STAILQ_INSERT_TAIL(&patch_list, new_patch, links); 481 return new_patch; 482 } 483