diff --git a/sys/dev/aic7xxx/aicasm/Makefile b/sys/dev/aic7xxx/aicasm/Makefile index c5575a8e7e88..acd6a0cc5ba3 100644 --- a/sys/dev/aic7xxx/aicasm/Makefile +++ b/sys/dev/aic7xxx/aicasm/Makefile @@ -1,31 +1,33 @@ +# $Id$ +# # $FreeBSD$ PROG= aicasm CSRCS= aicasm.c aicasm_symbol.c GENSRCS= aicasm_gram.c aicasm_scan.c GENHDRS= y.tab.h SRCS= ${GENSRCS} ${CSRCS} CLEANFILES+= ${GENSRCS} ${GENHDRS} y.output DPADD+= ${LIBL} LDADD+= -ll # Correct path for kernel builds # Don't rely on the kernel's .depend file .ifdef MAKESRCPATH .PATH: ${MAKESRCPATH} DEPENDFILE= .endif -CFLAGS+= -nostdinc -I${.CURDIR}/../.. -I. -I/usr/include +CFLAGS+= -nostdinc -I${.CURDIR}/../../.. -I. -I/usr/include NOMAN= noman .ifdef DEBUG CFLAGS+= -DDEBUG -g -YFLAGS+= -t +YFLAGS+= -t -v LFLAGS+= -d .endif .include diff --git a/sys/dev/aic7xxx/aicasm/aicasm.c b/sys/dev/aic7xxx/aicasm/aicasm.c index 374e86c79ca2..f17218fb3b26 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm.c +++ b/sys/dev/aic7xxx/aicasm/aicasm.c @@ -1,736 +1,737 @@ /* * Aic7xxx SCSI host adapter firmware asssembler * * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id$ + * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include "aicasm.h" #include "aicasm_symbol.h" #include "aicasm_insformat.h" typedef struct patch { STAILQ_ENTRY(patch) links; int patch_func; u_int begin; u_int skip_instr; u_int skip_patch; } patch_t; STAILQ_HEAD(patch_list, patch) patches; static void usage(void); static void back_patch(void); static void output_code(void); static void output_listing(char *ifilename); static void dump_scope(scope_t *scope); static void emit_patch(scope_t *scope, int patch); static int check_patch(patch_t **start_patch, int start_instr, int *skip_addr, int *func_vals); struct path_list search_path; int includes_search_curdir; char *appname; FILE *ofile; char *ofilename; char *regfilename; FILE *regfile; char *listfilename; FILE *listfile; static STAILQ_HEAD(,instruction) seq_program; struct scope_list scope_stack; symlist_t patch_functions; #if DEBUG extern int yy_flex_debug; extern int yydebug; #endif extern FILE *yyin; -extern int yyparse __P((void)); +extern int yyparse(void); + +int main(int argc, char *argv[]); int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { extern char *optarg; extern int optind; int ch; int retval; char *inputfilename; scope_t *sentinal; STAILQ_INIT(&patches); SLIST_INIT(&search_path); STAILQ_INIT(&seq_program); SLIST_INIT(&scope_stack); /* Set Sentinal scope node */ sentinal = scope_alloc(); sentinal->type = SCOPE_ROOT; includes_search_curdir = 1; appname = *argv; regfile = NULL; listfile = NULL; #if DEBUG yy_flex_debug = 0; yydebug = 0; #endif while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) { switch(ch) { case 'd': #if DEBUG if (strcmp(optarg, "s") == 0) { yy_flex_debug = 1; } else if (strcmp(optarg, "p") == 0) { yydebug = 1; } else { fprintf(stderr, "%s: -d Requires either an " "'s' or 'p' argument\n", appname); usage(); } #else stop("-d: Assembler not built with debugging " "information", EX_SOFTWARE); #endif break; case 'l': /* Create a program listing */ if ((listfile = fopen(optarg, "w")) == NULL) { perror(optarg); stop(NULL, EX_CANTCREAT); } listfilename = optarg; break; case 'n': /* Don't complain about the -nostdinc directrive */ if (strcmp(optarg, "ostdinc")) { fprintf(stderr, "%s: Unknown option -%c%s\n", appname, ch, optarg); usage(); /* NOTREACHED */ } break; case 'o': if ((ofile = fopen(optarg, "w")) == NULL) { perror(optarg); stop(NULL, EX_CANTCREAT); } ofilename = optarg; break; case 'r': if ((regfile = fopen(optarg, "w")) == NULL) { perror(optarg); stop(NULL, EX_CANTCREAT); } regfilename = optarg; break; case 'I': { path_entry_t include_dir; if (strcmp(optarg, "-") == 0) { if (includes_search_curdir == 0) { fprintf(stderr, "%s: Warning - '-I-' " "specified multiple " "times\n", appname); } includes_search_curdir = 0; for (include_dir = search_path.slh_first; include_dir != NULL; include_dir = include_dir->links.sle_next) /* * All entries before a '-I-' only * apply to includes specified with * quotes instead of "<>". */ include_dir->quoted_includes_only = 1; } else { include_dir = (path_entry_t)malloc(sizeof(*include_dir)); if (include_dir == NULL) { perror(optarg); stop(NULL, EX_OSERR); } include_dir->directory = strdup(optarg); if (include_dir->directory == NULL) { perror(optarg); stop(NULL, EX_OSERR); } include_dir->quoted_includes_only = 0; SLIST_INSERT_HEAD(&search_path, include_dir, links); } break; } case '?': default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 1) { fprintf(stderr, "%s: No input file specifiled\n", appname); usage(); /* NOTREACHED */ } symtable_open(); inputfilename = *argv; include_file(*argv, SOURCE_FILE); retval = yyparse(); if (retval == 0) { if (SLIST_FIRST(&scope_stack) == NULL || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { stop("Unterminated conditional expression", EX_DATAERR); /* NOTREACHED */ } /* Process outmost scope */ process_scope(SLIST_FIRST(&scope_stack)); /* * Decend the tree of scopes and insert/emit * patches as appropriate. We perform a depth first * tranversal, recursively handling each scope. */ /* start at the root scope */ dump_scope(SLIST_FIRST(&scope_stack)); /* Patch up forward jump addresses */ back_patch(); if (ofile != NULL) output_code(); if (regfile != NULL) { symtable_dump(regfile); } if (listfile != NULL) output_listing(inputfilename); } stop(NULL, 0); /* NOTREACHED */ return (0); } static void usage() { (void)fprintf(stderr, "usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file] [-r register_output_file] [-l program_list_file] input_file\n", appname); exit(EX_USAGE); } static void back_patch() { struct instruction *cur_instr; for(cur_instr = seq_program.stqh_first; cur_instr != NULL; cur_instr = cur_instr->links.stqe_next) { if (cur_instr->patch_label != NULL) { struct ins_format3 *f3_instr; u_int address; if (cur_instr->patch_label->type != LABEL) { char buf[255]; snprintf(buf, sizeof(buf), "Undefined label %s", cur_instr->patch_label->name); stop(buf, EX_DATAERR); /* NOTREACHED */ } f3_instr = &cur_instr->format.format3; address = f3_instr->address; address += cur_instr->patch_label->info.linfo->address; f3_instr->address = address; } } } static void output_code() { struct instruction *cur_instr; patch_t *cur_patch; symbol_node_t *cur_node; int instrcount; instrcount = 0; fprintf(ofile, "/* * DO NOT EDIT - This file is automatically generated. */\n"); fprintf(ofile, "static uint8_t seqprog[] = {\n"); for(cur_instr = seq_program.stqh_first; cur_instr != NULL; cur_instr = cur_instr->links.stqe_next) { fprintf(ofile, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n", #if BYTE_ORDER == LITTLE_ENDIAN cur_instr->format.bytes[0], cur_instr->format.bytes[1], cur_instr->format.bytes[2], cur_instr->format.bytes[3]); #else cur_instr->format.bytes[3], cur_instr->format.bytes[2], cur_instr->format.bytes[1], cur_instr->format.bytes[0]); #endif instrcount++; } fprintf(ofile, "};\n\n"); /* * Output patch information. Patch functions first. */ for(cur_node = SLIST_FIRST(&patch_functions); cur_node != NULL; cur_node = SLIST_NEXT(cur_node,links)) { fprintf(ofile, "static int ahc_patch%d_func(struct ahc_softc *ahc); static int ahc_patch%d_func(struct ahc_softc *ahc) { return (%s); }\n\n", cur_node->symbol->info.condinfo->func_num, cur_node->symbol->info.condinfo->func_num, cur_node->symbol->name); } fprintf(ofile, -"typedef int patch_func_t __P((struct ahc_softc *)); +"typedef int patch_func_t (struct ahc_softc *); struct patch { patch_func_t *patch_func; uint32_t begin :10, skip_instr :10, skip_patch :12; } patches[] = {\n"); for(cur_patch = STAILQ_FIRST(&patches); cur_patch != NULL; cur_patch = STAILQ_NEXT(cur_patch,links)) { fprintf(ofile, "\t{ ahc_patch%d_func, %d, %d, %d },\n", cur_patch->patch_func, cur_patch->begin, cur_patch->skip_instr, cur_patch->skip_patch); } fprintf(ofile, "\n};\n"); fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); } static void dump_scope(scope_t *scope) { scope_t *cur_scope; /* * Emit the first patch for this scope */ emit_patch(scope, 0); /* * Dump each scope within this one. */ cur_scope = TAILQ_FIRST(&scope->inner_scope); while (cur_scope != NULL) { dump_scope(cur_scope); cur_scope = TAILQ_NEXT(cur_scope, scope_links); } /* * Emit the second, closing, patch for this scope */ emit_patch(scope, 1); } void emit_patch(scope_t *scope, int patch) { patch_info_t *pinfo; patch_t *new_patch; pinfo = &scope->patches[patch]; if (pinfo->skip_instr == 0) /* No-Op patch */ return; new_patch = (patch_t *)malloc(sizeof(*new_patch)); if (new_patch == NULL) stop("Could not malloc patch structure", EX_OSERR); memset(new_patch, 0, sizeof(*new_patch)); if (patch == 0) { new_patch->patch_func = scope->func_num; new_patch->begin = scope->begin_addr; } else { new_patch->patch_func = 0; new_patch->begin = scope->end_addr; } new_patch->skip_instr = pinfo->skip_instr; new_patch->skip_patch = pinfo->skip_patch; STAILQ_INSERT_TAIL(&patches, new_patch, links); } void output_listing(char *ifilename) { char buf[1024]; FILE *ifile; struct instruction *cur_instr; patch_t *cur_patch; symbol_node_t *cur_func; int *func_values; int instrcount; int instrptr; int line; int func_count; int skip_addr; instrcount = 0; instrptr = 0; line = 1; skip_addr = 0; if ((ifile = fopen(ifilename, "r")) == NULL) { perror(ifilename); stop(NULL, EX_DATAERR); } /* * Determine which options to apply to this listing. */ for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions); cur_func != NULL; cur_func = SLIST_NEXT(cur_func, links)) func_count++; + func_values = NULL; if (func_count != 0) { func_values = (int *)malloc(func_count * sizeof(int)); if (func_values == NULL) stop("Could not malloc", EX_OSERR); func_values[0] = 0; /* FALSE func */ func_count--; /* * Ask the user to fill in the return values for * the rest of the functions. */ for (cur_func = SLIST_FIRST(&patch_functions); cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL; cur_func = SLIST_NEXT(cur_func, links), func_count--) { int input; fprintf(stdout, "\n(%s)\n", cur_func->symbol->name); fprintf(stdout, "Enter the return value for " "this expression[T/F]:"); while (1) { input = getchar(); input = toupper(input); if (input == 'T') { func_values[func_count] = 1; break; } else if (input == 'F') { func_values[func_count] = 0; break; } } if (isatty(fileno(stdin)) == 0) putchar(input); } fprintf(stdout, "\nThanks!\n"); } /* Now output the listing */ cur_patch = STAILQ_FIRST(&patches); for(cur_instr = STAILQ_FIRST(&seq_program); cur_instr != NULL; cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) { if (check_patch(&cur_patch, instrcount, &skip_addr, func_values) == 0) { /* Don't count this instruction as it is in a patch * that was removed. */ continue; } while (line < cur_instr->srcline) { fgets(buf, sizeof(buf), ifile); fprintf(listfile, "\t\t%s", buf); line++; } fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, #if BYTE_ORDER == LITTLE_ENDIAN cur_instr->format.bytes[0], cur_instr->format.bytes[1], cur_instr->format.bytes[2], cur_instr->format.bytes[3]); #else cur_instr->format.bytes[3], cur_instr->format.bytes[2], cur_instr->format.bytes[1], cur_instr->format.bytes[0]); #endif fgets(buf, sizeof(buf), ifile); fprintf(listfile, "\t%s", buf); line++; instrptr++; } /* Dump the remainder of the file */ while(fgets(buf, sizeof(buf), ifile) != NULL) fprintf(listfile, "\t\t%s", buf); fclose(ifile); } static int check_patch(patch_t **start_patch, int start_instr, int *skip_addr, int *func_vals) { patch_t *cur_patch; cur_patch = *start_patch; while (cur_patch != NULL && start_instr == cur_patch->begin) { if (func_vals[cur_patch->patch_func] == 0) { int skip; /* Start rejecting code */ *skip_addr = start_instr + cur_patch->skip_instr; for (skip = cur_patch->skip_patch; skip > 0 && cur_patch != NULL; skip--) cur_patch = STAILQ_NEXT(cur_patch, links); } else { /* Accepted this patch. Advance to the next * one and wait for our intruction pointer to * hit this point. */ cur_patch = STAILQ_NEXT(cur_patch, links); } } *start_patch = cur_patch; if (start_instr < *skip_addr) /* Still skipping */ return (0); return (1); } /* * Print out error information if appropriate, and clean up before * terminating the program. */ void -stop(string, err_code) - const char *string; - int err_code; +stop(const char *string, int err_code) { if (string != NULL) { fprintf(stderr, "%s: ", appname); if (yyfilename != NULL) { fprintf(stderr, "Stopped at file %s, line %d - ", yyfilename, yylineno); } fprintf(stderr, "%s\n", string); } if (ofile != NULL) { fclose(ofile); if (err_code != 0) { fprintf(stderr, "%s: Removing %s due to error\n", appname, ofilename); unlink(ofilename); } } if (regfile != NULL) { fclose(regfile); if (err_code != 0) { fprintf(stderr, "%s: Removing %s due to error\n", appname, regfilename); unlink(regfilename); } } if (listfile != NULL) { fclose(listfile); if (err_code != 0) { fprintf(stderr, "%s: Removing %s due to error\n", appname, listfilename); unlink(listfilename); } } symlist_free(&patch_functions); symtable_close(); exit(err_code); } struct instruction * seq_alloc() { struct instruction *new_instr; new_instr = (struct instruction *)malloc(sizeof(struct instruction)); if (new_instr == NULL) stop("Unable to malloc instruction object", EX_SOFTWARE); memset(new_instr, 0, sizeof(*new_instr)); STAILQ_INSERT_TAIL(&seq_program, new_instr, links); new_instr->srcline = yylineno; return new_instr; } scope_t * scope_alloc() { scope_t *new_scope; new_scope = (scope_t *)malloc(sizeof(scope_t)); if (new_scope == NULL) stop("Unable to malloc scope object", EX_SOFTWARE); memset(new_scope, 0, sizeof(*new_scope)); TAILQ_INIT(&new_scope->inner_scope); if (SLIST_FIRST(&scope_stack) != NULL) { TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope, new_scope, scope_links); } /* This patch is now the current scope */ SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links); return new_scope; } void process_scope(scope_t *scope) { /* * We are "leaving" this scope. We should now have * enough information to process the lists of scopes * we encapsulate. */ scope_t *cur_scope; u_int skip_patch_count; u_int skip_instr_count; cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq); skip_patch_count = 0; skip_instr_count = 0; while (cur_scope != NULL) { u_int patch0_patch_skip; patch0_patch_skip = 0; switch (cur_scope->type) { case SCOPE_IF: case SCOPE_ELSE_IF: if (skip_instr_count != 0) { /* Create a tail patch */ patch0_patch_skip++; cur_scope->patches[1].skip_patch = skip_patch_count + 1; cur_scope->patches[1].skip_instr = skip_instr_count; } /* Count Head patch */ patch0_patch_skip++; /* Count any patches contained in our inner scope */ patch0_patch_skip += cur_scope->inner_scope_patches; cur_scope->patches[0].skip_patch = patch0_patch_skip; cur_scope->patches[0].skip_instr = cur_scope->end_addr - cur_scope->begin_addr; skip_instr_count += cur_scope->patches[0].skip_instr; skip_patch_count += patch0_patch_skip; if (cur_scope->type == SCOPE_IF) { scope->inner_scope_patches += skip_patch_count; skip_patch_count = 0; skip_instr_count = 0; } break; case SCOPE_ELSE: /* Count any patches contained in our innter scope */ skip_patch_count += cur_scope->inner_scope_patches; skip_instr_count += cur_scope->end_addr - cur_scope->begin_addr; break; case SCOPE_ROOT: stop("Unexpected scope type encountered", EX_SOFTWARE); /* NOTREACHED */ } cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links); } } diff --git a/sys/dev/aic7xxx/aicasm/aicasm.h b/sys/dev/aic7xxx/aicasm/aicasm.h index 9faecd0f4f02..6a3400fda64f 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm.h +++ b/sys/dev/aic7xxx/aicasm/aicasm.h @@ -1,70 +1,76 @@ /* * Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters * * Copyright (c) 1997 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id$ + * * $FreeBSD$ */ +#ifdef __linux__ +#include "../queue.h" +#else #include +#endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif typedef struct path_entry { char *directory; int quoted_includes_only; SLIST_ENTRY(path_entry) links; } *path_entry_t; typedef enum { QUOTED_INCLUDE, BRACKETED_INCLUDE, SOURCE_FILE } include_type; SLIST_HEAD(path_list, path_entry); extern struct path_list search_path; extern struct scope_list scope_stack; extern struct symlist patch_functions; extern int includes_search_curdir; /* False if we've seen -I- */ extern char *appname; extern int yylineno; extern char *yyfilename; void stop(const char *errstring, int err_code); void include_file(char *file_name, include_type type); struct instruction *seq_alloc(void); struct scope *scope_alloc(void); void process_scope(struct scope *); diff --git a/sys/dev/aic7xxx/aicasm/aicasm_gram.y b/sys/dev/aic7xxx/aicasm/aicasm_gram.y index 5731f674bcdf..8a602637145b 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm_gram.y +++ b/sys/dev/aic7xxx/aicasm/aicasm_gram.y @@ -1,1438 +1,1416 @@ %{ /* * Parser for the Aic7xxx SCSI Host adapter sequencer assembler. * * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id$ + * * $FreeBSD$ */ #include #include #include #include #include +#ifdef __linux__ +#include "../queue.h" +#else #include +#endif #include "aicasm.h" #include "aicasm_symbol.h" #include "aicasm_insformat.h" int yylineno; char *yyfilename; static symbol_t *cur_symbol; static symtype cur_symtype; static symbol_t *accumulator; static symbol_ref_t allones; static symbol_ref_t allzeros; static symbol_ref_t none; static symbol_ref_t sindex; static int instruction_ptr; static int sram_or_scb_offset; static int download_constant_count; -static void process_bitmask __P((int mask_type, symbol_t *sym, int mask)); -static void initialize_symbol __P((symbol_t *symbol)); -static void process_register __P((symbol_t **p_symbol)); -static void format_1_instr __P((int opcode, symbol_ref_t *dest, - expression_t *immed, symbol_ref_t *src, - int ret)); -static void format_2_instr __P((int opcode, symbol_ref_t *dest, - expression_t *places, symbol_ref_t *src, - int ret)); -static void format_3_instr __P((int opcode, symbol_ref_t *src, - expression_t *immed, symbol_ref_t *address)); -static void test_readable_symbol __P((symbol_t *symbol)); -static void test_writable_symbol __P((symbol_t *symbol)); -static void type_check __P((symbol_t *symbol, expression_t *expression, - int and_op)); -static void make_expression __P((expression_t *immed, int value)); -static void add_conditional __P((symbol_t *symbol)); -static int is_download_const __P((expression_t *immed)); +static void process_bitmask(int mask_type, symbol_t *sym, int mask); +static void initialize_symbol(symbol_t *symbol); +static void process_register(symbol_t **p_symbol); +static void format_1_instr(int opcode, symbol_ref_t *dest, + expression_t *immed, symbol_ref_t *src, int ret); +static void format_2_instr(int opcode, symbol_ref_t *dest, + expression_t *places, symbol_ref_t *src, int ret); +static void format_3_instr(int opcode, symbol_ref_t *src, + expression_t *immed, symbol_ref_t *address); +static void test_readable_symbol(symbol_t *symbol); +static void test_writable_symbol(symbol_t *symbol); +static void type_check(symbol_t *symbol, expression_t *expression, int and_op); +static void make_expression(expression_t *immed, int value); +static void add_conditional(symbol_t *symbol); +static int is_download_const(expression_t *immed); #define YYDEBUG 1 #define SRAM_SYMNAME "SRAM_BASE" #define SCB_SYMNAME "SCB_BASE" %} %union { int value; char *str; symbol_t *sym; symbol_ref_t sym_ref; expression_t expression; } %token T_REGISTER %token T_CONST %token T_DOWNLOAD %token T_SCB %token T_SRAM %token T_ALIAS %token T_SIZE %token T_ADDRESS %token T_ACCESS_MODE %token T_MODE %token T_BIT %token T_MASK %token T_NUMBER %token T_PATH %token T_CEXPR %token T_EOF T_INCLUDE %token T_SHR T_SHL T_ROR T_ROL %token T_MVI T_MOV T_CLR T_BMOV %token T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL %token T_ADD T_ADC %token T_INC T_DEC %token T_STC T_CLC %token T_CMP T_NOT T_XOR %token T_TEST T_AND %token T_OR %token T_RET %token T_NOP %token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX %token T_A %token T_SYMBOL %token T_NL %token T_IF T_ELSE T_ELSE_IF T_ENDIF %type reg_symbol address destination source opt_source %type expression immediate immediate_or_a %type ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne %type numerical_value %left '|' %left '&' %left '+' '-' %right '~' %nonassoc UMINUS %% program: include | program include | register | program register | constant | program constant | scratch_ram | program scratch_ram | scb | program scb | label | program label | conditional | program conditional | code | program code ; include: T_INCLUDE '<' T_PATH '>' { include_file($3, BRACKETED_INCLUDE); } | T_INCLUDE '"' T_PATH '"' { include_file($3, QUOTED_INCLUDE); } ; register: T_REGISTER { cur_symtype = REGISTER; } reg_definition ; reg_definition: T_SYMBOL '{' { if ($1->type != UNINITIALIZED) { stop("Register multiply defined", EX_DATAERR); /* NOTREACHED */ } cur_symbol = $1; cur_symbol->type = cur_symtype; initialize_symbol(cur_symbol); } reg_attribute_list '}' { /* * Default to allowing everything in for registers * with no bit or mask definitions. */ if (cur_symbol->info.rinfo->valid_bitmask == 0) cur_symbol->info.rinfo->valid_bitmask = 0xFF; if (cur_symbol->info.rinfo->size == 0) cur_symbol->info.rinfo->size = 1; /* * This might be useful for registers too. */ if (cur_symbol->type != REGISTER) { if (cur_symbol->info.rinfo->address == 0) cur_symbol->info.rinfo->address = sram_or_scb_offset; sram_or_scb_offset += cur_symbol->info.rinfo->size; } cur_symbol = NULL; } ; reg_attribute_list: reg_attribute | reg_attribute_list reg_attribute ; reg_attribute: reg_address | size | access_mode | bit_defn | mask_defn | alias | accumulator | allones | allzeros | none | sindex ; reg_address: T_ADDRESS T_NUMBER { cur_symbol->info.rinfo->address = $2; } ; size: T_SIZE T_NUMBER { cur_symbol->info.rinfo->size = $2; } ; access_mode: T_ACCESS_MODE T_MODE { cur_symbol->info.rinfo->mode = $2; } ; bit_defn: T_BIT T_SYMBOL T_NUMBER { process_bitmask(BIT, $2, $3); } ; mask_defn: T_MASK T_SYMBOL expression { process_bitmask(MASK, $2, $3.value); } ; alias: T_ALIAS T_SYMBOL { if ($2->type != UNINITIALIZED) { stop("Re-definition of register alias", EX_DATAERR); /* NOTREACHED */ } $2->type = ALIAS; initialize_symbol($2); $2->info.ainfo->parent = cur_symbol; } ; accumulator: T_ACCUM { if (accumulator != NULL) { stop("Only one accumulator definition allowed", EX_DATAERR); /* NOTREACHED */ } accumulator = cur_symbol; } ; allones: T_ALLONES { if (allones.symbol != NULL) { stop("Only one definition of allones allowed", EX_DATAERR); /* NOTREACHED */ } allones.symbol = cur_symbol; } ; allzeros: T_ALLZEROS { if (allzeros.symbol != NULL) { stop("Only one definition of allzeros allowed", EX_DATAERR); /* NOTREACHED */ } allzeros.symbol = cur_symbol; } ; none: T_NONE { if (none.symbol != NULL) { stop("Only one definition of none allowed", EX_DATAERR); /* NOTREACHED */ } none.symbol = cur_symbol; } ; sindex: T_SINDEX { if (sindex.symbol != NULL) { stop("Only one definition of sindex allowed", EX_DATAERR); /* NOTREACHED */ } sindex.symbol = cur_symbol; } ; expression: expression '|' expression { $$.value = $1.value | $3.value; symlist_merge(&$$.referenced_syms, &$1.referenced_syms, &$3.referenced_syms); } | expression '&' expression { $$.value = $1.value & $3.value; symlist_merge(&$$.referenced_syms, &$1.referenced_syms, &$3.referenced_syms); } | expression '+' expression { $$.value = $1.value + $3.value; symlist_merge(&$$.referenced_syms, &$1.referenced_syms, &$3.referenced_syms); } | expression '-' expression { $$.value = $1.value - $3.value; symlist_merge(&($$.referenced_syms), &($1.referenced_syms), &($3.referenced_syms)); } | '(' expression ')' { $$ = $2; } | '~' expression { $$ = $2; $$.value = (~$$.value) & 0xFF; } | '-' expression %prec UMINUS { $$ = $2; $$.value = -$$.value; } | T_NUMBER { $$.value = $1; SLIST_INIT(&$$.referenced_syms); } | T_SYMBOL { symbol_t *symbol; symbol = $1; switch (symbol->type) { case ALIAS: symbol = $1->info.ainfo->parent; case REGISTER: case SCBLOC: case SRAMLOC: $$.value = symbol->info.rinfo->address; break; case MASK: case BIT: $$.value = symbol->info.minfo->mask; break; case DOWNLOAD_CONST: case CONST: $$.value = symbol->info.cinfo->value; break; case UNINITIALIZED: default: { char buf[255]; snprintf(buf, sizeof(buf), "Undefined symbol %s referenced", symbol->name); stop(buf, EX_DATAERR); /* NOTREACHED */ break; } } SLIST_INIT(&$$.referenced_syms); symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD); } ; constant: T_CONST T_SYMBOL numerical_value { if ($2->type != UNINITIALIZED) { stop("Re-definition of symbol as a constant", EX_DATAERR); /* NOTREACHED */ } $2->type = CONST; initialize_symbol($2); $2->info.cinfo->value = $3; $2->info.cinfo->define = $1; } | T_CONST T_SYMBOL T_DOWNLOAD { if ($1) { stop("Invalid downloaded constant declaration", EX_DATAERR); /* NOTREACHED */ } if ($2->type != UNINITIALIZED) { stop("Re-definition of symbol as a downloaded constant", EX_DATAERR); /* NOTREACHED */ } $2->type = DOWNLOAD_CONST; initialize_symbol($2); $2->info.cinfo->value = download_constant_count++; $2->info.cinfo->define = FALSE; } ; numerical_value: T_NUMBER { $$ = $1; } | '-' T_NUMBER { $$ = -$2; } ; scratch_ram: T_SRAM '{' { cur_symbol = symtable_get(SRAM_SYMNAME); cur_symtype = SRAMLOC; if (cur_symbol->type != UNINITIALIZED) { stop("Only one SRAM definition allowed", EX_DATAERR); /* NOTREACHED */ } cur_symbol->type = SRAMLOC; initialize_symbol(cur_symbol); } reg_address { sram_or_scb_offset = cur_symbol->info.rinfo->address; } scb_or_sram_reg_list '}' { cur_symbol = NULL; } ; scb: T_SCB '{' { cur_symbol = symtable_get(SCB_SYMNAME); cur_symtype = SCBLOC; if (cur_symbol->type != UNINITIALIZED) { stop("Only one SRAM definition allowed", EX_SOFTWARE); /* NOTREACHED */ } cur_symbol->type = SCBLOC; initialize_symbol(cur_symbol); + /* 64 bytes of SCB space */ + cur_symbol->info.rinfo->size = 64; } reg_address { sram_or_scb_offset = cur_symbol->info.rinfo->address; } scb_or_sram_reg_list '}' { cur_symbol = NULL; } ; scb_or_sram_reg_list: reg_definition | scb_or_sram_reg_list reg_definition ; reg_symbol: T_SYMBOL { process_register(&$1); $$.symbol = $1; $$.offset = 0; } | T_SYMBOL '[' T_SYMBOL ']' { process_register(&$1); if ($3->type != CONST) { stop("register offset must be a constant", EX_DATAERR); /* NOTREACHED */ } if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) { stop("Accessing offset beyond range of register", EX_DATAERR); /* NOTREACHED */ } $$.symbol = $1; $$.offset = $3->info.cinfo->value; } | T_SYMBOL '[' T_NUMBER ']' { process_register(&$1); if (($3 + 1) > $1->info.rinfo->size) { stop("Accessing offset beyond range of register", EX_DATAERR); /* NOTREACHED */ } $$.symbol = $1; $$.offset = $3; } | T_A { if (accumulator == NULL) { stop("No accumulator has been defined", EX_DATAERR); /* NOTREACHED */ } $$.symbol = accumulator; $$.offset = 0; } ; destination: reg_symbol { test_writable_symbol($1.symbol); $$ = $1; } ; immediate: expression { $$ = $1; } ; immediate_or_a: expression { $$ = $1; } | T_A { SLIST_INIT(&$$.referenced_syms); $$.value = 0; } ; source: reg_symbol { test_readable_symbol($1.symbol); $$ = $1; } ; opt_source: { $$.symbol = NULL; $$.offset = 0; } | ',' source { $$ = $2; } ; ret: { $$ = 0; } | T_RET { $$ = 1; } ; label: T_SYMBOL ':' { if ($1->type != UNINITIALIZED) { stop("Program label multiply defined", EX_DATAERR); /* NOTREACHED */ } $1->type = LABEL; initialize_symbol($1); $1->info.linfo->address = instruction_ptr; } ; address: T_SYMBOL { $$.symbol = $1; $$.offset = 0; } | T_SYMBOL '+' T_NUMBER { $$.symbol = $1; $$.offset = $3; } | T_SYMBOL '-' T_NUMBER { $$.symbol = $1; $$.offset = -$3; } | '.' { $$.symbol = NULL; $$.offset = 0; } | '.' '+' T_NUMBER { $$.symbol = NULL; $$.offset = $3; } | '.' '-' T_NUMBER { $$.symbol = NULL; $$.offset = -$3; } ; conditional: T_IF T_CEXPR '{' { scope_t *new_scope; add_conditional($2); new_scope = scope_alloc(); new_scope->type = SCOPE_IF; new_scope->begin_addr = instruction_ptr; new_scope->func_num = $2->info.condinfo->func_num; } | T_ELSE T_IF T_CEXPR '{' { scope_t *new_scope; scope_t *scope_context; scope_t *last_scope; /* * Ensure that the previous scope is either an * if or and else if. */ scope_context = SLIST_FIRST(&scope_stack); last_scope = TAILQ_LAST(&scope_context->inner_scope, scope_tailq); if (last_scope == NULL || last_scope->type == T_ELSE) { stop("'else if' without leading 'if'", EX_DATAERR); /* NOTREACHED */ } add_conditional($3); new_scope = scope_alloc(); new_scope->type = SCOPE_ELSE_IF; new_scope->begin_addr = instruction_ptr; new_scope->func_num = $3->info.condinfo->func_num; } | T_ELSE '{' { scope_t *new_scope; scope_t *scope_context; scope_t *last_scope; /* * Ensure that the previous scope is either an * if or and else if. */ scope_context = SLIST_FIRST(&scope_stack); last_scope = TAILQ_LAST(&scope_context->inner_scope, scope_tailq); if (last_scope == NULL || last_scope->type == SCOPE_ELSE) { stop("'else' without leading 'if'", EX_DATAERR); /* NOTREACHED */ } new_scope = scope_alloc(); new_scope->type = SCOPE_ELSE; new_scope->begin_addr = instruction_ptr; } ; conditional: '}' { scope_t *scope_context; - scope_t *last_scope; scope_context = SLIST_FIRST(&scope_stack); if (scope_context->type == SCOPE_ROOT) { stop("Unexpected '}' encountered", EX_DATAERR); /* NOTREACHED */ } scope_context->end_addr = instruction_ptr; /* Pop the scope */ SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links); process_scope(scope_context); if (SLIST_FIRST(&scope_stack) == NULL) { stop("Unexpected '}' encountered", EX_DATAERR); /* NOTREACHED */ } } ; f1_opcode: T_AND { $$ = AIC_OP_AND; } | T_XOR { $$ = AIC_OP_XOR; } | T_ADD { $$ = AIC_OP_ADD; } | T_ADC { $$ = AIC_OP_ADC; } ; code: f1_opcode destination ',' immediate_or_a opt_source ret ';' { format_1_instr($1, &$2, &$4, &$5, $6); } ; code: T_OR reg_symbol ',' immediate_or_a opt_source ret ';' { format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6); } ; code: T_INC destination opt_source ret ';' { expression_t immed; make_expression(&immed, 1); format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); } ; code: T_DEC destination opt_source ret ';' { expression_t immed; make_expression(&immed, -1); format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); } ; code: T_CLC ret ';' { expression_t immed; make_expression(&immed, -1); format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2); } | T_CLC T_MVI destination ',' immediate_or_a ret ';' { format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6); } ; code: T_STC ret ';' { expression_t immed; make_expression(&immed, 1); format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2); } | T_STC destination ret ';' { expression_t immed; make_expression(&immed, 1); format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3); } ; code: T_BMOV destination ',' source ',' immediate_or_a ret ';' { format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7); } ; code: T_MOV destination ',' source ret ';' { expression_t immed; make_expression(&immed, 0xff); format_1_instr(AIC_OP_AND, &$2, &immed, &$4, $5); } ; code: T_MVI destination ',' immediate_or_a ret ';' { format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5); } ; code: T_NOT destination opt_source ret ';' { expression_t immed; make_expression(&immed, 0xff); format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4); } ; code: T_CLR destination ret ';' { expression_t immed; make_expression(&immed, 0xff); format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3); } ; code: T_NOP ret ';' { expression_t immed; make_expression(&immed, 0xff); format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2); } ; code: T_RET ';' { expression_t immed; make_expression(&immed, 0xff); format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE); } ; /* * This grammer differs from the one in the aic7xxx * reference manual since the grammer listed there is * ambiguous and causes a shift/reduce conflict. * It also seems more logical as the "immediate" * argument is listed as the second arg like the * other formats. */ f2_opcode: T_SHL { $$ = AIC_OP_SHL; } | T_SHR { $$ = AIC_OP_SHR; } | T_ROL { $$ = AIC_OP_ROL; } | T_ROR { $$ = AIC_OP_ROR; } ; code: f2_opcode destination ',' expression opt_source ret ';' { format_2_instr($1, &$2, &$4, &$5, $6); } ; jmp_jc_jnc_call: T_JMP { $$ = AIC_OP_JMP; } | T_JC { $$ = AIC_OP_JC; } | T_JNC { $$ = AIC_OP_JNC; } | T_CALL { $$ = AIC_OP_CALL; } ; jz_jnz: T_JZ { $$ = AIC_OP_JZ; } | T_JNZ { $$ = AIC_OP_JNZ; } ; je_jne: T_JE { $$ = AIC_OP_JE; } | T_JNE { $$ = AIC_OP_JNE; } ; code: jmp_jc_jnc_call address ';' { expression_t immed; make_expression(&immed, 0); format_3_instr($1, &sindex, &immed, &$2); } ; code: T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';' { format_3_instr($5, &$2, &$4, &$6); } ; code: T_TEST source ',' immediate_or_a jz_jnz address ';' { format_3_instr($5, &$2, &$4, &$6); } ; code: T_CMP source ',' immediate_or_a je_jne address ';' { format_3_instr($5, &$2, &$4, &$6); } ; code: T_MOV source jmp_jc_jnc_call address ';' { expression_t immed; make_expression(&immed, 0); format_3_instr($3, &$2, &immed, &$4); } ; code: T_MVI immediate jmp_jc_jnc_call address ';' { format_3_instr($3, &allzeros, &$2, &$4); } ; %% static void -process_bitmask(mask_type, sym, mask) - int mask_type; - symbol_t *sym; - int mask; +process_bitmask(int mask_type, symbol_t *sym, int mask) { /* * Add the current register to its * symbol list, if it already exists, * warn if we are setting it to a * different value, or in the bit to * the "allowed bits" of this register. */ if (sym->type == UNINITIALIZED) { sym->type = mask_type; initialize_symbol(sym); if (mask_type == BIT) { if (mask == 0) { stop("Bitmask with no bits set", EX_DATAERR); /* NOTREACHED */ } if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) { stop("Bitmask with more than one bit set", EX_DATAERR); /* NOTREACHED */ } } sym->info.minfo->mask = mask; } else if (sym->type != mask_type) { stop("Bit definition mirrors a definition of the same " " name, but a different type", EX_DATAERR); /* NOTREACHED */ } else if (mask != sym->info.minfo->mask) { stop("Bitmask redefined with a conflicting value", EX_DATAERR); /* NOTREACHED */ } /* Fail if this symbol is already listed */ if (symlist_search(&(sym->info.minfo->symrefs), cur_symbol->name) != NULL) { stop("Bitmask defined multiple times for register", EX_DATAERR); /* NOTREACHED */ } symlist_add(&(sym->info.minfo->symrefs), cur_symbol, SYMLIST_INSERT_HEAD); cur_symbol->info.rinfo->valid_bitmask |= mask; cur_symbol->info.rinfo->typecheck_masks = TRUE; } static void -initialize_symbol(symbol) - symbol_t *symbol; +initialize_symbol(symbol_t *symbol) { switch (symbol->type) { case UNINITIALIZED: stop("Call to initialize_symbol with type field unset", EX_SOFTWARE); /* NOTREACHED */ break; case REGISTER: case SRAMLOC: case SCBLOC: symbol->info.rinfo = (struct reg_info *)malloc(sizeof(struct reg_info)); if (symbol->info.rinfo == NULL) { stop("Can't create register info", EX_SOFTWARE); /* NOTREACHED */ } memset(symbol->info.rinfo, 0, sizeof(struct reg_info)); break; case ALIAS: symbol->info.ainfo = (struct alias_info *)malloc(sizeof(struct alias_info)); if (symbol->info.ainfo == NULL) { stop("Can't create alias info", EX_SOFTWARE); /* NOTREACHED */ } memset(symbol->info.ainfo, 0, sizeof(struct alias_info)); break; case MASK: case BIT: symbol->info.minfo = (struct mask_info *)malloc(sizeof(struct mask_info)); if (symbol->info.minfo == NULL) { stop("Can't create bitmask info", EX_SOFTWARE); /* NOTREACHED */ } memset(symbol->info.minfo, 0, sizeof(struct mask_info)); SLIST_INIT(&(symbol->info.minfo->symrefs)); break; case CONST: case DOWNLOAD_CONST: symbol->info.cinfo = (struct const_info *)malloc(sizeof(struct const_info)); if (symbol->info.cinfo == NULL) { stop("Can't create alias info", EX_SOFTWARE); /* NOTREACHED */ } memset(symbol->info.cinfo, 0, sizeof(struct const_info)); break; case LABEL: symbol->info.linfo = (struct label_info *)malloc(sizeof(struct label_info)); if (symbol->info.linfo == NULL) { stop("Can't create label info", EX_SOFTWARE); /* NOTREACHED */ } memset(symbol->info.linfo, 0, sizeof(struct label_info)); break; case CONDITIONAL: symbol->info.condinfo = (struct cond_info *)malloc(sizeof(struct cond_info)); if (symbol->info.condinfo == NULL) { stop("Can't create conditional info", EX_SOFTWARE); /* NOTREACHED */ } memset(symbol->info.condinfo, 0, sizeof(struct cond_info)); break; default: stop("Call to initialize_symbol with invalid symbol type", EX_SOFTWARE); /* NOTREACHED */ break; } } static void -process_register(p_symbol) - symbol_t **p_symbol; +process_register(symbol_t **p_symbol) { char buf[255]; symbol_t *symbol = *p_symbol; if (symbol->type == UNINITIALIZED) { snprintf(buf, sizeof(buf), "Undefined register %s", symbol->name); stop(buf, EX_DATAERR); /* NOTREACHED */ } else if (symbol->type == ALIAS) { *p_symbol = symbol->info.ainfo->parent; } else if ((symbol->type != REGISTER) && (symbol->type != SCBLOC) && (symbol->type != SRAMLOC)) { snprintf(buf, sizeof(buf), "Specified symbol %s is not a register", symbol->name); stop(buf, EX_DATAERR); } } static void -format_1_instr(opcode, dest, immed, src, ret) - int opcode; - symbol_ref_t *dest; - expression_t *immed; - symbol_ref_t *src; - int ret; +format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed, + symbol_ref_t *src, int ret) { struct instruction *instr; struct ins_format1 *f1_instr; if (src->symbol == NULL) src = dest; /* Test register permissions */ test_writable_symbol(dest->symbol); test_readable_symbol(src->symbol); /* Ensure that immediate makes sense for this destination */ type_check(dest->symbol, immed, opcode); /* Allocate sequencer space for the instruction and fill it out */ instr = seq_alloc(); f1_instr = &instr->format.format1; f1_instr->ret = ret ? 1 : 0; f1_instr->opcode = opcode; f1_instr->destination = dest->symbol->info.rinfo->address + dest->offset; f1_instr->source = src->symbol->info.rinfo->address + src->offset; f1_instr->immediate = immed->value; if (is_download_const(immed)) f1_instr->parity = 1; symlist_free(&immed->referenced_syms); instruction_ptr++; } static void -format_2_instr(opcode, dest, places, src, ret) - int opcode; - symbol_ref_t *dest; - expression_t *places; - symbol_ref_t *src; - int ret; +format_2_instr(int opcode, symbol_ref_t *dest, expression_t *places, + symbol_ref_t *src, int ret) { struct instruction *instr; struct ins_format2 *f2_instr; uint8_t shift_control; if (src->symbol == NULL) src = dest; /* Test register permissions */ test_writable_symbol(dest->symbol); test_readable_symbol(src->symbol); /* Allocate sequencer space for the instruction and fill it out */ instr = seq_alloc(); f2_instr = &instr->format.format2; f2_instr->ret = ret ? 1 : 0; f2_instr->opcode = AIC_OP_ROL; f2_instr->destination = dest->symbol->info.rinfo->address + dest->offset; f2_instr->source = src->symbol->info.rinfo->address + src->offset; if (places->value > 8 || places->value <= 0) { stop("illegal shift value", EX_DATAERR); /* NOTREACHED */ } switch (opcode) { case AIC_OP_SHL: if (places->value == 8) shift_control = 0xf0; else shift_control = (places->value << 4) | places->value; break; case AIC_OP_SHR: if (places->value == 8) { shift_control = 0xf8; } else { shift_control = (places->value << 4) | (8 - places->value) | 0x08; } break; case AIC_OP_ROL: shift_control = places->value & 0x7; break; case AIC_OP_ROR: shift_control = (8 - places->value) | 0x08; break; default: shift_control = 0; /* Quiet Compiler */ stop("Invalid shift operation specified", EX_SOFTWARE); /* NOTREACHED */ break; }; f2_instr->shift_control = shift_control; symlist_free(&places->referenced_syms); instruction_ptr++; } static void -format_3_instr(opcode, src, immed, address) - int opcode; - symbol_ref_t *src; - expression_t *immed; - symbol_ref_t *address; +format_3_instr(int opcode, symbol_ref_t *src, + expression_t *immed, symbol_ref_t *address) { struct instruction *instr; struct ins_format3 *f3_instr; int addr; /* Test register permissions */ test_readable_symbol(src->symbol); /* Ensure that immediate makes sense for this source */ type_check(src->symbol, immed, opcode); /* Allocate sequencer space for the instruction and fill it out */ instr = seq_alloc(); f3_instr = &instr->format.format3; if (address->symbol == NULL) { /* 'dot' referrence. Use the current instruction pointer */ addr = instruction_ptr + address->offset; } else if (address->symbol->type == UNINITIALIZED) { /* forward reference */ addr = address->offset; instr->patch_label = address->symbol; } else addr = address->symbol->info.linfo->address + address->offset; f3_instr->opcode = opcode; f3_instr->address = addr; f3_instr->source = src->symbol->info.rinfo->address + src->offset; f3_instr->immediate = immed->value; if (is_download_const(immed)) f3_instr->parity = 1; symlist_free(&immed->referenced_syms); instruction_ptr++; } static void -test_readable_symbol(symbol) - symbol_t *symbol; +test_readable_symbol(symbol_t *symbol) { if (symbol->info.rinfo->mode == WO) { stop("Write Only register specified as source", EX_DATAERR); /* NOTREACHED */ } } static void -test_writable_symbol(symbol) - symbol_t *symbol; +test_writable_symbol(symbol_t *symbol) { if (symbol->info.rinfo->mode == RO) { stop("Read Only register specified as destination", EX_DATAERR); /* NOTREACHED */ } } static void -type_check(symbol, expression, opcode) - symbol_t *symbol; - expression_t *expression; - int opcode; +type_check(symbol_t *symbol, expression_t *expression, int opcode) { symbol_node_t *node; int and_op; char buf[255]; and_op = FALSE; if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ) and_op = TRUE; /* * Make sure that we aren't attempting to write something * that hasn't been defined. If this is an and operation, * this is a mask, so "undefined" bits are okay. */ if (and_op == FALSE && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) { snprintf(buf, sizeof(buf), "Invalid bit(s) 0x%x in immediate written to %s", expression->value & ~symbol->info.rinfo->valid_bitmask, symbol->name); stop(buf, EX_DATAERR); /* NOTREACHED */ } /* * Now make sure that all of the symbols referenced by the * expression are defined for this register. */ if(symbol->info.rinfo->typecheck_masks != FALSE) { for(node = expression->referenced_syms.slh_first; node != NULL; node = node->links.sle_next) { if ((node->symbol->type == MASK || node->symbol->type == BIT) && symlist_search(&node->symbol->info.minfo->symrefs, symbol->name) == NULL) { snprintf(buf, sizeof(buf), "Invalid bit or mask %s " "for register %s", node->symbol->name, symbol->name); stop(buf, EX_DATAERR); /* NOTREACHED */ } } } } static void -make_expression(immed, value) - expression_t *immed; - int value; +make_expression(expression_t *immed, int value) { SLIST_INIT(&immed->referenced_syms); immed->value = value & 0xff; } static void -add_conditional(symbol) - symbol_t *symbol; +add_conditional(symbol_t *symbol) { static int numfuncs; if (numfuncs == 0) { /* add a special conditional, "0" */ symbol_t *false_func; false_func = symtable_get("0"); if (false_func->type != UNINITIALIZED) { stop("Conditional expression '0' " "conflicts with a symbol", EX_DATAERR); /* NOTREACHED */ } false_func->type = CONDITIONAL; initialize_symbol(false_func); false_func->info.condinfo->func_num = numfuncs++; symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD); } /* This condition has occurred before */ if (symbol->type == CONDITIONAL) return; if (symbol->type != UNINITIALIZED) { stop("Conditional expression conflicts with a symbol", EX_DATAERR); /* NOTREACHED */ } symbol->type = CONDITIONAL; initialize_symbol(symbol); symbol->info.condinfo->func_num = numfuncs++; symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD); } void -yyerror(string) - const char *string; +yyerror(const char *string) { stop(string, EX_DATAERR); } static int -is_download_const(immed) - expression_t *immed; +is_download_const(expression_t *immed) { if ((immed->referenced_syms.slh_first != NULL) && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST)) return (TRUE); return (FALSE); } diff --git a/sys/dev/aic7xxx/aicasm/aicasm_insformat.h b/sys/dev/aic7xxx/aicasm/aicasm_insformat.h index 64667472b0ae..c729e573b4aa 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm_insformat.h +++ b/sys/dev/aic7xxx/aicasm/aicasm_insformat.h @@ -1,123 +1,129 @@ /* * Instruction formats for the sequencer program downloaded to * Aic7xxx SCSI host adapters * * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id$ + * * $FreeBSD$ */ +#if linux +#include +#else #include +#endif struct ins_format1 { #if BYTE_ORDER == LITTLE_ENDIAN uint32_t immediate : 8, source : 9, destination : 9, ret : 1, opcode : 4, parity : 1; #else uint32_t parity : 1, opcode : 4, ret : 1, destination : 9, source : 9, immediate : 8; #endif }; struct ins_format2 { #if BYTE_ORDER == LITTLE_ENDIAN uint32_t shift_control : 8, source : 9, destination : 9, ret : 1, opcode : 4, parity : 1; #else uint32_t parity : 1, opcode : 4, ret : 1, destination : 9, source : 9, shift_control : 8; #endif }; struct ins_format3 { #if BYTE_ORDER == LITTLE_ENDIAN uint32_t immediate : 8, source : 9, address : 10, opcode : 4, parity : 1; #else uint32_t parity : 1, opcode : 4, address : 10, source : 9, immediate : 8; #endif }; union ins_formats { struct ins_format1 format1; struct ins_format2 format2; struct ins_format3 format3; - uint8_t bytes[4]; + uint8_t bytes[4]; uint32_t integer; }; struct instruction { union ins_formats format; u_int srcline; struct symbol *patch_label; STAILQ_ENTRY(instruction) links; }; #define AIC_OP_OR 0x0 #define AIC_OP_AND 0x1 #define AIC_OP_XOR 0x2 #define AIC_OP_ADD 0x3 #define AIC_OP_ADC 0x4 #define AIC_OP_ROL 0x5 #define AIC_OP_BMOV 0x6 #define AIC_OP_JMP 0x8 #define AIC_OP_JC 0x9 #define AIC_OP_JNC 0xa #define AIC_OP_CALL 0xb #define AIC_OP_JNE 0xc #define AIC_OP_JNZ 0xd #define AIC_OP_JE 0xe #define AIC_OP_JZ 0xf /* Pseudo Ops */ #define AIC_OP_SHL 0x10 #define AIC_OP_SHR 0x20 #define AIC_OP_ROR 0x30 diff --git a/sys/dev/aic7xxx/aicasm/aicasm_scan.l b/sys/dev/aic7xxx/aicasm/aicasm_scan.l index 48170d68154d..a7a72605d8ef 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm_scan.l +++ b/sys/dev/aic7xxx/aicasm/aicasm_scan.l @@ -1,287 +1,300 @@ %{ /* * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler. * * Copyright (c) 1997, 1998 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id$ + * * $FreeBSD$ */ #include #include #include #include #include +#ifdef __linux__ +#include "../queue.h" +#else #include +#endif #include "aicasm.h" #include "aicasm_symbol.h" #include "y.tab.h" #define MAX_STR_CONST 256 char string_buf[MAX_STR_CONST]; char *string_buf_ptr; int parren_count; %} PATH [-/A-Za-z0-9_.]*[./][-/A-Za-z0-9_.]* WORD [A-Za-z_][-A-Za-z_0-9]* SPACE [ \t]+ %x COMMENT %x CEXPR %x INCLUDE %% \n { ++yylineno; } "/*" { BEGIN COMMENT; /* Enter comment eating state */ } "/*" { fprintf(stderr, "Warning! Comment within comment."); } \n { ++yylineno; } [^*/\n]* ; "*"+[^*/\n]* ; "/"+[^*/\n]* ; "*"+"/" { BEGIN INITIAL; } if[ \t]*\( { string_buf_ptr = string_buf; parren_count = 1; BEGIN CEXPR; return T_IF; } \( { *string_buf_ptr++ = '('; parren_count++; } \) { parren_count--; if (parren_count == 0) { /* All done */ BEGIN INITIAL; *string_buf_ptr = '\0'; yylval.sym = symtable_get(string_buf); return T_CEXPR; } else { *string_buf_ptr++ = ')'; } } \n { ++yylineno; } -[^()\n]+ { +[^()\n]+ { char *yptr = yytext; - while (*yptr != '\0') - *string_buf_ptr++ = *yptr++; + while (*yptr != '\0') { + /* Remove duplicate spaces */ + if (*yptr == '\t') + *yptr = ' '; + if (*yptr == ' ' + && string_buf_ptr != string_buf + && string_buf_ptr[-1] == ' ') + yptr++; + else + *string_buf_ptr++ = *yptr++; + } } {SPACE} ; /* Register/SCB/SRAM definition keywords */ register { return T_REGISTER; } const { yylval.value = FALSE; return T_CONST; } download { return T_DOWNLOAD; } address { return T_ADDRESS; } access_mode { return T_ACCESS_MODE; } RW|RO|WO { if (strcmp(yytext, "RW") == 0) yylval.value = RW; else if (strcmp(yytext, "RO") == 0) yylval.value = RO; else yylval.value = WO; return T_MODE; } bit { return T_BIT; } mask { return T_MASK; } alias { return T_ALIAS; } size { return T_SIZE; } scb { return T_SCB; } scratch_ram { return T_SRAM; } accumulator { return T_ACCUM; } allones { return T_ALLONES; } allzeros { return T_ALLZEROS; } none { return T_NONE; } sindex { return T_SINDEX; } A { return T_A; } /* Opcodes */ shl { return T_SHL; } shr { return T_SHR; } ror { return T_ROR; } rol { return T_ROL; } mvi { return T_MVI; } mov { return T_MOV; } clr { return T_CLR; } jmp { return T_JMP; } jc { return T_JC; } jnc { return T_JNC; } je { return T_JE; } jne { return T_JNE; } jz { return T_JZ; } jnz { return T_JNZ; } call { return T_CALL; } add { return T_ADD; } adc { return T_ADC; } bmov { return T_BMOV; } inc { return T_INC; } dec { return T_DEC; } stc { return T_STC; } clc { return T_CLC; } cmp { return T_CMP; } not { return T_NOT; } xor { return T_XOR; } test { return T_TEST;} and { return T_AND; } or { return T_OR; } ret { return T_RET; } nop { return T_NOP; } else { return T_ELSE; } /* Allowed Symbols */ [-+,:()~|&."{};<>[\]!] { return yytext[0]; } /* Number processing */ 0[0-7]* { yylval.value = strtol(yytext, NULL, 8); return T_NUMBER; } 0[xX][0-9a-fA-F]+ { yylval.value = strtoul(yytext + 2, NULL, 16); return T_NUMBER; } [1-9][0-9]* { yylval.value = strtol(yytext, NULL, 10); return T_NUMBER; } /* Include Files */ #include { return T_INCLUDE; BEGIN INCLUDE;} [<>\"] { return yytext[0]; } {PATH} { yylval.str = strdup(yytext); return T_PATH; } ; { BEGIN INITIAL; return yytext[0]; } . { stop("Invalid include line", EX_DATAERR); } /* For parsing C include files with #define foo */ #define { yylval.value = TRUE; return T_CONST; } /* Throw away macros */ #define[^\n]*[()]+[^\n]* ; {PATH} { yylval.str = strdup(yytext); return T_PATH; } {WORD} { yylval.sym = symtable_get(yytext); return T_SYMBOL; } . { char buf[255]; snprintf(buf, sizeof(buf), "Invalid character " "'%c'", yytext[0]); stop(buf, EX_DATAERR); } %% typedef struct include { YY_BUFFER_STATE buffer; int lineno; char *filename; SLIST_ENTRY(include) links; }include_t; SLIST_HEAD(, include) include_stack; void -include_file(file_name, type) - char *file_name; - include_type type; +include_file(char *file_name, include_type type) { FILE *newfile; include_t *include; newfile = NULL; /* Try the current directory first */ if (includes_search_curdir != 0 || type == SOURCE_FILE) newfile = fopen(file_name, "r"); if (newfile == NULL && type != SOURCE_FILE) { path_entry_t include_dir; for (include_dir = search_path.slh_first; include_dir != NULL; include_dir = include_dir->links.sle_next) { char fullname[PATH_MAX]; if ((include_dir->quoted_includes_only == TRUE) && (type != QUOTED_INCLUDE)) continue; snprintf(fullname, sizeof(fullname), "%s/%s", include_dir->directory, file_name); if ((newfile = fopen(fullname, "r")) != NULL) break; } } if (newfile == NULL) { perror(file_name); stop("Unable to open input file", EX_SOFTWARE); /* NOTREACHED */ } if (type != SOURCE_FILE) { include = (include_t *)malloc(sizeof(include_t)); if (include == NULL) { stop("Unable to allocate include stack entry", EX_SOFTWARE); /* NOTREACHED */ } include->buffer = YY_CURRENT_BUFFER; include->lineno = yylineno; include->filename = yyfilename; SLIST_INSERT_HEAD(&include_stack, include, links); } yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); yylineno = 1; yyfilename = strdup(file_name); } int yywrap() { include_t *include; yy_delete_buffer(YY_CURRENT_BUFFER); (void)fclose(yyin); if (yyfilename != NULL) free(yyfilename); yyfilename = NULL; include = include_stack.slh_first; if (include != NULL) { yy_switch_to_buffer(include->buffer); yylineno = include->lineno; yyfilename = include->filename; SLIST_REMOVE_HEAD(&include_stack, links); free(include); return (0); } return (1); } diff --git a/sys/dev/aic7xxx/aicasm/aicasm_symbol.c b/sys/dev/aic7xxx/aicasm/aicasm_symbol.c index 43440ea4f40f..4f5be1eccd65 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm_symbol.c +++ b/sys/dev/aic7xxx/aicasm/aicasm_symbol.c @@ -1,475 +1,468 @@ /* * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation * * Copyright (c) 1997 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id$ + * * $FreeBSD$ */ - #include +#ifdef __linux__ +#include +#else #include +#endif #include #include #include #include #include #include "aicasm_symbol.h" #include "aicasm.h" static DB *symtable; symbol_t * -symbol_create(name) - char *name; +symbol_create(char *name) { symbol_t *new_symbol; new_symbol = (symbol_t *)malloc(sizeof(symbol_t)); if (new_symbol == NULL) { perror("Unable to create new symbol"); exit(EX_SOFTWARE); } memset(new_symbol, 0, sizeof(*new_symbol)); new_symbol->name = strdup(name); new_symbol->type = UNINITIALIZED; return (new_symbol); } void -symbol_delete(symbol) - symbol_t *symbol; +symbol_delete(symbol_t *symbol) { if (symtable != NULL) { DBT key; key.data = symbol->name; key.size = strlen(symbol->name); symtable->del(symtable, &key, /*flags*/0); } switch(symbol->type) { case SCBLOC: case SRAMLOC: case REGISTER: if (symbol->info.rinfo != NULL) free(symbol->info.rinfo); break; case ALIAS: if (symbol->info.ainfo != NULL) free(symbol->info.ainfo); break; case MASK: case BIT: if (symbol->info.minfo != NULL) { symlist_free(&symbol->info.minfo->symrefs); free(symbol->info.minfo); } break; case DOWNLOAD_CONST: case CONST: if (symbol->info.cinfo != NULL) free(symbol->info.cinfo); break; case LABEL: if (symbol->info.linfo != NULL) free(symbol->info.linfo); break; case UNINITIALIZED: default: break; } free(symbol->name); free(symbol); } void symtable_open() { symtable = dbopen(/*filename*/NULL, O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH, /*openinfo*/NULL); if (symtable == NULL) { perror("Symbol table creation failed"); exit(EX_SOFTWARE); /* NOTREACHED */ } } void symtable_close() { if (symtable != NULL) { DBT key; DBT data; while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { symbol_t *stored_ptr; memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); symbol_delete(stored_ptr); } symtable->close(symtable); } } /* * The semantics of get is to return an uninitialized symbol entry * if a lookup fails. */ symbol_t * -symtable_get(name) - char *name; +symtable_get(char *name) { symbol_t *stored_ptr; DBT key; DBT data; int retval; key.data = (void *)name; key.size = strlen(name); if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) { if (retval == -1) { perror("Symbol table get operation failed"); exit(EX_SOFTWARE); /* NOTREACHED */ } else if (retval == 1) { /* Symbol wasn't found, so create a new one */ symbol_t *new_symbol; new_symbol = symbol_create(name); data.data = &new_symbol; data.size = sizeof(new_symbol); if (symtable->put(symtable, &key, &data, /*flags*/0) !=0) { perror("Symtable put failed"); exit(EX_SOFTWARE); } return (new_symbol); } else { perror("Unexpected return value from db get routine"); exit(EX_SOFTWARE); /* NOTREACHED */ } } memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); return (stored_ptr); } symbol_node_t * -symlist_search(symlist, symname) - symlist_t *symlist; - char *symname; +symlist_search(symlist_t *symlist, char *symname) { symbol_node_t *curnode; curnode = symlist->slh_first; while(curnode != NULL) { if (strcmp(symname, curnode->symbol->name) == 0) break; curnode = curnode->links.sle_next; } return (curnode); } void -symlist_add(symlist, symbol, how) - symlist_t *symlist; - symbol_t *symbol; - int how; +symlist_add(symlist_t *symlist, symbol_t *symbol, int how) { symbol_node_t *newnode; newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t)); if (newnode == NULL) { stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE); /* NOTREACHED */ } newnode->symbol = symbol; if (how == SYMLIST_SORT) { symbol_node_t *curnode; int mask; mask = FALSE; switch(symbol->type) { case REGISTER: case SCBLOC: case SRAMLOC: break; case BIT: case MASK: mask = TRUE; break; default: stop("symlist_add: Invalid symbol type for sorting", EX_SOFTWARE); /* NOTREACHED */ } curnode = symlist->slh_first; if (curnode == NULL || (mask && (curnode->symbol->info.minfo->mask > newnode->symbol->info.minfo->mask)) || (!mask && (curnode->symbol->info.rinfo->address > newnode->symbol->info.rinfo->address))) { SLIST_INSERT_HEAD(symlist, newnode, links); return; } while (1) { if (curnode->links.sle_next == NULL) { SLIST_INSERT_AFTER(curnode, newnode, links); break; } else { symbol_t *cursymbol; cursymbol = curnode->links.sle_next->symbol; if ((mask && (cursymbol->info.minfo->mask > symbol->info.minfo->mask)) || (!mask &&(cursymbol->info.rinfo->address > symbol->info.rinfo->address))){ SLIST_INSERT_AFTER(curnode, newnode, links); break; } } curnode = curnode->links.sle_next; } } else { SLIST_INSERT_HEAD(symlist, newnode, links); } } void -symlist_free(symlist) - symlist_t *symlist; +symlist_free(symlist_t *symlist) { symbol_node_t *node1, *node2; node1 = symlist->slh_first; while (node1 != NULL) { node2 = node1->links.sle_next; free(node1); node1 = node2; } SLIST_INIT(symlist); } void -symlist_merge(symlist_dest, symlist_src1, symlist_src2) - symlist_t *symlist_dest; - symlist_t *symlist_src1; - symlist_t *symlist_src2; +symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1, + symlist_t *symlist_src2) { symbol_node_t *node; *symlist_dest = *symlist_src1; while((node = symlist_src2->slh_first) != NULL) { SLIST_REMOVE_HEAD(symlist_src2, links); SLIST_INSERT_HEAD(symlist_dest, node, links); } /* These are now empty */ SLIST_INIT(symlist_src1); SLIST_INIT(symlist_src2); } void -symtable_dump(ofile) - FILE *ofile; +symtable_dump(FILE *ofile) { /* * Sort the registers by address with a simple insertion sort. * Put bitmasks next to the first register that defines them. * Put constants at the end. */ symlist_t registers; symlist_t masks; symlist_t constants; symlist_t download_constants; symlist_t aliases; SLIST_INIT(®isters); SLIST_INIT(&masks); SLIST_INIT(&constants); SLIST_INIT(&download_constants); SLIST_INIT(&aliases); if (symtable != NULL) { DBT key; DBT data; int flag = R_FIRST; while (symtable->seq(symtable, &key, &data, flag) == 0) { symbol_t *cursym; memcpy(&cursym, data.data, sizeof(cursym)); switch(cursym->type) { case REGISTER: case SCBLOC: case SRAMLOC: symlist_add(®isters, cursym, SYMLIST_SORT); break; case MASK: case BIT: symlist_add(&masks, cursym, SYMLIST_SORT); break; case CONST: if (cursym->info.cinfo->define == FALSE) { symlist_add(&constants, cursym, SYMLIST_INSERT_HEAD); } break; case DOWNLOAD_CONST: symlist_add(&download_constants, cursym, SYMLIST_INSERT_HEAD); break; case ALIAS: symlist_add(&aliases, cursym, SYMLIST_INSERT_HEAD); break; default: break; } flag = R_NEXT; } /* Put in the masks and bits */ while (masks.slh_first != NULL) { symbol_node_t *curnode; symbol_node_t *regnode; char *regname; curnode = masks.slh_first; SLIST_REMOVE_HEAD(&masks, links); regnode = curnode->symbol->info.minfo->symrefs.slh_first; regname = regnode->symbol->name; regnode = symlist_search(®isters, regname); SLIST_INSERT_AFTER(regnode, curnode, links); } /* Add the aliases */ while (aliases.slh_first != NULL) { symbol_node_t *curnode; symbol_node_t *regnode; char *regname; curnode = aliases.slh_first; SLIST_REMOVE_HEAD(&aliases, links); regname = curnode->symbol->info.ainfo->parent->name; regnode = symlist_search(®isters, regname); SLIST_INSERT_AFTER(regnode, curnode, links); } /* Output what we have */ fprintf(ofile, "/* * DO NOT EDIT - This file is automatically generated. */\n"); while (registers.slh_first != NULL) { symbol_node_t *curnode; - uint8_t value; + u_int8_t value; char *tab_str; char *tab_str2; curnode = registers.slh_first; SLIST_REMOVE_HEAD(®isters, links); switch(curnode->symbol->type) { case REGISTER: case SCBLOC: case SRAMLOC: fprintf(ofile, "\n"); value = curnode->symbol->info.rinfo->address; tab_str = "\t"; tab_str2 = "\t\t"; break; case ALIAS: { symbol_t *parent; parent = curnode->symbol->info.ainfo->parent; value = parent->info.rinfo->address; tab_str = "\t"; tab_str2 = "\t\t"; break; } case MASK: case BIT: value = curnode->symbol->info.minfo->mask; tab_str = "\t\t"; tab_str2 = "\t"; break; default: value = 0; /* Quiet compiler */ tab_str = NULL; tab_str2 = NULL; stop("symtable_dump: Invalid symbol type " "encountered", EX_SOFTWARE); break; } fprintf(ofile, "#define%s%-16s%s0x%02x\n", tab_str, curnode->symbol->name, tab_str2, value); free(curnode); } fprintf(ofile, "\n\n"); while (constants.slh_first != NULL) { symbol_node_t *curnode; curnode = constants.slh_first; SLIST_REMOVE_HEAD(&constants, links); fprintf(ofile, "#define\t%-8s\t0x%02x\n", curnode->symbol->name, curnode->symbol->info.cinfo->value); free(curnode); } fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); while (download_constants.slh_first != NULL) { symbol_node_t *curnode; curnode = download_constants.slh_first; SLIST_REMOVE_HEAD(&download_constants, links); fprintf(ofile, "#define\t%-8s\t0x%02x\n", curnode->symbol->name, curnode->symbol->info.cinfo->value); free(curnode); } } } diff --git a/sys/dev/aic7xxx/aicasm/aicasm_symbol.h b/sys/dev/aic7xxx/aicasm/aicasm_symbol.h index 37f5e7f66664..8a904c9712a4 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm_symbol.h +++ b/sys/dev/aic7xxx/aicasm/aicasm_symbol.h @@ -1,164 +1,170 @@ /* * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions * * Copyright (c) 1997 Justin T. Gibbs. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU Public License ("GPL"). * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * $Id$ + * * $FreeBSD$ */ +#ifdef __linux__ +#include "../queue.h" +#else #include +#endif typedef enum { UNINITIALIZED, REGISTER, ALIAS, SCBLOC, SRAMLOC, MASK, BIT, CONST, DOWNLOAD_CONST, LABEL, CONDITIONAL }symtype; typedef enum { RO = 0x01, WO = 0x02, RW = 0x03 }amode_t; struct reg_info { - uint8_t address; + u_int8_t address; int size; amode_t mode; - uint8_t valid_bitmask; + u_int8_t valid_bitmask; int typecheck_masks; }; typedef SLIST_HEAD(symlist, symbol_node) symlist_t; struct mask_info { symlist_t symrefs; - uint8_t mask; + u_int8_t mask; }; struct const_info { - uint8_t value; + u_int8_t value; int define; }; struct alias_info { struct symbol *parent; }; struct label_info { int address; }; struct cond_info { int func_num; }; typedef struct expression_info { symlist_t referenced_syms; int value; } expression_t; typedef struct symbol { char *name; symtype type; union { struct reg_info *rinfo; struct mask_info *minfo; struct const_info *cinfo; struct alias_info *ainfo; struct label_info *linfo; struct cond_info *condinfo; }info; } symbol_t; typedef struct symbol_ref { symbol_t *symbol; int offset; } symbol_ref_t; typedef struct symbol_node { SLIST_ENTRY(symbol_node) links; symbol_t *symbol; }symbol_node_t; typedef enum { SCOPE_ROOT, SCOPE_IF, SCOPE_ELSE_IF, SCOPE_ELSE } scope_type; typedef struct patch_info { int skip_patch; int skip_instr; } patch_info_t; typedef struct scope { SLIST_ENTRY(scope) scope_stack_links; TAILQ_ENTRY(scope) scope_links; TAILQ_HEAD(, scope) inner_scope; scope_type type; int inner_scope_patches; int begin_addr; int end_addr; patch_info_t patches[2]; int func_num; } scope_t; SLIST_HEAD(scope_list, scope); TAILQ_HEAD(scope_tailq, scope); void symbol_delete __P((symbol_t *symbol)); void symtable_open __P((void)); void symtable_close __P((void)); symbol_t * symtable_get __P((char *name)); symbol_node_t * symlist_search __P((symlist_t *symlist, char *symname)); void symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how)); #define SYMLIST_INSERT_HEAD 0x00 #define SYMLIST_SORT 0x01 void symlist_free __P((symlist_t *symlist)); void symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1, symlist_t *symlist_src2)); void symtable_dump __P((FILE *ofile));