aboutsummaryrefslogtreecommitdiff
path: root/src/fvm.c
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 /src/fvm.c
init
Diffstat (limited to 'src/fvm.c')
-rw-r--r--src/fvm.c418
1 files changed, 418 insertions, 0 deletions
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;
+}