1use crate::{Word, instruction::SurfaceValue};
5use vihaco::{
6 frame::Frame,
7 traits::{FrameMemory, StackFrame, StackMemory},
8};
9use vihaco_parser::Ident;
10
11vihaco::component! {
12 #[derive(Default, Debug)]
13 pub component CPU {
14 pub(crate) frames: Vec<Frame>,
15 pub(crate) heap: Heap,
16 pub(crate) stack: Vec<Word>,
17 pub(crate) span: (u32, u32, u32),
18 pub(crate) pending_pc: Option<u32>,
19 pub(crate) current_pc: u32,
20 pub(crate) return_values: Vec<Word>,
21 }
22
23 type Type = vihaco::Type;
24 value Word = crate::Word;
25
26 instruction {
27 #[pattern = "'span $0 $1 $2"]
28 Span(u32, u32, u32),
29
30 #[pattern = "'label `@` $0"]
31 Label(Ident),
32
33 #[pattern = "'func_start"]
34 FunctionStart,
35
36 #[pattern = "'func_end"]
37 FunctionEnd,
38
39 Breakpoint,
40
41 #[pattern = "'br `@` $0"]
42 Branch(Ident => u32),
43
44 #[pattern = "'cond_br `@` $0 `,` `@` $1"]
45 ConditionalBranch(Ident => u32, Ident => u32),
46
47 #[pattern = "'ret $0"]
48 Return(u32),
49
50 #[pattern = "'call_indirect"]
51 IndirectCall,
52
53 Call(u32, Ident => u32),
54
55 Halt,
56
57 Print,
58
59 #[pattern = "'load_i32 $0"]
60 LoadI32(u32),
61 #[pattern = "'load_i64 $0"]
62 LoadI64(u32),
63 #[pattern = "'load_u32 $0"]
64 LoadU32(u32),
65 #[pattern = "'load_u64 $0"]
66 LoadU64(u32),
67 #[pattern = "'load_f32 $0"]
68 LoadF32(u32),
69 #[pattern = "'load_f64 $0"]
70 LoadF64(u32),
71 #[pattern = "'load_bool $0"]
72 LoadBool(u32),
73 #[pattern = "'store_i32 $0"]
74 StoreI32(u32),
75 #[pattern = "'store_i64 $0"]
76 StoreI64(u32),
77 #[pattern = "'store_u32 $0"]
78 StoreU32(u32),
79 #[pattern = "'store_u64 $0"]
80 StoreU64(u32),
81 #[pattern = "'store_f32 $0"]
82 StoreF32(u32),
83 #[pattern = "'store_f64 $0"]
84 StoreF64(u32),
85 #[pattern = "'store_bool $0"]
86 StoreBool(u32),
87
88 Dup,
89
90 #[pattern = "'heap_alloc $0"]
91 HeapAlloc(u32),
92
93 #[pattern = "'get_item"]
94 GetItem,
95
96 #[pattern = "'heap_dealloc"]
97 HeapDealloc,
98
99 #[pattern = "'const_i32 $0"]
100 ConstI32(SurfaceValue => Word),
101 #[pattern = "'const_i64 $0"]
102 ConstI64(SurfaceValue => Word),
103 #[pattern = "'const_u32 $0"]
104 ConstU32(SurfaceValue => Word),
105 #[pattern = "'const_u64 $0"]
106 ConstU64(SurfaceValue => Word),
107 #[pattern = "'const_f32 $0"]
108 ConstF32(SurfaceValue => Word),
109 #[pattern = "'const_f64 $0"]
110 ConstF64(SurfaceValue => Word),
111 #[pattern = "'const_bool $0"]
112 ConstBool(SurfaceValue => Word),
113 #[pattern = "'const_string $0"]
114 ConstString(SurfaceValue => Word),
115 #[pattern = "'const_fn_ref $0"]
116 ConstFunctionRef(SurfaceValue => Word),
117 #[pattern = "'const_heap_ref $0"]
118 ConstHeapRef(SurfaceValue => Word),
119
120 #[pattern = "'add_i32"]
121 AddI32,
122 #[pattern = "'add_f32"]
123 AddF32,
124 #[pattern = "'add_i64"]
125 AddI64,
126 #[pattern = "'add_u32"]
127 AddU32,
128 #[pattern = "'add_u64"]
129 AddU64,
130 #[pattern = "'add_f64"]
131 AddF64,
132 #[pattern = "'sub_i32"]
133 SubI32,
134 #[pattern = "'sub_i64"]
135 SubI64,
136 #[pattern = "'sub_u32"]
137 SubU32,
138 #[pattern = "'sub_u64"]
139 SubU64,
140 #[pattern = "'sub_f32"]
141 SubF32,
142 #[pattern = "'sub_f64"]
143 SubF64,
144 #[pattern = "'mul_i32"]
145 MulI32,
146 #[pattern = "'mul_i64"]
147 MulI64,
148 #[pattern = "'mul_u32"]
149 MulU32,
150 #[pattern = "'mul_u64"]
151 MulU64,
152 #[pattern = "'mul_f32"]
153 MulF32,
154 #[pattern = "'mul_f64"]
155 MulF64,
156 #[pattern = "'div_i32"]
157 DivI32,
158 #[pattern = "'div_i64"]
159 DivI64,
160 #[pattern = "'div_u32"]
161 DivU32,
162 #[pattern = "'div_u64"]
163 DivU64,
164 #[pattern = "'div_f32"]
165 DivF32,
166 #[pattern = "'div_f64"]
167 DivF64,
168 #[pattern = "'rem_i32"]
169 RemI32,
170 #[pattern = "'rem_i64"]
171 RemI64,
172 #[pattern = "'rem_u32"]
173 RemU32,
174 #[pattern = "'rem_u64"]
175 RemU64,
176 #[pattern = "'rem_f32"]
177 RemF32,
178 #[pattern = "'rem_f64"]
179 RemF64,
180 #[pattern = "'neg_i32"]
181 NegI32,
182 #[pattern = "'neg_i64"]
183 NegI64,
184 #[pattern = "'neg_f32"]
185 NegF32,
186 #[pattern = "'neg_f64"]
187 NegF64,
188 #[pattern = "'shl_i32"]
189 ShlI32,
190 #[pattern = "'shl_i64"]
191 ShlI64,
192 #[pattern = "'shl_u32"]
193 ShlU32,
194 #[pattern = "'shl_u64"]
195 ShlU64,
196 #[pattern = "'shr_i32"]
197 ShrI32,
198 #[pattern = "'shr_i64"]
199 ShrI64,
200 #[pattern = "'shr_u32"]
201 ShrU32,
202 #[pattern = "'shr_u64"]
203 ShrU64,
204 #[pattern = "'rol_i32"]
205 RolI32,
206 #[pattern = "'rol_i64"]
207 RolI64,
208 #[pattern = "'rol_u32"]
209 RolU32,
210 #[pattern = "'rol_u64"]
211 RolU64,
212 #[pattern = "'ror_i32"]
213 RorI32,
214 #[pattern = "'ror_i64"]
215 RorI64,
216 #[pattern = "'ror_u32"]
217 RorU32,
218 #[pattern = "'ror_u64"]
219 RorU64,
220 #[pattern = "'bitand_i32"]
221 BitAndI32,
222 #[pattern = "'bitand_i64"]
223 BitAndI64,
224 #[pattern = "'bitand_u32"]
225 BitAndU32,
226 #[pattern = "'bitand_u64"]
227 BitAndU64,
228 #[pattern = "'bitor_i32"]
229 BitOrI32,
230 #[pattern = "'bitor_i64"]
231 BitOrI64,
232 #[pattern = "'bitor_u32"]
233 BitOrU32,
234 #[pattern = "'bitor_u64"]
235 BitOrU64,
236 #[pattern = "'bitxor_i32"]
237 BitXorI32,
238 #[pattern = "'bitxor_i64"]
239 BitXorI64,
240 #[pattern = "'bitxor_u32"]
241 BitXorU32,
242 #[pattern = "'bitxor_u64"]
243 BitXorU64,
244
245 Not,
246
247 And,
248
249 Or,
250
251 Xor,
252
253 #[pattern = "'eq_i32"]
254 EqI32,
255 #[pattern = "'eq_i64"]
256 EqI64,
257 #[pattern = "'eq_u32"]
258 EqU32,
259 #[pattern = "'eq_u64"]
260 EqU64,
261 #[pattern = "'eq_f32"]
262 EqF32,
263 #[pattern = "'eq_f64"]
264 EqF64,
265 #[pattern = "'ne_i32"]
266 NeI32,
267 #[pattern = "'ne_i64"]
268 NeI64,
269 #[pattern = "'ne_u32"]
270 NeU32,
271 #[pattern = "'ne_u64"]
272 NeU64,
273 #[pattern = "'ne_f32"]
274 NeF32,
275 #[pattern = "'ne_f64"]
276 NeF64,
277 #[pattern = "'lt_i32"]
278 LtI32,
279 #[pattern = "'lt_i64"]
280 LtI64,
281 #[pattern = "'lt_u32"]
282 LtU32,
283 #[pattern = "'lt_u64"]
284 LtU64,
285 #[pattern = "'lt_f32"]
286 LtF32,
287 #[pattern = "'lt_f64"]
288 LtF64,
289 #[pattern = "'gt_i32"]
290 GtI32,
291 #[pattern = "'gt_i64"]
292 GtI64,
293 #[pattern = "'gt_u32"]
294 GtU32,
295 #[pattern = "'gt_u64"]
296 GtU64,
297 #[pattern = "'gt_f32"]
298 GtF32,
299 #[pattern = "'gt_f64"]
300 GtF64,
301 #[pattern = "'le_i32"]
302 LeI32,
303 #[pattern = "'le_i64"]
304 LeI64,
305 #[pattern = "'le_u32"]
306 LeU32,
307 #[pattern = "'le_u64"]
308 LeU64,
309 #[pattern = "'le_f32"]
310 LeF32,
311 #[pattern = "'le_f64"]
312 LeF64,
313 #[pattern = "'ge_i32"]
314 GeI32,
315 #[pattern = "'ge_i64"]
316 GeI64,
317 #[pattern = "'ge_u32"]
318 GeU32,
319 #[pattern = "'ge_u64"]
320 GeU64,
321 #[pattern = "'ge_f32"]
322 GeF32,
323 #[pattern = "'ge_f64"]
324 GeF64,
325 }
326}
327
328pub use cpu::CPU;
329pub use cpu::runtime::Instruction as RuntimeInstruction;
330pub use cpu::syntax::Instruction as SurfaceInstruction;
331
332type HeapSlot = Option<Box<[Word]>>;
333
334#[derive(Debug, Clone, Default)]
335pub struct Heap {
336 slots: Vec<HeapSlot>,
337 free_list: Vec<u32>,
338}
339
340impl Heap {
341 pub fn alloc(&mut self, values: Box<[Word]>) -> u32 {
342 if let Some(id) = self.free_list.pop() {
343 self.slots[id as usize] = Some(values);
344 id
345 } else {
346 let id = self.slots.len() as u32;
347 self.slots.push(Some(values));
348 id
349 }
350 }
351
352 pub fn dealloc(&mut self, id: u32) -> eyre::Result<()> {
353 match self.slots.get_mut(id as usize) {
354 Some(slot @ Some(_)) => {
355 *slot = None;
356 self.free_list.push(id);
357 Ok(())
358 }
359 Some(None) => Err(eyre::eyre!(
360 "double-free: heap object {} already deallocated",
361 id
362 )),
363 None => Err(eyre::eyre!("invalid heap object id {}", id)),
364 }
365 }
366
367 pub fn get(&self, id: u32) -> eyre::Result<&[Word]> {
368 match self.slots.get(id as usize) {
369 Some(Some(v)) => Ok(v),
370 Some(None) => Err(eyre::eyre!("heap object {} has been deallocated", id)),
371 None => Err(eyre::eyre!("invalid heap object id {}", id)),
372 }
373 }
374
375 pub fn clear(&mut self) {
376 self.slots.clear();
377 self.free_list.clear();
378 }
379
380 #[cfg(test)]
381 pub fn is_empty(&self) -> bool {
382 self.slots.is_empty()
383 }
384}
385
386impl StackMemory for CPU {
387 type Value = Word;
388
389 fn stack(&self) -> &Vec<Self::Value> {
390 &self.stack
391 }
392
393 fn stack_mut(&mut self) -> &mut Vec<Self::Value> {
394 &mut self.stack
395 }
396
397 fn stack_is_empty(&self) -> bool {
398 self.stack.is_empty()
399 }
400
401 fn stack_len(&self) -> usize {
402 self.stack.len()
403 }
404
405 fn stack_get(&self, pos: usize) -> eyre::Result<&Self::Value> {
406 self.stack
407 .get(pos)
408 .ok_or_else(|| eyre::eyre!("stack underflow"))
409 }
410
411 fn stack_get_mut(&mut self, pos: usize) -> eyre::Result<&mut Self::Value> {
412 self.stack
413 .get_mut(pos)
414 .ok_or_else(|| eyre::eyre!("stack underflow"))
415 }
416
417 fn stack_pop(&mut self) -> eyre::Result<Self::Value> {
418 self.stack
419 .pop()
420 .ok_or_else(|| eyre::eyre!("stack underflow"))
421 }
422
423 fn stack_push<T: Into<Self::Value>>(&mut self, v: T) {
424 self.stack.push(v.into());
425 }
426}
427
428impl StackFrame for CPU {
429 fn get_frame(&self) -> eyre::Result<&Frame> {
430 self.frames
431 .last()
432 .ok_or_else(|| eyre::eyre!("no current frame"))
433 }
434
435 fn get_frame_mut(&mut self) -> eyre::Result<&mut Frame> {
436 self.frames
437 .last_mut()
438 .ok_or_else(|| eyre::eyre!("no current frame"))
439 }
440
441 fn push_frame(&mut self, frame: Frame) {
442 self.frames.push(frame);
443 }
444
445 fn pop_frame(&mut self) -> eyre::Result<Frame> {
446 self.frames
447 .pop()
448 .ok_or_else(|| eyre::eyre!("no frame to pop"))
449 }
450}
451
452impl FrameMemory for CPU {
453 fn frame_base(&self) -> eyre::Result<usize> {
454 self.get_frame().map(|f| f.base)
455 }
456
457 fn get_local(&self, index: usize) -> eyre::Result<&Self::Value> {
458 let base = self.frame_base()?;
459 self.stack
460 .get(base + index)
461 .ok_or_else(|| eyre::eyre!("local index out of bounds"))
462 }
463
464 fn get_local_mut(&mut self, index: usize) -> eyre::Result<&mut Self::Value> {
466 let base = self.frame_base()?;
467 let idx = base + index;
468 let len = self.stack.len();
469
470 if len <= idx {
471 self.stack.resize(idx + 1, 0);
472 }
473 self.stack
474 .get_mut(idx)
475 .ok_or_else(|| eyre::eyre!("Invalid local address at {:?}, stack size: {:?}", idx, len))
476 }
477}
478
479impl CPU {
480 pub fn push_heap_object(&mut self, values: Box<[Word]>) -> u32 {
481 self.heap.alloc(values)
482 }
483
484 pub fn heap_object(&self, id: u32) -> eyre::Result<&[Word]> {
485 self.heap.get(id)
486 }
487
488 pub fn dealloc_heap_object(&mut self, id: u32) -> eyre::Result<()> {
489 self.heap.dealloc(id)
490 }
491
492 pub fn take_pending_pc(&mut self) -> Option<u32> {
493 self.pending_pc.take()
494 }
495
496 pub fn set_pending_pc(&mut self, pc: u32) {
497 self.pending_pc = Some(pc);
498 }
499
500 pub fn clear_pending_pc(&mut self) {
501 self.pending_pc = None;
502 }
503
504 pub fn set_current_pc(&mut self, pc: u32) {
505 self.current_pc = pc;
506 }
507
508 pub fn return_values(&self) -> &[Word] {
509 &self.return_values
510 }
511
512 pub fn set_return_values(&mut self, values: Vec<Word>) {
513 self.return_values = values;
514 }
515}