aboutsummaryrefslogtreecommitdiff
path: root/src/asm.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2023-11-19 19:59:53 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2023-11-19 19:59:53 +0200
commit17a27d445295bbaf7c7c470b1e4648635af2f0a3 (patch)
tree2749eacfe577afc1902826a99a4437bfc8419f05 /src/asm.c
parent8f754f8b13e55e4bb92d72f105c5aaaba1754b7d (diff)
downloadek-17a27d445295bbaf7c7c470b1e4648635af2f0a3.tar.gz
ek-17a27d445295bbaf7c7c470b1e4648635af2f0a3.zip
first runnable test program
+ tests/pointer_literal.ek compiles down to very simple assembly that tasm can assemble and triscv run with correct results. Whopee + Did notice that void return functions should still have implicit return statements added
Diffstat (limited to 'src/asm.c')
-rw-r--r--src/asm.c96
1 files changed, 96 insertions, 0 deletions
diff --git a/src/asm.c b/src/asm.c
new file mode 100644
index 0000000..4102265
--- /dev/null
+++ b/src/asm.c
@@ -0,0 +1,96 @@
+#include <ek/ops.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+/* I guess using the zero register might be okay in some scenarios, but for now
+ * I'll just keep it an illegal register */
+#define ASSERT_REG(x) {assert(x->kind == LOC_REG); assert(x->reg > 0 && x->reg < 81);}
+#define ASSERT_MEM(x) {assert(x->kind == LOC_MEM); assert(x->reg > 0 && x->reg < 81);}
+
+static int print_comment(struct op *op, FILE *f)
+{
+ fprintf(f, "/* %s */\n", op->string);
+ return 0;
+}
+
+static int print_label(struct op *op, FILE *f)
+{
+ fprintf(f, "%s:\n", op->string);
+ return 0;
+}
+
+static int print_li(struct op *op, FILE *f)
+{
+ struct loc *o = &op->outputs;
+ assert(o->next == NULL);
+ /* unsure if this will always hold, but for now */
+ ASSERT_REG(o);
+
+ fprintf(f, "li x%zd, %lld\n", o->reg, op->constant);
+ return 0;
+}
+
+static int print_mv(struct op *op, FILE *f)
+{
+ struct loc *i = &op->inputs;
+ struct loc *o = &op->outputs;
+ assert(i->next == NULL);
+ assert(o->next == NULL);
+ ASSERT_REG(i);
+ ASSERT_REG(o);
+
+ fprintf(f, "mv x%zd, x%zd\n", o->reg, i->reg);
+ return 0;
+}
+
+static int print_stt(struct op *op, FILE *f)
+{
+ struct loc *i = &op->inputs;
+ struct loc *o = &op->outputs;
+ assert(i->next == NULL);
+ assert(o->next == NULL);
+ ASSERT_REG(i);
+ ASSERT_MEM(o);
+
+ fprintf(f, "st t, x%zd, %lld(x%zd)\n", i->reg, o->off, o->reg);
+ return 0;
+}
+
+static int print_op(struct op *op, FILE *f)
+{
+ int ret = 0;
+ switch (op->opcode) {
+ case OP_COMMENT: ret = print_comment(op, f); break;
+ case OP_LABEL: ret = print_label(op, f); break;
+ case OP_LI: ret = print_li(op, f); break;
+ case OP_MV: ret = print_mv(op, f); break;
+ case OP_STT: ret = print_stt(op, f); break;
+ default: abort();
+ }
+
+ return ret;
+}
+
+int print_asm(struct ops *ops, const char *output)
+{
+ FILE *f = fopen(output, "w");
+
+ /* main should probably be mangled here as well */
+ fprintf(f, "jal x0, main\n");
+ int ret = 0;
+ struct op *op = ops->base;
+ while (op) {
+ if ((ret = print_op(op, f)))
+ break;
+
+ op = op->next;
+ }
+
+ /* tell simulator to turn off (very much temp) */
+ fprintf(f, "li x1, 3\n");
+ fprintf(f, "csrrw mpower, x0, x1\n");
+
+ fclose(f);
+ return ret;
+}