xref: /titanic_52/usr/src/uts/common/io/audio/drv/audioemu10k/dsp/asm10k.c (revision 7f11fd00fc23e2af7ae21cc8837a2b86380dcfa7)
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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