tower_vm/interpreter/instruction.rs
1#[repr(u8)]
2#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
3pub enum Instruction {
4 // machine control instructions
5 Halt, // stop execution
6 SetType, // set the type flag the value of the next byte
7 GetType, // push the type flag to the stack as a byte
8
9 // arithmetic instructions: pop two values, convert to the type flag, perform the operation, push the result
10 Add,
11 Sub,
12 Mul,
13 Div,
14 Rem,
15
16 // Neg does not pop a value, it just negates the top of the stack
17 Neg,
18
19 // incr and decr don't pop a value, they just increment or decrement the top of the stack
20 // will probably throw err if called on a non-integer type
21 // good for control flow, address arithmetic, etc.
22 Incr,
23 Decr,
24
25 // comparison instructions: pop two values, perform the comparison, push boolean result
26 Eq,
27 Neq,
28 Lt,
29 Gt,
30 Lte,
31 Gte,
32
33 // bitwise instructions: pop two values, perform the operation, push the result
34 And,
35 Or,
36 Xor,
37 Shl,
38 Shr,
39
40 // bitwise not does not pop a value, it just negates the top of the stack
41 Not,
42
43 // control flow
44 Jmp, // set ip to address popped from stack
45 JmpIf, // pop two values, if the first is true, set ip to the second, otherwise continue (type flag is ignored everything is treated as u64)
46 JmpIfNot, // pop two values, if the first is false, set ip to the second, otherwise continue (type flag is ignored everything is treated as u64)
47
48 // function call instructions
49 Call, // pop address from stack, push return address, set ip to address
50 Ret, // pop return address from stack, set ip to address (same as jmp, but rather be explicit)
51
52 // stack manipulation instructions
53 Push, // based on the type flag, read the following bytes from the code and push them to the stack, and adjust the ip by the number of bytes read
54 Dup, // duplicate the top of the stack
55 Drop, // drop the top of the stack
56 Swap, // swap the top two values on the stack
57
58 // heap instructions
59 Load, // pop address from stack and push value at address using the current alignment
60 Store, // pop value and address from stack, store value at address as bytes
61 Alloc, // pop size from stack, expand heap by sizeof(current type flag) * size, push first address of new heap space
62 Free, // pop address from stack, decrement heap size by sizeof(current type flag) * size
63 HeapSize, // push heap size to stack
64 StackSize, // push stack size to stack
65
66 // meta instructions
67 // these instructions are used for loading code into the interpreter
68 LoadCode, // pop two addresses from stack, take the bytes between the addresses on the heap and extend the code segment with them, and push the address of the new code segment to the stack
69 SaveCode, // pop two addresses from stack, take the bytes between the addresses on the code segment and extend the heap with them, and push the address of the new heap segment to the stack
70
71 // io instructions
72 Read, // halts execution and awaits input to the stream
73 Write, // pops a value from the stack and writes it to the stream
74 Print, // print the stream
75 Clear, // clear the stream
76}
77
78impl From<u8> for Instruction {
79 fn from(value: u8) -> Self {
80 use Instruction::*;
81
82 match value {
83 0 => Halt,
84 1 => SetType,
85 2 => GetType,
86 3 => Add,
87 4 => Sub,
88 5 => Mul,
89 6 => Div,
90 7 => Rem,
91 8 => Neg,
92 9 => Incr,
93 10 => Decr,
94 11 => Eq,
95 12 => Neq,
96 13 => Lt,
97 14 => Gt,
98 15 => Lte,
99 16 => Gte,
100 17 => And,
101 18 => Or,
102 19 => Xor,
103 20 => Shl,
104 21 => Shr,
105 22 => Not,
106 23 => Jmp,
107 24 => JmpIf,
108 25 => JmpIfNot,
109 26 => Call,
110 27 => Ret,
111 28 => Push,
112 29 => Dup,
113 30 => Drop,
114 31 => Swap,
115 32 => Load,
116 33 => Store,
117 34 => Alloc,
118 35 => Free,
119 36 => HeapSize,
120 37 => StackSize,
121 38 => LoadCode,
122 39 => SaveCode,
123 40 => Read,
124 41 => Write,
125 42 => Print,
126 43 => Clear,
127 _ => panic!("invalid instruction"),
128 }
129 }
130}