1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Assembler for Emu10k1
28 */
29 /*
30 * Copyright (C) 4Front Technologies 1996-2008.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <string.h>
38 #include <stdarg.h>
39 #include <ctype.h>
40 #include <sys/param.h>
41
42 #define MAX_GPR 256
43 #define MAX_GPR_PARMS 60
44 #define MAX_CONST_PARMS 128
45 #define GPR_NAME_SIZE 32
46
47 typedef struct {
48 char name[GPR_NAME_SIZE];
49 unsigned int num;
50 int type;
51 int def;
52 } gpr_t;
53
54 typedef struct {
55 unsigned int gpr;
56 unsigned int value;
57 } const_t;
58
59 typedef struct {
60 unsigned int ngpr;
61
62 gpr_t gpr[MAX_GPR_PARMS];
63 } gpr_info;
64
65 typedef struct {
66 unsigned int nconst;
67
68 const_t consts[MAX_CONST_PARMS];
69 } const_info;
70
71 typedef struct {
72 unsigned int code[1024];
73 gpr_info parms;
74 const_info consts;
75 int ninit;
76 struct {
77 uint32_t gpr;
78 uint32_t value;
79 char name[GPR_NAME_SIZE];
80 } init[MAX_GPR];
81 } emu10k1_file;
82
83 #define MAX_NAME 64
84 #define MAX_SYMBOLS 1024
85
86 static int parms_only = 0;
87 static int is_audigy = 0;
88 static int verbose = 0;
89
90 static int gpr_base = 0x100;
91 static int input_base = 0x10;
92 static int output_base = 0x20;
93
94 static char *progname;
95
96 typedef struct {
97 char name[MAX_NAME];
98 int type;
99 #define SY_DUMMY 0
100 #define SY_GPR 1
101 #define SY_INPUT 2
102 #define SY_OUTPUT 3
103 #define SY_CONST 4
104 #define SY_FX 5
105 #define SY_ACCUM 6
106 #define SY_PARM 7
107 int arg;
108 } sym_t;
109
110 typedef struct {
111 char *name;
112 int opcode;
113 } instruction_t;
114
115 static char remarks[2048] = "";
116 static char *banner =
117 "/*\n"
118 " * Note: This file was automatically generated by %s\n"
119 " * on %s.\n"
120 " */\n";
121
122 /*
123 * Instructions. Each instruction takes 4 arguments, R, A, X, and Y.
124 */
125 static instruction_t instructions[] = {
126 { "MACS", 0x0}, /* R = A + (X * Y >> 31); saturation */
127 { "MACS1", 0x1}, /* R = A + (-X * Y >> 31); saturation */
128 { "MACW", 0x2}, /* R = A + (X * Y >> 31); wraparound */
129 { "MACW1", 0x3}, /* R = A + (-X * Y >> 31); wraparound */
130 { "MACINTS", 0x4}, /* R = A + (X * Y); saturation */
131 { "MACINTW", 0x5}, /* R = A + (X * Y); wraparound */
132 { "SUM", 0x6}, /* R = A + X + Y; saturation */
133 { "ACC3", 0x6}, /* R = A + X + Y; saturation */
134 { "MACMV", 0x7}, /* R = A, acc += X * Y >> 31 */
135 { "ANDXOR", 0x8}, /* R = (A & X) ^ Y */
136 { "TSTNEG", 0x9}, /* R = (A >= Y) ? X : ~X */
137 { "LIMIT", 0xa}, /* R = (A >= Y) ? X : Y */
138 { "LIMIT1", 0xb}, /* R = (A < Y) ? X : Y */
139 { "LOG", 0xc}, /* R = ... (log?) */
140 { "EXP", 0xd}, /* R = ... (exp?) */
141 { "INTERP", 0xe}, /* R = A + (X * (Y - A) >> 31) */
142 { "SKIP", 0xf}, /* R, CCR, CC_TEST, COUNT */
143 { NULL, 0}
144 };
145
146 #define CHECK_COUNT(tokens, cnt, mincnt, maxcnt) \
147 if (cnt < mincnt) { \
148 error("Too few parameters for '%s' (have %d, min %d)", \
149 tokens[0], cnt - 1, mincnt - 1); \
150 return; \
151 } \
152 if (cnt > maxcnt) { \
153 error("Too many parameters for '%s' (have %d, max %d)", \
154 tokens[0], cnt - 1, maxcnt - 1); \
155 return; \
156 }
157
158 static sym_t symtab[MAX_SYMBOLS];
159 static int nsyms = 0;
160
161 static int lineno = 0, errors = 0;
162 static emu10k1_file fle;
163 static int pc;
164
165 static int ngpr = 0;
166 static char *infile;
167
168 static int
getaline(FILE * input,char ** tokens)169 getaline(FILE *input, char **tokens)
170 {
171 char *s, *ls;
172 static char *stmt = NULL, *lasts = NULL;
173 static char line[4096];
174 int cnt, tokcnt;
175
176 for (;;) {
177
178 if (stmt == NULL) {
179 if (fgets(line, sizeof (line), input) == NULL)
180 return (-1);
181 lineno++;
182
183 /*
184 * Special handling for .' comments. We use
185 * .' as a keyword to ensure that entire
186 * comment makes it through the C preprocessor
187 * unmolested. We also need to make sure *we*
188 * don't molest it either. The comment will
189 * be exported to any resulting header,
190 * allowing us to pass through copyright and
191 * other information from the source file to
192 * the resulting header.
193 */
194 s = line;
195 s += strspn(s, " \t");
196 if ((strncmp(s, ".'", 2) == 0) &&
197 (strchr(" \t\n", s[2]) != NULL)) {
198 /* chop off trailing new line */
199 (void) strtok(line, "\n");
200 tokens[0] = s;
201 s += 2;
202 s += strspn(s, " \t");
203 if ((s[0] == '\'') &&
204 (s[strlen(s) - 1] == '\'')) {
205 s[strlen(s) - 1] = 0;
206 s++;
207 }
208 tokens[1] = s;
209 tokens[0][2] = 0;
210 tokens[2] = NULL;
211 stmt = NULL;
212 return (strlen(tokens[1]) ? 2 : 1);
213 }
214
215 /* strip off any C++ style comments that CPP missed */
216 if ((s = strstr(line, "//")) != NULL) {
217 *s = '\0';
218 }
219 stmt = strtok_r(line, ";\n", &lasts);
220 } else {
221 stmt = strtok_r(NULL, ";\n", &lasts);
222 }
223
224 if (stmt != NULL) {
225 break;
226 }
227 }
228
229 /*
230 * Ok, we have a statement, lets tokenize it. For
231 * simplicities sake we convert "OPCODE(arg1, arg2)" into
232 * "OPCODE arg1 arg2". This means that commas and parens are
233 * treated as whitespace. This can lead to some really messed
234 * up syntaxes that get assembled properly (such as nested
235 * calls, empty arguments, etc.) Hopefully people don't abuse
236 * this.
237 */
238 ls = NULL;
239 s = strtok_r(stmt, " \t\n(),", &ls);
240 cnt = 0;
241 tokcnt = 0;
242 while (cnt < 10) {
243 tokens[cnt++] = s;
244 if (s != NULL) {
245 tokcnt++;
246 s = strtok_r(NULL, " \t\n(),", &ls);
247 }
248 }
249 return (tokcnt);
250 }
251
252 static void
error(char * msg,...)253 error(char *msg, ...)
254 {
255 va_list va;
256 char msgbuf[1024];
257
258 va_start(va, msg);
259 (void) vsnprintf(msgbuf, sizeof (msgbuf), msg, va);
260 va_end(va);
261
262 (void) fprintf(stderr, "Error: %s on line %d of %s\n", msgbuf, lineno,
263 infile);
264 errors++;
265 }
266
267 static sym_t *
find_symbol(char * name)268 find_symbol(char *name)
269 {
270 int i;
271
272 for (i = 0; i < nsyms; i++)
273 if (strcmp(symtab[i].name, name) == 0) {
274 return (&symtab[i]);
275 }
276
277 return (NULL);
278 }
279
280 static void
add_symbol(char * name,int type,int arg)281 add_symbol(char *name, int type, int arg)
282 {
283 sym_t *sym;
284
285 if (nsyms >= MAX_SYMBOLS) {
286 error("Symbol table full");
287 exit(-1);
288 }
289
290 if (find_symbol(name) != NULL) {
291 error("Dublicate symbol '%s'", name);
292 return;
293 }
294
295 if (strlen(name) >= MAX_NAME) {
296 error("Symbol name '%s' too long", name);
297 exit(-1);
298 }
299
300 sym = &symtab[nsyms++];
301
302 (void) strcpy(sym->name, name);
303 sym->type = type;
304 sym->arg = arg;
305 }
306
307 static void
add_init(uint32_t gpr,uint32_t val,const char * name)308 add_init(uint32_t gpr, uint32_t val, const char *name)
309 {
310 int n;
311
312 n = fle.ninit;
313 if (n >= MAX_GPR) {
314 error("Too many GPRs");
315 return;
316 }
317 fle.init[n].gpr = gpr;
318 fle.init[n].value = val;
319 if (name)
320 (void) strlcpy(fle.init[n].name, name,
321 sizeof (fle.init[n].name));
322 fle.ninit++;
323 }
324
325 static void
compile_gpr(char ** tokens,int cnt)326 compile_gpr(char **tokens, int cnt)
327 {
328 CHECK_COUNT(tokens, cnt, 2, 2);
329
330 if (ngpr >= MAX_GPR)
331 error("Too many GPR variables");
332
333 add_symbol(tokens[1], SY_GPR, gpr_base + ngpr++);
334 }
335
336 static void
compile_rem(char ** tokens,int cnt)337 compile_rem(char **tokens, int cnt)
338 {
339 int i;
340
341 (void) strlcat(remarks, " *", sizeof (remarks));
342 for (i = 1; i < cnt; i++) {
343 (void) strlcat(remarks, " ", sizeof (remarks));
344 (void) strlcat(remarks, tokens[i], sizeof (remarks));
345 }
346 (void) strlcat(remarks, "\n", sizeof (remarks));
347 }
348
349 static void
declare_const(unsigned int gpr,char * value)350 declare_const(unsigned int gpr, char *value)
351 {
352 int n, intv;
353 float v;
354
355 n = fle.consts.nconst;
356
357 if (n >= MAX_CONST_PARMS) {
358 error("Too many constant parameters");
359 return;
360 }
361
362 if (*value == 'I') {
363 if (sscanf(&value[1], "%g", &v) != 1) {
364 error("Bad floating point value (%s)", value);
365 return;
366 }
367 intv = (int)v;
368 } else if (*value == '0' && value[1] == 'x') {
369 if (sscanf(&value[2], "%x", (unsigned *)&intv) != 1) {
370 error("Bad hexadecimal value (%s)", value);
371 return;
372 }
373 } else {
374 if (sscanf(value, "%g", &v) != 1) {
375 error("Bad floating point value (%s)", value);
376 return;
377 }
378 intv = (int)(v * 0x7fffffff);
379 }
380
381 fle.consts.consts[n].gpr = gpr;
382 fle.consts.consts[n].value = intv;
383 fle.consts.nconst = n + 1;
384
385 add_init(gpr, intv, NULL);
386 }
387
388 static void
compile_const(char ** tokens,int cnt)389 compile_const(char **tokens, int cnt)
390 {
391 CHECK_COUNT(tokens, cnt, 2, 3);
392 char *name = tokens[1];
393 char *value = tokens[2] ? tokens[2] : tokens[1];
394
395 if (ngpr >= MAX_GPR)
396 error("Too many GPR variables");
397
398 declare_const(ngpr, value);
399
400 add_symbol(name, SY_GPR, gpr_base + ngpr++);
401 }
402
403 static void
compile_bool(char ** tokens,int cnt)404 compile_bool(char **tokens, int cnt)
405 {
406 char *parm, *def;
407 int n, num;
408
409 CHECK_COUNT(tokens, cnt, 3, 3);
410
411 parm = tokens[1];
412 def = tokens[2];
413
414 n = fle.parms.ngpr;
415 if (n >= MAX_GPR_PARMS) {
416 error("Too many GPR parameters");
417 return;
418 }
419
420 if (sscanf(def, "%d", &num) != 1) {
421 error("Bad integer value near '%s'", def);
422 return;
423 }
424
425 (void) strcpy(fle.parms.gpr[n].name, parm);
426 fle.parms.gpr[n].num = ngpr;
427 fle.parms.gpr[n].def = num;
428 fle.parms.ngpr = n + 1;
429
430 add_init(ngpr, num, parm);
431
432 add_symbol(parm, SY_PARM, gpr_base + ngpr++);
433 }
434
435 static void
compile_mono(char ** tokens,int cnt)436 compile_mono(char **tokens, int cnt)
437 {
438 char *parm, *def;
439 int n, num;
440
441 CHECK_COUNT(tokens, cnt, 3, 3);
442
443 parm = tokens[1];
444 def = tokens[2];
445
446 n = fle.parms.ngpr;
447 if (n >= MAX_GPR_PARMS) {
448 error("Too many GPR parameters");
449 return;
450 }
451
452 if (sscanf(def, "%d", &num) != 1) {
453 error("Bad integer value near '%s'", def);
454 return;
455 }
456
457 (void) strcpy(fle.parms.gpr[n].name, parm);
458 fle.parms.gpr[n].num = ngpr;
459 fle.parms.gpr[n].def = num;
460 fle.parms.ngpr = n + 1;
461
462 add_init(ngpr, num, parm);
463
464 add_symbol(parm, SY_PARM, gpr_base + ngpr++);
465 }
466
467 static void
compile_stereo(char ** tokens,int cnt)468 compile_stereo(char **tokens, int cnt)
469 {
470 char *parm, *def;
471 int n, num;
472 char tmp[128];
473
474 CHECK_COUNT(tokens, cnt, 3, 3);
475
476 parm = tokens[1];
477 def = tokens[2];
478
479 n = fle.parms.ngpr;
480 if (n >= MAX_GPR_PARMS) {
481 error("Too many GPR parameters");
482 return;
483 }
484
485 if (sscanf(def, "%d", &num) != 1) {
486 error("Bad integer value near '%s'", def);
487 return;
488 }
489
490 (void) strcpy(fle.parms.gpr[n].name, parm);
491 fle.parms.gpr[n].num = ngpr;
492 fle.parms.gpr[n].def = num | (num << 8);
493 fle.parms.ngpr = n + 1;
494
495 add_init(ngpr, num, parm);
496 add_init(ngpr + 1, num, NULL);
497
498 (void) sprintf(tmp, "%s_L", parm);
499 add_symbol(tmp, SY_PARM, gpr_base + ngpr++);
500 (void) sprintf(tmp, "%s_R", parm);
501 add_symbol(tmp, SY_PARM, gpr_base + ngpr++);
502 }
503
504 static void
compile_input(char ** tokens,int cnt)505 compile_input(char **tokens, int cnt)
506 {
507 int num;
508
509 CHECK_COUNT(tokens, cnt, 3, 3);
510
511 if (sscanf(tokens[2], "%d", &num) != 1) {
512 error("Bad integer value near '%s'", tokens[2]);
513 return;
514 }
515
516 add_symbol(tokens[1], SY_INPUT, input_base + num);
517 }
518
519 static void
compile_send(char ** tokens,int cnt)520 compile_send(char **tokens, int cnt)
521 {
522 int num;
523
524 CHECK_COUNT(tokens, cnt, 3, 3);
525
526 if (sscanf(tokens[2], "%d", &num) != 1) {
527 error("Bad integer near '%s'", tokens[2]);
528 return;
529 }
530
531 add_symbol(tokens[1], SY_FX, num);
532 }
533
534 static void
compile_output(char ** tokens,int cnt)535 compile_output(char **tokens, int cnt)
536 {
537 int num;
538
539 CHECK_COUNT(tokens, cnt, 3, 3);
540
541 if (sscanf(tokens[2], "%d", &num) != 1) {
542 error("Bad integer value near '%s'", tokens[2]);
543 return;
544 }
545
546 add_symbol(tokens[1], SY_OUTPUT, output_base + num);
547 }
548
549 static void
compile_directive(char ** tokens,int cnt)550 compile_directive(char **tokens, int cnt)
551 {
552 if (strcmp(tokens[0], ".gpr") == 0) {
553 compile_gpr(tokens, cnt);
554 return;
555 }
556
557 if (strcmp(tokens[0], ".const") == 0) {
558 compile_const(tokens, cnt);
559 return;
560 }
561
562 if (strcmp(tokens[0], ".stereo") == 0) {
563 compile_stereo(tokens, cnt);
564 return;
565 }
566
567 if (strcmp(tokens[0], ".mono") == 0) {
568 compile_mono(tokens, cnt);
569 return;
570 }
571
572 if (strcmp(tokens[0], ".bool") == 0) {
573 compile_bool(tokens, cnt);
574 return;
575 }
576
577 if (strcmp(tokens[0], ".input") == 0) {
578 compile_input(tokens, cnt);
579 return;
580 }
581
582 if (strcmp(tokens[0], ".send") == 0) {
583 compile_send(tokens, cnt);
584 return;
585 }
586
587 if (strcmp(tokens[0], ".output") == 0) {
588 compile_output(tokens, cnt);
589 return;
590 }
591
592 if (strcmp(tokens[0], ".rem") == 0) {
593 compile_rem(tokens, cnt);
594 return;
595 }
596 if (strcmp(tokens[0], ".'") == 0) {
597 compile_rem(tokens, cnt);
598 return;
599 }
600
601 error("Unknown directive '%s'", tokens[0]);
602 }
603
604 static void
compile_asm(char ** tokens,int cnt)605 compile_asm(char **tokens, int cnt)
606 {
607 sym_t *symbols[4];
608 #define EMIT(o, r, a, x, y) \
609 fle.code[pc*2] = ((x) << 10) | (y); \
610 fle.code[pc*2+1] = ((o) << 20) | ((r) << 10) | a; pc++
611 #define EMIT_AUDIGY(o, r, a, x, y) \
612 fle.code[pc*2] = ((x) << 12) | (y); \
613 fle.code[pc*2+1] = ((o) << 24) | ((r) << 12) | a; pc++
614
615 int i, nerr = 0;
616 int ninputs = 0;
617
618 CHECK_COUNT(tokens, cnt, 5, 5);
619
620 for (i = 0; i < 4; i++) {
621 if ((symbols[i] = find_symbol(tokens[i+1])) == NULL) {
622 (void) fprintf(stderr, "%s\n", tokens[i+1]);
623 nerr++;
624 error("Undefined symbol '%s'", tokens[i + 1]);
625 continue;
626 }
627
628 if (symbols[i]->type == SY_INPUT)
629 ninputs++;
630
631 if (symbols[i]->type == SY_ACCUM && i != 1)
632 error("Bad usage of 'accum' operand.");
633 }
634
635 if (nerr > 0)
636 return;
637
638 if (ninputs > 1) {
639 error("Attempt to access more than one input "
640 "GPRs by the same instruction");
641 }
642
643 for (i = 0; instructions[i].name != NULL; i++)
644 if (strcasecmp(tokens[0], instructions[i].name) == 0) {
645
646 if (is_audigy) {
647 EMIT_AUDIGY(instructions[i].opcode,
648 symbols[0]->arg,
649 symbols[1]->arg,
650 symbols[2]->arg,
651 symbols[3]->arg);
652 } else {
653 EMIT(instructions[i].opcode,
654 symbols[0]->arg,
655 symbols[1]->arg,
656 symbols[2]->arg,
657 symbols[3]->arg);
658 }
659
660 return;
661 }
662
663 error("Unrecognized instruction '%s'", tokens[0]);
664 }
665
666 static void
init_compiler(void)667 init_compiler(void)
668 {
669 char tmp[100];
670 int i;
671
672 (void) memset(&fle, 0, sizeof (fle));
673 /*
674 * Initialize few predefined GPR parameter registers. These
675 * definitions have to be in sync with the GPR_* macros in
676 * <sblive.h>.
677 */
678
679 /*
680 * Make sure we start at gpr id 2 for now; 0 and 1 may be used
681 * differently.
682 */
683 add_symbol("NULL", SY_DUMMY, gpr_base + ngpr++);
684 add_symbol("NULL_", SY_DUMMY, gpr_base + ngpr++);
685
686 pc = 0;
687
688 if (is_audigy) {
689 /* Initialize the code array with NOPs (AUDIGY) */
690 for (i = 0; i < 512; i++) {
691 fle.code[i * 2 + 0] = (0xc0 << 12) | 0xc0;
692 fle.code[i * 2 + 1] =
693 (0x06 << 24) | (0xc0 << 12) | 0xc0;
694 }
695
696 for (i = 0; i < 32; i++) {
697 (void) sprintf(tmp, "fx%d", i);
698 add_symbol(tmp, SY_FX, i);
699 }
700 } else {
701 /* Initialize the code array with NOPs (LIVE) */
702 for (i = 0; i < 512; i++) {
703 fle.code[i * 2 + 0] = 0x10040;
704 fle.code[i * 2 + 1] = 0x610040;
705 }
706
707 for (i = 0; i < 16; i++) {
708 (void) sprintf(tmp, "fx%d", i);
709 add_symbol(tmp, SY_FX, i);
710 }
711 }
712
713 /*
714 * Constants
715 */
716
717 if (is_audigy) {
718 /* Audigy symbols */
719 add_symbol("0", SY_CONST, 0x0c0);
720 add_symbol("1", SY_CONST, 0x0c1);
721 add_symbol("2", SY_CONST, 0x0c2);
722 add_symbol("3", SY_CONST, 0x0c3);
723 add_symbol("4", SY_CONST, 0x0c4);
724 add_symbol("8", SY_CONST, 0x0c5);
725 add_symbol("16", SY_CONST, 0x0c6);
726 add_symbol("32", SY_CONST, 0x0c7);
727 add_symbol("256", SY_CONST, 0x0c8);
728 add_symbol("65536", SY_CONST, 0x0c9);
729
730 add_symbol("2048", SY_CONST, 0x0ca);
731 add_symbol("0x800", SY_CONST, 0x0ca);
732
733 add_symbol("2^28", SY_CONST, 0x0cb);
734 add_symbol("0x10000000", SY_CONST, 0x0cb);
735
736 add_symbol("2^29", SY_CONST, 0x0cc);
737 add_symbol("0x20000000", SY_CONST, 0x0cc);
738
739 add_symbol("2^30", SY_CONST, 0x0cd);
740 add_symbol("0x40000000", SY_CONST, 0x0cd);
741
742 add_symbol("2^31", SY_CONST, 0x0ce);
743 add_symbol("0x80000000", SY_CONST, 0x0ce);
744
745 add_symbol("0x7fffffff", SY_CONST, 0x0cf);
746
747 add_symbol("0xffffffff", SY_CONST, 0x0d0);
748 add_symbol("-1", SY_CONST, 0x0d0);
749
750 add_symbol("0xfffffffe", SY_CONST, 0x0d1);
751 add_symbol("-2", SY_CONST, 0x0d1);
752
753 add_symbol("0xc0000000", SY_CONST, 0x0d2);
754
755 add_symbol("0x4f1bbcdc", SY_CONST, 0x0d3);
756
757 add_symbol("0x5a7ef9db", SY_CONST, 0x0d4);
758
759 add_symbol("0x100000", SY_CONST, 0x0d5);
760 add_symbol("accum", SY_ACCUM, 0x0d6);
761 add_symbol("CCR", SY_CONST, 0x0d7);
762
763 add_symbol("noise_L", SY_CONST, 0x0d8);
764 add_symbol("noise_R", SY_CONST, 0x0d9);
765 add_symbol("IRQREQ", SY_CONST, 0x0da);
766 } else {
767 /* SB Live symbols */
768 add_symbol("0", SY_CONST, 0x040);
769 add_symbol("1", SY_CONST, 0x041);
770 add_symbol("2", SY_CONST, 0x042);
771 add_symbol("3", SY_CONST, 0x043);
772 add_symbol("4", SY_CONST, 0x044);
773 add_symbol("8", SY_CONST, 0x045);
774 add_symbol("16", SY_CONST, 0x046);
775 add_symbol("32", SY_CONST, 0x047);
776 add_symbol("256", SY_CONST, 0x048);
777 add_symbol("65536", SY_CONST, 0x049);
778
779 add_symbol("2^23", SY_CONST, 0x04a);
780 add_symbol("0x80000", SY_CONST, 0x04a);
781
782 add_symbol("2^28", SY_CONST, 0x04b);
783 add_symbol("0x10000000", SY_CONST, 0x04b);
784
785 add_symbol("2^29", SY_CONST, 0x04c);
786 add_symbol("0x20000000", SY_CONST, 0x04c);
787
788 add_symbol("2^30", SY_CONST, 0x04d);
789 add_symbol("0x40000000", SY_CONST, 0x04d);
790
791 add_symbol("2^31", SY_CONST, 0x04e);
792 add_symbol("0x80000000", SY_CONST, 0x04e);
793
794 add_symbol("0x7fffffff", SY_CONST, 0x04f);
795
796 add_symbol("0xffffffff", SY_CONST, 0x050);
797 add_symbol("-1", SY_CONST, 0x050);
798
799 add_symbol("0xfffffffe", SY_CONST, 0x051);
800 add_symbol("-2", SY_CONST, 0x051);
801
802 add_symbol("accum", SY_ACCUM, 0x056);
803 add_symbol("CCR", SY_CONST, 0x057);
804
805 add_symbol("noise_L", SY_CONST, 0x058);
806 add_symbol("noise_R", SY_CONST, 0x059);
807 add_symbol("IRQREQ", SY_CONST, 0x05a);
808 }
809 }
810
811 static void
produce_map(char * name)812 produce_map(char *name)
813 {
814 int i;
815 FILE *f;
816
817 if ((f = fopen(name, "w")) == NULL) {
818 perror(name);
819 return;
820 }
821
822 (void) fprintf(f, "%d\n", pc);
823
824 for (i = 0; i < nsyms; i++) {
825 (void) fprintf(f, "%04x %x %s\n",
826 symtab[i].arg, symtab[i].type, symtab[i].name);
827 }
828
829 (void) fclose(f);
830 if (verbose) {
831 (void) fprintf(stderr,
832 "No errors detected - Map written to %s\n", name);
833 }
834 }
835
836 static void
produce_output(char * fname)837 produce_output(char *fname)
838 {
839 int fd;
840
841 if ((fd = creat(fname, 0644)) == -1) {
842 perror(fname);
843 exit(-1);
844 }
845
846 if (write(fd, &fle, sizeof (fle)) != sizeof (fle)) {
847 perror(fname);
848 exit(-1);
849 }
850
851 if (verbose) {
852 (void) fprintf(stderr,
853 "No errors detected - Binary written to %s\n",
854 fname);
855 }
856
857 (void) close(fd);
858 }
859
860 static void
produce_header(char * fname,char * prefix)861 produce_header(char *fname, char *prefix)
862 {
863 FILE *f;
864 char *s;
865 char sname[MAXPATHLEN + 1];
866 char dname[MAXPATHLEN + 1];
867 int i;
868 clock_t now;
869 char when[128];
870
871 /* get basename */
872 if (prefix == NULL) {
873 s = strrchr(fname, '/');
874 s = (s == NULL) ? fname : s + 1;
875 } else {
876 s = prefix;
877 }
878 (void) strlcpy(sname, s, sizeof (sname));
879
880 /* strip off any extension */
881 s = strchr(sname, '.');
882 if (s != NULL) {
883 *s = 0;
884 }
885 if ((f = fopen(fname, "w")) == NULL) {
886 perror(fname);
887 return;
888 }
889
890 if (remarks[0] != 0) {
891 (void) fprintf(f, "/*\n%s */\n", remarks);
892 }
893 now = time(NULL);
894 strftime(when, sizeof (when), "%c", localtime(&now));
895 (void) fprintf(f, banner, progname, when);
896
897 (void) strlcpy(dname, prefix ? prefix : sname, sizeof (dname));
898 for (i = 0; dname[i]; i++) {
899 dname[i] = toupper(dname[i]);
900 if (!isalnum(dname[i])) {
901 dname[i] = '_';
902 }
903 }
904
905 for (i = 0; i < fle.parms.ngpr; i++) {
906 (void) fprintf(f, "#define\t%s_%s\t\t%d\n",
907 dname, fle.parms.gpr[i].name, fle.parms.gpr[i].num);
908 }
909
910 (void) fprintf(f, "\n");
911
912 if (parms_only)
913 goto done;
914
915 (void) fprintf(f, "uint32_t %s_code[] = {\n", sname);
916
917 for (i = 0; i < pc * 2; i++) {
918 if (i == 0) {
919 (void) fprintf(f, "\t0x%08xU", fle.code[i]);
920 } else if ((i % 4) == 0) {
921 (void) fprintf(f, ",\n\t0x%08xU", fle.code[i]);
922 } else {
923 (void) fprintf(f, ", 0x%08xU", fle.code[i]);
924 }
925 }
926 (void) fprintf(f, "\n};\n");
927
928 (void) fprintf(f, "uint32_t %s_ninit = %d;\n", sname, fle.ninit);
929 (void) fprintf(f, "uint32_t %s_init[] = {\n", sname);
930
931 for (i = 0; i < fle.ninit; i++) {
932 if (fle.init[i].name[0]) {
933 (void) fprintf(f, "\t%u, 0x%x%s,\t/* %s */\n",
934 fle.init[i].gpr, fle.init[i].value,
935 fle.init[i].value >= 0x80000000U ? "U" : "",
936 fle.init[i].name);
937 } else {
938 (void) fprintf(f, "\t%u, 0x%x%s,\n",
939 fle.init[i].gpr, fle.init[i].value,
940 fle.init[i].value >= 0x80000000U ? "U" : "");
941 }
942 }
943 (void) fprintf(f, "};\n");
944
945 done:
946 (void) fclose(f);
947 if (verbose) {
948 (void) fprintf(stderr,
949 "No errors detected - Header written to %s\n",
950 fname);
951 }
952 }
953
954 int
main(int argc,char * argv[])955 main(int argc, char *argv[])
956 {
957 char *outfile;
958 int i;
959 FILE *input;
960 char *tokens[10];
961 int tokcnt;
962 char *mapfile = NULL;
963 char *header = NULL;
964 char *prefix = NULL;
965
966 outfile = NULL;
967 infile = NULL;
968 input = NULL;
969 progname = argv[0];
970
971 while ((i = getopt(argc, argv, "m:h:o:i:P:021v")) != EOF) {
972 switch (i) {
973 case 'o':
974 outfile = optarg;
975 break;
976 case 'i':
977 infile = strdup(optarg);
978 break;
979 case 'm':
980 mapfile = optarg;
981 break;
982 case 'P':
983 prefix = optarg;
984 break;
985 case 'h':
986 header = optarg;
987 break;
988 case '0':
989 parms_only = 1;
990 break;
991 case '2':
992 is_audigy = 1;
993 break;
994 case '1':
995 is_audigy = 0;
996 break;
997 case 'v':
998 verbose++;
999 break;
1000 default:
1001 (void) fprintf(stderr,
1002 "usage: %s [-m <map>] [-h <header>] "
1003 "[-o <binary>] [-i <source>] [-2|-1]",
1004 progname);
1005 exit(-1);
1006 break;
1007 }
1008 }
1009
1010 if ((outfile == NULL) && (mapfile == NULL) && (header == NULL)) {
1011 outfile = "dsp.bin";
1012 }
1013
1014 if (infile) {
1015 input = fopen(infile, "r");
1016 if (input == NULL) {
1017 perror(infile);
1018 exit(-1);
1019 }
1020 } else {
1021 infile = strdup("<stdin>");
1022 input = stdin;
1023 }
1024
1025 if (is_audigy) {
1026 gpr_base = 0x400;
1027 input_base = 0x40;
1028 output_base = 0x60;
1029 if (verbose)
1030 (void) fprintf(stderr, "Compiling for SB Audigy\n");
1031 } else {
1032 if (verbose)
1033 (void) fprintf(stderr, "Compiling for SB Live\n");
1034 }
1035
1036 init_compiler();
1037
1038 while ((tokcnt = getaline(input, tokens)) != -1) {
1039 /* skip empty lines */
1040 if (tokcnt == 0) {
1041 continue;
1042 }
1043
1044 if (strcmp(tokens[0], "#") == 0) {
1045 int num;
1046 if ((tokcnt >= 3) &&
1047 (sscanf(tokens[1], "%d", &num) == 1)) {
1048 lineno = num;
1049 free(infile);
1050 infile = strdup(tokens[2]);
1051 /* we don't want to count the # directive */
1052 lineno--;
1053 }
1054
1055 /* unknown # directive? muddle on... */
1056 continue;
1057 }
1058 if (*tokens[0] == '.') {
1059 compile_directive(tokens, tokcnt);
1060 } else {
1061 compile_asm(tokens, tokcnt);
1062 }
1063 }
1064
1065 if (lineno < 1) {
1066 error("Empty input");
1067 }
1068
1069 if (errors == 0) {
1070 if (verbose) {
1071 (void) fprintf(stderr,
1072 "%d instructions out of 512 assembled\n", pc);
1073 }
1074
1075 if (outfile)
1076 produce_output(outfile);
1077 if (mapfile)
1078 produce_map(mapfile);
1079 if (header)
1080 produce_header(header, prefix);
1081 }
1082
1083 if (errors > 0) {
1084 (void) fprintf(stderr, "%d errors - compile failed\n", errors);
1085 exit(-1);
1086 }
1087
1088 return (0);
1089 }
1090