commit 777ee77e05570b7ff8864cbf1352d71741d96737
parent 24cdd328a68688a3f1c0c319d53650fc45461a8c
Author: Brian Swetland <swetland@frotz.net>
Date: Wed, 1 Dec 2021 22:20:54 -0800
compiler2: progress on the simple/stupid code generator
- We're walking the AST tree and generating output.
- Everything's partially in place (a little expr processing,
a little flow control, etc)
- Some simple test cases compile correctly
Diffstat:
4 files changed, 586 insertions(+), 20 deletions(-)
diff --git a/Makefile b/Makefile
@@ -22,9 +22,9 @@ bin/compiler: src/compiler.c src/risc5dis.c out/risc5ins.h
@mkdir -p bin
$(CC) -o $@ $(CFLAGS) -Wno-unused-result -DC src/compiler.c src/risc5dis.c
-bin/compiler2: src/compiler2.c
+bin/compiler2: src/compiler2.c src/codegen-risc5-simple.c src/risc5dis.c out/risc5ins.h
@mkdir -p bin
- $(CC) -o $@ $(CFLAGS) -Wno-unused-result -DC src/compiler2.c
+ $(CC) -o $@ $(CFLAGS) -Wno-unused-result -DC src/compiler2.c src/risc5dis.c
bin/rewriter: src/rewriter.c
@mkdir -p bin
diff --git a/src/codegen-risc5-simple.c b/src/codegen-risc5-simple.c
@@ -0,0 +1,468 @@
+// Copyright 2020, Brian Swetland <swetland@frotz.net>
+// Licensed under the Apache License, Version 2.0.
+
+// ------------------------------------------------------------------
+
+// R0 is used for returns
+// R11 is for instruction combo temporary
+// FP, SB, SP, LR have fixed uses
+enum {
+ tmp_reg_count = 10,
+ tmp_reg_first = 1, // 8,
+ tmp_reg_last = 10, // 11,
+};
+
+bool is_tmp_reg(u32 n) {
+ return (n >= tmp_reg_first) && (n <= tmp_reg_last);
+}
+
+u32 regbits;
+
+u32 get_reg_tmp() {
+ u32 n = tmp_reg_first;
+ while (n <= tmp_reg_last) {
+ if (!(regbits & (1 << n))) {
+ regbits |= (1 << n);
+ return n;
+ }
+ n++;
+ }
+ error("cannot allocate register");
+ return 0;
+}
+
+void put_reg(u32 r) {
+ if ((r < tmp_reg_first) || (r > tmp_reg_last)) {
+ // currently we don't strictly track r0..r7
+ // they are used for function calls and returns
+ return;
+ }
+ if (!(regbits & (1 << r))) {
+ error("freeing non-allocated register %u\n", r);
+ }
+ regbits = regbits & (~(1 << r));
+}
+
+void emit(u32 ins) {
+ ctx.code[ctx.pc / 4] = ins;
+ //gen_trace_code("", ctx.pc);
+ ctx.pc = ctx.pc + 4;
+}
+
+enum {
+ R0 = 0, R1 = 1, R2 = 2, R3 = 3, R4 = 4, R5 = 5, R6 = 6, R7 = 7,
+ R8 = 9, R9 = 9, R10 = 10, R11 = 11, FP = 12, SB = 13, SP = 14, LR = 15,
+ TMP = 16
+};
+enum {
+ MOV = 0x0000, LSL = 0x0001, ASR = 0x0002, ROR = 0x0003,
+ AND = 0x0004, ANN = 0x0005, IOR = 0x0006, XOR = 0x0007,
+ ADD = 0x0008, SUB = 0x0009, MUL = 0x000A, DIV = 0x000B,
+ FAD = 0x000C, FSB = 0x000D, FML = 0x000E, FDV = 0x000F,
+ ADC = 0x2008, SBC = 0x2009, UML = 0x200A,
+ MHI = 0x2000,
+ MOV_H = 0x2000,
+ MOV_CC = 0x3000,
+ MOD = 0x001B, // fake op for plumbing (DIV+MOV_H)
+};
+
+void emit_op(u32 op, u32 a, u32 b, u32 c) {
+ emit((op << 16) | (a << 24) | (b << 20) | c);
+}
+void emit_opi(u32 op, u32 a, u32 b, u32 n) {
+ emit(((0x4000 | op) << 16) | (a << 24) | (b << 20) | (n & 0xffff));
+}
+void emit_mov(u32 dst, u32 src) {
+ if (dst != src) {
+ emit_op(MOV, dst, 0, src);
+ }
+}
+
+// mov (load immediate) using the appropriate one or two
+// instruction form for the immediate argument
+void emit_movi(u32 a, u32 n) {
+ u32 m = n >> 16;
+ if (m == 0) {
+ emit_opi(MOV, a, 0, n);
+ } else if (m == 0xFFFF) {
+ emit_opi(MOV | 0x1000, a, 0, n);
+ } else {
+ emit_opi(MHI, a, 0, m);
+ if ((n & 0xFFFF) != 0) {
+ emit_opi(IOR, a, a, n);
+ }
+ }
+}
+
+#if 0
+// immediate op, using a temporary register and register op if the
+// immediate argument does not fit the single instruction form
+void emit_opi_n(u32 op, u32 a, u32 b, u32 n) {
+ u32 m = n >> 16;
+ if (m == 0) {
+ emit_opi(op, a, b, n);
+ } else if (m == 0xFFFF) {
+ emit_opi(op | 0x1000, a, b, n);
+ } else {
+ u32 t0 = get_reg_tmp();
+ emit_opi(MHI, t0, 0, m);
+ if ((n & 0xFFFF) != 0) {
+ emit_opi(IOR, t0, t0, n);
+ }
+ emit_op(op, a, b, t0);
+ put_reg(t0);
+ }
+}
+#endif
+
+enum {
+ LDW = 8, LDB = 9, STW = 10, STB = 11
+};
+void emit_mem(u32 op, u32 a, u32 b, u32 off) {
+ emit((op << 28) | (a << 24) | (b << 20) | (off & 0xfffff));
+}
+
+enum {
+ MI = 0, EQ = 1, CS = 2, VS = 3, LS = 4, LT = 5, LE = 6, AL = 7,
+ PL = 8, NE = 9, CC = 10, VC = 11, HI = 12, GE = 13, GT = 14, NV = 15,
+ L = 0x10,
+};
+void emit_br(u32 op, u32 r) {
+ emit(((0xC0 | op) << 24) | r);
+}
+void emit_bi(u32 op, u32 off) {
+ emit(((0xE0 | op) << 24) | (off & 0xffffff));
+}
+
+u8 rel_op_to_cc_tab[6] = { EQ, NE, LT, LE, GT, GE };
+u32 add_op_to_ins_tab[4] = { ADD, SUB, IOR, XOR };
+u32 mul_op_to_ins_tab[7] = { MUL, DIV, MOD, AND, ANN, LSL, ASR };
+
+// ------------------------------------------------------------------
+
+void gen_branch_back(u32 op, u32 addr) {
+ emit_bi(op, (addr - ctx.pc - 4) >> 2);
+}
+
+void gen_branch_fwd(u32 op, Fixup list) {
+ fixup_add_list(list, ctx.pc);
+ emit_bi(op, 0);
+}
+
+void gen_branch_sym(u32 op, Symbol sym) {
+ if (sym->flags & SYM_IS_PLACED) {
+ gen_branch_back(op, sym->value);
+ } else {
+ fixup_add_sym(sym, ctx.pc);
+ emit_bi(op, 0);
+ }
+}
+
+// patch branch instruction at addr to
+// branch to current pc
+void fixup_branch_fwd(u32 addr) {
+ u32 off = (ctx.pc - addr - 4) >> 2;
+ u32 ins = ctx.code[addr >> 2] & 0xFF000000;
+ ctx.code[addr >> 2] = ins | (off & 0x00FFFFFF);
+}
+
+void fixup_branches_fwd(Fixup fixup) {
+ while (fixup != nil) {
+ fixup_branch_fwd(fixup->addr);
+ fixup = fixup->next;
+ }
+}
+
+enum {
+ VAL_IMM = 0x0001, // immediate value
+ VAL_REG = 0x0002, // value in register
+ VAL_GLOBAL = 0x0010, // SB offset
+ VAL_PARAM = 0x0020, // FP +offset
+ VAL_LOCAL = 0x0040, // FP -offset
+ VAL_ADDR = 0x0080, // address
+ VAL_RO = 0x1000, // read only
+ VAL_LEFT = 0x00F0, // asignable if non-ro
+};
+
+typedef struct ValRec ValRec;
+typedef struct ValRec* Val;
+
+struct ValRec {
+ u32 kind;
+ Type type;
+ u32 n;
+};
+
+u32 loop_continue = 0;
+Fixup loop_exit = nil;
+Fixup func_exit = nil;
+
+void gen_block(Ast node);
+u32 gen_expr(Ast node);
+
+void sym_get_loc(Symbol sym, u32* base, i32* offset) {
+ if (sym->kind == SYM_LOCAL) {
+ *base = FP;
+ *offset = -(8 + sym->value);
+ } else if (sym->kind == SYM_PARAM) {
+ *base = FP;
+ *offset = sym->value;
+ } else if (sym->kind == SYM_GLOBAL) {
+ *base = SB;
+ *offset = sym->value;
+ } else {
+ error("non-register-relative symbol");
+ }
+}
+
+u32 gen_assign(Symbol sym, Ast expr) {
+ fprintf(stderr,"gen_assign()\n");
+ u32 base;
+ i32 offset;
+ sym_get_loc(sym, &base, &offset);
+ //XXX type compat
+ u32 r = gen_expr(expr);
+ emit_mem(STW, r, base, offset);
+ return r;
+}
+
+u32 gen_call(Ast node) {
+ fprintf(stderr,"gen_call()\n");
+ Symbol sym = node->child->sym;
+ Ast arg = node->child->next;
+ emit_opi(SUB, SP, SP, 4 * sym->type->len);
+ u32 n = 0;
+ while (arg != nil) {
+ u32 r = gen_expr(arg);
+ emit_mem(STW, r, SP, 4 * n);
+ put_reg(r);
+ arg = arg->next;
+ n = n + 1;
+ }
+ emit_bi(AL|L, 0); ///XXX
+ emit_opi(ADD, SP, SP, 4 * sym->type->len);
+
+ // return is in r0, if it exists
+ return 0;
+}
+
+u32 gen_lexpr(Ast node) {
+ return 0;
+}
+
+u32 gen_binop(Ast node, u32 op) {
+ fprintf(stderr, "gen_binop()\n");
+ u32 left = gen_expr(node->child);
+ u32 right = gen_expr(node->child->next);
+ u32 res = get_reg_tmp();
+ emit_op(op, res, left, right);
+ put_reg(left);
+ put_reg(right);
+ return res;
+}
+
+u32 gen_expr(Ast node) {
+ fprintf(stderr,"gen_expr()\n");
+ if (node->kind == AST_U32) {
+ u32 r = get_reg_tmp();
+ emit_movi(r, node->ival);
+ return r;
+ } else if (node->kind == AST_NAME) {
+ u32 base;
+ i32 offset;
+ sym_get_loc(node->sym, &base, &offset);
+ u32 r = get_reg_tmp();
+ emit_mem(LDW, r, base, offset);
+ return r;
+ } else if (node->kind == AST_BINOP) {
+ u32 op = node->ival;
+ if (op == tASSIGN) {
+ if (node->child->kind != AST_NAME) {
+ error("unhandled complex assignment");
+ }
+ return gen_assign(node->child->sym, node->child->next);
+ } else if ((op & tcMASK) == tcRELOP) {
+ error("sorry");
+ } else if ((op & tcMASK) == tcADDOP) {
+ op = add_op_to_ins_tab[op - tPLUS];
+ return gen_binop(node, op);
+ } else if ((op & tcMASK) == tcMULOP) {
+ op = mul_op_to_ins_tab[op - tSTAR];
+ return gen_binop(node, op);
+ } else {
+ error("gen_expr cannot handle binop %s\n", tnames[op]);
+ }
+ } else if (node->kind == AST_UNOP) {
+ error("sorry no unops");
+ } else if (node->kind == AST_CALL) {
+ return gen_call(node);
+ } else {
+ error("gen_expr cannot handle %s\n", ast_kind[node->kind]);
+ }
+ return 0;
+}
+
+void gen_while(Ast node) {
+ // save branch targets
+ u32 old_loop_continue = loop_continue;
+ Fixup old_loop_exit = loop_exit;
+
+ FixupRec list;
+ list.next = nil;
+ loop_exit = &list;
+
+ loop_continue = ctx.pc;
+ u32 r = gen_expr(node->child);
+ put_reg(r);
+
+ // XXX flow
+
+ gen_block(node->child->next);
+ emit_br(AL, loop_continue);
+
+ // patch breaks
+ fixup_branches_fwd(loop_exit->next);
+
+ // restore branch targets
+ loop_continue = old_loop_continue;
+ loop_exit = old_loop_exit;
+}
+
+void gen_if_else(Ast node) {
+ gen_expr(node->child);
+ Ast ifthen = node->child->next;
+ Ast ifelse = ifthen->next;
+ gen_block(ifthen);
+ if (ifelse != nil) {
+ gen_block(ifelse);
+ }
+}
+
+void gen_stmt(Ast node) {
+ fprintf(stderr,"gen_stmt()\n");
+ u32 kind = node->kind;
+ if (kind == AST_EXPR) {
+ u32 r = gen_expr(node);
+ put_reg(r);
+ } else if (kind == AST_LOCAL) {
+ if (node->child) {
+ u32 r = gen_assign(node->sym, node->child);
+ put_reg(r);
+ }
+ } else if (kind == AST_IF) {
+ gen_if_else(node);
+ } else if (kind == AST_WHILE) {
+ gen_while(node);
+ } else if (kind == AST_RETURN) {
+ if (node->child) {
+ u32 r = gen_expr(node->child);
+ emit_mov(0, r);
+ put_reg(r);
+ }
+ gen_branch_fwd(AL, func_exit);
+ } else if (kind == AST_BREAK) {
+ gen_branch_fwd(AL, loop_exit);
+ } else if (kind == AST_CONTINUE) {
+ gen_branch_back(AL, loop_continue);
+ } else {
+ error("gen_stmt cannot handle %s\n", ast_kind[kind]);
+ }
+}
+
+void gen_block(Ast node) {
+ fprintf(stderr,"gen_block()\n");
+ node = node->child;
+ while (node != nil) {
+ gen_stmt(node);
+ node = node->next;
+ }
+}
+
+// before prologue after prologue
+// --------------- --------------
+// arg2 oldarg2
+// arg1 oldarg1
+// FP -> arg0 oldarg0 <-+
+// fpsave oldfp |
+// lrsave oldlp |
+// loc0 oldloc0 |
+// loc1 oldloc1 |
+// ... ... |
+// locn oldlocn |
+// newarg2 arg2 |
+// newarg1 arg1 |
+// SP -> newarg0 FP -> arg0 |
+// fpsave ---+
+// lrsave
+// loc0
+// loc1
+// ...
+// SP -> locn
+
+void gen_func(Ast node) {
+ fprintf(stderr,"gen_func()\n");
+ u32 x = node->sym->type->size + 8;
+
+ node->sym->value = ctx.pc;
+ node->sym->flags |= SYM_IS_PLACED;
+
+ // patch previous calls now that we have an entry address
+ fixup_branches_fwd(node->sym->fixups);
+ node->sym->fixups = nil; // XXX discard
+
+ // generate prologue
+ emit_opi(SUB, SP, SP, x);
+ emit_mem(STW, FP, SP, x - 4);
+ emit_mem(STW, LR, SP, x - 8);
+ emit_opi(ADD, FP, SP, x);
+
+ // setup list of branches-to-epilogue
+ FixupRec list;
+ list.next = nil;
+ func_exit = &list;
+
+ // generate body
+ gen_block(node->child);
+
+ // patch branches to epilogue
+ fixup_branches_fwd(list.next);
+
+ // generate epilogue
+ emit_mem(LDW, LR, FP, x - 8);
+ emit_mem(LDW, FP, FP, x - 4);
+ emit_br(AL, LR);
+}
+
+void gen_risc5_simple(Ast node) {
+ fprintf(stderr, "gen_risc5_simple()\n");
+
+ emit_mov(SB, 0); // placeholder SB load
+ emit_bi(AL, 0); // placeholder branch to init
+
+ node = node->child;
+ while (node != nil) {
+ if (node->kind == AST_FUNC) {
+ gen_func(node);
+ }
+ node = node->next;
+ }
+
+ Symbol sym = symbol_find(string_make("start", 5));
+ if (sym == nil) {
+ error("no 'start' function\n");
+ }
+ if (sym->type->kind != TYPE_FUNC) {
+ error("'start' is not a function\n");
+ }
+ if (sym->first != nil) {
+ error("'start' must have no parameters\n");
+ }
+
+ // patch static base load to after the last instruction
+ ctx.code[0] |= ctx.pc;
+ // patch branch-to-start
+ ctx.code[1] |= (sym->value - 8) >> 2;
+
+ // TODO: copy ro globals after code
+ // TODO: SB should neg-index into ro, pos-index into rw
+}
diff --git a/src/compiler2.c b/src/compiler2.c
@@ -14,7 +14,7 @@
#include <unistd.h>
#include <sys/stat.h>
-//#include "risc5.h"
+#include "risc5.h"
// builtin types
#define nil 0
@@ -44,6 +44,7 @@ typedef struct AstRec AstRec;
typedef struct TypeRec TypeRec;
typedef struct SymbolRec SymbolRec;
typedef struct ScopeRec ScopeRec;
+typedef struct FixupRec FixupRec;
typedef struct StringRec* String;
typedef struct CtxRec* Ctx;
@@ -51,6 +52,7 @@ typedef struct AstRec* Ast;
typedef struct TypeRec* Type;
typedef struct SymbolRec* Symbol;
typedef struct ScopeRec* Scope;
+typedef struct FixupRec* Fixup;
struct StringRec {
String next;
@@ -65,7 +67,7 @@ enum {
AST_BINOP, // EXPR EXPR
AST_UNOP, // EXPR
AST_BLOCK, // STMT*
- AST_ASSIGN, // NAME EXPR
+ AST_EXPR, // EXPR
AST_CALL, // NAME EXPR*
AST_WHILE, // WHILE EXPR BLOCK
AST_IF, // IF EXPR BLOCKthen BLOCKelse
@@ -79,16 +81,15 @@ enum {
AST_FUNC, // BLOCK PARAM*
AST_GLOBAL, // EXPR
AST_FIELD,
- AST_DISCARD,
AST_DEREF,
AST_INDEX,
};
-str ast_t_names[] = {
- "NAME", "U32", "STR", "BINOP", "UNOP", "BLOCK", "ASSIGN",
+str ast_kind[AST_INDEX + 1] = {
+ "NAME", "U32", "STR", "BINOP", "UNOP", "BLOCK", "EXPR",
"CALL", "WHILE", "IF", "RETURN", "BREAK", "CONTINUE",
"LOCAL", "PROGRAM", "TYPEDEF", "ENUMDEF", "FUNCDEF",
- "GLOBAL", "FIELD", "DISCARD", "DEREF", "INDEX"
+ "GLOBAL", "FIELD", "DEREF", "INDEX"
};
struct AstRec {
@@ -117,7 +118,7 @@ enum {
TYPE_UNDEFINED,
};
-str type_id_tab[TYPE_UNDEFINED + 1] = {
+str type_kind[TYPE_UNDEFINED + 1] = {
"void", "bool", "byte", "i32", "nil", "*", "[]", "[]",
"struct", "func", "enum", "undef"
};
@@ -128,7 +129,7 @@ struct TypeRec {
Symbol sym; // if not anonymous
Symbol first; // list of params or fields
u32 len; // array, params
- u32 size; // in bytes
+ u32 size; // in bytes, local stack for funcs
};
enum {
@@ -141,11 +142,16 @@ enum {
SYM_FIELD,
};
+str sym_kind[SYM_FIELD + 1] = {
+ "CONST", "TYPE", "FUNC", "GLOBAL", "LOCAL", "PARAM", "FIELD",
+};
+
enum {
SYM_IS_READ_ONLY = 1,
SYM_IS_PUBLIC = 2,
SYM_IS_DEFINED = 4,
SYM_IS_BUILTIN = 8,
+ SYM_IS_PLACED = 16, // exists at addr in sym->value
};
struct SymbolRec {
@@ -154,9 +160,9 @@ struct SymbolRec {
u32 flags;
String name;
Type type;
- Symbol first; // list of?
-
+ Symbol first; // list of fields or params
u32 value; // SYM_CONST
+ Fixup fixups; // references from before placement
};
enum {
@@ -172,6 +178,12 @@ struct ScopeRec {
// Fixup?
};
+
+struct FixupRec {
+ Fixup next;
+ u32 addr;
+};
+
// ------------------------------------------------------------------
// compiler global context
@@ -310,6 +322,7 @@ Symbol symbol_make(symbol_t kind, u32 flags, String name, Type type, u32 value)
s->type = type;
s->value = value;
s->first = nil;
+ s->fixups = nil;
return s;
}
@@ -420,7 +433,7 @@ void type_dump(Type type, bool use_short_name) {
}
printf("}");
} else {
- printf("%s", type_id_tab[type->kind]);
+ printf("%s", type_kind[type->kind]);
if ((type->kind == TYPE_POINTER) || (type->kind == TYPE_SLICE)) {
type_dump(type->base, true);
}
@@ -497,6 +510,20 @@ void builtin_make(const char* name, u32 id, Type p0, Type p1, Type rtn) {
symbol_add_global(type->sym);
}
+void fixup_add_list(Fixup list, u32 addr) {
+ Fixup fixup = malloc(sizeof(FixupRec));
+ fixup->next = list->next;
+ fixup->addr = addr;
+ list->next = fixup;
+}
+
+void fixup_add_sym(Symbol sym, u32 addr) {
+ Fixup fixup = malloc(sizeof(FixupRec));
+ fixup->next = sym->fixups;
+ fixup->addr = addr;
+ sym->fixups = fixup;
+}
+
// ================================================================
enum {
@@ -1022,7 +1049,7 @@ i32 ast_get_const_i32(Ast node) {
error("unsupported UNOP %s\n", tnames[op]);
}
} else {
- error("non-const expr (%s)\n", ast_t_names[node->kind]);
+ error("non-const expr (%s)\n", ast_kind[node->kind]);
}
return 0;
}
@@ -1527,7 +1554,7 @@ Ast parse_expr_statement() {
node = ast_make_unop(ctx.tok, left);
next();
} else {
- node = ast_make_simple(AST_DISCARD, 0);
+ node = ast_make_simple(AST_EXPR, 0);
node->child = left;
}
require(tSEMI);
@@ -1590,13 +1617,14 @@ Ast parse_function_body(Symbol fn) {
node->sym = scope_pop();
scope_pop();
ctx.fn = nil;
+ fn->type->size = ctx.local_stack;
return node;
}
Symbol parse_param(String fname, u32 n, Symbol first, Symbol last) {
String pname = parse_name("parameter name");
Type ptype = parse_type(false);
- Symbol param = symbol_make(SYM_PARAM, 0, pname, ptype, 4 + n * 4);
+ Symbol param = symbol_make(SYM_PARAM, 0, pname, ptype, /* 4 + */ n * 4);
Symbol sym = first;
while (sym != nil) {
@@ -1680,10 +1708,11 @@ Ast parse_function() {
} else {
// if there was no existing record of this function, create one now
Type type = type_make(TYPE_FUNC, rettype, n, 0);
- type->first = first;
sym = symbol_make(SYM_FUNC, 0, fname, type, 0);
sym->first = first;
+ type->first = first;
type->sym = sym;
+ type->len = n; // parameter count
symbol_add_global(sym);
}
@@ -1819,7 +1848,7 @@ void ast_dump_rtype(Symbol sym, u32 indent) {
void ast_dump(Ast node, u32 indent) {
u32 i = 0;
while (i < indent) { printf(" "); i++; }
- printf("%s ", ast_t_names[node->kind]);
+ printf("%s ", ast_kind[node->kind]);
if (node->kind == AST_NAME) {
printf("'%s'\n", node->name->text);
} else if ((node->kind == AST_BINOP) || (node->kind == AST_UNOP)) {
@@ -1862,6 +1891,8 @@ void ast_dump(Ast node, u32 indent) {
}
}
+#include "codegen-risc5-simple.c"
+
#if 0
void type_dump_all() {
Symbol sym = ctx.typetab;
@@ -1880,6 +1911,58 @@ void type_dump_all() {
// ================================================================
+void listing_write(const char* listfn, const char* srcfn) {
+ FILE* fin = fopen(srcfn, "r");
+ if (fin == NULL) {
+ error("cannot re-read '%s'\n", srcfn);
+ }
+ FILE* fout = fopen(listfn, "w");
+ if (fout == NULL) {
+ error("cannot write '%s'\n", listfn);
+ }
+ u32 n = 0;
+ u32 line = 1;
+ char buf[1024];
+ while (n < ctx.pc) {
+ u32 ins = ctx.code[n/4];
+#if 0
+ if ((line < ctx.xref[n/4]) && fin) {
+ fprintf(fout, "\n");
+ while (line < ctx.xref[n/4]) {
+ if (fgets(buf, sizeof(buf), fin) == nil) {
+ fin = nil;
+ break;
+ }
+ u32 i = 0;
+ while (buf[i] != 0) {
+ if (buf[i] > ' ') {
+ fprintf(fout,"%s", buf);
+ break;
+ }
+ i++;
+ }
+ line++;
+ }
+ fprintf(fout, "\n");
+ }
+#endif
+ risc5dis(n, ins, buf);
+ fprintf(fout, "%08x: %08x %s\n", n, ins, buf);
+ n += 4;
+ }
+ n = 0;
+ while (n < ctx.gp) {
+ fprintf(fout, "%08x: %08x\n", ctx.pc + n, ctx.data[n >> 2]);
+ n += 4;
+ }
+ fclose(fout);
+ if (fin) {
+ fclose(fin);
+ }
+}
+
+// ================================================================
+
i32 main(int argc, args argv) {
str outname = "out.bin";
str lstname = nil;
@@ -1927,7 +2010,16 @@ i32 main(int argc, args argv) {
}
if (srcname == nil) {
- error("no file specified");
+ printf(
+"usage: compiler [ <option> | <sourcefilename> ]*\n"
+"\n"
+"options: -o <filename> binary output (default 'out.bin')\n"
+" -l <filename> listing output (default none)\n"
+" -v trace code generation\n"
+" -s scan only\n"
+" -p dump type context\n"
+" -A abort on error\n");
+ return 0;
}
ctx.filename = srcname;
@@ -1953,6 +2045,12 @@ i32 main(int argc, args argv) {
ast_dump(a, 0);
+ gen_risc5_simple(a);
+
+ if (lstname != nil) {
+ listing_write(lstname, ctx.filename);
+ }
+
//type_dump_all();
return 0;
diff --git a/src/risc5dis.c b/src/risc5dis.c
@@ -21,7 +21,7 @@ static char *append_u32(char *buf, int32_t n) {
static const char* regname[16] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "mt", "sb", "sp", "lr",
+ "r8", "r9", "r10", "r11", "fp", "sb", "sp", "lr",
};
#define R(n) regname[(n) & 15]