1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
/* Copyright (C) 2023 Aryadev Chavali
* You may distribute and modify this code under the terms of the
* GPLv2 license. You should have received a copy of the GPLv2
* license with this file. If not, please write to:
* aryadev@aryadevchavali.com.
* Created: 2023-10-15
* Author: Aryadev Chavali
* Description: Virtual machine implementation
*/
#ifndef RUNTIME_H
#define RUNTIME_H
#include <stdio.h>
#include <stdlib.h>
#include <lib/heap.h>
#include <lib/inst.h>
typedef enum
{
ERR_OK = 0,
ERR_STACK_UNDERFLOW,
ERR_STACK_OVERFLOW,
ERR_INVALID_OPCODE,
ERR_INVALID_REGISTER_BYTE,
ERR_INVALID_REGISTER_HWORD,
ERR_INVALID_REGISTER_WORD,
ERR_INVALID_PROGRAM_ADDRESS,
ERR_INVALID_PAGE_ADDRESS,
ERR_OUT_OF_BOUNDS,
ERR_END_OF_PROGRAM,
} err_t;
const char *err_as_cstr(err_t);
typedef darr_t registers_t;
#define VM_NTH_REGISTER(REGISTERS, N) (((word *)((REGISTERS).data))[N])
#define VM_REGISTERS_AVAILABLE(REGISTERS) (((REGISTERS).available) / WORD_SIZE)
typedef struct
{
registers_t registers;
struct Stack
{
byte *data;
word ptr, max;
} stack;
heap_t heap;
struct Program
{
inst_t *instructions;
word ptr, max;
} program;
} vm_t;
err_t vm_execute(vm_t *);
err_t vm_execute_all(vm_t *);
void vm_load_stack(vm_t *, byte *, size_t);
void vm_load_registers(vm_t *, registers_t);
void vm_load_heap(vm_t *, heap_t);
void vm_load_program(vm_t *, inst_t *, size_t);
void vm_stop(vm_t *);
// Print routines
#define VM_PRINT_PROGRAM_EXCERPT 5
void vm_print_registers(vm_t *, FILE *);
void vm_print_stack(vm_t *, FILE *);
void vm_print_program(vm_t *, FILE *);
void vm_print_heap(vm_t *, FILE *);
void vm_print_all(vm_t *, FILE *);
// Execution routines
err_t vm_jump(vm_t *, word);
err_t vm_pop_byte(vm_t *, data_t *);
err_t vm_pop_hword(vm_t *, data_t *);
err_t vm_pop_word(vm_t *, data_t *);
err_t vm_push_byte(vm_t *, data_t);
err_t vm_push_hword(vm_t *, data_t);
err_t vm_push_word(vm_t *, data_t);
typedef err_t (*push_f)(vm_t *, data_t);
static const push_f PUSH_ROUTINES[] = {
[OP_PUSH_BYTE] = vm_push_byte,
[OP_PUSH_HWORD] = vm_push_hword,
[OP_PUSH_WORD] = vm_push_word,
};
err_t vm_push_byte_register(vm_t *, word);
err_t vm_push_hword_register(vm_t *, word);
err_t vm_push_word_register(vm_t *, word);
err_t vm_mov_byte(vm_t *, word);
err_t vm_mov_hword(vm_t *, word);
err_t vm_mov_word(vm_t *, word);
err_t vm_dup_byte(vm_t *, word);
err_t vm_dup_hword(vm_t *, word);
err_t vm_dup_word(vm_t *, word);
err_t vm_malloc_byte(vm_t *, word);
err_t vm_malloc_hword(vm_t *, word);
err_t vm_malloc_word(vm_t *, word);
err_t vm_mset_byte(vm_t *, word);
err_t vm_mset_hword(vm_t *, word);
err_t vm_mset_word(vm_t *, word);
err_t vm_mget_byte(vm_t *, word);
err_t vm_mget_hword(vm_t *, word);
err_t vm_mget_word(vm_t *, word);
typedef err_t (*word_f)(vm_t *, word);
static const word_f WORD_ROUTINES[] = {
[OP_PUSH_REGISTER_BYTE] = vm_push_byte_register,
[OP_PUSH_REGISTER_HWORD] = vm_push_hword_register,
[OP_PUSH_REGISTER_WORD] = vm_push_word_register,
[OP_MOV_BYTE] = vm_mov_byte,
[OP_MOV_HWORD] = vm_mov_hword,
[OP_MOV_WORD] = vm_mov_word,
[OP_DUP_BYTE] = vm_dup_byte,
[OP_DUP_HWORD] = vm_dup_hword,
[OP_DUP_WORD] = vm_dup_word,
[OP_MALLOC_BYTE] = vm_malloc_byte,
[OP_MALLOC_HWORD] = vm_malloc_hword,
[OP_MALLOC_WORD] = vm_malloc_word,
[OP_MGET_BYTE] = vm_mget_byte,
[OP_MGET_HWORD] = vm_mget_hword,
[OP_MGET_WORD] = vm_mget_word,
[OP_MSET_BYTE] = vm_mset_byte,
[OP_MSET_HWORD] = vm_mset_hword,
[OP_MSET_WORD] = vm_mset_word,
};
err_t vm_mdelete(vm_t *);
err_t vm_not_byte(vm_t *);
err_t vm_not_hword(vm_t *);
err_t vm_not_word(vm_t *);
err_t vm_or_byte(vm_t *);
err_t vm_or_hword(vm_t *);
err_t vm_or_word(vm_t *);
err_t vm_and_byte(vm_t *);
err_t vm_and_hword(vm_t *);
err_t vm_and_word(vm_t *);
err_t vm_xor_byte(vm_t *);
err_t vm_xor_hword(vm_t *);
err_t vm_xor_word(vm_t *);
err_t vm_eq_byte(vm_t *);
err_t vm_eq_char(vm_t *);
err_t vm_eq_int(vm_t *);
err_t vm_eq_hword(vm_t *);
err_t vm_eq_long(vm_t *);
err_t vm_eq_word(vm_t *);
err_t vm_lt_byte(vm_t *);
err_t vm_lt_char(vm_t *);
err_t vm_lt_int(vm_t *);
err_t vm_lt_hword(vm_t *);
err_t vm_lt_long(vm_t *);
err_t vm_lt_word(vm_t *);
err_t vm_lte_byte(vm_t *);
err_t vm_lte_char(vm_t *);
err_t vm_lte_int(vm_t *);
err_t vm_lte_hword(vm_t *);
err_t vm_lte_long(vm_t *);
err_t vm_lte_word(vm_t *);
err_t vm_gt_byte(vm_t *);
err_t vm_gt_char(vm_t *);
err_t vm_gt_int(vm_t *);
err_t vm_gt_hword(vm_t *);
err_t vm_gt_long(vm_t *);
err_t vm_gt_word(vm_t *);
err_t vm_gte_byte(vm_t *);
err_t vm_gte_char(vm_t *);
err_t vm_gte_int(vm_t *);
err_t vm_gte_hword(vm_t *);
err_t vm_gte_long(vm_t *);
err_t vm_gte_word(vm_t *);
err_t vm_plus_byte(vm_t *);
err_t vm_plus_hword(vm_t *);
err_t vm_plus_word(vm_t *);
err_t vm_mult_byte(vm_t *);
err_t vm_mult_hword(vm_t *);
err_t vm_mult_word(vm_t *);
typedef err_t (*stack_f)(vm_t *);
static const stack_f STACK_ROUTINES[] = {
[OP_MDELETE] = vm_mdelete, [OP_NOT_BYTE] = vm_not_byte,
[OP_NOT_HWORD] = vm_not_hword, [OP_NOT_WORD] = vm_not_word,
[OP_OR_BYTE] = vm_or_byte, [OP_OR_HWORD] = vm_or_hword,
[OP_OR_WORD] = vm_or_word,
[OP_AND_BYTE] = vm_and_byte, [OP_AND_HWORD] = vm_and_hword,
[OP_AND_WORD] = vm_and_word,
[OP_XOR_BYTE] = vm_xor_byte, [OP_XOR_HWORD] = vm_xor_hword,
[OP_XOR_WORD] = vm_xor_word,
[OP_EQ_BYTE] = vm_eq_byte, [OP_EQ_HWORD] = vm_eq_hword,
[OP_EQ_WORD] = vm_eq_word,
[OP_LT_BYTE] = vm_lt_byte, [OP_LT_CHAR] = vm_lt_char,
[OP_LT_INT] = vm_lt_int, [OP_LT_HWORD] = vm_lt_hword,
[OP_LT_LONG] = vm_lt_long, [OP_LT_WORD] = vm_lt_word,
[OP_LTE_BYTE] = vm_lte_byte, [OP_LTE_CHAR] = vm_lte_char,
[OP_LTE_INT] = vm_lte_int, [OP_LTE_HWORD] = vm_lte_hword,
[OP_LTE_LONG] = vm_lte_long, [OP_LTE_WORD] = vm_lte_word,
[OP_GT_BYTE] = vm_gt_byte, [OP_GT_CHAR] = vm_gt_char,
[OP_GT_INT] = vm_gt_int, [OP_GT_HWORD] = vm_gt_hword,
[OP_GT_LONG] = vm_gt_long, [OP_GT_WORD] = vm_gt_word,
[OP_GTE_BYTE] = vm_gte_byte, [OP_GTE_CHAR] = vm_gte_char,
[OP_GTE_INT] = vm_gte_int, [OP_GTE_HWORD] = vm_gte_hword,
[OP_GTE_LONG] = vm_gte_long, [OP_GTE_WORD] = vm_gte_word,
[OP_PLUS_BYTE] = vm_plus_byte, [OP_PLUS_HWORD] = vm_plus_hword,
[OP_PLUS_WORD] = vm_plus_word,
[OP_MULT_BYTE] = vm_mult_byte, [OP_MULT_HWORD] = vm_mult_hword,
[OP_MULT_WORD] = vm_mult_word,
};
#endif
|