aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMistivia <i@mistivia.com>2024-11-15 13:12:29 +0800
committerMistivia <i@mistivia.com>2024-11-15 13:12:29 +0800
commitbbe08c2ed46a54bf3d16ac2b7f6ead26fc6f3239 (patch)
treefa751afe6a36d30477b2b01b160b3c79300d776b
init
-rw-r--r--Makefile38
-rw-r--r--src/fvm.c418
-rw-r--r--src/fvm.h116
3 files changed, 572 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4095f31
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,38 @@
+target = foo
+cflags = -g
+ldflags = -lm
+cc = gcc
+
+src = $(shell find src/ -name '*.c' -not -name 'main.c')
+obj = $(src:.c=.o)
+tests=$(shell find tests/ -name '*.c')
+tests_bin=$(tests:.c=.bin)
+
+all: $(target)
+
+$(target): $(obj) src/main.o
+ $(cc) $(cflags) $(ldflags) -o $@ $^
+
+test: $(tests_bin)
+ @echo
+ @echo "Run tests:"
+ @scripts/runall.sh $^
+
+$(obj):%.o:%.c
+ $(cc) -c $(cflags) $< -MD -MF $@.d -o $@
+
+src/main.o:src/main.c
+ $(cc) -c $(cflags) $< -MD -MF $@.d -o $@
+
+$(tests_bin):%.bin:%.c $(obj)
+ $(cc) -Isrc/ $(cflags) $(ldflags) $< $(obj) -MD -MF $@.d -o $@
+
+clean:
+ -rm $(shell find tests/ -name '*.bin')
+ -rm $(shell find . -name '*.o' -or -name '*.d')
+ -rm $(target)
+
+DEPS := $(shell find . -name *.d)
+ifneq ($(DEPS),)
+include $(DEPS)
+endif
diff --git a/src/fvm.c b/src/fvm.c
new file mode 100644
index 0000000..3f1e3fb
--- /dev/null
+++ b/src/fvm.c
@@ -0,0 +1,418 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "fvm.h"
+
+int fvm_init(struct fvm *vm, void *code, int64_t stack_size) {
+ void *stack_vm = malloc(stack_size);
+ vm->sp = (fvm_word_t)(stack_vm + stack_size);
+ vm->bp = vm->sp;
+ vm->pc = (fvm_word_t)code;
+ return 1;
+}
+
+void fvm_push(struct fvm *vm, fvm_word_t val) {
+ vm->sp -= sizeof(fvm_word_t);
+ fvm_store(vm, vm->sp, val);
+}
+
+int64_t fvm_pop(struct fvm *vm) {
+ int64_t r = fvm_load(vm, vm->sp);
+ vm->sp += sizeof(fvm_word_t);
+ return r;
+}
+
+void fvm_pushf(struct fvm *vm, fvm_float_t val) {
+ assert(sizeof(fvm_word_t) >= sizeof(fvm_float_t));
+ vm->sp -= sizeof(fvm_word_t);
+ fvm_storef(vm, vm->sp, val);
+}
+
+fvm_float_t fvm_popf(struct fvm *vm) {
+ assert(sizeof(fvm_word_t) >= sizeof(fvm_float_t));
+ fvm_float_t r = fvm_loadf(vm, vm->sp);
+ vm->sp += sizeof(fvm_word_t);
+ return r;
+}
+
+fvm_float_t fvm_loadf(struct fvm *vm, fvm_word_t addr) {
+ return *(fvm_float_t*)addr;
+}
+
+void fvm_storef(struct fvm *vm, fvm_word_t addr, fvm_float_t val) {
+ *(fvm_float_t*)addr = val;
+}
+
+fvm_word_t fvm_load(struct fvm *vm, fvm_word_t addr) {
+ return *(fvm_word_t*)addr;
+}
+void fvm_store(struct fvm *vm, fvm_word_t addr, int64_t value) {
+ *(fvm_word_t*)addr = value;
+}
+
+int32_t fvm_load32(struct fvm *vm, fvm_word_t addr) {
+ return *(int32_t*)addr;
+}
+void fvm_store32(struct fvm *vm, fvm_word_t addr, int32_t value) {
+ *(int32_t*)addr = value;
+}
+
+int16_t fvm_load16(struct fvm *vm, fvm_word_t addr) {
+ return *(int16_t*)addr;
+}
+void fvm_store16(struct fvm *vm, fvm_word_t addr, int16_t value) {
+ *(int16_t*)addr = value;
+}
+
+int8_t fvm_load8(struct fvm *vm, fvm_word_t addr) {
+ return *(int8_t*)addr;
+}
+void fvm_store8(struct fvm *vm, fvm_word_t addr, int8_t value) {
+ *(int8_t*)addr = value;
+}
+
+
+int fvm_execute(struct fvm *vm) {
+ fvm_word_t a, b, c;
+ fvm_float_t x, y, z;
+ while (1) {
+ enum fvm_op op = (enum fvm_op)(uint8_t)fvm_load8(vm, vm->pc);
+ switch (op) {
+ case FVM_OP_SP:
+ fvm_push(vm, vm->sp);
+ vm->pc++;
+ break;
+ case FVM_OP_SSP:
+ vm->sp = fvm_pop(vm);
+ vm->pc++;
+ break;
+ case FVM_OP_BP:
+ fvm_push(vm, vm->bp);
+ vm->pc++;
+ break;
+ case FVM_OP_SBP:
+ vm->bp = fvm_pop(vm);
+ vm->pc++;
+ break;
+ case FVM_OP_PC:
+ fvm_push(vm, vm->pc);
+ vm->pc++;
+ break;
+ case FVM_OP_IMM:
+ fvm_push(vm, fvm_load(vm, vm->pc + 1));
+ vm->pc += sizeof(fvm_word_t) + 1;
+ break;
+ case FVM_OP_LD:
+ fvm_push(vm, fvm_load(vm, fvm_pop(vm)));
+ vm->pc++;
+ break;
+ case FVM_OP_LD32:
+ fvm_push(vm, fvm_load32(vm, fvm_pop(vm)));
+ vm->pc++;
+ break;
+ case FVM_OP_LD16:
+ fvm_push(vm, fvm_load16(vm, fvm_pop(vm)));
+ vm->pc++;
+ break;
+ case FVM_OP_LD8:
+ fvm_push(vm, fvm_load8(vm, fvm_pop(vm)));
+ vm->pc++;
+ break;
+ case FVM_OP_ST:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_store(vm, b, a);
+ vm->pc++;
+ break;
+ case FVM_OP_ST32:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_store32(vm, b, a);
+ vm->pc++;
+ break;
+ case FVM_OP_ST16:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_store16(vm, b, a);
+ vm->pc++;
+ break;
+ case FVM_OP_ST8:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_store8(vm, b, a);
+ vm->pc++;
+ break;
+ case FVM_OP_DUP:
+ a = fvm_pop(vm);
+ fvm_push(vm, a);
+ fvm_push(vm, a);
+ vm->pc++;
+ break;
+ case FVM_OP_POP:
+ fvm_pop(vm);
+ vm->pc++;
+ break;
+ case FVM_OP_SWAP:
+ a = fvm_pop(vm);
+ b = fvm_pop(vm);
+ fvm_push(vm, a);
+ fvm_push(vm, b);
+ vm->pc++;
+ break;
+ case FVM_OP_OVER:
+ a = fvm_pop(vm);
+ b = fvm_pop(vm);
+ fvm_push(vm, b);
+ fvm_push(vm, a);
+ fvm_push(vm, b);
+ vm->pc++;
+ break;
+ case FVM_OP_ROT:
+ a = fvm_pop(vm);
+ b = fvm_pop(vm);
+ c = fvm_pop(vm);
+ fvm_push(vm, b);
+ fvm_push(vm, a);
+ fvm_push(vm, c);
+ vm->pc++;
+ break;
+ case FVM_OP_ADD:
+ a = fvm_pop(vm);
+ b = fvm_pop(vm);
+ fvm_push(vm, a + b);
+ vm->pc++;
+ break;
+ case FVM_OP_SUB:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a - b);
+ vm->pc++;
+ break;
+ case FVM_OP_MUL:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a * b);
+ vm->pc++;
+ break;
+ case FVM_OP_DIV:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a / b);
+ vm->pc++;
+ break;
+ case FVM_OP_MOD:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a % b);
+ vm->pc++;
+ break;
+ case FVM_OP_SHR:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, (int64_t)(((uint64_t)a) >> b));
+ vm->pc++;
+ break;
+ case FVM_OP_SHL:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a << b);
+ vm->pc++;
+ break;
+ case FVM_OP_SAR:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a >> b);
+ vm->pc++;
+ break;
+ case FVM_OP_AND:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a && b);
+ vm->pc++;
+ break;
+ case FVM_OP_OR:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a || b);
+ vm->pc++;
+ break;
+ case FVM_OP_NOT:
+ a = fvm_pop(vm);
+ fvm_push(vm, !a);
+ vm->pc++;
+ break;
+ case FVM_OP_BITAND:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a & b);
+ vm->pc++;
+ break;
+ case FVM_OP_BITOR:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a | b);
+ vm->pc++;
+ break;
+ case FVM_OP_XOR:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a ^ b);
+ vm->pc++;
+ break;
+ case FVM_OP_INVERT:
+ a = fvm_pop(vm);
+ fvm_push(vm, ~a);
+ vm->pc++;
+ break;
+ case FVM_OP_GE:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a >= b);
+ vm->pc++;
+ break;
+ case FVM_OP_LE:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a <= b);
+ vm->pc++;
+ break;
+ case FVM_OP_GT:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a > b);
+ vm->pc++;
+ break;
+ case FVM_OP_LT:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a < b);
+ vm->pc++;
+ break;
+ case FVM_OP_EQ:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a == b);
+ vm->pc++;
+ break;
+ case FVM_OP_NEQ:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ fvm_push(vm, a != b);
+ vm->pc++;
+ break;
+ case FVM_OP_JMP:
+ vm->pc = fvm_pop(vm);
+ break;
+ case FVM_OP_JZ:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ if (a) {
+ vm->pc++;
+ break;
+ } else {
+ vm->pc = b;
+ break;
+ }
+ case FVM_OP_JNZ:
+ b = fvm_pop(vm);
+ a = fvm_pop(vm);
+ if (a) {
+ vm->pc = b;
+ break;
+ } else {
+ vm->pc++;
+ break;
+ }
+ case FVM_OP_CALL:
+ a = fvm_pop(vm);
+ fvm_push(vm, vm->pc);
+ vm->pc = a;
+ break;
+ case FVM_OP_RET:
+ a = fvm_pop(vm);
+ vm->pc = a;
+ break;
+ case FVM_OP_SYSCALL:
+ a = fvm_pop(vm);
+ vm->pc++;
+ (*(vm->syscall_table[a]))(vm);
+ break;
+ case FVM_OP_FADD:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_pushf(vm, x + y);
+ vm->pc++;
+ break;
+ case FVM_OP_FSUB:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_pushf(vm, x - y);
+ vm->pc++;
+ break;
+ case FVM_OP_FMUL:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_pushf(vm, x * y);
+ vm->pc++;
+ break;
+ case FVM_OP_FDIV:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_pushf(vm, x / y);
+ vm->pc++;
+ break;
+ case FVM_OP_FGE:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_push(vm, x >= y);
+ vm->pc++;
+ break;
+ case FVM_OP_FGT:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_push(vm, x > y);
+ vm->pc++;
+ break;
+ case FVM_OP_FLE:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_push(vm, x <= y);
+ vm->pc++;
+ break;
+ case FVM_OP_FLT:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_push(vm, x < y);
+ vm->pc++;
+ break;
+ case FVM_OP_FEQ:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_push(vm, x == y);
+ vm->pc++;
+ break;
+ case FVM_OP_FNEQ:
+ y = fvm_popf(vm);
+ x = fvm_popf(vm);
+ fvm_push(vm, x != y);
+ vm->pc++;
+ break;
+ case FVM_OP_FTI:
+ x = fvm_popf(vm);
+ fvm_push(vm, (fvm_word_t)x);
+ vm->pc++;
+ break;
+ case FVM_OP_ITF:
+ a = fvm_pop(vm);
+ fvm_pushf(vm, (fvm_float_t)x);
+ vm->pc++;
+ break;
+ default:
+ fprintf(stderr, "unknown opcode.\n");
+ break;
+ }
+ }
+ return -1;
+}
diff --git a/src/fvm.h b/src/fvm.h
new file mode 100644
index 0000000..40c71e2
--- /dev/null
+++ b/src/fvm.h
@@ -0,0 +1,116 @@
+#ifndef FVM_H_
+#define FVM_H_
+
+#include <stdint.h>
+
+typedef int64_t fvm_word_t;
+typedef double fvm_float_t;;
+
+struct fvm;
+
+// return non-zero if vm should be suspended
+typedef int64_t (*fvm_syscall_fn_t)(struct fvm* vm);
+
+struct fvm {
+ fvm_word_t sp;
+ fvm_word_t bp;
+ fvm_word_t pc;
+ fvm_syscall_fn_t *syscall_table;
+};
+
+enum fvm_op {
+ FVM_OP_SP,
+ FVM_OP_SSP,
+ FVM_OP_BP,
+ FVM_OP_SBP,
+ FVM_OP_PC,
+
+ FVM_OP_IMM,
+
+ FVM_OP_LD8,
+ FVM_OP_LD16,
+ FVM_OP_LD32,
+ FVM_OP_LD,
+ FVM_OP_ST8,
+ FVM_OP_ST16,
+ FVM_OP_ST32,
+ FVM_OP_ST,
+
+ FVM_OP_DUP,
+ FVM_OP_POP,
+ FVM_OP_SWAP,
+ FVM_OP_OVER,
+ FVM_OP_ROT,
+
+ FVM_OP_ADD,
+ FVM_OP_SUB,
+ FVM_OP_DIV,
+ FVM_OP_MUL,
+ FVM_OP_MOD,
+
+ FVM_OP_SHR,
+ FVM_OP_SHL,
+ FVM_OP_SAR,
+
+ FVM_OP_AND,
+ FVM_OP_OR,
+ FVM_OP_NOT,
+
+ FVM_OP_BITAND,
+ FVM_OP_BITOR,
+ FVM_OP_XOR,
+ FVM_OP_INVERT,
+
+ FVM_OP_GT,
+ FVM_OP_LT,
+ FVM_OP_GE,
+ FVM_OP_LE,
+ FVM_OP_EQ,
+ FVM_OP_NEQ,
+
+ FVM_OP_JMP,
+ FVM_OP_JZ,
+ FVM_OP_JNZ,
+
+ FVM_OP_RET,
+ FVM_OP_CALL,
+ FVM_OP_SYSCALL,
+
+ FVM_OP_FADD,
+ FVM_OP_FSUB,
+ FVM_OP_FMUL,
+ FVM_OP_FDIV,
+
+ FVM_OP_FGE,
+ FVM_OP_FGT,
+ FVM_OP_FLE,
+ FVM_OP_FLT,
+ FVM_OP_FEQ,
+ FVM_OP_FNEQ,
+
+ FVM_OP_FTI,
+ FVM_OP_ITF,
+};
+
+int fvm_init(struct fvm *vm, void *code, int64_t stack_size);
+int fvm_execute(struct fvm *vm);
+
+void fvm_push(struct fvm *vm, fvm_word_t value);
+int64_t fvm_pop(struct fvm *vm);
+
+fvm_float_t fvm_loadf(struct fvm *vm, fvm_word_t addr);
+void fvm_storef(struct fvm *vm, fvm_word_t addr, fvm_float_t val);
+
+fvm_word_t fvm_load(struct fvm *vm, fvm_word_t addr);
+void fvm_store(struct fvm *vm, fvm_word_t addr, int64_t value);
+
+int32_t fvm_load32(struct fvm *vm, fvm_word_t addr);
+void fvm_store32(struct fvm *vm, fvm_word_t addr, int32_t value);
+
+int16_t fvm_load16(struct fvm *vm, fvm_word_t addr);
+void fvm_store16(struct fvm *vm, fvm_word_t addr, int16_t value);
+
+int8_t fvm_load8(struct fvm *vm, fvm_word_t addr);
+void fvm_store8(struct fvm *vm, fvm_word_t addr, int8_t value);
+
+#endif