asm10k.c revision 10914:185115acf63e
1178479Sjb/*
2178479Sjb * CDDL HEADER START
3178479Sjb *
4178479Sjb * The contents of this file are subject to the terms of the
5178479Sjb * Common Development and Distribution License (the "License").
6178479Sjb * You may not use this file except in compliance with the License.
7178479Sjb *
8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178479Sjb * or http://www.opensolaris.org/os/licensing.
10178479Sjb * See the License for the specific language governing permissions
11178479Sjb * and limitations under the License.
12178479Sjb *
13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178479Sjb * If applicable, add the following below this CDDL HEADER, with the
16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178479Sjb *
19178479Sjb * CDDL HEADER END
20178479Sjb */
21178479Sjb
22256002Spfg/*
23178479Sjb * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24178479Sjb * Use is subject to license terms.
25178479Sjb */
26178479Sjb
27178479Sjb/*
28256002Spfg * Assembler for Emu10k1
29256002Spfg */
30256002Spfg/*
31256002Spfg * Copyright (C) 4Front Technologies 1996-2008.
32178479Sjb */
33178479Sjb
34178479Sjb#include <stdio.h>
35178479Sjb#include <stdlib.h>
36178479Sjb#include <unistd.h>
37178479Sjb#include <fcntl.h>
38178479Sjb#include <string.h>
39178479Sjb#include <stdarg.h>
40178479Sjb#include <ctype.h>
41178479Sjb#include <sys/param.h>
42178479Sjb
43178479Sjb#define	MAX_GPR	256
44178479Sjb#define	MAX_GPR_PARMS	60
45178479Sjb#define	MAX_CONST_PARMS	128
46178479Sjb#define	GPR_NAME_SIZE 32
47178479Sjb
48178479Sjbtypedef struct {
49178479Sjb	char name[GPR_NAME_SIZE];
50178479Sjb	unsigned int num;
51256002Spfg	int type;
52178479Sjb	int def;
53178479Sjb} gpr_t;
54178479Sjb
55178479Sjbtypedef struct {
56178479Sjb	unsigned int gpr;
57178479Sjb	unsigned int value;
58} const_t;
59
60typedef struct {
61	unsigned int ngpr;
62
63	gpr_t gpr[MAX_GPR_PARMS];
64} gpr_info;
65
66typedef struct {
67	unsigned int nconst;
68
69	const_t consts[MAX_CONST_PARMS];
70} const_info;
71
72typedef 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
87static int parms_only = 0;
88static int is_audigy = 0;
89static int verbose = 0;
90
91static int gpr_base = 0x100;
92static int input_base = 0x10;
93static int output_base = 0x20;
94
95static char *progname;
96
97typedef 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
111typedef struct {
112	char *name;
113	int opcode;
114} instruction_t;
115
116static char remarks[2048] = "";
117static 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 */
126static 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
159static sym_t symtab[MAX_SYMBOLS];
160static int nsyms = 0;
161
162static int lineno = 0, errors = 0;
163static emu10k1_file fle;
164static int pc;
165
166static int ngpr = 0;
167static char *infile;
168
169static int
170getline(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
253static void
254error(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
268static sym_t *
269find_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
281static void
282add_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
308static void
309add_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
326static void
327compile_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
337static void
338compile_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
350static void
351declare_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
389static void
390compile_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
404static void
405compile_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
436static void
437compile_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
469static void
470compile_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
506static void
507compile_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
521static void
522compile_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
536static void
537compile_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
551static void
552compile_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
606static void
607compile_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
669static void
670init_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
814static void
815produce_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
840static void
841produce_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
864static void
865produce_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
949done:
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
958int
959main(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