diff options
| author | Mistivia <i@mistivia.com> | 2024-11-15 13:12:29 +0800 |
|---|---|---|
| committer | Mistivia <i@mistivia.com> | 2024-11-15 13:12:29 +0800 |
| commit | bbe08c2ed46a54bf3d16ac2b7f6ead26fc6f3239 (patch) | |
| tree | fa751afe6a36d30477b2b01b160b3c79300d776b /src/fvm.c | |
init
Diffstat (limited to 'src/fvm.c')
| -rw-r--r-- | src/fvm.c | 418 |
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; +} |
