691 lines · c
1/*2 * Aic7xxx SCSI host adapter firmware assembler symbol table implementation3 *4 * Copyright (c) 1997 Justin T. Gibbs.5 * Copyright (c) 2002 Adaptec Inc.6 * All rights reserved.7 *8 * Redistribution and use in source and binary forms, with or without9 * modification, are permitted provided that the following conditions10 * are met:11 * 1. Redistributions of source code must retain the above copyright12 * notice, this list of conditions, and the following disclaimer,13 * without modification.14 * 2. Redistributions in binary form must reproduce at minimum a disclaimer15 * substantially similar to the "NO WARRANTY" disclaimer below16 * ("Disclaimer") and any redistribution must be conditioned upon17 * including a substantially similar Disclaimer requirement for further18 * binary redistribution.19 * 3. Neither the names of the above-listed copyright holders nor the names20 * of any contributors may be used to endorse or promote products derived21 * from this software without specific prior written permission.22 *23 * Alternatively, this software may be distributed under the terms of the24 * GNU General Public License ("GPL") version 2 as published by the Free25 * Software Foundation.26 *27 * NO WARRANTY28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT32 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING37 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE38 * POSSIBILITY OF SUCH DAMAGES.39 *40 * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#24 $41 *42 * $FreeBSD$43 */44 45#include <sys/types.h>46 47#include "aicdb.h"48#include <fcntl.h>49#include <inttypes.h>50#include <regex.h>51#include <stdio.h>52#include <stdlib.h>53#include <string.h>54#include <sysexits.h>55#include <ctype.h>56 57#include "aicasm_symbol.h"58#include "aicasm.h"59 60static DB *symtable;61 62symbol_t *63symbol_create(char *name)64{65 symbol_t *new_symbol;66 67 new_symbol = (symbol_t *)malloc(sizeof(symbol_t));68 if (new_symbol == NULL) {69 perror("Unable to create new symbol");70 exit(EX_SOFTWARE);71 }72 memset(new_symbol, 0, sizeof(*new_symbol));73 new_symbol->name = strdup(name);74 if (new_symbol->name == NULL)75 stop("Unable to strdup symbol name", EX_SOFTWARE);76 new_symbol->type = UNINITIALIZED;77 new_symbol->count = 1;78 return (new_symbol);79}80 81void82symbol_delete(symbol_t *symbol)83{84 if (symtable != NULL) {85 DBT key;86 87 key.data = symbol->name;88 key.size = strlen(symbol->name);89 symtable->del(symtable, &key, /*flags*/0);90 }91 switch(symbol->type) {92 case SCBLOC:93 case SRAMLOC:94 case REGISTER:95 if (symbol->info.rinfo != NULL)96 free(symbol->info.rinfo);97 break;98 case ALIAS:99 if (symbol->info.ainfo != NULL)100 free(symbol->info.ainfo);101 break;102 case MASK:103 case FIELD:104 case ENUM:105 case ENUM_ENTRY:106 if (symbol->info.finfo != NULL) {107 symlist_free(&symbol->info.finfo->symrefs);108 free(symbol->info.finfo);109 }110 break;111 case DOWNLOAD_CONST:112 case CONST:113 if (symbol->info.cinfo != NULL)114 free(symbol->info.cinfo);115 break;116 case LABEL:117 if (symbol->info.linfo != NULL)118 free(symbol->info.linfo);119 break;120 case UNINITIALIZED:121 default:122 break;123 }124 free(symbol->name);125 free(symbol);126}127 128void129symtable_open()130{131 symtable = dbopen(/*filename*/NULL,132 O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,133 /*openinfo*/NULL);134 135 if (symtable == NULL) {136 perror("Symbol table creation failed");137 exit(EX_SOFTWARE);138 /* NOTREACHED */139 }140}141 142void143symtable_close()144{145 if (symtable != NULL) {146 DBT key;147 DBT data;148 149 while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {150 symbol_t *stored_ptr;151 152 memcpy(&stored_ptr, data.data, sizeof(stored_ptr));153 symbol_delete(stored_ptr);154 }155 symtable->close(symtable);156 }157}158 159/*160 * The semantics of get is to return an uninitialized symbol entry161 * if a lookup fails.162 */163symbol_t *164symtable_get(char *name)165{166 symbol_t *stored_ptr;167 DBT key;168 DBT data;169 int retval;170 171 key.data = (void *)name;172 key.size = strlen(name);173 174 if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {175 if (retval == -1) {176 perror("Symbol table get operation failed");177 exit(EX_SOFTWARE);178 /* NOTREACHED */179 } else if (retval == 1) {180 /* Symbol wasn't found, so create a new one */181 symbol_t *new_symbol;182 183 new_symbol = symbol_create(name);184 data.data = &new_symbol;185 data.size = sizeof(new_symbol);186 if (symtable->put(symtable, &key, &data,187 /*flags*/0) !=0) {188 perror("Symtable put failed");189 exit(EX_SOFTWARE);190 }191 return (new_symbol);192 } else {193 perror("Unexpected return value from db get routine");194 exit(EX_SOFTWARE);195 /* NOTREACHED */196 }197 }198 memcpy(&stored_ptr, data.data, sizeof(stored_ptr));199 stored_ptr->count++;200 data.data = &stored_ptr;201 if (symtable->put(symtable, &key, &data, /*flags*/0) !=0) {202 perror("Symtable put failed");203 exit(EX_SOFTWARE);204 }205 return (stored_ptr);206}207 208symbol_node_t *209symlist_search(symlist_t *symlist, char *symname)210{211 symbol_node_t *curnode;212 213 curnode = SLIST_FIRST(symlist);214 while(curnode != NULL) {215 if (strcmp(symname, curnode->symbol->name) == 0)216 break;217 curnode = SLIST_NEXT(curnode, links);218 }219 return (curnode);220}221 222void223symlist_add(symlist_t *symlist, symbol_t *symbol, int how)224{225 symbol_node_t *newnode;226 227 newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));228 if (newnode == NULL) {229 stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);230 /* NOTREACHED */231 }232 newnode->symbol = symbol;233 if (how == SYMLIST_SORT) {234 symbol_node_t *curnode;235 int field;236 237 field = FALSE;238 switch(symbol->type) {239 case REGISTER:240 case SCBLOC:241 case SRAMLOC:242 break;243 case FIELD:244 case MASK:245 case ENUM:246 case ENUM_ENTRY:247 field = TRUE;248 break;249 default:250 stop("symlist_add: Invalid symbol type for sorting",251 EX_SOFTWARE);252 /* NOTREACHED */253 }254 255 curnode = SLIST_FIRST(symlist);256 if (curnode == NULL257 || (field258 && (curnode->symbol->type > newnode->symbol->type259 || (curnode->symbol->type == newnode->symbol->type260 && (curnode->symbol->info.finfo->value >261 newnode->symbol->info.finfo->value))))262 || (!field && (curnode->symbol->info.rinfo->address >263 newnode->symbol->info.rinfo->address))) {264 SLIST_INSERT_HEAD(symlist, newnode, links);265 return;266 }267 268 while (1) {269 if (SLIST_NEXT(curnode, links) == NULL) {270 SLIST_INSERT_AFTER(curnode, newnode,271 links);272 break;273 } else {274 symbol_t *cursymbol;275 276 cursymbol = SLIST_NEXT(curnode, links)->symbol;277 if ((field278 && (cursymbol->type > symbol->type279 || (cursymbol->type == symbol->type280 && (cursymbol->info.finfo->value >281 symbol->info.finfo->value))))282 || (!field283 && (cursymbol->info.rinfo->address >284 symbol->info.rinfo->address))) {285 SLIST_INSERT_AFTER(curnode, newnode,286 links);287 break;288 }289 }290 curnode = SLIST_NEXT(curnode, links);291 }292 } else {293 SLIST_INSERT_HEAD(symlist, newnode, links);294 }295}296 297void298symlist_free(symlist_t *symlist)299{300 symbol_node_t *node1, *node2;301 302 node1 = SLIST_FIRST(symlist);303 while (node1 != NULL) {304 node2 = SLIST_NEXT(node1, links);305 free(node1);306 node1 = node2;307 }308 SLIST_INIT(symlist);309}310 311void312symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,313 symlist_t *symlist_src2)314{315 symbol_node_t *node;316 317 *symlist_dest = *symlist_src1;318 while((node = SLIST_FIRST(symlist_src2)) != NULL) {319 SLIST_REMOVE_HEAD(symlist_src2, links);320 SLIST_INSERT_HEAD(symlist_dest, node, links);321 }322 323 /* These are now empty */324 SLIST_INIT(symlist_src1);325 SLIST_INIT(symlist_src2);326}327 328void329aic_print_file_prologue(FILE *ofile)330{331 332 if (ofile == NULL)333 return;334 335 fprintf(ofile,336"/*\n"337" * DO NOT EDIT - This file is automatically generated\n"338" * from the following source files:\n"339" *\n"340"%s */\n",341 versions);342}343 344void345aic_print_include(FILE *dfile, char *include_file)346{347 348 if (dfile == NULL)349 return;350 fprintf(dfile, "\n#include \"%s\"\n\n", include_file);351}352 353void354aic_print_reg_dump_types(FILE *ofile)355{356 if (ofile == NULL)357 return;358 359 fprintf(ofile,360"typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n"361"typedef struct %sreg_parse_entry {\n"362" char *name;\n"363" uint8_t value;\n"364" uint8_t mask;\n"365"} %sreg_parse_entry_t;\n"366"\n",367 prefix, prefix, prefix);368}369 370static void371aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode)372{373 if (dfile == NULL)374 return;375 376 fprintf(dfile,377"static const %sreg_parse_entry_t %s_parse_table[] = {\n",378 prefix,379 regnode->symbol->name);380}381 382static void383aic_print_reg_dump_end(FILE *ofile, FILE *dfile,384 symbol_node_t *regnode, u_int num_entries)385{386 char *lower_name;387 char *letter;388 389 lower_name = strdup(regnode->symbol->name);390 if (lower_name == NULL)391 stop("Unable to strdup symbol name", EX_SOFTWARE);392 393 for (letter = lower_name; *letter != '\0'; letter++)394 *letter = tolower(*letter);395 396 if (dfile != NULL) {397 if (num_entries != 0)398 fprintf(dfile,399"\n"400"};\n"401"\n");402 403 fprintf(dfile,404"int\n"405"%s%s_print(u_int regvalue, u_int *cur_col, u_int wrap)\n"406"{\n"407" return (%sprint_register(%s%s, %d, \"%s\",\n"408" 0x%02x, regvalue, cur_col, wrap));\n"409"}\n"410"\n",411 prefix,412 lower_name,413 prefix,414 num_entries != 0 ? regnode->symbol->name : "NULL",415 num_entries != 0 ? "_parse_table" : "",416 num_entries,417 regnode->symbol->name,418 regnode->symbol->info.rinfo->address);419 }420 421 fprintf(ofile,422"#if AIC_DEBUG_REGISTERS\n"423"%sreg_print_t %s%s_print;\n"424"#else\n"425"#define %s%s_print(regvalue, cur_col, wrap) \\\n"426" %sprint_register(NULL, 0, \"%s\", 0x%02x, regvalue, cur_col, wrap)\n"427"#endif\n"428"\n",429 prefix,430 prefix,431 lower_name,432 prefix,433 lower_name,434 prefix,435 regnode->symbol->name,436 regnode->symbol->info.rinfo->address);437}438 439static void440aic_print_reg_dump_entry(FILE *dfile, symbol_node_t *curnode)441{442 int num_tabs;443 444 if (dfile == NULL)445 return;446 447 fprintf(dfile,448" { \"%s\",",449 curnode->symbol->name);450 451 num_tabs = 3 - (strlen(curnode->symbol->name) + 5) / 8;452 453 while (num_tabs-- > 0)454 fputc('\t', dfile);455 fprintf(dfile, "0x%02x, 0x%02x }",456 curnode->symbol->info.finfo->value,457 curnode->symbol->info.finfo->mask);458}459 460void461symtable_dump(FILE *ofile, FILE *dfile)462{463 /*464 * Sort the registers by address with a simple insertion sort.465 * Put bitmasks next to the first register that defines them.466 * Put constants at the end.467 */468 symlist_t registers;469 symlist_t masks;470 symlist_t constants;471 symlist_t download_constants;472 symlist_t aliases;473 symlist_t exported_labels;474 symbol_node_t *curnode;475 symbol_node_t *regnode;476 DBT key;477 DBT data;478 int flag;479 int reg_count = 0, reg_used = 0;480 u_int i;481 482 if (symtable == NULL)483 return;484 485 SLIST_INIT(®isters);486 SLIST_INIT(&masks);487 SLIST_INIT(&constants);488 SLIST_INIT(&download_constants);489 SLIST_INIT(&aliases);490 SLIST_INIT(&exported_labels);491 flag = R_FIRST;492 while (symtable->seq(symtable, &key, &data, flag) == 0) {493 symbol_t *cursym;494 495 memcpy(&cursym, data.data, sizeof(cursym));496 switch(cursym->type) {497 case REGISTER:498 case SCBLOC:499 case SRAMLOC:500 symlist_add(®isters, cursym, SYMLIST_SORT);501 break;502 case MASK:503 case FIELD:504 case ENUM:505 case ENUM_ENTRY:506 symlist_add(&masks, cursym, SYMLIST_SORT);507 break;508 case CONST:509 symlist_add(&constants, cursym,510 SYMLIST_INSERT_HEAD);511 break;512 case DOWNLOAD_CONST:513 symlist_add(&download_constants, cursym,514 SYMLIST_INSERT_HEAD);515 break;516 case ALIAS:517 symlist_add(&aliases, cursym,518 SYMLIST_INSERT_HEAD);519 break;520 case LABEL:521 if (cursym->info.linfo->exported == 0)522 break;523 symlist_add(&exported_labels, cursym,524 SYMLIST_INSERT_HEAD);525 break;526 default:527 break;528 }529 flag = R_NEXT;530 }531 532 /* Register dianostic functions/declarations first. */533 aic_print_file_prologue(ofile);534 aic_print_reg_dump_types(ofile);535 aic_print_file_prologue(dfile);536 aic_print_include(dfile, stock_include_file);537 SLIST_FOREACH(curnode, ®isters, links) {538 539 if (curnode->symbol->dont_generate_debug_code)540 continue;541 542 switch(curnode->symbol->type) {543 case REGISTER:544 case SCBLOC:545 case SRAMLOC:546 {547 symlist_t *fields;548 symbol_node_t *fieldnode;549 int num_entries;550 551 num_entries = 0;552 reg_count++;553 if (curnode->symbol->count == 1)554 break;555 fields = &curnode->symbol->info.rinfo->fields;556 SLIST_FOREACH(fieldnode, fields, links) {557 if (num_entries == 0)558 aic_print_reg_dump_start(dfile,559 curnode);560 else if (dfile != NULL)561 fputs(",\n", dfile);562 num_entries++;563 aic_print_reg_dump_entry(dfile, fieldnode);564 }565 aic_print_reg_dump_end(ofile, dfile,566 curnode, num_entries);567 reg_used++;568 }569 default:570 break;571 }572 }573 fprintf(stderr, "%s: %d of %d register definitions used\n", appname,574 reg_used, reg_count);575 576 /* Fold in the masks and bits */577 while (SLIST_FIRST(&masks) != NULL) {578 char *regname;579 580 curnode = SLIST_FIRST(&masks);581 SLIST_REMOVE_HEAD(&masks, links);582 583 regnode = SLIST_FIRST(&curnode->symbol->info.finfo->symrefs);584 regname = regnode->symbol->name;585 regnode = symlist_search(®isters, regname);586 SLIST_INSERT_AFTER(regnode, curnode, links);587 }588 589 /* Add the aliases */590 while (SLIST_FIRST(&aliases) != NULL) {591 char *regname;592 593 curnode = SLIST_FIRST(&aliases);594 SLIST_REMOVE_HEAD(&aliases, links);595 596 regname = curnode->symbol->info.ainfo->parent->name;597 regnode = symlist_search(®isters, regname);598 SLIST_INSERT_AFTER(regnode, curnode, links);599 }600 601 /* Output generated #defines. */602 while (SLIST_FIRST(®isters) != NULL) {603 symbol_node_t *curnode;604 u_int value;605 char *tab_str;606 char *tab_str2;607 608 curnode = SLIST_FIRST(®isters);609 SLIST_REMOVE_HEAD(®isters, links);610 switch(curnode->symbol->type) {611 case REGISTER:612 case SCBLOC:613 case SRAMLOC:614 fprintf(ofile, "\n");615 value = curnode->symbol->info.rinfo->address;616 tab_str = "\t";617 tab_str2 = "\t\t";618 break;619 case ALIAS:620 {621 symbol_t *parent;622 623 parent = curnode->symbol->info.ainfo->parent;624 value = parent->info.rinfo->address;625 tab_str = "\t";626 tab_str2 = "\t\t";627 break;628 }629 case MASK:630 case FIELD:631 case ENUM:632 case ENUM_ENTRY:633 value = curnode->symbol->info.finfo->value;634 tab_str = "\t\t";635 tab_str2 = "\t";636 break;637 default:638 value = 0; /* Quiet compiler */639 tab_str = NULL;640 tab_str2 = NULL;641 stop("symtable_dump: Invalid symbol type "642 "encountered", EX_SOFTWARE);643 break;644 }645 fprintf(ofile, "#define%s%-16s%s0x%02x\n",646 tab_str, curnode->symbol->name, tab_str2,647 value);648 free(curnode);649 }650 fprintf(ofile, "\n\n");651 652 while (SLIST_FIRST(&constants) != NULL) {653 symbol_node_t *curnode;654 655 curnode = SLIST_FIRST(&constants);656 SLIST_REMOVE_HEAD(&constants, links);657 fprintf(ofile, "#define\t%-8s\t0x%02x\n",658 curnode->symbol->name,659 curnode->symbol->info.cinfo->value);660 free(curnode);661 }662 663 fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");664 665 for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) {666 symbol_node_t *curnode;667 668 curnode = SLIST_FIRST(&download_constants);669 SLIST_REMOVE_HEAD(&download_constants, links);670 fprintf(ofile, "#define\t%-8s\t0x%02x\n",671 curnode->symbol->name,672 curnode->symbol->info.cinfo->value);673 free(curnode);674 }675 fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i);676 677 fprintf(ofile, "\n\n/* Exported Labels */\n");678 679 while (SLIST_FIRST(&exported_labels) != NULL) {680 symbol_node_t *curnode;681 682 curnode = SLIST_FIRST(&exported_labels);683 SLIST_REMOVE_HEAD(&exported_labels, links);684 fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n",685 curnode->symbol->name,686 curnode->symbol->info.linfo->address);687 free(curnode);688 }689}690 691