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 | |
init
| -rw-r--r-- | Makefile | 38 | ||||
| -rw-r--r-- | src/fvm.c | 418 | ||||
| -rw-r--r-- | src/fvm.h | 116 |
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 |
