aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--README.md29
-rwxr-xr-xbcgen211
-rw-r--r--bcode.c62
-rw-r--r--bcode.h32
-rw-r--r--rules.py4
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);`.
diff --git a/bcgen b/bcgen
new file mode 100755
index 0000000..c7d1a7f
--- /dev/null
+++ b/bcgen
@@ -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())
diff --git a/bcode.c b/bcode.c
new file mode 100644
index 0000000..a78f9e9
--- /dev/null
+++ b/bcode.c
@@ -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)
+{
+}
diff --git a/bcode.h b/bcode.h
new file mode 100644
index 0000000..6683686
--- /dev/null
+++ b/bcode.h
@@ -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);')