codegen-risc5-simple.c (19034B)
1 // Copyright 2020, Brian Swetland <swetland@frotz.net> 2 // Licensed under the Apache License, Version 2.0. 3 4 // ------------------------------------------------------------------ 5 6 #include "risc5.h" 7 8 // R0 is used for returns 9 // R11 is for instruction combo temporary 10 // FP, SB, SP, LR have fixed uses 11 enum { 12 tmp_reg_count = 10, 13 tmp_reg_first = 1, // 8, 14 tmp_reg_last = 10, // 11, 15 }; 16 17 bool is_tmp_reg(u32 n) { 18 return (n >= tmp_reg_first) && (n <= tmp_reg_last); 19 } 20 21 u32 regbits = 0; 22 u32 regcount = 0; 23 24 u32 get_reg_tmp() { 25 u32 n = tmp_reg_first; 26 while (n <= tmp_reg_last) { 27 if (!(regbits & (1 << n))) { 28 regbits |= (1 << n); 29 regcount++; 30 return n; 31 } 32 n++; 33 } 34 error("cannot allocate register"); 35 return 0; 36 } 37 38 void put_reg(u32 r) { 39 if ((r < tmp_reg_first) || (r > tmp_reg_last)) { 40 // currently we don't strictly track r0..r7 41 // they are used for function calls and returns 42 return; 43 } 44 if (!(regbits & (1 << r))) { 45 error("freeing non-allocated register %u\n", r); 46 } 47 regbits = regbits & (~(1 << r)); 48 regcount--; 49 } 50 51 bool is_reg_busy(u32 r) { 52 return regbits & (1 << r); 53 } 54 55 void emit(u32 ins) { 56 ctx.code[ctx.pc / 4] = ins; 57 //gen_trace_code("", ctx.pc); 58 ctx.pc = ctx.pc + 4; 59 } 60 61 enum { 62 R0 = 0, R1 = 1, R2 = 2, R3 = 3, R4 = 4, R5 = 5, R6 = 6, R7 = 7, 63 R8 = 9, R9 = 9, R10 = 10, R11 = 11, FP = 12, SB = 13, SP = 14, LR = 15, 64 TMP = 16 65 }; 66 enum { 67 MOV = 0x0000, LSL = 0x0001, ASR = 0x0002, ROR = 0x0003, 68 AND = 0x0004, ANN = 0x0005, IOR = 0x0006, XOR = 0x0007, 69 ADD = 0x0008, SUB = 0x0009, MUL = 0x000A, DIV = 0x000B, 70 FAD = 0x000C, FSB = 0x000D, FML = 0x000E, FDV = 0x000F, 71 ADC = 0x2008, SBC = 0x2009, UML = 0x200A, 72 MHI = 0x2000, 73 MOV_H = 0x2000, 74 MOV_CC = 0x3000, 75 MOD = 0x001B, // fake op for plumbing (DIV+MOV_H) 76 }; 77 78 void emit_op(u32 op, u32 a, u32 b, u32 c) { 79 if (op == MOD) { 80 emit_op(DIV, a, b, c); 81 emit_op(MOV_H, a, 0, 0); 82 } else { 83 emit((op << 16) | (a << 24) | (b << 20) | c); 84 } 85 } 86 void emit_opi_u16(u32 op, u32 a, u32 b, u32 n) { 87 if (op == MOD) { 88 emit_opi_u16(DIV, a, b, n); 89 emit_op(MOV_H, a, 0, 0); 90 } else { 91 emit(((0x4000 | op) << 16) | (a << 24) | (b << 20) | (n & 0xffff)); 92 } 93 } 94 void emit_mov(u32 dst, u32 src) { 95 if (dst != src) { 96 emit_op(MOV, dst, 0, src); 97 } 98 } 99 100 // mov (load immediate) using the appropriate one or two 101 // instruction form for the immediate argument 102 void emit_movi(u32 a, u32 n) { 103 u32 m = n >> 16; 104 if (m == 0) { 105 emit_opi_u16(MOV, a, 0, n); 106 } else if (m == 0xFFFF) { 107 emit_opi_u16(MOV | 0x1000, a, 0, n); 108 } else { 109 emit_opi_u16(MHI, a, 0, m); 110 if ((n & 0xFFFF) != 0) { 111 emit_opi_u16(IOR, a, a, n); 112 } 113 } 114 } 115 116 // immediate op, using a temporary register and register op if the 117 // immediate argument does not fit the single instruction form 118 void emit_opi(u32 op, u32 a, u32 b, u32 n) { 119 u32 m = n >> 16; 120 if (m == 0) { 121 emit_opi_u16(op, a, b, n); 122 } else if (m == 0xFFFF) { 123 emit_opi_u16(op | 0x1000, a, b, n); 124 } else { 125 emit_opi_u16(MHI, R11, 0, m); 126 if ((n & 0xFFFF) != 0) { 127 emit_opi_u16(IOR, R11, R11, n); 128 } 129 emit_op(op, a, b, R11); 130 } 131 } 132 133 enum { 134 LDW = 8, LDB = 9, STW = 10, STB = 11 135 }; 136 void emit_mem(u32 op, u32 a, u32 b, u32 off) { 137 emit((op << 28) | (a << 24) | (b << 20) | (off & 0xfffff)); 138 } 139 140 enum { 141 MI = 0, EQ = 1, CS = 2, VS = 3, LS = 4, LT = 5, LE = 6, AL = 7, 142 PL = 8, NE = 9, CC = 10, VC = 11, HI = 12, GE = 13, GT = 14, NV = 15, 143 L = 0x10, 144 }; 145 void emit_br(u32 op, u32 r) { 146 emit(((0xC0 | op) << 24) | r); 147 } 148 void emit_bi(u32 op, u32 off) { 149 emit(((0xE0 | op) << 24) | (off & 0xffffff)); 150 } 151 152 u8 rel_op_to_cc_tab[6] = { EQ, NE, LT, LE, GT, GE }; 153 u8 rel_op_to_inv_cc_tab[6] = { NE, EQ, GE, GT, LE, LT }; 154 u32 add_op_to_ins_tab[4] = { ADD, SUB, IOR, XOR }; 155 u32 mul_op_to_ins_tab[6] = { MUL, DIV, MOD, AND, LSL, ASR }; 156 157 // ------------------------------------------------------------------ 158 159 void gen_branch(u32 op, u32 addr) { 160 emit_bi(op, (addr - ctx.pc - 4) >> 2); 161 } 162 163 void gen_branch_fwd(u32 op, Fixup list) { 164 fixup_add_list(list, ctx.pc); 165 emit_bi(op, 0); 166 } 167 168 void gen_branch_sym(u32 op, Symbol sym) { 169 if (sym->flags & SYM_IS_PLACED) { 170 gen_branch(op, sym->value); 171 } else { 172 fixup_add_sym(sym, ctx.pc); 173 emit_bi(op, 0); 174 } 175 } 176 177 // patch branch instruction at addr to 178 // branch to current pc 179 void fixup_branch_fwd(u32 addr) { 180 u32 off = (ctx.pc - addr - 4) >> 2; 181 u32 ins = ctx.code[addr >> 2] & 0xFF000000; 182 ctx.code[addr >> 2] = ins | (off & 0x00FFFFFF); 183 } 184 185 void fixup_branches_fwd(Fixup fixup) { 186 while (fixup != nil) { 187 fixup_branch_fwd(fixup->addr); 188 fixup = fixup->next; 189 } 190 } 191 192 enum { 193 VAL_IMM = 0x0001, // immediate value 194 VAL_REG = 0x0002, // value in register 195 VAL_GLOBAL = 0x0010, // SB offset 196 VAL_PARAM = 0x0020, // FP +offset 197 VAL_LOCAL = 0x0040, // FP -offset 198 VAL_ADDR = 0x0080, // address 199 VAL_RO = 0x1000, // read only 200 VAL_LEFT = 0x00F0, // asignable if non-ro 201 }; 202 203 typedef struct ValRec ValRec; 204 typedef struct ValRec* Val; 205 206 struct ValRec { 207 u32 kind; 208 Type type; 209 u32 n; 210 }; 211 212 u32 loop_continue = 0; 213 Fixup loop_exit = nil; 214 Fixup func_exit = nil; 215 216 void gen_block(Ast node); 217 u32 gen_expr(Ast node); 218 219 Ast err_last_func = nil; 220 Ast err_ast = nil; 221 222 void gen_trace(str msg) { 223 // fprintf(stderr, "%p %p %s\n", err_last_func, err_ast, msg); 224 } 225 226 void gen_src_xref(Ast node) { 227 ctx.xref[ctx.pc/4] = node->srcloc; 228 } 229 230 void dump_error_ctxt() { 231 fprintf(stderr, "\n"); 232 if (err_last_func) { 233 ast_dump(stderr, err_last_func, err_ast); 234 } 235 fprintf(stderr, "\n"); 236 } 237 238 // obtain base register and offset 239 // for the memory backing a Symbol 240 void sym_get_loc(Symbol sym, u32* base, i32* offset) { 241 if (sym->kind == SYM_LOCAL) { 242 *base = FP; 243 *offset = -(4 + sym->value); 244 } else if (sym->kind == SYM_PARAM) { 245 *base = FP; 246 *offset = 8 + sym->value; 247 } else if (sym->kind == SYM_GLOBAL) { 248 *base = SB; 249 *offset = sym->value; 250 } else { 251 error("non-register-relative symbol"); 252 } 253 } 254 255 u32 gen_addr_expr(Ast node) { 256 if (node->kind == AST_DEREF) { 257 u32 r = gen_addr_expr(node->c0); 258 emit_mem(LDW, r, r, 0); 259 return r; 260 } else if (node->kind == AST_INDEX) { 261 u32 esz = node->type->size; 262 u32 raddr = gen_addr_expr(node->c0); 263 u32 roff = gen_expr(node->c1); 264 if (esz > 1) { 265 emit_opi(MUL, roff, roff, esz); 266 } 267 emit_op(ADD, raddr, raddr, roff); 268 put_reg(roff); 269 return raddr; 270 } else if (node->kind == AST_FIELD) { 271 u32 raddr = gen_addr_expr(node->c0); 272 u32 off = node->c1->sym->value; 273 // HANDLE non-word-sized 274 emit_opi(ADD, raddr, raddr, off); 275 return raddr; 276 } else if (node->kind == AST_SYMBOL) { 277 u32 base; 278 i32 offset; 279 sym_get_loc(node->sym, &base, &offset); 280 u32 r = get_reg_tmp(); 281 emit_opi(ADD, r, base, offset); 282 return r; 283 } else if (node->kind == AST_ADDROF) { 284 return gen_addr_expr(node->c0); 285 } else { 286 err_ast = node; 287 error("gen_addr_expr cannot handle %s", ast_kind[node->kind]); 288 } 289 return 0; 290 } 291 292 u32 gen_assign(Ast lhs, Ast expr) { 293 gen_trace("gen_assign()"); 294 295 u32 raddr = gen_addr_expr(lhs); 296 u32 rval = gen_expr(expr); 297 298 if (lhs->type->size == 4) { 299 emit_mem(STW, rval, raddr, 0); 300 } else if (lhs->type->size == 1) { 301 emit_mem(STB, rval, raddr, 0); 302 } else { 303 err_ast = lhs; 304 error("unexpected size %u store", lhs->type->size); 305 } 306 put_reg(raddr); 307 return rval; 308 } 309 310 u32 reg_save(u32 base) { 311 u32 r = tmp_reg_first; 312 u32 n = 0; 313 while (r <= tmp_reg_last) { 314 if (regbits & (1 << r)) { 315 emit_mem(STW, r, SP, base + n); 316 n += 4; 317 } 318 r++; 319 } 320 u32 mask = regbits; 321 regbits = 0; 322 return mask; 323 } 324 325 void reg_restore(u32 base, u32 mask) { 326 if (regbits != 0) { 327 error("register restore collision"); 328 } 329 regbits = mask; 330 u32 r = tmp_reg_first; 331 u32 n = 0; 332 while (r <= tmp_reg_last) { 333 if (regbits & (1 << r)) { 334 emit_mem(LDW, r, SP, base + n); 335 n += 4; 336 } 337 r++; 338 } 339 } 340 341 u32 gen_call(Ast node) { 342 gen_src_xref(node); 343 gen_trace("gen_call()"); 344 Symbol sym = node->c0->sym; 345 Ast arg = node->c2; 346 Symbol param = sym->first; 347 348 if (sym->flags & SYM_IS_BUILTIN) { 349 u32 r = gen_expr(arg); 350 emit_movi(R11, 0xffff0000); 351 emit_mem(STW, r, R11, 0x100 + sym->value * 4); 352 put_reg(r); 353 } else { 354 u32 sizeregs = 4 * regcount; 355 if ((sym->type->len > 0) || (sizeregs > 0)) { 356 u32 sizeargs = 4 * sym->type->len; 357 emit_opi(SUB, SP, SP, sizeregs + sizeargs); 358 u32 mask = reg_save(sizeargs); 359 u32 n = 0; 360 while (arg != nil) { 361 u32 r; 362 if (param->type->kind == TYPE_POINTER) { 363 // XXX or ptr type? 364 r = gen_addr_expr(arg); 365 } else { 366 r = gen_expr(arg); 367 } 368 emit_mem(STW, r, SP, 4 * n); 369 put_reg(r); 370 arg = arg->c2; 371 param = param->next; 372 n = n + 1; 373 } 374 gen_branch_sym(AL|L, sym); 375 reg_restore(sizeargs, mask); 376 emit_opi(ADD, SP, SP, sizeregs + sizeargs); 377 } else { 378 // no args or temporaries to save 379 gen_branch_sym(AL|L, sym); 380 } 381 } 382 // return is in r0, if it exists 383 // stash it somewhere where it won't get stomped 384 // by other calls in this expr 385 u32 r = get_reg_tmp(); 386 emit_mov(r, R0); 387 return r; 388 } 389 390 u32 gen_binop(Ast node, u32 op) { 391 gen_trace( "gen_binop()"); 392 u32 left = gen_expr(node->c0); 393 u32 right = gen_expr(node->c1); 394 u32 res = get_reg_tmp(); 395 emit_op(op, res, left, right); 396 put_reg(left); 397 put_reg(right); 398 return res; 399 } 400 401 u32 gen_relop(Ast node, u32 cc) { 402 gen_trace("gen_relop()"); 403 u32 left = gen_expr(node->c0); 404 u32 right = gen_expr(node->c1); 405 u32 res = get_reg_tmp(); 406 emit_movi(res, 1); 407 emit_op(SUB, left, left, right); 408 gen_branch(cc, ctx.pc + 8); 409 emit_movi(res, 0); 410 put_reg(left); 411 put_reg(right); 412 return res; 413 } 414 415 // returns address of branch to patch 416 u32 gen_branch_if_expr_false(Ast node) { 417 if (ast_kind_is_relop(node->kind)) { 418 u32 cc = rel_op_to_inv_cc_tab[node->kind - AST_EQ]; 419 u32 left = gen_expr(node->c0); 420 u32 right = gen_expr(node->c1); 421 emit_op(SUB, left, left, right); 422 put_reg(left); 423 put_reg(right); 424 u32 addr = ctx.pc; 425 emit_bi(cc, 0); 426 return addr; 427 } else { 428 i32 r = gen_expr(node); 429 emit_mov(R11, r); // set z flag 430 put_reg(r); 431 u32 addr = ctx.pc; 432 emit_bi(EQ, 0); 433 return addr; 434 } 435 } 436 437 u32 gen_short_circuit_op(Ast node, u32 cc, u32 sc) { 438 u32 r = gen_expr(node->c0); 439 emit_mov(R11, r); // set z flag 440 put_reg(r); 441 u32 l0_br_sc = ctx.pc; 442 emit_bi(cc, 0); 443 r = gen_expr(node->c1); 444 emit_mov(R11, r); // set z flag 445 put_reg(r); 446 u32 l1_br_sc = ctx.pc; 447 emit_bi(cc, 0); 448 r = get_reg_tmp(); 449 emit_movi(r, !sc); 450 u32 l2_br_exit = ctx.pc; 451 emit_bi(AL, 0); 452 fixup_branch_fwd(l0_br_sc); 453 fixup_branch_fwd(l1_br_sc); 454 emit_movi(r, sc); 455 fixup_branch_fwd(l2_br_exit); 456 return r; 457 } 458 459 u32 gen_array_read(Ast node) { 460 u32 raddr = gen_addr_expr(node->c0); 461 u32 roff = gen_expr(node->c1); 462 463 u32 sz = node->c0->type->base->size; 464 if (sz > 1) { 465 emit_opi(MUL, roff, roff, sz); 466 } 467 emit_op(ADD, raddr, raddr, roff); 468 if (sz == 1) { 469 emit_mem(LDB, roff, raddr, 0); 470 } else { 471 emit_mem(LDW, roff, raddr, 0); 472 } 473 put_reg(raddr); 474 return roff; 475 } 476 477 u32 gen_struct_read(Ast node) { 478 u32 raddr = gen_addr_expr(node->c0); 479 u32 off = node->c1->sym->value; 480 u32 sz = node->c1->type->size; 481 if (sz == 1) { 482 emit_mem(LDB, raddr, raddr, off); 483 } else if (sz == 4) { 484 emit_mem(LDW, raddr, raddr, off); 485 } else { 486 err_ast = node; 487 error("unsupported field size"); 488 } 489 return raddr; 490 } 491 492 u32 gen_expr(Ast node) { 493 err_ast = node; 494 gen_src_xref(node); 495 gen_trace("gen_expr()"); 496 u32 kind = node->kind; 497 if (kind == AST_CONST) { 498 u32 r = get_reg_tmp(); 499 emit_movi(r, node->ival); 500 return r; 501 } else if (kind == AST_SYMBOL) { 502 u32 r = get_reg_tmp(); 503 // XXX type checking here or before 504 if (node->sym->kind == SYM_CONST) { 505 emit_movi(r, node->sym->value); 506 } else { 507 u32 base; 508 i32 offset; 509 sym_get_loc(node->sym, &base, &offset); 510 emit_mem(LDW, r, base, offset); 511 } 512 return r; 513 } else if (ast_kind_is_relop(kind)) { 514 return gen_relop(node, rel_op_to_cc_tab[kind - AST_EQ]); 515 } else if (ast_kind_is_addop(kind)) { 516 return gen_binop(node, add_op_to_ins_tab[kind - AST_ADD]); 517 } else if (ast_kind_is_mulop(kind)) { 518 return gen_binop(node, mul_op_to_ins_tab[kind - AST_MUL]); 519 } else if (kind == AST_BOOL_OR) { 520 return gen_short_circuit_op(node, NE, 1); 521 } else if (kind == AST_BOOL_AND) { 522 return gen_short_circuit_op(node, EQ, 0); 523 } else if (kind == AST_ASSIGN) { 524 return gen_assign(node->c0, node->c1); 525 } else if (kind == AST_NEG) { 526 u32 r = gen_expr(node->c0); 527 emit_movi(R11, 0); 528 emit_op(SUB, r, R11, r); 529 return r; 530 } else if (kind == AST_NOT) { 531 u32 r = gen_expr(node->c0); 532 emit_opi(XOR, r, r, 0xffffffff); 533 return r; 534 } else if (kind == AST_BOOL_NOT) { 535 u32 r = gen_expr(node->c0); 536 emit_opi(XOR, r, r, r); 537 return r; 538 } else if (kind == AST_CALL) { 539 return gen_call(node); 540 } else if (kind == AST_INDEX) { 541 return gen_array_read(node); 542 } else if (kind == AST_FIELD) { 543 return gen_struct_read(node); 544 } else { 545 error("gen_expr cannot handle %s\n", ast_kind[node->kind]); 546 } 547 return 0; 548 } 549 550 void gen_while(Ast node) { 551 gen_trace("gen_while()"); 552 // save branch targets 553 u32 old_loop_continue = loop_continue; 554 Fixup old_loop_exit = loop_exit; 555 556 FixupRec list; 557 list.next = nil; 558 loop_exit = &list; 559 560 loop_continue = ctx.pc; 561 562 u32 br_false = gen_branch_if_expr_false(node->c0); 563 564 gen_block(node->c1); 565 566 gen_branch(AL, loop_continue); 567 568 // patch branches 569 fixup_branch_fwd(br_false); 570 fixup_branches_fwd(loop_exit->next); 571 572 // restore branch targets 573 loop_continue = old_loop_continue; 574 loop_exit = old_loop_exit; 575 } 576 577 void gen_if_else(Ast node) { 578 // fixups for jumps to the very end 579 FixupRec if_exit; 580 if_exit.next = nil; 581 582 gen_trace("gen_if()"); 583 // IF contains one or more IFELSE nodes 584 node = node->c0; 585 586 // compute if expr 587 // branch ahead if false; 588 u32 l0_br_false = gen_branch_if_expr_false(node->c0); 589 590 // exec then block 591 gen_block(node->c1); 592 593 node = node->c2; 594 while (node != nil) { 595 // jump from end of 'then' block to end 596 gen_branch_fwd(AL, &if_exit); 597 598 // patch false jump (over 'then' block) to here 599 fixup_branch_fwd(l0_br_false); 600 601 if (node->kind == AST_IFELSE) { // ifelse ... 602 gen_trace("gen_ifelse()"); 603 l0_br_false = gen_branch_if_expr_false(node->c0); 604 gen_block(node->c1); 605 node = node->c2; 606 } else { // else ... 607 gen_trace("gen_else()"); 608 gen_block(node); 609 610 // done, patch up earlier jumps to exit 611 fixup_branches_fwd(if_exit.next); 612 return; 613 } 614 } 615 616 // patch false jump (over previous 'then' block) to here 617 fixup_branch_fwd(l0_br_false); 618 619 // done, patch up earlier jumps to exit 620 fixup_branches_fwd(if_exit.next); 621 } 622 623 void gen_block(Ast node); 624 625 void gen_stmt(Ast node) { 626 err_ast = node; 627 gen_src_xref(node); 628 gen_trace("gen_stmt()\n"); 629 u32 kind = node->kind; 630 if (kind == AST_EXPR) { 631 u32 r = gen_expr(node->c0); 632 put_reg(r); 633 } else if (kind == AST_IF) { 634 gen_if_else(node); 635 } else if (kind == AST_WHILE) { 636 gen_while(node); 637 } else if (kind == AST_RETURN) { 638 if (node->c0) { 639 u32 r = gen_expr(node->c0); 640 emit_mov(0, r); 641 put_reg(r); 642 } 643 gen_branch_fwd(AL, func_exit); 644 } else if (kind == AST_BREAK) { 645 gen_branch_fwd(AL, loop_exit); 646 } else if (kind == AST_CONTINUE) { 647 gen_branch(AL, loop_continue); 648 } else if (kind == AST_BLOCK) { 649 gen_block(node); 650 } else { 651 error("gen_stmt cannot handle %s\n", ast_kind[kind]); 652 } 653 } 654 655 void gen_block(Ast node) { 656 gen_trace("gen_block()\n"); 657 gen_src_xref(node); 658 node = node->c2; 659 while (node != nil) { 660 gen_stmt(node); 661 node = node->c2; 662 } 663 } 664 665 // before prologue after prologue 666 // --------------- -------------- 667 // arg2 oldarg2 668 // arg1 oldarg1 669 // FP -> arg0 oldarg0 670 // lrsave oldlr 671 // fpsave oldfp <-+ 672 // loc0 oldloc0 | 673 // loc1 oldloc1 | 674 // ... ... | 675 // locn oldlocn | 676 // callarg2 arg2 | 677 // callarg1 arg1 | 678 // SP -> callarg0 arg0 | 679 // lrsave | 680 // FP -> fpsave ---+ 681 // loc0 682 // loc1 683 // ... 684 // SP -> locn 685 686 void gen_func(Ast node) { 687 err_last_func = node; 688 err_ast = node; 689 690 gen_src_xref(node); 691 gen_trace("gen_func()\n"); 692 693 // local space plus saved lr and fp 694 u32 x = node->sym->type->size + 8; 695 696 node->sym->value = ctx.pc; 697 node->sym->flags |= SYM_IS_PLACED; 698 699 // patch previous calls now that we have an entry address 700 fixup_branches_fwd(node->sym->fixups); 701 node->sym->fixups = nil; // XXX discard 702 703 // generate prologue 704 emit_opi(SUB, SP, SP, x); 705 emit_mem(STW, LR, SP, x - 4); 706 emit_mem(STW, FP, SP, x - 8); 707 emit_opi(ADD, FP, SP, x - 8); 708 709 // setup list of branches-to-epilogue 710 FixupRec list; 711 list.next = nil; 712 func_exit = &list; 713 714 // generate body 715 gen_block(node->c0); 716 717 // patch branches to epilogue 718 fixup_branches_fwd(list.next); 719 720 // generate epilogue 721 emit_mem(LDW, LR, FP, 4); 722 emit_mem(LDW, FP, FP, 0); 723 emit_opi(ADD, SP, SP, x); 724 emit_br(AL, LR); 725 } 726 727 void gen_program(Ast node) { 728 gen_trace( "gen_risc5_simple()\n"); 729 730 emit_movi(SB, 0); // placeholder SB load 731 emit_bi(AL, 0); // placeholder branch to init 732 733 node = node->c2; 734 while (node != nil) { 735 if (node->kind == AST_FUNC) { 736 gen_func(node); 737 } 738 node = node->c2; 739 } 740 741 err_last_func = nil; 742 743 Symbol sym = symbol_find(string_make("start", 5)); 744 if (sym == nil) { 745 error("no 'start' function\n"); 746 } 747 if (sym->type->kind != TYPE_FUNC) { 748 error("'start' is not a function\n"); 749 } 750 if (sym->first != nil) { 751 error("'start' must have no parameters\n"); 752 } 753 754 // patch static base load to after the last instruction 755 ctx.code[0] |= ctx.pc; 756 // patch branch-to-start 757 ctx.code[1] |= (sym->value - 8) >> 2; 758 759 // TODO: copy ro globals after code 760 // TODO: SB should neg-index into ro, pos-index into rw 761 } 762 763 // ================================================================ 764 765 void binary_write(const char* outname) { 766 int fd = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0644); 767 if (fd < 0) { 768 error("cannot open '%s' to write", outname); 769 } 770 u32 n = 0; 771 while (n < ctx.pc) { 772 if (write(fd, ctx.code + (n/4), sizeof(u32)) != sizeof(u32)) { 773 error("error writing '%s'", outname); 774 } 775 n += 4; 776 } 777 n = 0; 778 while (n < ctx.gp) { 779 if (write(fd, ctx.data + (n/4), sizeof(u32)) != sizeof(u32)) { 780 error("error writing '%s'", outname); 781 } 782 n += 4; 783 } 784 close(fd); 785 } 786 787 void listing_write(const char* listfn, const char* srcfn) { 788 FILE* fin = fopen(srcfn, "r"); 789 if (fin == NULL) { 790 error("cannot re-read '%s'\n", srcfn); 791 } 792 FILE* fout = fopen(listfn, "w"); 793 if (fout == NULL) { 794 error("cannot write '%s'\n", listfn); 795 } 796 u32 n = 0; 797 u32 line = 1; 798 char buf[1024]; 799 while (n < ctx.pc) { 800 u32 ins = ctx.code[n/4]; 801 if ((line < ctx.xref[n/4]) && fin) { 802 fprintf(fout, "\n"); 803 while (line < ctx.xref[n/4]) { 804 if (fgets(buf, sizeof(buf), fin) == nil) { 805 fin = nil; 806 break; 807 } 808 u32 i = 0; 809 while (buf[i] != 0) { 810 if (buf[i] > ' ') { 811 fprintf(fout,"%s", buf); 812 break; 813 } 814 i++; 815 } 816 line++; 817 } 818 fprintf(fout, "\n"); 819 } 820 risc5dis(n, ins, buf); 821 fprintf(fout, "%08x: %08x %s\n", n, ins, buf); 822 n += 4; 823 } 824 n = 0; 825 while (n < ctx.gp) { 826 fprintf(fout, "%08x: %08x\n", ctx.pc + n, ctx.data[n >> 2]); 827 n += 4; 828 } 829 fclose(fout); 830 if (fin) { 831 fclose(fin); 832 } 833 }