mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-28 08:44:06 +02:00
slige: add runtime
This commit is contained in:
parent
8f3523d4e1
commit
6d1693c318
8
slige/runtime/.clang-format
Normal file
8
slige/runtime/.clang-format
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: WebKit
|
||||||
|
IndentWidth: 4
|
||||||
|
ColumnLimit: 80
|
||||||
|
IndentCaseLabels: true
|
||||||
|
InsertNewlineAtEOF: true
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
|
1
slige/runtime/.gitignore
vendored
Normal file
1
slige/runtime/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
build/
|
52
slige/runtime/Makefile
Normal file
52
slige/runtime/Makefile
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Slige 2 Runtime
|
||||||
|
#
|
||||||
|
# To build for debug:
|
||||||
|
# $ make
|
||||||
|
#
|
||||||
|
# To build for release:
|
||||||
|
# $ make RELEASE=1
|
||||||
|
#
|
||||||
|
# NOTICE that `RELEASE=1` is __after__ `make`
|
||||||
|
#
|
||||||
|
|
||||||
|
C_FLAGS = \
|
||||||
|
-std=c17 \
|
||||||
|
-Wall -Wextra -Wpedantic -Wconversion \
|
||||||
|
-pedantic -pedantic-errors \
|
||||||
|
|
||||||
|
L_FLAGS = -lm
|
||||||
|
|
||||||
|
F_FLAGS =
|
||||||
|
OPTIMIZATION =
|
||||||
|
|
||||||
|
RELEASE=0
|
||||||
|
|
||||||
|
ifeq ($(RELEASE),1)
|
||||||
|
C_FLAGS += -Werror
|
||||||
|
F_FLAGS += -flto=auto
|
||||||
|
OPTIMIZATION += -O3
|
||||||
|
else
|
||||||
|
C_FLAGS += -g
|
||||||
|
F_FLAGS += -fsanitize=address,undefined
|
||||||
|
OPTIMIZATION += -Og
|
||||||
|
endif
|
||||||
|
|
||||||
|
HEADERS = $(shell find src/ -name *.h)
|
||||||
|
C_FILES = $(shell find src/ -name *.c)
|
||||||
|
O_FILES = $(patsubst src/%.c,build/%.o,$(C_FILES))
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
|
||||||
|
all: build_dir runtime
|
||||||
|
|
||||||
|
runtime: $(O_FILES)
|
||||||
|
$(CC) -o build/$@ $^ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS)
|
||||||
|
|
||||||
|
build/%.o: src/%.c $(HEADERS)
|
||||||
|
$(CC) $< -c -o $@ $(C_FLAGS) $(OPTIMIZATION) $(F_FLAGS)
|
||||||
|
|
||||||
|
build_dir:
|
||||||
|
mkdir -p build/
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf build/
|
9
slige/runtime/compile_flags.txt
Normal file
9
slige/runtime/compile_flags.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
xc
|
||||||
|
-std=c17
|
||||||
|
-Wall
|
||||||
|
-Wextra
|
||||||
|
-Wpedantic
|
||||||
|
-Wconversion
|
||||||
|
-pedantic
|
||||||
|
-pedantic-errors
|
||||||
|
|
6
slige/runtime/src/main.c
Normal file
6
slige/runtime/src/main.c
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
printf("hello world\n");
|
||||||
|
}
|
8
slige/runtime/src/util.h
Normal file
8
slige/runtime/src/util.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
#define ALWAYS_INLINE __attribute__((always_inline))
|
||||||
|
|
||||||
|
#define MAYBE_UNUSED __attribute__((unused))
|
||||||
|
|
||||||
|
#endif
|
899
slige/runtime/src/vm.c
Normal file
899
slige/runtime/src/vm.c
Normal file
@ -0,0 +1,899 @@
|
|||||||
|
#include "vm.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void vm_construct(VM* vm)
|
||||||
|
{
|
||||||
|
size_t files_capacity = 64;
|
||||||
|
FsFile* files = malloc(sizeof(FsFile) * files_capacity);
|
||||||
|
|
||||||
|
*vm = (VM) {
|
||||||
|
.files = files,
|
||||||
|
.files_size = 0,
|
||||||
|
.files_capacity = files_capacity,
|
||||||
|
.next_file_id = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
vm->files[vm->files_size++] = (FsFile) { .id = 0, .fp = stdin };
|
||||||
|
vm->files[vm->files_size++] = (FsFile) { .id = 1, .fp = stdout };
|
||||||
|
vm->files[vm->files_size++] = (FsFile) { .id = 2, .fp = stderr };
|
||||||
|
vm->next_file_id += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_destroy(VM* vm)
|
||||||
|
{
|
||||||
|
(void)vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE static inline Op line_op(uint32_t line)
|
||||||
|
{
|
||||||
|
return line & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE static inline Reg line_dst(uint32_t line)
|
||||||
|
{
|
||||||
|
return line >> 8 & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE static inline Reg line_src_right(uint32_t line)
|
||||||
|
{
|
||||||
|
return line >> 16 & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE static inline Reg line_src_left(uint32_t line)
|
||||||
|
{
|
||||||
|
return line >> 24 & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE static inline uint32_t eat_i32(const uint32_t** pc)
|
||||||
|
{
|
||||||
|
uint32_t imm = **pc;
|
||||||
|
++*pc;
|
||||||
|
return imm;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE static inline uint64_t eat_i64(const uint32_t** pc)
|
||||||
|
{
|
||||||
|
uint64_t imm = **pc;
|
||||||
|
++*pc;
|
||||||
|
imm &= (uint64_t)**pc << 32;
|
||||||
|
++*pc;
|
||||||
|
return imm;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE static inline double eat_f64(const uint32_t** pc)
|
||||||
|
{
|
||||||
|
return (double)eat_i64(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_run(VM* vm, const uint32_t* program)
|
||||||
|
{
|
||||||
|
(void)vm;
|
||||||
|
|
||||||
|
Regs regs = {
|
||||||
|
.iregs = { 0 },
|
||||||
|
.fregs = { 0.0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
uint64_t* const stack = malloc(STACK_SIZE * sizeof(uint64_t));
|
||||||
|
Call* const call_stack_base = malloc(CALL_STACK_SIZE * sizeof(Call));
|
||||||
|
|
||||||
|
Call* call_stack = call_stack_base;
|
||||||
|
|
||||||
|
const uint32_t* program_base = program;
|
||||||
|
const uint32_t* pc = program_base;
|
||||||
|
|
||||||
|
uint64_t* sb = stack;
|
||||||
|
uint64_t* sp = sb;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
uint32_t line = *pc;
|
||||||
|
Op op = line_op(line);
|
||||||
|
++pc;
|
||||||
|
switch (op) {
|
||||||
|
case Op_Nop: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Halt: {
|
||||||
|
goto halt_program;
|
||||||
|
}
|
||||||
|
case Op_Builtin: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_Call: {
|
||||||
|
Reg reg = line_src_left(line);
|
||||||
|
*call_stack = (Call) { .caller_sb = sb, .return_ptr = pc + 1 };
|
||||||
|
++call_stack;
|
||||||
|
pc = program_base + regs.iregs[reg];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_CallI: {
|
||||||
|
uint32_t ptr = eat_i32(&pc);
|
||||||
|
*call_stack = (Call) { .caller_sb = sb, .return_ptr = pc + 1 };
|
||||||
|
++call_stack;
|
||||||
|
pc = program_base + ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Ret: {
|
||||||
|
--call_stack;
|
||||||
|
sb = call_stack->caller_sb;
|
||||||
|
pc = call_stack->return_ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Alloca: {
|
||||||
|
uint32_t size = eat_i32(&pc);
|
||||||
|
sp += size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_Jmp: {
|
||||||
|
uint32_t ptr = eat_i32(&pc);
|
||||||
|
pc = program_base + ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Jnz: {
|
||||||
|
uint32_t ptr = eat_i32(&pc);
|
||||||
|
if (regs.iregs[line_src_right(line)] != 0) {
|
||||||
|
pc = program_base + ptr;
|
||||||
|
} else {
|
||||||
|
++pc;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Jz: {
|
||||||
|
Reg reg = line_src_left(line);
|
||||||
|
uint32_t ptr = eat_i32(&pc);
|
||||||
|
if (regs.iregs[reg] == 0) {
|
||||||
|
pc = program_base + ptr;
|
||||||
|
} else {
|
||||||
|
++pc;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_Load8: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.iregs[dst] = *(uint8_t*)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadI8: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
uint64_t addr = eat_i64(&pc);
|
||||||
|
regs.iregs[dst] = *(uint8_t*)addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadA8: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg base = line_src_left(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
regs.iregs[dst] = *(uint8_t*)(addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Load16: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.iregs[dst] = *(uint16_t*)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadI16: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
uint64_t addr = eat_i64(&pc);
|
||||||
|
regs.iregs[dst] = *(uint16_t*)addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadA16: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg base = line_src_left(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
regs.iregs[dst] = *(uint16_t*)(addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Load32: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.iregs[dst] = *(uint32_t*)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadI32: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
uint64_t addr = eat_i64(&pc);
|
||||||
|
regs.iregs[dst] = *(uint32_t*)addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadA32: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg base = line_src_left(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
regs.iregs[dst] = *(uint32_t*)(addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Load64: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.iregs[dst] = *(uint64_t*)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadI64: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
uint64_t addr = eat_i64(&pc);
|
||||||
|
regs.iregs[dst] = *(uint64_t*)addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadA64: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg base = line_src_left(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
regs.iregs[dst] = *(uint64_t*)(addr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.fregs[dst] = *(double*)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadIF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
uint64_t addr = eat_i64(&pc);
|
||||||
|
regs.fregs[dst] = *(double*)addr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadAF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg base = line_src_left(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
regs.fregs[dst]
|
||||||
|
= *(double*)(regs.iregs[base] + regs.iregs[offset] * incr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_Store8: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
*(uint8_t*)regs.iregs[dst] = (uint8_t)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_StoreA8: {
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
Reg base = line_dst(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
*(uint8_t*)addr = (uint8_t)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Store16: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
*(uint16_t*)regs.iregs[dst] = (uint16_t)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_StoreA16: {
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
Reg base = line_dst(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
*(uint16_t*)addr = (uint16_t)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Store32: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
*(uint32_t*)regs.iregs[dst] = (uint32_t)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_StoreA32: {
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
Reg base = line_dst(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
*(uint32_t*)addr = (uint32_t)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Store64: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
*(uint64_t*)regs.iregs[dst] = regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_StoreA64: {
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
Reg base = line_dst(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
*(uint64_t*)addr = regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_StoreF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
*(double*)regs.iregs[dst] = regs.fregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_StoreAF: {
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
Reg base = line_dst(line);
|
||||||
|
Reg offset = line_src_right(line);
|
||||||
|
uint32_t incr = eat_i32(&pc);
|
||||||
|
uint64_t addr = regs.iregs[base] + regs.iregs[offset] * incr;
|
||||||
|
*(double*)addr = regs.fregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_LoadImm32: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
regs.iregs[dst] = eat_i32(&pc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadImm64: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
regs.iregs[dst] = eat_i64(&pc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadImmF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
regs.fregs[dst] = eat_f64(&pc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadSb: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
regs.iregs[dst] = (uint64_t)sb;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LoadSp: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
regs.iregs[dst] = (uint64_t)sp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_MovII: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_MovIF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.fregs[dst] = (double)regs.iregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_MovFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.iregs[dst] = (uint64_t)regs.fregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_MovFF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
regs.fregs[dst] = regs.fregs[src];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op_Push: {
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
*sp = regs.iregs[src];
|
||||||
|
++sp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Pop: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
--sp;
|
||||||
|
regs.iregs[dst] = *sp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Op_PushF: {
|
||||||
|
Reg src = line_src_left(line);
|
||||||
|
*sp = (uint64_t)regs.fregs[src];
|
||||||
|
++sp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_PopF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
--sp;
|
||||||
|
regs.fregs[dst] = (double)*sp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_Eq: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] == regs.iregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Ne: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] != regs.iregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Lt: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] < regs.iregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Gt: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] > regs.iregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Lte: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] <= regs.iregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Gte: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] >= regs.iregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_And: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] & regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Or: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] | regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Xor: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] ^ regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Add: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] + regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Sub: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] - regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Mul: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] * regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Div: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] / regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_Rem: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] / regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_IMul: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
int64_t val
|
||||||
|
= (int64_t)regs.iregs[left] * (int64_t)regs.iregs[right];
|
||||||
|
regs.iregs[dst] = (uint64_t)val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_IDiv: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
int64_t val
|
||||||
|
= (int64_t)regs.iregs[left] / (int64_t)regs.iregs[right];
|
||||||
|
regs.iregs[dst] = (uint64_t)val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_EqI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] == right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_NeI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] != right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LtI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] < right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_GtI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] > right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LteI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] <= right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_GteI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] >= right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_AndI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] & right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_OrI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] | right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_XorI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] ^ right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_AddI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] + right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_SubI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] - right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_RSubI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
uint64_t left = eat_i32(&pc);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = left - regs.iregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_MulI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] * right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_DivI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] / right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_RemI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
regs.iregs[dst] = regs.iregs[left] % right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_IMulI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
int64_t val = (int64_t)regs.iregs[left] * (int64_t)right;
|
||||||
|
regs.iregs[dst] = (uint64_t)val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_IDivI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
uint64_t right = eat_i32(&pc);
|
||||||
|
int64_t val = (int64_t)regs.iregs[left] / (int64_t)right;
|
||||||
|
regs.iregs[dst] = (uint64_t)val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_EqF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] == regs.fregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_NeF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] != regs.fregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LtF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] < regs.fregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_GtF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] > regs.fregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LteF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] <= regs.fregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_GteF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] >= regs.fregs[right] ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_AddF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.fregs[dst] = regs.fregs[left] + regs.fregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_SubF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.fregs[dst] = regs.fregs[left] - regs.fregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_MulF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.fregs[dst] = regs.fregs[left] * regs.fregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_DivF: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.fregs[dst] = regs.fregs[left] / regs.fregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
case Op_EqFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] == right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_NeFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] != right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LtFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] < right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_GtFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] > right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_LteFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] <= right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_GteFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.iregs[dst] = regs.fregs[left] >= right ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_AddFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.fregs[dst] = regs.fregs[left] + right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_SubFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.fregs[dst] = regs.fregs[left] - right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_RSubFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
double left = eat_f64(&pc);
|
||||||
|
Reg right = line_src_right(line);
|
||||||
|
regs.fregs[dst] = left - regs.fregs[right];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_MulFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.fregs[dst] = regs.fregs[left] * right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_DivFI: {
|
||||||
|
Reg dst = line_dst(line);
|
||||||
|
Reg left = line_src_left(line);
|
||||||
|
double right = eat_f64(&pc);
|
||||||
|
regs.fregs[dst] = regs.fregs[left] / right;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
halt_program:
|
||||||
|
free(stack);
|
||||||
|
free(call_stack_base);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_exec_builtin(VM* vm, Builtin builtin, Regs* regs)
|
||||||
|
{
|
||||||
|
MAYBE_UNUSED uint64_t* res = ®s->iregs[0];
|
||||||
|
MAYBE_UNUSED uint64_t arg1 = regs->iregs[1];
|
||||||
|
MAYBE_UNUSED uint64_t arg2 = regs->iregs[2];
|
||||||
|
MAYBE_UNUSED uint64_t arg3 = regs->iregs[3];
|
||||||
|
MAYBE_UNUSED uint64_t arg4 = regs->iregs[4];
|
||||||
|
|
||||||
|
switch (builtin) {
|
||||||
|
case Builtin_Alloc: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Builtin_FsOpen: {
|
||||||
|
uint64_t id = 0;
|
||||||
|
int r = vm_open_file(vm, &id, (char*)arg1, (char*)arg2);
|
||||||
|
*res = r == 0 ? 0 : 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Builtin_FsClose: {
|
||||||
|
vm_close_file(vm, arg1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Builtin_FsWrite:
|
||||||
|
fwrite((void*)arg2, arg3, 1, vm_file_fp(vm, arg1));
|
||||||
|
break;
|
||||||
|
case Builtin_FsRead:
|
||||||
|
fread((void*)arg2, arg3, 1, vm_file_fp(vm, arg1));
|
||||||
|
break;
|
||||||
|
case Builtin_FsFlush:
|
||||||
|
fflush(vm_file_fp(vm, arg1));
|
||||||
|
break;
|
||||||
|
case Builtin_FsEof:
|
||||||
|
*res = feof(vm_file_fp(vm, arg1)) == EOF ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_open_file(VM* vm, uint64_t* id, const char* path, const char* mode)
|
||||||
|
{
|
||||||
|
FILE* fp = fopen(path, mode);
|
||||||
|
if (fp == NULL)
|
||||||
|
return -1;
|
||||||
|
*id = vm->next_file_id;
|
||||||
|
++vm->next_file_id;
|
||||||
|
vm->files[vm->files_size++] = (FsFile) { *id, fp };
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_close_file(VM* vm, uint64_t id)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for (; i < vm->files_size; ++i)
|
||||||
|
if (vm->files[i].id == id)
|
||||||
|
break;
|
||||||
|
if (i == vm->files_size)
|
||||||
|
return;
|
||||||
|
for (size_t j = i; j < vm->files_size - 1; ++j)
|
||||||
|
vm->files[j] = vm->files[j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* vm_file_fp(VM* vm, uint64_t id)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < vm->files_size; ++i)
|
||||||
|
if (vm->files[i].id == id)
|
||||||
|
return vm->files[i].fp;
|
||||||
|
return NULL;
|
||||||
|
}
|
221
slige/runtime/src/vm.h
Normal file
221
slige/runtime/src/vm.h
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
#ifndef VM_H
|
||||||
|
#define VM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/// Instruction operations.
|
||||||
|
///
|
||||||
|
/// These definitions dictate how instructions should be decoded.
|
||||||
|
///
|
||||||
|
/// `%ireg` is an int or pointer register.
|
||||||
|
/// `%i32` is a 32-bit immediate int value.
|
||||||
|
/// `%i64` is a 64-bit immediate int value.
|
||||||
|
///
|
||||||
|
/// `%freg` is a float register.
|
||||||
|
/// `%f64` is a 64-bit immediate float value.
|
||||||
|
///
|
||||||
|
/// The instruction header is 4 bytes. Usually instruction headers are encoding
|
||||||
|
/// like this:
|
||||||
|
/// ```
|
||||||
|
/// XX = 1 byte
|
||||||
|
///
|
||||||
|
/// XX XX XX XX
|
||||||
|
/// ^^ ^^ ^^ ^^ - Op
|
||||||
|
/// | | |
|
||||||
|
/// | | ++-- destination register
|
||||||
|
/// | |
|
||||||
|
/// | ++-- right/second operand register
|
||||||
|
/// |
|
||||||
|
/// ++--- left/first operand register
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Then immediate values are appended after the header.
|
||||||
|
///
|
||||||
|
/// Immediates are little endian. This means that the smallest byte has the
|
||||||
|
/// smallest address. Example: take a value like `4660`, convert it to hex
|
||||||
|
/// `0x1234`, split up in bytes `12 34`, put it into an array `[12, 34]`. This
|
||||||
|
/// is big endian ie. WRONG. Put the bytes `12 34` into the array in reverse
|
||||||
|
/// order `[34, 12]`. This is little endiang ie. CORRECT.
|
||||||
|
///
|
||||||
|
typedef enum {
|
||||||
|
Op_Nop,
|
||||||
|
Op_Halt,
|
||||||
|
Op_Builtin,
|
||||||
|
|
||||||
|
Op_Call,
|
||||||
|
Op_CallI,
|
||||||
|
Op_Ret,
|
||||||
|
Op_Alloca,
|
||||||
|
|
||||||
|
Op_Jmp,
|
||||||
|
Op_Jnz,
|
||||||
|
Op_Jz,
|
||||||
|
|
||||||
|
Op_Load8,
|
||||||
|
Op_LoadI8,
|
||||||
|
Op_LoadA8,
|
||||||
|
Op_Load16,
|
||||||
|
Op_LoadI16,
|
||||||
|
Op_LoadA16,
|
||||||
|
Op_Load32,
|
||||||
|
Op_LoadI32,
|
||||||
|
Op_LoadA32,
|
||||||
|
Op_Load64,
|
||||||
|
Op_LoadI64,
|
||||||
|
Op_LoadA64,
|
||||||
|
Op_LoadF,
|
||||||
|
Op_LoadIF,
|
||||||
|
Op_LoadAF,
|
||||||
|
|
||||||
|
Op_Store8,
|
||||||
|
Op_StoreA8,
|
||||||
|
Op_Store16,
|
||||||
|
Op_StoreA16,
|
||||||
|
Op_Store32,
|
||||||
|
Op_StoreA32,
|
||||||
|
Op_Store64,
|
||||||
|
Op_StoreA64,
|
||||||
|
Op_StoreF,
|
||||||
|
Op_StoreAF,
|
||||||
|
|
||||||
|
Op_LoadImm32,
|
||||||
|
Op_LoadImm64,
|
||||||
|
Op_LoadImmF,
|
||||||
|
Op_LoadSb,
|
||||||
|
Op_LoadSp,
|
||||||
|
|
||||||
|
Op_MovII,
|
||||||
|
Op_MovIF,
|
||||||
|
Op_MovFI,
|
||||||
|
Op_MovFF,
|
||||||
|
|
||||||
|
Op_Push,
|
||||||
|
Op_Pop,
|
||||||
|
|
||||||
|
Op_PushF,
|
||||||
|
Op_PopF,
|
||||||
|
|
||||||
|
Op_Eq,
|
||||||
|
Op_Ne,
|
||||||
|
Op_Lt,
|
||||||
|
Op_Gt,
|
||||||
|
Op_Lte,
|
||||||
|
Op_Gte,
|
||||||
|
Op_And,
|
||||||
|
Op_Or,
|
||||||
|
Op_Xor,
|
||||||
|
Op_Add,
|
||||||
|
Op_Sub,
|
||||||
|
Op_Mul,
|
||||||
|
Op_Div,
|
||||||
|
Op_Rem,
|
||||||
|
Op_IMul,
|
||||||
|
Op_IDiv,
|
||||||
|
|
||||||
|
Op_EqI,
|
||||||
|
Op_NeI,
|
||||||
|
Op_LtI,
|
||||||
|
Op_GtI,
|
||||||
|
Op_LteI,
|
||||||
|
Op_GteI,
|
||||||
|
Op_AndI,
|
||||||
|
Op_OrI,
|
||||||
|
Op_XorI,
|
||||||
|
Op_AddI,
|
||||||
|
Op_SubI,
|
||||||
|
Op_RSubI,
|
||||||
|
Op_MulI,
|
||||||
|
Op_DivI,
|
||||||
|
Op_RemI,
|
||||||
|
Op_IMulI,
|
||||||
|
Op_IDivI,
|
||||||
|
|
||||||
|
Op_EqF,
|
||||||
|
Op_NeF,
|
||||||
|
Op_LtF,
|
||||||
|
Op_GtF,
|
||||||
|
Op_LteF,
|
||||||
|
Op_GteF,
|
||||||
|
Op_AddF,
|
||||||
|
Op_SubF,
|
||||||
|
Op_MulF,
|
||||||
|
Op_DivF,
|
||||||
|
|
||||||
|
Op_EqFI,
|
||||||
|
Op_NeFI,
|
||||||
|
Op_LtFI,
|
||||||
|
Op_GtFI,
|
||||||
|
Op_LteFI,
|
||||||
|
Op_GteFI,
|
||||||
|
Op_AddFI,
|
||||||
|
Op_SubFI,
|
||||||
|
Op_RSubFI,
|
||||||
|
Op_MulFI,
|
||||||
|
Op_DivFI,
|
||||||
|
} Op;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
Builtin_Alloc,
|
||||||
|
Builtin_FsOpen,
|
||||||
|
Builtin_FsClose,
|
||||||
|
Builtin_FsWrite,
|
||||||
|
Builtin_FsRead,
|
||||||
|
Builtin_FsFlush,
|
||||||
|
Builtin_FsEof,
|
||||||
|
} Builtin;
|
||||||
|
|
||||||
|
#define IREGS 32
|
||||||
|
#define FREGS 16
|
||||||
|
|
||||||
|
#define STACK_SIZE 65536
|
||||||
|
#define CALL_STACK_SIZE 65536
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t id;
|
||||||
|
FILE* fp;
|
||||||
|
} FsFile;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Main data structure for the runtime virtual machine.
|
||||||
|
///
|
||||||
|
/// NOTICE: This structure is not necessarily used actively when running the
|
||||||
|
/// program. This is because the runner caches some values instead of storing
|
||||||
|
/// them in the struct. The point of this struct is mostly to provide some form
|
||||||
|
/// of cohesion of the virtual machine. This means that for debugging, this
|
||||||
|
/// internals of this struct CANNOT be relied on for live data.
|
||||||
|
///
|
||||||
|
typedef struct {
|
||||||
|
FsFile* files;
|
||||||
|
size_t files_size;
|
||||||
|
size_t files_capacity;
|
||||||
|
uint64_t next_file_id;
|
||||||
|
} VM;
|
||||||
|
|
||||||
|
void vm_construct(VM* vm);
|
||||||
|
void vm_destroy(VM* vm);
|
||||||
|
|
||||||
|
typedef uint8_t Reg;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t iregs[IREGS];
|
||||||
|
double fregs[FREGS];
|
||||||
|
} Regs;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t* caller_sb;
|
||||||
|
const uint32_t* return_ptr;
|
||||||
|
} Call;
|
||||||
|
|
||||||
|
/// Runner function for the VM.
|
||||||
|
///
|
||||||
|
/// 'program` is a program encoded according to the encoding rules. The program
|
||||||
|
/// is expected to exit before hitting the end, hence there's no size parameter.
|
||||||
|
int vm_run(VM* vm, const uint32_t* program);
|
||||||
|
|
||||||
|
int vm_exec_builtin(VM* vm, Builtin builtin, Regs* regs);
|
||||||
|
int vm_open_file(VM* vm, uint64_t* id, const char* path, const char* mode);
|
||||||
|
void vm_close_file(VM* vm, uint64_t id);
|
||||||
|
FILE* vm_file_fp(VM* vm, uint64_t id);
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user