1992413f4SGarrett D'Amore /*
2992413f4SGarrett D'Amore  * CDDL HEADER START
3992413f4SGarrett D'Amore  *
4992413f4SGarrett D'Amore  * The contents of this file are subject to the terms of the
5992413f4SGarrett D'Amore  * Common Development and Distribution License (the "License").
6992413f4SGarrett D'Amore  * You may not use this file except in compliance with the License.
7992413f4SGarrett D'Amore  *
8992413f4SGarrett D'Amore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9992413f4SGarrett D'Amore  * or http://www.opensolaris.org/os/licensing.
10992413f4SGarrett D'Amore  * See the License for the specific language governing permissions
11992413f4SGarrett D'Amore  * and limitations under the License.
12992413f4SGarrett D'Amore  *
13992413f4SGarrett D'Amore  * When distributing Covered Code, include this CDDL HEADER in each
14992413f4SGarrett D'Amore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15992413f4SGarrett D'Amore  * If applicable, add the following below this CDDL HEADER, with the
16992413f4SGarrett D'Amore  * fields enclosed by brackets "[]" replaced with your own identifying
17992413f4SGarrett D'Amore  * information: Portions Copyright [yyyy] [name of copyright owner]
18992413f4SGarrett D'Amore  *
19992413f4SGarrett D'Amore  * CDDL HEADER END
20992413f4SGarrett D'Amore  */
21992413f4SGarrett D'Amore 
22992413f4SGarrett D'Amore /*
2323a1cceaSRoger A. Faulkner  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24992413f4SGarrett D'Amore  */
25992413f4SGarrett D'Amore 
26992413f4SGarrett D'Amore /*
27992413f4SGarrett D'Amore  * Assembler for Emu10k1
28992413f4SGarrett D'Amore  */
29992413f4SGarrett D'Amore /*
30992413f4SGarrett D'Amore  * Copyright (C) 4Front Technologies 1996-2008.
31992413f4SGarrett D'Amore  */
32992413f4SGarrett D'Amore 
33992413f4SGarrett D'Amore #include <stdio.h>
34992413f4SGarrett D'Amore #include <stdlib.h>
35992413f4SGarrett D'Amore #include <unistd.h>
36992413f4SGarrett D'Amore #include <fcntl.h>
37992413f4SGarrett D'Amore #include <string.h>
38992413f4SGarrett D'Amore #include <stdarg.h>
39992413f4SGarrett D'Amore #include <ctype.h>
40992413f4SGarrett D'Amore #include <sys/param.h>
41992413f4SGarrett D'Amore 
42992413f4SGarrett D'Amore #define	MAX_GPR	256
43992413f4SGarrett D'Amore #define	MAX_GPR_PARMS	60
44992413f4SGarrett D'Amore #define	MAX_CONST_PARMS	128
45992413f4SGarrett D'Amore #define	GPR_NAME_SIZE 32
46992413f4SGarrett D'Amore 
47992413f4SGarrett D'Amore typedef struct {
48992413f4SGarrett D'Amore 	char name[GPR_NAME_SIZE];
49992413f4SGarrett D'Amore 	unsigned int num;
50992413f4SGarrett D'Amore 	int type;
51992413f4SGarrett D'Amore 	int def;
52992413f4SGarrett D'Amore } gpr_t;
53992413f4SGarrett D'Amore 
54992413f4SGarrett D'Amore typedef struct {
55992413f4SGarrett D'Amore 	unsigned int gpr;
56992413f4SGarrett D'Amore 	unsigned int value;
57992413f4SGarrett D'Amore } const_t;
58992413f4SGarrett D'Amore 
59992413f4SGarrett D'Amore typedef struct {
60992413f4SGarrett D'Amore 	unsigned int ngpr;
61992413f4SGarrett D'Amore 
62992413f4SGarrett D'Amore 	gpr_t gpr[MAX_GPR_PARMS];
63992413f4SGarrett D'Amore } gpr_info;
64992413f4SGarrett D'Amore 
65992413f4SGarrett D'Amore typedef struct {
66992413f4SGarrett D'Amore 	unsigned int nconst;
67992413f4SGarrett D'Amore 
68992413f4SGarrett D'Amore 	const_t consts[MAX_CONST_PARMS];
69992413f4SGarrett D'Amore } const_info;
70992413f4SGarrett D'Amore 
71992413f4SGarrett D'Amore typedef struct {
72992413f4SGarrett D'Amore 	unsigned int code[1024];
73992413f4SGarrett D'Amore 	gpr_info parms;
74992413f4SGarrett D'Amore 	const_info consts;
75992413f4SGarrett D'Amore 	int	ninit;
76992413f4SGarrett D'Amore 	struct {
77992413f4SGarrett D'Amore 		uint32_t	gpr;
78992413f4SGarrett D'Amore 		uint32_t	value;
79992413f4SGarrett D'Amore 		char		name[GPR_NAME_SIZE];
80992413f4SGarrett D'Amore 	} init[MAX_GPR];
81992413f4SGarrett D'Amore } emu10k1_file;
82992413f4SGarrett D'Amore 
83992413f4SGarrett D'Amore #define	MAX_NAME	64
84992413f4SGarrett D'Amore #define	MAX_SYMBOLS	1024
85992413f4SGarrett D'Amore 
86992413f4SGarrett D'Amore static int parms_only = 0;
87992413f4SGarrett D'Amore static int is_audigy = 0;
88992413f4SGarrett D'Amore static int verbose = 0;
89992413f4SGarrett D'Amore 
90992413f4SGarrett D'Amore static int gpr_base = 0x100;
91992413f4SGarrett D'Amore static int input_base = 0x10;
92992413f4SGarrett D'Amore static int output_base = 0x20;
93992413f4SGarrett D'Amore 
94992413f4SGarrett D'Amore static char *progname;
95992413f4SGarrett D'Amore 
96992413f4SGarrett D'Amore typedef struct {
97992413f4SGarrett D'Amore 	char name[MAX_NAME];
98992413f4SGarrett D'Amore 	int type;
99992413f4SGarrett D'Amore #define	SY_DUMMY	0
100992413f4SGarrett D'Amore #define	SY_GPR		1
101992413f4SGarrett D'Amore #define	SY_INPUT	2
102992413f4SGarrett D'Amore #define	SY_OUTPUT	3
103992413f4SGarrett D'Amore #define	SY_CONST	4
104992413f4SGarrett D'Amore #define	SY_FX		5
105992413f4SGarrett D'Amore #define	SY_ACCUM	6
106992413f4SGarrett D'Amore #define	SY_PARM		7
107992413f4SGarrett D'Amore 	int arg;
108992413f4SGarrett D'Amore } sym_t;
109992413f4SGarrett D'Amore 
110992413f4SGarrett D'Amore typedef struct {
111992413f4SGarrett D'Amore 	char *name;
112992413f4SGarrett D'Amore 	int opcode;
113992413f4SGarrett D'Amore } instruction_t;
114992413f4SGarrett D'Amore 
115992413f4SGarrett D'Amore static char remarks[2048] = "";
116992413f4SGarrett D'Amore static char *banner =
117992413f4SGarrett D'Amore 	"/*\n"
118992413f4SGarrett D'Amore 	" * Note: This file was automatically generated by %s\n"
119992413f4SGarrett D'Amore 	" * on %s.\n"
120992413f4SGarrett D'Amore 	" */\n";
121992413f4SGarrett D'Amore 
122992413f4SGarrett D'Amore /*
123992413f4SGarrett D'Amore  * Instructions.  Each instruction takes 4 arguments, R, A, X, and Y.
124992413f4SGarrett D'Amore  */
125992413f4SGarrett D'Amore static instruction_t instructions[] = {
126992413f4SGarrett D'Amore 	{ "MACS",	0x0},	/* R = A + (X * Y >> 31); saturation */
127992413f4SGarrett D'Amore 	{ "MACS1",	0x1},	/* R = A + (-X * Y >> 31); saturation */
128992413f4SGarrett D'Amore 	{ "MACW",	0x2},	/* R = A + (X * Y >> 31); wraparound */
129992413f4SGarrett D'Amore 	{ "MACW1",	0x3},	/* R = A + (-X * Y >> 31); wraparound */
130992413f4SGarrett D'Amore 	{ "MACINTS",	0x4},	/* R = A + (X * Y); saturation */
131992413f4SGarrett D'Amore 	{ "MACINTW",	0x5},	/* R = A + (X * Y); wraparound */
132992413f4SGarrett D'Amore 	{ "SUM",	0x6},	/* R = A + X + Y; saturation */
133992413f4SGarrett D'Amore 	{ "ACC3",	0x6},	/* R = A + X + Y; saturation */
134992413f4SGarrett D'Amore 	{ "MACMV",	0x7},	/* R = A, acc += X * Y >> 31 */
135992413f4SGarrett D'Amore 	{ "ANDXOR",	0x8},	/* R = (A & X) ^ Y */
136992413f4SGarrett D'Amore 	{ "TSTNEG",	0x9},	/* R = (A >= Y) ? X : ~X */
137992413f4SGarrett D'Amore 	{ "LIMIT",	0xa},	/* R = (A >= Y) ? X : Y */
138992413f4SGarrett D'Amore 	{ "LIMIT1",	0xb},	/* R = (A < Y) ? X : Y */
139992413f4SGarrett D'Amore 	{ "LOG",	0xc},	/* R = ... (log?) */
140992413f4SGarrett D'Amore 	{ "EXP",	0xd},	/* R = ... (exp?) */
141992413f4SGarrett D'Amore 	{ "INTERP",	0xe},	/* R = A + (X * (Y - A) >> 31) */
142992413f4SGarrett D'Amore 	{ "SKIP",	0xf},	/* R, CCR, CC_TEST, COUNT */
143992413f4SGarrett D'Amore 	{ NULL, 0}
144992413f4SGarrett D'Amore };
145992413f4SGarrett D'Amore 
146992413f4SGarrett D'Amore #define	CHECK_COUNT(tokens, cnt, mincnt, maxcnt)			\
147992413f4SGarrett D'Amore 	if (cnt < mincnt) {						\
148992413f4SGarrett D'Amore 		error("Too few parameters for '%s' (have %d, min %d)",	\
149992413f4SGarrett D'Amore 		    tokens[0], cnt - 1, mincnt - 1);			\
150992413f4SGarrett D'Amore 		return;							\
151992413f4SGarrett D'Amore 	}								\
152992413f4SGarrett D'Amore 	if (cnt > maxcnt) {						\
153992413f4SGarrett D'Amore 		error("Too many parameters for '%s' (have %d, max %d)",	\
154992413f4SGarrett D'Amore 		    tokens[0], cnt - 1, maxcnt - 1);			\
155992413f4SGarrett D'Amore 		return;							\
156992413f4SGarrett D'Amore 	}
157992413f4SGarrett D'Amore 
158992413f4SGarrett D'Amore static sym_t symtab[MAX_SYMBOLS];
159992413f4SGarrett D'Amore static int nsyms = 0;
160992413f4SGarrett D'Amore 
161992413f4SGarrett D'Amore static int lineno = 0, errors = 0;
162992413f4SGarrett D'Amore static emu10k1_file fle;
163992413f4SGarrett D'Amore static int pc;
164992413f4SGarrett D'Amore 
165992413f4SGarrett D'Amore static int ngpr = 0;
166992413f4SGarrett D'Amore static char *infile;
167992413f4SGarrett D'Amore 
168992413f4SGarrett D'Amore static int
getaline(FILE * input,char ** tokens)16923a1cceaSRoger A. Faulkner getaline(FILE *input, char **tokens)
170992413f4SGarrett D'Amore {
171992413f4SGarrett D'Amore 	char *s, *ls;
172992413f4SGarrett D'Amore 	static char *stmt = NULL, *lasts = NULL;
173992413f4SGarrett D'Amore 	static char line[4096];
174992413f4SGarrett D'Amore 	int cnt, tokcnt;
175992413f4SGarrett D'Amore 
176992413f4SGarrett D'Amore 	for (;;) {
177992413f4SGarrett D'Amore 
178992413f4SGarrett D'Amore 		if (stmt == NULL) {
179992413f4SGarrett D'Amore 			if (fgets(line, sizeof (line), input) == NULL)
180992413f4SGarrett D'Amore 				return (-1);
181992413f4SGarrett D'Amore 			lineno++;
182992413f4SGarrett D'Amore 
183992413f4SGarrett D'Amore 			/*
184992413f4SGarrett D'Amore 			 * Special handling for .' comments.  We use
185992413f4SGarrett D'Amore 			 * .' as a keyword to ensure that entire
186992413f4SGarrett D'Amore 			 * comment makes it through the C preprocessor
187992413f4SGarrett D'Amore 			 * unmolested.  We also need to make sure *we*
188992413f4SGarrett D'Amore 			 * don't molest it either.  The comment will
189992413f4SGarrett D'Amore 			 * be exported to any resulting header,
190992413f4SGarrett D'Amore 			 * allowing us to pass through copyright and
191992413f4SGarrett D'Amore 			 * other information from the source file to
192992413f4SGarrett D'Amore 			 * the resulting header.
193992413f4SGarrett D'Amore 			 */
194992413f4SGarrett D'Amore 			s = line;
195992413f4SGarrett D'Amore 			s += strspn(s, " \t");
196992413f4SGarrett D'Amore 			if ((strncmp(s, ".'", 2) == 0) &&
197992413f4SGarrett D'Amore 			    (strchr(" \t\n", s[2]) != NULL)) {
198992413f4SGarrett D'Amore 				/* chop off trailing new line */
199992413f4SGarrett D'Amore 				(void) strtok(line, "\n");
200992413f4SGarrett D'Amore 				tokens[0] = s;
201992413f4SGarrett D'Amore 				s += 2;
202992413f4SGarrett D'Amore 				s += strspn(s, " \t");
203992413f4SGarrett D'Amore 				if ((s[0] == '\'') &&
204992413f4SGarrett D'Amore 				    (s[strlen(s) - 1] == '\'')) {
205992413f4SGarrett D'Amore 					s[strlen(s) - 1] = 0;
206992413f4SGarrett D'Amore 					s++;
207992413f4SGarrett D'Amore 				}
208992413f4SGarrett D'Amore 				tokens[1] = s;
209992413f4SGarrett D'Amore 				tokens[0][2] = 0;
210992413f4SGarrett D'Amore 				tokens[2] = NULL;
211992413f4SGarrett D'Amore 				stmt = NULL;
212992413f4SGarrett D'Amore 				return (strlen(tokens[1]) ? 2 : 1);
213992413f4SGarrett D'Amore 			}
214992413f4SGarrett D'Amore 
215992413f4SGarrett D'Amore 			/* strip off any C++ style comments that CPP missed */
216992413f4SGarrett D'Amore 			if ((s = strstr(line, "//")) != NULL) {
217bb2183e0SRichard PALO 				*s = '\0';
218992413f4SGarrett D'Amore 			}
219992413f4SGarrett D'Amore 			stmt = strtok_r(line, ";\n", &lasts);
220992413f4SGarrett D'Amore 		} else {
221992413f4SGarrett D'Amore 			stmt = strtok_r(NULL, ";\n", &lasts);
222992413f4SGarrett D'Amore 		}
223992413f4SGarrett D'Amore 
224992413f4SGarrett D'Amore 		if (stmt != NULL) {
225992413f4SGarrett D'Amore 			break;
226992413f4SGarrett D'Amore 		}
227992413f4SGarrett D'Amore 	}
228992413f4SGarrett D'Amore 
229992413f4SGarrett D'Amore 	/*
230992413f4SGarrett D'Amore 	 * Ok, we have a statement, lets tokenize it.  For
231992413f4SGarrett D'Amore 	 * simplicities sake we convert "OPCODE(arg1, arg2)" into
232992413f4SGarrett D'Amore 	 * "OPCODE arg1 arg2".  This means that commas and parens are
233992413f4SGarrett D'Amore 	 * treated as whitespace.  This can lead to some really messed
234992413f4SGarrett D'Amore 	 * up syntaxes that get assembled properly (such as nested
235992413f4SGarrett D'Amore 	 * calls, empty arguments, etc.)  Hopefully people don't abuse
236992413f4SGarrett D'Amore 	 * this.
237992413f4SGarrett D'Amore 	 */
238992413f4SGarrett D'Amore 	ls = NULL;
239992413f4SGarrett D'Amore 	s = strtok_r(stmt, " \t\n(),", &ls);
240992413f4SGarrett D'Amore 	cnt = 0;
241992413f4SGarrett D'Amore 	tokcnt = 0;
242992413f4SGarrett D'Amore 	while (cnt < 10) {
243992413f4SGarrett D'Amore 		tokens[cnt++] = s;
244992413f4SGarrett D'Amore 		if (s != NULL) {
245992413f4SGarrett D'Amore 			tokcnt++;
246992413f4SGarrett D'Amore 			s = strtok_r(NULL, " \t\n(),", &ls);
247992413f4SGarrett D'Amore 		}
248992413f4SGarrett D'Amore 	}
249992413f4SGarrett D'Amore 	return (tokcnt);
250992413f4SGarrett D'Amore }
251992413f4SGarrett D'Amore 
252992413f4SGarrett D'Amore static void
error(char * msg,...)253992413f4SGarrett D'Amore error(char *msg, ...)
254992413f4SGarrett D'Amore {
255992413f4SGarrett D'Amore 	va_list va;
256992413f4SGarrett D'Amore 	char msgbuf[1024];
257992413f4SGarrett D'Amore 
258992413f4SGarrett D'Amore 	va_start(va, msg);
259992413f4SGarrett D'Amore 	(void) vsnprintf(msgbuf, sizeof (msgbuf), msg, va);
260992413f4SGarrett D'Amore 	va_end(va);
261992413f4SGarrett D'Amore 
262992413f4SGarrett D'Amore 	(void) fprintf(stderr, "Error: %s on line %d of %s\n", msgbuf, lineno,
263992413f4SGarrett D'Amore 	    infile);
264992413f4SGarrett D'Amore 	errors++;
265992413f4SGarrett D'Amore }
266992413f4SGarrett D'Amore 
267992413f4SGarrett D'Amore static sym_t *
find_symbol(char * name)268992413f4SGarrett D'Amore find_symbol(char *name)
269992413f4SGarrett D'Amore {
270992413f4SGarrett D'Amore 	int i;
271992413f4SGarrett D'Amore 
272992413f4SGarrett D'Amore 	for (i = 0; i < nsyms; i++)
273992413f4SGarrett D'Amore 		if (strcmp(symtab[i].name, name) == 0) {
274992413f4SGarrett D'Amore 			return (&symtab[i]);
275992413f4SGarrett D'Amore 		}
276992413f4SGarrett D'Amore 
277992413f4SGarrett D'Amore 	return (NULL);
278992413f4SGarrett D'Amore }
279992413f4SGarrett D'Amore 
280992413f4SGarrett D'Amore static void
add_symbol(char * name,int type,int arg)281992413f4SGarrett D'Amore add_symbol(char *name, int type, int arg)
282992413f4SGarrett D'Amore {
283992413f4SGarrett D'Amore 	sym_t *sym;
284992413f4SGarrett D'Amore 
285992413f4SGarrett D'Amore 	if (nsyms >= MAX_SYMBOLS) {
286992413f4SGarrett D'Amore 		error("Symbol table full");
287992413f4SGarrett D'Amore 		exit(-1);
288992413f4SGarrett D'Amore 	}
289992413f4SGarrett D'Amore 
290992413f4SGarrett D'Amore 	if (find_symbol(name) != NULL) {
291992413f4SGarrett D'Amore 		error("Dublicate symbol '%s'", name);
292992413f4SGarrett D'Amore 		return;
293992413f4SGarrett D'Amore 	}
294992413f4SGarrett D'Amore 
295992413f4SGarrett D'Amore 	if (strlen(name) >= MAX_NAME) {
296992413f4SGarrett D'Amore 		error("Symbol name '%s' too long", name);
297992413f4SGarrett D'Amore 		exit(-1);
298992413f4SGarrett D'Amore 	}
299992413f4SGarrett D'Amore 
300992413f4SGarrett D'Amore 	sym = &symtab[nsyms++];
301992413f4SGarrett D'Amore 
302992413f4SGarrett D'Amore 	(void) strcpy(sym->name, name);
303992413f4SGarrett D'Amore 	sym->type = type;
304992413f4SGarrett D'Amore 	sym->arg = arg;
305992413f4SGarrett D'Amore }
306992413f4SGarrett D'Amore 
307992413f4SGarrett D'Amore static void
add_init(uint32_t gpr,uint32_t val,const char * name)308992413f4SGarrett D'Amore add_init(uint32_t gpr, uint32_t val, const char *name)
309992413f4SGarrett D'Amore {
310992413f4SGarrett D'Amore 	int	n;
311992413f4SGarrett D'Amore 
312992413f4SGarrett D'Amore 	n = fle.ninit;
313992413f4SGarrett D'Amore 	if (n >= MAX_GPR) {
314992413f4SGarrett D'Amore 		error("Too many GPRs");
315992413f4SGarrett D'Amore 		return;
316992413f4SGarrett D'Amore 	}
317992413f4SGarrett D'Amore 	fle.init[n].gpr = gpr;
318992413f4SGarrett D'Amore 	fle.init[n].value = val;
319992413f4SGarrett D'Amore 	if (name)
320992413f4SGarrett D'Amore 		(void) strlcpy(fle.init[n].name, name,
321992413f4SGarrett D'Amore 		    sizeof (fle.init[n].name));
322992413f4SGarrett D'Amore 	fle.ninit++;
323992413f4SGarrett D'Amore }
324992413f4SGarrett D'Amore 
325992413f4SGarrett D'Amore static void
compile_gpr(char ** tokens,int cnt)326992413f4SGarrett D'Amore compile_gpr(char **tokens, int cnt)
327992413f4SGarrett D'Amore {
328992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 2, 2);
329992413f4SGarrett D'Amore 
330992413f4SGarrett D'Amore 	if (ngpr >= MAX_GPR)
331992413f4SGarrett D'Amore 		error("Too many GPR variables");
332992413f4SGarrett D'Amore 
333992413f4SGarrett D'Amore 	add_symbol(tokens[1], SY_GPR, gpr_base + ngpr++);
334992413f4SGarrett D'Amore }
335992413f4SGarrett D'Amore 
336992413f4SGarrett D'Amore static void
compile_rem(char ** tokens,int cnt)337992413f4SGarrett D'Amore compile_rem(char **tokens, int cnt)
338992413f4SGarrett D'Amore {
339992413f4SGarrett D'Amore 	int i;
340992413f4SGarrett D'Amore 
341992413f4SGarrett D'Amore 	(void) strlcat(remarks, " *", sizeof (remarks));
342992413f4SGarrett D'Amore 	for (i = 1; i < cnt; i++) {
343992413f4SGarrett D'Amore 		(void) strlcat(remarks, " ", sizeof (remarks));
344992413f4SGarrett D'Amore 		(void) strlcat(remarks, tokens[i], sizeof (remarks));
345992413f4SGarrett D'Amore 	}
346992413f4SGarrett D'Amore 	(void) strlcat(remarks, "\n", sizeof (remarks));
347992413f4SGarrett D'Amore }
348992413f4SGarrett D'Amore 
349992413f4SGarrett D'Amore static void
declare_const(unsigned int gpr,char * value)350992413f4SGarrett D'Amore declare_const(unsigned int gpr, char *value)
351992413f4SGarrett D'Amore {
352992413f4SGarrett D'Amore 	int n, intv;
353992413f4SGarrett D'Amore 	float v;
354992413f4SGarrett D'Amore 
355992413f4SGarrett D'Amore 	n = fle.consts.nconst;
356992413f4SGarrett D'Amore 
357992413f4SGarrett D'Amore 	if (n >= MAX_CONST_PARMS) {
358992413f4SGarrett D'Amore 		error("Too many constant parameters");
359992413f4SGarrett D'Amore 		return;
360992413f4SGarrett D'Amore 	}
361992413f4SGarrett D'Amore 
362992413f4SGarrett D'Amore 	if (*value == 'I') {
363992413f4SGarrett D'Amore 		if (sscanf(&value[1], "%g", &v) != 1) {
364992413f4SGarrett D'Amore 			error("Bad floating point value (%s)", value);
365992413f4SGarrett D'Amore 			return;
366992413f4SGarrett D'Amore 		}
367992413f4SGarrett D'Amore 		intv = (int)v;
368992413f4SGarrett D'Amore 	} else if (*value == '0' && value[1] == 'x') {
369992413f4SGarrett D'Amore 		if (sscanf(&value[2], "%x", (unsigned *)&intv) != 1) {
370992413f4SGarrett D'Amore 			error("Bad hexadecimal value (%s)", value);
371992413f4SGarrett D'Amore 			return;
372992413f4SGarrett D'Amore 		}
373992413f4SGarrett D'Amore 	} else {
374992413f4SGarrett D'Amore 		if (sscanf(value, "%g", &v) != 1) {
375992413f4SGarrett D'Amore 			error("Bad floating point value (%s)", value);
376992413f4SGarrett D'Amore 			return;
377992413f4SGarrett D'Amore 		}
378992413f4SGarrett D'Amore 		intv = (int)(v * 0x7fffffff);
379992413f4SGarrett D'Amore 	}
380992413f4SGarrett D'Amore 
381992413f4SGarrett D'Amore 	fle.consts.consts[n].gpr = gpr;
382992413f4SGarrett D'Amore 	fle.consts.consts[n].value = intv;
383992413f4SGarrett D'Amore 	fle.consts.nconst = n + 1;
384992413f4SGarrett D'Amore 
385992413f4SGarrett D'Amore 	add_init(gpr, intv, NULL);
386992413f4SGarrett D'Amore }
387992413f4SGarrett D'Amore 
388992413f4SGarrett D'Amore static void
compile_const(char ** tokens,int cnt)389992413f4SGarrett D'Amore compile_const(char **tokens, int cnt)
390992413f4SGarrett D'Amore {
391992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 2, 3);
392992413f4SGarrett D'Amore 	char *name = tokens[1];
393992413f4SGarrett D'Amore 	char *value = tokens[2] ? tokens[2] : tokens[1];
394992413f4SGarrett D'Amore 
395992413f4SGarrett D'Amore 	if (ngpr >= MAX_GPR)
396992413f4SGarrett D'Amore 		error("Too many GPR variables");
397992413f4SGarrett D'Amore 
398992413f4SGarrett D'Amore 	declare_const(ngpr, value);
399992413f4SGarrett D'Amore 
400992413f4SGarrett D'Amore 	add_symbol(name, SY_GPR, gpr_base + ngpr++);
401992413f4SGarrett D'Amore }
402992413f4SGarrett D'Amore 
403992413f4SGarrett D'Amore static void
compile_bool(char ** tokens,int cnt)404992413f4SGarrett D'Amore compile_bool(char **tokens, int cnt)
405992413f4SGarrett D'Amore {
406992413f4SGarrett D'Amore 	char *parm, *def;
407992413f4SGarrett D'Amore 	int n, num;
408992413f4SGarrett D'Amore 
409992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 3, 3);
410992413f4SGarrett D'Amore 
411992413f4SGarrett D'Amore 	parm = tokens[1];
412992413f4SGarrett D'Amore 	def = tokens[2];
413992413f4SGarrett D'Amore 
414992413f4SGarrett D'Amore 	n = fle.parms.ngpr;
415992413f4SGarrett D'Amore 	if (n >= MAX_GPR_PARMS) {
416992413f4SGarrett D'Amore 		error("Too many GPR parameters");
417992413f4SGarrett D'Amore 		return;
418992413f4SGarrett D'Amore 	}
419992413f4SGarrett D'Amore 
420992413f4SGarrett D'Amore 	if (sscanf(def, "%d", &num) != 1) {
421992413f4SGarrett D'Amore 		error("Bad integer value near '%s'", def);
422992413f4SGarrett D'Amore 		return;
423992413f4SGarrett D'Amore 	}
424992413f4SGarrett D'Amore 
425992413f4SGarrett D'Amore 	(void) strcpy(fle.parms.gpr[n].name, parm);
426992413f4SGarrett D'Amore 	fle.parms.gpr[n].num = ngpr;
427992413f4SGarrett D'Amore 	fle.parms.gpr[n].def = num;
428992413f4SGarrett D'Amore 	fle.parms.ngpr = n + 1;
429992413f4SGarrett D'Amore 
430992413f4SGarrett D'Amore 	add_init(ngpr, num, parm);
431992413f4SGarrett D'Amore 
432992413f4SGarrett D'Amore 	add_symbol(parm, SY_PARM, gpr_base + ngpr++);
433992413f4SGarrett D'Amore }
434992413f4SGarrett D'Amore 
435992413f4SGarrett D'Amore static void
compile_mono(char ** tokens,int cnt)436992413f4SGarrett D'Amore compile_mono(char **tokens, int cnt)
437992413f4SGarrett D'Amore {
438992413f4SGarrett D'Amore 	char *parm, *def;
439992413f4SGarrett D'Amore 	int n, num;
440992413f4SGarrett D'Amore 
441992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 3, 3);
442992413f4SGarrett D'Amore 
443992413f4SGarrett D'Amore 	parm = tokens[1];
444992413f4SGarrett D'Amore 	def = tokens[2];
445992413f4SGarrett D'Amore 
446992413f4SGarrett D'Amore 	n = fle.parms.ngpr;
447992413f4SGarrett D'Amore 	if (n >= MAX_GPR_PARMS) {
448992413f4SGarrett D'Amore 		error("Too many GPR parameters");
449992413f4SGarrett D'Amore 		return;
450992413f4SGarrett D'Amore 	}
451992413f4SGarrett D'Amore 
452992413f4SGarrett D'Amore 	if (sscanf(def, "%d", &num) != 1) {
453992413f4SGarrett D'Amore 		error("Bad integer value near '%s'", def);
454992413f4SGarrett D'Amore 		return;
455992413f4SGarrett D'Amore 	}
456992413f4SGarrett D'Amore 
457992413f4SGarrett D'Amore 	(void) strcpy(fle.parms.gpr[n].name, parm);
458992413f4SGarrett D'Amore 	fle.parms.gpr[n].num = ngpr;
459992413f4SGarrett D'Amore 	fle.parms.gpr[n].def = num;
460992413f4SGarrett D'Amore 	fle.parms.ngpr = n + 1;
461992413f4SGarrett D'Amore 
462992413f4SGarrett D'Amore 	add_init(ngpr, num, parm);
463992413f4SGarrett D'Amore 
464992413f4SGarrett D'Amore 	add_symbol(parm, SY_PARM, gpr_base + ngpr++);
465992413f4SGarrett D'Amore }
466992413f4SGarrett D'Amore 
467992413f4SGarrett D'Amore static void
compile_stereo(char ** tokens,int cnt)468992413f4SGarrett D'Amore compile_stereo(char **tokens, int cnt)
469992413f4SGarrett D'Amore {
470992413f4SGarrett D'Amore 	char *parm, *def;
471992413f4SGarrett D'Amore 	int n, num;
472992413f4SGarrett D'Amore 	char tmp[128];
473992413f4SGarrett D'Amore 
474992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 3, 3);
475992413f4SGarrett D'Amore 
476992413f4SGarrett D'Amore 	parm = tokens[1];
477992413f4SGarrett D'Amore 	def = tokens[2];
478992413f4SGarrett D'Amore 
479992413f4SGarrett D'Amore 	n = fle.parms.ngpr;
480992413f4SGarrett D'Amore 	if (n >= MAX_GPR_PARMS) {
481992413f4SGarrett D'Amore 		error("Too many GPR parameters");
482992413f4SGarrett D'Amore 		return;
483992413f4SGarrett D'Amore 	}
484992413f4SGarrett D'Amore 
485992413f4SGarrett D'Amore 	if (sscanf(def, "%d", &num) != 1) {
486992413f4SGarrett D'Amore 		error("Bad integer value near '%s'", def);
487992413f4SGarrett D'Amore 		return;
488992413f4SGarrett D'Amore 	}
489992413f4SGarrett D'Amore 
490992413f4SGarrett D'Amore 	(void) strcpy(fle.parms.gpr[n].name, parm);
491992413f4SGarrett D'Amore 	fle.parms.gpr[n].num = ngpr;
492992413f4SGarrett D'Amore 	fle.parms.gpr[n].def = num | (num << 8);
493992413f4SGarrett D'Amore 	fle.parms.ngpr = n + 1;
494992413f4SGarrett D'Amore 
495992413f4SGarrett D'Amore 	add_init(ngpr, num, parm);
496992413f4SGarrett D'Amore 	add_init(ngpr + 1, num, NULL);
497992413f4SGarrett D'Amore 
498992413f4SGarrett D'Amore 	(void) sprintf(tmp, "%s_L", parm);
499992413f4SGarrett D'Amore 	add_symbol(tmp, SY_PARM, gpr_base + ngpr++);
500992413f4SGarrett D'Amore 	(void) sprintf(tmp, "%s_R", parm);
501992413f4SGarrett D'Amore 	add_symbol(tmp, SY_PARM, gpr_base + ngpr++);
502992413f4SGarrett D'Amore }
503992413f4SGarrett D'Amore 
504992413f4SGarrett D'Amore static void
compile_input(char ** tokens,int cnt)505992413f4SGarrett D'Amore compile_input(char **tokens, int cnt)
506992413f4SGarrett D'Amore {
507992413f4SGarrett D'Amore 	int num;
508992413f4SGarrett D'Amore 
509992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 3, 3);
510992413f4SGarrett D'Amore 
511992413f4SGarrett D'Amore 	if (sscanf(tokens[2], "%d", &num) != 1) {
512992413f4SGarrett D'Amore 		error("Bad integer value near '%s'", tokens[2]);
513992413f4SGarrett D'Amore 		return;
514992413f4SGarrett D'Amore 	}
515992413f4SGarrett D'Amore 
516992413f4SGarrett D'Amore 	add_symbol(tokens[1], SY_INPUT, input_base + num);
517992413f4SGarrett D'Amore }
518992413f4SGarrett D'Amore 
519992413f4SGarrett D'Amore static void
compile_send(char ** tokens,int cnt)520992413f4SGarrett D'Amore compile_send(char **tokens, int cnt)
521992413f4SGarrett D'Amore {
522992413f4SGarrett D'Amore 	int num;
523992413f4SGarrett D'Amore 
524992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 3, 3);
525992413f4SGarrett D'Amore 
526992413f4SGarrett D'Amore 	if (sscanf(tokens[2], "%d", &num) != 1) {
527992413f4SGarrett D'Amore 		error("Bad integer near '%s'", tokens[2]);
528992413f4SGarrett D'Amore 		return;
529992413f4SGarrett D'Amore 	}
530992413f4SGarrett D'Amore 
531992413f4SGarrett D'Amore 	add_symbol(tokens[1], SY_FX, num);
532992413f4SGarrett D'Amore }
533992413f4SGarrett D'Amore 
534992413f4SGarrett D'Amore static void
compile_output(char ** tokens,int cnt)535992413f4SGarrett D'Amore compile_output(char **tokens, int cnt)
536992413f4SGarrett D'Amore {
537992413f4SGarrett D'Amore 	int num;
538992413f4SGarrett D'Amore 
539992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 3, 3);
540992413f4SGarrett D'Amore 
541992413f4SGarrett D'Amore 	if (sscanf(tokens[2], "%d", &num) != 1) {
542992413f4SGarrett D'Amore 		error("Bad integer value near '%s'", tokens[2]);
543992413f4SGarrett D'Amore 		return;
544992413f4SGarrett D'Amore 	}
545992413f4SGarrett D'Amore 
546992413f4SGarrett D'Amore 	add_symbol(tokens[1], SY_OUTPUT, output_base + num);
547992413f4SGarrett D'Amore }
548992413f4SGarrett D'Amore 
549992413f4SGarrett D'Amore static void
compile_directive(char ** tokens,int cnt)550992413f4SGarrett D'Amore compile_directive(char **tokens, int cnt)
551992413f4SGarrett D'Amore {
552992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".gpr") == 0) {
553992413f4SGarrett D'Amore 		compile_gpr(tokens, cnt);
554992413f4SGarrett D'Amore 		return;
555992413f4SGarrett D'Amore 	}
556992413f4SGarrett D'Amore 
557992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".const") == 0) {
558992413f4SGarrett D'Amore 		compile_const(tokens, cnt);
559992413f4SGarrett D'Amore 		return;
560992413f4SGarrett D'Amore 	}
561992413f4SGarrett D'Amore 
562992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".stereo") == 0) {
563992413f4SGarrett D'Amore 		compile_stereo(tokens, cnt);
564992413f4SGarrett D'Amore 		return;
565992413f4SGarrett D'Amore 	}
566992413f4SGarrett D'Amore 
567992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".mono") == 0) {
568992413f4SGarrett D'Amore 		compile_mono(tokens, cnt);
569992413f4SGarrett D'Amore 		return;
570992413f4SGarrett D'Amore 	}
571992413f4SGarrett D'Amore 
572992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".bool") == 0) {
573992413f4SGarrett D'Amore 		compile_bool(tokens, cnt);
574992413f4SGarrett D'Amore 		return;
575992413f4SGarrett D'Amore 	}
576992413f4SGarrett D'Amore 
577992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".input") == 0) {
578992413f4SGarrett D'Amore 		compile_input(tokens, cnt);
579992413f4SGarrett D'Amore 		return;
580992413f4SGarrett D'Amore 	}
581992413f4SGarrett D'Amore 
582992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".send") == 0) {
583992413f4SGarrett D'Amore 		compile_send(tokens, cnt);
584992413f4SGarrett D'Amore 		return;
585992413f4SGarrett D'Amore 	}
586992413f4SGarrett D'Amore 
587992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".output") == 0) {
588992413f4SGarrett D'Amore 		compile_output(tokens, cnt);
589992413f4SGarrett D'Amore 		return;
590992413f4SGarrett D'Amore 	}
591992413f4SGarrett D'Amore 
592992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".rem") == 0) {
593992413f4SGarrett D'Amore 		compile_rem(tokens, cnt);
594992413f4SGarrett D'Amore 		return;
595992413f4SGarrett D'Amore 	}
596992413f4SGarrett D'Amore 	if (strcmp(tokens[0], ".'") == 0) {
597992413f4SGarrett D'Amore 		compile_rem(tokens, cnt);
598992413f4SGarrett D'Amore 		return;
599992413f4SGarrett D'Amore 	}
600992413f4SGarrett D'Amore 
601992413f4SGarrett D'Amore 	error("Unknown directive '%s'", tokens[0]);
602992413f4SGarrett D'Amore }
603992413f4SGarrett D'Amore 
604992413f4SGarrett D'Amore static void
compile_asm(char ** tokens,int cnt)605992413f4SGarrett D'Amore compile_asm(char **tokens, int cnt)
606992413f4SGarrett D'Amore {
607992413f4SGarrett D'Amore 	sym_t *symbols[4];
608992413f4SGarrett D'Amore #define	EMIT(o, r, a, x, y) \
609992413f4SGarrett D'Amore 	fle.code[pc*2] =  ((x) << 10) | (y);			\
610992413f4SGarrett D'Amore 	fle.code[pc*2+1] = ((o) << 20) | ((r) << 10) | a; pc++
611992413f4SGarrett D'Amore #define	EMIT_AUDIGY(o, r, a, x, y) \
612992413f4SGarrett D'Amore 	fle.code[pc*2] =  ((x) << 12) | (y);			\
613992413f4SGarrett D'Amore 	fle.code[pc*2+1] = ((o) << 24) | ((r) << 12) | a; pc++
614992413f4SGarrett D'Amore 
615*7f11fd00SRichard Lowe 	int i, nerr = 0;
616992413f4SGarrett D'Amore 	int ninputs = 0;
617992413f4SGarrett D'Amore 
618992413f4SGarrett D'Amore 	CHECK_COUNT(tokens, cnt, 5, 5);
619992413f4SGarrett D'Amore 
620992413f4SGarrett D'Amore 	for (i = 0; i < 4; i++) {
621992413f4SGarrett D'Amore 		if ((symbols[i] = find_symbol(tokens[i+1])) == NULL) {
622992413f4SGarrett D'Amore 			(void) fprintf(stderr, "%s\n", tokens[i+1]);
623992413f4SGarrett D'Amore 			nerr++;
624992413f4SGarrett D'Amore 			error("Undefined symbol '%s'", tokens[i + 1]);
625992413f4SGarrett D'Amore 			continue;
626992413f4SGarrett D'Amore 		}
627992413f4SGarrett D'Amore 
628992413f4SGarrett D'Amore 		if (symbols[i]->type == SY_INPUT)
629992413f4SGarrett D'Amore 			ninputs++;
630992413f4SGarrett D'Amore 
631992413f4SGarrett D'Amore 		if (symbols[i]->type == SY_ACCUM && i != 1)
632992413f4SGarrett D'Amore 			error("Bad usage of 'accum' operand.");
633992413f4SGarrett D'Amore 	}
634992413f4SGarrett D'Amore 
635992413f4SGarrett D'Amore 	if (nerr > 0)
636992413f4SGarrett D'Amore 		return;
637992413f4SGarrett D'Amore 
638992413f4SGarrett D'Amore 	if (ninputs > 1) {
639992413f4SGarrett D'Amore 		error("Attempt to access more than one input "
640992413f4SGarrett D'Amore 		    "GPRs by the same instruction");
641992413f4SGarrett D'Amore 	}
642992413f4SGarrett D'Amore 
643992413f4SGarrett D'Amore 	for (i = 0; instructions[i].name != NULL; i++)
644992413f4SGarrett D'Amore 		if (strcasecmp(tokens[0], instructions[i].name) == 0)  {
645992413f4SGarrett D'Amore 
646992413f4SGarrett D'Amore 			if (is_audigy) {
647992413f4SGarrett D'Amore 				EMIT_AUDIGY(instructions[i].opcode,
648992413f4SGarrett D'Amore 				    symbols[0]->arg,
649992413f4SGarrett D'Amore 				    symbols[1]->arg,
650992413f4SGarrett D'Amore 				    symbols[2]->arg,
651992413f4SGarrett D'Amore 				    symbols[3]->arg);
652992413f4SGarrett D'Amore 			} else {
653992413f4SGarrett D'Amore 				EMIT(instructions[i].opcode,
654992413f4SGarrett D'Amore 				    symbols[0]->arg,
655992413f4SGarrett D'Amore 				    symbols[1]->arg,
656992413f4SGarrett D'Amore 				    symbols[2]->arg,
657992413f4SGarrett D'Amore 				    symbols[3]->arg);
658992413f4SGarrett D'Amore 			}
659992413f4SGarrett D'Amore 
660992413f4SGarrett D'Amore 			return;
661992413f4SGarrett D'Amore 		}
662992413f4SGarrett D'Amore 
663992413f4SGarrett D'Amore 	error("Unrecognized instruction '%s'", tokens[0]);
664992413f4SGarrett D'Amore }
665992413f4SGarrett D'Amore 
666992413f4SGarrett D'Amore static void
init_compiler(void)667992413f4SGarrett D'Amore init_compiler(void)
668992413f4SGarrett D'Amore {
669992413f4SGarrett D'Amore 	char tmp[100];
670992413f4SGarrett D'Amore 	int i;
671992413f4SGarrett D'Amore 
672992413f4SGarrett D'Amore 	(void) memset(&fle, 0, sizeof (fle));
673992413f4SGarrett D'Amore 	/*
674992413f4SGarrett D'Amore 	 * Initialize few predefined GPR parameter registers. These
675992413f4SGarrett D'Amore 	 * definitions have to be in sync with the GPR_* macros in
676992413f4SGarrett D'Amore 	 * <sblive.h>.
677992413f4SGarrett D'Amore 	 */
678992413f4SGarrett D'Amore 
679992413f4SGarrett D'Amore 	/*
680992413f4SGarrett D'Amore 	 * Make sure we start at gpr id 2 for now; 0 and 1 may be used
681992413f4SGarrett D'Amore 	 * differently.
682992413f4SGarrett D'Amore 	 */
683992413f4SGarrett D'Amore 	add_symbol("NULL", SY_DUMMY, gpr_base + ngpr++);
684992413f4SGarrett D'Amore 	add_symbol("NULL_", SY_DUMMY, gpr_base + ngpr++);
685992413f4SGarrett D'Amore 
686992413f4SGarrett D'Amore 	pc = 0;
687992413f4SGarrett D'Amore 
688992413f4SGarrett D'Amore 	if (is_audigy) {
689992413f4SGarrett D'Amore 		/* Initialize the code array with NOPs (AUDIGY) */
690992413f4SGarrett D'Amore 		for (i = 0; i < 512; i++) {
691992413f4SGarrett D'Amore 			fle.code[i * 2 + 0] = (0xc0 << 12) | 0xc0;
692992413f4SGarrett D'Amore 			fle.code[i * 2 + 1] =
693992413f4SGarrett D'Amore 			    (0x06 << 24) | (0xc0 << 12) | 0xc0;
694992413f4SGarrett D'Amore 		}
695992413f4SGarrett D'Amore 
696992413f4SGarrett D'Amore 		for (i = 0; i < 32; i++) {
697992413f4SGarrett D'Amore 			(void) sprintf(tmp, "fx%d", i);
698992413f4SGarrett D'Amore 			add_symbol(tmp, SY_FX, i);
699992413f4SGarrett D'Amore 		}
700992413f4SGarrett D'Amore 	} else {
701992413f4SGarrett D'Amore 		/* Initialize the code array with NOPs (LIVE) */
702992413f4SGarrett D'Amore 		for (i = 0; i < 512; i++) {
703992413f4SGarrett D'Amore 			fle.code[i * 2 + 0] = 0x10040;
704992413f4SGarrett D'Amore 			fle.code[i * 2 + 1] = 0x610040;
705992413f4SGarrett D'Amore 		}
706992413f4SGarrett D'Amore 
707992413f4SGarrett D'Amore 		for (i = 0; i < 16; i++) {
708992413f4SGarrett D'Amore 			(void) sprintf(tmp, "fx%d", i);
709992413f4SGarrett D'Amore 			add_symbol(tmp, SY_FX, i);
710992413f4SGarrett D'Amore 		}
711992413f4SGarrett D'Amore 	}
712992413f4SGarrett D'Amore 
713992413f4SGarrett D'Amore 	/*
714992413f4SGarrett D'Amore 	 * Constants
715992413f4SGarrett D'Amore 	 */
716992413f4SGarrett D'Amore 
717992413f4SGarrett D'Amore 	if (is_audigy) {
718992413f4SGarrett D'Amore 		/* Audigy symbols */
719992413f4SGarrett D'Amore 		add_symbol("0", SY_CONST, 0x0c0);
720992413f4SGarrett D'Amore 		add_symbol("1", SY_CONST, 0x0c1);
721992413f4SGarrett D'Amore 		add_symbol("2", SY_CONST, 0x0c2);
722992413f4SGarrett D'Amore 		add_symbol("3", SY_CONST, 0x0c3);
723992413f4SGarrett D'Amore 		add_symbol("4", SY_CONST, 0x0c4);
724992413f4SGarrett D'Amore 		add_symbol("8", SY_CONST, 0x0c5);
725992413f4SGarrett D'Amore 		add_symbol("16", SY_CONST, 0x0c6);
726992413f4SGarrett D'Amore 		add_symbol("32", SY_CONST, 0x0c7);
727992413f4SGarrett D'Amore 		add_symbol("256", SY_CONST, 0x0c8);
728992413f4SGarrett D'Amore 		add_symbol("65536", SY_CONST, 0x0c9);
729992413f4SGarrett D'Amore 
730992413f4SGarrett D'Amore 		add_symbol("2048", SY_CONST, 0x0ca);
731992413f4SGarrett D'Amore 		add_symbol("0x800", SY_CONST, 0x0ca);
732992413f4SGarrett D'Amore 
733992413f4SGarrett D'Amore 		add_symbol("2^28", SY_CONST, 0x0cb);
734992413f4SGarrett D'Amore 		add_symbol("0x10000000", SY_CONST, 0x0cb);
735992413f4SGarrett D'Amore 
736992413f4SGarrett D'Amore 		add_symbol("2^29", SY_CONST, 0x0cc);
737992413f4SGarrett D'Amore 		add_symbol("0x20000000", SY_CONST, 0x0cc);
738992413f4SGarrett D'Amore 
739992413f4SGarrett D'Amore 		add_symbol("2^30", SY_CONST, 0x0cd);
740992413f4SGarrett D'Amore 		add_symbol("0x40000000", SY_CONST, 0x0cd);
741992413f4SGarrett D'Amore 
742992413f4SGarrett D'Amore 		add_symbol("2^31", SY_CONST, 0x0ce);
743992413f4SGarrett D'Amore 		add_symbol("0x80000000", SY_CONST, 0x0ce);
744992413f4SGarrett D'Amore 
745992413f4SGarrett D'Amore 		add_symbol("0x7fffffff", SY_CONST, 0x0cf);
746992413f4SGarrett D'Amore 
747992413f4SGarrett D'Amore 		add_symbol("0xffffffff", SY_CONST, 0x0d0);
748992413f4SGarrett D'Amore 		add_symbol("-1", SY_CONST, 0x0d0);
749992413f4SGarrett D'Amore 
750992413f4SGarrett D'Amore 		add_symbol("0xfffffffe", SY_CONST, 0x0d1);
751992413f4SGarrett D'Amore 		add_symbol("-2", SY_CONST, 0x0d1);
752992413f4SGarrett D'Amore 
753992413f4SGarrett D'Amore 		add_symbol("0xc0000000", SY_CONST, 0x0d2);
754992413f4SGarrett D'Amore 
755992413f4SGarrett D'Amore 		add_symbol("0x4f1bbcdc", SY_CONST, 0x0d3);
756992413f4SGarrett D'Amore 
757992413f4SGarrett D'Amore 		add_symbol("0x5a7ef9db", SY_CONST, 0x0d4);
758992413f4SGarrett D'Amore 
759992413f4SGarrett D'Amore 		add_symbol("0x100000", SY_CONST, 0x0d5);
760992413f4SGarrett D'Amore 		add_symbol("accum", SY_ACCUM, 0x0d6);
761992413f4SGarrett D'Amore 		add_symbol("CCR", SY_CONST, 0x0d7);
762992413f4SGarrett D'Amore 
763992413f4SGarrett D'Amore 		add_symbol("noise_L", SY_CONST, 0x0d8);
764992413f4SGarrett D'Amore 		add_symbol("noise_R", SY_CONST, 0x0d9);
765992413f4SGarrett D'Amore 		add_symbol("IRQREQ", SY_CONST, 0x0da);
766992413f4SGarrett D'Amore 	} else {
767992413f4SGarrett D'Amore 		/* SB Live symbols */
768992413f4SGarrett D'Amore 		add_symbol("0", SY_CONST, 0x040);
769992413f4SGarrett D'Amore 		add_symbol("1", SY_CONST, 0x041);
770992413f4SGarrett D'Amore 		add_symbol("2", SY_CONST, 0x042);
771992413f4SGarrett D'Amore 		add_symbol("3", SY_CONST, 0x043);
772992413f4SGarrett D'Amore 		add_symbol("4", SY_CONST, 0x044);
773992413f4SGarrett D'Amore 		add_symbol("8", SY_CONST, 0x045);
774992413f4SGarrett D'Amore 		add_symbol("16", SY_CONST, 0x046);
775992413f4SGarrett D'Amore 		add_symbol("32", SY_CONST, 0x047);
776992413f4SGarrett D'Amore 		add_symbol("256", SY_CONST, 0x048);
777992413f4SGarrett D'Amore 		add_symbol("65536", SY_CONST, 0x049);
778992413f4SGarrett D'Amore 
779992413f4SGarrett D'Amore 		add_symbol("2^23", SY_CONST, 0x04a);
780992413f4SGarrett D'Amore 		add_symbol("0x80000", SY_CONST, 0x04a);
781992413f4SGarrett D'Amore 
782992413f4SGarrett D'Amore 		add_symbol("2^28", SY_CONST, 0x04b);
783992413f4SGarrett D'Amore 		add_symbol("0x10000000", SY_CONST, 0x04b);
784992413f4SGarrett D'Amore 
785992413f4SGarrett D'Amore 		add_symbol("2^29", SY_CONST, 0x04c);
786992413f4SGarrett D'Amore 		add_symbol("0x20000000", SY_CONST, 0x04c);
787992413f4SGarrett D'Amore 
788992413f4SGarrett D'Amore 		add_symbol("2^30", SY_CONST, 0x04d);
789992413f4SGarrett D'Amore 		add_symbol("0x40000000", SY_CONST, 0x04d);
790992413f4SGarrett D'Amore 
791992413f4SGarrett D'Amore 		add_symbol("2^31", SY_CONST, 0x04e);
792992413f4SGarrett D'Amore 		add_symbol("0x80000000", SY_CONST, 0x04e);
793992413f4SGarrett D'Amore 
794992413f4SGarrett D'Amore 		add_symbol("0x7fffffff", SY_CONST, 0x04f);
795992413f4SGarrett D'Amore 
796992413f4SGarrett D'Amore 		add_symbol("0xffffffff", SY_CONST, 0x050);
797992413f4SGarrett D'Amore 		add_symbol("-1", SY_CONST, 0x050);
798992413f4SGarrett D'Amore 
799992413f4SGarrett D'Amore 		add_symbol("0xfffffffe", SY_CONST, 0x051);
800992413f4SGarrett D'Amore 		add_symbol("-2", SY_CONST, 0x051);
801992413f4SGarrett D'Amore 
802992413f4SGarrett D'Amore 		add_symbol("accum", SY_ACCUM, 0x056);
803992413f4SGarrett D'Amore 		add_symbol("CCR", SY_CONST, 0x057);
804992413f4SGarrett D'Amore 
805992413f4SGarrett D'Amore 		add_symbol("noise_L", SY_CONST, 0x058);
806992413f4SGarrett D'Amore 		add_symbol("noise_R", SY_CONST, 0x059);
807992413f4SGarrett D'Amore 		add_symbol("IRQREQ", SY_CONST, 0x05a);
808992413f4SGarrett D'Amore 	}
809992413f4SGarrett D'Amore }
810992413f4SGarrett D'Amore 
811992413f4SGarrett D'Amore static void
produce_map(char * name)812992413f4SGarrett D'Amore produce_map(char *name)
813992413f4SGarrett D'Amore {
814992413f4SGarrett D'Amore 	int i;
815992413f4SGarrett D'Amore 	FILE *f;
816992413f4SGarrett D'Amore 
817992413f4SGarrett D'Amore 	if ((f = fopen(name, "w")) == NULL) {
818992413f4SGarrett D'Amore 		perror(name);
819992413f4SGarrett D'Amore 		return;
820992413f4SGarrett D'Amore 	}
821992413f4SGarrett D'Amore 
822992413f4SGarrett D'Amore 	(void) fprintf(f, "%d\n", pc);
823992413f4SGarrett D'Amore 
824992413f4SGarrett D'Amore 	for (i = 0; i < nsyms; i++) {
825992413f4SGarrett D'Amore 		(void) fprintf(f, "%04x %x %s\n",
826992413f4SGarrett D'Amore 		    symtab[i].arg, symtab[i].type, symtab[i].name);
827992413f4SGarrett D'Amore 	}
828992413f4SGarrett D'Amore 
829992413f4SGarrett D'Amore 	(void) fclose(f);
830992413f4SGarrett D'Amore 	if (verbose) {
831992413f4SGarrett D'Amore 		(void) fprintf(stderr,
832992413f4SGarrett D'Amore 		    "No errors detected - Map written to %s\n", name);
833992413f4SGarrett D'Amore 	}
834992413f4SGarrett D'Amore }
835992413f4SGarrett D'Amore 
836992413f4SGarrett D'Amore static void
produce_output(char * fname)837992413f4SGarrett D'Amore produce_output(char *fname)
838992413f4SGarrett D'Amore {
839992413f4SGarrett D'Amore 	int fd;
840992413f4SGarrett D'Amore 
841992413f4SGarrett D'Amore 	if ((fd = creat(fname, 0644)) == -1) {
842992413f4SGarrett D'Amore 		perror(fname);
843992413f4SGarrett D'Amore 		exit(-1);
844992413f4SGarrett D'Amore 	}
845992413f4SGarrett D'Amore 
846992413f4SGarrett D'Amore 	if (write(fd, &fle, sizeof (fle)) != sizeof (fle)) {
847992413f4SGarrett D'Amore 		perror(fname);
848992413f4SGarrett D'Amore 		exit(-1);
849992413f4SGarrett D'Amore 	}
850992413f4SGarrett D'Amore 
851992413f4SGarrett D'Amore 	if (verbose) {
852992413f4SGarrett D'Amore 		(void) fprintf(stderr,
853992413f4SGarrett D'Amore 		    "No errors detected - Binary written to %s\n",
854992413f4SGarrett D'Amore 		    fname);
855992413f4SGarrett D'Amore 	}
856992413f4SGarrett D'Amore 
857992413f4SGarrett D'Amore 	(void) close(fd);
858992413f4SGarrett D'Amore }
859992413f4SGarrett D'Amore 
860992413f4SGarrett D'Amore static void
produce_header(char * fname,char * prefix)861992413f4SGarrett D'Amore produce_header(char *fname, char *prefix)
862992413f4SGarrett D'Amore {
863992413f4SGarrett D'Amore 	FILE *f;
864992413f4SGarrett D'Amore 	char *s;
865992413f4SGarrett D'Amore 	char sname[MAXPATHLEN + 1];
866992413f4SGarrett D'Amore 	char dname[MAXPATHLEN + 1];
867992413f4SGarrett D'Amore 	int i;
868992413f4SGarrett D'Amore 	clock_t now;
869992413f4SGarrett D'Amore 	char when[128];
870992413f4SGarrett D'Amore 
871992413f4SGarrett D'Amore 	/* get basename */
872992413f4SGarrett D'Amore 	if (prefix == NULL) {
873992413f4SGarrett D'Amore 		s = strrchr(fname, '/');
874992413f4SGarrett D'Amore 		s = (s == NULL) ? fname : s + 1;
875992413f4SGarrett D'Amore 	} else {
876992413f4SGarrett D'Amore 		s = prefix;
877992413f4SGarrett D'Amore 	}
878992413f4SGarrett D'Amore 	(void) strlcpy(sname, s, sizeof (sname));
879992413f4SGarrett D'Amore 
880992413f4SGarrett D'Amore 	/* strip off any extension */
881992413f4SGarrett D'Amore 	s = strchr(sname, '.');
882992413f4SGarrett D'Amore 	if (s != NULL) {
883992413f4SGarrett D'Amore 		*s = 0;
884992413f4SGarrett D'Amore 	}
885992413f4SGarrett D'Amore 	if ((f = fopen(fname, "w")) == NULL) {
886992413f4SGarrett D'Amore 		perror(fname);
887992413f4SGarrett D'Amore 		return;
888992413f4SGarrett D'Amore 	}
889992413f4SGarrett D'Amore 
890992413f4SGarrett D'Amore 	if (remarks[0] != 0) {
891992413f4SGarrett D'Amore 		(void) fprintf(f, "/*\n%s */\n", remarks);
892992413f4SGarrett D'Amore 	}
893992413f4SGarrett D'Amore 	now = time(NULL);
894992413f4SGarrett D'Amore 	strftime(when, sizeof (when), "%c", localtime(&now));
895992413f4SGarrett D'Amore 	(void) fprintf(f, banner, progname, when);
896992413f4SGarrett D'Amore 
897992413f4SGarrett D'Amore 	(void) strlcpy(dname, prefix ? prefix : sname, sizeof (dname));
898992413f4SGarrett D'Amore 	for (i = 0; dname[i]; i++) {
899992413f4SGarrett D'Amore 		dname[i] = toupper(dname[i]);
900992413f4SGarrett D'Amore 		if (!isalnum(dname[i])) {
901992413f4SGarrett D'Amore 			dname[i] = '_';
902992413f4SGarrett D'Amore 		}
903992413f4SGarrett D'Amore 	}
904992413f4SGarrett D'Amore 
905992413f4SGarrett D'Amore 	for (i = 0; i < fle.parms.ngpr; i++) {
906992413f4SGarrett D'Amore 		(void) fprintf(f, "#define\t%s_%s\t\t%d\n",
907992413f4SGarrett D'Amore 		    dname, fle.parms.gpr[i].name, fle.parms.gpr[i].num);
908992413f4SGarrett D'Amore 	}
909992413f4SGarrett D'Amore 
910992413f4SGarrett D'Amore 	(void) fprintf(f, "\n");
911992413f4SGarrett D'Amore 
912992413f4SGarrett D'Amore 	if (parms_only)
913992413f4SGarrett D'Amore 		goto done;
914992413f4SGarrett D'Amore 
915992413f4SGarrett D'Amore 	(void) fprintf(f, "uint32_t %s_code[] = {\n", sname);
916992413f4SGarrett D'Amore 
917992413f4SGarrett D'Amore 	for (i = 0; i < pc * 2; i++) {
918992413f4SGarrett D'Amore 		if (i == 0) {
919992413f4SGarrett D'Amore 			(void) fprintf(f, "\t0x%08xU", fle.code[i]);
920992413f4SGarrett D'Amore 		} else if ((i % 4) == 0) {
921992413f4SGarrett D'Amore 			(void) fprintf(f, ",\n\t0x%08xU", fle.code[i]);
922992413f4SGarrett D'Amore 		} else {
923992413f4SGarrett D'Amore 			(void) fprintf(f, ", 0x%08xU", fle.code[i]);
924992413f4SGarrett D'Amore 		}
925992413f4SGarrett D'Amore 	}
926992413f4SGarrett D'Amore 	(void) fprintf(f, "\n};\n");
927992413f4SGarrett D'Amore 
928992413f4SGarrett D'Amore 	(void) fprintf(f, "uint32_t %s_ninit = %d;\n", sname, fle.ninit);
929992413f4SGarrett D'Amore 	(void) fprintf(f, "uint32_t %s_init[] = {\n", sname);
930992413f4SGarrett D'Amore 
931992413f4SGarrett D'Amore 	for (i = 0; i < fle.ninit; i++) {
932992413f4SGarrett D'Amore 		if (fle.init[i].name[0]) {
933992413f4SGarrett D'Amore 			(void) fprintf(f, "\t%u, 0x%x%s,\t/* %s */\n",
934992413f4SGarrett D'Amore 			    fle.init[i].gpr, fle.init[i].value,
935992413f4SGarrett D'Amore 			    fle.init[i].value >= 0x80000000U ? "U" : "",
936992413f4SGarrett D'Amore 			    fle.init[i].name);
937992413f4SGarrett D'Amore 		} else {
938992413f4SGarrett D'Amore 			(void) fprintf(f, "\t%u, 0x%x%s,\n",
939992413f4SGarrett D'Amore 			    fle.init[i].gpr, fle.init[i].value,
940992413f4SGarrett D'Amore 			    fle.init[i].value >= 0x80000000U ? "U" : "");
941992413f4SGarrett D'Amore 		}
942992413f4SGarrett D'Amore 	}
943992413f4SGarrett D'Amore 	(void) fprintf(f, "};\n");
944992413f4SGarrett D'Amore 
945992413f4SGarrett D'Amore done:
946992413f4SGarrett D'Amore 	(void) fclose(f);
947992413f4SGarrett D'Amore 	if (verbose) {
948992413f4SGarrett D'Amore 		(void) fprintf(stderr,
949992413f4SGarrett D'Amore 		    "No errors detected - Header written to %s\n",
950992413f4SGarrett D'Amore 		    fname);
951992413f4SGarrett D'Amore 	}
952992413f4SGarrett D'Amore }
953992413f4SGarrett D'Amore 
954992413f4SGarrett D'Amore int
main(int argc,char * argv[])955992413f4SGarrett D'Amore main(int argc, char *argv[])
956992413f4SGarrett D'Amore {
957*7f11fd00SRichard Lowe 	char *outfile;
958992413f4SGarrett D'Amore 	int i;
959992413f4SGarrett D'Amore 	FILE *input;
960992413f4SGarrett D'Amore 	char *tokens[10];
961992413f4SGarrett D'Amore 	int tokcnt;
962992413f4SGarrett D'Amore 	char *mapfile = NULL;
963992413f4SGarrett D'Amore 	char *header = NULL;
964992413f4SGarrett D'Amore 	char *prefix = NULL;
965992413f4SGarrett D'Amore 
966992413f4SGarrett D'Amore 	outfile = NULL;
967992413f4SGarrett D'Amore 	infile = NULL;
968992413f4SGarrett D'Amore 	input = NULL;
969992413f4SGarrett D'Amore 	progname = argv[0];
970992413f4SGarrett D'Amore 
971992413f4SGarrett D'Amore 	while ((i = getopt(argc, argv, "m:h:o:i:P:021v")) != EOF) {
972992413f4SGarrett D'Amore 		switch (i) {
973992413f4SGarrett D'Amore 		case 'o':
974992413f4SGarrett D'Amore 			outfile = optarg;
975992413f4SGarrett D'Amore 			break;
976992413f4SGarrett D'Amore 		case 'i':
977992413f4SGarrett D'Amore 			infile = strdup(optarg);
978992413f4SGarrett D'Amore 			break;
979992413f4SGarrett D'Amore 		case 'm':
980992413f4SGarrett D'Amore 			mapfile = optarg;
981992413f4SGarrett D'Amore 			break;
982992413f4SGarrett D'Amore 		case 'P':
983992413f4SGarrett D'Amore 			prefix = optarg;
984992413f4SGarrett D'Amore 			break;
985992413f4SGarrett D'Amore 		case 'h':
986992413f4SGarrett D'Amore 			header = optarg;
987992413f4SGarrett D'Amore 			break;
988992413f4SGarrett D'Amore 		case '0':
989992413f4SGarrett D'Amore 			parms_only = 1;
990992413f4SGarrett D'Amore 			break;
991992413f4SGarrett D'Amore 		case '2':
992992413f4SGarrett D'Amore 			is_audigy = 1;
993992413f4SGarrett D'Amore 			break;
994992413f4SGarrett D'Amore 		case '1':
995992413f4SGarrett D'Amore 			is_audigy = 0;
996992413f4SGarrett D'Amore 			break;
997992413f4SGarrett D'Amore 		case 'v':
998992413f4SGarrett D'Amore 			verbose++;
999992413f4SGarrett D'Amore 			break;
1000992413f4SGarrett D'Amore 		default:
1001992413f4SGarrett D'Amore 			(void) fprintf(stderr,
1002992413f4SGarrett D'Amore 			    "usage: %s [-m <map>] [-h <header>] "
1003992413f4SGarrett D'Amore 			    "[-o <binary>] [-i <source>] [-2|-1]",
1004992413f4SGarrett D'Amore 			    progname);
1005992413f4SGarrett D'Amore 			exit(-1);
1006992413f4SGarrett D'Amore 			break;
1007992413f4SGarrett D'Amore 		}
1008992413f4SGarrett D'Amore 	}
1009992413f4SGarrett D'Amore 
1010992413f4SGarrett D'Amore 	if ((outfile == NULL) && (mapfile == NULL) && (header == NULL)) {
1011992413f4SGarrett D'Amore 		outfile = "dsp.bin";
1012992413f4SGarrett D'Amore 	}
1013992413f4SGarrett D'Amore 
1014992413f4SGarrett D'Amore 	if (infile) {
1015992413f4SGarrett D'Amore 		input = fopen(infile, "r");
1016992413f4SGarrett D'Amore 		if (input == NULL) {
1017992413f4SGarrett D'Amore 			perror(infile);
1018992413f4SGarrett D'Amore 			exit(-1);
1019992413f4SGarrett D'Amore 		}
1020992413f4SGarrett D'Amore 	} else {
1021992413f4SGarrett D'Amore 		infile = strdup("<stdin>");
1022992413f4SGarrett D'Amore 		input = stdin;
1023992413f4SGarrett D'Amore 	}
1024992413f4SGarrett D'Amore 
1025992413f4SGarrett D'Amore 	if (is_audigy) {
1026992413f4SGarrett D'Amore 		gpr_base = 0x400;
1027992413f4SGarrett D'Amore 		input_base = 0x40;
1028992413f4SGarrett D'Amore 		output_base = 0x60;
1029992413f4SGarrett D'Amore 		if (verbose)
1030992413f4SGarrett D'Amore 			(void) fprintf(stderr, "Compiling for SB Audigy\n");
1031992413f4SGarrett D'Amore 	} else {
1032992413f4SGarrett D'Amore 		if (verbose)
1033992413f4SGarrett D'Amore 			(void) fprintf(stderr, "Compiling for SB Live\n");
1034992413f4SGarrett D'Amore 	}
1035992413f4SGarrett D'Amore 
1036992413f4SGarrett D'Amore 	init_compiler();
1037992413f4SGarrett D'Amore 
103823a1cceaSRoger A. Faulkner 	while ((tokcnt = getaline(input, tokens)) != -1) {
1039992413f4SGarrett D'Amore 		/* skip empty lines */
1040992413f4SGarrett D'Amore 		if (tokcnt == 0) {
1041992413f4SGarrett D'Amore 			continue;
1042992413f4SGarrett D'Amore 		}
1043992413f4SGarrett D'Amore 
1044992413f4SGarrett D'Amore 		if (strcmp(tokens[0], "#") == 0) {
1045992413f4SGarrett D'Amore 			int	num;
1046992413f4SGarrett D'Amore 			if ((tokcnt >= 3) &&
1047992413f4SGarrett D'Amore 			    (sscanf(tokens[1], "%d", &num) == 1)) {
1048992413f4SGarrett D'Amore 				lineno = num;
1049992413f4SGarrett D'Amore 				free(infile);
1050992413f4SGarrett D'Amore 				infile = strdup(tokens[2]);
1051992413f4SGarrett D'Amore 				/* we don't want to count the # directive */
1052992413f4SGarrett D'Amore 				lineno--;
1053992413f4SGarrett D'Amore 			}
1054992413f4SGarrett D'Amore 
1055992413f4SGarrett D'Amore 			/* unknown # directive? muddle on... */
1056992413f4SGarrett D'Amore 			continue;
1057992413f4SGarrett D'Amore 		}
1058992413f4SGarrett D'Amore 		if (*tokens[0] == '.') {
1059992413f4SGarrett D'Amore 			compile_directive(tokens, tokcnt);
1060992413f4SGarrett D'Amore 		} else {
1061992413f4SGarrett D'Amore 			compile_asm(tokens, tokcnt);
1062992413f4SGarrett D'Amore 		}
1063992413f4SGarrett D'Amore 	}
1064992413f4SGarrett D'Amore 
1065992413f4SGarrett D'Amore 	if (lineno < 1) {
1066992413f4SGarrett D'Amore 		error("Empty input");
1067992413f4SGarrett D'Amore 	}
1068992413f4SGarrett D'Amore 
1069992413f4SGarrett D'Amore 	if (errors == 0) {
1070992413f4SGarrett D'Amore 		if (verbose) {
1071992413f4SGarrett D'Amore 			(void) fprintf(stderr,
1072992413f4SGarrett D'Amore 			    "%d instructions out of 512 assembled\n", pc);
1073992413f4SGarrett D'Amore 		}
1074992413f4SGarrett D'Amore 
1075992413f4SGarrett D'Amore 		if (outfile)
1076992413f4SGarrett D'Amore 			produce_output(outfile);
1077992413f4SGarrett D'Amore 		if (mapfile)
1078992413f4SGarrett D'Amore 			produce_map(mapfile);
1079992413f4SGarrett D'Amore 		if (header)
1080992413f4SGarrett D'Amore 			produce_header(header, prefix);
1081992413f4SGarrett D'Amore 	}
1082992413f4SGarrett D'Amore 
1083992413f4SGarrett D'Amore 	if (errors > 0) {
1084992413f4SGarrett D'Amore 		(void) fprintf(stderr, "%d errors - compile failed\n", errors);
1085992413f4SGarrett D'Amore 		exit(-1);
1086992413f4SGarrett D'Amore 	}
1087992413f4SGarrett D'Amore 
1088992413f4SGarrett D'Amore 	return (0);
1089992413f4SGarrett D'Amore }
1090