/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* Assembler for Emu10k1
*/
/*
* Copyright (C) 4Front Technologies 1996-2008.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/param.h>
#define MAX_GPR 256
#define MAX_GPR_PARMS 60
#define MAX_CONST_PARMS 128
#define GPR_NAME_SIZE 32
typedef struct {
char name[GPR_NAME_SIZE];
unsigned int num;
int type;
int def;
} gpr_t;
typedef struct {
unsigned int gpr;
unsigned int value;
} const_t;
typedef struct {
unsigned int ngpr;
gpr_t gpr[MAX_GPR_PARMS];
} gpr_info;
typedef struct {
unsigned int nconst;
const_t consts[MAX_CONST_PARMS];
} const_info;
typedef struct {
unsigned int code[1024];
gpr_info parms;
const_info consts;
int ninit;
struct {
uint32_t gpr;
uint32_t value;
char name[GPR_NAME_SIZE];
} init[MAX_GPR];
} emu10k1_file;
#define MAX_NAME 64
#define MAX_SYMBOLS 1024
static int parms_only = 0;
static int is_audigy = 0;
static int verbose = 0;
static int gpr_base = 0x100;
static int input_base = 0x10;
static int output_base = 0x20;
static char *progname;
typedef struct {
char name[MAX_NAME];
int type;
#define SY_DUMMY 0
#define SY_GPR 1
#define SY_INPUT 2
#define SY_OUTPUT 3
#define SY_CONST 4
#define SY_FX 5
#define SY_ACCUM 6
#define SY_PARM 7
int arg;
} sym_t;
typedef struct {
char *name;
int opcode;
} instruction_t;
static char remarks[2048] = "";
static char *banner =
"/*\n"
" * Note: This file was automatically generated by %s\n"
" * on %s.\n"
" */\n";
/*
* Instructions. Each instruction takes 4 arguments, R, A, X, and Y.
*/
static instruction_t instructions[] = {
{ "MACS", 0x0}, /* R = A + (X * Y >> 31); saturation */
{ "MACS1", 0x1}, /* R = A + (-X * Y >> 31); saturation */
{ "MACW", 0x2}, /* R = A + (X * Y >> 31); wraparound */
{ "MACW1", 0x3}, /* R = A + (-X * Y >> 31); wraparound */
{ "MACINTS", 0x4}, /* R = A + (X * Y); saturation */
{ "MACINTW", 0x5}, /* R = A + (X * Y); wraparound */
{ "SUM", 0x6}, /* R = A + X + Y; saturation */
{ "ACC3", 0x6}, /* R = A + X + Y; saturation */
{ "MACMV", 0x7}, /* R = A, acc += X * Y >> 31 */
{ "ANDXOR", 0x8}, /* R = (A & X) ^ Y */
{ "TSTNEG", 0x9}, /* R = (A >= Y) ? X : ~X */
{ "LIMIT", 0xa}, /* R = (A >= Y) ? X : Y */
{ "LIMIT1", 0xb}, /* R = (A < Y) ? X : Y */
{ "LOG", 0xc}, /* R = ... (log?) */
{ "EXP", 0xd}, /* R = ... (exp?) */
{ "INTERP", 0xe}, /* R = A + (X * (Y - A) >> 31) */
{ "SKIP", 0xf}, /* R, CCR, CC_TEST, COUNT */
{ NULL, 0}
};
#define CHECK_COUNT(tokens, cnt, mincnt, maxcnt) \
if (cnt < mincnt) { \
error("Too few parameters for '%s' (have %d, min %d)", \
tokens[0], cnt - 1, mincnt - 1); \
return; \
} \
if (cnt > maxcnt) { \
error("Too many parameters for '%s' (have %d, max %d)", \
tokens[0], cnt - 1, maxcnt - 1); \
return; \
}
static sym_t symtab[MAX_SYMBOLS];
static int nsyms = 0;
static int lineno = 0, errors = 0;
static emu10k1_file fle;
static int pc;
static int ngpr = 0;
static char *infile;
static int
getaline(FILE *input, char **tokens)
{
char *s, *ls;
static char *stmt = NULL, *lasts = NULL;
static char line[4096];
int cnt, tokcnt;
for (;;) {
if (stmt == NULL) {
if (fgets(line, sizeof (line), input) == NULL)
return (-1);
lineno++;
/*
* Special handling for .' comments. We use
* .' as a keyword to ensure that entire
* comment makes it through the C preprocessor
* unmolested. We also need to make sure *we*
* don't molest it either. The comment will
* be exported to any resulting header,
* allowing us to pass through copyright and
* other information from the source file to
* the resulting header.
*/
s = line;
s += strspn(s, " \t");
if ((strncmp(s, ".'", 2) == 0) &&
(strchr(" \t\n", s[2]) != NULL)) {
/* chop off trailing new line */
(void) strtok(line, "\n");
tokens[0] = s;
s += 2;
s += strspn(s, " \t");
if ((s[0] == '\'') &&
(s[strlen(s) - 1] == '\'')) {
s[strlen(s) - 1] = 0;
s++;
}
tokens[1] = s;
tokens[0][2] = 0;
tokens[2] = NULL;
stmt = NULL;
return (strlen(tokens[1]) ? 2 : 1);
}
/* strip off any C++ style comments that CPP missed */
if ((s = strstr(line, "//")) != NULL) {
*s = '\0';
}
stmt = strtok_r(line, ";\n", &lasts);
} else {
stmt = strtok_r(NULL, ";\n", &lasts);
}
if (stmt != NULL) {
break;
}
}
/*
* Ok, we have a statement, lets tokenize it. For
* simplicities sake we convert "OPCODE(arg1, arg2)" into
* "OPCODE arg1 arg2". This means that commas and parens are
* treated as whitespace. This can lead to some really messed
* up syntaxes that get assembled properly (such as nested
* calls, empty arguments, etc.) Hopefully people don't abuse
* this.
*/
ls = NULL;
s = strtok_r(stmt, " \t\n(),", &ls);
cnt = 0;
tokcnt = 0;
while (cnt < 10) {
tokens[cnt++] = s;
if (s != NULL) {
tokcnt++;
s = strtok_r(NULL, " \t\n(),", &ls);
}
}
return (tokcnt);
}
static void
error(char *msg, ...)
{
va_list va;
char msgbuf[1024];
va_start(va, msg);
(void) vsnprintf(msgbuf, sizeof (msgbuf), msg, va);
va_end(va);
(void) fprintf(stderr, "Error: %s on line %d of %s\n", msgbuf, lineno,
infile);
errors++;
}
static sym_t *
find_symbol(char *name)
{
int i;
for (i = 0; i < nsyms; i++)
if (strcmp(symtab[i].name, name) == 0) {
return (&symtab[i]);
}
return (NULL);
}
static void
add_symbol(char *name, int type, int arg)
{
sym_t *sym;
if (nsyms >= MAX_SYMBOLS) {
error("Symbol table full");
exit(-1);
}
if (find_symbol(name) != NULL) {
error("Dublicate symbol '%s'", name);
return;
}
if (strlen(name) >= MAX_NAME) {
error("Symbol name '%s' too long", name);
exit(-1);
}
sym = &symtab[nsyms++];
(void) strcpy(sym->name, name);
sym->type = type;
sym->arg = arg;
}
static void
add_init(uint32_t gpr, uint32_t val, const char *name)
{
int n;
n = fle.ninit;
if (n >= MAX_GPR) {
error("Too many GPRs");
return;
}
fle.init[n].gpr = gpr;
fle.init[n].value = val;
if (name)
(void) strlcpy(fle.init[n].name, name,
sizeof (fle.init[n].name));
fle.ninit++;
}
static void
compile_gpr(char **tokens, int cnt)
{
CHECK_COUNT(tokens, cnt, 2, 2);
if (ngpr >= MAX_GPR)
error("Too many GPR variables");
add_symbol(tokens[1], SY_GPR, gpr_base + ngpr++);
}
static void
compile_rem(char **tokens, int cnt)
{
int i;
(void) strlcat(remarks, " *", sizeof (remarks));
for (i = 1; i < cnt; i++) {
(void) strlcat(remarks, " ", sizeof (remarks));
(void) strlcat(remarks, tokens[i], sizeof (remarks));
}
(void) strlcat(remarks, "\n", sizeof (remarks));
}
static void
declare_const(unsigned int gpr, char *value)
{
int n, intv;
float v;
n = fle.consts.nconst;
if (n >= MAX_CONST_PARMS) {
error("Too many constant parameters");
return;
}
if (*value == 'I') {
if (sscanf(&value[1], "%g", &v) != 1) {
error("Bad floating point value (%s)", value);
return;
}
intv = (int)v;
} else if (*value == '0' && value[1] == 'x') {
if (sscanf(&value[2], "%x", (unsigned *)&intv) != 1) {
error("Bad hexadecimal value (%s)", value);
return;
}
} else {
if (sscanf(value, "%g", &v) != 1) {
error("Bad floating point value (%s)", value);
return;
}
intv = (int)(v * 0x7fffffff);
}
fle.consts.consts[n].gpr = gpr;
fle.consts.consts[n].value = intv;
fle.consts.nconst = n + 1;
add_init(gpr, intv, NULL);
}
static void
compile_const(char **tokens, int cnt)
{
CHECK_COUNT(tokens, cnt, 2, 3);
char *name = tokens[1];
char *value = tokens[2] ? tokens[2] : tokens[1];
if (ngpr >= MAX_GPR)
error("Too many GPR variables");
declare_const(ngpr, value);
add_symbol(name, SY_GPR, gpr_base + ngpr++);
}
static void
compile_bool(char **tokens, int cnt)
{
char *parm, *def;
int n, num;
CHECK_COUNT(tokens, cnt, 3, 3);
parm = tokens[1];
def = tokens[2];
n = fle.parms.ngpr;
if (n >= MAX_GPR_PARMS) {
error("Too many GPR parameters");
return;
}
if (sscanf(def, "%d", &num) != 1) {
error("Bad integer value near '%s'", def);
return;
}
(void) strcpy(fle.parms.gpr[n].name, parm);
fle.parms.gpr[n].num = ngpr;
fle.parms.gpr[n].def = num;
fle.parms.ngpr = n + 1;
add_init(ngpr, num, parm);
add_symbol(parm, SY_PARM, gpr_base + ngpr++);
}
static void
compile_mono(char **tokens, int cnt)
{
char *parm, *def;
int n, num;
CHECK_COUNT(tokens, cnt, 3, 3);
parm = tokens[1];
def = tokens[2];
n = fle.parms.ngpr;
if (n >= MAX_GPR_PARMS) {
error("Too many GPR parameters");
return;
}
if (sscanf(def, "%d", &num) != 1) {
error("Bad integer value near '%s'", def);
return;
}
(void) strcpy(fle.parms.gpr[n].name, parm);
fle.parms.gpr[n].num = ngpr;
fle.parms.gpr[n].def = num;
fle.parms.ngpr = n + 1;
add_init(ngpr, num, parm);
add_symbol(parm, SY_PARM, gpr_base + ngpr++);
}
static void
compile_stereo(char **tokens, int cnt)
{
char *parm, *def;
int n, num;
char tmp[128];
CHECK_COUNT(tokens, cnt, 3, 3);
parm = tokens[1];
def = tokens[2];
n = fle.parms.ngpr;
if (n >= MAX_GPR_PARMS) {
error("Too many GPR parameters");
return;
}
if (sscanf(def, "%d", &num) != 1) {
error("Bad integer value near '%s'", def);
return;
}
(void) strcpy(fle.parms.gpr[n].name, parm);
fle.parms.gpr[n].num = ngpr;
fle.parms.gpr[n].def = num | (num << 8);
fle.parms.ngpr = n + 1;
add_init(ngpr, num, parm);
add_init(ngpr + 1, num, NULL);
(void) sprintf(tmp, "%s_L", parm);
add_symbol(tmp, SY_PARM, gpr_base + ngpr++);
(void) sprintf(tmp, "%s_R", parm);
add_symbol(tmp, SY_PARM, gpr_base + ngpr++);
}
static void
compile_input(char **tokens, int cnt)
{
int num;
CHECK_COUNT(tokens, cnt, 3, 3);
if (sscanf(tokens[2], "%d", &num) != 1) {
error("Bad integer value near '%s'", tokens[2]);
return;
}
add_symbol(tokens[1], SY_INPUT, input_base + num);
}
static void
compile_send(char **tokens, int cnt)
{
int num;
CHECK_COUNT(tokens, cnt, 3, 3);
if (sscanf(tokens[2], "%d", &num) != 1) {
error("Bad integer near '%s'", tokens[2]);
return;
}
add_symbol(tokens[1], SY_FX, num);
}
static void
compile_output(char **tokens, int cnt)
{
int num;
CHECK_COUNT(tokens, cnt, 3, 3);
if (sscanf(tokens[2], "%d", &num) != 1) {
error("Bad integer value near '%s'", tokens[2]);
return;
}
add_symbol(tokens[1], SY_OUTPUT, output_base + num);
}
static void
compile_directive(char **tokens, int cnt)
{
if (strcmp(tokens[0], ".gpr") == 0) {
compile_gpr(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".const") == 0) {
compile_const(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".stereo") == 0) {
compile_stereo(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".mono") == 0) {
compile_mono(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".bool") == 0) {
compile_bool(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".input") == 0) {
compile_input(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".send") == 0) {
compile_send(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".output") == 0) {
compile_output(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".rem") == 0) {
compile_rem(tokens, cnt);
return;
}
if (strcmp(tokens[0], ".'") == 0) {
compile_rem(tokens, cnt);
return;
}
error("Unknown directive '%s'", tokens[0]);
}
static void
compile_asm(char **tokens, int cnt)
{
sym_t *symbols[4];
#define EMIT(o, r, a, x, y) \
fle.code[pc*2] = ((x) << 10) | (y); \
fle.code[pc*2+1] = ((o) << 20) | ((r) << 10) | a; pc++
#define EMIT_AUDIGY(o, r, a, x, y) \
fle.code[pc*2] = ((x) << 12) | (y); \
fle.code[pc*2+1] = ((o) << 24) | ((r) << 12) | a; pc++
int i, nerr = 0;
int ninputs = 0;
CHECK_COUNT(tokens, cnt, 5, 5);
for (i = 0; i < 4; i++) {
if ((symbols[i] = find_symbol(tokens[i+1])) == NULL) {
(void) fprintf(stderr, "%s\n", tokens[i+1]);
nerr++;
error("Undefined symbol '%s'", tokens[i + 1]);
continue;
}
if (symbols[i]->type == SY_INPUT)
ninputs++;
if (symbols[i]->type == SY_ACCUM && i != 1)
error("Bad usage of 'accum' operand.");
}
if (nerr > 0)
return;
if (ninputs > 1) {
error("Attempt to access more than one input "
"GPRs by the same instruction");
}
for (i = 0; instructions[i].name != NULL; i++)
if (strcasecmp(tokens[0], instructions[i].name) == 0) {
if (is_audigy) {
EMIT_AUDIGY(instructions[i].opcode,
symbols[0]->arg,
symbols[1]->arg,
symbols[2]->arg,
symbols[3]->arg);
} else {
EMIT(instructions[i].opcode,
symbols[0]->arg,
symbols[1]->arg,
symbols[2]->arg,
symbols[3]->arg);
}
return;
}
error("Unrecognized instruction '%s'", tokens[0]);
}
static void
init_compiler(void)
{
char tmp[100];
int i;
(void) memset(&fle, 0, sizeof (fle));
/*
* Initialize few predefined GPR parameter registers. These
* definitions have to be in sync with the GPR_* macros in
* <sblive.h>.
*/
/*
* Make sure we start at gpr id 2 for now; 0 and 1 may be used
* differently.
*/
add_symbol("NULL", SY_DUMMY, gpr_base + ngpr++);
add_symbol("NULL_", SY_DUMMY, gpr_base + ngpr++);
pc = 0;
if (is_audigy) {
/* Initialize the code array with NOPs (AUDIGY) */
for (i = 0; i < 512; i++) {
fle.code[i * 2 + 0] = (0xc0 << 12) | 0xc0;
fle.code[i * 2 + 1] =
(0x06 << 24) | (0xc0 << 12) | 0xc0;
}
for (i = 0; i < 32; i++) {
(void) sprintf(tmp, "fx%d", i);
add_symbol(tmp, SY_FX, i);
}
} else {
/* Initialize the code array with NOPs (LIVE) */
for (i = 0; i < 512; i++) {
fle.code[i * 2 + 0] = 0x10040;
fle.code[i * 2 + 1] = 0x610040;
}
for (i = 0; i < 16; i++) {
(void) sprintf(tmp, "fx%d", i);
add_symbol(tmp, SY_FX, i);
}
}
/*
* Constants
*/
if (is_audigy) {
/* Audigy symbols */
add_symbol("0", SY_CONST, 0x0c0);
add_symbol("1", SY_CONST, 0x0c1);
add_symbol("2", SY_CONST, 0x0c2);
add_symbol("3", SY_CONST, 0x0c3);
add_symbol("4", SY_CONST, 0x0c4);
add_symbol("8", SY_CONST, 0x0c5);
add_symbol("16", SY_CONST, 0x0c6);
add_symbol("32", SY_CONST, 0x0c7);
add_symbol("256", SY_CONST, 0x0c8);
add_symbol("65536", SY_CONST, 0x0c9);
add_symbol("2048", SY_CONST, 0x0ca);
add_symbol("0x800", SY_CONST, 0x0ca);
add_symbol("2^28", SY_CONST, 0x0cb);
add_symbol("0x10000000", SY_CONST, 0x0cb);
add_symbol("2^29", SY_CONST, 0x0cc);
add_symbol("0x20000000", SY_CONST, 0x0cc);
add_symbol("2^30", SY_CONST, 0x0cd);
add_symbol("0x40000000", SY_CONST, 0x0cd);
add_symbol("2^31", SY_CONST, 0x0ce);
add_symbol("0x80000000", SY_CONST, 0x0ce);
add_symbol("0x7fffffff", SY_CONST, 0x0cf);
add_symbol("0xffffffff", SY_CONST, 0x0d0);
add_symbol("-1", SY_CONST, 0x0d0);
add_symbol("0xfffffffe", SY_CONST, 0x0d1);
add_symbol("-2", SY_CONST, 0x0d1);
add_symbol("0xc0000000", SY_CONST, 0x0d2);
add_symbol("0x4f1bbcdc", SY_CONST, 0x0d3);
add_symbol("0x5a7ef9db", SY_CONST, 0x0d4);
add_symbol("0x100000", SY_CONST, 0x0d5);
add_symbol("accum", SY_ACCUM, 0x0d6);
add_symbol("CCR", SY_CONST, 0x0d7);
add_symbol("noise_L", SY_CONST, 0x0d8);
add_symbol("noise_R", SY_CONST, 0x0d9);
add_symbol("IRQREQ", SY_CONST, 0x0da);
} else {
/* SB Live symbols */
add_symbol("0", SY_CONST, 0x040);
add_symbol("1", SY_CONST, 0x041);
add_symbol("2", SY_CONST, 0x042);
add_symbol("3", SY_CONST, 0x043);
add_symbol("4", SY_CONST, 0x044);
add_symbol("8", SY_CONST, 0x045);
add_symbol("16", SY_CONST, 0x046);
add_symbol("32", SY_CONST, 0x047);
add_symbol("256", SY_CONST, 0x048);
add_symbol("65536", SY_CONST, 0x049);
add_symbol("2^23", SY_CONST, 0x04a);
add_symbol("0x80000", SY_CONST, 0x04a);
add_symbol("2^28", SY_CONST, 0x04b);
add_symbol("0x10000000", SY_CONST, 0x04b);
add_symbol("2^29", SY_CONST, 0x04c);
add_symbol("0x20000000", SY_CONST, 0x04c);
add_symbol("2^30", SY_CONST, 0x04d);
add_symbol("0x40000000", SY_CONST, 0x04d);
add_symbol("2^31", SY_CONST, 0x04e);
add_symbol("0x80000000", SY_CONST, 0x04e);
add_symbol("0x7fffffff", SY_CONST, 0x04f);
add_symbol("0xffffffff", SY_CONST, 0x050);
add_symbol("-1", SY_CONST, 0x050);
add_symbol("0xfffffffe", SY_CONST, 0x051);
add_symbol("-2", SY_CONST, 0x051);
add_symbol("accum", SY_ACCUM, 0x056);
add_symbol("CCR", SY_CONST, 0x057);
add_symbol("noise_L", SY_CONST, 0x058);
add_symbol("noise_R", SY_CONST, 0x059);
add_symbol("IRQREQ", SY_CONST, 0x05a);
}
}
static void
produce_map(char *name)
{
int i;
FILE *f;
if ((f = fopen(name, "w")) == NULL) {
perror(name);
return;
}
(void) fprintf(f, "%d\n", pc);
for (i = 0; i < nsyms; i++) {
(void) fprintf(f, "%04x %x %s\n",
symtab[i].arg, symtab[i].type, symtab[i].name);
}
(void) fclose(f);
if (verbose) {
(void) fprintf(stderr,
"No errors detected - Map written to %s\n", name);
}
}
static void
produce_output(char *fname)
{
int fd;
if ((fd = creat(fname, 0644)) == -1) {
perror(fname);
exit(-1);
}
if (write(fd, &fle, sizeof (fle)) != sizeof (fle)) {
perror(fname);
exit(-1);
}
if (verbose) {
(void) fprintf(stderr,
"No errors detected - Binary written to %s\n",
fname);
}
(void) close(fd);
}
static void
produce_header(char *fname, char *prefix)
{
FILE *f;
char *s;
char sname[MAXPATHLEN + 1];
char dname[MAXPATHLEN + 1];
int i;
clock_t now;
char when[128];
/* get basename */
if (prefix == NULL) {
s = strrchr(fname, '/');
s = (s == NULL) ? fname : s + 1;
} else {
s = prefix;
}
(void) strlcpy(sname, s, sizeof (sname));
/* strip off any extension */
s = strchr(sname, '.');
if (s != NULL) {
*s = 0;
}
if ((f = fopen(fname, "w")) == NULL) {
perror(fname);
return;
}
if (remarks[0] != 0) {
(void) fprintf(f, "/*\n%s */\n", remarks);
}
now = time(NULL);
strftime(when, sizeof (when), "%c", localtime(&now));
(void) fprintf(f, banner, progname, when);
(void) strlcpy(dname, prefix ? prefix : sname, sizeof (dname));
for (i = 0; dname[i]; i++) {
dname[i] = toupper(dname[i]);
if (!isalnum(dname[i])) {
dname[i] = '_';
}
}
for (i = 0; i < fle.parms.ngpr; i++) {
(void) fprintf(f, "#define\t%s_%s\t\t%d\n",
dname, fle.parms.gpr[i].name, fle.parms.gpr[i].num);
}
(void) fprintf(f, "\n");
if (parms_only)
goto done;
(void) fprintf(f, "uint32_t %s_code[] = {\n", sname);
for (i = 0; i < pc * 2; i++) {
if (i == 0) {
(void) fprintf(f, "\t0x%08xU", fle.code[i]);
} else if ((i % 4) == 0) {
(void) fprintf(f, ",\n\t0x%08xU", fle.code[i]);
} else {
(void) fprintf(f, ", 0x%08xU", fle.code[i]);
}
}
(void) fprintf(f, "\n};\n");
(void) fprintf(f, "uint32_t %s_ninit = %d;\n", sname, fle.ninit);
(void) fprintf(f, "uint32_t %s_init[] = {\n", sname);
for (i = 0; i < fle.ninit; i++) {
if (fle.init[i].name[0]) {
(void) fprintf(f, "\t%u, 0x%x%s,\t/* %s */\n",
fle.init[i].gpr, fle.init[i].value,
fle.init[i].value >= 0x80000000U ? "U" : "",
fle.init[i].name);
} else {
(void) fprintf(f, "\t%u, 0x%x%s,\n",
fle.init[i].gpr, fle.init[i].value,
fle.init[i].value >= 0x80000000U ? "U" : "");
}
}
(void) fprintf(f, "};\n");
done:
(void) fclose(f);
if (verbose) {
(void) fprintf(stderr,
"No errors detected - Header written to %s\n",
fname);
}
}
int
main(int argc, char *argv[])
{
char *outfile;
int i;
FILE *input;
char *tokens[10];
int tokcnt;
char *mapfile = NULL;
char *header = NULL;
char *prefix = NULL;
outfile = NULL;
infile = NULL;
input = NULL;
progname = argv[0];
while ((i = getopt(argc, argv, "m:h:o:i:P:021v")) != EOF) {
switch (i) {
case 'o':
outfile = optarg;
break;
case 'i':
infile = strdup(optarg);
break;
case 'm':
mapfile = optarg;
break;
case 'P':
prefix = optarg;
break;
case 'h':
header = optarg;
break;
case '0':
parms_only = 1;
break;
case '2':
is_audigy = 1;
break;
case '1':
is_audigy = 0;
break;
case 'v':
verbose++;
break;
default:
(void) fprintf(stderr,
"usage: %s [-m <map>] [-h <header>] "
"[-o <binary>] [-i <source>] [-2|-1]",
progname);
exit(-1);
break;
}
}
if ((outfile == NULL) && (mapfile == NULL) && (header == NULL)) {
outfile = "dsp.bin";
}
if (infile) {
input = fopen(infile, "r");
if (input == NULL) {
perror(infile);
exit(-1);
}
} else {
infile = strdup("<stdin>");
input = stdin;
}
if (is_audigy) {
gpr_base = 0x400;
input_base = 0x40;
output_base = 0x60;
if (verbose)
(void) fprintf(stderr, "Compiling for SB Audigy\n");
} else {
if (verbose)
(void) fprintf(stderr, "Compiling for SB Live\n");
}
init_compiler();
while ((tokcnt = getaline(input, tokens)) != -1) {
/* skip empty lines */
if (tokcnt == 0) {
continue;
}
if (strcmp(tokens[0], "#") == 0) {
int num;
if ((tokcnt >= 3) &&
(sscanf(tokens[1], "%d", &num) == 1)) {
lineno = num;
free(infile);
infile = strdup(tokens[2]);
/* we don't want to count the # directive */
lineno--;
}
/* unknown # directive? muddle on... */
continue;
}
if (*tokens[0] == '.') {
compile_directive(tokens, tokcnt);
} else {
compile_asm(tokens, tokcnt);
}
}
if (lineno < 1) {
error("Empty input");
}
if (errors == 0) {
if (verbose) {
(void) fprintf(stderr,
"%d instructions out of 512 assembled\n", pc);
}
if (outfile)
produce_output(outfile);
if (mapfile)
produce_map(mapfile);
if (header)
produce_header(header, prefix);
}
if (errors > 0) {
(void) fprintf(stderr, "%d errors - compile failed\n", errors);
exit(-1);
}
return (0);
}