1 1.14 andvar /* $NetBSD: aicasm.c,v 1.14 2023/09/01 11:23:39 andvar Exp $ */ 2 1.1 fvdl 3 1.1 fvdl /* 4 1.13 andvar * Aic7xxx SCSI host adapter firmware assembler 5 1.1 fvdl * 6 1.4 fvdl * Copyright (c) 1997, 1998, 2000, 2001 Justin T. Gibbs. 7 1.4 fvdl * Copyright (c) 2001, 2002 Adaptec Inc. 8 1.1 fvdl * All rights reserved. 9 1.1 fvdl * 10 1.1 fvdl * Redistribution and use in source and binary forms, with or without 11 1.1 fvdl * modification, are permitted provided that the following conditions 12 1.1 fvdl * are met: 13 1.1 fvdl * 1. Redistributions of source code must retain the above copyright 14 1.1 fvdl * notice, this list of conditions, and the following disclaimer, 15 1.4 fvdl * without modification. 16 1.4 fvdl * 2. Redistributions in binary form must reproduce at minimum a disclaimer 17 1.4 fvdl * substantially similar to the "NO WARRANTY" disclaimer below 18 1.4 fvdl * ("Disclaimer") and any redistribution must be conditioned upon 19 1.4 fvdl * including a substantially similar Disclaimer requirement for further 20 1.4 fvdl * binary redistribution. 21 1.4 fvdl * 3. Neither the names of the above-listed copyright holders nor the names 22 1.4 fvdl * of any contributors may be used to endorse or promote products derived 23 1.4 fvdl * from this software without specific prior written permission. 24 1.1 fvdl * 25 1.4 fvdl * Alternatively, this software may be distributed under the terms of the 26 1.4 fvdl * GNU General Public License ("GPL") version 2 as published by the Free 27 1.4 fvdl * Software Foundation. 28 1.4 fvdl * 29 1.4 fvdl * NO WARRANTY 30 1.4 fvdl * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 1.4 fvdl * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 1.4 fvdl * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 33 1.4 fvdl * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 1.4 fvdl * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 1.1 fvdl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 1.1 fvdl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 1.4 fvdl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 38 1.4 fvdl * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 39 1.4 fvdl * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 1.4 fvdl * POSSIBILITY OF SUCH DAMAGES. 41 1.1 fvdl * 42 1.4 fvdl * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.c,v 1.35 2002/08/31 06:39:40 gibbs Exp $ 43 1.1 fvdl */ 44 1.5 lukem 45 1.5 lukem #include <sys/cdefs.h> 46 1.14 andvar __RCSID("$NetBSD: aicasm.c,v 1.14 2023/09/01 11:23:39 andvar Exp $"); 47 1.5 lukem 48 1.1 fvdl #include <sys/types.h> 49 1.1 fvdl #include <sys/mman.h> 50 1.1 fvdl 51 1.1 fvdl #include <ctype.h> 52 1.4 fvdl #include <inttypes.h> 53 1.4 fvdl #include <regex.h> 54 1.1 fvdl #include <stdio.h> 55 1.1 fvdl #include <stdlib.h> 56 1.1 fvdl #include <string.h> 57 1.1 fvdl #include <sysexits.h> 58 1.1 fvdl #include <unistd.h> 59 1.1 fvdl 60 1.4 fvdl #if linux 61 1.4 fvdl #include <endian.h> 62 1.4 fvdl #else 63 1.4 fvdl #include <machine/endian.h> 64 1.4 fvdl #endif 65 1.4 fvdl 66 1.1 fvdl #include "aicasm.h" 67 1.1 fvdl #include "aicasm_symbol.h" 68 1.4 fvdl #include "aicasm_insformat.h" 69 1.1 fvdl 70 1.1 fvdl typedef struct patch { 71 1.1 fvdl STAILQ_ENTRY(patch) links; 72 1.1 fvdl int patch_func; 73 1.1 fvdl u_int begin; 74 1.1 fvdl u_int skip_instr; 75 1.1 fvdl u_int skip_patch; 76 1.1 fvdl } patch_t; 77 1.1 fvdl 78 1.1 fvdl STAILQ_HEAD(patch_list, patch) patches; 79 1.1 fvdl 80 1.1 fvdl static void usage(void); 81 1.1 fvdl static void back_patch(void); 82 1.4 fvdl static void output_code(void); 83 1.4 fvdl static void output_listing(char *ifilename); 84 1.1 fvdl static void dump_scope(scope_t *scope); 85 1.1 fvdl static void emit_patch(scope_t *scope, int patch); 86 1.1 fvdl static int check_patch(patch_t **start_patch, int start_instr, 87 1.1 fvdl int *skip_addr, int *func_vals); 88 1.1 fvdl 89 1.1 fvdl struct path_list search_path; 90 1.1 fvdl int includes_search_curdir; 91 1.1 fvdl char *appname; 92 1.4 fvdl char *stock_include_file; 93 1.1 fvdl FILE *ofile; 94 1.1 fvdl char *ofilename; 95 1.1 fvdl char *regfilename; 96 1.1 fvdl FILE *regfile; 97 1.1 fvdl char *listfilename; 98 1.1 fvdl FILE *listfile; 99 1.4 fvdl char *regdiagfilename; 100 1.4 fvdl FILE *regdiagfile; 101 1.4 fvdl int src_mode; 102 1.4 fvdl int dst_mode; 103 1.1 fvdl 104 1.1 fvdl static STAILQ_HEAD(,instruction) seq_program; 105 1.4 fvdl struct cs_tailq cs_tailq; 106 1.1 fvdl struct scope_list scope_stack; 107 1.1 fvdl symlist_t patch_functions; 108 1.1 fvdl 109 1.1 fvdl #if DEBUG 110 1.1 fvdl extern int yy_flex_debug; 111 1.4 fvdl extern int mm_flex_debug; 112 1.1 fvdl extern int yydebug; 113 1.4 fvdl extern int mmdebug; 114 1.1 fvdl #endif 115 1.1 fvdl extern FILE *yyin; 116 1.4 fvdl extern int yyparse(void); 117 1.4 fvdl 118 1.4 fvdl int main(int argc, char *argv[]); 119 1.1 fvdl 120 1.1 fvdl int 121 1.4 fvdl main(int argc, char *argv[]) 122 1.1 fvdl { 123 1.1 fvdl extern char *optarg; 124 1.1 fvdl extern int optind; 125 1.1 fvdl int ch; 126 1.1 fvdl int retval; 127 1.1 fvdl char *inputfilename; 128 1.1 fvdl scope_t *sentinal; 129 1.1 fvdl 130 1.1 fvdl STAILQ_INIT(&patches); 131 1.1 fvdl SLIST_INIT(&search_path); 132 1.1 fvdl STAILQ_INIT(&seq_program); 133 1.4 fvdl TAILQ_INIT(&cs_tailq); 134 1.1 fvdl SLIST_INIT(&scope_stack); 135 1.1 fvdl 136 1.1 fvdl /* Set Sentinal scope node */ 137 1.1 fvdl sentinal = scope_alloc(); 138 1.1 fvdl sentinal->type = SCOPE_ROOT; 139 1.1 fvdl 140 1.1 fvdl includes_search_curdir = 1; 141 1.1 fvdl appname = *argv; 142 1.1 fvdl regfile = NULL; 143 1.1 fvdl listfile = NULL; 144 1.1 fvdl #if DEBUG 145 1.1 fvdl yy_flex_debug = 0; 146 1.4 fvdl mm_flex_debug = 0; 147 1.1 fvdl yydebug = 0; 148 1.4 fvdl mmdebug = 0; 149 1.1 fvdl #endif 150 1.4 fvdl while ((ch = getopt(argc, argv, "d:i:l:n:o:p:r:I:")) != -1) { 151 1.1 fvdl switch(ch) { 152 1.1 fvdl case 'd': 153 1.1 fvdl #if DEBUG 154 1.1 fvdl if (strcmp(optarg, "s") == 0) { 155 1.1 fvdl yy_flex_debug = 1; 156 1.4 fvdl mm_flex_debug = 1; 157 1.1 fvdl } else if (strcmp(optarg, "p") == 0) { 158 1.1 fvdl yydebug = 1; 159 1.4 fvdl mmdebug = 1; 160 1.1 fvdl } else { 161 1.1 fvdl fprintf(stderr, "%s: -d Requires either an " 162 1.1 fvdl "'s' or 'p' argument\n", appname); 163 1.1 fvdl usage(); 164 1.1 fvdl } 165 1.1 fvdl #else 166 1.1 fvdl stop("-d: Assembler not built with debugging " 167 1.1 fvdl "information", EX_SOFTWARE); 168 1.1 fvdl #endif 169 1.1 fvdl break; 170 1.4 fvdl case 'i': 171 1.4 fvdl stock_include_file = optarg; 172 1.4 fvdl break; 173 1.1 fvdl case 'l': 174 1.1 fvdl /* Create a program listing */ 175 1.1 fvdl if ((listfile = fopen(optarg, "w")) == NULL) { 176 1.1 fvdl perror(optarg); 177 1.1 fvdl stop(NULL, EX_CANTCREAT); 178 1.1 fvdl } 179 1.1 fvdl listfilename = optarg; 180 1.1 fvdl break; 181 1.1 fvdl case 'n': 182 1.13 andvar /* Don't complain about the -nostdinc directive */ 183 1.1 fvdl if (strcmp(optarg, "ostdinc")) { 184 1.1 fvdl fprintf(stderr, "%s: Unknown option -%c%s\n", 185 1.1 fvdl appname, ch, optarg); 186 1.1 fvdl usage(); 187 1.1 fvdl /* NOTREACHED */ 188 1.1 fvdl } 189 1.1 fvdl break; 190 1.1 fvdl case 'o': 191 1.1 fvdl if ((ofile = fopen(optarg, "w")) == NULL) { 192 1.1 fvdl perror(optarg); 193 1.1 fvdl stop(NULL, EX_CANTCREAT); 194 1.1 fvdl } 195 1.1 fvdl ofilename = optarg; 196 1.1 fvdl break; 197 1.4 fvdl case 'p': 198 1.4 fvdl /* Create Register Diagnostic "printing" Functions */ 199 1.4 fvdl if ((regdiagfile = fopen(optarg, "w")) == NULL) { 200 1.4 fvdl perror(optarg); 201 1.4 fvdl stop(NULL, EX_CANTCREAT); 202 1.4 fvdl } 203 1.4 fvdl regdiagfilename = optarg; 204 1.4 fvdl break; 205 1.1 fvdl case 'r': 206 1.1 fvdl if ((regfile = fopen(optarg, "w")) == NULL) { 207 1.1 fvdl perror(optarg); 208 1.1 fvdl stop(NULL, EX_CANTCREAT); 209 1.1 fvdl } 210 1.1 fvdl regfilename = optarg; 211 1.1 fvdl break; 212 1.1 fvdl case 'I': 213 1.1 fvdl { 214 1.1 fvdl path_entry_t include_dir; 215 1.1 fvdl 216 1.1 fvdl if (strcmp(optarg, "-") == 0) { 217 1.1 fvdl if (includes_search_curdir == 0) { 218 1.1 fvdl fprintf(stderr, "%s: Warning - '-I-' " 219 1.1 fvdl "specified multiple " 220 1.1 fvdl "times\n", appname); 221 1.1 fvdl } 222 1.1 fvdl includes_search_curdir = 0; 223 1.1 fvdl for (include_dir = SLIST_FIRST(&search_path); 224 1.1 fvdl include_dir != NULL; 225 1.4 fvdl include_dir = SLIST_NEXT(include_dir, 226 1.4 fvdl links)) 227 1.1 fvdl /* 228 1.1 fvdl * All entries before a '-I-' only 229 1.1 fvdl * apply to includes specified with 230 1.1 fvdl * quotes instead of "<>". 231 1.1 fvdl */ 232 1.1 fvdl include_dir->quoted_includes_only = 1; 233 1.1 fvdl } else { 234 1.1 fvdl include_dir = 235 1.1 fvdl (path_entry_t)malloc(sizeof(*include_dir)); 236 1.1 fvdl if (include_dir == NULL) { 237 1.1 fvdl perror(optarg); 238 1.1 fvdl stop(NULL, EX_OSERR); 239 1.1 fvdl } 240 1.1 fvdl include_dir->directory = strdup(optarg); 241 1.1 fvdl if (include_dir->directory == NULL) { 242 1.1 fvdl perror(optarg); 243 1.1 fvdl stop(NULL, EX_OSERR); 244 1.1 fvdl } 245 1.1 fvdl include_dir->quoted_includes_only = 0; 246 1.1 fvdl SLIST_INSERT_HEAD(&search_path, include_dir, 247 1.1 fvdl links); 248 1.1 fvdl } 249 1.1 fvdl break; 250 1.1 fvdl } 251 1.1 fvdl case '?': 252 1.1 fvdl default: 253 1.1 fvdl usage(); 254 1.1 fvdl /* NOTREACHED */ 255 1.1 fvdl } 256 1.1 fvdl } 257 1.1 fvdl argc -= optind; 258 1.1 fvdl argv += optind; 259 1.1 fvdl 260 1.1 fvdl if (argc != 1) { 261 1.13 andvar fprintf(stderr, "%s: No input file specified\n", appname); 262 1.1 fvdl usage(); 263 1.1 fvdl /* NOTREACHED */ 264 1.1 fvdl } 265 1.1 fvdl 266 1.4 fvdl if (regdiagfile != NULL 267 1.4 fvdl && (regfile == NULL || stock_include_file == NULL)) { 268 1.4 fvdl fprintf(stderr, 269 1.4 fvdl "%s: The -p option requires the -r and -i options.\n", 270 1.4 fvdl appname); 271 1.4 fvdl usage(); 272 1.4 fvdl /* NOTREACHED */ 273 1.4 fvdl } 274 1.1 fvdl symtable_open(); 275 1.1 fvdl inputfilename = *argv; 276 1.1 fvdl include_file(*argv, SOURCE_FILE); 277 1.1 fvdl retval = yyparse(); 278 1.1 fvdl if (retval == 0) { 279 1.1 fvdl if (SLIST_FIRST(&scope_stack) == NULL 280 1.1 fvdl || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { 281 1.4 fvdl stop("Unterminated conditional expression", EX_DATAERR); 282 1.1 fvdl /* NOTREACHED */ 283 1.1 fvdl } 284 1.1 fvdl 285 1.1 fvdl /* Process outmost scope */ 286 1.1 fvdl process_scope(SLIST_FIRST(&scope_stack)); 287 1.1 fvdl /* 288 1.13 andvar * Descend the tree of scopes and insert/emit 289 1.1 fvdl * patches as appropriate. We perform a depth first 290 1.13 andvar * transversal, recursively handling each scope. 291 1.1 fvdl */ 292 1.1 fvdl /* start at the root scope */ 293 1.1 fvdl dump_scope(SLIST_FIRST(&scope_stack)); 294 1.1 fvdl 295 1.1 fvdl /* Patch up forward jump addresses */ 296 1.1 fvdl back_patch(); 297 1.1 fvdl 298 1.1 fvdl if (ofile != NULL) 299 1.4 fvdl output_code(); 300 1.4 fvdl if (regfile != NULL) 301 1.4 fvdl symtable_dump(regfile, regdiagfile); 302 1.1 fvdl if (listfile != NULL) 303 1.4 fvdl output_listing(inputfilename); 304 1.1 fvdl } 305 1.1 fvdl 306 1.1 fvdl stop(NULL, 0); 307 1.1 fvdl /* NOTREACHED */ 308 1.1 fvdl return (0); 309 1.1 fvdl } 310 1.1 fvdl 311 1.1 fvdl static void 312 1.7 cegger usage(void) 313 1.1 fvdl { 314 1.1 fvdl 315 1.1 fvdl (void)fprintf(stderr, 316 1.4 fvdl "usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]\n" 317 1.4 fvdl " [-r register_output_file [-p register_diag_file -i includefile]]\n" 318 1.4 fvdl " [-l program_list_file]\n" 319 1.4 fvdl " input_file\n", appname); 320 1.1 fvdl exit(EX_USAGE); 321 1.1 fvdl } 322 1.1 fvdl 323 1.1 fvdl static void 324 1.7 cegger back_patch(void) 325 1.1 fvdl { 326 1.1 fvdl struct instruction *cur_instr; 327 1.1 fvdl 328 1.4 fvdl for (cur_instr = STAILQ_FIRST(&seq_program); 329 1.4 fvdl cur_instr != NULL; 330 1.4 fvdl cur_instr = STAILQ_NEXT(cur_instr, links)) { 331 1.1 fvdl if (cur_instr->patch_label != NULL) { 332 1.1 fvdl struct ins_format3 *f3_instr; 333 1.1 fvdl u_int address; 334 1.1 fvdl 335 1.1 fvdl if (cur_instr->patch_label->type != LABEL) { 336 1.1 fvdl char buf[255]; 337 1.1 fvdl 338 1.1 fvdl snprintf(buf, sizeof(buf), 339 1.1 fvdl "Undefined label %s", 340 1.1 fvdl cur_instr->patch_label->name); 341 1.1 fvdl stop(buf, EX_DATAERR); 342 1.1 fvdl /* NOTREACHED */ 343 1.1 fvdl } 344 1.1 fvdl f3_instr = &cur_instr->format.format3; 345 1.1 fvdl address = f3_instr->address; 346 1.1 fvdl address += cur_instr->patch_label->info.linfo->address; 347 1.1 fvdl f3_instr->address = address; 348 1.1 fvdl } 349 1.1 fvdl } 350 1.1 fvdl } 351 1.1 fvdl 352 1.1 fvdl static void 353 1.7 cegger output_code(void) 354 1.1 fvdl { 355 1.1 fvdl struct instruction *cur_instr; 356 1.1 fvdl patch_t *cur_patch; 357 1.4 fvdl critical_section_t *cs; 358 1.1 fvdl symbol_node_t *cur_node; 359 1.1 fvdl int instrcount; 360 1.1 fvdl 361 1.1 fvdl instrcount = 0; 362 1.1 fvdl fprintf(ofile, 363 1.4 fvdl "/*\n" 364 1.4 fvdl " * DO NOT EDIT - This file is automatically generated\n" 365 1.4 fvdl " * from the following source files:\n" 366 1.4 fvdl " *\n" 367 1.4 fvdl "%s */\n", versions); 368 1.4 fvdl 369 1.10 jdolecek fprintf(ofile, "static const uint8_t seqprog[] = {\n"); 370 1.4 fvdl for (cur_instr = STAILQ_FIRST(&seq_program); 371 1.4 fvdl cur_instr != NULL; 372 1.4 fvdl cur_instr = STAILQ_NEXT(cur_instr, links)) { 373 1.4 fvdl 374 1.4 fvdl fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x", 375 1.4 fvdl cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n", 376 1.4 fvdl #if BYTE_ORDER == LITTLE_ENDIAN 377 1.4 fvdl cur_instr->format.bytes[0], 378 1.4 fvdl cur_instr->format.bytes[1], 379 1.4 fvdl cur_instr->format.bytes[2], 380 1.4 fvdl cur_instr->format.bytes[3]); 381 1.4 fvdl #else 382 1.1 fvdl cur_instr->format.bytes[3], 383 1.1 fvdl cur_instr->format.bytes[2], 384 1.1 fvdl cur_instr->format.bytes[1], 385 1.1 fvdl cur_instr->format.bytes[0]); 386 1.1 fvdl #endif 387 1.1 fvdl instrcount++; 388 1.1 fvdl } 389 1.4 fvdl fprintf(ofile, "\n};\n\n"); 390 1.4 fvdl 391 1.4 fvdl if (patch_arg_list == NULL) 392 1.4 fvdl stop("Patch argument list not defined", 393 1.4 fvdl EX_DATAERR); 394 1.1 fvdl 395 1.1 fvdl /* 396 1.1 fvdl * Output patch information. Patch functions first. 397 1.1 fvdl */ 398 1.4 fvdl fprintf(ofile, 399 1.4 fvdl "typedef int %spatch_func_t (%s);\n", prefix, patch_arg_list); 400 1.4 fvdl 401 1.4 fvdl for (cur_node = SLIST_FIRST(&patch_functions); 402 1.4 fvdl cur_node != NULL; 403 1.4 fvdl cur_node = SLIST_NEXT(cur_node,links)) { 404 1.1 fvdl fprintf(ofile, 405 1.4 fvdl "static %spatch_func_t %spatch%d_func;\n" 406 1.4 fvdl "\n" 407 1.4 fvdl "static int\n" 408 1.4 fvdl "%spatch%d_func(%s)\n" 409 1.4 fvdl "{\n" 410 1.4 fvdl " return (%s);\n" 411 1.4 fvdl "}\n\n", 412 1.4 fvdl prefix, 413 1.4 fvdl prefix, 414 1.1 fvdl cur_node->symbol->info.condinfo->func_num, 415 1.4 fvdl prefix, 416 1.1 fvdl cur_node->symbol->info.condinfo->func_num, 417 1.4 fvdl patch_arg_list, 418 1.1 fvdl cur_node->symbol->name); 419 1.1 fvdl } 420 1.1 fvdl 421 1.1 fvdl fprintf(ofile, 422 1.10 jdolecek "static const struct patch {\n" 423 1.4 fvdl " %spatch_func_t *patch_func;\n" 424 1.4 fvdl " uint32_t begin :10,\n" 425 1.4 fvdl " skip_instr :10,\n" 426 1.4 fvdl " skip_patch :12;\n" 427 1.4 fvdl "} patches[] = {\n", prefix); 428 1.4 fvdl 429 1.4 fvdl for (cur_patch = STAILQ_FIRST(&patches); 430 1.4 fvdl cur_patch != NULL; 431 1.4 fvdl cur_patch = STAILQ_NEXT(cur_patch,links)) { 432 1.4 fvdl fprintf(ofile, "%s\t{ %spatch%d_func, %d, %d, %d }", 433 1.4 fvdl cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n", 434 1.4 fvdl prefix, 435 1.1 fvdl cur_patch->patch_func, cur_patch->begin, 436 1.1 fvdl cur_patch->skip_instr, cur_patch->skip_patch); 437 1.1 fvdl } 438 1.1 fvdl 439 1.4 fvdl fprintf(ofile, "\n};\n\n"); 440 1.4 fvdl 441 1.4 fvdl fprintf(ofile, 442 1.10 jdolecek "static const struct cs {\n" 443 1.4 fvdl " uint16_t begin;\n" 444 1.4 fvdl " uint16_t end;\n" 445 1.4 fvdl "} critical_sections[] = {\n"); 446 1.4 fvdl 447 1.4 fvdl for (cs = TAILQ_FIRST(&cs_tailq); 448 1.4 fvdl cs != NULL; 449 1.4 fvdl cs = TAILQ_NEXT(cs, links)) { 450 1.4 fvdl fprintf(ofile, "%s\t{ %d, %d }", 451 1.4 fvdl cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n", 452 1.4 fvdl cs->begin_addr, cs->end_addr); 453 1.4 fvdl } 454 1.4 fvdl 455 1.4 fvdl fprintf(ofile, "\n};\n\n"); 456 1.4 fvdl 457 1.4 fvdl fprintf(ofile, 458 1.12 ryo "#define NUM_CRITICAL_SECTIONS \\\n" 459 1.12 ryo " (sizeof(critical_sections) / sizeof(*critical_sections))\n"); 460 1.12 ryo fprintf(ofile, 461 1.12 ryo "static const int num_critical_sections = NUM_CRITICAL_SECTIONS;\n"); 462 1.1 fvdl 463 1.1 fvdl fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); 464 1.1 fvdl } 465 1.1 fvdl 466 1.1 fvdl static void 467 1.1 fvdl dump_scope(scope_t *scope) 468 1.1 fvdl { 469 1.1 fvdl scope_t *cur_scope; 470 1.1 fvdl 471 1.1 fvdl /* 472 1.1 fvdl * Emit the first patch for this scope 473 1.1 fvdl */ 474 1.1 fvdl emit_patch(scope, 0); 475 1.1 fvdl 476 1.1 fvdl /* 477 1.1 fvdl * Dump each scope within this one. 478 1.1 fvdl */ 479 1.1 fvdl cur_scope = TAILQ_FIRST(&scope->inner_scope); 480 1.1 fvdl 481 1.1 fvdl while (cur_scope != NULL) { 482 1.1 fvdl 483 1.1 fvdl dump_scope(cur_scope); 484 1.1 fvdl 485 1.1 fvdl cur_scope = TAILQ_NEXT(cur_scope, scope_links); 486 1.1 fvdl } 487 1.1 fvdl 488 1.1 fvdl /* 489 1.1 fvdl * Emit the second, closing, patch for this scope 490 1.1 fvdl */ 491 1.1 fvdl emit_patch(scope, 1); 492 1.1 fvdl } 493 1.1 fvdl 494 1.1 fvdl void 495 1.1 fvdl emit_patch(scope_t *scope, int patch) 496 1.1 fvdl { 497 1.1 fvdl patch_info_t *pinfo; 498 1.1 fvdl patch_t *new_patch; 499 1.1 fvdl 500 1.1 fvdl pinfo = &scope->patches[patch]; 501 1.1 fvdl 502 1.1 fvdl if (pinfo->skip_instr == 0) 503 1.1 fvdl /* No-Op patch */ 504 1.1 fvdl return; 505 1.1 fvdl 506 1.1 fvdl new_patch = (patch_t *)malloc(sizeof(*new_patch)); 507 1.1 fvdl 508 1.1 fvdl if (new_patch == NULL) 509 1.1 fvdl stop("Could not malloc patch structure", EX_OSERR); 510 1.1 fvdl 511 1.1 fvdl memset(new_patch, 0, sizeof(*new_patch)); 512 1.1 fvdl 513 1.1 fvdl if (patch == 0) { 514 1.1 fvdl new_patch->patch_func = scope->func_num; 515 1.1 fvdl new_patch->begin = scope->begin_addr; 516 1.1 fvdl } else { 517 1.1 fvdl new_patch->patch_func = 0; 518 1.1 fvdl new_patch->begin = scope->end_addr; 519 1.1 fvdl } 520 1.1 fvdl new_patch->skip_instr = pinfo->skip_instr; 521 1.1 fvdl new_patch->skip_patch = pinfo->skip_patch; 522 1.1 fvdl STAILQ_INSERT_TAIL(&patches, new_patch, links); 523 1.1 fvdl } 524 1.1 fvdl 525 1.1 fvdl void 526 1.4 fvdl output_listing(char *ifilename) 527 1.1 fvdl { 528 1.1 fvdl char buf[1024]; 529 1.1 fvdl FILE *ifile; 530 1.1 fvdl struct instruction *cur_instr; 531 1.1 fvdl patch_t *cur_patch; 532 1.1 fvdl symbol_node_t *cur_func; 533 1.1 fvdl int *func_values; 534 1.1 fvdl int instrcount; 535 1.1 fvdl int instrptr; 536 1.1 fvdl int line; 537 1.1 fvdl int func_count; 538 1.1 fvdl int skip_addr; 539 1.1 fvdl 540 1.1 fvdl instrcount = 0; 541 1.1 fvdl instrptr = 0; 542 1.1 fvdl line = 1; 543 1.1 fvdl skip_addr = 0; 544 1.1 fvdl if ((ifile = fopen(ifilename, "r")) == NULL) { 545 1.1 fvdl perror(ifilename); 546 1.1 fvdl stop(NULL, EX_DATAERR); 547 1.1 fvdl } 548 1.1 fvdl 549 1.1 fvdl /* 550 1.1 fvdl * Determine which options to apply to this listing. 551 1.1 fvdl */ 552 1.1 fvdl for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions); 553 1.1 fvdl cur_func != NULL; 554 1.1 fvdl cur_func = SLIST_NEXT(cur_func, links)) 555 1.1 fvdl func_count++; 556 1.1 fvdl 557 1.4 fvdl func_values = NULL; 558 1.1 fvdl if (func_count != 0) { 559 1.1 fvdl func_values = (int *)malloc(func_count * sizeof(int)); 560 1.1 fvdl 561 1.1 fvdl if (func_values == NULL) 562 1.1 fvdl stop("Could not malloc", EX_OSERR); 563 1.1 fvdl 564 1.1 fvdl func_values[0] = 0; /* FALSE func */ 565 1.1 fvdl func_count--; 566 1.1 fvdl 567 1.1 fvdl /* 568 1.1 fvdl * Ask the user to fill in the return values for 569 1.1 fvdl * the rest of the functions. 570 1.1 fvdl */ 571 1.1 fvdl 572 1.1 fvdl 573 1.1 fvdl for (cur_func = SLIST_FIRST(&patch_functions); 574 1.1 fvdl cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL; 575 1.1 fvdl cur_func = SLIST_NEXT(cur_func, links), func_count--) { 576 1.1 fvdl int input; 577 1.1 fvdl 578 1.1 fvdl fprintf(stdout, "\n(%s)\n", cur_func->symbol->name); 579 1.1 fvdl fprintf(stdout, 580 1.1 fvdl "Enter the return value for " 581 1.1 fvdl "this expression[T/F]:"); 582 1.1 fvdl 583 1.1 fvdl while (1) { 584 1.1 fvdl 585 1.1 fvdl input = getchar(); 586 1.1 fvdl input = toupper(input); 587 1.1 fvdl 588 1.1 fvdl if (input == 'T') { 589 1.1 fvdl func_values[func_count] = 1; 590 1.1 fvdl break; 591 1.1 fvdl } else if (input == 'F') { 592 1.1 fvdl func_values[func_count] = 0; 593 1.1 fvdl break; 594 1.1 fvdl } 595 1.1 fvdl } 596 1.1 fvdl if (isatty(fileno(stdin)) == 0) 597 1.1 fvdl putchar(input); 598 1.1 fvdl } 599 1.8 jakllsch free(func_values); 600 1.9 maxv func_values = NULL; 601 1.1 fvdl fprintf(stdout, "\nThanks!\n"); 602 1.1 fvdl } 603 1.1 fvdl 604 1.1 fvdl /* Now output the listing */ 605 1.1 fvdl cur_patch = STAILQ_FIRST(&patches); 606 1.4 fvdl for (cur_instr = STAILQ_FIRST(&seq_program); 607 1.4 fvdl cur_instr != NULL; 608 1.4 fvdl cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) { 609 1.1 fvdl 610 1.9 maxv /* 611 1.9 maxv * XXX XXX XXX: What exactly are we trying to do here? 612 1.9 maxv * 'func_values' is always NULL, so check_patch will 613 1.9 maxv * necessarily crash. 614 1.9 maxv */ 615 1.1 fvdl if (check_patch(&cur_patch, instrcount, 616 1.1 fvdl &skip_addr, func_values) == 0) { 617 1.1 fvdl /* Don't count this instruction as it is in a patch 618 1.1 fvdl * that was removed. 619 1.1 fvdl */ 620 1.1 fvdl continue; 621 1.1 fvdl } 622 1.1 fvdl 623 1.1 fvdl while (line < cur_instr->srcline) { 624 1.1 fvdl fgets(buf, sizeof(buf), ifile); 625 1.1 fvdl fprintf(listfile, "\t\t%s", buf); 626 1.1 fvdl line++; 627 1.1 fvdl } 628 1.1 fvdl fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, 629 1.4 fvdl #if BYTE_ORDER == LITTLE_ENDIAN 630 1.1 fvdl cur_instr->format.bytes[0], 631 1.1 fvdl cur_instr->format.bytes[1], 632 1.1 fvdl cur_instr->format.bytes[2], 633 1.1 fvdl cur_instr->format.bytes[3]); 634 1.4 fvdl #else 635 1.4 fvdl cur_instr->format.bytes[3], 636 1.4 fvdl cur_instr->format.bytes[2], 637 1.4 fvdl cur_instr->format.bytes[1], 638 1.4 fvdl cur_instr->format.bytes[0]); 639 1.4 fvdl #endif 640 1.1 fvdl fgets(buf, sizeof(buf), ifile); 641 1.1 fvdl fprintf(listfile, "\t%s", buf); 642 1.1 fvdl line++; 643 1.1 fvdl instrptr++; 644 1.1 fvdl } 645 1.1 fvdl /* Dump the remainder of the file */ 646 1.1 fvdl while(fgets(buf, sizeof(buf), ifile) != NULL) 647 1.1 fvdl fprintf(listfile, "\t\t%s", buf); 648 1.1 fvdl 649 1.1 fvdl fclose(ifile); 650 1.1 fvdl } 651 1.1 fvdl 652 1.1 fvdl static int 653 1.1 fvdl check_patch(patch_t **start_patch, int start_instr, 654 1.1 fvdl int *skip_addr, int *func_vals) 655 1.1 fvdl { 656 1.1 fvdl patch_t *cur_patch; 657 1.1 fvdl 658 1.1 fvdl cur_patch = *start_patch; 659 1.1 fvdl 660 1.1 fvdl while (cur_patch != NULL && start_instr == cur_patch->begin) { 661 1.1 fvdl if (func_vals[cur_patch->patch_func] == 0) { 662 1.1 fvdl int skip; 663 1.1 fvdl 664 1.1 fvdl /* Start rejecting code */ 665 1.1 fvdl *skip_addr = start_instr + cur_patch->skip_instr; 666 1.1 fvdl for (skip = cur_patch->skip_patch; 667 1.1 fvdl skip > 0 && cur_patch != NULL; 668 1.1 fvdl skip--) 669 1.1 fvdl cur_patch = STAILQ_NEXT(cur_patch, links); 670 1.1 fvdl } else { 671 1.1 fvdl /* Accepted this patch. Advance to the next 672 1.11 andvar * one and wait for our instruction pointer to 673 1.1 fvdl * hit this point. 674 1.1 fvdl */ 675 1.1 fvdl cur_patch = STAILQ_NEXT(cur_patch, links); 676 1.1 fvdl } 677 1.1 fvdl } 678 1.1 fvdl 679 1.1 fvdl *start_patch = cur_patch; 680 1.1 fvdl if (start_instr < *skip_addr) 681 1.1 fvdl /* Still skipping */ 682 1.1 fvdl return (0); 683 1.1 fvdl 684 1.1 fvdl return (1); 685 1.1 fvdl } 686 1.1 fvdl 687 1.1 fvdl /* 688 1.1 fvdl * Print out error information if appropriate, and clean up before 689 1.1 fvdl * terminating the program. 690 1.1 fvdl */ 691 1.1 fvdl void 692 1.4 fvdl stop(const char *string, int err_code) 693 1.1 fvdl { 694 1.1 fvdl if (string != NULL) { 695 1.1 fvdl fprintf(stderr, "%s: ", appname); 696 1.1 fvdl if (yyfilename != NULL) { 697 1.1 fvdl fprintf(stderr, "Stopped at file %s, line %d - ", 698 1.1 fvdl yyfilename, yylineno); 699 1.1 fvdl } 700 1.1 fvdl fprintf(stderr, "%s\n", string); 701 1.1 fvdl } 702 1.1 fvdl 703 1.1 fvdl if (ofile != NULL) { 704 1.1 fvdl fclose(ofile); 705 1.1 fvdl if (err_code != 0) { 706 1.1 fvdl fprintf(stderr, "%s: Removing %s due to error\n", 707 1.1 fvdl appname, ofilename); 708 1.1 fvdl unlink(ofilename); 709 1.1 fvdl } 710 1.1 fvdl } 711 1.1 fvdl 712 1.1 fvdl if (regfile != NULL) { 713 1.1 fvdl fclose(regfile); 714 1.1 fvdl if (err_code != 0) { 715 1.1 fvdl fprintf(stderr, "%s: Removing %s due to error\n", 716 1.1 fvdl appname, regfilename); 717 1.1 fvdl unlink(regfilename); 718 1.1 fvdl } 719 1.1 fvdl } 720 1.1 fvdl 721 1.1 fvdl if (listfile != NULL) { 722 1.1 fvdl fclose(listfile); 723 1.1 fvdl if (err_code != 0) { 724 1.1 fvdl fprintf(stderr, "%s: Removing %s due to error\n", 725 1.1 fvdl appname, listfilename); 726 1.1 fvdl unlink(listfilename); 727 1.1 fvdl } 728 1.1 fvdl } 729 1.1 fvdl 730 1.1 fvdl symlist_free(&patch_functions); 731 1.1 fvdl symtable_close(); 732 1.1 fvdl 733 1.1 fvdl exit(err_code); 734 1.1 fvdl } 735 1.1 fvdl 736 1.1 fvdl struct instruction * 737 1.7 cegger seq_alloc(void) 738 1.1 fvdl { 739 1.1 fvdl struct instruction *new_instr; 740 1.1 fvdl 741 1.1 fvdl new_instr = (struct instruction *)malloc(sizeof(struct instruction)); 742 1.1 fvdl if (new_instr == NULL) 743 1.1 fvdl stop("Unable to malloc instruction object", EX_SOFTWARE); 744 1.1 fvdl memset(new_instr, 0, sizeof(*new_instr)); 745 1.1 fvdl STAILQ_INSERT_TAIL(&seq_program, new_instr, links); 746 1.1 fvdl new_instr->srcline = yylineno; 747 1.1 fvdl return new_instr; 748 1.4 fvdl } 749 1.4 fvdl 750 1.4 fvdl critical_section_t * 751 1.7 cegger cs_alloc(void) 752 1.4 fvdl { 753 1.4 fvdl critical_section_t *new_cs; 754 1.4 fvdl 755 1.4 fvdl new_cs= (critical_section_t *)malloc(sizeof(critical_section_t)); 756 1.4 fvdl if (new_cs == NULL) 757 1.4 fvdl stop("Unable to malloc critical_section object", EX_SOFTWARE); 758 1.4 fvdl memset(new_cs, 0, sizeof(*new_cs)); 759 1.4 fvdl 760 1.4 fvdl TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links); 761 1.4 fvdl return new_cs; 762 1.1 fvdl } 763 1.1 fvdl 764 1.1 fvdl scope_t * 765 1.7 cegger scope_alloc(void) 766 1.1 fvdl { 767 1.1 fvdl scope_t *new_scope; 768 1.1 fvdl 769 1.1 fvdl new_scope = (scope_t *)malloc(sizeof(scope_t)); 770 1.1 fvdl if (new_scope == NULL) 771 1.1 fvdl stop("Unable to malloc scope object", EX_SOFTWARE); 772 1.1 fvdl memset(new_scope, 0, sizeof(*new_scope)); 773 1.1 fvdl TAILQ_INIT(&new_scope->inner_scope); 774 1.1 fvdl 775 1.1 fvdl if (SLIST_FIRST(&scope_stack) != NULL) { 776 1.1 fvdl TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope, 777 1.1 fvdl new_scope, scope_links); 778 1.1 fvdl } 779 1.1 fvdl /* This patch is now the current scope */ 780 1.1 fvdl SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links); 781 1.1 fvdl return new_scope; 782 1.1 fvdl } 783 1.1 fvdl 784 1.1 fvdl void 785 1.1 fvdl process_scope(scope_t *scope) 786 1.1 fvdl { 787 1.1 fvdl /* 788 1.1 fvdl * We are "leaving" this scope. We should now have 789 1.1 fvdl * enough information to process the lists of scopes 790 1.1 fvdl * we encapsulate. 791 1.1 fvdl */ 792 1.1 fvdl scope_t *cur_scope; 793 1.1 fvdl u_int skip_patch_count; 794 1.1 fvdl u_int skip_instr_count; 795 1.1 fvdl 796 1.1 fvdl cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq); 797 1.1 fvdl skip_patch_count = 0; 798 1.1 fvdl skip_instr_count = 0; 799 1.1 fvdl while (cur_scope != NULL) { 800 1.1 fvdl u_int patch0_patch_skip; 801 1.1 fvdl 802 1.1 fvdl patch0_patch_skip = 0; 803 1.1 fvdl switch (cur_scope->type) { 804 1.1 fvdl case SCOPE_IF: 805 1.1 fvdl case SCOPE_ELSE_IF: 806 1.1 fvdl if (skip_instr_count != 0) { 807 1.1 fvdl /* Create a tail patch */ 808 1.1 fvdl patch0_patch_skip++; 809 1.1 fvdl cur_scope->patches[1].skip_patch = 810 1.1 fvdl skip_patch_count + 1; 811 1.1 fvdl cur_scope->patches[1].skip_instr = 812 1.1 fvdl skip_instr_count; 813 1.1 fvdl } 814 1.1 fvdl 815 1.1 fvdl /* Count Head patch */ 816 1.1 fvdl patch0_patch_skip++; 817 1.1 fvdl 818 1.1 fvdl /* Count any patches contained in our inner scope */ 819 1.1 fvdl patch0_patch_skip += cur_scope->inner_scope_patches; 820 1.1 fvdl 821 1.1 fvdl cur_scope->patches[0].skip_patch = patch0_patch_skip; 822 1.1 fvdl cur_scope->patches[0].skip_instr = 823 1.1 fvdl cur_scope->end_addr - cur_scope->begin_addr; 824 1.1 fvdl 825 1.1 fvdl skip_instr_count += cur_scope->patches[0].skip_instr; 826 1.1 fvdl 827 1.1 fvdl skip_patch_count += patch0_patch_skip; 828 1.1 fvdl if (cur_scope->type == SCOPE_IF) { 829 1.1 fvdl scope->inner_scope_patches += skip_patch_count; 830 1.1 fvdl skip_patch_count = 0; 831 1.1 fvdl skip_instr_count = 0; 832 1.1 fvdl } 833 1.1 fvdl break; 834 1.1 fvdl case SCOPE_ELSE: 835 1.14 andvar /* Count any patches contained in our inner scope */ 836 1.1 fvdl skip_patch_count += cur_scope->inner_scope_patches; 837 1.1 fvdl 838 1.1 fvdl skip_instr_count += cur_scope->end_addr 839 1.1 fvdl - cur_scope->begin_addr; 840 1.1 fvdl break; 841 1.1 fvdl case SCOPE_ROOT: 842 1.1 fvdl stop("Unexpected scope type encountered", EX_SOFTWARE); 843 1.1 fvdl /* NOTREACHED */ 844 1.1 fvdl } 845 1.1 fvdl 846 1.1 fvdl cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links); 847 1.1 fvdl } 848 1.1 fvdl } 849