From 22575e056586a7810007952c717eff4e9e005bdb Mon Sep 17 00:00:00 2001
From: David Phillips <david@sighup.nz>
Date: Sat, 3 Aug 2019 14:44:12 +1200
Subject: File input and output routines away

---
 output/output_asm.c | 134 +++++++++++++++++++++++++++++++++++
 output/output_asm.h |   6 ++
 output/output_bin.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 output/output_bin.h |   6 ++
 4 files changed, 346 insertions(+)
 create mode 100644 output/output_asm.c
 create mode 100644 output/output_asm.h
 create mode 100644 output/output_bin.c
 create mode 100644 output/output_bin.h

(limited to 'output')

diff --git a/output/output_asm.c b/output/output_asm.c
new file mode 100644
index 0000000..fd9f792
--- /dev/null
+++ b/output/output_asm.c
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "parse.h"
+#include "util.h"
+
+static size_t inst_sizes[] = {
+	[INST_TYPE_R] = 2,
+	[INST_TYPE_NI] = 2,
+	[INST_TYPE_WI] = 4,
+	[INST_TYPE_JR] = 2,
+	[INST_TYPE_JI] = 4,
+	[INST_TYPE_B] = 2,
+};
+
+void emit_single_r_type(FILE *f, struct r_type inst)
+{
+	const char *oper = get_asm_from_oper(inst.oper);
+	const char *dest = get_asm_from_reg(inst.dest);
+	const char *left = get_asm_from_reg(inst.left);
+	const char *right = get_asm_from_reg(inst.right);
+
+	fprintf(f, "%s  %s, %s, %s\n", oper, dest, left, right);
+}
+
+void emit_single_i_type(FILE *f, struct i_type inst)
+{
+	const char *oper = get_asm_from_oper(inst.oper);
+	const char *dest = get_asm_from_reg(inst.dest);
+	const char *left = get_asm_from_reg(inst.left);
+
+	fprintf(f, "%si %s, %s, 0x%x\n", oper, dest, left, inst.imm.value);
+}
+
+/*void emit_single_wi_type(FILE *f, struct i_type inst)
+{
+	const char *oper = get_asm_from_oper(inst.oper);
+	const char *dest = get_asm_from_oper(inst.dest);
+	const char *left = get_asm_from_oper(inst.left);
+
+	fprintf(f, "%si %s, %s, 0x%s\n", oper, dest, left, inst.imm.value);
+}*/
+
+void emit_single_ji_type(FILE *f, struct ji_type inst)
+{
+	const char *cond = get_asm_from_j(inst.cond);
+
+	fprintf(f, "%s  0x%x\n", cond, inst.imm.value);
+}
+
+void emit_single_jr_type(FILE *f, struct jr_type inst)
+{
+	const char *cond = get_asm_from_j(inst.cond);
+	const char *reg = get_asm_from_reg(inst.reg);
+
+	fprintf(f, "%s  %s\n", cond, reg);
+}
+
+void emit_single_b_type(FILE *f, struct b_type inst)
+{
+	const char *cond = get_asm_from_b(inst.cond);
+
+	fprintf(f, "%s  0x%x\n", cond, inst.imm.value);
+}
+
+
+int look_up_label(struct label *labels, size_t labels_count, uint16_t *val, const char *label)
+{
+	size_t i = 0;
+
+	for (i = 0; i < labels_count; i++) {
+		if (strcmp(labels[i].name, label) == 0) {
+			*val = labels[i].byte_offset;
+			return 0;
+		}
+	}
+
+	/* FIXME emit */
+	fprintf(stderr, "Reference to undefined label `%s'\n", label);
+	return 1;
+}
+
+int output_single(FILE *f, size_t *cur_byte, struct label *labels, size_t labels_count, struct instruction inst)
+{
+	switch (inst.type) {
+		case INST_TYPE_R:
+			emit_single_r_type(f, inst.inst.r);
+			break;
+		case INST_TYPE_NI:
+		case INST_TYPE_WI:
+			if (   inst.inst.i.imm_is_ident
+			    && look_up_label(labels, labels_count, &inst.inst.i.imm.value, inst.inst.i.imm.label))
+				return 1;
+
+			emit_single_i_type(f, inst.inst.i);
+			break;
+		case INST_TYPE_JR:
+			emit_single_jr_type(f, inst.inst.jr);
+			break;
+		case INST_TYPE_JI:
+			if (   inst.inst.ji.imm_is_ident
+			    && look_up_label(labels, labels_count, &inst.inst.ji.imm.value, inst.inst.ji.imm.label))
+				return 1;
+
+			emit_single_ji_type(f, inst.inst.ji);
+			break;
+		case INST_TYPE_B:
+			if (   inst.inst.b.imm_is_ident
+			    && look_up_label(labels, labels_count, &inst.inst.b.imm.value, inst.inst.b.imm.label))
+				return 1;
+			emit_single_b_type(f, inst.inst.b);
+			break;
+		default:
+			fprintf(stderr, "Internal error: unhandled instruction type\n");
+			break;
+	}
+
+	*cur_byte += inst_sizes[inst.type];
+
+	return 0;
+}
+
+int output_asm(FILE *fout, struct label *labels, size_t label_count, struct instruction *insts, size_t insts_count)
+{
+	size_t i = 0;
+	size_t cur_byte = 0;
+
+	for (i = 0; i < insts_count; i++)
+		if (output_single(fout, &cur_byte, labels, label_count, insts[i]))
+			return 1;
+
+	return 0;
+}
diff --git a/output/output_asm.h b/output/output_asm.h
new file mode 100644
index 0000000..b4afd2a
--- /dev/null
+++ b/output/output_asm.h
@@ -0,0 +1,6 @@
+#ifndef OUTPUT_ASM_H
+#define OUTPUT_ASM_H
+
+int output_asm(FILE *fout, struct label *labels, size_t label_count, struct instruction *insts, size_t insts_count);
+
+#endif /* OUTPUT_ASM_H */
diff --git a/output/output_bin.c b/output/output_bin.c
new file mode 100644
index 0000000..1c7b961
--- /dev/null
+++ b/output/output_bin.c
@@ -0,0 +1,200 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "parse.h"
+
+static size_t cur_byte;
+
+int generate_single_r_type(uint32_t *dest, struct r_type inst)
+{
+	uint32_t i = 0;
+
+	i |= MASK_INST_RTYPE;
+	i |= MASK_OPER(inst.oper);
+	i |= MASK_REG_DEST(inst.dest);
+	i |= MASK_REG_LEFT(inst.left);
+	i |= MASK_REG_RIGHT(inst.right);
+
+	*dest = i;
+	return 1;
+}
+int generate_single_ni_type(uint32_t *dest, struct i_type inst)
+{
+	uint32_t i = 0;
+
+	i |= MASK_INST_NITYPE;
+	i |= MASK_OPER(inst.oper);
+	i |= MASK_REG_DEST(inst.dest);
+	i |= MASK_REG_LEFT(inst.left);
+	i |= MASK_NI_IMM(inst.imm.value);
+
+	*dest = i;
+	return 1;
+}
+
+int generate_single_wi_type(uint32_t *dest, struct i_type inst)
+{
+	uint32_t i = 0;
+
+	i |= MASK_INST_WITYPE;
+	i |= MASK_OPER(inst.oper);
+	i |= MASK_REG_DEST(inst.dest);
+	i |= MASK_REG_LEFT(inst.left);
+
+	/* two-word instruction - make room for the immediate */
+	i <<= 16;
+
+	i |= inst.imm.value;
+
+	*dest = i;
+	return 2;
+}
+
+int generate_single_ji_type(uint32_t *dest, struct ji_type inst)
+{
+	uint32_t i = 0;
+
+	i |= MASK_INST_JTYPE;
+	i |= MASK_IS_JUMP;
+	i |= MASK_JB_COND(inst.cond);
+	i |= MASK_JI;
+
+	/* two-word instruction - make room for the immediate */
+	i <<= 16;
+
+	i |= inst.imm.value;
+
+	*dest = i;
+	return 2;
+}
+
+int generate_single_jr_type(uint32_t *dest, struct jr_type inst)
+{
+	uint32_t i = 0;
+
+	i |= MASK_INST_JTYPE;
+	i |= MASK_IS_JUMP;
+	i |= MASK_JB_COND(inst.cond);
+	i |= MASK_JR;
+	i |= MASK_JUMP_REGISTER(inst.reg);
+
+	*dest = i;
+	return 1;
+}
+
+int generate_single_b_type(uint32_t *dest, struct b_type inst)
+{
+	uint32_t i = 0;
+
+	i |= MASK_INST_JTYPE;
+	i |= MASK_IS_BRANCH;
+	i |= MASK_JB_COND(inst.cond);
+	i |= MASK_B_OFFSET(inst.imm.value);
+
+	*dest = i;
+	return 1;
+}
+
+
+int look_up_label(struct label *labels, size_t labels_count, uint16_t *val, const char *label)
+{
+	size_t i = 0;
+
+	for (i = 0; i < labels_count; i++) {
+		if (strcmp(labels[i].name, label) == 0) {
+			*val = labels[i].byte_offset;
+			return 0;
+		}
+	}
+
+	/* FIXME emit */
+	fprintf(stderr, "Reference to undefined label `%s'\n", label);
+	return 1;
+}
+
+int output_single(FILE *f, struct label *labels, size_t labels_count, struct instruction inst)
+{
+	int len = 0;
+	uint32_t i = 0;
+
+	switch (inst.type) {
+		case INST_TYPE_R:
+			len = generate_single_r_type(&i, inst.inst.r);
+			break;
+		case INST_TYPE_NI:
+			if (   inst.inst.i.imm_is_ident
+			    && look_up_label(labels, labels_count, &inst.inst.i.imm.value, inst.inst.i.imm.label))
+				return 1;
+
+			len = generate_single_ni_type(&i, inst.inst.i);
+			break;
+		case INST_TYPE_WI:
+			if (   inst.inst.i.imm_is_ident
+			    && look_up_label(labels, labels_count, &inst.inst.i.imm.value, inst.inst.i.imm.label))
+				return 1;
+
+			len = generate_single_wi_type(&i, inst.inst.i);
+			break;
+		case INST_TYPE_JR:
+			len = generate_single_jr_type(&i, inst.inst.jr);
+			break;
+		case INST_TYPE_JI:
+			if (   inst.inst.ji.imm_is_ident
+			    && look_up_label(labels, labels_count, &inst.inst.ji.imm.value, inst.inst.ji.imm.label))
+				return 1;
+
+			len = generate_single_ji_type(&i, inst.inst.ji);
+			break;
+		case INST_TYPE_B:
+			if (   inst.inst.b.imm_is_ident
+			    && look_up_label(labels, labels_count, &inst.inst.b.imm.value, inst.inst.b.imm.label))
+				return 1;
+			inst.inst.b.imm.value -= cur_byte;
+			if (inst.inst.b.imm.value % 2 != 0) {
+				fprintf(stderr, "Internal error: branch offset %d not a multiple of 2\n", inst.inst.b.imm.value);
+			}
+			inst.inst.b.imm.value /= 2;
+
+			len = generate_single_b_type(&i, inst.inst.b);
+			break;
+		default:
+			fprintf(stderr, "Internal error: unhandled instruction type\n");
+			break;
+	}
+
+	if (len == 2) {
+#define RAW
+#ifdef RAW
+		fputc(0xFF & (i >> 24), f);
+		fputc(0xFF & (i >> 16), f);
+#else
+		fprintf(f, "%04x ", i >> 16);
+#endif
+	}
+#ifdef RAW
+	fputc(0xFF & (i >> 8), f);
+	fputc(0xFF & (i >> 0), f);
+#else
+	fprintf(f, "%04x ", 0xFFFF & i);
+#endif
+
+	cur_byte += 2 * len;
+	return 0;
+}
+
+int output_bin(FILE *fout, struct label *labels, size_t label_count, struct instruction *insts, size_t insts_count)
+{
+	size_t i = 0;
+	cur_byte = 0;
+
+#ifndef RAW
+	fprintf(fout, "v2.0 raw\n");
+#endif
+
+	for (i = 0; i < insts_count; i++)
+		if (output_single(fout, labels, label_count, insts[i]))
+			return 1;
+
+	return 0;
+}
diff --git a/output/output_bin.h b/output/output_bin.h
new file mode 100644
index 0000000..d57326b
--- /dev/null
+++ b/output/output_bin.h
@@ -0,0 +1,6 @@
+#ifndef OUTPUT_H
+#define OUTPUT_H
+
+int output_bin(FILE *fout, struct label *labels, size_t label_count, struct instruction *insts, size_t insts_count);
+
+#endif /* OUTPUT_H */
-- 
cgit v1.1