diff options
| -rw-r--r-- | .gitignore | 2 | ||||
| -rw-r--r-- | README.md | 29 | ||||
| -rwxr-xr-x | bcgen | 211 | ||||
| -rw-r--r-- | bcode.c | 62 | ||||
| -rw-r--r-- | bcode.h | 32 | ||||
| -rw-r--r-- | rules.py | 4 |
6 files changed, 340 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a9b52b0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +gen/* +*.o diff --git a/README.md b/README.md new file mode 100644 index 0000000..1bb5875 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Byte code generator + +Separate project for now, but essentially create a program that takes some input +(for example) +``` +addr(_GGG_) +{ + R0 = R1 + R2; + return NEXT_INSN; +} + +addi(_GGi_) +{ + R0 = R1 + IMM; + return NEXT_INSN; +} + +beqi(RGi__) +{ + if (R0 == IMM) + return BRANCH; + + return NEXT_INSN; +} +``` + +and generates implementations with registers fixed and some kind of muxing +compilation functions that selects the correct implementation from some runtime +`compile_addr(1, 2, 3);`. @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 + +import sys + +def check_fmt(fmt): + assert(len(fmt) == 6) + assert(fmt[0] == '_' or fmt[0] == 'r') + + for i in range(1, 5): + c = fmt[i] + assert(c == 'R' or c == 'F' or c == '_') + + assert(fmt[5] == '_' or fmt[5] == 'I' or fmt[5] == 'D') + +def param(fmt, i): + c = fmt[i + 1] + return c + str(i) + +def gen_label(name, r0, r1, r2, r3): + return '{}_{}{}{}{}'.format(name, r0, r1, r2, r3) + +def gen_enum(name, r0, r1, r2, r3): + return gen_label(name, r0, r1, r2, r3).upper() + +def gen_exec_instance(f, name, r0, r1, r2, r3): + label = gen_label(name, r0, r1, r2, r3) + ': ' + macro = '{}({}, {}, {}, {}); '.format(name.upper(), r0, r1, r2, r3) + next = 'NEXT_INSN;' + f.write(label + macro + next + '\n') + +# gen should maybe just generate the string and print_ would print it? +def gen_static_instance(f, name, r0, r1, r2, r3): + label = gen_label(name, r0, r1, r2, r3) + enum = gen_enum(name, r0, r1, r2, r3) + f.write('[' + enum + '] = &&' + label + ',\n') + +def gen_params(fmt): + n = 0 + r = "" + for p in fmt[1:-1]: + if p == 'R' or p == 'F': + # todo: could be useful to have different types for general purpose + # registers and floating point registers, might avoid bugs that + # would otherwise be pretty annoying to track down. + r += ', size_t a' + str(n) + n += 1 + + i = "" + if fmt[5] == 'I': + i = ', gbreg_t imm' + elif fmt[5] == 'D': + i = ', fbreg_t dimm' + + return '(struct compile_state *cs' + r + i + ')' + +def gen_signature(name, fmt): + ret = 'void ' + if fmt[0] == 'r': + ret = 'breloc_t ' + + n = 'select_' + name + p = gen_params(fmt) + return ret + n + p + +def gen_cond(r, i): + if r == '': + return '1' + + return 'a' + str(i) + ' == ' + r[1] + +def gen_select_instance(f, name, r0, r1, r2, r3): + c0 = gen_cond(r0, 0) + c1 = gen_cond(r1, 1) + c2 = gen_cond(r2, 2) + c3 = gen_cond(r3, 3) + cond = c0 + ' && ' + c1 + ' && ' + c2 + ' && ' + c3 + action = 'label = ' + gen_enum(name, r0, r1, r2, r3) + ';' + f.write('else if (' + cond + ') {' + action + '}\n') + +def gen_enum_instance(f, name, r0, r1, r2, r3): + enum = gen_enum(name, r0, r1, r2, r3) + f.write(enum + ',\n') + +class BCGen: + def __init__(self, r = 3, f = 3, head=''): + self.r = r + self.f = f + + # clear out files + with open('gen/body.inc', 'w') as inc: + pass + + with open('gen/macro.inc', 'w') as inc: + pass + + with open('gen/static.inc', 'w') as inc: + pass + + with open('gen/select.inc', 'w') as inc: + pass + + with open('gen/enum.inc', 'w') as inc: + pass + + with open('gen/select.h', 'w') as h: + pass + + with open('gen/head.inc', 'w') as inc: + inc.write(head) + + with open('gen/regs.inc', 'w') as inc: + gregs = ['gbreg_t r' + str(i) + ' = 0;\n' for i in range(r)] + fregs = ['fbreg_t f' + str(i) + ' = 0;\n' for i in range(f)] + + for g in gregs: + inc.write(g); + + for f in fregs: + inc.write(f) + + def gen_macro(self, name, fmt, body): + with open('gen/macro.inc', 'a') as f: + name = name.upper() + + p0 = param(fmt, 0) + p1 = param(fmt, 1) + p2 = param(fmt, 2) + p3 = param(fmt, 3) + + macro = '#define {}({}, {}, {}, {}) {}\n'.format( + name, p0, p1, p2, p3, body) + + f.write(macro) + + def place(self, fmt, i): + c = fmt[i + 1] + if c == 'R': + return ['r' + str(i) for i in range(self.r)] + + if c == 'F': + return ['f' + str(i) for i in range(self.f)] + + return [""] + + def gen_body(self, name, fmt): + with open('gen/body.inc', 'a') as f: + for r0 in self.place(fmt, 0): + for r1 in self.place(fmt, 1): + for r2 in self.place(fmt, 2): + for r3 in self.place(fmt, 3): + gen_exec_instance(f, name, r0, r1, r2, r3) + + def gen_static(self, name, fmt): + with open('gen/static.inc', 'a') as f: + for r0 in self.place(fmt, 0): + for r1 in self.place(fmt, 1): + for r2 in self.place(fmt, 2): + for r3 in self.place(fmt, 3): + gen_static_instance(f, name, r0, r1, r2, r3) + + def gen_select(self, name, fmt): + with open('gen/select.h', 'a') as f: + sign = gen_signature(name, fmt) + f.write(sign + ';\n') + + with open('gen/select.inc', 'a') as f: + sign = gen_signature(name, fmt) + f.write(sign + '\n') + f.write('{\nenum bcode_insn label = 0;\n') + if fmt[0] == 'r': + f.write('breloc_t reloc = RELOC;\n') + # kind of ugly but simplifies gen_select_instance a fair bit + f.write('if (0) {}\n') + + for r0 in self.place(fmt, 0): + for r1 in self.place(fmt, 1): + for r2 in self.place(fmt, 2): + for r3 in self.place(fmt, 3): + gen_select_instance(f, name, r0, r1, r2, r3) + + if fmt[5] == 'I': + f.write('PUSH_IMM_OP(label, imm);\n') + elif fmt[5] == 'D': + f.write('PUSH_DIMM_OP(label, dimm);\n') + else: + f.write('PUSH_OP(label);\n') + + if fmt[0] == 'r': + f.write('return reloc;\n') + + f.write('}\n') + + def gen_enum(self, name, fmt): + with open('gen/enum.inc', 'a') as f: + for r0 in self.place(fmt, 0): + for r1 in self.place(fmt, 1): + for r2 in self.place(fmt, 2): + for r3 in self.place(fmt, 3): + gen_enum_instance(f, name, r0, r1, r2, r3) + + + def rule(self, name, fmt, body): + check_fmt(fmt) + self.gen_macro(name, fmt, body) + self.gen_static(name, fmt) + self.gen_select(name, fmt) + self.gen_body(name, fmt) + self.gen_enum(name, fmt) + +assert(len(sys.argv) == 2) +exec(open(sys.argv[1]).read()) @@ -0,0 +1,62 @@ +#include <stdbool.h> +#include "bcode.h" + +enum bcode_insn { + END, +#include "gen/enum.inc" +}; + +static void append(struct compile_state *cs, enum bcode_insn label, breg_t imm) +{ +} + +#define RELOC cs->pc +#define PUSH_OP(label) append(cs, label, (breg_t){ .g = 0 }) +#define PUSH_IMM_OP(label, imm) append(cs, label, (breg_t){ .g = imm }) +#define PUSH_DIMM_OP(label, dimm) append(cs, label, (breg_t){ .f = dimm }) + +#include "gen/select.inc" +#include "gen/macro.inc" + +#define IMM s.imm[pc].g +#define DIMM s.imm[pc].f +#define NEXT_INSN goto *s.op[pc++] +#define JUMP(i) goto *s.op[pc = (i)] + +static void _run(struct compile_state *cs, bool init) +{ + static void *labels[] = { + [END] = &&end, +#include "gen/static.inc" + }; + + if (init) { + cs->labels = labels; + return; + } + +#include "gen/head.inc" +#include "gen/regs.inc" + + const struct run_state s = cs->s; + size_t pc = 0; + JUMP(pc); +#include "gen/body.inc" + +end: + return; +} + +void run(struct compile_state *cs) +{ + _run(cs, false); +} + +void init(struct compile_state *cs) +{ + _run(cs, true); +} + +void destroy(struct compile_state *cs) +{ +} @@ -0,0 +1,32 @@ +#ifndef BCGEN_BCODE_H +#define BCGEN_BCODE_H + +#include <stddef.h> + +typedef unsigned long gbreg_t; +typedef double fbreg_t; +typedef size_t breloc_t; + +typedef union { + gbreg_t g; + fbreg_t f; +} breg_t; + +struct run_state { + void* (*op); + breg_t *imm; +}; + +struct compile_state { + struct run_state s; + void* (*labels); + size_t pc; +}; + +#include "gen/select.h" + +void run(struct compile_state *cs); +void init(struct compile_state *cs); +void destroy(struct compile_state *cs); + +#endif /* BCGEN_BCODE_H */ diff --git a/rules.py b/rules.py new file mode 100644 index 0000000..b0aabbf --- /dev/null +++ b/rules.py @@ -0,0 +1,4 @@ +g = BCGen(r = 7, f = 6, head='gbreg_t t = 0;') +g.rule('addr', '_RRR__', 'R0 = R1 + R2;') +g.rule('addr_f', '_FFF__', 'F0 = F1 + F2;') +g.rule('bltr', 'rRR__I', 'if (R0 < R1) JUMP(IMM);') |
