Mistivia 4 miesięcy temu
commit
bbe08c2ed4
3 zmienionych plików z 572 dodań i 0 usunięć
  1. 38 0
      Makefile
  2. 418 0
      src/fvm.c
  3. 116 0
      src/fvm.h

+ 38 - 0
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

+ 418 - 0
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;
+}

+ 116 - 0
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