diff options
author | 3gg <3gg@shellblade.net> | 2023-03-02 20:03:52 -0800 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2023-03-02 20:03:52 -0800 |
commit | 664006b1c42aae84a3c749d9b71c1047e0b8ffcf (patch) | |
tree | e08f8af944b132742b3bb1d240d8954328e667e5 /vm/src/vm.h |
Diffstat (limited to 'vm/src/vm.h')
-rw-r--r-- | vm/src/vm.h | 166 |
1 files changed, 166 insertions, 0 deletions
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 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <stdbool.h> | ||
4 | #include <stddef.h> | ||
5 | #include <stdint.h> | ||
6 | |||
7 | typedef enum Op { | ||
8 | Exit, // Pop value from the stack and return as exit code. Return 0 if the | ||
9 | // stack is empty. | ||
10 | Push, | ||
11 | Pop, | ||
12 | Add, | ||
13 | Sub, | ||
14 | Mul, | ||
15 | Div, | ||
16 | Dec, // Decrement the top of the stack by 1. | ||
17 | Empty, // Check whether the stack is empty. Pushes a bool. | ||
18 | Cmp, // Pop the top of the stack and compare it with the payload. Pushes a | ||
19 | // bool. | ||
20 | /* Blocks */ | ||
21 | End, // Marks the end of a block. | ||
22 | Break, // Exit the current block. | ||
23 | Loop, // Push a loop block. Payload (i32): label. | ||
24 | /* Branches */ | ||
25 | Br, // Branch. Payload (i64): [(i32) conditional? | (i32) label]. | ||
26 | // A condtional branch pops a bool from the stack and branches if true. | ||
27 | // The condition can also be negated. See br_if(). | ||
28 | /* Functions */ | ||
29 | Func, | ||
30 | Arg, | ||
31 | Call, | ||
32 | /* Locals */ | ||
33 | Local, // Create a local variable. | ||
34 | LocalRd, // Load a local variable into the top of the stack. | ||
35 | LocalWr, // Pop the top of the stack and store it in a local variable. | ||
36 | } Op; | ||
37 | |||
38 | typedef enum Type { | ||
39 | I32, | ||
40 | F32, | ||
41 | } Type; | ||
42 | |||
43 | // Label type for blocks and locals. | ||
44 | typedef uint32_t Label; | ||
45 | |||
46 | typedef struct Branch { | ||
47 | Label label; | ||
48 | bool conditional : 1; // True for conditional branches. | ||
49 | bool expected : 1; // Comparison value for conditional branches. | ||
50 | } Branch; | ||
51 | |||
52 | typedef struct Function { | ||
53 | Label label; | ||
54 | } Function; | ||
55 | |||
56 | typedef struct Value { | ||
57 | union { | ||
58 | uint64_t u64; | ||
59 | int32_t i32; | ||
60 | float f32; | ||
61 | Branch branch; | ||
62 | Label label; | ||
63 | }; | ||
64 | } Value; | ||
65 | |||
66 | typedef struct Inst { | ||
67 | Op op : 5; | ||
68 | Type type : 2; | ||
69 | Value payload; | ||
70 | } Inst; | ||
71 | |||
72 | typedef struct Vm Vm; | ||
73 | |||
74 | // ----------------------------------------------------------------------------- | ||
75 | // VM API | ||
76 | |||
77 | /// Create a new virtual machine. | ||
78 | Vm* vm_new(); | ||
79 | |||
80 | /// Destroy the virtual machine. | ||
81 | void vm_del(Vm**); | ||
82 | |||
83 | /// Execute code on the virtual machine. | ||
84 | /// | ||
85 | /// Returns the program exit code if an exit operation is executed, 0 otherwise. | ||
86 | int vm_run(Vm*, const Inst[], size_t count); | ||
87 | |||
88 | /// Prints the virtual machine's stack to stdout. | ||
89 | void vm_print_stack(const Vm*); | ||
90 | |||
91 | // ----------------------------------------------------------------------------- | ||
92 | // Programming API | ||
93 | |||
94 | /// Exit the program. | ||
95 | static inline Inst vmExit() { return (Inst){.op = Exit}; } | ||
96 | |||
97 | /// Push a value. | ||
98 | static inline Inst vmPushI32(int32_t value) { | ||
99 | return (Inst){.op = Push, .type = I32, .payload = (Value){.i32 = value}}; | ||
100 | } | ||
101 | |||
102 | /// Pop a value. | ||
103 | static inline Inst vmPop(Type type) { return (Inst){.op = Pop, .type = type}; } | ||
104 | |||
105 | /// Add two values. | ||
106 | static inline Inst vmAdd(Type type) { return (Inst){.op = Add, .type = type}; } | ||
107 | |||
108 | /// Decrement a value. | ||
109 | static inline Inst vmDec(Type type) { return (Inst){.op = Dec, .type = type}; } | ||
110 | |||
111 | /// Compare a value. | ||
112 | static inline Inst vmCmpI32(int32_t value) { | ||
113 | return (Inst){.op = Cmp, .type = I32, .payload = (Value){.i32 = value}}; | ||
114 | } | ||
115 | |||
116 | /// End the current block. | ||
117 | static inline Inst vmEnd() { return (Inst){.op = End}; } | ||
118 | |||
119 | /// Create a loop. | ||
120 | static inline Inst vmLoop(Label label) { | ||
121 | return (Inst){.op = Loop, .payload = (Value){.label = label}}; | ||
122 | } | ||
123 | |||
124 | /// Create the payload of a conditional branch. | ||
125 | static inline Inst vmBr_if(bool value, Label label) { | ||
126 | return (Inst){ | ||
127 | .op = Br, | ||
128 | .payload = (Value){ | ||
129 | .branch = { | ||
130 | .label = label, | ||
131 | .conditional = 1, | ||
132 | .expected = value, | ||
133 | }}}; | ||
134 | } | ||
135 | |||
136 | /// Create a function. | ||
137 | static inline Inst vmFunc(Label label) { | ||
138 | return (Inst){.op = Func, .payload = (Value){.label = label}}; | ||
139 | } | ||
140 | |||
141 | /// Create a function argument. | ||
142 | static inline Inst vmArg(Type type, Label label) { | ||
143 | return (Inst){.op = Arg, .type = type, .payload = (Value){.label = label}}; | ||
144 | } | ||
145 | |||
146 | /// Call a function. | ||
147 | static inline Inst vmCall(Label label) { | ||
148 | return (Inst){.op = Call, .payload = (Value){.label = label}}; | ||
149 | } | ||
150 | |||
151 | /// Create a local variable. | ||
152 | static inline Inst vmLocal(Type type, Label label) { | ||
153 | return (Inst){.op = Local, .type = type, .payload = (Value){.label = label}}; | ||
154 | } | ||
155 | |||
156 | /// Read a local variable. | ||
157 | static inline Inst vmLocalRd(Type type, Label label) { | ||
158 | return (Inst){ | ||
159 | .op = LocalRd, .type = type, .payload = (Value){.label = label}}; | ||
160 | } | ||
161 | |||
162 | /// Write a local variable. | ||
163 | static inline Inst vmLocalWr(Type type, Label label) { | ||
164 | return (Inst){ | ||
165 | .op = LocalWr, .type = type, .payload = (Value){.label = label}}; | ||
166 | } | ||