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