assemble-sr32.c (16727B)
1 // Copyright 2025, Brian Swetland <swetland@frotz.net> 2 // Licensed under the Apache License, Version 2.0. 3 4 #include <assert.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <stdarg.h> 8 #include <ctype.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include <fcntl.h> 12 13 #include "sr32.h" 14 15 #define RBUFSIZE 4096 16 #define SMAXSIZE 1024 17 18 static unsigned linenumber = 0; 19 static char *filename; 20 21 void die(const char *fmt, ...) { 22 va_list ap; 23 fprintf(stderr,"\n%s:%d: ", filename, linenumber); 24 va_start(ap, fmt); 25 vfprintf(stderr, fmt, ap); 26 va_end(ap); 27 fprintf(stderr,"\n"); 28 exit(1); 29 } 30 31 int is_signed16(uint32_t n) { 32 n &= 0xFFFF0000; 33 return ((n == 0) || (n == 0xFFFF0000)); 34 } 35 int is_signed21(uint32_t n) { 36 n &= 0xFFFFF800; 37 return ((n == 0) || (n == 0xFFFFF800)); 38 } 39 int fits_in_signed16(uint32_t n) { 40 n &= 0xFFFF8000; 41 return ((n == 0) || (n == 0xFFFF8000)); 42 } 43 44 uint8_t image[1*1024*1024]; 45 uint32_t image_base = 0; 46 uint32_t image_size = 0; 47 uint32_t PC = 0; 48 49 void wr32(uint32_t addr, uint32_t val) { 50 addr &= ~3; 51 addr -= image_base; 52 if (addr < image_size) { 53 *((uint32_t*) (image + addr)) = val; 54 } 55 } 56 uint32_t rd32(uint32_t addr) { 57 addr &= ~3; 58 addr -= image_base; 59 if (addr < image_size) { 60 return *((uint32_t*) (image + addr)); 61 } 62 return 0; 63 } 64 void wr8(uint32_t addr, uint32_t val) { 65 addr -= image_base; 66 if (addr < image_size) { 67 image[addr] = val; 68 } 69 } 70 71 #define TYPE_PCREL_S16 1 72 #define TYPE_PCREL_S21 2 73 #define TYPE_ABS_U32 3 74 #define TYPE_ABS_HILO 4 75 #define TYPE_PCREL_HILO 5 76 77 struct fixup { 78 struct fixup *next; 79 unsigned pc; 80 unsigned type; 81 }; 82 83 struct label { 84 struct label *next; 85 struct fixup *fixups; 86 const char *name; 87 unsigned pc; 88 unsigned defined; 89 }; 90 91 struct label *labels; 92 struct fixup *fixups; 93 94 uint32_t do_fixup(const char *name, uint32_t addr, uint32_t tgt, int type) { 95 uint32_t n = tgt; 96 switch(type) { 97 case TYPE_PCREL_S16: 98 n = n - (addr + 4); 99 if (!is_signed16(n)) goto oops; 100 wr32(addr, rd32(addr) | (n << 16)); 101 break; 102 case TYPE_PCREL_S21: 103 n = n - (addr + 4); 104 if (!is_signed21(n)) goto oops; 105 wr32(addr, rd32(addr) | (n << 11)); 106 break; 107 case TYPE_ABS_U32: 108 wr32(addr, n); 109 break; 110 case TYPE_PCREL_HILO: 111 n = n - (addr + 4); 112 case TYPE_ABS_HILO: 113 uint32_t hi = n >> 16; 114 uint32_t lo = n & 0xffff; 115 if (lo & 0x8000) hi += 1; 116 n = (hi << 16) | lo; 117 wr32(addr + 0, rd32(addr + 0) | (hi << 16)); 118 wr32(addr + 4, rd32(addr + 4) | (lo << 16)); 119 break; 120 default: 121 die("unknown branch type %d\n", type); 122 } 123 return n; 124 oops: 125 die("label '%s' at %08x is out of range of %08x\n", name, tgt, addr); 126 return 0; 127 } 128 129 void setlabel(const char *name, unsigned pc) { 130 struct label *l; 131 struct fixup *f; 132 133 for (l = labels; l; l = l->next) { 134 if (!strcasecmp(l->name, name)) { 135 if (l->defined) die("cannot redefine '%s'", name); 136 l->pc = pc; 137 l->defined = 1; 138 for (f = l->fixups; f; f = f->next) { 139 do_fixup(name, f->pc, l->pc, f->type); 140 } 141 return; 142 } 143 } 144 l = malloc(sizeof(*l)); 145 l->name = name; 146 l->pc = pc; 147 l->fixups = 0; 148 l->defined = 1; 149 l->next = labels; 150 labels = l; 151 } 152 153 const char *getlabel(unsigned pc) { 154 struct label *l; 155 for (l = labels; l; l = l->next) 156 if (l->pc == pc) 157 return l->name; 158 return 0; 159 } 160 161 uint32_t uselabel(const char *name, unsigned pc, unsigned type) { 162 struct label *l; 163 struct fixup *f; 164 165 for (l = labels; l; l = l->next) { 166 if (!strcmp(l->name, name)) { 167 if (l->defined) { 168 return do_fixup(name, pc, l->pc, type); 169 } else { 170 goto add_fixup; 171 } 172 } 173 } 174 l = malloc(sizeof(*l)); 175 l->name = strdup(name); 176 l->pc = 0; 177 l->fixups = 0; 178 l->defined = 0; 179 l->next = labels; 180 labels = l; 181 add_fixup: 182 f = malloc(sizeof(*f)); 183 f->pc = pc; 184 f->type = type; 185 f->next = l->fixups; 186 l->fixups = f; 187 return 0; 188 } 189 190 void checklabels(void) { 191 struct label *l; 192 for (l = labels; l; l = l->next) { 193 if (!l->defined) { 194 die("undefined label '%s'", l->name); 195 } 196 } 197 } 198 199 void sr32dis(uint32_t pc, uint32_t ins, char *out); 200 201 void emit(uint32_t instr) { 202 if (PC & 3) { 203 PC = (PC + 3) & ~3; 204 } 205 //fprintf(stderr,"{%08x:%08x} ", PC, instr); 206 wr32(PC, instr); 207 PC += 4; 208 } 209 210 void save(const char *fn) { 211 const char *name; 212 uint32_t n; 213 char dis[128]; 214 215 FILE *fp = fopen(fn, "w"); 216 if (!fp) die("cannot write to '%s'", fn); 217 for (n = image_base; n < PC; n += 4) { 218 uint32_t ins = rd32(n); 219 sr32dis(n, ins, dis); 220 name = getlabel(n); 221 char bs[8] = "000000 "; 222 for (unsigned i = 0; i < 6; i++) { 223 if (ins & (1<<i)) bs[5-i] = '1'; 224 } 225 if (name) { 226 fprintf(fp, "%08x: %08x // %s %-25s <- %s\n", n, ins, bs, dis, name); 227 } else { 228 fprintf(fp, "%08x: %08x // %s %s\n", n, ins, bs, dis); 229 } 230 } 231 fclose(fp); 232 } 233 234 enum tokens { 235 tEOF, tEOL, tIDENT, tREGISTER, tNUMBER, tSTRING, 236 tCOMMA, tCOLON, tOPAREN, tCPAREN, tAT, tDOT, 237 tADD, tSUB, tAND, tOR, tXOR, tSLL, tSRL, tSRA, 238 tSLT, tSLTU, tMUL, tDIV, 239 tADDI, tSUBI, tANDI, tORI, tXORI, tSLLI, tSRLI, tSRAI, 240 tSLTI, tSLTUI, tMULI, tDIVI, 241 tJALR, 242 tBEQ, tBNE, tBLT, tBLTU, tBGE, tBGEU, 243 tLDW, tLDH, tLDB, tLDX, tLUI, tLDHU, tLDBU, tAUIPC, 244 tSTW, tSTH, tSTB, tSTX, 245 tJAL, tSYSCALL, tBREAK, tSYSRET, 246 tNOP, tMV, tLI, tLA, tJ, tJR, tCALL, tRET, 247 tNOT, tNEG, tSEQZ, tSNEZ, tSLTZ, tSGTZ, 248 tBEQZ, tBNEZ, tBLEZ, tBGEZ, tBLTZ, tBGTZ, 249 tBGT, tBLE, tBGTU, tBLEU, 250 tEQU, tBYTE, tHALF, tWORD, 251 NUMTOKENS, 252 }; 253 254 char *tnames[] = { "<EOF>", "<EOL>", "IDENT", "REGISTER", "NUMBER", "STRING", 255 ",", ":", "(", ")", "@", ".", 256 "ADD", "SUB", "AND", "OR", "XOR", "SLL", "SRL", "SRA", 257 "SLT", "SLTU", "MUL", "DIV", 258 "ADDI", "SUBI", "ANDI", "ORI", "XORI", "SLLI", "SRLI", "SRAI", 259 "SLTI", "SLTUI", "MULI", "DIVI", 260 "JALR", 261 "BEQ", "BNE", "BLT", "BLTU", "BGE", "BGEU", 262 "LDW", "LDH", "LDB", "LDX", "LUI", "LDHU", "LDBU", "AUIPC", 263 "STW", "STH", "STB", "STX", 264 "JAL", "SYSCALL", "BREAK", "SYSRET", 265 // pseudo instructions 266 "NOP", "MV", "LI", "LA", "J", "JR", "CALL", "RET", 267 "NOT", "NEG", "SEQZ", "SNEZ", "SLTZ", "SGTZ", 268 "BEQZ", "BNEZ", "BLEZ", "BGEZ", "BLTZ", "BGTZ", 269 "BGT", "BLE", "BGTU", "BLEU", 270 ".EQU", ".BYTE", ".HALF", ".WORD", 271 }; 272 273 static_assert(NUMTOKENS == (sizeof(tnames) / sizeof(tnames[0])), 274 "length of tokens and tnames must be equal"); 275 276 #define FIRSTKEYWORD tDOT 277 278 int is_stopchar(unsigned x) { 279 switch (x) { 280 case 0: case ' ': case '\t': case '\r': case '\n': 281 case '.': case ',': case ':': case ';': case '@': 282 case '#': case '"': case '/': case '(': case ')': 283 return 1; 284 default: 285 return 0; 286 } 287 } 288 289 typedef struct State { 290 char *next; 291 unsigned avail; 292 unsigned tok; 293 unsigned num; 294 char *str; 295 int fd; 296 char rbuf[RBUFSIZE]; 297 char sbuf[SMAXSIZE + 1]; 298 } State; 299 300 static char* rnames[64] = { 301 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", 302 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", 303 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", 304 "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31", 305 "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", 306 "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", 307 "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", 308 "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", 309 }; 310 311 // may be called once after nextchar 312 void pushback(State *state, unsigned ch) { 313 state->avail++; 314 state->next--; 315 *(state->next) = ch; 316 } 317 318 unsigned nextchar(State *state) { 319 for (;;) { 320 if (state->avail) { 321 state->avail--; 322 return *(state->next)++; 323 } else { 324 if (state->fd < 0) { 325 return 0; 326 } 327 state->next = state->rbuf; 328 ssize_t n = read(state->fd, state->rbuf, RBUFSIZE); 329 if (n <= 0) { 330 close(state->fd); 331 state->fd = -1; 332 state->avail = 0; 333 return 0; 334 } else { 335 state->avail = n; 336 } 337 } 338 } 339 } 340 341 unsigned tokenize(State *state) { 342 char *sbuf = state->sbuf; 343 char *s = sbuf; 344 unsigned x, n; 345 346 for (;;) { 347 switch (x = nextchar(state)) { 348 case 0: 349 return tEOF; 350 case ' ': case '\t': case '\r': 351 continue; 352 case '/': 353 if (nextchar(state) != '/') { 354 die("stray /"); 355 } 356 case '#': 357 for (;;) { 358 x = nextchar(state); 359 if ((x == '\n') || (x == 0)) break; 360 } 361 case '\n': 362 linenumber++; 363 return tEOL; 364 case ';': return tEOL; 365 case ',': return tCOMMA; 366 case ':': return tCOLON; 367 case '(': return tOPAREN; 368 case ')': return tCPAREN; 369 case '@': return tAT; 370 case '"': 371 while ((x = nextchar(state)) != '"') { 372 if ((x == '\n') || (x == 0)) { 373 die("unterminated string"); 374 } 375 if ((s - sbuf) == SMAXSIZE) { 376 die("string too long"); 377 } 378 *s++ = x; 379 } 380 *s++ = 0; 381 state->str = sbuf; 382 return tSTRING; 383 } 384 *s++ = x; 385 while (!is_stopchar(x = nextchar(state))) { 386 if ((s - sbuf) == SMAXSIZE) { 387 die("token too long"); 388 } 389 *s++ = x; 390 } 391 *s = 0; 392 pushback(state, x); 393 state->str = sbuf; 394 395 char *end = sbuf; 396 n = strtoul(sbuf, &end, 0); 397 if (*end == '\0') { 398 state->num = n; 399 return tNUMBER; 400 } 401 for (n = 0; n < (sizeof(rnames)/sizeof(rnames[0])); n++) { 402 if (!strcasecmp(sbuf, rnames[n])) { 403 state->str = rnames[n]; 404 state->num = n & 31; 405 return tREGISTER; 406 } 407 } 408 if (isalpha(sbuf[0]) || (sbuf[0] == '.') || (sbuf[0] == '_')) { 409 for (n = FIRSTKEYWORD; n < NUMTOKENS; n++) { 410 if (!strcasecmp(sbuf, tnames[n])) { 411 return n; 412 } 413 } 414 s = sbuf + 1; 415 while (*s) { 416 if (!isalnum(*s) && (*s != '_')) { 417 die("invalid character '%c' (%d) in identifier", *s, *s); 418 } 419 s++; 420 } 421 return tIDENT; 422 } 423 die("invalid character '%c' (%d)", s[0], s[0]); 424 } 425 // impossible 426 return tEOF; 427 } 428 429 unsigned next(State *state) { 430 state->num = 0; 431 state->str = 0; 432 state->tok = tokenize(state); 433 if (state->str == 0) { 434 state->str = tnames[state->tok]; 435 } 436 #if 0 437 if (state->tok == tNUMBER) { 438 fprintf(stderr, "#%08x ", state->num); 439 } else { 440 fprintf(stderr,"%s ", state->str); 441 } 442 if (state->tok == tEOL) fprintf(stderr,"\n"); 443 #endif 444 return state->tok; 445 } 446 447 void expect(State *s, unsigned expected) { 448 if (expected != s->tok) { 449 die("expected %s, got %s", tnames[expected], tnames[s->tok]); 450 } 451 } 452 void require(State *s, unsigned expected) { 453 expect(s, expected); 454 next(s); 455 } 456 457 void parse_reg(State *s, uint32_t *r) { 458 expect(s, tREGISTER); 459 *r = s->num; 460 next(s); 461 } 462 void parse_num(State *s, uint32_t *n) { 463 expect(s, tNUMBER); 464 *n = s->num; 465 next(s); 466 } 467 void parse_memref(State *s, uint32_t *r, uint32_t *i) { 468 if (s->tok == tNUMBER) { 469 *i = s->num; 470 if (next(s) != tOPAREN) { 471 *r = 0; 472 return; 473 } 474 } else { 475 *i = 0; 476 } 477 require(s, tOPAREN); 478 parse_reg(s, r); 479 require(s, tCPAREN); 480 } 481 void parse_rel(State *s, unsigned type, uint32_t *i) { 482 switch (s->tok) { 483 case tIDENT: 484 *i = uselabel(s->str, PC, type); 485 break; 486 case tDOT: 487 *i = -4; 488 break; 489 case tAT: 490 next(s); 491 if ((type == TYPE_PCREL_S16) || (type == TYPE_PCREL_S21)) { 492 expect(s, tNUMBER); 493 *i = (s->num * 4) - 4; 494 break; 495 } 496 default: 497 die("expected address"); 498 } 499 next(s); 500 } 501 502 void parse_r_c(State *s, uint32_t *one) { 503 parse_reg(s, one); 504 require(s, tCOMMA); 505 } 506 void parse_2r(State *s, uint32_t *one, uint32_t *two) { 507 parse_r_c(s, one); 508 parse_reg(s, two); 509 } 510 void parse_2r_c(State *s, uint32_t *one, uint32_t *two) { 511 parse_2r(s, one, two); 512 require(s, tCOMMA); 513 } 514 515 int parse_line(State *s) { 516 uint32_t a, b, t, i, o; 517 char *name; 518 if (s->tok == tIDENT) { 519 name = strdup(s->str); 520 setlabel(name, PC); 521 if (next(s) != tCOLON) { 522 die("unexpected '%s'\n", name); 523 } 524 next(s); 525 } 526 527 unsigned tok = s->tok; 528 next(s); 529 530 switch (tok) { 531 case tADD: case tSUB: case tAND: case tOR: 532 case tXOR: case tSLL: case tSRL: case tSRA: 533 case tSLT: case tSLTU: 534 o = tok - tADD; 535 parse_2r_c(s, &t, &a); 536 parse_reg(s, &b); 537 emit(ins_r(o, t, a, b, 0)); 538 break; 539 case tADDI: case tSUBI: case tANDI: case tORI: 540 case tXORI: case tSLLI: case tSRLI: case tSRAI: 541 case tSLTI: case tSLTUI: 542 o = tok - tADDI; 543 parse_2r_c(s, &t, &a); 544 parse_num(s, &i); 545 emit(ins_i(o, t, a, i)); 546 break; 547 // todo: mul div 548 case tBEQ: case tBNE: case tBLT: 549 case tBLTU: case tBGE: case tBGEU: 550 o = tok - tBEQ; 551 parse_2r_c(s, &a, &b); 552 parse_rel(s, TYPE_PCREL_S16, &i); 553 emit(ins_b(o, a, b, i)); 554 break; 555 case tLDW: case tLDH: case tLDB: case tLDX: 556 case tLDHU: case tLDBU: 557 o = tok - tLDW; 558 parse_r_c(s, &t); 559 parse_memref(s, &a, &i); 560 emit(ins_l(o, t, a, i)); 561 break; 562 case tLUI: 563 case tAUIPC: 564 o = tok - tLDW; 565 parse_r_c(s, &t); 566 parse_num(s, &i); 567 emit(ins_l(o, t, 0, i >> 16)); 568 break; 569 case tSTW: case tSTH: case tSTB: case tSTX: 570 o = tok - tSTW; 571 parse_r_c(s, &b); 572 parse_memref(s, &a, &i); 573 emit(ins_s(o, b, a, i)); 574 break; 575 case tJAL: 576 parse_r_c(s, &t); 577 parse_rel(s, TYPE_PCREL_S21, &i); 578 emit(ins_j(J_JAL, t, i)); 579 break; 580 case tSYSCALL: 581 parse_num(s, &i); 582 emit(ins_j(J_SYSCALL, 0, i)); 583 break; 584 case tBREAK: 585 emit(ins_j(J_BREAK, 0, 0)); 586 break; 587 case tSYSRET: 588 emit(ins_j(J_SYSRET, 0, 0)); 589 break; 590 case tJALR: 591 parse_2r_c(s, &t, &a); 592 if (s->tok == tNUMBER) { 593 emit(ins_i(IR_JALR, t, a, s->num)); 594 } else if (s->tok == tREGISTER) { 595 emit(ins_r(IR_JALR, t, a, s->num, 0)); 596 } else { 597 die("expected register or immediate"); 598 } 599 break; 600 case tNOT: 601 parse_2r(s, &t, &a); 602 emit(ins_i(IR_XOR, t, a, -1)); 603 break; 604 case tNEG: 605 parse_2r(s, &t, &a); 606 emit(ins_r(IR_SUB, t, 0, a, 0)); 607 break; 608 case tSEQZ: 609 parse_2r(s, &t, &a); 610 emit(ins_i(IR_SLTU, t, a, 1)); 611 break; 612 case tSNEZ: 613 parse_2r(s, &t, &a); 614 emit(ins_r(IR_SLTU, t, 0, a, 0)); 615 break; 616 case tSLTZ: 617 parse_2r(s, &t, &a); 618 emit(ins_r(IR_SLT, t, a, 0, 0)); 619 break; 620 case tSGTZ: 621 parse_2r(s, &t, &a); 622 emit(ins_r(IR_SLT, t, 0, a, 0)); 623 break; 624 case tBEQZ: 625 parse_r_c(s, &a); 626 parse_rel(s, TYPE_PCREL_S16, &i); 627 emit(ins_b(B_BEQ, a, 0, i)); 628 break; 629 case tBNEZ: 630 parse_r_c(s, &a); 631 parse_rel(s, TYPE_PCREL_S16, &i); 632 emit(ins_b(B_BNE, a, 0, i)); 633 break; 634 case tBLEZ: 635 parse_r_c(s, &a); 636 parse_rel(s, TYPE_PCREL_S16, &i); 637 emit(ins_b(B_BGE, 0, a, i)); 638 break; 639 case tBGEZ: 640 parse_r_c(s, &a); 641 parse_rel(s, TYPE_PCREL_S16, &i); 642 emit(ins_b(B_BGE, 0, a, i)); 643 break; 644 case tBLTZ: 645 parse_r_c(s, &a); 646 parse_rel(s, TYPE_PCREL_S16, &i); 647 emit(ins_b(B_BLT, a, 0, i)); 648 break; 649 case tBGTZ: 650 parse_r_c(s, &a); 651 parse_rel(s, TYPE_PCREL_S16, &i); 652 emit(ins_b(B_BLT, 0, a, i)); 653 break; 654 case tBGT: 655 parse_2r_c(s, &a, &b); 656 parse_rel(s, TYPE_PCREL_S16, &i); 657 emit(ins_b(B_BLT, b, a, i)); 658 break; 659 case tBLE: 660 parse_2r_c(s, &a, &b); 661 parse_rel(s, TYPE_PCREL_S16, &i); 662 emit(ins_b(B_BGE, b, a, i)); 663 break; 664 case tBGTU: 665 parse_2r_c(s, &a, &b); 666 parse_rel(s, TYPE_PCREL_S16, &i); 667 emit(ins_b(B_BLTU, b, a, i)); 668 break; 669 case tBLEU: 670 parse_2r_c(s, &a, &b); 671 parse_rel(s, TYPE_PCREL_S16, &i); 672 emit(ins_b(B_BGEU, b, a, i)); 673 break; 674 case tJR: 675 parse_reg(s, &a); 676 emit(ins_r(IR_JALR, 0, a, 0, 0)); 677 break; 678 case tRET: 679 emit(ins_r(IR_JALR, 0, 1, 0, 0)); 680 break; 681 case tNOP: 682 emit(ins_i(IR_ADD, 0, 0, 0)); 683 break; 684 case tMV: 685 parse_2r(s, &t, &a); 686 emit(ins_i(IR_ADD, t, a, 0)); 687 break; 688 case tLI: 689 parse_r_c(s, &t); 690 if (s->tok == tIDENT) { 691 parse_rel(s, TYPE_ABS_HILO, &i); 692 } else { 693 parse_num(s, &i); 694 if (fits_in_signed16(i)) { 695 emit(ins_i(IR_ADD, t, 0, i)); 696 } else { 697 uint32_t hi = i >> 16; 698 uint32_t lo = i & 0xffff; 699 if (lo & 0x8000) hi += 1; 700 emit(ins_l(L_LUI, t, 0, hi)); 701 emit(ins_i(IR_ADD, t, t, lo)); 702 } 703 } 704 break; 705 case tLA: 706 parse_r_c(s, &t); 707 parse_rel(s, TYPE_PCREL_HILO, &i); 708 emit(ins_l(L_AUIPC, t, 0, i >> 16)); 709 emit(ins_i(IR_ADD, t, t, i & 0xFFFF)); 710 break; 711 case tJ: 712 parse_rel(s, TYPE_PCREL_S21, &i); 713 emit(ins_j(J_JAL, 0, i)); 714 break; 715 case tCALL: 716 parse_rel(s, TYPE_PCREL_S21, &i); 717 emit(ins_j(J_JAL, 1, i)); 718 break; 719 case tEQU: 720 require(s, tIDENT); 721 name = strdup(s->str); 722 parse_num(s, &i); 723 setlabel(name, i); 724 break; 725 case tWORD: 726 for (;;) { 727 switch (s->tok) { 728 case tNUMBER: 729 emit(s->num); 730 break; 731 case tIDENT: 732 emit(0); 733 uselabel(s->str, PC - 4, TYPE_ABS_U32); 734 break; 735 default: 736 die("expected constant or symbol"); 737 } 738 if (next(s) != tCOMMA) break; 739 next(s); 740 } 741 break; 742 case tBYTE: 743 for (;;) { 744 switch (s->tok) { 745 case tNUMBER: 746 wr8(PC++, s->num); 747 break; 748 case tSTRING: 749 for (char *p = s->str; *p != 0; p++) { 750 wr8(PC++, *p); 751 } 752 break; 753 default: 754 die("expected numeric or string data"); 755 } 756 if (next(s) != tCOMMA) break; 757 next(s); 758 } 759 break; 760 761 // todo: HALF 762 case tEOL: 763 return 1; 764 case tEOF: 765 return 0; 766 } 767 768 require(s, tEOL); 769 return 1; 770 } 771 772 void assemble(const char *fn) { 773 State state; 774 memset(&state, 0, sizeof(state)); 775 state.fd = open(fn, O_RDONLY); 776 if (state.fd < 0) { 777 die("cannot open '%s'", fn); 778 } 779 state.next = state.sbuf; 780 linenumber = 1; 781 next(&state); 782 while (parse_line(&state)) ; 783 } 784 785 int main(int argc, char **argv) { 786 const char *outname = "out.hex"; 787 filename = argv[1]; 788 789 image_base = 0x100000; 790 image_size = sizeof(image); 791 PC = image_base; 792 793 if (argc < 2) { 794 die("no file specified"); 795 } 796 if (argc == 3) { 797 outname = argv[2]; 798 } 799 800 assemble(filename); 801 checklabels(); 802 save(outname); 803 return 0; 804 }