Home | History | Annotate | Line # | Download | only in aic7xxx
aicasm.c revision 1.8.40.1
      1  1.8.40.1     skrll /*	$NetBSD: aicasm.c,v 1.8.40.1 2016/10/05 20:55:42 skrll Exp $	*/
      2       1.1      fvdl 
      3       1.1      fvdl /*
      4       1.1      fvdl  * Aic7xxx SCSI host adapter firmware asssembler
      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.8.40.1     skrll __RCSID("$NetBSD: aicasm.c,v 1.8.40.1 2016/10/05 20:55:42 skrll 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.1      fvdl 			/* Don't complain about the -nostdinc directrive */
    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.1      fvdl 		fprintf(stderr, "%s: No input file specifiled\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.1      fvdl 		 * Decend the tree of scopes and insert/emit
    289       1.1      fvdl 		 * patches as appropriate.  We perform a depth first
    290       1.1      fvdl 		 * tranversal, 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.4      fvdl 	fprintf(ofile, "static 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.4      fvdl "static 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.4      fvdl "static 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.4      fvdl "static const int num_critical_sections = sizeof(critical_sections)\n"
    459       1.4      fvdl "				       / sizeof(*critical_sections);\n");
    460       1.1      fvdl 
    461       1.1      fvdl 	fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
    462       1.1      fvdl }
    463       1.1      fvdl 
    464       1.1      fvdl static void
    465       1.1      fvdl dump_scope(scope_t *scope)
    466       1.1      fvdl {
    467       1.1      fvdl 	scope_t *cur_scope;
    468       1.1      fvdl 
    469       1.1      fvdl 	/*
    470       1.1      fvdl 	 * Emit the first patch for this scope
    471       1.1      fvdl 	 */
    472       1.1      fvdl 	emit_patch(scope, 0);
    473       1.1      fvdl 
    474       1.1      fvdl 	/*
    475       1.1      fvdl 	 * Dump each scope within this one.
    476       1.1      fvdl 	 */
    477       1.1      fvdl 	cur_scope = TAILQ_FIRST(&scope->inner_scope);
    478       1.1      fvdl 
    479       1.1      fvdl 	while (cur_scope != NULL) {
    480       1.1      fvdl 
    481       1.1      fvdl 		dump_scope(cur_scope);
    482       1.1      fvdl 
    483       1.1      fvdl 		cur_scope = TAILQ_NEXT(cur_scope, scope_links);
    484       1.1      fvdl 	}
    485       1.1      fvdl 
    486       1.1      fvdl 	/*
    487       1.1      fvdl 	 * Emit the second, closing, patch for this scope
    488       1.1      fvdl 	 */
    489       1.1      fvdl 	emit_patch(scope, 1);
    490       1.1      fvdl }
    491       1.1      fvdl 
    492       1.1      fvdl void
    493       1.1      fvdl emit_patch(scope_t *scope, int patch)
    494       1.1      fvdl {
    495       1.1      fvdl 	patch_info_t *pinfo;
    496       1.1      fvdl 	patch_t *new_patch;
    497       1.1      fvdl 
    498       1.1      fvdl 	pinfo = &scope->patches[patch];
    499       1.1      fvdl 
    500       1.1      fvdl 	if (pinfo->skip_instr == 0)
    501       1.1      fvdl 		/* No-Op patch */
    502       1.1      fvdl 		return;
    503       1.1      fvdl 
    504       1.1      fvdl 	new_patch = (patch_t *)malloc(sizeof(*new_patch));
    505       1.1      fvdl 
    506       1.1      fvdl 	if (new_patch == NULL)
    507       1.1      fvdl 		stop("Could not malloc patch structure", EX_OSERR);
    508       1.1      fvdl 
    509       1.1      fvdl 	memset(new_patch, 0, sizeof(*new_patch));
    510       1.1      fvdl 
    511       1.1      fvdl 	if (patch == 0) {
    512       1.1      fvdl 		new_patch->patch_func = scope->func_num;
    513       1.1      fvdl 		new_patch->begin = scope->begin_addr;
    514       1.1      fvdl 	} else {
    515       1.1      fvdl 		new_patch->patch_func = 0;
    516       1.1      fvdl 		new_patch->begin = scope->end_addr;
    517       1.1      fvdl 	}
    518       1.1      fvdl 	new_patch->skip_instr = pinfo->skip_instr;
    519       1.1      fvdl 	new_patch->skip_patch = pinfo->skip_patch;
    520       1.1      fvdl 	STAILQ_INSERT_TAIL(&patches, new_patch, links);
    521       1.1      fvdl }
    522       1.1      fvdl 
    523       1.1      fvdl void
    524       1.4      fvdl output_listing(char *ifilename)
    525       1.1      fvdl {
    526       1.1      fvdl 	char buf[1024];
    527       1.1      fvdl 	FILE *ifile;
    528       1.1      fvdl 	struct instruction *cur_instr;
    529       1.1      fvdl 	patch_t *cur_patch;
    530       1.1      fvdl 	symbol_node_t *cur_func;
    531       1.1      fvdl 	int *func_values;
    532       1.1      fvdl 	int instrcount;
    533       1.1      fvdl 	int instrptr;
    534       1.1      fvdl 	int line;
    535       1.1      fvdl 	int func_count;
    536       1.1      fvdl 	int skip_addr;
    537       1.1      fvdl 
    538       1.1      fvdl 	instrcount = 0;
    539       1.1      fvdl 	instrptr = 0;
    540       1.1      fvdl 	line = 1;
    541       1.1      fvdl 	skip_addr = 0;
    542       1.1      fvdl 	if ((ifile = fopen(ifilename, "r")) == NULL) {
    543       1.1      fvdl 		perror(ifilename);
    544       1.1      fvdl 		stop(NULL, EX_DATAERR);
    545       1.1      fvdl 	}
    546       1.1      fvdl 
    547       1.1      fvdl 	/*
    548       1.1      fvdl 	 * Determine which options to apply to this listing.
    549       1.1      fvdl 	 */
    550       1.1      fvdl 	for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
    551       1.1      fvdl 	    cur_func != NULL;
    552       1.1      fvdl 	    cur_func = SLIST_NEXT(cur_func, links))
    553       1.1      fvdl 		func_count++;
    554       1.1      fvdl 
    555       1.4      fvdl 	func_values = NULL;
    556       1.1      fvdl 	if (func_count != 0) {
    557       1.1      fvdl 		func_values = (int *)malloc(func_count * sizeof(int));
    558       1.1      fvdl 
    559       1.1      fvdl 		if (func_values == NULL)
    560       1.1      fvdl 			stop("Could not malloc", EX_OSERR);
    561       1.1      fvdl 
    562       1.1      fvdl 		func_values[0] = 0; /* FALSE func */
    563       1.1      fvdl 		func_count--;
    564       1.1      fvdl 
    565       1.1      fvdl 		/*
    566       1.1      fvdl 		 * Ask the user to fill in the return values for
    567       1.1      fvdl 		 * the rest of the functions.
    568       1.1      fvdl 		 */
    569       1.1      fvdl 
    570       1.1      fvdl 
    571       1.1      fvdl 		for (cur_func = SLIST_FIRST(&patch_functions);
    572       1.1      fvdl 		     cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
    573       1.1      fvdl 		     cur_func = SLIST_NEXT(cur_func, links), func_count--) {
    574       1.1      fvdl 			int input;
    575       1.1      fvdl 
    576       1.1      fvdl 			fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
    577       1.1      fvdl 			fprintf(stdout,
    578       1.1      fvdl 				"Enter the return value for "
    579       1.1      fvdl 				"this expression[T/F]:");
    580       1.1      fvdl 
    581       1.1      fvdl 			while (1) {
    582       1.1      fvdl 
    583       1.1      fvdl 				input = getchar();
    584       1.1      fvdl 				input = toupper(input);
    585       1.1      fvdl 
    586       1.1      fvdl 				if (input == 'T') {
    587       1.1      fvdl 					func_values[func_count] = 1;
    588       1.1      fvdl 					break;
    589       1.1      fvdl 				} else if (input == 'F') {
    590       1.1      fvdl 					func_values[func_count] = 0;
    591       1.1      fvdl 					break;
    592       1.1      fvdl 				}
    593       1.1      fvdl 			}
    594       1.1      fvdl 			if (isatty(fileno(stdin)) == 0)
    595       1.1      fvdl 				putchar(input);
    596       1.1      fvdl 		}
    597       1.8  jakllsch 		free(func_values);
    598  1.8.40.1     skrll 		func_values = NULL;
    599       1.1      fvdl 		fprintf(stdout, "\nThanks!\n");
    600       1.1      fvdl 	}
    601       1.1      fvdl 
    602       1.1      fvdl 	/* Now output the listing */
    603       1.1      fvdl 	cur_patch = STAILQ_FIRST(&patches);
    604       1.4      fvdl 	for (cur_instr = STAILQ_FIRST(&seq_program);
    605       1.4      fvdl 	     cur_instr != NULL;
    606       1.4      fvdl 	     cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
    607       1.1      fvdl 
    608  1.8.40.1     skrll 		/*
    609  1.8.40.1     skrll 		 * XXX XXX XXX: What exactly are we trying to do here?
    610  1.8.40.1     skrll 		 * 'func_values' is always NULL, so check_patch will
    611  1.8.40.1     skrll 		 * necessarily crash.
    612  1.8.40.1     skrll 		 */
    613       1.1      fvdl 		if (check_patch(&cur_patch, instrcount,
    614       1.1      fvdl 				&skip_addr, func_values) == 0) {
    615       1.1      fvdl 			/* Don't count this instruction as it is in a patch
    616       1.1      fvdl 			 * that was removed.
    617       1.1      fvdl 			 */
    618       1.1      fvdl                         continue;
    619       1.1      fvdl 		}
    620       1.1      fvdl 
    621       1.1      fvdl 		while (line < cur_instr->srcline) {
    622       1.1      fvdl 			fgets(buf, sizeof(buf), ifile);
    623       1.1      fvdl 				fprintf(listfile, "\t\t%s", buf);
    624       1.1      fvdl 				line++;
    625       1.1      fvdl 		}
    626       1.1      fvdl 		fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
    627       1.4      fvdl #if BYTE_ORDER == LITTLE_ENDIAN
    628       1.1      fvdl 			cur_instr->format.bytes[0],
    629       1.1      fvdl 			cur_instr->format.bytes[1],
    630       1.1      fvdl 			cur_instr->format.bytes[2],
    631       1.1      fvdl 			cur_instr->format.bytes[3]);
    632       1.4      fvdl #else
    633       1.4      fvdl 			cur_instr->format.bytes[3],
    634       1.4      fvdl 			cur_instr->format.bytes[2],
    635       1.4      fvdl 			cur_instr->format.bytes[1],
    636       1.4      fvdl 			cur_instr->format.bytes[0]);
    637       1.4      fvdl #endif
    638       1.1      fvdl 		fgets(buf, sizeof(buf), ifile);
    639       1.1      fvdl 		fprintf(listfile, "\t%s", buf);
    640       1.1      fvdl 		line++;
    641       1.1      fvdl 		instrptr++;
    642       1.1      fvdl 	}
    643       1.1      fvdl 	/* Dump the remainder of the file */
    644       1.1      fvdl 	while(fgets(buf, sizeof(buf), ifile) != NULL)
    645       1.1      fvdl 		fprintf(listfile, "\t\t%s", buf);
    646       1.1      fvdl 
    647       1.1      fvdl 	fclose(ifile);
    648       1.1      fvdl }
    649       1.1      fvdl 
    650       1.1      fvdl static int
    651       1.1      fvdl check_patch(patch_t **start_patch, int start_instr,
    652       1.1      fvdl 	    int *skip_addr, int *func_vals)
    653       1.1      fvdl {
    654       1.1      fvdl 	patch_t *cur_patch;
    655       1.1      fvdl 
    656       1.1      fvdl 	cur_patch = *start_patch;
    657       1.1      fvdl 
    658       1.1      fvdl 	while (cur_patch != NULL && start_instr == cur_patch->begin) {
    659       1.1      fvdl 		if (func_vals[cur_patch->patch_func] == 0) {
    660       1.1      fvdl 			int skip;
    661       1.1      fvdl 
    662       1.1      fvdl 			/* Start rejecting code */
    663       1.1      fvdl 			*skip_addr = start_instr + cur_patch->skip_instr;
    664       1.1      fvdl 			for (skip = cur_patch->skip_patch;
    665       1.1      fvdl 			     skip > 0 && cur_patch != NULL;
    666       1.1      fvdl 			     skip--)
    667       1.1      fvdl 				cur_patch = STAILQ_NEXT(cur_patch, links);
    668       1.1      fvdl 		} else {
    669       1.1      fvdl 			/* Accepted this patch.  Advance to the next
    670       1.1      fvdl 			 * one and wait for our intruction pointer to
    671       1.1      fvdl 			 * hit this point.
    672       1.1      fvdl 			 */
    673       1.1      fvdl 			cur_patch = STAILQ_NEXT(cur_patch, links);
    674       1.1      fvdl 		}
    675       1.1      fvdl 	}
    676       1.1      fvdl 
    677       1.1      fvdl 	*start_patch = cur_patch;
    678       1.1      fvdl 	if (start_instr < *skip_addr)
    679       1.1      fvdl 		/* Still skipping */
    680       1.1      fvdl 		return (0);
    681       1.1      fvdl 
    682       1.1      fvdl 	return (1);
    683       1.1      fvdl }
    684       1.1      fvdl 
    685       1.1      fvdl /*
    686       1.1      fvdl  * Print out error information if appropriate, and clean up before
    687       1.1      fvdl  * terminating the program.
    688       1.1      fvdl  */
    689       1.1      fvdl void
    690       1.4      fvdl stop(const char *string, int err_code)
    691       1.1      fvdl {
    692       1.1      fvdl 	if (string != NULL) {
    693       1.1      fvdl 		fprintf(stderr, "%s: ", appname);
    694       1.1      fvdl 		if (yyfilename != NULL) {
    695       1.1      fvdl 			fprintf(stderr, "Stopped at file %s, line %d - ",
    696       1.1      fvdl 				yyfilename, yylineno);
    697       1.1      fvdl 		}
    698       1.1      fvdl 		fprintf(stderr, "%s\n", string);
    699       1.1      fvdl 	}
    700       1.1      fvdl 
    701       1.1      fvdl 	if (ofile != NULL) {
    702       1.1      fvdl 		fclose(ofile);
    703       1.1      fvdl 		if (err_code != 0) {
    704       1.1      fvdl 			fprintf(stderr, "%s: Removing %s due to error\n",
    705       1.1      fvdl 				appname, ofilename);
    706       1.1      fvdl 			unlink(ofilename);
    707       1.1      fvdl 		}
    708       1.1      fvdl 	}
    709       1.1      fvdl 
    710       1.1      fvdl 	if (regfile != NULL) {
    711       1.1      fvdl 		fclose(regfile);
    712       1.1      fvdl 		if (err_code != 0) {
    713       1.1      fvdl 			fprintf(stderr, "%s: Removing %s due to error\n",
    714       1.1      fvdl 				appname, regfilename);
    715       1.1      fvdl 			unlink(regfilename);
    716       1.1      fvdl 		}
    717       1.1      fvdl 	}
    718       1.1      fvdl 
    719       1.1      fvdl 	if (listfile != NULL) {
    720       1.1      fvdl 		fclose(listfile);
    721       1.1      fvdl 		if (err_code != 0) {
    722       1.1      fvdl 			fprintf(stderr, "%s: Removing %s due to error\n",
    723       1.1      fvdl 				appname, listfilename);
    724       1.1      fvdl 			unlink(listfilename);
    725       1.1      fvdl 		}
    726       1.1      fvdl 	}
    727       1.1      fvdl 
    728       1.1      fvdl 	symlist_free(&patch_functions);
    729       1.1      fvdl 	symtable_close();
    730       1.1      fvdl 
    731       1.1      fvdl 	exit(err_code);
    732       1.1      fvdl }
    733       1.1      fvdl 
    734       1.1      fvdl struct instruction *
    735       1.7    cegger seq_alloc(void)
    736       1.1      fvdl {
    737       1.1      fvdl 	struct instruction *new_instr;
    738       1.1      fvdl 
    739       1.1      fvdl 	new_instr = (struct instruction *)malloc(sizeof(struct instruction));
    740       1.1      fvdl 	if (new_instr == NULL)
    741       1.1      fvdl 		stop("Unable to malloc instruction object", EX_SOFTWARE);
    742       1.1      fvdl 	memset(new_instr, 0, sizeof(*new_instr));
    743       1.1      fvdl 	STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
    744       1.1      fvdl 	new_instr->srcline = yylineno;
    745       1.1      fvdl 	return new_instr;
    746       1.4      fvdl }
    747       1.4      fvdl 
    748       1.4      fvdl critical_section_t *
    749       1.7    cegger cs_alloc(void)
    750       1.4      fvdl {
    751       1.4      fvdl 	critical_section_t *new_cs;
    752       1.4      fvdl 
    753       1.4      fvdl 	new_cs= (critical_section_t *)malloc(sizeof(critical_section_t));
    754       1.4      fvdl 	if (new_cs == NULL)
    755       1.4      fvdl 		stop("Unable to malloc critical_section object", EX_SOFTWARE);
    756       1.4      fvdl 	memset(new_cs, 0, sizeof(*new_cs));
    757       1.4      fvdl 
    758       1.4      fvdl 	TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links);
    759       1.4      fvdl 	return new_cs;
    760       1.1      fvdl }
    761       1.1      fvdl 
    762       1.1      fvdl scope_t *
    763       1.7    cegger scope_alloc(void)
    764       1.1      fvdl {
    765       1.1      fvdl 	scope_t *new_scope;
    766       1.1      fvdl 
    767       1.1      fvdl 	new_scope = (scope_t *)malloc(sizeof(scope_t));
    768       1.1      fvdl 	if (new_scope == NULL)
    769       1.1      fvdl 		stop("Unable to malloc scope object", EX_SOFTWARE);
    770       1.1      fvdl 	memset(new_scope, 0, sizeof(*new_scope));
    771       1.1      fvdl 	TAILQ_INIT(&new_scope->inner_scope);
    772       1.1      fvdl 
    773       1.1      fvdl 	if (SLIST_FIRST(&scope_stack) != NULL) {
    774       1.1      fvdl 		TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
    775       1.1      fvdl 				  new_scope, scope_links);
    776       1.1      fvdl 	}
    777       1.1      fvdl 	/* This patch is now the current scope */
    778       1.1      fvdl 	SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
    779       1.1      fvdl 	return new_scope;
    780       1.1      fvdl }
    781       1.1      fvdl 
    782       1.1      fvdl void
    783       1.1      fvdl process_scope(scope_t *scope)
    784       1.1      fvdl {
    785       1.1      fvdl 	/*
    786       1.1      fvdl 	 * We are "leaving" this scope.  We should now have
    787       1.1      fvdl 	 * enough information to process the lists of scopes
    788       1.1      fvdl 	 * we encapsulate.
    789       1.1      fvdl 	 */
    790       1.1      fvdl 	scope_t *cur_scope;
    791       1.1      fvdl 	u_int skip_patch_count;
    792       1.1      fvdl 	u_int skip_instr_count;
    793       1.1      fvdl 
    794       1.1      fvdl 	cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
    795       1.1      fvdl 	skip_patch_count = 0;
    796       1.1      fvdl 	skip_instr_count = 0;
    797       1.1      fvdl 	while (cur_scope != NULL) {
    798       1.1      fvdl 		u_int patch0_patch_skip;
    799       1.1      fvdl 
    800       1.1      fvdl 		patch0_patch_skip = 0;
    801       1.1      fvdl 		switch (cur_scope->type) {
    802       1.1      fvdl 		case SCOPE_IF:
    803       1.1      fvdl 		case SCOPE_ELSE_IF:
    804       1.1      fvdl 			if (skip_instr_count != 0) {
    805       1.1      fvdl 				/* Create a tail patch */
    806       1.1      fvdl 				patch0_patch_skip++;
    807       1.1      fvdl 				cur_scope->patches[1].skip_patch =
    808       1.1      fvdl 				    skip_patch_count + 1;
    809       1.1      fvdl 				cur_scope->patches[1].skip_instr =
    810       1.1      fvdl 				    skip_instr_count;
    811       1.1      fvdl 			}
    812       1.1      fvdl 
    813       1.1      fvdl 			/* Count Head patch */
    814       1.1      fvdl 			patch0_patch_skip++;
    815       1.1      fvdl 
    816       1.1      fvdl 			/* Count any patches contained in our inner scope */
    817       1.1      fvdl 			patch0_patch_skip += cur_scope->inner_scope_patches;
    818       1.1      fvdl 
    819       1.1      fvdl 			cur_scope->patches[0].skip_patch = patch0_patch_skip;
    820       1.1      fvdl 			cur_scope->patches[0].skip_instr =
    821       1.1      fvdl 			    cur_scope->end_addr - cur_scope->begin_addr;
    822       1.1      fvdl 
    823       1.1      fvdl 			skip_instr_count += cur_scope->patches[0].skip_instr;
    824       1.1      fvdl 
    825       1.1      fvdl 			skip_patch_count += patch0_patch_skip;
    826       1.1      fvdl 			if (cur_scope->type == SCOPE_IF) {
    827       1.1      fvdl 				scope->inner_scope_patches += skip_patch_count;
    828       1.1      fvdl 				skip_patch_count = 0;
    829       1.1      fvdl 			        skip_instr_count = 0;
    830       1.1      fvdl 			}
    831       1.1      fvdl 			break;
    832       1.1      fvdl 		case SCOPE_ELSE:
    833       1.1      fvdl 			/* Count any patches contained in our innter scope */
    834       1.1      fvdl 			skip_patch_count += cur_scope->inner_scope_patches;
    835       1.1      fvdl 
    836       1.1      fvdl 			skip_instr_count += cur_scope->end_addr
    837       1.1      fvdl 					  - cur_scope->begin_addr;
    838       1.1      fvdl 			break;
    839       1.1      fvdl 		case SCOPE_ROOT:
    840       1.1      fvdl 			stop("Unexpected scope type encountered", EX_SOFTWARE);
    841       1.1      fvdl 			/* NOTREACHED */
    842       1.1      fvdl 		}
    843       1.1      fvdl 
    844       1.1      fvdl 		cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
    845       1.1      fvdl 	}
    846       1.1      fvdl }
    847