From 664006b1c42aae84a3c749d9b71c1047e0b8ffcf Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Thu, 2 Mar 2023 20:03:52 -0800 Subject: Initial commit. --- vm/src/vm.h | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 vm/src/vm.h (limited to 'vm/src/vm.h') diff --git a/vm/src/vm.h b/vm/src/vm.h new file mode 100644 index 0000000..03dfc88 --- /dev/null +++ b/vm/src/vm.h @@ -0,0 +1,166 @@ +#pragma once + +#include +#include +#include + +typedef enum Op { + Exit, // Pop value from the stack and return as exit code. Return 0 if the + // stack is empty. + Push, + Pop, + Add, + Sub, + Mul, + Div, + Dec, // Decrement the top of the stack by 1. + Empty, // Check whether the stack is empty. Pushes a bool. + Cmp, // Pop the top of the stack and compare it with the payload. Pushes a + // bool. + /* Blocks */ + End, // Marks the end of a block. + Break, // Exit the current block. + Loop, // Push a loop block. Payload (i32): label. + /* Branches */ + Br, // Branch. Payload (i64): [(i32) conditional? | (i32) label]. + // A condtional branch pops a bool from the stack and branches if true. + // The condition can also be negated. See br_if(). + /* Functions */ + Func, + Arg, + Call, + /* Locals */ + Local, // Create a local variable. + LocalRd, // Load a local variable into the top of the stack. + LocalWr, // Pop the top of the stack and store it in a local variable. +} Op; + +typedef enum Type { + I32, + F32, +} Type; + +// Label type for blocks and locals. +typedef uint32_t Label; + +typedef struct Branch { + Label label; + bool conditional : 1; // True for conditional branches. + bool expected : 1; // Comparison value for conditional branches. +} Branch; + +typedef struct Function { + Label label; +} Function; + +typedef struct Value { + union { + uint64_t u64; + int32_t i32; + float f32; + Branch branch; + Label label; + }; +} Value; + +typedef struct Inst { + Op op : 5; + Type type : 2; + Value payload; +} Inst; + +typedef struct Vm Vm; + +// ----------------------------------------------------------------------------- +// VM API + +/// Create a new virtual machine. +Vm* vm_new(); + +/// Destroy the virtual machine. +void vm_del(Vm**); + +/// Execute code on the virtual machine. +/// +/// Returns the program exit code if an exit operation is executed, 0 otherwise. +int vm_run(Vm*, const Inst[], size_t count); + +/// Prints the virtual machine's stack to stdout. +void vm_print_stack(const Vm*); + +// ----------------------------------------------------------------------------- +// Programming API + +/// Exit the program. +static inline Inst vmExit() { return (Inst){.op = Exit}; } + +/// Push a value. +static inline Inst vmPushI32(int32_t value) { + return (Inst){.op = Push, .type = I32, .payload = (Value){.i32 = value}}; +} + +/// Pop a value. +static inline Inst vmPop(Type type) { return (Inst){.op = Pop, .type = type}; } + +/// Add two values. +static inline Inst vmAdd(Type type) { return (Inst){.op = Add, .type = type}; } + +/// Decrement a value. +static inline Inst vmDec(Type type) { return (Inst){.op = Dec, .type = type}; } + +/// Compare a value. +static inline Inst vmCmpI32(int32_t value) { + return (Inst){.op = Cmp, .type = I32, .payload = (Value){.i32 = value}}; +} + +/// End the current block. +static inline Inst vmEnd() { return (Inst){.op = End}; } + +/// Create a loop. +static inline Inst vmLoop(Label label) { + return (Inst){.op = Loop, .payload = (Value){.label = label}}; +} + +/// Create the payload of a conditional branch. +static inline Inst vmBr_if(bool value, Label label) { + return (Inst){ + .op = Br, + .payload = (Value){ + .branch = { + .label = label, + .conditional = 1, + .expected = value, + }}}; +} + +/// Create a function. +static inline Inst vmFunc(Label label) { + return (Inst){.op = Func, .payload = (Value){.label = label}}; +} + +/// Create a function argument. +static inline Inst vmArg(Type type, Label label) { + return (Inst){.op = Arg, .type = type, .payload = (Value){.label = label}}; +} + +/// Call a function. +static inline Inst vmCall(Label label) { + return (Inst){.op = Call, .payload = (Value){.label = label}}; +} + +/// Create a local variable. +static inline Inst vmLocal(Type type, Label label) { + return (Inst){.op = Local, .type = type, .payload = (Value){.label = label}}; +} + +/// Read a local variable. +static inline Inst vmLocalRd(Type type, Label label) { + return (Inst){ + .op = LocalRd, .type = type, .payload = (Value){.label = label}}; +} + +/// Write a local variable. +static inline Inst vmLocalWr(Type type, Label label) { + return (Inst){ + .op = LocalWr, .type = type, .payload = (Value){.label = label}}; +} -- cgit v1.2.3