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