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