slvm/opcodes.rs
1pub type OpCode = u8;
2
3pub const NOP: OpCode = 0x00;
4pub const HALT: OpCode = 0x01;
5pub const RET: OpCode = 0x02;
6pub const SRET: OpCode = 0x03; // SRET A - R(0) = R(A) and then RET
7pub const WIDE: OpCode = 0x04;
8
9const STACK_BASE: OpCode = 0x04;
10pub const MOV: OpCode = STACK_BASE + 1; // MOV A B - R(A) = R(B) does not respect closed over values
11pub const SET: OpCode = STACK_BASE + 2; // SET A B - R(A) = R(B) respecting local closed over values
12pub const CONST: OpCode = STACK_BASE + 3; // CONST A B - R(A) = K(B)
13pub const DEF: OpCode = STACK_BASE + 4; // DEF A B - G(B) = R(A)
14pub const DEFV: OpCode = STACK_BASE + 5; // DEFV A B - G(B) = R(A) if G(B) is undefined
15pub const REFI: OpCode = STACK_BASE + 6; // REFI A B - R(A) = G[B]
16pub const CLRREG: OpCode = STACK_BASE + 7; // CLRREG A - R(A) = UNDEFINED (ignores a closed over value)
17pub const REGT: OpCode = STACK_BASE + 8; // REGT A - R(A) = TRUE
18pub const REGF: OpCode = STACK_BASE + 9; // REGF A - R(A) = FALSE
19pub const REGN: OpCode = STACK_BASE + 10; // REGN A - R(A) = NIL
20pub const REGC: OpCode = STACK_BASE + 11; // REGC A - R(A) = UNDEFINED
21pub const REGB: OpCode = STACK_BASE + 12; // REGB A B - R(A) = Byte(B)
22pub const REGI: OpCode = STACK_BASE + 13; // REGI A B - R(A) = Int(B)
23pub const CLOSE: OpCode = STACK_BASE + 15; // CLOSE A B - R(A) = closure derived from lambda in R(B)
24pub const BMOV: OpCode = STACK_BASE + 16; // BMOV A B C - R(A)..R(A+C) = R(B)..R(B+C) does not respect closed over values
25pub const LDSC: OpCode = STACK_BASE + 17; // LDSC A B C - R(A)..R(A+B) = destructured list or vec in R(C) (ignore leftover values)
26pub const LDSCR: OpCode = STACK_BASE + 18; // LDSCR A B C - R(A)..R(A+B) = destructured list or vec in R(C) (R(A+B) gets all leftover values)
27pub const MDSC: OpCode = STACK_BASE + 19; // MDSC A B C - R(A)..R(A+B) = destructured map in R(C) (ignore leftover values), R(A..) start with keys
28pub const COPY: OpCode = STACK_BASE + 20; // COPY A B - R(A) = deep copy of R(B)
29pub const FRZ: OpCode = STACK_BASE + 21; // FRZ A - R(A) if a heap object will be made read only
30pub const MOVI: OpCode = STACK_BASE + 22; // MOVI A B - R(R(A)) = R(B), A is an indirect index; does not respect closed over values for A
31pub const MOVII: OpCode = STACK_BASE + 23; // MOVII A B - R(A) = R(R(B)), B is an indirect index; does not respect closed over values for A
32pub const GET: OpCode = STACK_BASE + 24; // GET A B C - if R(A) = R(B) (if it is a complex data structure) element R(C)
33pub const SETCOL: OpCode = STACK_BASE + 25; // SETCOL A B C - Set R(B) (if it is a complex data structure) element R(C) to R(A)
34
35/// Flow control
36const FLOW_BASE: OpCode = STACK_BASE + 26;
37/// CALL A B C - Call fn R(A) with B args with R(C) as first reg/param
38pub const CALL: OpCode = FLOW_BASE;
39/// TCALL A B - Tail Call fn R(A) with B args with existing stack/regs
40pub const TCALL: OpCode = FLOW_BASE + 1;
41/// CALLG A B C - Call fn G[A] with B args with R(C) as first reg/param
42pub const CALLG: OpCode = FLOW_BASE + 2;
43/// TCALLG A B - Tail Call fn G[A] with B args with existing stack/regs
44pub const TCALLG: OpCode = FLOW_BASE + 3;
45/// CALLM A B - Call current fn with B args with R(C) as first reg/param
46pub const CALLM: OpCode = FLOW_BASE + 4;
47/// TCALLM B - Tail Call current fn with B args with existing stack/regs
48pub const TCALLM: OpCode = FLOW_BASE + 5;
49/// Jumps, all jumps use a signed 24 bit OFFSET (high bit is sign and next 23 are integer).
50/// This means all jumps are forward or back (negative target).
51/// JMP OFFSET - Jump to IP + OFFSET
52pub const JMP: OpCode = FLOW_BASE + 6;
53/// JMPT A OFFSET - Jump to current IP + OFFSET if R(A) is truthy (not (nil or false))
54pub const JMPT: OpCode = FLOW_BASE + 7;
55/// JMPF A OFFSET - Jump to current IP + OFFSET if R(A) is falsy (nil or false)
56pub const JMPF: OpCode = FLOW_BASE + 8;
57/// JMPEQ A B OFFSET - compare A and B and jump to IP + OFFSET if they are equal
58pub const JMPEQ: OpCode = FLOW_BASE + 9;
59/// JMPLT A B OFFSET - compare A and B and jump to IP + OFFSET if R(A) < R(B)
60pub const JMPLT: OpCode = FLOW_BASE + 10;
61/// JMPGT A B OFFSET - compare A and B and jump to IP + OFFSET if R(A) > R(B)
62pub const JMPGT: OpCode = FLOW_BASE + 11;
63/// JMPU A OFFSET - Jump to current IP + OFFSET if R(A) is undefined
64pub const JMPU: OpCode = FLOW_BASE + 12;
65/// JMPNU A OFFSET - Jump to current IP + OFFSET if R(A) is NOT undefined
66pub const JMPNU: OpCode = FLOW_BASE + 13;
67/// EQ A B C - R[A] is #t if objects in R[B] - R[C] (inclusive) are the same objects
68pub const EQ: OpCode = FLOW_BASE + 14;
69/// EQUAL A B C - R[A] is #t if objects in R[B] - R[C] (inclusive) are the same objects, values or
70/// containers with equal values (must be the same container type)
71pub const EQUAL: OpCode = FLOW_BASE + 15;
72/// NOT A B - R[A] is #t if R[B] is falsey and #f otherwise
73pub const NOT: OpCode = FLOW_BASE + 16;
74/// ERR A B - raise error with key R(A) (must be keyword) and value R(B)
75pub const ERR: OpCode = FLOW_BASE + 17;
76/// CCC A B - call with continuation, R(A) must be a lambda that takes one arg (the continuation)
77/// R(B) is the first reg for the call
78pub const CCC: OpCode = FLOW_BASE + 18;
79/// DFR A - Add a lambda, R(A) to the deferred list.
80pub const DFR: OpCode = FLOW_BASE + 19;
81/// DFRPOP - Pop and call the last deferred lambda.
82pub const DFRPOP: OpCode = FLOW_BASE + 20;
83/// ONERR A - Make R(A) the current error handler and put the previous error handler in R(A).
84/// If R(A) is nil then remove error handler.
85pub const ONERR: OpCode = FLOW_BASE + 21;
86
87/// JMPRU A B OFFSET - Jump to current IP + OFFSET if any in R(A)..R(A+B) is undefined
88pub const JMPRU: OpCode = FLOW_BASE + 22;
89/// JMPRNU A B OFFSET - Jump to current IP + OFFSET if any in R(A)..R(A+B) is NOT undefined
90pub const JMPRNU: OpCode = FLOW_BASE + 23;
91/// MKERR A B C - R(A) = error with key R(B) (must be keyword) and value R(C)
92pub const MKERR: OpCode = FLOW_BASE + 24;
93/// ISERR A B - R(A) is #t if R(B) is an error type, #f otherwise
94pub const ISERR: OpCode = FLOW_BASE + 25;
95/// ISOK A B - R(A) is #f if R(B) is an error type, #t otherwise
96pub const ISOK: OpCode = FLOW_BASE + 26;
97
98// Basic math
99const MATH_BASE: OpCode = FLOW_BASE + 27;
100/// ADD A B - set R(A) = R(A) + R(B)
101pub const ADD: OpCode = MATH_BASE;
102/// SUB A B - set R(A) = R(A) - R(B)
103pub const SUB: OpCode = MATH_BASE + 1;
104/// MUL A B - set R(A) = R(A) * R(B)
105pub const MUL: OpCode = MATH_BASE + 2;
106/// DIV A B - set R(A) = R(A) / R(B)
107pub const DIV: OpCode = MATH_BASE + 3;
108/// INC A B - Increment the integer in R(A) by B
109pub const INC: OpCode = MATH_BASE + 4;
110/// DEC A B - Decrement the integer in R(A) by B
111pub const DEC: OpCode = MATH_BASE + 5;
112/// NUMEQ A B C - compare (=) in register B (inclusive) to C (inclusive) and set R[A] to the
113/// result.
114pub const NUMEQ: OpCode = MATH_BASE + 6;
115/// NUMLT A B C - compare (<) in register B (inclusive) to C (inclusive) and set R[A] to the
116/// result.
117pub const NUMLT: OpCode = MATH_BASE + 7;
118/// NUMGT A B C - compare (>) in register B (inclusive) to C (inclusive) and set R[A] to the
119/// result.
120pub const NUMGT: OpCode = MATH_BASE + 8;
121/// NUMLTE A B C - compare (<=) in register B (inclusive) to C (inclusive) and set R[A] to the
122/// result.
123pub const NUMLTE: OpCode = MATH_BASE + 9;
124/// NUMGTE A B C - compare (>=) in register B (inclusive) to C (inclusive) and set R[A] to the
125/// result.
126pub const NUMGTE: OpCode = MATH_BASE + 10;
127/// Cons cells
128const CONS_BASE: OpCode = MATH_BASE + 11;
129/// CONS A B C - R(A) = conscell(R(B), R(C))
130pub const CONS: OpCode = CONS_BASE;
131/// CAR A B - R(A) = car(R(B))
132pub const CAR: OpCode = CONS_BASE + 1;
133/// CDR A B - R(A) = cdr(R(B))
134pub const CDR: OpCode = CONS_BASE + 2;
135/// XAR A B - car(R(A)) = R(B)
136pub const XAR: OpCode = CONS_BASE + 3;
137/// XDR A B - cdr(R(A)) = R(B)
138pub const XDR: OpCode = CONS_BASE + 4;
139/// LIST A B C - R(A) = list(elements R(B)..R(C)) (R(B) and R(C) are inclusive)
140pub const LIST: OpCode = CONS_BASE + 5;
141/// APND A B C - R(A) = append lists R(B)..R(C) (R(B) and R(C) are inclusive)
142pub const APND: OpCode = CONS_BASE + 6;
143
144// Vectors
145const VEC_BASE: OpCode = CONS_BASE + 7;
146/// VECMK A B - make a vector with R(B) elements and put it in R(A)
147pub const VECMK: OpCode = VEC_BASE;
148/// VECELS A B - make the length of vec in R(A) R(B)
149pub const VECELS: OpCode = VEC_BASE + 1;
150/// VECPSH A B - push R(B) into vec in R(A)
151pub const VECPSH: OpCode = VEC_BASE + 2;
152/// VECPOP A B - pop from vec in R(A) to R(B)
153pub const VECPOP: OpCode = VEC_BASE + 3;
154pub const VECMKD: OpCode = VEC_BASE + 4;
155/// VEC A B C - R(A) = vec(elements R(B)..R(C)) (R(B) inclusive, R(C) exclusive)
156pub const VEC: OpCode = VEC_BASE + 5;
157/// LEN A B - R(A) = length of data in R(B)
158pub const LEN: OpCode = VEC_BASE + 6;
159/// CLR A - Clear the collection in R(A)
160pub const CLR: OpCode = VEC_BASE + 7;
161/// MAPMK A B C - R(A) = map(elements R(B)..R(C)) (R(B) inclusive, R(C) exclusive), alternating key, val pairs
162pub const MAPMK: OpCode = VEC_BASE + 8;
163
164/// Strings
165const STRING_BASE: OpCode = VEC_BASE + 9;
166/// STR A B C - R(A) = string concatenated from objects in R(A) - R(B) (inclusive)
167pub const STR: OpCode = STRING_BASE;
168
169/// Types
170const TYPE_BASE: OpCode = STRING_BASE + 1;
171/// TYPE A B - R(A) = type(R(B)) as a StringConst
172pub const TYPE: OpCode = TYPE_BASE;
173
174pub const MAX_OP_CODE: OpCode = TYPE_BASE;