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