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