swamp_vm_types/
opcode.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use std::fmt::{Display, Formatter};
6
7#[repr(u8)]
8#[derive(Debug)]
9pub enum OpCode {
10    Nop,
11    Hlt, // Return to the host
12    UserHalt,
13    Step,  // Stop executing and return to host. User has a step-point here.
14    Panic, // Stop executing and return to host. String provides reason.
15    Trap,  // Provides a reason code.
16    Brk,   // Breakpoint. pause execution, keep all relevant state
17
18    // Operators
19    // u32 and i32
20    AddU32,
21    AddU32Imm,
22    MulU32,
23    SubU32,
24
25    // i32 specific
26    NegI32,
27    ModI32,
28    DivI32,
29
30    // Fixed
31    MulF32,
32    DivF32,
33
34    // Comparisons
35    // Clears or sets the P flag
36    // Integer and Float
37    LtI32,
38    LeI32,
39    GtI32,
40    GeI32,
41
42    // Unsigned int
43    GeU32,
44    LtU32,
45
46    // Comparison, set P flag
47    Eq8Imm,
48    CmpReg,
49    CmpBlock,
50
51    // Other Comparisons
52    TrapOnLessThan,
53
54    // Conditional branching
55    BFalse,
56    BTrue,
57
58    // Unconditional branching
59    B,
60
61    // Call, frame and return
62    Call,
63    Enter,
64    Ret,
65
66    BlockCopy, // Copy without offsets
67    FrameMemClr,
68
69    // Loaders --------------
70
71    // Load immediate into reg
72    LdPtrFromEffectiveFrameAddress, // Load effective address
73    Ld8FromPointerWithOffset,
74    Ld16FromPointerWithOffset,
75    Ld32FromPointerWithOffset,
76
77    LdRegFromFrameRange,
78    LdRegFromFrameUsingMask,
79
80    // TODO: LEA Rddest, [Rbase + ImmediateOffset]
81    // TODO: LEA.SI Rdest, Rbase, Rindex, ScaleImmediate
82    Ld8FromAbsoluteAddress,
83    Ld32FromAbsoluteAddress,
84
85    // Storers ---
86    St8UsingPtrWithOffset,
87    St16UsingPtrWithOffset,
88    St32UsingPtrWithOffset,
89    StRegToFrame,
90    StRegToFrameUsingMask,
91
92    // Movers
93    MovReg,
94    // Mov immediate
95    Mov8FromImmediateValue,
96    Mov16FromImmediateValue,
97    Mov32FromImmediateValue,
98
99    MovEqualToZero,
100    // TODO: Maybe bring back MovNotEqualToZero back for symmetry / completeness?
101
102    // Type specific -----
103
104    // Float
105    FloatRound,
106    FloatFloor,
107    FloatSqrt,
108    FloatSign,
109    FloatAbs,
110    FloatPseudoRandom,
111    FloatSin,
112    FloatCos,
113    FloatAcos,
114    FloatAsin,
115    FloatAtan2,
116    FloatMin,
117    FloatMax,
118    FloatClamp,
119    FloatToString,
120
121    // Int
122    IntToRnd,
123    IntToFloat,
124    IntAbs,
125    IntMin,
126    IntMax,
127    IntClamp,
128    IntToString,
129
130    // Codepoint
131    CodepointToString,
132
133    // Bool
134    BoolToString,
135
136    ByteToString,
137
138    // Collection intrinsics ----
139
140    // Range
141    RangeInit,
142    RangeIterInit,
143    RangeIterNext,
144
145    // Fixed Capacity Size Array
146    ArrayInitWithLenAndCapacity,
147
148    // Vec
149    VecInit, // For vec likes
150    VecCmp,
151    VecCopy,
152    VecPushAddr,
153    VecRemoveIndex,
154    VecPop,
155    VecRemoveIndexGetValue,
156    VecGet,
157    VecGetRange,
158    VecSwap,
159    VecIterInit,
160    VecIterNext,
161    VecIterNextPair,
162
163    // Map
164    MapInitWithCapacityAndKeyAndTupleSizeAddr, // Initialize the Map
165    MapGetEntryLocation,                       // RHS, lookup, do not add
166    MapGetOrReserveEntryLocation,              // For the LHS, create entry if needed
167    MapRemove,
168    MapHas,
169    MapOverwrite,
170
171    MapIterInit,
172    MapIterNext,
173    MapIterNextPair,
174
175    // String
176    StringAppend,
177    StringCmp,
178    StringToString,
179    StringIterInit,
180    StringIterNext,
181    StringIterNextPair,
182
183    // Other
184    HostCall, // calls back into host
185
186    // Sparse
187    SparseInit,
188    SparseAddGiveEntryAddress,
189    SparseRemove,
190    SparseGetEntryAddr,
191    SparseIterNext,
192    SparseIterNextPair,
193    SparseIterInit,
194    SparseIsAlive,
195
196    // Grid
197    GridInit,
198    GridGetEntryAddr,
199}
200
201impl OpCode {
202    #[allow(clippy::too_many_lines)]
203    #[must_use]
204    pub const fn as_string(&self) -> &str {
205        match self {
206            Self::Nop => "nop",
207            Self::Hlt => "hlt",
208            Self::UserHalt => "user_halt",
209            Self::Step => "step",
210            Self::Panic => "panic",
211            Self::Trap => "trap",
212            Self::Brk => "brk",
213
214            // Integer arithmetic
215            Self::AddU32 | Self::AddU32Imm => "add",
216            Self::MulU32 => "mul",
217            Self::SubU32 => "sub",
218
219            Self::NegI32 => "s.neg",
220            Self::ModI32 => "s.mod",
221            Self::DivI32 => "s.div",
222
223            // Float arithmetic
224            Self::MulF32 => "f.mul",
225            Self::DivF32 => "f.div",
226
227            // Integer comparisons
228            Self::LtI32 => "lt",
229            Self::LeI32 => "le",
230            Self::GtI32 => "gt",
231            Self::GeI32 => "ge",
232
233            Self::GeU32 => "uge",
234            Self::LtU32 => "ult",
235
236            // Byte/memory comparisons
237            Self::Eq8Imm | Self::CmpReg => "cmp",
238            Self::CmpBlock => "cmp.blk",
239            Self::FrameMemClr => "clr.blk.f",
240
241            // Other comparisons
242            Self::TrapOnLessThan => "trap.lt",
243
244            // Branches
245            Self::BFalse => "b.false",
246            Self::BTrue => "b.true",
247            Self::B => "b",
248
249            // Call/Frame/Return
250            Self::Call => "call",
251            Self::Enter => "enter",
252            Self::Ret => "ret",
253
254            // Mem
255            Self::BlockCopy => "blk.cpy",
256            Self::LdPtrFromEffectiveFrameAddress => "lea",
257
258            // Move
259            Self::Mov8FromImmediateValue => "mov.b",
260            Self::Mov16FromImmediateValue => "mov.h",
261            Self::MovReg | Self::Mov32FromImmediateValue => "mov", // alias for `mov.w`
262            Self::MovEqualToZero => "meqz",
263
264            // Load. From memory to register
265            Self::Ld8FromPointerWithOffset | Self::Ld8FromAbsoluteAddress => "ld.b",
266            Self::Ld16FromPointerWithOffset => "ld.h",
267            Self::Ld32FromPointerWithOffset | Self::Ld32FromAbsoluteAddress => "ld", // alias for `ld.w`
268            Self::LdRegFromFrameUsingMask | Self::LdRegFromFrameRange => "ldmf",
269
270            // Store. From register to memory
271            Self::St32UsingPtrWithOffset => "st", // alias for `st.w`
272            Self::St16UsingPtrWithOffset => "st.h",
273            Self::St8UsingPtrWithOffset => "st.b",
274            Self::StRegToFrameUsingMask | Self::StRegToFrame => "stmf",
275
276            // Float functions
277            Self::FloatRound => "f.round",
278            Self::FloatFloor => "f.floor",
279            Self::FloatSqrt => "f.sqrt",
280            Self::FloatSign => "f.sign",
281            Self::FloatAbs => "f.abs",
282            Self::FloatPseudoRandom => "f.prnd",
283            Self::FloatSin => "f.sin",
284            Self::FloatCos => "f.cos",
285            Self::FloatAcos => "f.acos",
286            Self::FloatAsin => "f.asin",
287            Self::FloatAtan2 => "f.atan2",
288            Self::FloatMin => "f.min",
289            Self::FloatMax => "f.max",
290            Self::FloatClamp => "f.clamp",
291            Self::FloatToString => "f.to.str",
292
293            // Int functions
294            Self::IntToRnd => "i.rnd",
295            Self::IntToFloat => "i.tof",
296            Self::IntAbs => "i.abs",
297            Self::IntMin => "i.min",
298            Self::IntMax => "i.max",
299            Self::IntClamp => "i.clamp",
300            Self::IntToString => "i.tos",
301
302            // Other
303            Self::HostCall => "host",
304
305            // Bool
306            Self::BoolToString => "bool.to.str",
307
308            // Bool
309            Self::CodepointToString => "codepoint.to.str",
310
311            // Byte
312            Self::ByteToString => "byte.to.str",
313
314            // Range
315            Self::RangeInit => "range.init",
316            Self::RangeIterInit => "range.iter",
317            Self::RangeIterNext => "range.iter.next",
318
319            // Fixed capacity size array
320            Self::ArrayInitWithLenAndCapacity => "array.init",
321
322            // Vec
323            Self::VecPushAddr => "vec.push",
324            Self::VecRemoveIndex => "vec.rem",
325            Self::VecPop => "vec.pop",
326            Self::VecRemoveIndexGetValue => "vec.rem.v",
327            Self::VecGet => "vec.get",
328            Self::VecGetRange => "vec.get.range",
329            Self::VecSwap => "vec.swap",
330            Self::VecInit => "vec.init",
331            Self::VecCopy => "vec.copy",
332            Self::VecCmp => "vec.cmp",
333            Self::VecIterInit => "vec.iter",
334            Self::VecIterNext => "vec.iter.next",
335            Self::VecIterNextPair => "vec.iter.next.pair",
336
337            // Map
338            Self::MapInitWithCapacityAndKeyAndTupleSizeAddr => "map.init",
339            Self::MapGetEntryLocation => "map.entry",
340            Self::MapGetOrReserveEntryLocation => "map.entry.or_create",
341            Self::MapHas => "map.has",
342            Self::MapOverwrite => "map.overwrite",
343            Self::MapRemove => "map.rem",
344            Self::MapIterInit => "map.iter.init",
345            Self::MapIterNext => "map.iter.next",
346            Self::MapIterNextPair => "map.iter.next.pair",
347
348            // Sparse
349            Self::SparseInit => "sparse.init",
350            Self::SparseAddGiveEntryAddress => "sparse.add_entry_addr",
351            Self::SparseRemove => "sparse.remove",
352            Self::SparseGetEntryAddr => "sparse.entry_addr",
353            Self::SparseIsAlive => "sparse.is_alive",
354            // iter
355            Self::SparseIterInit => "sparse.iter.init",
356            Self::SparseIterNext => "sparse.iter.next",
357            Self::SparseIterNextPair => "sparse.iter.next.pair",
358
359            // Grid
360            Self::GridInit => "grid.init",
361            Self::GridGetEntryAddr => "grid.entry_addr",
362
363            // String
364            Self::StringAppend => "str.app",
365            Self::StringCmp => "str.cmp",
366            Self::StringToString => "str.tos",
367            Self::StringIterInit => "str.iter",
368            Self::StringIterNext => "str.iter.next",
369            Self::StringIterNextPair => "str.iter.next.pair",
370        }
371    }
372}
373impl Display for OpCode {
374    #[allow(clippy::too_many_lines)]
375    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
376        write!(f, "{}", self.as_string())
377    }
378}
379
380// Add this to your OpCode implementation
381impl From<u8> for OpCode {
382    fn from(value: u8) -> Self {
383        // Safety: This assumes the u8 value corresponds to a valid OpCode variant
384        // For production code, consider using TryFrom instead to validate the value
385        unsafe { std::mem::transmute(value) }
386    }
387}