diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/aic7xxx/aicasm |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/scsi/aic7xxx/aicasm')
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/Makefile | 78 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm.c | 835 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm.h | 95 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_gram.y | 1945 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h | 131 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y | 164 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l | 156 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_scan.l | 607 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c | 677 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h | 207 |
10 files changed, 4895 insertions, 0 deletions
diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile new file mode 100644 index 000000000000..8c91fda6482c --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/Makefile | |||
@@ -0,0 +1,78 @@ | |||
1 | PROG= aicasm | ||
2 | |||
3 | .SUFFIXES= .l .y .c .h | ||
4 | |||
5 | CSRCS= aicasm.c aicasm_symbol.c | ||
6 | YSRCS= aicasm_gram.y aicasm_macro_gram.y | ||
7 | LSRCS= aicasm_scan.l aicasm_macro_scan.l | ||
8 | |||
9 | GENHDRS= aicdb.h $(YSRCS:.y=.h) | ||
10 | GENSRCS= $(YSRCS:.y=.c) $(LSRCS:.l=.c) | ||
11 | |||
12 | SRCS= ${CSRCS} ${GENSRCS} | ||
13 | LIBS= -ldb | ||
14 | clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG) | ||
15 | # Override default kernel CFLAGS. This is a userland app. | ||
16 | AICASM_CFLAGS:= -I/usr/include -I. | ||
17 | YFLAGS= -d | ||
18 | |||
19 | NOMAN= noman | ||
20 | |||
21 | ifneq ($(HOSTCC),) | ||
22 | AICASM_CC= $(HOSTCC) | ||
23 | else | ||
24 | AICASM_CC= $(CC) | ||
25 | endif | ||
26 | |||
27 | ifdef DEBUG | ||
28 | CFLAGS+= -DDEBUG -g | ||
29 | YFLAGS+= -t -v | ||
30 | LFLAGS= -d | ||
31 | endif | ||
32 | |||
33 | $(PROG): ${GENHDRS} $(SRCS) | ||
34 | $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) $(LIBS) | ||
35 | |||
36 | aicdb.h: | ||
37 | @if [ -e "/usr/include/db4/db_185.h" ]; then \ | ||
38 | echo "#include <db4/db_185.h>" > aicdb.h; \ | ||
39 | elif [ -e "/usr/include/db3/db_185.h" ]; then \ | ||
40 | echo "#include <db3/db_185.h>" > aicdb.h; \ | ||
41 | elif [ -e "/usr/include/db2/db_185.h" ]; then \ | ||
42 | echo "#include <db2/db_185.h>" > aicdb.h; \ | ||
43 | elif [ -e "/usr/include/db1/db_185.h" ]; then \ | ||
44 | echo "#include <db1/db_185.h>" > aicdb.h; \ | ||
45 | elif [ -e "/usr/include/db/db_185.h" ]; then \ | ||
46 | echo "#include <db/db_185.h>" > aicdb.h; \ | ||
47 | elif [ -e "/usr/include/db_185.h" ]; then \ | ||
48 | echo "#include <db_185.h>" > aicdb.h; \ | ||
49 | else \ | ||
50 | echo "*** Install db development libraries"; \ | ||
51 | fi | ||
52 | |||
53 | clean: | ||
54 | rm -f $(clean-files) | ||
55 | |||
56 | # Create a dependency chain in generated files | ||
57 | # to avoid concurrent invocations of the single | ||
58 | # rule that builds them all. | ||
59 | aicasm_gram.c: aicasm_gram.h | ||
60 | aicasm_gram.c aicasm_gram.h: aicasm_gram.y | ||
61 | $(YACC) $(YFLAGS) -b $(<:.y=) $< | ||
62 | mv $(<:.y=).tab.c $(<:.y=.c) | ||
63 | mv $(<:.y=).tab.h $(<:.y=.h) | ||
64 | |||
65 | # Create a dependency chain in generated files | ||
66 | # to avoid concurrent invocations of the single | ||
67 | # rule that builds them all. | ||
68 | aicasm_macro_gram.c: aicasm_macro_gram.h | ||
69 | aicasm_macro_gram.c aicasm_macro_gram.h: aicasm_macro_gram.y | ||
70 | $(YACC) $(YFLAGS) -b $(<:.y=) -p mm $< | ||
71 | mv $(<:.y=).tab.c $(<:.y=.c) | ||
72 | mv $(<:.y=).tab.h $(<:.y=.h) | ||
73 | |||
74 | aicasm_scan.c: aicasm_scan.l | ||
75 | $(LEX) $(LFLAGS) -o$@ $< | ||
76 | |||
77 | aicasm_macro_scan.c: aicasm_macro_scan.l | ||
78 | $(LEX) $(LFLAGS) -Pmm -o$@ $< | ||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.c b/drivers/scsi/aic7xxx/aicasm/aicasm.c new file mode 100644 index 000000000000..c34639481904 --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.c | |||
@@ -0,0 +1,835 @@ | |||
1 | /* | ||
2 | * Aic7xxx SCSI host adapter firmware asssembler | ||
3 | * | ||
4 | * Copyright (c) 1997, 1998, 2000, 2001 Justin T. Gibbs. | ||
5 | * Copyright (c) 2001, 2002 Adaptec Inc. | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions, and the following disclaimer, | ||
13 | * without modification. | ||
14 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
15 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
16 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
17 | * including a substantially similar Disclaimer requirement for further | ||
18 | * binary redistribution. | ||
19 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
20 | * of any contributors may be used to endorse or promote products derived | ||
21 | * from this software without specific prior written permission. | ||
22 | * | ||
23 | * Alternatively, this software may be distributed under the terms of the | ||
24 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
25 | * Software Foundation. | ||
26 | * | ||
27 | * NO WARRANTY | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
30 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
31 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
32 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
37 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGES. | ||
39 | * | ||
40 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#22 $ | ||
41 | * | ||
42 | * $FreeBSD$ | ||
43 | */ | ||
44 | #include <sys/types.h> | ||
45 | #include <sys/mman.h> | ||
46 | |||
47 | #include <ctype.h> | ||
48 | #include <inttypes.h> | ||
49 | #include <regex.h> | ||
50 | #include <stdio.h> | ||
51 | #include <stdlib.h> | ||
52 | #include <string.h> | ||
53 | #include <sysexits.h> | ||
54 | #include <unistd.h> | ||
55 | |||
56 | #if linux | ||
57 | #include <endian.h> | ||
58 | #else | ||
59 | #include <machine/endian.h> | ||
60 | #endif | ||
61 | |||
62 | #include "aicasm.h" | ||
63 | #include "aicasm_symbol.h" | ||
64 | #include "aicasm_insformat.h" | ||
65 | |||
66 | typedef struct patch { | ||
67 | STAILQ_ENTRY(patch) links; | ||
68 | int patch_func; | ||
69 | u_int begin; | ||
70 | u_int skip_instr; | ||
71 | u_int skip_patch; | ||
72 | } patch_t; | ||
73 | |||
74 | STAILQ_HEAD(patch_list, patch) patches; | ||
75 | |||
76 | static void usage(void); | ||
77 | static void back_patch(void); | ||
78 | static void output_code(void); | ||
79 | static void output_listing(char *ifilename); | ||
80 | static void dump_scope(scope_t *scope); | ||
81 | static void emit_patch(scope_t *scope, int patch); | ||
82 | static int check_patch(patch_t **start_patch, int start_instr, | ||
83 | int *skip_addr, int *func_vals); | ||
84 | |||
85 | struct path_list search_path; | ||
86 | int includes_search_curdir; | ||
87 | char *appname; | ||
88 | char *stock_include_file; | ||
89 | FILE *ofile; | ||
90 | char *ofilename; | ||
91 | char *regfilename; | ||
92 | FILE *regfile; | ||
93 | char *listfilename; | ||
94 | FILE *listfile; | ||
95 | char *regdiagfilename; | ||
96 | FILE *regdiagfile; | ||
97 | int src_mode; | ||
98 | int dst_mode; | ||
99 | |||
100 | static STAILQ_HEAD(,instruction) seq_program; | ||
101 | struct cs_tailq cs_tailq; | ||
102 | struct scope_list scope_stack; | ||
103 | symlist_t patch_functions; | ||
104 | |||
105 | #if DEBUG | ||
106 | extern int yy_flex_debug; | ||
107 | extern int mm_flex_debug; | ||
108 | extern int yydebug; | ||
109 | extern int mmdebug; | ||
110 | #endif | ||
111 | extern FILE *yyin; | ||
112 | extern int yyparse(void); | ||
113 | |||
114 | int main(int argc, char *argv[]); | ||
115 | |||
116 | int | ||
117 | main(int argc, char *argv[]) | ||
118 | { | ||
119 | extern char *optarg; | ||
120 | extern int optind; | ||
121 | int ch; | ||
122 | int retval; | ||
123 | char *inputfilename; | ||
124 | scope_t *sentinal; | ||
125 | |||
126 | STAILQ_INIT(&patches); | ||
127 | SLIST_INIT(&search_path); | ||
128 | STAILQ_INIT(&seq_program); | ||
129 | TAILQ_INIT(&cs_tailq); | ||
130 | SLIST_INIT(&scope_stack); | ||
131 | |||
132 | /* Set Sentinal scope node */ | ||
133 | sentinal = scope_alloc(); | ||
134 | sentinal->type = SCOPE_ROOT; | ||
135 | |||
136 | includes_search_curdir = 1; | ||
137 | appname = *argv; | ||
138 | regfile = NULL; | ||
139 | listfile = NULL; | ||
140 | #if DEBUG | ||
141 | yy_flex_debug = 0; | ||
142 | mm_flex_debug = 0; | ||
143 | yydebug = 0; | ||
144 | mmdebug = 0; | ||
145 | #endif | ||
146 | while ((ch = getopt(argc, argv, "d:i:l:n:o:p:r:I:")) != -1) { | ||
147 | switch(ch) { | ||
148 | case 'd': | ||
149 | #if DEBUG | ||
150 | if (strcmp(optarg, "s") == 0) { | ||
151 | yy_flex_debug = 1; | ||
152 | mm_flex_debug = 1; | ||
153 | } else if (strcmp(optarg, "p") == 0) { | ||
154 | yydebug = 1; | ||
155 | mmdebug = 1; | ||
156 | } else { | ||
157 | fprintf(stderr, "%s: -d Requires either an " | ||
158 | "'s' or 'p' argument\n", appname); | ||
159 | usage(); | ||
160 | } | ||
161 | #else | ||
162 | stop("-d: Assembler not built with debugging " | ||
163 | "information", EX_SOFTWARE); | ||
164 | #endif | ||
165 | break; | ||
166 | case 'i': | ||
167 | stock_include_file = optarg; | ||
168 | break; | ||
169 | case 'l': | ||
170 | /* Create a program listing */ | ||
171 | if ((listfile = fopen(optarg, "w")) == NULL) { | ||
172 | perror(optarg); | ||
173 | stop(NULL, EX_CANTCREAT); | ||
174 | } | ||
175 | listfilename = optarg; | ||
176 | break; | ||
177 | case 'n': | ||
178 | /* Don't complain about the -nostdinc directrive */ | ||
179 | if (strcmp(optarg, "ostdinc")) { | ||
180 | fprintf(stderr, "%s: Unknown option -%c%s\n", | ||
181 | appname, ch, optarg); | ||
182 | usage(); | ||
183 | /* NOTREACHED */ | ||
184 | } | ||
185 | break; | ||
186 | case 'o': | ||
187 | if ((ofile = fopen(optarg, "w")) == NULL) { | ||
188 | perror(optarg); | ||
189 | stop(NULL, EX_CANTCREAT); | ||
190 | } | ||
191 | ofilename = optarg; | ||
192 | break; | ||
193 | case 'p': | ||
194 | /* Create Register Diagnostic "printing" Functions */ | ||
195 | if ((regdiagfile = fopen(optarg, "w")) == NULL) { | ||
196 | perror(optarg); | ||
197 | stop(NULL, EX_CANTCREAT); | ||
198 | } | ||
199 | regdiagfilename = optarg; | ||
200 | break; | ||
201 | case 'r': | ||
202 | if ((regfile = fopen(optarg, "w")) == NULL) { | ||
203 | perror(optarg); | ||
204 | stop(NULL, EX_CANTCREAT); | ||
205 | } | ||
206 | regfilename = optarg; | ||
207 | break; | ||
208 | case 'I': | ||
209 | { | ||
210 | path_entry_t include_dir; | ||
211 | |||
212 | if (strcmp(optarg, "-") == 0) { | ||
213 | if (includes_search_curdir == 0) { | ||
214 | fprintf(stderr, "%s: Warning - '-I-' " | ||
215 | "specified multiple " | ||
216 | "times\n", appname); | ||
217 | } | ||
218 | includes_search_curdir = 0; | ||
219 | for (include_dir = SLIST_FIRST(&search_path); | ||
220 | include_dir != NULL; | ||
221 | include_dir = SLIST_NEXT(include_dir, | ||
222 | links)) | ||
223 | /* | ||
224 | * All entries before a '-I-' only | ||
225 | * apply to includes specified with | ||
226 | * quotes instead of "<>". | ||
227 | */ | ||
228 | include_dir->quoted_includes_only = 1; | ||
229 | } else { | ||
230 | include_dir = | ||
231 | (path_entry_t)malloc(sizeof(*include_dir)); | ||
232 | if (include_dir == NULL) { | ||
233 | perror(optarg); | ||
234 | stop(NULL, EX_OSERR); | ||
235 | } | ||
236 | include_dir->directory = strdup(optarg); | ||
237 | if (include_dir->directory == NULL) { | ||
238 | perror(optarg); | ||
239 | stop(NULL, EX_OSERR); | ||
240 | } | ||
241 | include_dir->quoted_includes_only = 0; | ||
242 | SLIST_INSERT_HEAD(&search_path, include_dir, | ||
243 | links); | ||
244 | } | ||
245 | break; | ||
246 | } | ||
247 | case '?': | ||
248 | default: | ||
249 | usage(); | ||
250 | /* NOTREACHED */ | ||
251 | } | ||
252 | } | ||
253 | argc -= optind; | ||
254 | argv += optind; | ||
255 | |||
256 | if (argc != 1) { | ||
257 | fprintf(stderr, "%s: No input file specifiled\n", appname); | ||
258 | usage(); | ||
259 | /* NOTREACHED */ | ||
260 | } | ||
261 | |||
262 | if (regdiagfile != NULL | ||
263 | && (regfile == NULL || stock_include_file == NULL)) { | ||
264 | fprintf(stderr, | ||
265 | "%s: The -p option requires the -r and -i options.\n", | ||
266 | appname); | ||
267 | usage(); | ||
268 | /* NOTREACHED */ | ||
269 | } | ||
270 | symtable_open(); | ||
271 | inputfilename = *argv; | ||
272 | include_file(*argv, SOURCE_FILE); | ||
273 | retval = yyparse(); | ||
274 | if (retval == 0) { | ||
275 | if (SLIST_FIRST(&scope_stack) == NULL | ||
276 | || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { | ||
277 | stop("Unterminated conditional expression", EX_DATAERR); | ||
278 | /* NOTREACHED */ | ||
279 | } | ||
280 | |||
281 | /* Process outmost scope */ | ||
282 | process_scope(SLIST_FIRST(&scope_stack)); | ||
283 | /* | ||
284 | * Decend the tree of scopes and insert/emit | ||
285 | * patches as appropriate. We perform a depth first | ||
286 | * tranversal, recursively handling each scope. | ||
287 | */ | ||
288 | /* start at the root scope */ | ||
289 | dump_scope(SLIST_FIRST(&scope_stack)); | ||
290 | |||
291 | /* Patch up forward jump addresses */ | ||
292 | back_patch(); | ||
293 | |||
294 | if (ofile != NULL) | ||
295 | output_code(); | ||
296 | if (regfile != NULL) | ||
297 | symtable_dump(regfile, regdiagfile); | ||
298 | if (listfile != NULL) | ||
299 | output_listing(inputfilename); | ||
300 | } | ||
301 | |||
302 | stop(NULL, 0); | ||
303 | /* NOTREACHED */ | ||
304 | return (0); | ||
305 | } | ||
306 | |||
307 | static void | ||
308 | usage() | ||
309 | { | ||
310 | |||
311 | (void)fprintf(stderr, | ||
312 | "usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]\n" | ||
313 | " [-r register_output_file [-p register_diag_file -i includefile]]\n" | ||
314 | " [-l program_list_file]\n" | ||
315 | " input_file\n", appname); | ||
316 | exit(EX_USAGE); | ||
317 | } | ||
318 | |||
319 | static void | ||
320 | back_patch() | ||
321 | { | ||
322 | struct instruction *cur_instr; | ||
323 | |||
324 | for (cur_instr = STAILQ_FIRST(&seq_program); | ||
325 | cur_instr != NULL; | ||
326 | cur_instr = STAILQ_NEXT(cur_instr, links)) { | ||
327 | if (cur_instr->patch_label != NULL) { | ||
328 | struct ins_format3 *f3_instr; | ||
329 | u_int address; | ||
330 | |||
331 | if (cur_instr->patch_label->type != LABEL) { | ||
332 | char buf[255]; | ||
333 | |||
334 | snprintf(buf, sizeof(buf), | ||
335 | "Undefined label %s", | ||
336 | cur_instr->patch_label->name); | ||
337 | stop(buf, EX_DATAERR); | ||
338 | /* NOTREACHED */ | ||
339 | } | ||
340 | f3_instr = &cur_instr->format.format3; | ||
341 | address = f3_instr->address; | ||
342 | address += cur_instr->patch_label->info.linfo->address; | ||
343 | f3_instr->address = address; | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | |||
348 | static void | ||
349 | output_code() | ||
350 | { | ||
351 | struct instruction *cur_instr; | ||
352 | patch_t *cur_patch; | ||
353 | critical_section_t *cs; | ||
354 | symbol_node_t *cur_node; | ||
355 | int instrcount; | ||
356 | |||
357 | instrcount = 0; | ||
358 | fprintf(ofile, | ||
359 | "/*\n" | ||
360 | " * DO NOT EDIT - This file is automatically generated\n" | ||
361 | " * from the following source files:\n" | ||
362 | " *\n" | ||
363 | "%s */\n", versions); | ||
364 | |||
365 | fprintf(ofile, "static uint8_t seqprog[] = {\n"); | ||
366 | for (cur_instr = STAILQ_FIRST(&seq_program); | ||
367 | cur_instr != NULL; | ||
368 | cur_instr = STAILQ_NEXT(cur_instr, links)) { | ||
369 | |||
370 | fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x", | ||
371 | cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n", | ||
372 | #if BYTE_ORDER == LITTLE_ENDIAN | ||
373 | cur_instr->format.bytes[0], | ||
374 | cur_instr->format.bytes[1], | ||
375 | cur_instr->format.bytes[2], | ||
376 | cur_instr->format.bytes[3]); | ||
377 | #else | ||
378 | cur_instr->format.bytes[3], | ||
379 | cur_instr->format.bytes[2], | ||
380 | cur_instr->format.bytes[1], | ||
381 | cur_instr->format.bytes[0]); | ||
382 | #endif | ||
383 | instrcount++; | ||
384 | } | ||
385 | fprintf(ofile, "\n};\n\n"); | ||
386 | |||
387 | if (patch_arg_list == NULL) | ||
388 | stop("Patch argument list not defined", | ||
389 | EX_DATAERR); | ||
390 | |||
391 | /* | ||
392 | * Output patch information. Patch functions first. | ||
393 | */ | ||
394 | fprintf(ofile, | ||
395 | "typedef int %spatch_func_t (%s);\n", prefix, patch_arg_list); | ||
396 | |||
397 | for (cur_node = SLIST_FIRST(&patch_functions); | ||
398 | cur_node != NULL; | ||
399 | cur_node = SLIST_NEXT(cur_node,links)) { | ||
400 | fprintf(ofile, | ||
401 | "static %spatch_func_t %spatch%d_func;\n" | ||
402 | "\n" | ||
403 | "static int\n" | ||
404 | "%spatch%d_func(%s)\n" | ||
405 | "{\n" | ||
406 | " return (%s);\n" | ||
407 | "}\n\n", | ||
408 | prefix, | ||
409 | prefix, | ||
410 | cur_node->symbol->info.condinfo->func_num, | ||
411 | prefix, | ||
412 | cur_node->symbol->info.condinfo->func_num, | ||
413 | patch_arg_list, | ||
414 | cur_node->symbol->name); | ||
415 | } | ||
416 | |||
417 | fprintf(ofile, | ||
418 | "static struct patch {\n" | ||
419 | " %spatch_func_t *patch_func;\n" | ||
420 | " uint32_t begin :10,\n" | ||
421 | " skip_instr :10,\n" | ||
422 | " skip_patch :12;\n" | ||
423 | "} patches[] = {\n", prefix); | ||
424 | |||
425 | for (cur_patch = STAILQ_FIRST(&patches); | ||
426 | cur_patch != NULL; | ||
427 | cur_patch = STAILQ_NEXT(cur_patch,links)) { | ||
428 | fprintf(ofile, "%s\t{ %spatch%d_func, %d, %d, %d }", | ||
429 | cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n", | ||
430 | prefix, | ||
431 | cur_patch->patch_func, cur_patch->begin, | ||
432 | cur_patch->skip_instr, cur_patch->skip_patch); | ||
433 | } | ||
434 | |||
435 | fprintf(ofile, "\n};\n\n"); | ||
436 | |||
437 | fprintf(ofile, | ||
438 | "static struct cs {\n" | ||
439 | " uint16_t begin;\n" | ||
440 | " uint16_t end;\n" | ||
441 | "} critical_sections[] = {\n"); | ||
442 | |||
443 | for (cs = TAILQ_FIRST(&cs_tailq); | ||
444 | cs != NULL; | ||
445 | cs = TAILQ_NEXT(cs, links)) { | ||
446 | fprintf(ofile, "%s\t{ %d, %d }", | ||
447 | cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n", | ||
448 | cs->begin_addr, cs->end_addr); | ||
449 | } | ||
450 | |||
451 | fprintf(ofile, "\n};\n\n"); | ||
452 | |||
453 | fprintf(ofile, | ||
454 | "static const int num_critical_sections = sizeof(critical_sections)\n" | ||
455 | " / sizeof(*critical_sections);\n"); | ||
456 | |||
457 | fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); | ||
458 | } | ||
459 | |||
460 | static void | ||
461 | dump_scope(scope_t *scope) | ||
462 | { | ||
463 | scope_t *cur_scope; | ||
464 | |||
465 | /* | ||
466 | * Emit the first patch for this scope | ||
467 | */ | ||
468 | emit_patch(scope, 0); | ||
469 | |||
470 | /* | ||
471 | * Dump each scope within this one. | ||
472 | */ | ||
473 | cur_scope = TAILQ_FIRST(&scope->inner_scope); | ||
474 | |||
475 | while (cur_scope != NULL) { | ||
476 | |||
477 | dump_scope(cur_scope); | ||
478 | |||
479 | cur_scope = TAILQ_NEXT(cur_scope, scope_links); | ||
480 | } | ||
481 | |||
482 | /* | ||
483 | * Emit the second, closing, patch for this scope | ||
484 | */ | ||
485 | emit_patch(scope, 1); | ||
486 | } | ||
487 | |||
488 | void | ||
489 | emit_patch(scope_t *scope, int patch) | ||
490 | { | ||
491 | patch_info_t *pinfo; | ||
492 | patch_t *new_patch; | ||
493 | |||
494 | pinfo = &scope->patches[patch]; | ||
495 | |||
496 | if (pinfo->skip_instr == 0) | ||
497 | /* No-Op patch */ | ||
498 | return; | ||
499 | |||
500 | new_patch = (patch_t *)malloc(sizeof(*new_patch)); | ||
501 | |||
502 | if (new_patch == NULL) | ||
503 | stop("Could not malloc patch structure", EX_OSERR); | ||
504 | |||
505 | memset(new_patch, 0, sizeof(*new_patch)); | ||
506 | |||
507 | if (patch == 0) { | ||
508 | new_patch->patch_func = scope->func_num; | ||
509 | new_patch->begin = scope->begin_addr; | ||
510 | } else { | ||
511 | new_patch->patch_func = 0; | ||
512 | new_patch->begin = scope->end_addr; | ||
513 | } | ||
514 | new_patch->skip_instr = pinfo->skip_instr; | ||
515 | new_patch->skip_patch = pinfo->skip_patch; | ||
516 | STAILQ_INSERT_TAIL(&patches, new_patch, links); | ||
517 | } | ||
518 | |||
519 | void | ||
520 | output_listing(char *ifilename) | ||
521 | { | ||
522 | char buf[1024]; | ||
523 | FILE *ifile; | ||
524 | struct instruction *cur_instr; | ||
525 | patch_t *cur_patch; | ||
526 | symbol_node_t *cur_func; | ||
527 | int *func_values; | ||
528 | int instrcount; | ||
529 | int instrptr; | ||
530 | int line; | ||
531 | int func_count; | ||
532 | int skip_addr; | ||
533 | |||
534 | instrcount = 0; | ||
535 | instrptr = 0; | ||
536 | line = 1; | ||
537 | skip_addr = 0; | ||
538 | if ((ifile = fopen(ifilename, "r")) == NULL) { | ||
539 | perror(ifilename); | ||
540 | stop(NULL, EX_DATAERR); | ||
541 | } | ||
542 | |||
543 | /* | ||
544 | * Determine which options to apply to this listing. | ||
545 | */ | ||
546 | for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions); | ||
547 | cur_func != NULL; | ||
548 | cur_func = SLIST_NEXT(cur_func, links)) | ||
549 | func_count++; | ||
550 | |||
551 | func_values = NULL; | ||
552 | if (func_count != 0) { | ||
553 | func_values = (int *)malloc(func_count * sizeof(int)); | ||
554 | |||
555 | if (func_values == NULL) | ||
556 | stop("Could not malloc", EX_OSERR); | ||
557 | |||
558 | func_values[0] = 0; /* FALSE func */ | ||
559 | func_count--; | ||
560 | |||
561 | /* | ||
562 | * Ask the user to fill in the return values for | ||
563 | * the rest of the functions. | ||
564 | */ | ||
565 | |||
566 | |||
567 | for (cur_func = SLIST_FIRST(&patch_functions); | ||
568 | cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL; | ||
569 | cur_func = SLIST_NEXT(cur_func, links), func_count--) { | ||
570 | int input; | ||
571 | |||
572 | fprintf(stdout, "\n(%s)\n", cur_func->symbol->name); | ||
573 | fprintf(stdout, | ||
574 | "Enter the return value for " | ||
575 | "this expression[T/F]:"); | ||
576 | |||
577 | while (1) { | ||
578 | |||
579 | input = getchar(); | ||
580 | input = toupper(input); | ||
581 | |||
582 | if (input == 'T') { | ||
583 | func_values[func_count] = 1; | ||
584 | break; | ||
585 | } else if (input == 'F') { | ||
586 | func_values[func_count] = 0; | ||
587 | break; | ||
588 | } | ||
589 | } | ||
590 | if (isatty(fileno(stdin)) == 0) | ||
591 | putchar(input); | ||
592 | } | ||
593 | fprintf(stdout, "\nThanks!\n"); | ||
594 | } | ||
595 | |||
596 | /* Now output the listing */ | ||
597 | cur_patch = STAILQ_FIRST(&patches); | ||
598 | for (cur_instr = STAILQ_FIRST(&seq_program); | ||
599 | cur_instr != NULL; | ||
600 | cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) { | ||
601 | |||
602 | if (check_patch(&cur_patch, instrcount, | ||
603 | &skip_addr, func_values) == 0) { | ||
604 | /* Don't count this instruction as it is in a patch | ||
605 | * that was removed. | ||
606 | */ | ||
607 | continue; | ||
608 | } | ||
609 | |||
610 | while (line < cur_instr->srcline) { | ||
611 | fgets(buf, sizeof(buf), ifile); | ||
612 | fprintf(listfile, "\t\t%s", buf); | ||
613 | line++; | ||
614 | } | ||
615 | fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, | ||
616 | #if BYTE_ORDER == LITTLE_ENDIAN | ||
617 | cur_instr->format.bytes[0], | ||
618 | cur_instr->format.bytes[1], | ||
619 | cur_instr->format.bytes[2], | ||
620 | cur_instr->format.bytes[3]); | ||
621 | #else | ||
622 | cur_instr->format.bytes[3], | ||
623 | cur_instr->format.bytes[2], | ||
624 | cur_instr->format.bytes[1], | ||
625 | cur_instr->format.bytes[0]); | ||
626 | #endif | ||
627 | fgets(buf, sizeof(buf), ifile); | ||
628 | fprintf(listfile, "\t%s", buf); | ||
629 | line++; | ||
630 | instrptr++; | ||
631 | } | ||
632 | /* Dump the remainder of the file */ | ||
633 | while(fgets(buf, sizeof(buf), ifile) != NULL) | ||
634 | fprintf(listfile, "\t\t%s", buf); | ||
635 | |||
636 | fclose(ifile); | ||
637 | } | ||
638 | |||
639 | static int | ||
640 | check_patch(patch_t **start_patch, int start_instr, | ||
641 | int *skip_addr, int *func_vals) | ||
642 | { | ||
643 | patch_t *cur_patch; | ||
644 | |||
645 | cur_patch = *start_patch; | ||
646 | |||
647 | while (cur_patch != NULL && start_instr == cur_patch->begin) { | ||
648 | if (func_vals[cur_patch->patch_func] == 0) { | ||
649 | int skip; | ||
650 | |||
651 | /* Start rejecting code */ | ||
652 | *skip_addr = start_instr + cur_patch->skip_instr; | ||
653 | for (skip = cur_patch->skip_patch; | ||
654 | skip > 0 && cur_patch != NULL; | ||
655 | skip--) | ||
656 | cur_patch = STAILQ_NEXT(cur_patch, links); | ||
657 | } else { | ||
658 | /* Accepted this patch. Advance to the next | ||
659 | * one and wait for our intruction pointer to | ||
660 | * hit this point. | ||
661 | */ | ||
662 | cur_patch = STAILQ_NEXT(cur_patch, links); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | *start_patch = cur_patch; | ||
667 | if (start_instr < *skip_addr) | ||
668 | /* Still skipping */ | ||
669 | return (0); | ||
670 | |||
671 | return (1); | ||
672 | } | ||
673 | |||
674 | /* | ||
675 | * Print out error information if appropriate, and clean up before | ||
676 | * terminating the program. | ||
677 | */ | ||
678 | void | ||
679 | stop(const char *string, int err_code) | ||
680 | { | ||
681 | if (string != NULL) { | ||
682 | fprintf(stderr, "%s: ", appname); | ||
683 | if (yyfilename != NULL) { | ||
684 | fprintf(stderr, "Stopped at file %s, line %d - ", | ||
685 | yyfilename, yylineno); | ||
686 | } | ||
687 | fprintf(stderr, "%s\n", string); | ||
688 | } | ||
689 | |||
690 | if (ofile != NULL) { | ||
691 | fclose(ofile); | ||
692 | if (err_code != 0) { | ||
693 | fprintf(stderr, "%s: Removing %s due to error\n", | ||
694 | appname, ofilename); | ||
695 | unlink(ofilename); | ||
696 | } | ||
697 | } | ||
698 | |||
699 | if (regfile != NULL) { | ||
700 | fclose(regfile); | ||
701 | if (err_code != 0) { | ||
702 | fprintf(stderr, "%s: Removing %s due to error\n", | ||
703 | appname, regfilename); | ||
704 | unlink(regfilename); | ||
705 | } | ||
706 | } | ||
707 | |||
708 | if (listfile != NULL) { | ||
709 | fclose(listfile); | ||
710 | if (err_code != 0) { | ||
711 | fprintf(stderr, "%s: Removing %s due to error\n", | ||
712 | appname, listfilename); | ||
713 | unlink(listfilename); | ||
714 | } | ||
715 | } | ||
716 | |||
717 | symlist_free(&patch_functions); | ||
718 | symtable_close(); | ||
719 | |||
720 | exit(err_code); | ||
721 | } | ||
722 | |||
723 | struct instruction * | ||
724 | seq_alloc() | ||
725 | { | ||
726 | struct instruction *new_instr; | ||
727 | |||
728 | new_instr = (struct instruction *)malloc(sizeof(struct instruction)); | ||
729 | if (new_instr == NULL) | ||
730 | stop("Unable to malloc instruction object", EX_SOFTWARE); | ||
731 | memset(new_instr, 0, sizeof(*new_instr)); | ||
732 | STAILQ_INSERT_TAIL(&seq_program, new_instr, links); | ||
733 | new_instr->srcline = yylineno; | ||
734 | return new_instr; | ||
735 | } | ||
736 | |||
737 | critical_section_t * | ||
738 | cs_alloc() | ||
739 | { | ||
740 | critical_section_t *new_cs; | ||
741 | |||
742 | new_cs= (critical_section_t *)malloc(sizeof(critical_section_t)); | ||
743 | if (new_cs == NULL) | ||
744 | stop("Unable to malloc critical_section object", EX_SOFTWARE); | ||
745 | memset(new_cs, 0, sizeof(*new_cs)); | ||
746 | |||
747 | TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links); | ||
748 | return new_cs; | ||
749 | } | ||
750 | |||
751 | scope_t * | ||
752 | scope_alloc() | ||
753 | { | ||
754 | scope_t *new_scope; | ||
755 | |||
756 | new_scope = (scope_t *)malloc(sizeof(scope_t)); | ||
757 | if (new_scope == NULL) | ||
758 | stop("Unable to malloc scope object", EX_SOFTWARE); | ||
759 | memset(new_scope, 0, sizeof(*new_scope)); | ||
760 | TAILQ_INIT(&new_scope->inner_scope); | ||
761 | |||
762 | if (SLIST_FIRST(&scope_stack) != NULL) { | ||
763 | TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope, | ||
764 | new_scope, scope_links); | ||
765 | } | ||
766 | /* This patch is now the current scope */ | ||
767 | SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links); | ||
768 | return new_scope; | ||
769 | } | ||
770 | |||
771 | void | ||
772 | process_scope(scope_t *scope) | ||
773 | { | ||
774 | /* | ||
775 | * We are "leaving" this scope. We should now have | ||
776 | * enough information to process the lists of scopes | ||
777 | * we encapsulate. | ||
778 | */ | ||
779 | scope_t *cur_scope; | ||
780 | u_int skip_patch_count; | ||
781 | u_int skip_instr_count; | ||
782 | |||
783 | cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq); | ||
784 | skip_patch_count = 0; | ||
785 | skip_instr_count = 0; | ||
786 | while (cur_scope != NULL) { | ||
787 | u_int patch0_patch_skip; | ||
788 | |||
789 | patch0_patch_skip = 0; | ||
790 | switch (cur_scope->type) { | ||
791 | case SCOPE_IF: | ||
792 | case SCOPE_ELSE_IF: | ||
793 | if (skip_instr_count != 0) { | ||
794 | /* Create a tail patch */ | ||
795 | patch0_patch_skip++; | ||
796 | cur_scope->patches[1].skip_patch = | ||
797 | skip_patch_count + 1; | ||
798 | cur_scope->patches[1].skip_instr = | ||
799 | skip_instr_count; | ||
800 | } | ||
801 | |||
802 | /* Count Head patch */ | ||
803 | patch0_patch_skip++; | ||
804 | |||
805 | /* Count any patches contained in our inner scope */ | ||
806 | patch0_patch_skip += cur_scope->inner_scope_patches; | ||
807 | |||
808 | cur_scope->patches[0].skip_patch = patch0_patch_skip; | ||
809 | cur_scope->patches[0].skip_instr = | ||
810 | cur_scope->end_addr - cur_scope->begin_addr; | ||
811 | |||
812 | skip_instr_count += cur_scope->patches[0].skip_instr; | ||
813 | |||
814 | skip_patch_count += patch0_patch_skip; | ||
815 | if (cur_scope->type == SCOPE_IF) { | ||
816 | scope->inner_scope_patches += skip_patch_count; | ||
817 | skip_patch_count = 0; | ||
818 | skip_instr_count = 0; | ||
819 | } | ||
820 | break; | ||
821 | case SCOPE_ELSE: | ||
822 | /* Count any patches contained in our innter scope */ | ||
823 | skip_patch_count += cur_scope->inner_scope_patches; | ||
824 | |||
825 | skip_instr_count += cur_scope->end_addr | ||
826 | - cur_scope->begin_addr; | ||
827 | break; | ||
828 | case SCOPE_ROOT: | ||
829 | stop("Unexpected scope type encountered", EX_SOFTWARE); | ||
830 | /* NOTREACHED */ | ||
831 | } | ||
832 | |||
833 | cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links); | ||
834 | } | ||
835 | } | ||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.h b/drivers/scsi/aic7xxx/aicasm/aicasm.h new file mode 100644 index 000000000000..51678dd46ff7 --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters | ||
3 | * | ||
4 | * Copyright (c) 1997 Justin T. Gibbs. | ||
5 | * Copyright (c) 2001, 2002 Adaptec Inc. | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions, and the following disclaimer, | ||
13 | * without modification. | ||
14 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
15 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
16 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
17 | * including a substantially similar Disclaimer requirement for further | ||
18 | * binary redistribution. | ||
19 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
20 | * of any contributors may be used to endorse or promote products derived | ||
21 | * from this software without specific prior written permission. | ||
22 | * | ||
23 | * Alternatively, this software may be distributed under the terms of the | ||
24 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
25 | * Software Foundation. | ||
26 | * | ||
27 | * NO WARRANTY | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
30 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
31 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
32 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
37 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGES. | ||
39 | * | ||
40 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.h#14 $ | ||
41 | * | ||
42 | * $FreeBSD$ | ||
43 | */ | ||
44 | |||
45 | #ifdef __linux__ | ||
46 | #include "../queue.h" | ||
47 | #else | ||
48 | #include <sys/queue.h> | ||
49 | #endif | ||
50 | |||
51 | #ifndef TRUE | ||
52 | #define TRUE 1 | ||
53 | #endif | ||
54 | |||
55 | #ifndef FALSE | ||
56 | #define FALSE 0 | ||
57 | #endif | ||
58 | |||
59 | typedef struct path_entry { | ||
60 | char *directory; | ||
61 | int quoted_includes_only; | ||
62 | SLIST_ENTRY(path_entry) links; | ||
63 | } *path_entry_t; | ||
64 | |||
65 | typedef enum { | ||
66 | QUOTED_INCLUDE, | ||
67 | BRACKETED_INCLUDE, | ||
68 | SOURCE_FILE | ||
69 | } include_type; | ||
70 | |||
71 | SLIST_HEAD(path_list, path_entry); | ||
72 | |||
73 | extern struct path_list search_path; | ||
74 | extern struct cs_tailq cs_tailq; | ||
75 | extern struct scope_list scope_stack; | ||
76 | extern struct symlist patch_functions; | ||
77 | extern int includes_search_curdir; /* False if we've seen -I- */ | ||
78 | extern char *appname; | ||
79 | extern char *stock_include_file; | ||
80 | extern int yylineno; | ||
81 | extern char *yyfilename; | ||
82 | extern char *prefix; | ||
83 | extern char *patch_arg_list; | ||
84 | extern char *versions; | ||
85 | extern int src_mode; | ||
86 | extern int dst_mode; | ||
87 | struct symbol; | ||
88 | |||
89 | void stop(const char *errstring, int err_code); | ||
90 | void include_file(char *file_name, include_type type); | ||
91 | void expand_macro(struct symbol *macro_symbol); | ||
92 | struct instruction *seq_alloc(void); | ||
93 | struct critical_section *cs_alloc(void); | ||
94 | struct scope *scope_alloc(void); | ||
95 | void process_scope(struct scope *); | ||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y new file mode 100644 index 000000000000..67e046d96625 --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y | |||
@@ -0,0 +1,1945 @@ | |||
1 | %{ | ||
2 | /* | ||
3 | * Parser for the Aic7xxx SCSI Host adapter sequencer assembler. | ||
4 | * | ||
5 | * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. | ||
6 | * Copyright (c) 2001, 2002 Adaptec Inc. | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * 1. Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions, and the following disclaimer, | ||
14 | * without modification. | ||
15 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
16 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
17 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
18 | * including a substantially similar Disclaimer requirement for further | ||
19 | * binary redistribution. | ||
20 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
21 | * of any contributors may be used to endorse or promote products derived | ||
22 | * from this software without specific prior written permission. | ||
23 | * | ||
24 | * Alternatively, this software may be distributed under the terms of the | ||
25 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
26 | * Software Foundation. | ||
27 | * | ||
28 | * NO WARRANTY | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
32 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
33 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
37 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
38 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGES. | ||
40 | * | ||
41 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#29 $ | ||
42 | * | ||
43 | * $FreeBSD$ | ||
44 | */ | ||
45 | |||
46 | #include <sys/types.h> | ||
47 | |||
48 | #include <inttypes.h> | ||
49 | #include <regex.h> | ||
50 | #include <stdio.h> | ||
51 | #include <stdlib.h> | ||
52 | #include <string.h> | ||
53 | #include <sysexits.h> | ||
54 | |||
55 | #ifdef __linux__ | ||
56 | #include "../queue.h" | ||
57 | #else | ||
58 | #include <sys/queue.h> | ||
59 | #endif | ||
60 | |||
61 | #include "aicasm.h" | ||
62 | #include "aicasm_symbol.h" | ||
63 | #include "aicasm_insformat.h" | ||
64 | |||
65 | int yylineno; | ||
66 | char *yyfilename; | ||
67 | char stock_prefix[] = "aic_"; | ||
68 | char *prefix = stock_prefix; | ||
69 | char *patch_arg_list; | ||
70 | char *versions; | ||
71 | static char errbuf[255]; | ||
72 | static char regex_pattern[255]; | ||
73 | static symbol_t *cur_symbol; | ||
74 | static symbol_t *field_symbol; | ||
75 | static symbol_t *scb_or_sram_symbol; | ||
76 | static symtype cur_symtype; | ||
77 | static symbol_ref_t accumulator; | ||
78 | static symbol_ref_t mode_ptr; | ||
79 | static symbol_ref_t allones; | ||
80 | static symbol_ref_t allzeros; | ||
81 | static symbol_ref_t none; | ||
82 | static symbol_ref_t sindex; | ||
83 | static int instruction_ptr; | ||
84 | static int num_srams; | ||
85 | static int sram_or_scb_offset; | ||
86 | static int download_constant_count; | ||
87 | static int in_critical_section; | ||
88 | static u_int enum_increment; | ||
89 | static u_int enum_next_value; | ||
90 | |||
91 | static void process_field(int field_type, symbol_t *sym, int mask); | ||
92 | static void initialize_symbol(symbol_t *symbol); | ||
93 | static void add_macro_arg(const char *argtext, int position); | ||
94 | static void add_macro_body(const char *bodytext); | ||
95 | static void process_register(symbol_t **p_symbol); | ||
96 | static void format_1_instr(int opcode, symbol_ref_t *dest, | ||
97 | expression_t *immed, symbol_ref_t *src, int ret); | ||
98 | static void format_2_instr(int opcode, symbol_ref_t *dest, | ||
99 | expression_t *places, symbol_ref_t *src, int ret); | ||
100 | static void format_3_instr(int opcode, symbol_ref_t *src, | ||
101 | expression_t *immed, symbol_ref_t *address); | ||
102 | static void test_readable_symbol(symbol_t *symbol); | ||
103 | static void test_writable_symbol(symbol_t *symbol); | ||
104 | static void type_check(symbol_t *symbol, expression_t *expression, int and_op); | ||
105 | static void make_expression(expression_t *immed, int value); | ||
106 | static void add_conditional(symbol_t *symbol); | ||
107 | static void add_version(const char *verstring); | ||
108 | static int is_download_const(expression_t *immed); | ||
109 | |||
110 | #define SRAM_SYMNAME "SRAM_BASE" | ||
111 | #define SCB_SYMNAME "SCB_BASE" | ||
112 | %} | ||
113 | |||
114 | %union { | ||
115 | u_int value; | ||
116 | char *str; | ||
117 | symbol_t *sym; | ||
118 | symbol_ref_t sym_ref; | ||
119 | expression_t expression; | ||
120 | } | ||
121 | |||
122 | %token T_REGISTER | ||
123 | |||
124 | %token <value> T_CONST | ||
125 | |||
126 | %token T_EXPORT | ||
127 | |||
128 | %token T_DOWNLOAD | ||
129 | |||
130 | %token T_SCB | ||
131 | |||
132 | %token T_SRAM | ||
133 | |||
134 | %token T_ALIAS | ||
135 | |||
136 | %token T_SIZE | ||
137 | |||
138 | %token T_EXPR_LSHIFT | ||
139 | |||
140 | %token T_EXPR_RSHIFT | ||
141 | |||
142 | %token <value> T_ADDRESS | ||
143 | |||
144 | %token T_ACCESS_MODE | ||
145 | |||
146 | %token T_MODES | ||
147 | |||
148 | %token T_DEFINE | ||
149 | |||
150 | %token T_SET_SRC_MODE | ||
151 | |||
152 | %token T_SET_DST_MODE | ||
153 | |||
154 | %token <value> T_MODE | ||
155 | |||
156 | %token T_BEGIN_CS | ||
157 | |||
158 | %token T_END_CS | ||
159 | |||
160 | %token T_FIELD | ||
161 | |||
162 | %token T_ENUM | ||
163 | |||
164 | %token T_MASK | ||
165 | |||
166 | %token <value> T_NUMBER | ||
167 | |||
168 | %token <str> T_PATH T_STRING T_ARG T_MACROBODY | ||
169 | |||
170 | %token <sym> T_CEXPR | ||
171 | |||
172 | %token T_EOF T_INCLUDE T_VERSION T_PREFIX T_PATCH_ARG_LIST | ||
173 | |||
174 | %token <value> T_SHR T_SHL T_ROR T_ROL | ||
175 | |||
176 | %token <value> T_MVI T_MOV T_CLR T_BMOV | ||
177 | |||
178 | %token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL | ||
179 | |||
180 | %token <value> T_ADD T_ADC | ||
181 | |||
182 | %token <value> T_INC T_DEC | ||
183 | |||
184 | %token <value> T_STC T_CLC | ||
185 | |||
186 | %token <value> T_CMP T_NOT T_XOR | ||
187 | |||
188 | %token <value> T_TEST T_AND | ||
189 | |||
190 | %token <value> T_OR | ||
191 | |||
192 | %token T_RET | ||
193 | |||
194 | %token T_NOP | ||
195 | |||
196 | %token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX T_MODE_PTR | ||
197 | |||
198 | %token T_A | ||
199 | |||
200 | %token <sym> T_SYMBOL | ||
201 | |||
202 | %token T_NL | ||
203 | |||
204 | %token T_IF T_ELSE T_ELSE_IF T_ENDIF | ||
205 | |||
206 | %type <sym_ref> reg_symbol address destination source opt_source | ||
207 | |||
208 | %type <expression> expression immediate immediate_or_a | ||
209 | |||
210 | %type <value> export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne | ||
211 | |||
212 | %type <value> mode_value mode_list macro_arglist | ||
213 | |||
214 | %left '|' | ||
215 | %left '&' | ||
216 | %left T_EXPR_LSHIFT T_EXPR_RSHIFT | ||
217 | %left '+' '-' | ||
218 | %left '*' '/' | ||
219 | %right '~' | ||
220 | %nonassoc UMINUS | ||
221 | %% | ||
222 | |||
223 | program: | ||
224 | include | ||
225 | | program include | ||
226 | | prefix | ||
227 | | program prefix | ||
228 | | patch_arg_list | ||
229 | | program patch_arg_list | ||
230 | | version | ||
231 | | program version | ||
232 | | register | ||
233 | | program register | ||
234 | | constant | ||
235 | | program constant | ||
236 | | macrodefn | ||
237 | | program macrodefn | ||
238 | | scratch_ram | ||
239 | | program scratch_ram | ||
240 | | scb | ||
241 | | program scb | ||
242 | | label | ||
243 | | program label | ||
244 | | set_src_mode | ||
245 | | program set_src_mode | ||
246 | | set_dst_mode | ||
247 | | program set_dst_mode | ||
248 | | critical_section_start | ||
249 | | program critical_section_start | ||
250 | | critical_section_end | ||
251 | | program critical_section_end | ||
252 | | conditional | ||
253 | | program conditional | ||
254 | | code | ||
255 | | program code | ||
256 | ; | ||
257 | |||
258 | include: | ||
259 | T_INCLUDE '<' T_PATH '>' | ||
260 | { | ||
261 | include_file($3, BRACKETED_INCLUDE); | ||
262 | } | ||
263 | | T_INCLUDE '"' T_PATH '"' | ||
264 | { | ||
265 | include_file($3, QUOTED_INCLUDE); | ||
266 | } | ||
267 | ; | ||
268 | |||
269 | prefix: | ||
270 | T_PREFIX '=' T_STRING | ||
271 | { | ||
272 | if (prefix != stock_prefix) | ||
273 | stop("Prefix multiply defined", | ||
274 | EX_DATAERR); | ||
275 | prefix = strdup($3); | ||
276 | if (prefix == NULL) | ||
277 | stop("Unable to record prefix", EX_SOFTWARE); | ||
278 | } | ||
279 | ; | ||
280 | |||
281 | patch_arg_list: | ||
282 | T_PATCH_ARG_LIST '=' T_STRING | ||
283 | { | ||
284 | if (patch_arg_list != NULL) | ||
285 | stop("Patch argument list multiply defined", | ||
286 | EX_DATAERR); | ||
287 | patch_arg_list = strdup($3); | ||
288 | if (patch_arg_list == NULL) | ||
289 | stop("Unable to record patch arg list", EX_SOFTWARE); | ||
290 | } | ||
291 | ; | ||
292 | |||
293 | version: | ||
294 | T_VERSION '=' T_STRING | ||
295 | { add_version($3); } | ||
296 | ; | ||
297 | |||
298 | register: | ||
299 | T_REGISTER { cur_symtype = REGISTER; } reg_definition | ||
300 | ; | ||
301 | |||
302 | reg_definition: | ||
303 | T_SYMBOL '{' | ||
304 | { | ||
305 | if ($1->type != UNINITIALIZED) { | ||
306 | stop("Register multiply defined", EX_DATAERR); | ||
307 | /* NOTREACHED */ | ||
308 | } | ||
309 | cur_symbol = $1; | ||
310 | cur_symbol->type = cur_symtype; | ||
311 | initialize_symbol(cur_symbol); | ||
312 | } | ||
313 | reg_attribute_list | ||
314 | '}' | ||
315 | { | ||
316 | /* | ||
317 | * Default to allowing everything in for registers | ||
318 | * with no bit or mask definitions. | ||
319 | */ | ||
320 | if (cur_symbol->info.rinfo->valid_bitmask == 0) | ||
321 | cur_symbol->info.rinfo->valid_bitmask = 0xFF; | ||
322 | |||
323 | if (cur_symbol->info.rinfo->size == 0) | ||
324 | cur_symbol->info.rinfo->size = 1; | ||
325 | |||
326 | /* | ||
327 | * This might be useful for registers too. | ||
328 | */ | ||
329 | if (cur_symbol->type != REGISTER) { | ||
330 | if (cur_symbol->info.rinfo->address == 0) | ||
331 | cur_symbol->info.rinfo->address = | ||
332 | sram_or_scb_offset; | ||
333 | sram_or_scb_offset += | ||
334 | cur_symbol->info.rinfo->size; | ||
335 | } | ||
336 | cur_symbol = NULL; | ||
337 | } | ||
338 | ; | ||
339 | |||
340 | reg_attribute_list: | ||
341 | reg_attribute | ||
342 | | reg_attribute_list reg_attribute | ||
343 | ; | ||
344 | |||
345 | reg_attribute: | ||
346 | reg_address | ||
347 | | size | ||
348 | | access_mode | ||
349 | | modes | ||
350 | | field_defn | ||
351 | | enum_defn | ||
352 | | mask_defn | ||
353 | | alias | ||
354 | | accumulator | ||
355 | | mode_pointer | ||
356 | | allones | ||
357 | | allzeros | ||
358 | | none | ||
359 | | sindex | ||
360 | ; | ||
361 | |||
362 | reg_address: | ||
363 | T_ADDRESS T_NUMBER | ||
364 | { | ||
365 | cur_symbol->info.rinfo->address = $2; | ||
366 | } | ||
367 | ; | ||
368 | |||
369 | size: | ||
370 | T_SIZE T_NUMBER | ||
371 | { | ||
372 | cur_symbol->info.rinfo->size = $2; | ||
373 | if (scb_or_sram_symbol != NULL) { | ||
374 | u_int max_addr; | ||
375 | u_int sym_max_addr; | ||
376 | |||
377 | max_addr = scb_or_sram_symbol->info.rinfo->address | ||
378 | + scb_or_sram_symbol->info.rinfo->size; | ||
379 | sym_max_addr = cur_symbol->info.rinfo->address | ||
380 | + cur_symbol->info.rinfo->size; | ||
381 | |||
382 | if (sym_max_addr > max_addr) | ||
383 | stop("SCB or SRAM space exhausted", EX_DATAERR); | ||
384 | } | ||
385 | } | ||
386 | ; | ||
387 | |||
388 | access_mode: | ||
389 | T_ACCESS_MODE T_MODE | ||
390 | { | ||
391 | cur_symbol->info.rinfo->mode = $2; | ||
392 | } | ||
393 | ; | ||
394 | |||
395 | modes: | ||
396 | T_MODES mode_list | ||
397 | { | ||
398 | cur_symbol->info.rinfo->modes = $2; | ||
399 | } | ||
400 | ; | ||
401 | |||
402 | mode_list: | ||
403 | mode_value | ||
404 | { | ||
405 | $$ = $1; | ||
406 | } | ||
407 | | mode_list ',' mode_value | ||
408 | { | ||
409 | $$ = $1 | $3; | ||
410 | } | ||
411 | ; | ||
412 | |||
413 | mode_value: | ||
414 | T_NUMBER | ||
415 | { | ||
416 | if ($1 > 4) { | ||
417 | stop("Valid register modes range between 0 and 4.", | ||
418 | EX_DATAERR); | ||
419 | /* NOTREACHED */ | ||
420 | } | ||
421 | |||
422 | $$ = (0x1 << $1); | ||
423 | } | ||
424 | | T_SYMBOL | ||
425 | { | ||
426 | symbol_t *symbol; | ||
427 | |||
428 | symbol = $1; | ||
429 | if (symbol->type != CONST) { | ||
430 | stop("Only \"const\" symbols allowed in " | ||
431 | "mode definitions.", EX_DATAERR); | ||
432 | /* NOTREACHED */ | ||
433 | } | ||
434 | if (symbol->info.cinfo->value > 4) { | ||
435 | stop("Valid register modes range between 0 and 4.", | ||
436 | EX_DATAERR); | ||
437 | /* NOTREACHED */ | ||
438 | } | ||
439 | $$ = (0x1 << symbol->info.cinfo->value); | ||
440 | } | ||
441 | ; | ||
442 | |||
443 | field_defn: | ||
444 | T_FIELD | ||
445 | { | ||
446 | field_symbol = NULL; | ||
447 | enum_next_value = 0; | ||
448 | enum_increment = 1; | ||
449 | } | ||
450 | '{' enum_entry_list '}' | ||
451 | | T_FIELD T_SYMBOL expression | ||
452 | { | ||
453 | process_field(FIELD, $2, $3.value); | ||
454 | field_symbol = $2; | ||
455 | enum_next_value = 0; | ||
456 | enum_increment = 0x01 << (ffs($3.value) - 1); | ||
457 | } | ||
458 | '{' enum_entry_list '}' | ||
459 | | T_FIELD T_SYMBOL expression | ||
460 | { | ||
461 | process_field(FIELD, $2, $3.value); | ||
462 | } | ||
463 | ; | ||
464 | |||
465 | enum_defn: | ||
466 | T_ENUM | ||
467 | { | ||
468 | field_symbol = NULL; | ||
469 | enum_next_value = 0; | ||
470 | enum_increment = 1; | ||
471 | } | ||
472 | '{' enum_entry_list '}' | ||
473 | | T_ENUM T_SYMBOL expression | ||
474 | { | ||
475 | process_field(ENUM, $2, $3.value); | ||
476 | field_symbol = $2; | ||
477 | enum_next_value = 0; | ||
478 | enum_increment = 0x01 << (ffs($3.value) - 1); | ||
479 | } | ||
480 | '{' enum_entry_list '}' | ||
481 | ; | ||
482 | |||
483 | enum_entry_list: | ||
484 | enum_entry | ||
485 | | enum_entry_list ',' enum_entry | ||
486 | ; | ||
487 | |||
488 | enum_entry: | ||
489 | T_SYMBOL | ||
490 | { | ||
491 | process_field(ENUM_ENTRY, $1, enum_next_value); | ||
492 | enum_next_value += enum_increment; | ||
493 | } | ||
494 | | T_SYMBOL expression | ||
495 | { | ||
496 | process_field(ENUM_ENTRY, $1, $2.value); | ||
497 | enum_next_value = $2.value + enum_increment; | ||
498 | } | ||
499 | ; | ||
500 | |||
501 | mask_defn: | ||
502 | T_MASK T_SYMBOL expression | ||
503 | { | ||
504 | process_field(MASK, $2, $3.value); | ||
505 | } | ||
506 | ; | ||
507 | |||
508 | alias: | ||
509 | T_ALIAS T_SYMBOL | ||
510 | { | ||
511 | if ($2->type != UNINITIALIZED) { | ||
512 | stop("Re-definition of register alias", | ||
513 | EX_DATAERR); | ||
514 | /* NOTREACHED */ | ||
515 | } | ||
516 | $2->type = ALIAS; | ||
517 | initialize_symbol($2); | ||
518 | $2->info.ainfo->parent = cur_symbol; | ||
519 | } | ||
520 | ; | ||
521 | |||
522 | accumulator: | ||
523 | T_ACCUM | ||
524 | { | ||
525 | if (accumulator.symbol != NULL) { | ||
526 | stop("Only one accumulator definition allowed", | ||
527 | EX_DATAERR); | ||
528 | /* NOTREACHED */ | ||
529 | } | ||
530 | accumulator.symbol = cur_symbol; | ||
531 | } | ||
532 | ; | ||
533 | |||
534 | mode_pointer: | ||
535 | T_MODE_PTR | ||
536 | { | ||
537 | if (mode_ptr.symbol != NULL) { | ||
538 | stop("Only one mode pointer definition allowed", | ||
539 | EX_DATAERR); | ||
540 | /* NOTREACHED */ | ||
541 | } | ||
542 | mode_ptr.symbol = cur_symbol; | ||
543 | } | ||
544 | ; | ||
545 | |||
546 | allones: | ||
547 | T_ALLONES | ||
548 | { | ||
549 | if (allones.symbol != NULL) { | ||
550 | stop("Only one definition of allones allowed", | ||
551 | EX_DATAERR); | ||
552 | /* NOTREACHED */ | ||
553 | } | ||
554 | allones.symbol = cur_symbol; | ||
555 | } | ||
556 | ; | ||
557 | |||
558 | allzeros: | ||
559 | T_ALLZEROS | ||
560 | { | ||
561 | if (allzeros.symbol != NULL) { | ||
562 | stop("Only one definition of allzeros allowed", | ||
563 | EX_DATAERR); | ||
564 | /* NOTREACHED */ | ||
565 | } | ||
566 | allzeros.symbol = cur_symbol; | ||
567 | } | ||
568 | ; | ||
569 | |||
570 | none: | ||
571 | T_NONE | ||
572 | { | ||
573 | if (none.symbol != NULL) { | ||
574 | stop("Only one definition of none allowed", | ||
575 | EX_DATAERR); | ||
576 | /* NOTREACHED */ | ||
577 | } | ||
578 | none.symbol = cur_symbol; | ||
579 | } | ||
580 | ; | ||
581 | |||
582 | sindex: | ||
583 | T_SINDEX | ||
584 | { | ||
585 | if (sindex.symbol != NULL) { | ||
586 | stop("Only one definition of sindex allowed", | ||
587 | EX_DATAERR); | ||
588 | /* NOTREACHED */ | ||
589 | } | ||
590 | sindex.symbol = cur_symbol; | ||
591 | } | ||
592 | ; | ||
593 | |||
594 | expression: | ||
595 | expression '|' expression | ||
596 | { | ||
597 | $$.value = $1.value | $3.value; | ||
598 | symlist_merge(&$$.referenced_syms, | ||
599 | &$1.referenced_syms, | ||
600 | &$3.referenced_syms); | ||
601 | } | ||
602 | | expression '&' expression | ||
603 | { | ||
604 | $$.value = $1.value & $3.value; | ||
605 | symlist_merge(&$$.referenced_syms, | ||
606 | &$1.referenced_syms, | ||
607 | &$3.referenced_syms); | ||
608 | } | ||
609 | | expression '+' expression | ||
610 | { | ||
611 | $$.value = $1.value + $3.value; | ||
612 | symlist_merge(&$$.referenced_syms, | ||
613 | &$1.referenced_syms, | ||
614 | &$3.referenced_syms); | ||
615 | } | ||
616 | | expression '-' expression | ||
617 | { | ||
618 | $$.value = $1.value - $3.value; | ||
619 | symlist_merge(&($$.referenced_syms), | ||
620 | &($1.referenced_syms), | ||
621 | &($3.referenced_syms)); | ||
622 | } | ||
623 | | expression '*' expression | ||
624 | { | ||
625 | $$.value = $1.value * $3.value; | ||
626 | symlist_merge(&($$.referenced_syms), | ||
627 | &($1.referenced_syms), | ||
628 | &($3.referenced_syms)); | ||
629 | } | ||
630 | | expression '/' expression | ||
631 | { | ||
632 | $$.value = $1.value / $3.value; | ||
633 | symlist_merge(&($$.referenced_syms), | ||
634 | &($1.referenced_syms), | ||
635 | &($3.referenced_syms)); | ||
636 | } | ||
637 | | expression T_EXPR_LSHIFT expression | ||
638 | { | ||
639 | $$.value = $1.value << $3.value; | ||
640 | symlist_merge(&$$.referenced_syms, | ||
641 | &$1.referenced_syms, | ||
642 | &$3.referenced_syms); | ||
643 | } | ||
644 | | expression T_EXPR_RSHIFT expression | ||
645 | { | ||
646 | $$.value = $1.value >> $3.value; | ||
647 | symlist_merge(&$$.referenced_syms, | ||
648 | &$1.referenced_syms, | ||
649 | &$3.referenced_syms); | ||
650 | } | ||
651 | | '(' expression ')' | ||
652 | { | ||
653 | $$ = $2; | ||
654 | } | ||
655 | | '~' expression | ||
656 | { | ||
657 | $$ = $2; | ||
658 | $$.value = (~$$.value) & 0xFF; | ||
659 | } | ||
660 | | '-' expression %prec UMINUS | ||
661 | { | ||
662 | $$ = $2; | ||
663 | $$.value = -$$.value; | ||
664 | } | ||
665 | | T_NUMBER | ||
666 | { | ||
667 | $$.value = $1; | ||
668 | SLIST_INIT(&$$.referenced_syms); | ||
669 | } | ||
670 | | T_SYMBOL | ||
671 | { | ||
672 | symbol_t *symbol; | ||
673 | |||
674 | symbol = $1; | ||
675 | switch (symbol->type) { | ||
676 | case ALIAS: | ||
677 | symbol = $1->info.ainfo->parent; | ||
678 | case REGISTER: | ||
679 | case SCBLOC: | ||
680 | case SRAMLOC: | ||
681 | $$.value = symbol->info.rinfo->address; | ||
682 | break; | ||
683 | case MASK: | ||
684 | case FIELD: | ||
685 | case ENUM: | ||
686 | case ENUM_ENTRY: | ||
687 | $$.value = symbol->info.finfo->value; | ||
688 | break; | ||
689 | case DOWNLOAD_CONST: | ||
690 | case CONST: | ||
691 | $$.value = symbol->info.cinfo->value; | ||
692 | break; | ||
693 | case UNINITIALIZED: | ||
694 | default: | ||
695 | { | ||
696 | snprintf(errbuf, sizeof(errbuf), | ||
697 | "Undefined symbol %s referenced", | ||
698 | symbol->name); | ||
699 | stop(errbuf, EX_DATAERR); | ||
700 | /* NOTREACHED */ | ||
701 | break; | ||
702 | } | ||
703 | } | ||
704 | SLIST_INIT(&$$.referenced_syms); | ||
705 | symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD); | ||
706 | } | ||
707 | ; | ||
708 | |||
709 | constant: | ||
710 | T_CONST T_SYMBOL expression | ||
711 | { | ||
712 | if ($2->type != UNINITIALIZED) { | ||
713 | stop("Re-definition of symbol as a constant", | ||
714 | EX_DATAERR); | ||
715 | /* NOTREACHED */ | ||
716 | } | ||
717 | $2->type = CONST; | ||
718 | initialize_symbol($2); | ||
719 | $2->info.cinfo->value = $3.value; | ||
720 | } | ||
721 | | T_CONST T_SYMBOL T_DOWNLOAD | ||
722 | { | ||
723 | if ($1) { | ||
724 | stop("Invalid downloaded constant declaration", | ||
725 | EX_DATAERR); | ||
726 | /* NOTREACHED */ | ||
727 | } | ||
728 | if ($2->type != UNINITIALIZED) { | ||
729 | stop("Re-definition of symbol as a downloaded constant", | ||
730 | EX_DATAERR); | ||
731 | /* NOTREACHED */ | ||
732 | } | ||
733 | $2->type = DOWNLOAD_CONST; | ||
734 | initialize_symbol($2); | ||
735 | $2->info.cinfo->value = download_constant_count++; | ||
736 | } | ||
737 | ; | ||
738 | |||
739 | macrodefn_prologue: | ||
740 | T_DEFINE T_SYMBOL | ||
741 | { | ||
742 | if ($2->type != UNINITIALIZED) { | ||
743 | stop("Re-definition of symbol as a macro", | ||
744 | EX_DATAERR); | ||
745 | /* NOTREACHED */ | ||
746 | } | ||
747 | cur_symbol = $2; | ||
748 | cur_symbol->type = MACRO; | ||
749 | initialize_symbol(cur_symbol); | ||
750 | } | ||
751 | ; | ||
752 | |||
753 | macrodefn: | ||
754 | macrodefn_prologue T_MACROBODY | ||
755 | { | ||
756 | add_macro_body($2); | ||
757 | } | ||
758 | | macrodefn_prologue '(' macro_arglist ')' T_MACROBODY | ||
759 | { | ||
760 | add_macro_body($5); | ||
761 | cur_symbol->info.macroinfo->narg = $3; | ||
762 | } | ||
763 | ; | ||
764 | |||
765 | macro_arglist: | ||
766 | { | ||
767 | /* Macros can take no arguments */ | ||
768 | $$ = 0; | ||
769 | } | ||
770 | | T_ARG | ||
771 | { | ||
772 | $$ = 1; | ||
773 | add_macro_arg($1, 0); | ||
774 | } | ||
775 | | macro_arglist ',' T_ARG | ||
776 | { | ||
777 | if ($1 == 0) { | ||
778 | stop("Comma without preceeding argument in arg list", | ||
779 | EX_DATAERR); | ||
780 | /* NOTREACHED */ | ||
781 | } | ||
782 | $$ = $1 + 1; | ||
783 | add_macro_arg($3, $1); | ||
784 | } | ||
785 | ; | ||
786 | |||
787 | scratch_ram: | ||
788 | T_SRAM '{' | ||
789 | { | ||
790 | snprintf(errbuf, sizeof(errbuf), "%s%d", SRAM_SYMNAME, | ||
791 | num_srams); | ||
792 | cur_symbol = symtable_get(SRAM_SYMNAME); | ||
793 | cur_symtype = SRAMLOC; | ||
794 | cur_symbol->type = SRAMLOC; | ||
795 | initialize_symbol(cur_symbol); | ||
796 | } | ||
797 | reg_address | ||
798 | { | ||
799 | sram_or_scb_offset = cur_symbol->info.rinfo->address; | ||
800 | } | ||
801 | size | ||
802 | { | ||
803 | scb_or_sram_symbol = cur_symbol; | ||
804 | } | ||
805 | scb_or_sram_attributes | ||
806 | '}' | ||
807 | { | ||
808 | cur_symbol = NULL; | ||
809 | scb_or_sram_symbol = NULL; | ||
810 | } | ||
811 | ; | ||
812 | |||
813 | scb: | ||
814 | T_SCB '{' | ||
815 | { | ||
816 | cur_symbol = symtable_get(SCB_SYMNAME); | ||
817 | cur_symtype = SCBLOC; | ||
818 | if (cur_symbol->type != UNINITIALIZED) { | ||
819 | stop("Only one SRAM definition allowed", | ||
820 | EX_SOFTWARE); | ||
821 | /* NOTREACHED */ | ||
822 | } | ||
823 | cur_symbol->type = SCBLOC; | ||
824 | initialize_symbol(cur_symbol); | ||
825 | /* 64 bytes of SCB space */ | ||
826 | cur_symbol->info.rinfo->size = 64; | ||
827 | } | ||
828 | reg_address | ||
829 | { | ||
830 | sram_or_scb_offset = cur_symbol->info.rinfo->address; | ||
831 | } | ||
832 | size | ||
833 | { | ||
834 | scb_or_sram_symbol = cur_symbol; | ||
835 | } | ||
836 | scb_or_sram_attributes | ||
837 | '}' | ||
838 | { | ||
839 | cur_symbol = NULL; | ||
840 | scb_or_sram_symbol = NULL; | ||
841 | } | ||
842 | ; | ||
843 | |||
844 | scb_or_sram_attributes: | ||
845 | /* NULL definition is okay */ | ||
846 | | modes | ||
847 | | scb_or_sram_reg_list | ||
848 | | modes scb_or_sram_reg_list | ||
849 | ; | ||
850 | |||
851 | scb_or_sram_reg_list: | ||
852 | reg_definition | ||
853 | | scb_or_sram_reg_list reg_definition | ||
854 | ; | ||
855 | |||
856 | reg_symbol: | ||
857 | T_SYMBOL | ||
858 | { | ||
859 | process_register(&$1); | ||
860 | $$.symbol = $1; | ||
861 | $$.offset = 0; | ||
862 | } | ||
863 | | T_SYMBOL '[' T_SYMBOL ']' | ||
864 | { | ||
865 | process_register(&$1); | ||
866 | if ($3->type != CONST) { | ||
867 | stop("register offset must be a constant", EX_DATAERR); | ||
868 | /* NOTREACHED */ | ||
869 | } | ||
870 | if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) { | ||
871 | stop("Accessing offset beyond range of register", | ||
872 | EX_DATAERR); | ||
873 | /* NOTREACHED */ | ||
874 | } | ||
875 | $$.symbol = $1; | ||
876 | $$.offset = $3->info.cinfo->value; | ||
877 | } | ||
878 | | T_SYMBOL '[' T_NUMBER ']' | ||
879 | { | ||
880 | process_register(&$1); | ||
881 | if (($3 + 1) > $1->info.rinfo->size) { | ||
882 | stop("Accessing offset beyond range of register", | ||
883 | EX_DATAERR); | ||
884 | /* NOTREACHED */ | ||
885 | } | ||
886 | $$.symbol = $1; | ||
887 | $$.offset = $3; | ||
888 | } | ||
889 | | T_A | ||
890 | { | ||
891 | if (accumulator.symbol == NULL) { | ||
892 | stop("No accumulator has been defined", EX_DATAERR); | ||
893 | /* NOTREACHED */ | ||
894 | } | ||
895 | $$.symbol = accumulator.symbol; | ||
896 | $$.offset = 0; | ||
897 | } | ||
898 | ; | ||
899 | |||
900 | destination: | ||
901 | reg_symbol | ||
902 | { | ||
903 | test_writable_symbol($1.symbol); | ||
904 | $$ = $1; | ||
905 | } | ||
906 | ; | ||
907 | |||
908 | immediate: | ||
909 | expression | ||
910 | { $$ = $1; } | ||
911 | ; | ||
912 | |||
913 | immediate_or_a: | ||
914 | expression | ||
915 | { | ||
916 | if ($1.value == 0 && is_download_const(&$1) == 0) { | ||
917 | snprintf(errbuf, sizeof(errbuf), | ||
918 | "\nExpression evaluates to 0 and thus " | ||
919 | "references the accumulator.\n " | ||
920 | "If this is the desired effect, use 'A' " | ||
921 | "instead.\n"); | ||
922 | stop(errbuf, EX_DATAERR); | ||
923 | } | ||
924 | $$ = $1; | ||
925 | } | ||
926 | | T_A | ||
927 | { | ||
928 | SLIST_INIT(&$$.referenced_syms); | ||
929 | symlist_add(&$$.referenced_syms, accumulator.symbol, | ||
930 | SYMLIST_INSERT_HEAD); | ||
931 | $$.value = 0; | ||
932 | } | ||
933 | ; | ||
934 | |||
935 | source: | ||
936 | reg_symbol | ||
937 | { | ||
938 | test_readable_symbol($1.symbol); | ||
939 | $$ = $1; | ||
940 | } | ||
941 | ; | ||
942 | |||
943 | opt_source: | ||
944 | { | ||
945 | $$.symbol = NULL; | ||
946 | $$.offset = 0; | ||
947 | } | ||
948 | | ',' source | ||
949 | { $$ = $2; } | ||
950 | ; | ||
951 | |||
952 | ret: | ||
953 | { $$ = 0; } | ||
954 | | T_RET | ||
955 | { $$ = 1; } | ||
956 | ; | ||
957 | |||
958 | set_src_mode: | ||
959 | T_SET_SRC_MODE T_NUMBER ';' | ||
960 | { | ||
961 | src_mode = $2; | ||
962 | } | ||
963 | ; | ||
964 | |||
965 | set_dst_mode: | ||
966 | T_SET_DST_MODE T_NUMBER ';' | ||
967 | { | ||
968 | dst_mode = $2; | ||
969 | } | ||
970 | ; | ||
971 | |||
972 | critical_section_start: | ||
973 | T_BEGIN_CS ';' | ||
974 | { | ||
975 | critical_section_t *cs; | ||
976 | |||
977 | if (in_critical_section != FALSE) { | ||
978 | stop("Critical Section within Critical Section", | ||
979 | EX_DATAERR); | ||
980 | /* NOTREACHED */ | ||
981 | } | ||
982 | cs = cs_alloc(); | ||
983 | cs->begin_addr = instruction_ptr; | ||
984 | in_critical_section = TRUE; | ||
985 | } | ||
986 | ; | ||
987 | |||
988 | critical_section_end: | ||
989 | T_END_CS ';' | ||
990 | { | ||
991 | critical_section_t *cs; | ||
992 | |||
993 | if (in_critical_section == FALSE) { | ||
994 | stop("Unballanced 'end_cs'", EX_DATAERR); | ||
995 | /* NOTREACHED */ | ||
996 | } | ||
997 | cs = TAILQ_LAST(&cs_tailq, cs_tailq); | ||
998 | cs->end_addr = instruction_ptr; | ||
999 | in_critical_section = FALSE; | ||
1000 | } | ||
1001 | ; | ||
1002 | |||
1003 | export: | ||
1004 | { $$ = 0; } | ||
1005 | | T_EXPORT | ||
1006 | { $$ = 1; } | ||
1007 | ; | ||
1008 | |||
1009 | label: | ||
1010 | export T_SYMBOL ':' | ||
1011 | { | ||
1012 | if ($2->type != UNINITIALIZED) { | ||
1013 | stop("Program label multiply defined", EX_DATAERR); | ||
1014 | /* NOTREACHED */ | ||
1015 | } | ||
1016 | $2->type = LABEL; | ||
1017 | initialize_symbol($2); | ||
1018 | $2->info.linfo->address = instruction_ptr; | ||
1019 | $2->info.linfo->exported = $1; | ||
1020 | } | ||
1021 | ; | ||
1022 | |||
1023 | address: | ||
1024 | T_SYMBOL | ||
1025 | { | ||
1026 | $$.symbol = $1; | ||
1027 | $$.offset = 0; | ||
1028 | } | ||
1029 | | T_SYMBOL '+' T_NUMBER | ||
1030 | { | ||
1031 | $$.symbol = $1; | ||
1032 | $$.offset = $3; | ||
1033 | } | ||
1034 | | T_SYMBOL '-' T_NUMBER | ||
1035 | { | ||
1036 | $$.symbol = $1; | ||
1037 | $$.offset = -$3; | ||
1038 | } | ||
1039 | | '.' | ||
1040 | { | ||
1041 | $$.symbol = NULL; | ||
1042 | $$.offset = 0; | ||
1043 | } | ||
1044 | | '.' '+' T_NUMBER | ||
1045 | { | ||
1046 | $$.symbol = NULL; | ||
1047 | $$.offset = $3; | ||
1048 | } | ||
1049 | | '.' '-' T_NUMBER | ||
1050 | { | ||
1051 | $$.symbol = NULL; | ||
1052 | $$.offset = -$3; | ||
1053 | } | ||
1054 | ; | ||
1055 | |||
1056 | conditional: | ||
1057 | T_IF T_CEXPR '{' | ||
1058 | { | ||
1059 | scope_t *new_scope; | ||
1060 | |||
1061 | add_conditional($2); | ||
1062 | new_scope = scope_alloc(); | ||
1063 | new_scope->type = SCOPE_IF; | ||
1064 | new_scope->begin_addr = instruction_ptr; | ||
1065 | new_scope->func_num = $2->info.condinfo->func_num; | ||
1066 | } | ||
1067 | | T_ELSE T_IF T_CEXPR '{' | ||
1068 | { | ||
1069 | scope_t *new_scope; | ||
1070 | scope_t *scope_context; | ||
1071 | scope_t *last_scope; | ||
1072 | |||
1073 | /* | ||
1074 | * Ensure that the previous scope is either an | ||
1075 | * if or and else if. | ||
1076 | */ | ||
1077 | scope_context = SLIST_FIRST(&scope_stack); | ||
1078 | last_scope = TAILQ_LAST(&scope_context->inner_scope, | ||
1079 | scope_tailq); | ||
1080 | if (last_scope == NULL | ||
1081 | || last_scope->type == T_ELSE) { | ||
1082 | |||
1083 | stop("'else if' without leading 'if'", EX_DATAERR); | ||
1084 | /* NOTREACHED */ | ||
1085 | } | ||
1086 | add_conditional($3); | ||
1087 | new_scope = scope_alloc(); | ||
1088 | new_scope->type = SCOPE_ELSE_IF; | ||
1089 | new_scope->begin_addr = instruction_ptr; | ||
1090 | new_scope->func_num = $3->info.condinfo->func_num; | ||
1091 | } | ||
1092 | | T_ELSE '{' | ||
1093 | { | ||
1094 | scope_t *new_scope; | ||
1095 | scope_t *scope_context; | ||
1096 | scope_t *last_scope; | ||
1097 | |||
1098 | /* | ||
1099 | * Ensure that the previous scope is either an | ||
1100 | * if or and else if. | ||
1101 | */ | ||
1102 | scope_context = SLIST_FIRST(&scope_stack); | ||
1103 | last_scope = TAILQ_LAST(&scope_context->inner_scope, | ||
1104 | scope_tailq); | ||
1105 | if (last_scope == NULL | ||
1106 | || last_scope->type == SCOPE_ELSE) { | ||
1107 | |||
1108 | stop("'else' without leading 'if'", EX_DATAERR); | ||
1109 | /* NOTREACHED */ | ||
1110 | } | ||
1111 | new_scope = scope_alloc(); | ||
1112 | new_scope->type = SCOPE_ELSE; | ||
1113 | new_scope->begin_addr = instruction_ptr; | ||
1114 | } | ||
1115 | ; | ||
1116 | |||
1117 | conditional: | ||
1118 | '}' | ||
1119 | { | ||
1120 | scope_t *scope_context; | ||
1121 | |||
1122 | scope_context = SLIST_FIRST(&scope_stack); | ||
1123 | if (scope_context->type == SCOPE_ROOT) { | ||
1124 | stop("Unexpected '}' encountered", EX_DATAERR); | ||
1125 | /* NOTREACHED */ | ||
1126 | } | ||
1127 | |||
1128 | scope_context->end_addr = instruction_ptr; | ||
1129 | |||
1130 | /* Pop the scope */ | ||
1131 | SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links); | ||
1132 | |||
1133 | process_scope(scope_context); | ||
1134 | |||
1135 | if (SLIST_FIRST(&scope_stack) == NULL) { | ||
1136 | stop("Unexpected '}' encountered", EX_DATAERR); | ||
1137 | /* NOTREACHED */ | ||
1138 | } | ||
1139 | } | ||
1140 | ; | ||
1141 | |||
1142 | f1_opcode: | ||
1143 | T_AND { $$ = AIC_OP_AND; } | ||
1144 | | T_XOR { $$ = AIC_OP_XOR; } | ||
1145 | | T_ADD { $$ = AIC_OP_ADD; } | ||
1146 | | T_ADC { $$ = AIC_OP_ADC; } | ||
1147 | ; | ||
1148 | |||
1149 | code: | ||
1150 | f1_opcode destination ',' immediate_or_a opt_source ret ';' | ||
1151 | { | ||
1152 | format_1_instr($1, &$2, &$4, &$5, $6); | ||
1153 | } | ||
1154 | ; | ||
1155 | |||
1156 | code: | ||
1157 | T_OR reg_symbol ',' immediate_or_a opt_source ret ';' | ||
1158 | { | ||
1159 | format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6); | ||
1160 | } | ||
1161 | ; | ||
1162 | |||
1163 | code: | ||
1164 | T_INC destination opt_source ret ';' | ||
1165 | { | ||
1166 | expression_t immed; | ||
1167 | |||
1168 | make_expression(&immed, 1); | ||
1169 | format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); | ||
1170 | } | ||
1171 | ; | ||
1172 | |||
1173 | code: | ||
1174 | T_DEC destination opt_source ret ';' | ||
1175 | { | ||
1176 | expression_t immed; | ||
1177 | |||
1178 | make_expression(&immed, -1); | ||
1179 | format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); | ||
1180 | } | ||
1181 | ; | ||
1182 | |||
1183 | code: | ||
1184 | T_CLC ret ';' | ||
1185 | { | ||
1186 | expression_t immed; | ||
1187 | |||
1188 | make_expression(&immed, -1); | ||
1189 | format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2); | ||
1190 | } | ||
1191 | | T_CLC T_MVI destination ',' immediate_or_a ret ';' | ||
1192 | { | ||
1193 | format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6); | ||
1194 | } | ||
1195 | ; | ||
1196 | |||
1197 | code: | ||
1198 | T_STC ret ';' | ||
1199 | { | ||
1200 | expression_t immed; | ||
1201 | |||
1202 | make_expression(&immed, 1); | ||
1203 | format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2); | ||
1204 | } | ||
1205 | | T_STC destination ret ';' | ||
1206 | { | ||
1207 | expression_t immed; | ||
1208 | |||
1209 | make_expression(&immed, 1); | ||
1210 | format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3); | ||
1211 | } | ||
1212 | ; | ||
1213 | |||
1214 | code: | ||
1215 | T_BMOV destination ',' source ',' immediate ret ';' | ||
1216 | { | ||
1217 | format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7); | ||
1218 | } | ||
1219 | ; | ||
1220 | |||
1221 | code: | ||
1222 | T_MOV destination ',' source ret ';' | ||
1223 | { | ||
1224 | expression_t immed; | ||
1225 | |||
1226 | make_expression(&immed, 1); | ||
1227 | format_1_instr(AIC_OP_BMOV, &$2, &immed, &$4, $5); | ||
1228 | } | ||
1229 | ; | ||
1230 | |||
1231 | code: | ||
1232 | T_MVI destination ',' immediate ret ';' | ||
1233 | { | ||
1234 | if ($4.value == 0 | ||
1235 | && is_download_const(&$4) == 0) { | ||
1236 | expression_t immed; | ||
1237 | |||
1238 | /* | ||
1239 | * Allow move immediates of 0 so that macros, | ||
1240 | * that can't know the immediate's value and | ||
1241 | * otherwise compensate, still work. | ||
1242 | */ | ||
1243 | make_expression(&immed, 1); | ||
1244 | format_1_instr(AIC_OP_BMOV, &$2, &immed, &allzeros, $5); | ||
1245 | } else { | ||
1246 | format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5); | ||
1247 | } | ||
1248 | } | ||
1249 | ; | ||
1250 | |||
1251 | code: | ||
1252 | T_NOT destination opt_source ret ';' | ||
1253 | { | ||
1254 | expression_t immed; | ||
1255 | |||
1256 | make_expression(&immed, 0xff); | ||
1257 | format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4); | ||
1258 | } | ||
1259 | ; | ||
1260 | |||
1261 | code: | ||
1262 | T_CLR destination ret ';' | ||
1263 | { | ||
1264 | expression_t immed; | ||
1265 | |||
1266 | make_expression(&immed, 0xff); | ||
1267 | format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3); | ||
1268 | } | ||
1269 | ; | ||
1270 | |||
1271 | code: | ||
1272 | T_NOP ret ';' | ||
1273 | { | ||
1274 | expression_t immed; | ||
1275 | |||
1276 | make_expression(&immed, 0xff); | ||
1277 | format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2); | ||
1278 | } | ||
1279 | ; | ||
1280 | |||
1281 | code: | ||
1282 | T_RET ';' | ||
1283 | { | ||
1284 | expression_t immed; | ||
1285 | |||
1286 | make_expression(&immed, 0xff); | ||
1287 | format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE); | ||
1288 | } | ||
1289 | ; | ||
1290 | |||
1291 | /* | ||
1292 | * This grammer differs from the one in the aic7xxx | ||
1293 | * reference manual since the grammer listed there is | ||
1294 | * ambiguous and causes a shift/reduce conflict. | ||
1295 | * It also seems more logical as the "immediate" | ||
1296 | * argument is listed as the second arg like the | ||
1297 | * other formats. | ||
1298 | */ | ||
1299 | |||
1300 | f2_opcode: | ||
1301 | T_SHL { $$ = AIC_OP_SHL; } | ||
1302 | | T_SHR { $$ = AIC_OP_SHR; } | ||
1303 | | T_ROL { $$ = AIC_OP_ROL; } | ||
1304 | | T_ROR { $$ = AIC_OP_ROR; } | ||
1305 | ; | ||
1306 | |||
1307 | code: | ||
1308 | f2_opcode destination ',' expression opt_source ret ';' | ||
1309 | { | ||
1310 | format_2_instr($1, &$2, &$4, &$5, $6); | ||
1311 | } | ||
1312 | ; | ||
1313 | |||
1314 | jmp_jc_jnc_call: | ||
1315 | T_JMP { $$ = AIC_OP_JMP; } | ||
1316 | | T_JC { $$ = AIC_OP_JC; } | ||
1317 | | T_JNC { $$ = AIC_OP_JNC; } | ||
1318 | | T_CALL { $$ = AIC_OP_CALL; } | ||
1319 | ; | ||
1320 | |||
1321 | jz_jnz: | ||
1322 | T_JZ { $$ = AIC_OP_JZ; } | ||
1323 | | T_JNZ { $$ = AIC_OP_JNZ; } | ||
1324 | ; | ||
1325 | |||
1326 | je_jne: | ||
1327 | T_JE { $$ = AIC_OP_JE; } | ||
1328 | | T_JNE { $$ = AIC_OP_JNE; } | ||
1329 | ; | ||
1330 | |||
1331 | code: | ||
1332 | jmp_jc_jnc_call address ';' | ||
1333 | { | ||
1334 | expression_t immed; | ||
1335 | |||
1336 | make_expression(&immed, 0); | ||
1337 | format_3_instr($1, &sindex, &immed, &$2); | ||
1338 | } | ||
1339 | ; | ||
1340 | |||
1341 | code: | ||
1342 | T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';' | ||
1343 | { | ||
1344 | format_3_instr($5, &$2, &$4, &$6); | ||
1345 | } | ||
1346 | ; | ||
1347 | |||
1348 | code: | ||
1349 | T_TEST source ',' immediate_or_a jz_jnz address ';' | ||
1350 | { | ||
1351 | format_3_instr($5, &$2, &$4, &$6); | ||
1352 | } | ||
1353 | ; | ||
1354 | |||
1355 | code: | ||
1356 | T_CMP source ',' immediate_or_a je_jne address ';' | ||
1357 | { | ||
1358 | format_3_instr($5, &$2, &$4, &$6); | ||
1359 | } | ||
1360 | ; | ||
1361 | |||
1362 | code: | ||
1363 | T_MOV source jmp_jc_jnc_call address ';' | ||
1364 | { | ||
1365 | expression_t immed; | ||
1366 | |||
1367 | make_expression(&immed, 0); | ||
1368 | format_3_instr($3, &$2, &immed, &$4); | ||
1369 | } | ||
1370 | ; | ||
1371 | |||
1372 | code: | ||
1373 | T_MVI immediate jmp_jc_jnc_call address ';' | ||
1374 | { | ||
1375 | format_3_instr($3, &allzeros, &$2, &$4); | ||
1376 | } | ||
1377 | ; | ||
1378 | |||
1379 | %% | ||
1380 | |||
1381 | static void | ||
1382 | process_field(int field_type, symbol_t *sym, int value) | ||
1383 | { | ||
1384 | /* | ||
1385 | * Add the current register to its | ||
1386 | * symbol list, if it already exists, | ||
1387 | * warn if we are setting it to a | ||
1388 | * different value, or in the bit to | ||
1389 | * the "allowed bits" of this register. | ||
1390 | */ | ||
1391 | if (sym->type == UNINITIALIZED) { | ||
1392 | sym->type = field_type; | ||
1393 | initialize_symbol(sym); | ||
1394 | sym->info.finfo->value = value; | ||
1395 | if (field_type != ENUM_ENTRY) { | ||
1396 | if (field_type != MASK && value == 0) { | ||
1397 | stop("Empty Field, or Enum", EX_DATAERR); | ||
1398 | /* NOTREACHED */ | ||
1399 | } | ||
1400 | sym->info.finfo->value = value; | ||
1401 | sym->info.finfo->mask = value; | ||
1402 | } else if (field_symbol != NULL) { | ||
1403 | sym->info.finfo->mask = field_symbol->info.finfo->value; | ||
1404 | } else { | ||
1405 | sym->info.finfo->mask = 0xFF; | ||
1406 | } | ||
1407 | } else if (sym->type != field_type) { | ||
1408 | stop("Field definition mirrors a definition of the same " | ||
1409 | " name, but a different type", EX_DATAERR); | ||
1410 | /* NOTREACHED */ | ||
1411 | } else if (value != sym->info.finfo->value) { | ||
1412 | stop("Field redefined with a conflicting value", EX_DATAERR); | ||
1413 | /* NOTREACHED */ | ||
1414 | } | ||
1415 | /* Fail if this symbol is already listed */ | ||
1416 | if (symlist_search(&(sym->info.finfo->symrefs), | ||
1417 | cur_symbol->name) != NULL) { | ||
1418 | stop("Field defined multiple times for register", EX_DATAERR); | ||
1419 | /* NOTREACHED */ | ||
1420 | } | ||
1421 | symlist_add(&(sym->info.finfo->symrefs), cur_symbol, | ||
1422 | SYMLIST_INSERT_HEAD); | ||
1423 | cur_symbol->info.rinfo->valid_bitmask |= sym->info.finfo->mask; | ||
1424 | cur_symbol->info.rinfo->typecheck_masks = TRUE; | ||
1425 | symlist_add(&(cur_symbol->info.rinfo->fields), sym, SYMLIST_SORT); | ||
1426 | } | ||
1427 | |||
1428 | static void | ||
1429 | initialize_symbol(symbol_t *symbol) | ||
1430 | { | ||
1431 | switch (symbol->type) { | ||
1432 | case UNINITIALIZED: | ||
1433 | stop("Call to initialize_symbol with type field unset", | ||
1434 | EX_SOFTWARE); | ||
1435 | /* NOTREACHED */ | ||
1436 | break; | ||
1437 | case REGISTER: | ||
1438 | case SRAMLOC: | ||
1439 | case SCBLOC: | ||
1440 | symbol->info.rinfo = | ||
1441 | (struct reg_info *)malloc(sizeof(struct reg_info)); | ||
1442 | if (symbol->info.rinfo == NULL) { | ||
1443 | stop("Can't create register info", EX_SOFTWARE); | ||
1444 | /* NOTREACHED */ | ||
1445 | } | ||
1446 | memset(symbol->info.rinfo, 0, | ||
1447 | sizeof(struct reg_info)); | ||
1448 | SLIST_INIT(&(symbol->info.rinfo->fields)); | ||
1449 | /* | ||
1450 | * Default to allowing access in all register modes | ||
1451 | * or to the mode specified by the SCB or SRAM space | ||
1452 | * we are in. | ||
1453 | */ | ||
1454 | if (scb_or_sram_symbol != NULL) | ||
1455 | symbol->info.rinfo->modes = | ||
1456 | scb_or_sram_symbol->info.rinfo->modes; | ||
1457 | else | ||
1458 | symbol->info.rinfo->modes = ~0; | ||
1459 | break; | ||
1460 | case ALIAS: | ||
1461 | symbol->info.ainfo = | ||
1462 | (struct alias_info *)malloc(sizeof(struct alias_info)); | ||
1463 | if (symbol->info.ainfo == NULL) { | ||
1464 | stop("Can't create alias info", EX_SOFTWARE); | ||
1465 | /* NOTREACHED */ | ||
1466 | } | ||
1467 | memset(symbol->info.ainfo, 0, | ||
1468 | sizeof(struct alias_info)); | ||
1469 | break; | ||
1470 | case MASK: | ||
1471 | case FIELD: | ||
1472 | case ENUM: | ||
1473 | case ENUM_ENTRY: | ||
1474 | symbol->info.finfo = | ||
1475 | (struct field_info *)malloc(sizeof(struct field_info)); | ||
1476 | if (symbol->info.finfo == NULL) { | ||
1477 | stop("Can't create field info", EX_SOFTWARE); | ||
1478 | /* NOTREACHED */ | ||
1479 | } | ||
1480 | memset(symbol->info.finfo, 0, sizeof(struct field_info)); | ||
1481 | SLIST_INIT(&(symbol->info.finfo->symrefs)); | ||
1482 | break; | ||
1483 | case CONST: | ||
1484 | case DOWNLOAD_CONST: | ||
1485 | symbol->info.cinfo = | ||
1486 | (struct const_info *)malloc(sizeof(struct const_info)); | ||
1487 | if (symbol->info.cinfo == NULL) { | ||
1488 | stop("Can't create alias info", EX_SOFTWARE); | ||
1489 | /* NOTREACHED */ | ||
1490 | } | ||
1491 | memset(symbol->info.cinfo, 0, | ||
1492 | sizeof(struct const_info)); | ||
1493 | break; | ||
1494 | case LABEL: | ||
1495 | symbol->info.linfo = | ||
1496 | (struct label_info *)malloc(sizeof(struct label_info)); | ||
1497 | if (symbol->info.linfo == NULL) { | ||
1498 | stop("Can't create label info", EX_SOFTWARE); | ||
1499 | /* NOTREACHED */ | ||
1500 | } | ||
1501 | memset(symbol->info.linfo, 0, | ||
1502 | sizeof(struct label_info)); | ||
1503 | break; | ||
1504 | case CONDITIONAL: | ||
1505 | symbol->info.condinfo = | ||
1506 | (struct cond_info *)malloc(sizeof(struct cond_info)); | ||
1507 | if (symbol->info.condinfo == NULL) { | ||
1508 | stop("Can't create conditional info", EX_SOFTWARE); | ||
1509 | /* NOTREACHED */ | ||
1510 | } | ||
1511 | memset(symbol->info.condinfo, 0, | ||
1512 | sizeof(struct cond_info)); | ||
1513 | break; | ||
1514 | case MACRO: | ||
1515 | symbol->info.macroinfo = | ||
1516 | (struct macro_info *)malloc(sizeof(struct macro_info)); | ||
1517 | if (symbol->info.macroinfo == NULL) { | ||
1518 | stop("Can't create macro info", EX_SOFTWARE); | ||
1519 | /* NOTREACHED */ | ||
1520 | } | ||
1521 | memset(symbol->info.macroinfo, 0, | ||
1522 | sizeof(struct macro_info)); | ||
1523 | STAILQ_INIT(&symbol->info.macroinfo->args); | ||
1524 | break; | ||
1525 | default: | ||
1526 | stop("Call to initialize_symbol with invalid symbol type", | ||
1527 | EX_SOFTWARE); | ||
1528 | /* NOTREACHED */ | ||
1529 | break; | ||
1530 | } | ||
1531 | } | ||
1532 | |||
1533 | static void | ||
1534 | add_macro_arg(const char *argtext, int argnum) | ||
1535 | { | ||
1536 | struct macro_arg *marg; | ||
1537 | int i; | ||
1538 | int retval; | ||
1539 | |||
1540 | |||
1541 | if (cur_symbol == NULL || cur_symbol->type != MACRO) { | ||
1542 | stop("Invalid current symbol for adding macro arg", | ||
1543 | EX_SOFTWARE); | ||
1544 | /* NOTREACHED */ | ||
1545 | } | ||
1546 | |||
1547 | marg = (struct macro_arg *)malloc(sizeof(*marg)); | ||
1548 | if (marg == NULL) { | ||
1549 | stop("Can't create macro_arg structure", EX_SOFTWARE); | ||
1550 | /* NOTREACHED */ | ||
1551 | } | ||
1552 | marg->replacement_text = NULL; | ||
1553 | retval = snprintf(regex_pattern, sizeof(regex_pattern), | ||
1554 | "[^-/A-Za-z0-9_](%s)([^-/A-Za-z0-9_]|$)", | ||
1555 | argtext); | ||
1556 | if (retval >= sizeof(regex_pattern)) { | ||
1557 | stop("Regex text buffer too small for arg", | ||
1558 | EX_SOFTWARE); | ||
1559 | /* NOTREACHED */ | ||
1560 | } | ||
1561 | retval = regcomp(&marg->arg_regex, regex_pattern, REG_EXTENDED); | ||
1562 | if (retval != 0) { | ||
1563 | stop("Regex compilation failed", EX_SOFTWARE); | ||
1564 | /* NOTREACHED */ | ||
1565 | } | ||
1566 | STAILQ_INSERT_TAIL(&cur_symbol->info.macroinfo->args, marg, links); | ||
1567 | } | ||
1568 | |||
1569 | static void | ||
1570 | add_macro_body(const char *bodytext) | ||
1571 | { | ||
1572 | if (cur_symbol == NULL || cur_symbol->type != MACRO) { | ||
1573 | stop("Invalid current symbol for adding macro arg", | ||
1574 | EX_SOFTWARE); | ||
1575 | /* NOTREACHED */ | ||
1576 | } | ||
1577 | cur_symbol->info.macroinfo->body = strdup(bodytext); | ||
1578 | if (cur_symbol->info.macroinfo->body == NULL) { | ||
1579 | stop("Can't duplicate macro body text", EX_SOFTWARE); | ||
1580 | /* NOTREACHED */ | ||
1581 | } | ||
1582 | } | ||
1583 | |||
1584 | static void | ||
1585 | process_register(symbol_t **p_symbol) | ||
1586 | { | ||
1587 | symbol_t *symbol = *p_symbol; | ||
1588 | |||
1589 | if (symbol->type == UNINITIALIZED) { | ||
1590 | snprintf(errbuf, sizeof(errbuf), "Undefined register %s", | ||
1591 | symbol->name); | ||
1592 | stop(errbuf, EX_DATAERR); | ||
1593 | /* NOTREACHED */ | ||
1594 | } else if (symbol->type == ALIAS) { | ||
1595 | *p_symbol = symbol->info.ainfo->parent; | ||
1596 | } else if ((symbol->type != REGISTER) | ||
1597 | && (symbol->type != SCBLOC) | ||
1598 | && (symbol->type != SRAMLOC)) { | ||
1599 | snprintf(errbuf, sizeof(errbuf), | ||
1600 | "Specified symbol %s is not a register", | ||
1601 | symbol->name); | ||
1602 | stop(errbuf, EX_DATAERR); | ||
1603 | } | ||
1604 | } | ||
1605 | |||
1606 | static void | ||
1607 | format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed, | ||
1608 | symbol_ref_t *src, int ret) | ||
1609 | { | ||
1610 | struct instruction *instr; | ||
1611 | struct ins_format1 *f1_instr; | ||
1612 | |||
1613 | if (src->symbol == NULL) | ||
1614 | src = dest; | ||
1615 | |||
1616 | /* Test register permissions */ | ||
1617 | test_writable_symbol(dest->symbol); | ||
1618 | test_readable_symbol(src->symbol); | ||
1619 | |||
1620 | /* Ensure that immediate makes sense for this destination */ | ||
1621 | type_check(dest->symbol, immed, opcode); | ||
1622 | |||
1623 | /* Allocate sequencer space for the instruction and fill it out */ | ||
1624 | instr = seq_alloc(); | ||
1625 | f1_instr = &instr->format.format1; | ||
1626 | f1_instr->ret = ret ? 1 : 0; | ||
1627 | f1_instr->opcode = opcode; | ||
1628 | f1_instr->destination = dest->symbol->info.rinfo->address | ||
1629 | + dest->offset; | ||
1630 | f1_instr->source = src->symbol->info.rinfo->address | ||
1631 | + src->offset; | ||
1632 | f1_instr->immediate = immed->value; | ||
1633 | |||
1634 | if (is_download_const(immed)) | ||
1635 | f1_instr->parity = 1; | ||
1636 | else if (dest->symbol == mode_ptr.symbol) { | ||
1637 | u_int src_value; | ||
1638 | u_int dst_value; | ||
1639 | |||
1640 | /* | ||
1641 | * Attempt to update mode information if | ||
1642 | * we are operating on the mode register. | ||
1643 | */ | ||
1644 | if (src->symbol == allones.symbol) | ||
1645 | src_value = 0xFF; | ||
1646 | else if (src->symbol == allzeros.symbol) | ||
1647 | src_value = 0; | ||
1648 | else if (src->symbol == mode_ptr.symbol) | ||
1649 | src_value = (dst_mode << 4) | src_mode; | ||
1650 | else | ||
1651 | goto cant_update; | ||
1652 | |||
1653 | switch (opcode) { | ||
1654 | case AIC_OP_AND: | ||
1655 | dst_value = src_value & immed->value; | ||
1656 | break; | ||
1657 | case AIC_OP_XOR: | ||
1658 | dst_value = src_value ^ immed->value; | ||
1659 | break; | ||
1660 | case AIC_OP_ADD: | ||
1661 | dst_value = (src_value + immed->value) & 0xFF; | ||
1662 | break; | ||
1663 | case AIC_OP_OR: | ||
1664 | dst_value = src_value | immed->value; | ||
1665 | break; | ||
1666 | case AIC_OP_BMOV: | ||
1667 | dst_value = src_value; | ||
1668 | break; | ||
1669 | default: | ||
1670 | goto cant_update; | ||
1671 | } | ||
1672 | src_mode = dst_value & 0xF; | ||
1673 | dst_mode = (dst_value >> 4) & 0xF; | ||
1674 | } | ||
1675 | |||
1676 | cant_update: | ||
1677 | symlist_free(&immed->referenced_syms); | ||
1678 | instruction_ptr++; | ||
1679 | } | ||
1680 | |||
1681 | static void | ||
1682 | format_2_instr(int opcode, symbol_ref_t *dest, expression_t *places, | ||
1683 | symbol_ref_t *src, int ret) | ||
1684 | { | ||
1685 | struct instruction *instr; | ||
1686 | struct ins_format2 *f2_instr; | ||
1687 | uint8_t shift_control; | ||
1688 | |||
1689 | if (src->symbol == NULL) | ||
1690 | src = dest; | ||
1691 | |||
1692 | /* Test register permissions */ | ||
1693 | test_writable_symbol(dest->symbol); | ||
1694 | test_readable_symbol(src->symbol); | ||
1695 | |||
1696 | /* Allocate sequencer space for the instruction and fill it out */ | ||
1697 | instr = seq_alloc(); | ||
1698 | f2_instr = &instr->format.format2; | ||
1699 | f2_instr->ret = ret ? 1 : 0; | ||
1700 | f2_instr->opcode = AIC_OP_ROL; | ||
1701 | f2_instr->destination = dest->symbol->info.rinfo->address | ||
1702 | + dest->offset; | ||
1703 | f2_instr->source = src->symbol->info.rinfo->address | ||
1704 | + src->offset; | ||
1705 | if (places->value > 8 || places->value <= 0) { | ||
1706 | stop("illegal shift value", EX_DATAERR); | ||
1707 | /* NOTREACHED */ | ||
1708 | } | ||
1709 | switch (opcode) { | ||
1710 | case AIC_OP_SHL: | ||
1711 | if (places->value == 8) | ||
1712 | shift_control = 0xf0; | ||
1713 | else | ||
1714 | shift_control = (places->value << 4) | places->value; | ||
1715 | break; | ||
1716 | case AIC_OP_SHR: | ||
1717 | if (places->value == 8) { | ||
1718 | shift_control = 0xf8; | ||
1719 | } else { | ||
1720 | shift_control = (places->value << 4) | ||
1721 | | (8 - places->value) | ||
1722 | | 0x08; | ||
1723 | } | ||
1724 | break; | ||
1725 | case AIC_OP_ROL: | ||
1726 | shift_control = places->value & 0x7; | ||
1727 | break; | ||
1728 | case AIC_OP_ROR: | ||
1729 | shift_control = (8 - places->value) | 0x08; | ||
1730 | break; | ||
1731 | default: | ||
1732 | shift_control = 0; /* Quiet Compiler */ | ||
1733 | stop("Invalid shift operation specified", EX_SOFTWARE); | ||
1734 | /* NOTREACHED */ | ||
1735 | break; | ||
1736 | }; | ||
1737 | f2_instr->shift_control = shift_control; | ||
1738 | symlist_free(&places->referenced_syms); | ||
1739 | instruction_ptr++; | ||
1740 | } | ||
1741 | |||
1742 | static void | ||
1743 | format_3_instr(int opcode, symbol_ref_t *src, | ||
1744 | expression_t *immed, symbol_ref_t *address) | ||
1745 | { | ||
1746 | struct instruction *instr; | ||
1747 | struct ins_format3 *f3_instr; | ||
1748 | int addr; | ||
1749 | |||
1750 | /* Test register permissions */ | ||
1751 | test_readable_symbol(src->symbol); | ||
1752 | |||
1753 | /* Ensure that immediate makes sense for this source */ | ||
1754 | type_check(src->symbol, immed, opcode); | ||
1755 | |||
1756 | /* Allocate sequencer space for the instruction and fill it out */ | ||
1757 | instr = seq_alloc(); | ||
1758 | f3_instr = &instr->format.format3; | ||
1759 | if (address->symbol == NULL) { | ||
1760 | /* 'dot' referrence. Use the current instruction pointer */ | ||
1761 | addr = instruction_ptr + address->offset; | ||
1762 | } else if (address->symbol->type == UNINITIALIZED) { | ||
1763 | /* forward reference */ | ||
1764 | addr = address->offset; | ||
1765 | instr->patch_label = address->symbol; | ||
1766 | } else | ||
1767 | addr = address->symbol->info.linfo->address + address->offset; | ||
1768 | f3_instr->opcode = opcode; | ||
1769 | f3_instr->address = addr; | ||
1770 | f3_instr->source = src->symbol->info.rinfo->address | ||
1771 | + src->offset; | ||
1772 | f3_instr->immediate = immed->value; | ||
1773 | |||
1774 | if (is_download_const(immed)) | ||
1775 | f3_instr->parity = 1; | ||
1776 | |||
1777 | symlist_free(&immed->referenced_syms); | ||
1778 | instruction_ptr++; | ||
1779 | } | ||
1780 | |||
1781 | static void | ||
1782 | test_readable_symbol(symbol_t *symbol) | ||
1783 | { | ||
1784 | |||
1785 | if ((symbol->info.rinfo->modes & (0x1 << src_mode)) == 0) { | ||
1786 | snprintf(errbuf, sizeof(errbuf), | ||
1787 | "Register %s unavailable in source reg mode %d", | ||
1788 | symbol->name, src_mode); | ||
1789 | stop(errbuf, EX_DATAERR); | ||
1790 | } | ||
1791 | |||
1792 | if (symbol->info.rinfo->mode == WO) { | ||
1793 | stop("Write Only register specified as source", | ||
1794 | EX_DATAERR); | ||
1795 | /* NOTREACHED */ | ||
1796 | } | ||
1797 | } | ||
1798 | |||
1799 | static void | ||
1800 | test_writable_symbol(symbol_t *symbol) | ||
1801 | { | ||
1802 | |||
1803 | if ((symbol->info.rinfo->modes & (0x1 << dst_mode)) == 0) { | ||
1804 | snprintf(errbuf, sizeof(errbuf), | ||
1805 | "Register %s unavailable in destination reg mode %d", | ||
1806 | symbol->name, dst_mode); | ||
1807 | stop(errbuf, EX_DATAERR); | ||
1808 | } | ||
1809 | |||
1810 | if (symbol->info.rinfo->mode == RO) { | ||
1811 | stop("Read Only register specified as destination", | ||
1812 | EX_DATAERR); | ||
1813 | /* NOTREACHED */ | ||
1814 | } | ||
1815 | } | ||
1816 | |||
1817 | static void | ||
1818 | type_check(symbol_t *symbol, expression_t *expression, int opcode) | ||
1819 | { | ||
1820 | symbol_node_t *node; | ||
1821 | int and_op; | ||
1822 | |||
1823 | and_op = FALSE; | ||
1824 | if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ) | ||
1825 | and_op = TRUE; | ||
1826 | |||
1827 | /* | ||
1828 | * Make sure that we aren't attempting to write something | ||
1829 | * that hasn't been defined. If this is an and operation, | ||
1830 | * this is a mask, so "undefined" bits are okay. | ||
1831 | */ | ||
1832 | if (and_op == FALSE | ||
1833 | && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) { | ||
1834 | snprintf(errbuf, sizeof(errbuf), | ||
1835 | "Invalid bit(s) 0x%x in immediate written to %s", | ||
1836 | expression->value & ~symbol->info.rinfo->valid_bitmask, | ||
1837 | symbol->name); | ||
1838 | stop(errbuf, EX_DATAERR); | ||
1839 | /* NOTREACHED */ | ||
1840 | } | ||
1841 | |||
1842 | /* | ||
1843 | * Now make sure that all of the symbols referenced by the | ||
1844 | * expression are defined for this register. | ||
1845 | */ | ||
1846 | if (symbol->info.rinfo->typecheck_masks != FALSE) { | ||
1847 | for(node = expression->referenced_syms.slh_first; | ||
1848 | node != NULL; | ||
1849 | node = node->links.sle_next) { | ||
1850 | if ((node->symbol->type == MASK | ||
1851 | || node->symbol->type == FIELD | ||
1852 | || node->symbol->type == ENUM | ||
1853 | || node->symbol->type == ENUM_ENTRY) | ||
1854 | && symlist_search(&node->symbol->info.finfo->symrefs, | ||
1855 | symbol->name) == NULL) { | ||
1856 | snprintf(errbuf, sizeof(errbuf), | ||
1857 | "Invalid field or mask %s " | ||
1858 | "for register %s", | ||
1859 | node->symbol->name, symbol->name); | ||
1860 | stop(errbuf, EX_DATAERR); | ||
1861 | /* NOTREACHED */ | ||
1862 | } | ||
1863 | } | ||
1864 | } | ||
1865 | } | ||
1866 | |||
1867 | static void | ||
1868 | make_expression(expression_t *immed, int value) | ||
1869 | { | ||
1870 | SLIST_INIT(&immed->referenced_syms); | ||
1871 | immed->value = value & 0xff; | ||
1872 | } | ||
1873 | |||
1874 | static void | ||
1875 | add_conditional(symbol_t *symbol) | ||
1876 | { | ||
1877 | static int numfuncs; | ||
1878 | |||
1879 | if (numfuncs == 0) { | ||
1880 | /* add a special conditional, "0" */ | ||
1881 | symbol_t *false_func; | ||
1882 | |||
1883 | false_func = symtable_get("0"); | ||
1884 | if (false_func->type != UNINITIALIZED) { | ||
1885 | stop("Conditional expression '0' " | ||
1886 | "conflicts with a symbol", EX_DATAERR); | ||
1887 | /* NOTREACHED */ | ||
1888 | } | ||
1889 | false_func->type = CONDITIONAL; | ||
1890 | initialize_symbol(false_func); | ||
1891 | false_func->info.condinfo->func_num = numfuncs++; | ||
1892 | symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD); | ||
1893 | } | ||
1894 | |||
1895 | /* This condition has occurred before */ | ||
1896 | if (symbol->type == CONDITIONAL) | ||
1897 | return; | ||
1898 | |||
1899 | if (symbol->type != UNINITIALIZED) { | ||
1900 | stop("Conditional expression conflicts with a symbol", | ||
1901 | EX_DATAERR); | ||
1902 | /* NOTREACHED */ | ||
1903 | } | ||
1904 | |||
1905 | symbol->type = CONDITIONAL; | ||
1906 | initialize_symbol(symbol); | ||
1907 | symbol->info.condinfo->func_num = numfuncs++; | ||
1908 | symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD); | ||
1909 | } | ||
1910 | |||
1911 | static void | ||
1912 | add_version(const char *verstring) | ||
1913 | { | ||
1914 | const char prefix[] = " * "; | ||
1915 | int newlen; | ||
1916 | int oldlen; | ||
1917 | |||
1918 | newlen = strlen(verstring) + strlen(prefix); | ||
1919 | oldlen = 0; | ||
1920 | if (versions != NULL) | ||
1921 | oldlen = strlen(versions); | ||
1922 | versions = realloc(versions, newlen + oldlen + 2); | ||
1923 | if (versions == NULL) | ||
1924 | stop("Can't allocate version string", EX_SOFTWARE); | ||
1925 | strcpy(&versions[oldlen], prefix); | ||
1926 | strcpy(&versions[oldlen + strlen(prefix)], verstring); | ||
1927 | versions[newlen + oldlen] = '\n'; | ||
1928 | versions[newlen + oldlen + 1] = '\0'; | ||
1929 | } | ||
1930 | |||
1931 | void | ||
1932 | yyerror(const char *string) | ||
1933 | { | ||
1934 | stop(string, EX_DATAERR); | ||
1935 | } | ||
1936 | |||
1937 | static int | ||
1938 | is_download_const(expression_t *immed) | ||
1939 | { | ||
1940 | if ((immed->referenced_syms.slh_first != NULL) | ||
1941 | && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST)) | ||
1942 | return (TRUE); | ||
1943 | |||
1944 | return (FALSE); | ||
1945 | } | ||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h new file mode 100644 index 000000000000..3e80f07df49c --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * Instruction formats for the sequencer program downloaded to | ||
3 | * Aic7xxx SCSI host adapters | ||
4 | * | ||
5 | * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions, and the following disclaimer, | ||
13 | * without modification. | ||
14 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
15 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
16 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
17 | * including a substantially similar Disclaimer requirement for further | ||
18 | * binary redistribution. | ||
19 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
20 | * of any contributors may be used to endorse or promote products derived | ||
21 | * from this software without specific prior written permission. | ||
22 | * | ||
23 | * Alternatively, this software may be distributed under the terms of the | ||
24 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
25 | * Software Foundation. | ||
26 | * | ||
27 | * NO WARRANTY | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
30 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
31 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
32 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
37 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGES. | ||
39 | * | ||
40 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#11 $ | ||
41 | * | ||
42 | * $FreeBSD$ | ||
43 | */ | ||
44 | |||
45 | struct ins_format1 { | ||
46 | #if BYTE_ORDER == LITTLE_ENDIAN | ||
47 | uint32_t immediate : 8, | ||
48 | source : 9, | ||
49 | destination : 9, | ||
50 | ret : 1, | ||
51 | opcode : 4, | ||
52 | parity : 1; | ||
53 | #else | ||
54 | uint32_t parity : 1, | ||
55 | opcode : 4, | ||
56 | ret : 1, | ||
57 | destination : 9, | ||
58 | source : 9, | ||
59 | immediate : 8; | ||
60 | #endif | ||
61 | }; | ||
62 | |||
63 | struct ins_format2 { | ||
64 | #if BYTE_ORDER == LITTLE_ENDIAN | ||
65 | uint32_t shift_control : 8, | ||
66 | source : 9, | ||
67 | destination : 9, | ||
68 | ret : 1, | ||
69 | opcode : 4, | ||
70 | parity : 1; | ||
71 | #else | ||
72 | uint32_t parity : 1, | ||
73 | opcode : 4, | ||
74 | ret : 1, | ||
75 | destination : 9, | ||
76 | source : 9, | ||
77 | shift_control : 8; | ||
78 | #endif | ||
79 | }; | ||
80 | |||
81 | struct ins_format3 { | ||
82 | #if BYTE_ORDER == LITTLE_ENDIAN | ||
83 | uint32_t immediate : 8, | ||
84 | source : 9, | ||
85 | address : 10, | ||
86 | opcode : 4, | ||
87 | parity : 1; | ||
88 | #else | ||
89 | uint32_t parity : 1, | ||
90 | opcode : 4, | ||
91 | address : 10, | ||
92 | source : 9, | ||
93 | immediate : 8; | ||
94 | #endif | ||
95 | }; | ||
96 | |||
97 | union ins_formats { | ||
98 | struct ins_format1 format1; | ||
99 | struct ins_format2 format2; | ||
100 | struct ins_format3 format3; | ||
101 | uint8_t bytes[4]; | ||
102 | uint32_t integer; | ||
103 | }; | ||
104 | struct instruction { | ||
105 | union ins_formats format; | ||
106 | u_int srcline; | ||
107 | struct symbol *patch_label; | ||
108 | STAILQ_ENTRY(instruction) links; | ||
109 | }; | ||
110 | |||
111 | #define AIC_OP_OR 0x0 | ||
112 | #define AIC_OP_AND 0x1 | ||
113 | #define AIC_OP_XOR 0x2 | ||
114 | #define AIC_OP_ADD 0x3 | ||
115 | #define AIC_OP_ADC 0x4 | ||
116 | #define AIC_OP_ROL 0x5 | ||
117 | #define AIC_OP_BMOV 0x6 | ||
118 | |||
119 | #define AIC_OP_JMP 0x8 | ||
120 | #define AIC_OP_JC 0x9 | ||
121 | #define AIC_OP_JNC 0xa | ||
122 | #define AIC_OP_CALL 0xb | ||
123 | #define AIC_OP_JNE 0xc | ||
124 | #define AIC_OP_JNZ 0xd | ||
125 | #define AIC_OP_JE 0xe | ||
126 | #define AIC_OP_JZ 0xf | ||
127 | |||
128 | /* Pseudo Ops */ | ||
129 | #define AIC_OP_SHL 0x10 | ||
130 | #define AIC_OP_SHR 0x20 | ||
131 | #define AIC_OP_ROR 0x30 | ||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y new file mode 100644 index 000000000000..439f760b34b5 --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y | |||
@@ -0,0 +1,164 @@ | |||
1 | %{ | ||
2 | /* | ||
3 | * Sub-parser for macro invocation in the Aic7xxx SCSI | ||
4 | * Host adapter sequencer assembler. | ||
5 | * | ||
6 | * Copyright (c) 2001 Adaptec Inc. | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * 1. Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions, and the following disclaimer, | ||
14 | * without modification. | ||
15 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
16 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
17 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
18 | * including a substantially similar Disclaimer requirement for further | ||
19 | * binary redistribution. | ||
20 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
21 | * of any contributors may be used to endorse or promote products derived | ||
22 | * from this software without specific prior written permission. | ||
23 | * | ||
24 | * Alternatively, this software may be distributed under the terms of the | ||
25 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
26 | * Software Foundation. | ||
27 | * | ||
28 | * NO WARRANTY | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
32 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
33 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
37 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
38 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGES. | ||
40 | * | ||
41 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_macro_gram.y#5 $ | ||
42 | * | ||
43 | * $FreeBSD$ | ||
44 | */ | ||
45 | |||
46 | #include <sys/types.h> | ||
47 | |||
48 | #include <inttypes.h> | ||
49 | #include <regex.h> | ||
50 | #include <stdio.h> | ||
51 | #include <stdlib.h> | ||
52 | #include <string.h> | ||
53 | #include <sysexits.h> | ||
54 | |||
55 | #ifdef __linux__ | ||
56 | #include "../queue.h" | ||
57 | #else | ||
58 | #include <sys/queue.h> | ||
59 | #endif | ||
60 | |||
61 | #include "aicasm.h" | ||
62 | #include "aicasm_symbol.h" | ||
63 | #include "aicasm_insformat.h" | ||
64 | |||
65 | static symbol_t *macro_symbol; | ||
66 | |||
67 | static void add_macro_arg(const char *argtext, int position); | ||
68 | |||
69 | %} | ||
70 | |||
71 | %union { | ||
72 | int value; | ||
73 | char *str; | ||
74 | symbol_t *sym; | ||
75 | } | ||
76 | |||
77 | |||
78 | %token <str> T_ARG | ||
79 | |||
80 | %token <sym> T_SYMBOL | ||
81 | |||
82 | %type <value> macro_arglist | ||
83 | |||
84 | %% | ||
85 | |||
86 | macrocall: | ||
87 | T_SYMBOL '(' | ||
88 | { | ||
89 | macro_symbol = $1; | ||
90 | } | ||
91 | macro_arglist ')' | ||
92 | { | ||
93 | if (macro_symbol->info.macroinfo->narg != $4) { | ||
94 | printf("Narg == %d", macro_symbol->info.macroinfo->narg); | ||
95 | stop("Too few arguments for macro invocation", | ||
96 | EX_DATAERR); | ||
97 | /* NOTREACHED */ | ||
98 | } | ||
99 | macro_symbol = NULL; | ||
100 | YYACCEPT; | ||
101 | } | ||
102 | ; | ||
103 | |||
104 | macro_arglist: | ||
105 | { | ||
106 | /* Macros can take 0 arguments */ | ||
107 | $$ = 0; | ||
108 | } | ||
109 | | T_ARG | ||
110 | { | ||
111 | $$ = 1; | ||
112 | add_macro_arg($1, 1); | ||
113 | } | ||
114 | | macro_arglist ',' T_ARG | ||
115 | { | ||
116 | if ($1 == 0) { | ||
117 | stop("Comma without preceeding argument in arg list", | ||
118 | EX_DATAERR); | ||
119 | /* NOTREACHED */ | ||
120 | } | ||
121 | $$ = $1 + 1; | ||
122 | add_macro_arg($3, $$); | ||
123 | } | ||
124 | ; | ||
125 | |||
126 | %% | ||
127 | |||
128 | static void | ||
129 | add_macro_arg(const char *argtext, int argnum) | ||
130 | { | ||
131 | struct macro_arg *marg; | ||
132 | int i; | ||
133 | |||
134 | if (macro_symbol == NULL || macro_symbol->type != MACRO) { | ||
135 | stop("Invalid current symbol for adding macro arg", | ||
136 | EX_SOFTWARE); | ||
137 | /* NOTREACHED */ | ||
138 | } | ||
139 | /* | ||
140 | * Macro Invocation. Find the appropriate argument and fill | ||
141 | * in the replace ment text for this call. | ||
142 | */ | ||
143 | i = 0; | ||
144 | STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { | ||
145 | i++; | ||
146 | if (i == argnum) | ||
147 | break; | ||
148 | } | ||
149 | if (marg == NULL) { | ||
150 | stop("Too many arguments for macro invocation", EX_DATAERR); | ||
151 | /* NOTREACHED */ | ||
152 | } | ||
153 | marg->replacement_text = strdup(argtext); | ||
154 | if (marg->replacement_text == NULL) { | ||
155 | stop("Unable to replicate replacement text", EX_SOFTWARE); | ||
156 | /* NOTREACHED */ | ||
157 | } | ||
158 | } | ||
159 | |||
160 | void | ||
161 | mmerror(const char *string) | ||
162 | { | ||
163 | stop(string, EX_DATAERR); | ||
164 | } | ||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l new file mode 100644 index 000000000000..f06e7035cb35 --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l | |||
@@ -0,0 +1,156 @@ | |||
1 | %{ | ||
2 | /* | ||
3 | * Sub-Lexical Analyzer for macro invokation in | ||
4 | * the Aic7xxx SCSI Host adapter sequencer assembler. | ||
5 | * | ||
6 | * Copyright (c) 2001 Adaptec Inc. | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * 1. Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions, and the following disclaimer, | ||
14 | * without modification. | ||
15 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
16 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
17 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
18 | * including a substantially similar Disclaimer requirement for further | ||
19 | * binary redistribution. | ||
20 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
21 | * of any contributors may be used to endorse or promote products derived | ||
22 | * from this software without specific prior written permission. | ||
23 | * | ||
24 | * Alternatively, this software may be distributed under the terms of the | ||
25 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
26 | * Software Foundation. | ||
27 | * | ||
28 | * NO WARRANTY | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
32 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
33 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
37 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
38 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGES. | ||
40 | * | ||
41 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_macro_scan.l#8 $ | ||
42 | * | ||
43 | * $FreeBSD$ | ||
44 | */ | ||
45 | |||
46 | #include <sys/types.h> | ||
47 | |||
48 | #include <inttypes.h> | ||
49 | #include <limits.h> | ||
50 | #include <regex.h> | ||
51 | #include <stdio.h> | ||
52 | #include <string.h> | ||
53 | #include <sysexits.h> | ||
54 | #ifdef __linux__ | ||
55 | #include "../queue.h" | ||
56 | #else | ||
57 | #include <sys/queue.h> | ||
58 | #endif | ||
59 | |||
60 | #include "aicasm.h" | ||
61 | #include "aicasm_symbol.h" | ||
62 | #include "aicasm_macro_gram.h" | ||
63 | |||
64 | #define MAX_STR_CONST 4096 | ||
65 | static char string_buf[MAX_STR_CONST]; | ||
66 | static char *string_buf_ptr; | ||
67 | static int parren_count; | ||
68 | static char buf[255]; | ||
69 | %} | ||
70 | |||
71 | WORD [A-Za-z_][-A-Za-z_0-9]* | ||
72 | SPACE [ \t]+ | ||
73 | MCARG [^(), \t]+ | ||
74 | |||
75 | %x ARGLIST | ||
76 | |||
77 | %% | ||
78 | \n { | ||
79 | ++yylineno; | ||
80 | } | ||
81 | \r ; | ||
82 | <ARGLIST>{SPACE} ; | ||
83 | <ARGLIST>\( { | ||
84 | parren_count++; | ||
85 | if (parren_count == 1) { | ||
86 | string_buf_ptr = string_buf; | ||
87 | return ('('); | ||
88 | } | ||
89 | *string_buf_ptr++ = '('; | ||
90 | } | ||
91 | <ARGLIST>\) { | ||
92 | if (parren_count == 1) { | ||
93 | if (string_buf_ptr != string_buf) { | ||
94 | /* | ||
95 | * Return an argument and | ||
96 | * rescan this parren so we | ||
97 | * can return it as well. | ||
98 | */ | ||
99 | *string_buf_ptr = '\0'; | ||
100 | mmlval.str = string_buf; | ||
101 | string_buf_ptr = string_buf; | ||
102 | unput(')'); | ||
103 | return T_ARG; | ||
104 | } | ||
105 | BEGIN INITIAL; | ||
106 | return (')'); | ||
107 | } | ||
108 | parren_count--; | ||
109 | *string_buf_ptr++ = ')'; | ||
110 | } | ||
111 | <ARGLIST>{MCARG} { | ||
112 | char *yptr; | ||
113 | |||
114 | yptr = mmtext; | ||
115 | while (*yptr) | ||
116 | *string_buf_ptr++ = *yptr++; | ||
117 | } | ||
118 | <ARGLIST>\, { | ||
119 | if (string_buf_ptr != string_buf) { | ||
120 | /* | ||
121 | * Return an argument and | ||
122 | * rescan this comma so we | ||
123 | * can return it as well. | ||
124 | */ | ||
125 | *string_buf_ptr = '\0'; | ||
126 | mmlval.str = string_buf; | ||
127 | string_buf_ptr = string_buf; | ||
128 | unput(','); | ||
129 | return T_ARG; | ||
130 | } | ||
131 | return ','; | ||
132 | } | ||
133 | {WORD}[(] { | ||
134 | /* May be a symbol or a macro invocation. */ | ||
135 | mmlval.sym = symtable_get(mmtext); | ||
136 | if (mmlval.sym->type != MACRO) { | ||
137 | stop("Expecting Macro Name", | ||
138 | EX_DATAERR); | ||
139 | } | ||
140 | unput('('); | ||
141 | parren_count = 0; | ||
142 | BEGIN ARGLIST; | ||
143 | return T_SYMBOL; | ||
144 | } | ||
145 | . { | ||
146 | snprintf(buf, sizeof(buf), "Invalid character " | ||
147 | "'%c'", mmtext[0]); | ||
148 | stop(buf, EX_DATAERR); | ||
149 | } | ||
150 | %% | ||
151 | |||
152 | int | ||
153 | mmwrap() | ||
154 | { | ||
155 | stop("EOF encountered in macro call", EX_DATAERR); | ||
156 | } | ||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l new file mode 100644 index 000000000000..45c0b233d0bc --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l | |||
@@ -0,0 +1,607 @@ | |||
1 | %{ | ||
2 | /* | ||
3 | * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler. | ||
4 | * | ||
5 | * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. | ||
6 | * Copyright (c) 2001, 2002 Adaptec Inc. | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * 1. Redistributions of source code must retain the above copyright | ||
13 | * notice, this list of conditions, and the following disclaimer, | ||
14 | * without modification. | ||
15 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
16 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
17 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
18 | * including a substantially similar Disclaimer requirement for further | ||
19 | * binary redistribution. | ||
20 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
21 | * of any contributors may be used to endorse or promote products derived | ||
22 | * from this software without specific prior written permission. | ||
23 | * | ||
24 | * Alternatively, this software may be distributed under the terms of the | ||
25 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
26 | * Software Foundation. | ||
27 | * | ||
28 | * NO WARRANTY | ||
29 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
30 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
31 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
32 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
33 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
34 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
35 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
36 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
37 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
38 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
39 | * POSSIBILITY OF SUCH DAMAGES. | ||
40 | * | ||
41 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#19 $ | ||
42 | * | ||
43 | * $FreeBSD$ | ||
44 | */ | ||
45 | |||
46 | #include <sys/types.h> | ||
47 | |||
48 | #include <inttypes.h> | ||
49 | #include <limits.h> | ||
50 | #include <regex.h> | ||
51 | #include <stdio.h> | ||
52 | #include <string.h> | ||
53 | #include <sysexits.h> | ||
54 | #ifdef __linux__ | ||
55 | #include "../queue.h" | ||
56 | #else | ||
57 | #include <sys/queue.h> | ||
58 | #endif | ||
59 | |||
60 | #include "aicasm.h" | ||
61 | #include "aicasm_symbol.h" | ||
62 | #include "aicasm_gram.h" | ||
63 | |||
64 | /* This is used for macro body capture too, so err on the large size. */ | ||
65 | #define MAX_STR_CONST 4096 | ||
66 | static char string_buf[MAX_STR_CONST]; | ||
67 | static char *string_buf_ptr; | ||
68 | static int parren_count; | ||
69 | static int quote_count; | ||
70 | static char buf[255]; | ||
71 | %} | ||
72 | |||
73 | PATH ([/]*[-A-Za-z0-9_.])+ | ||
74 | WORD [A-Za-z_][-A-Za-z_0-9]* | ||
75 | SPACE [ \t]+ | ||
76 | MCARG [^(), \t]+ | ||
77 | MBODY ((\\[^\n])*[^\n\\]*)+ | ||
78 | |||
79 | %x COMMENT | ||
80 | %x CEXPR | ||
81 | %x INCLUDE | ||
82 | %x STRING | ||
83 | %x MACRODEF | ||
84 | %x MACROARGLIST | ||
85 | %x MACROCALLARGS | ||
86 | %x MACROBODY | ||
87 | |||
88 | %% | ||
89 | \n { ++yylineno; } | ||
90 | \r ; | ||
91 | "/*" { BEGIN COMMENT; /* Enter comment eating state */ } | ||
92 | <COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); } | ||
93 | <COMMENT>\n { ++yylineno; } | ||
94 | <COMMENT>[^*/\n]* ; | ||
95 | <COMMENT>"*"+[^*/\n]* ; | ||
96 | <COMMENT>"/"+[^*/\n]* ; | ||
97 | <COMMENT>"*"+"/" { BEGIN INITIAL; } | ||
98 | if[ \t]*\( { | ||
99 | string_buf_ptr = string_buf; | ||
100 | parren_count = 1; | ||
101 | BEGIN CEXPR; | ||
102 | return T_IF; | ||
103 | } | ||
104 | <CEXPR>\( { *string_buf_ptr++ = '('; parren_count++; } | ||
105 | <CEXPR>\) { | ||
106 | parren_count--; | ||
107 | if (parren_count == 0) { | ||
108 | /* All done */ | ||
109 | BEGIN INITIAL; | ||
110 | *string_buf_ptr = '\0'; | ||
111 | yylval.sym = symtable_get(string_buf); | ||
112 | return T_CEXPR; | ||
113 | } else { | ||
114 | *string_buf_ptr++ = ')'; | ||
115 | } | ||
116 | } | ||
117 | <CEXPR>\n { ++yylineno; } | ||
118 | <CEXPR>\r ; | ||
119 | <CEXPR>[^()\n]+ { | ||
120 | char *yptr; | ||
121 | |||
122 | yptr = yytext; | ||
123 | while (*yptr != '\0') { | ||
124 | /* Remove duplicate spaces */ | ||
125 | if (*yptr == '\t') | ||
126 | *yptr = ' '; | ||
127 | if (*yptr == ' ' | ||
128 | && string_buf_ptr != string_buf | ||
129 | && string_buf_ptr[-1] == ' ') | ||
130 | yptr++; | ||
131 | else | ||
132 | *string_buf_ptr++ = *yptr++; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | VERSION { return T_VERSION; } | ||
137 | PREFIX { return T_PREFIX; } | ||
138 | PATCH_ARG_LIST { return T_PATCH_ARG_LIST; } | ||
139 | \" { | ||
140 | string_buf_ptr = string_buf; | ||
141 | BEGIN STRING; | ||
142 | } | ||
143 | <STRING>[^"]+ { | ||
144 | char *yptr; | ||
145 | |||
146 | yptr = yytext; | ||
147 | while (*yptr) | ||
148 | *string_buf_ptr++ = *yptr++; | ||
149 | } | ||
150 | <STRING>\" { | ||
151 | /* All done */ | ||
152 | BEGIN INITIAL; | ||
153 | *string_buf_ptr = '\0'; | ||
154 | yylval.str = string_buf; | ||
155 | return T_STRING; | ||
156 | } | ||
157 | {SPACE} ; | ||
158 | |||
159 | /* Register/SCB/SRAM definition keywords */ | ||
160 | export { return T_EXPORT; } | ||
161 | register { return T_REGISTER; } | ||
162 | const { yylval.value = FALSE; return T_CONST; } | ||
163 | download { return T_DOWNLOAD; } | ||
164 | address { return T_ADDRESS; } | ||
165 | access_mode { return T_ACCESS_MODE; } | ||
166 | modes { return T_MODES; } | ||
167 | RW|RO|WO { | ||
168 | if (strcmp(yytext, "RW") == 0) | ||
169 | yylval.value = RW; | ||
170 | else if (strcmp(yytext, "RO") == 0) | ||
171 | yylval.value = RO; | ||
172 | else | ||
173 | yylval.value = WO; | ||
174 | return T_MODE; | ||
175 | } | ||
176 | BEGIN_CRITICAL { return T_BEGIN_CS; } | ||
177 | END_CRITICAL { return T_END_CS; } | ||
178 | SET_SRC_MODE { return T_SET_SRC_MODE; } | ||
179 | SET_DST_MODE { return T_SET_DST_MODE; } | ||
180 | field { return T_FIELD; } | ||
181 | enum { return T_ENUM; } | ||
182 | mask { return T_MASK; } | ||
183 | alias { return T_ALIAS; } | ||
184 | size { return T_SIZE; } | ||
185 | scb { return T_SCB; } | ||
186 | scratch_ram { return T_SRAM; } | ||
187 | accumulator { return T_ACCUM; } | ||
188 | mode_pointer { return T_MODE_PTR; } | ||
189 | allones { return T_ALLONES; } | ||
190 | allzeros { return T_ALLZEROS; } | ||
191 | none { return T_NONE; } | ||
192 | sindex { return T_SINDEX; } | ||
193 | A { return T_A; } | ||
194 | |||
195 | /* Opcodes */ | ||
196 | shl { return T_SHL; } | ||
197 | shr { return T_SHR; } | ||
198 | ror { return T_ROR; } | ||
199 | rol { return T_ROL; } | ||
200 | mvi { return T_MVI; } | ||
201 | mov { return T_MOV; } | ||
202 | clr { return T_CLR; } | ||
203 | jmp { return T_JMP; } | ||
204 | jc { return T_JC; } | ||
205 | jnc { return T_JNC; } | ||
206 | je { return T_JE; } | ||
207 | jne { return T_JNE; } | ||
208 | jz { return T_JZ; } | ||
209 | jnz { return T_JNZ; } | ||
210 | call { return T_CALL; } | ||
211 | add { return T_ADD; } | ||
212 | adc { return T_ADC; } | ||
213 | bmov { return T_BMOV; } | ||
214 | inc { return T_INC; } | ||
215 | dec { return T_DEC; } | ||
216 | stc { return T_STC; } | ||
217 | clc { return T_CLC; } | ||
218 | cmp { return T_CMP; } | ||
219 | not { return T_NOT; } | ||
220 | xor { return T_XOR; } | ||
221 | test { return T_TEST;} | ||
222 | and { return T_AND; } | ||
223 | or { return T_OR; } | ||
224 | ret { return T_RET; } | ||
225 | nop { return T_NOP; } | ||
226 | else { return T_ELSE; } | ||
227 | |||
228 | /* Allowed Symbols */ | ||
229 | \<\< { return T_EXPR_LSHIFT; } | ||
230 | \>\> { return T_EXPR_RSHIFT; } | ||
231 | [-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; } | ||
232 | |||
233 | /* Number processing */ | ||
234 | 0[0-7]* { | ||
235 | yylval.value = strtol(yytext, NULL, 8); | ||
236 | return T_NUMBER; | ||
237 | } | ||
238 | |||
239 | 0[xX][0-9a-fA-F]+ { | ||
240 | yylval.value = strtoul(yytext + 2, NULL, 16); | ||
241 | return T_NUMBER; | ||
242 | } | ||
243 | |||
244 | [1-9][0-9]* { | ||
245 | yylval.value = strtol(yytext, NULL, 10); | ||
246 | return T_NUMBER; | ||
247 | } | ||
248 | /* Include Files */ | ||
249 | #include{SPACE} { | ||
250 | BEGIN INCLUDE; | ||
251 | quote_count = 0; | ||
252 | return T_INCLUDE; | ||
253 | } | ||
254 | <INCLUDE>[<] { return yytext[0]; } | ||
255 | <INCLUDE>[>] { BEGIN INITIAL; return yytext[0]; } | ||
256 | <INCLUDE>[\"] { | ||
257 | if (quote_count != 0) | ||
258 | BEGIN INITIAL; | ||
259 | quote_count++; | ||
260 | return yytext[0]; | ||
261 | } | ||
262 | <INCLUDE>{PATH} { | ||
263 | char *yptr; | ||
264 | |||
265 | yptr = yytext; | ||
266 | string_buf_ptr = string_buf; | ||
267 | while (*yptr) | ||
268 | *string_buf_ptr++ = *yptr++; | ||
269 | yylval.str = string_buf; | ||
270 | *string_buf_ptr = '\0'; | ||
271 | return T_PATH; | ||
272 | } | ||
273 | <INCLUDE>. { stop("Invalid include line", EX_DATAERR); } | ||
274 | #define{SPACE} { | ||
275 | BEGIN MACRODEF; | ||
276 | return T_DEFINE; | ||
277 | } | ||
278 | <MACRODEF>{WORD}{SPACE} { | ||
279 | char *yptr; | ||
280 | |||
281 | /* Strip space and return as a normal symbol */ | ||
282 | yptr = yytext; | ||
283 | while (*yptr != ' ' && *yptr != '\t') | ||
284 | yptr++; | ||
285 | *yptr = '\0'; | ||
286 | yylval.sym = symtable_get(yytext); | ||
287 | string_buf_ptr = string_buf; | ||
288 | BEGIN MACROBODY; | ||
289 | return T_SYMBOL; | ||
290 | } | ||
291 | <MACRODEF>{WORD}\( { | ||
292 | /* | ||
293 | * We store the symbol with its opening | ||
294 | * parren so we can differentiate macros | ||
295 | * that take args from macros with the | ||
296 | * same name that do not take args as | ||
297 | * is allowed in C. | ||
298 | */ | ||
299 | BEGIN MACROARGLIST; | ||
300 | yylval.sym = symtable_get(yytext); | ||
301 | unput('('); | ||
302 | return T_SYMBOL; | ||
303 | } | ||
304 | <MACROARGLIST>{WORD} { | ||
305 | yylval.str = yytext; | ||
306 | return T_ARG; | ||
307 | } | ||
308 | <MACROARGLIST>{SPACE} ; | ||
309 | <MACROARGLIST>[(,] { | ||
310 | return yytext[0]; | ||
311 | } | ||
312 | <MACROARGLIST>[)] { | ||
313 | string_buf_ptr = string_buf; | ||
314 | BEGIN MACROBODY; | ||
315 | return ')'; | ||
316 | } | ||
317 | <MACROARGLIST>. { | ||
318 | snprintf(buf, sizeof(buf), "Invalid character " | ||
319 | "'%c' in macro argument list", | ||
320 | yytext[0]); | ||
321 | stop(buf, EX_DATAERR); | ||
322 | } | ||
323 | <MACROCALLARGS>{SPACE} ; | ||
324 | <MACROCALLARGS>\( { | ||
325 | parren_count++; | ||
326 | if (parren_count == 1) | ||
327 | return ('('); | ||
328 | *string_buf_ptr++ = '('; | ||
329 | } | ||
330 | <MACROCALLARGS>\) { | ||
331 | parren_count--; | ||
332 | if (parren_count == 0) { | ||
333 | BEGIN INITIAL; | ||
334 | return (')'); | ||
335 | } | ||
336 | *string_buf_ptr++ = ')'; | ||
337 | } | ||
338 | <MACROCALLARGS>{MCARG} { | ||
339 | char *yptr; | ||
340 | |||
341 | yptr = yytext; | ||
342 | while (*yptr) | ||
343 | *string_buf_ptr++ = *yptr++; | ||
344 | } | ||
345 | <MACROCALLARGS>\, { | ||
346 | if (string_buf_ptr != string_buf) { | ||
347 | /* | ||
348 | * Return an argument and | ||
349 | * rescan this comma so we | ||
350 | * can return it as well. | ||
351 | */ | ||
352 | *string_buf_ptr = '\0'; | ||
353 | yylval.str = string_buf; | ||
354 | string_buf_ptr = string_buf; | ||
355 | unput(','); | ||
356 | return T_ARG; | ||
357 | } | ||
358 | return ','; | ||
359 | } | ||
360 | <MACROBODY>\\\n { | ||
361 | /* Eat escaped newlines. */ | ||
362 | ++yylineno; | ||
363 | } | ||
364 | <MACROBODY>\r ; | ||
365 | <MACROBODY>\n { | ||
366 | /* Macros end on the first unescaped newline. */ | ||
367 | BEGIN INITIAL; | ||
368 | *string_buf_ptr = '\0'; | ||
369 | yylval.str = string_buf; | ||
370 | ++yylineno; | ||
371 | return T_MACROBODY; | ||
372 | } | ||
373 | <MACROBODY>{MBODY} { | ||
374 | char *yptr; | ||
375 | char c; | ||
376 | |||
377 | yptr = yytext; | ||
378 | while (c = *yptr++) { | ||
379 | /* | ||
380 | * Strip carriage returns. | ||
381 | */ | ||
382 | if (c == '\r') | ||
383 | continue; | ||
384 | *string_buf_ptr++ = c; | ||
385 | } | ||
386 | } | ||
387 | {WORD}\( { | ||
388 | char *yptr; | ||
389 | char *ycopy; | ||
390 | |||
391 | /* May be a symbol or a macro invocation. */ | ||
392 | yylval.sym = symtable_get(yytext); | ||
393 | if (yylval.sym->type == MACRO) { | ||
394 | YY_BUFFER_STATE old_state; | ||
395 | YY_BUFFER_STATE temp_state; | ||
396 | |||
397 | ycopy = strdup(yytext); | ||
398 | yptr = ycopy + yyleng; | ||
399 | while (yptr > ycopy) | ||
400 | unput(*--yptr); | ||
401 | old_state = YY_CURRENT_BUFFER; | ||
402 | temp_state = | ||
403 | yy_create_buffer(stdin, | ||
404 | YY_BUF_SIZE); | ||
405 | yy_switch_to_buffer(temp_state); | ||
406 | mm_switch_to_buffer(old_state); | ||
407 | mmparse(); | ||
408 | mm_switch_to_buffer(temp_state); | ||
409 | yy_switch_to_buffer(old_state); | ||
410 | mm_delete_buffer(temp_state); | ||
411 | expand_macro(yylval.sym); | ||
412 | } else { | ||
413 | if (yylval.sym->type == UNINITIALIZED) { | ||
414 | /* Try without the '(' */ | ||
415 | symbol_delete(yylval.sym); | ||
416 | yytext[yyleng-1] = '\0'; | ||
417 | yylval.sym = | ||
418 | symtable_get(yytext); | ||
419 | } | ||
420 | unput('('); | ||
421 | return T_SYMBOL; | ||
422 | } | ||
423 | } | ||
424 | {WORD} { | ||
425 | yylval.sym = symtable_get(yytext); | ||
426 | if (yylval.sym->type == MACRO) { | ||
427 | expand_macro(yylval.sym); | ||
428 | } else { | ||
429 | return T_SYMBOL; | ||
430 | } | ||
431 | } | ||
432 | . { | ||
433 | snprintf(buf, sizeof(buf), "Invalid character " | ||
434 | "'%c'", yytext[0]); | ||
435 | stop(buf, EX_DATAERR); | ||
436 | } | ||
437 | %% | ||
438 | |||
439 | typedef struct include { | ||
440 | YY_BUFFER_STATE buffer; | ||
441 | int lineno; | ||
442 | char *filename; | ||
443 | SLIST_ENTRY(include) links; | ||
444 | }include_t; | ||
445 | |||
446 | SLIST_HEAD(, include) include_stack; | ||
447 | |||
448 | void | ||
449 | include_file(char *file_name, include_type type) | ||
450 | { | ||
451 | FILE *newfile; | ||
452 | include_t *include; | ||
453 | |||
454 | newfile = NULL; | ||
455 | /* Try the current directory first */ | ||
456 | if (includes_search_curdir != 0 || type == SOURCE_FILE) | ||
457 | newfile = fopen(file_name, "r"); | ||
458 | |||
459 | if (newfile == NULL && type != SOURCE_FILE) { | ||
460 | path_entry_t include_dir; | ||
461 | for (include_dir = search_path.slh_first; | ||
462 | include_dir != NULL; | ||
463 | include_dir = include_dir->links.sle_next) { | ||
464 | char fullname[PATH_MAX]; | ||
465 | |||
466 | if ((include_dir->quoted_includes_only == TRUE) | ||
467 | && (type != QUOTED_INCLUDE)) | ||
468 | continue; | ||
469 | |||
470 | snprintf(fullname, sizeof(fullname), | ||
471 | "%s/%s", include_dir->directory, file_name); | ||
472 | |||
473 | if ((newfile = fopen(fullname, "r")) != NULL) | ||
474 | break; | ||
475 | } | ||
476 | } | ||
477 | |||
478 | if (newfile == NULL) { | ||
479 | perror(file_name); | ||
480 | stop("Unable to open input file", EX_SOFTWARE); | ||
481 | /* NOTREACHED */ | ||
482 | } | ||
483 | |||
484 | if (type != SOURCE_FILE) { | ||
485 | include = (include_t *)malloc(sizeof(include_t)); | ||
486 | if (include == NULL) { | ||
487 | stop("Unable to allocate include stack entry", | ||
488 | EX_SOFTWARE); | ||
489 | /* NOTREACHED */ | ||
490 | } | ||
491 | include->buffer = YY_CURRENT_BUFFER; | ||
492 | include->lineno = yylineno; | ||
493 | include->filename = yyfilename; | ||
494 | SLIST_INSERT_HEAD(&include_stack, include, links); | ||
495 | } | ||
496 | yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); | ||
497 | yylineno = 1; | ||
498 | yyfilename = strdup(file_name); | ||
499 | } | ||
500 | |||
501 | static void next_substitution(struct symbol *mac_symbol, const char *body_pos, | ||
502 | const char **next_match, | ||
503 | struct macro_arg **match_marg, regmatch_t *match); | ||
504 | |||
505 | void | ||
506 | expand_macro(struct symbol *macro_symbol) | ||
507 | { | ||
508 | struct macro_arg *marg; | ||
509 | struct macro_arg *match_marg; | ||
510 | const char *body_head; | ||
511 | const char *body_pos; | ||
512 | const char *next_match; | ||
513 | |||
514 | /* | ||
515 | * Due to the nature of unput, we must work | ||
516 | * backwards through the macro body performing | ||
517 | * any expansions. | ||
518 | */ | ||
519 | body_head = macro_symbol->info.macroinfo->body; | ||
520 | body_pos = body_head + strlen(body_head); | ||
521 | while (body_pos > body_head) { | ||
522 | regmatch_t match; | ||
523 | |||
524 | next_match = body_head; | ||
525 | match_marg = NULL; | ||
526 | next_substitution(macro_symbol, body_pos, &next_match, | ||
527 | &match_marg, &match); | ||
528 | |||
529 | /* Put back everything up until the replacement. */ | ||
530 | while (body_pos > next_match) | ||
531 | unput(*--body_pos); | ||
532 | |||
533 | /* Perform the replacement. */ | ||
534 | if (match_marg != NULL) { | ||
535 | const char *strp; | ||
536 | |||
537 | next_match = match_marg->replacement_text; | ||
538 | strp = next_match + strlen(next_match); | ||
539 | while (strp > next_match) | ||
540 | unput(*--strp); | ||
541 | |||
542 | /* Skip past the unexpanded macro arg. */ | ||
543 | body_pos -= match.rm_eo - match.rm_so; | ||
544 | } | ||
545 | } | ||
546 | |||
547 | /* Cleanup replacement text. */ | ||
548 | STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { | ||
549 | free(marg->replacement_text); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | /* | ||
554 | * Find the next substitution in the macro working backwards from | ||
555 | * body_pos until the beginning of the macro buffer. next_match | ||
556 | * should be initialized to the beginning of the macro buffer prior | ||
557 | * to calling this routine. | ||
558 | */ | ||
559 | static void | ||
560 | next_substitution(struct symbol *mac_symbol, const char *body_pos, | ||
561 | const char **next_match, struct macro_arg **match_marg, | ||
562 | regmatch_t *match) | ||
563 | { | ||
564 | regmatch_t matches[2]; | ||
565 | struct macro_arg *marg; | ||
566 | const char *search_pos; | ||
567 | int retval; | ||
568 | |||
569 | do { | ||
570 | search_pos = *next_match; | ||
571 | |||
572 | STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) { | ||
573 | |||
574 | retval = regexec(&marg->arg_regex, search_pos, 2, | ||
575 | matches, 0); | ||
576 | if (retval == 0 | ||
577 | && (matches[1].rm_eo + search_pos) <= body_pos | ||
578 | && (matches[1].rm_eo + search_pos) > *next_match) { | ||
579 | *match = matches[1]; | ||
580 | *next_match = match->rm_eo + search_pos; | ||
581 | *match_marg = marg; | ||
582 | } | ||
583 | } | ||
584 | } while (search_pos != *next_match); | ||
585 | } | ||
586 | |||
587 | int | ||
588 | yywrap() | ||
589 | { | ||
590 | include_t *include; | ||
591 | |||
592 | yy_delete_buffer(YY_CURRENT_BUFFER); | ||
593 | (void)fclose(yyin); | ||
594 | if (yyfilename != NULL) | ||
595 | free(yyfilename); | ||
596 | yyfilename = NULL; | ||
597 | include = include_stack.slh_first; | ||
598 | if (include != NULL) { | ||
599 | yy_switch_to_buffer(include->buffer); | ||
600 | yylineno = include->lineno; | ||
601 | yyfilename = include->filename; | ||
602 | SLIST_REMOVE_HEAD(&include_stack, links); | ||
603 | free(include); | ||
604 | return (0); | ||
605 | } | ||
606 | return (1); | ||
607 | } | ||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c new file mode 100644 index 000000000000..f1f448dff569 --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c | |||
@@ -0,0 +1,677 @@ | |||
1 | /* | ||
2 | * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation | ||
3 | * | ||
4 | * Copyright (c) 1997 Justin T. Gibbs. | ||
5 | * Copyright (c) 2002 Adaptec Inc. | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions, and the following disclaimer, | ||
13 | * without modification. | ||
14 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
15 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
16 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
17 | * including a substantially similar Disclaimer requirement for further | ||
18 | * binary redistribution. | ||
19 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
20 | * of any contributors may be used to endorse or promote products derived | ||
21 | * from this software without specific prior written permission. | ||
22 | * | ||
23 | * Alternatively, this software may be distributed under the terms of the | ||
24 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
25 | * Software Foundation. | ||
26 | * | ||
27 | * NO WARRANTY | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
30 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
31 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
32 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
37 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGES. | ||
39 | * | ||
40 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#24 $ | ||
41 | * | ||
42 | * $FreeBSD$ | ||
43 | */ | ||
44 | |||
45 | #include <sys/types.h> | ||
46 | |||
47 | #ifdef __linux__ | ||
48 | #include "aicdb.h" | ||
49 | #else | ||
50 | #include <db.h> | ||
51 | #endif | ||
52 | #include <fcntl.h> | ||
53 | #include <inttypes.h> | ||
54 | #include <regex.h> | ||
55 | #include <stdio.h> | ||
56 | #include <stdlib.h> | ||
57 | #include <string.h> | ||
58 | #include <sysexits.h> | ||
59 | |||
60 | #include "aicasm_symbol.h" | ||
61 | #include "aicasm.h" | ||
62 | |||
63 | static DB *symtable; | ||
64 | |||
65 | symbol_t * | ||
66 | symbol_create(char *name) | ||
67 | { | ||
68 | symbol_t *new_symbol; | ||
69 | |||
70 | new_symbol = (symbol_t *)malloc(sizeof(symbol_t)); | ||
71 | if (new_symbol == NULL) { | ||
72 | perror("Unable to create new symbol"); | ||
73 | exit(EX_SOFTWARE); | ||
74 | } | ||
75 | memset(new_symbol, 0, sizeof(*new_symbol)); | ||
76 | new_symbol->name = strdup(name); | ||
77 | if (new_symbol->name == NULL) | ||
78 | stop("Unable to strdup symbol name", EX_SOFTWARE); | ||
79 | new_symbol->type = UNINITIALIZED; | ||
80 | return (new_symbol); | ||
81 | } | ||
82 | |||
83 | void | ||
84 | symbol_delete(symbol_t *symbol) | ||
85 | { | ||
86 | if (symtable != NULL) { | ||
87 | DBT key; | ||
88 | |||
89 | key.data = symbol->name; | ||
90 | key.size = strlen(symbol->name); | ||
91 | symtable->del(symtable, &key, /*flags*/0); | ||
92 | } | ||
93 | switch(symbol->type) { | ||
94 | case SCBLOC: | ||
95 | case SRAMLOC: | ||
96 | case REGISTER: | ||
97 | if (symbol->info.rinfo != NULL) | ||
98 | free(symbol->info.rinfo); | ||
99 | break; | ||
100 | case ALIAS: | ||
101 | if (symbol->info.ainfo != NULL) | ||
102 | free(symbol->info.ainfo); | ||
103 | break; | ||
104 | case MASK: | ||
105 | case FIELD: | ||
106 | case ENUM: | ||
107 | case ENUM_ENTRY: | ||
108 | if (symbol->info.finfo != NULL) { | ||
109 | symlist_free(&symbol->info.finfo->symrefs); | ||
110 | free(symbol->info.finfo); | ||
111 | } | ||
112 | break; | ||
113 | case DOWNLOAD_CONST: | ||
114 | case CONST: | ||
115 | if (symbol->info.cinfo != NULL) | ||
116 | free(symbol->info.cinfo); | ||
117 | break; | ||
118 | case LABEL: | ||
119 | if (symbol->info.linfo != NULL) | ||
120 | free(symbol->info.linfo); | ||
121 | break; | ||
122 | case UNINITIALIZED: | ||
123 | default: | ||
124 | break; | ||
125 | } | ||
126 | free(symbol->name); | ||
127 | free(symbol); | ||
128 | } | ||
129 | |||
130 | void | ||
131 | symtable_open() | ||
132 | { | ||
133 | symtable = dbopen(/*filename*/NULL, | ||
134 | O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH, | ||
135 | /*openinfo*/NULL); | ||
136 | |||
137 | if (symtable == NULL) { | ||
138 | perror("Symbol table creation failed"); | ||
139 | exit(EX_SOFTWARE); | ||
140 | /* NOTREACHED */ | ||
141 | } | ||
142 | } | ||
143 | |||
144 | void | ||
145 | symtable_close() | ||
146 | { | ||
147 | if (symtable != NULL) { | ||
148 | DBT key; | ||
149 | DBT data; | ||
150 | |||
151 | while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { | ||
152 | symbol_t *stored_ptr; | ||
153 | |||
154 | memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); | ||
155 | symbol_delete(stored_ptr); | ||
156 | } | ||
157 | symtable->close(symtable); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * The semantics of get is to return an uninitialized symbol entry | ||
163 | * if a lookup fails. | ||
164 | */ | ||
165 | symbol_t * | ||
166 | symtable_get(char *name) | ||
167 | { | ||
168 | symbol_t *stored_ptr; | ||
169 | DBT key; | ||
170 | DBT data; | ||
171 | int retval; | ||
172 | |||
173 | key.data = (void *)name; | ||
174 | key.size = strlen(name); | ||
175 | |||
176 | if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) { | ||
177 | if (retval == -1) { | ||
178 | perror("Symbol table get operation failed"); | ||
179 | exit(EX_SOFTWARE); | ||
180 | /* NOTREACHED */ | ||
181 | } else if (retval == 1) { | ||
182 | /* Symbol wasn't found, so create a new one */ | ||
183 | symbol_t *new_symbol; | ||
184 | |||
185 | new_symbol = symbol_create(name); | ||
186 | data.data = &new_symbol; | ||
187 | data.size = sizeof(new_symbol); | ||
188 | if (symtable->put(symtable, &key, &data, | ||
189 | /*flags*/0) !=0) { | ||
190 | perror("Symtable put failed"); | ||
191 | exit(EX_SOFTWARE); | ||
192 | } | ||
193 | return (new_symbol); | ||
194 | } else { | ||
195 | perror("Unexpected return value from db get routine"); | ||
196 | exit(EX_SOFTWARE); | ||
197 | /* NOTREACHED */ | ||
198 | } | ||
199 | } | ||
200 | memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); | ||
201 | return (stored_ptr); | ||
202 | } | ||
203 | |||
204 | symbol_node_t * | ||
205 | symlist_search(symlist_t *symlist, char *symname) | ||
206 | { | ||
207 | symbol_node_t *curnode; | ||
208 | |||
209 | curnode = SLIST_FIRST(symlist); | ||
210 | while(curnode != NULL) { | ||
211 | if (strcmp(symname, curnode->symbol->name) == 0) | ||
212 | break; | ||
213 | curnode = SLIST_NEXT(curnode, links); | ||
214 | } | ||
215 | return (curnode); | ||
216 | } | ||
217 | |||
218 | void | ||
219 | symlist_add(symlist_t *symlist, symbol_t *symbol, int how) | ||
220 | { | ||
221 | symbol_node_t *newnode; | ||
222 | |||
223 | newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t)); | ||
224 | if (newnode == NULL) { | ||
225 | stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE); | ||
226 | /* NOTREACHED */ | ||
227 | } | ||
228 | newnode->symbol = symbol; | ||
229 | if (how == SYMLIST_SORT) { | ||
230 | symbol_node_t *curnode; | ||
231 | int field; | ||
232 | |||
233 | field = FALSE; | ||
234 | switch(symbol->type) { | ||
235 | case REGISTER: | ||
236 | case SCBLOC: | ||
237 | case SRAMLOC: | ||
238 | break; | ||
239 | case FIELD: | ||
240 | case MASK: | ||
241 | case ENUM: | ||
242 | case ENUM_ENTRY: | ||
243 | field = TRUE; | ||
244 | break; | ||
245 | default: | ||
246 | stop("symlist_add: Invalid symbol type for sorting", | ||
247 | EX_SOFTWARE); | ||
248 | /* NOTREACHED */ | ||
249 | } | ||
250 | |||
251 | curnode = SLIST_FIRST(symlist); | ||
252 | if (curnode == NULL | ||
253 | || (field | ||
254 | && (curnode->symbol->type > newnode->symbol->type | ||
255 | || (curnode->symbol->type == newnode->symbol->type | ||
256 | && (curnode->symbol->info.finfo->value > | ||
257 | newnode->symbol->info.finfo->value)))) | ||
258 | || (!field && (curnode->symbol->info.rinfo->address > | ||
259 | newnode->symbol->info.rinfo->address))) { | ||
260 | SLIST_INSERT_HEAD(symlist, newnode, links); | ||
261 | return; | ||
262 | } | ||
263 | |||
264 | while (1) { | ||
265 | if (SLIST_NEXT(curnode, links) == NULL) { | ||
266 | SLIST_INSERT_AFTER(curnode, newnode, | ||
267 | links); | ||
268 | break; | ||
269 | } else { | ||
270 | symbol_t *cursymbol; | ||
271 | |||
272 | cursymbol = SLIST_NEXT(curnode, links)->symbol; | ||
273 | if ((field | ||
274 | && (cursymbol->type > symbol->type | ||
275 | || (cursymbol->type == symbol->type | ||
276 | && (cursymbol->info.finfo->value > | ||
277 | symbol->info.finfo->value)))) | ||
278 | || (!field | ||
279 | && (cursymbol->info.rinfo->address > | ||
280 | symbol->info.rinfo->address))) { | ||
281 | SLIST_INSERT_AFTER(curnode, newnode, | ||
282 | links); | ||
283 | break; | ||
284 | } | ||
285 | } | ||
286 | curnode = SLIST_NEXT(curnode, links); | ||
287 | } | ||
288 | } else { | ||
289 | SLIST_INSERT_HEAD(symlist, newnode, links); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | void | ||
294 | symlist_free(symlist_t *symlist) | ||
295 | { | ||
296 | symbol_node_t *node1, *node2; | ||
297 | |||
298 | node1 = SLIST_FIRST(symlist); | ||
299 | while (node1 != NULL) { | ||
300 | node2 = SLIST_NEXT(node1, links); | ||
301 | free(node1); | ||
302 | node1 = node2; | ||
303 | } | ||
304 | SLIST_INIT(symlist); | ||
305 | } | ||
306 | |||
307 | void | ||
308 | symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1, | ||
309 | symlist_t *symlist_src2) | ||
310 | { | ||
311 | symbol_node_t *node; | ||
312 | |||
313 | *symlist_dest = *symlist_src1; | ||
314 | while((node = SLIST_FIRST(symlist_src2)) != NULL) { | ||
315 | SLIST_REMOVE_HEAD(symlist_src2, links); | ||
316 | SLIST_INSERT_HEAD(symlist_dest, node, links); | ||
317 | } | ||
318 | |||
319 | /* These are now empty */ | ||
320 | SLIST_INIT(symlist_src1); | ||
321 | SLIST_INIT(symlist_src2); | ||
322 | } | ||
323 | |||
324 | void | ||
325 | aic_print_file_prologue(FILE *ofile) | ||
326 | { | ||
327 | |||
328 | if (ofile == NULL) | ||
329 | return; | ||
330 | |||
331 | fprintf(ofile, | ||
332 | "/*\n" | ||
333 | " * DO NOT EDIT - This file is automatically generated\n" | ||
334 | " * from the following source files:\n" | ||
335 | " *\n" | ||
336 | "%s */\n", | ||
337 | versions); | ||
338 | } | ||
339 | |||
340 | void | ||
341 | aic_print_include(FILE *dfile, char *include_file) | ||
342 | { | ||
343 | |||
344 | if (dfile == NULL) | ||
345 | return; | ||
346 | fprintf(dfile, "\n#include \"%s\"\n\n", include_file); | ||
347 | } | ||
348 | |||
349 | void | ||
350 | aic_print_reg_dump_types(FILE *ofile) | ||
351 | { | ||
352 | if (ofile == NULL) | ||
353 | return; | ||
354 | |||
355 | fprintf(ofile, | ||
356 | "typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n" | ||
357 | "typedef struct %sreg_parse_entry {\n" | ||
358 | " char *name;\n" | ||
359 | " uint8_t value;\n" | ||
360 | " uint8_t mask;\n" | ||
361 | "} %sreg_parse_entry_t;\n" | ||
362 | "\n", | ||
363 | prefix, prefix, prefix); | ||
364 | } | ||
365 | |||
366 | static void | ||
367 | aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode) | ||
368 | { | ||
369 | if (dfile == NULL) | ||
370 | return; | ||
371 | |||
372 | fprintf(dfile, | ||
373 | "static %sreg_parse_entry_t %s_parse_table[] = {\n", | ||
374 | prefix, | ||
375 | regnode->symbol->name); | ||
376 | } | ||
377 | |||
378 | static void | ||
379 | aic_print_reg_dump_end(FILE *ofile, FILE *dfile, | ||
380 | symbol_node_t *regnode, u_int num_entries) | ||
381 | { | ||
382 | char *lower_name; | ||
383 | char *letter; | ||
384 | |||
385 | lower_name = strdup(regnode->symbol->name); | ||
386 | if (lower_name == NULL) | ||
387 | stop("Unable to strdup symbol name", EX_SOFTWARE); | ||
388 | |||
389 | for (letter = lower_name; *letter != '\0'; letter++) | ||
390 | *letter = tolower(*letter); | ||
391 | |||
392 | if (dfile != NULL) { | ||
393 | if (num_entries != 0) | ||
394 | fprintf(dfile, | ||
395 | "\n" | ||
396 | "};\n" | ||
397 | "\n"); | ||
398 | |||
399 | fprintf(dfile, | ||
400 | "int\n" | ||
401 | "%s%s_print(u_int regvalue, u_int *cur_col, u_int wrap)\n" | ||
402 | "{\n" | ||
403 | " return (%sprint_register(%s%s, %d, \"%s\",\n" | ||
404 | " 0x%02x, regvalue, cur_col, wrap));\n" | ||
405 | "}\n" | ||
406 | "\n", | ||
407 | prefix, | ||
408 | lower_name, | ||
409 | prefix, | ||
410 | num_entries != 0 ? regnode->symbol->name : "NULL", | ||
411 | num_entries != 0 ? "_parse_table" : "", | ||
412 | num_entries, | ||
413 | regnode->symbol->name, | ||
414 | regnode->symbol->info.rinfo->address); | ||
415 | } | ||
416 | |||
417 | fprintf(ofile, | ||
418 | "#if AIC_DEBUG_REGISTERS\n" | ||
419 | "%sreg_print_t %s%s_print;\n" | ||
420 | "#else\n" | ||
421 | "#define %s%s_print(regvalue, cur_col, wrap) \\\n" | ||
422 | " %sprint_register(NULL, 0, \"%s\", 0x%02x, regvalue, cur_col, wrap)\n" | ||
423 | "#endif\n" | ||
424 | "\n", | ||
425 | prefix, | ||
426 | prefix, | ||
427 | lower_name, | ||
428 | prefix, | ||
429 | lower_name, | ||
430 | prefix, | ||
431 | regnode->symbol->name, | ||
432 | regnode->symbol->info.rinfo->address); | ||
433 | } | ||
434 | |||
435 | static void | ||
436 | aic_print_reg_dump_entry(FILE *dfile, symbol_node_t *curnode) | ||
437 | { | ||
438 | int num_tabs; | ||
439 | |||
440 | if (dfile == NULL) | ||
441 | return; | ||
442 | |||
443 | fprintf(dfile, | ||
444 | " { \"%s\",", | ||
445 | curnode->symbol->name); | ||
446 | |||
447 | num_tabs = 3 - (strlen(curnode->symbol->name) + 5) / 8; | ||
448 | |||
449 | while (num_tabs-- > 0) | ||
450 | fputc('\t', dfile); | ||
451 | fprintf(dfile, "0x%02x, 0x%02x }", | ||
452 | curnode->symbol->info.finfo->value, | ||
453 | curnode->symbol->info.finfo->mask); | ||
454 | } | ||
455 | |||
456 | void | ||
457 | symtable_dump(FILE *ofile, FILE *dfile) | ||
458 | { | ||
459 | /* | ||
460 | * Sort the registers by address with a simple insertion sort. | ||
461 | * Put bitmasks next to the first register that defines them. | ||
462 | * Put constants at the end. | ||
463 | */ | ||
464 | symlist_t registers; | ||
465 | symlist_t masks; | ||
466 | symlist_t constants; | ||
467 | symlist_t download_constants; | ||
468 | symlist_t aliases; | ||
469 | symlist_t exported_labels; | ||
470 | symbol_node_t *curnode; | ||
471 | symbol_node_t *regnode; | ||
472 | DBT key; | ||
473 | DBT data; | ||
474 | int flag; | ||
475 | u_int i; | ||
476 | |||
477 | if (symtable == NULL) | ||
478 | return; | ||
479 | |||
480 | SLIST_INIT(®isters); | ||
481 | SLIST_INIT(&masks); | ||
482 | SLIST_INIT(&constants); | ||
483 | SLIST_INIT(&download_constants); | ||
484 | SLIST_INIT(&aliases); | ||
485 | SLIST_INIT(&exported_labels); | ||
486 | flag = R_FIRST; | ||
487 | while (symtable->seq(symtable, &key, &data, flag) == 0) { | ||
488 | symbol_t *cursym; | ||
489 | |||
490 | memcpy(&cursym, data.data, sizeof(cursym)); | ||
491 | switch(cursym->type) { | ||
492 | case REGISTER: | ||
493 | case SCBLOC: | ||
494 | case SRAMLOC: | ||
495 | symlist_add(®isters, cursym, SYMLIST_SORT); | ||
496 | break; | ||
497 | case MASK: | ||
498 | case FIELD: | ||
499 | case ENUM: | ||
500 | case ENUM_ENTRY: | ||
501 | symlist_add(&masks, cursym, SYMLIST_SORT); | ||
502 | break; | ||
503 | case CONST: | ||
504 | symlist_add(&constants, cursym, | ||
505 | SYMLIST_INSERT_HEAD); | ||
506 | break; | ||
507 | case DOWNLOAD_CONST: | ||
508 | symlist_add(&download_constants, cursym, | ||
509 | SYMLIST_INSERT_HEAD); | ||
510 | break; | ||
511 | case ALIAS: | ||
512 | symlist_add(&aliases, cursym, | ||
513 | SYMLIST_INSERT_HEAD); | ||
514 | break; | ||
515 | case LABEL: | ||
516 | if (cursym->info.linfo->exported == 0) | ||
517 | break; | ||
518 | symlist_add(&exported_labels, cursym, | ||
519 | SYMLIST_INSERT_HEAD); | ||
520 | break; | ||
521 | default: | ||
522 | break; | ||
523 | } | ||
524 | flag = R_NEXT; | ||
525 | } | ||
526 | |||
527 | /* Register dianostic functions/declarations first. */ | ||
528 | aic_print_file_prologue(ofile); | ||
529 | aic_print_reg_dump_types(ofile); | ||
530 | aic_print_file_prologue(dfile); | ||
531 | aic_print_include(dfile, stock_include_file); | ||
532 | SLIST_FOREACH(curnode, ®isters, links) { | ||
533 | |||
534 | switch(curnode->symbol->type) { | ||
535 | case REGISTER: | ||
536 | case SCBLOC: | ||
537 | case SRAMLOC: | ||
538 | { | ||
539 | symlist_t *fields; | ||
540 | symbol_node_t *fieldnode; | ||
541 | int num_entries; | ||
542 | |||
543 | num_entries = 0; | ||
544 | fields = &curnode->symbol->info.rinfo->fields; | ||
545 | SLIST_FOREACH(fieldnode, fields, links) { | ||
546 | if (num_entries == 0) | ||
547 | aic_print_reg_dump_start(dfile, | ||
548 | curnode); | ||
549 | else if (dfile != NULL) | ||
550 | fputs(",\n", dfile); | ||
551 | num_entries++; | ||
552 | aic_print_reg_dump_entry(dfile, fieldnode); | ||
553 | } | ||
554 | aic_print_reg_dump_end(ofile, dfile, | ||
555 | curnode, num_entries); | ||
556 | } | ||
557 | default: | ||
558 | break; | ||
559 | } | ||
560 | } | ||
561 | |||
562 | /* Fold in the masks and bits */ | ||
563 | while (SLIST_FIRST(&masks) != NULL) { | ||
564 | char *regname; | ||
565 | |||
566 | curnode = SLIST_FIRST(&masks); | ||
567 | SLIST_REMOVE_HEAD(&masks, links); | ||
568 | |||
569 | regnode = SLIST_FIRST(&curnode->symbol->info.finfo->symrefs); | ||
570 | regname = regnode->symbol->name; | ||
571 | regnode = symlist_search(®isters, regname); | ||
572 | SLIST_INSERT_AFTER(regnode, curnode, links); | ||
573 | } | ||
574 | |||
575 | /* Add the aliases */ | ||
576 | while (SLIST_FIRST(&aliases) != NULL) { | ||
577 | char *regname; | ||
578 | |||
579 | curnode = SLIST_FIRST(&aliases); | ||
580 | SLIST_REMOVE_HEAD(&aliases, links); | ||
581 | |||
582 | regname = curnode->symbol->info.ainfo->parent->name; | ||
583 | regnode = symlist_search(®isters, regname); | ||
584 | SLIST_INSERT_AFTER(regnode, curnode, links); | ||
585 | } | ||
586 | |||
587 | /* Output generated #defines. */ | ||
588 | while (SLIST_FIRST(®isters) != NULL) { | ||
589 | symbol_node_t *curnode; | ||
590 | u_int value; | ||
591 | char *tab_str; | ||
592 | char *tab_str2; | ||
593 | |||
594 | curnode = SLIST_FIRST(®isters); | ||
595 | SLIST_REMOVE_HEAD(®isters, links); | ||
596 | switch(curnode->symbol->type) { | ||
597 | case REGISTER: | ||
598 | case SCBLOC: | ||
599 | case SRAMLOC: | ||
600 | fprintf(ofile, "\n"); | ||
601 | value = curnode->symbol->info.rinfo->address; | ||
602 | tab_str = "\t"; | ||
603 | tab_str2 = "\t\t"; | ||
604 | break; | ||
605 | case ALIAS: | ||
606 | { | ||
607 | symbol_t *parent; | ||
608 | |||
609 | parent = curnode->symbol->info.ainfo->parent; | ||
610 | value = parent->info.rinfo->address; | ||
611 | tab_str = "\t"; | ||
612 | tab_str2 = "\t\t"; | ||
613 | break; | ||
614 | } | ||
615 | case MASK: | ||
616 | case FIELD: | ||
617 | case ENUM: | ||
618 | case ENUM_ENTRY: | ||
619 | value = curnode->symbol->info.finfo->value; | ||
620 | tab_str = "\t\t"; | ||
621 | tab_str2 = "\t"; | ||
622 | break; | ||
623 | default: | ||
624 | value = 0; /* Quiet compiler */ | ||
625 | tab_str = NULL; | ||
626 | tab_str2 = NULL; | ||
627 | stop("symtable_dump: Invalid symbol type " | ||
628 | "encountered", EX_SOFTWARE); | ||
629 | break; | ||
630 | } | ||
631 | fprintf(ofile, "#define%s%-16s%s0x%02x\n", | ||
632 | tab_str, curnode->symbol->name, tab_str2, | ||
633 | value); | ||
634 | free(curnode); | ||
635 | } | ||
636 | fprintf(ofile, "\n\n"); | ||
637 | |||
638 | while (SLIST_FIRST(&constants) != NULL) { | ||
639 | symbol_node_t *curnode; | ||
640 | |||
641 | curnode = SLIST_FIRST(&constants); | ||
642 | SLIST_REMOVE_HEAD(&constants, links); | ||
643 | fprintf(ofile, "#define\t%-8s\t0x%02x\n", | ||
644 | curnode->symbol->name, | ||
645 | curnode->symbol->info.cinfo->value); | ||
646 | free(curnode); | ||
647 | } | ||
648 | |||
649 | |||
650 | fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); | ||
651 | |||
652 | for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) { | ||
653 | symbol_node_t *curnode; | ||
654 | |||
655 | curnode = SLIST_FIRST(&download_constants); | ||
656 | SLIST_REMOVE_HEAD(&download_constants, links); | ||
657 | fprintf(ofile, "#define\t%-8s\t0x%02x\n", | ||
658 | curnode->symbol->name, | ||
659 | curnode->symbol->info.cinfo->value); | ||
660 | free(curnode); | ||
661 | } | ||
662 | fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i); | ||
663 | |||
664 | fprintf(ofile, "\n\n/* Exported Labels */\n"); | ||
665 | |||
666 | while (SLIST_FIRST(&exported_labels) != NULL) { | ||
667 | symbol_node_t *curnode; | ||
668 | |||
669 | curnode = SLIST_FIRST(&exported_labels); | ||
670 | SLIST_REMOVE_HEAD(&exported_labels, links); | ||
671 | fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n", | ||
672 | curnode->symbol->name, | ||
673 | curnode->symbol->info.linfo->address); | ||
674 | free(curnode); | ||
675 | } | ||
676 | } | ||
677 | |||
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h new file mode 100644 index 000000000000..afc22e8b4903 --- /dev/null +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h | |||
@@ -0,0 +1,207 @@ | |||
1 | /* | ||
2 | * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions | ||
3 | * | ||
4 | * Copyright (c) 1997 Justin T. Gibbs. | ||
5 | * Copyright (c) 2002 Adaptec Inc. | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * Redistribution and use in source and binary forms, with or without | ||
9 | * modification, are permitted provided that the following conditions | ||
10 | * are met: | ||
11 | * 1. Redistributions of source code must retain the above copyright | ||
12 | * notice, this list of conditions, and the following disclaimer, | ||
13 | * without modification. | ||
14 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
15 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
16 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
17 | * including a substantially similar Disclaimer requirement for further | ||
18 | * binary redistribution. | ||
19 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
20 | * of any contributors may be used to endorse or promote products derived | ||
21 | * from this software without specific prior written permission. | ||
22 | * | ||
23 | * Alternatively, this software may be distributed under the terms of the | ||
24 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
25 | * Software Foundation. | ||
26 | * | ||
27 | * NO WARRANTY | ||
28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
30 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
31 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
32 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
33 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
34 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
35 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
36 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
37 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
38 | * POSSIBILITY OF SUCH DAMAGES. | ||
39 | * | ||
40 | * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.h#17 $ | ||
41 | * | ||
42 | * $FreeBSD$ | ||
43 | */ | ||
44 | |||
45 | #ifdef __linux__ | ||
46 | #include "../queue.h" | ||
47 | #else | ||
48 | #include <sys/queue.h> | ||
49 | #endif | ||
50 | |||
51 | typedef enum { | ||
52 | UNINITIALIZED, | ||
53 | REGISTER, | ||
54 | ALIAS, | ||
55 | SCBLOC, | ||
56 | SRAMLOC, | ||
57 | ENUM_ENTRY, | ||
58 | FIELD, | ||
59 | MASK, | ||
60 | ENUM, | ||
61 | CONST, | ||
62 | DOWNLOAD_CONST, | ||
63 | LABEL, | ||
64 | CONDITIONAL, | ||
65 | MACRO | ||
66 | } symtype; | ||
67 | |||
68 | typedef enum { | ||
69 | RO = 0x01, | ||
70 | WO = 0x02, | ||
71 | RW = 0x03 | ||
72 | }amode_t; | ||
73 | |||
74 | typedef SLIST_HEAD(symlist, symbol_node) symlist_t; | ||
75 | |||
76 | struct reg_info { | ||
77 | u_int address; | ||
78 | int size; | ||
79 | amode_t mode; | ||
80 | symlist_t fields; | ||
81 | uint8_t valid_bitmask; | ||
82 | uint8_t modes; | ||
83 | int typecheck_masks; | ||
84 | }; | ||
85 | |||
86 | struct field_info { | ||
87 | symlist_t symrefs; | ||
88 | uint8_t value; | ||
89 | uint8_t mask; | ||
90 | }; | ||
91 | |||
92 | struct const_info { | ||
93 | u_int value; | ||
94 | int define; | ||
95 | }; | ||
96 | |||
97 | struct alias_info { | ||
98 | struct symbol *parent; | ||
99 | }; | ||
100 | |||
101 | struct label_info { | ||
102 | int address; | ||
103 | int exported; | ||
104 | }; | ||
105 | |||
106 | struct cond_info { | ||
107 | int func_num; | ||
108 | }; | ||
109 | |||
110 | struct macro_arg { | ||
111 | STAILQ_ENTRY(macro_arg) links; | ||
112 | regex_t arg_regex; | ||
113 | char *replacement_text; | ||
114 | }; | ||
115 | STAILQ_HEAD(macro_arg_list, macro_arg) args; | ||
116 | |||
117 | struct macro_info { | ||
118 | struct macro_arg_list args; | ||
119 | int narg; | ||
120 | const char* body; | ||
121 | }; | ||
122 | |||
123 | typedef struct expression_info { | ||
124 | symlist_t referenced_syms; | ||
125 | int value; | ||
126 | } expression_t; | ||
127 | |||
128 | typedef struct symbol { | ||
129 | char *name; | ||
130 | symtype type; | ||
131 | union { | ||
132 | struct reg_info *rinfo; | ||
133 | struct field_info *finfo; | ||
134 | struct const_info *cinfo; | ||
135 | struct alias_info *ainfo; | ||
136 | struct label_info *linfo; | ||
137 | struct cond_info *condinfo; | ||
138 | struct macro_info *macroinfo; | ||
139 | }info; | ||
140 | } symbol_t; | ||
141 | |||
142 | typedef struct symbol_ref { | ||
143 | symbol_t *symbol; | ||
144 | int offset; | ||
145 | } symbol_ref_t; | ||
146 | |||
147 | typedef struct symbol_node { | ||
148 | SLIST_ENTRY(symbol_node) links; | ||
149 | symbol_t *symbol; | ||
150 | } symbol_node_t; | ||
151 | |||
152 | typedef struct critical_section { | ||
153 | TAILQ_ENTRY(critical_section) links; | ||
154 | int begin_addr; | ||
155 | int end_addr; | ||
156 | } critical_section_t; | ||
157 | |||
158 | typedef enum { | ||
159 | SCOPE_ROOT, | ||
160 | SCOPE_IF, | ||
161 | SCOPE_ELSE_IF, | ||
162 | SCOPE_ELSE | ||
163 | } scope_type; | ||
164 | |||
165 | typedef struct patch_info { | ||
166 | int skip_patch; | ||
167 | int skip_instr; | ||
168 | } patch_info_t; | ||
169 | |||
170 | typedef struct scope { | ||
171 | SLIST_ENTRY(scope) scope_stack_links; | ||
172 | TAILQ_ENTRY(scope) scope_links; | ||
173 | TAILQ_HEAD(, scope) inner_scope; | ||
174 | scope_type type; | ||
175 | int inner_scope_patches; | ||
176 | int begin_addr; | ||
177 | int end_addr; | ||
178 | patch_info_t patches[2]; | ||
179 | int func_num; | ||
180 | } scope_t; | ||
181 | |||
182 | TAILQ_HEAD(cs_tailq, critical_section); | ||
183 | SLIST_HEAD(scope_list, scope); | ||
184 | TAILQ_HEAD(scope_tailq, scope); | ||
185 | |||
186 | void symbol_delete(symbol_t *symbol); | ||
187 | |||
188 | void symtable_open(void); | ||
189 | |||
190 | void symtable_close(void); | ||
191 | |||
192 | symbol_t * | ||
193 | symtable_get(char *name); | ||
194 | |||
195 | symbol_node_t * | ||
196 | symlist_search(symlist_t *symlist, char *symname); | ||
197 | |||
198 | void | ||
199 | symlist_add(symlist_t *symlist, symbol_t *symbol, int how); | ||
200 | #define SYMLIST_INSERT_HEAD 0x00 | ||
201 | #define SYMLIST_SORT 0x01 | ||
202 | |||
203 | void symlist_free(symlist_t *symlist); | ||
204 | |||
205 | void symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1, | ||
206 | symlist_t *symlist_src2); | ||
207 | void symtable_dump(FILE *ofile, FILE *dfile); | ||