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    VecCopyRange,
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    StringRepeat,
178    StringCmp,
179    StringToString,
180    StringIterInit,
181    StringIterNext,
182    StringIterNextPair,
183
184    // Other
185    HostCall, // calls back into host
186
187    // Sparse
188    SparseInit,
189    SparseAddGiveEntryAddress,
190    SparseRemove,
191    SparseGetEntryAddr,
192    SparseIterNext,
193    SparseIterNextPair,
194    SparseIterInit,
195    SparseIsAlive,
196
197    // Grid
198    GridInit,
199    GridGetEntryAddr,
200}
201
202impl OpCode {
203    #[allow(clippy::too_many_lines)]
204    #[must_use]
205    pub const fn as_string(&self) -> &str {
206        match self {
207            Self::Nop => "nop",
208            Self::Hlt => "hlt",
209            Self::UserHalt => "user_halt",
210            Self::Step => "step",
211            Self::Panic => "panic",
212            Self::Trap => "trap",
213            Self::Brk => "brk",
214
215            // Integer arithmetic
216            Self::AddU32 | Self::AddU32Imm => "add",
217            Self::MulU32 => "mul",
218            Self::SubU32 => "sub",
219
220            Self::NegI32 => "s.neg",
221            Self::ModI32 => "s.mod",
222            Self::DivI32 => "s.div",
223
224            // Float arithmetic
225            Self::MulF32 => "f.mul",
226            Self::DivF32 => "f.div",
227
228            // Integer comparisons
229            Self::LtI32 => "lt",
230            Self::LeI32 => "le",
231            Self::GtI32 => "gt",
232            Self::GeI32 => "ge",
233
234            Self::GeU32 => "uge",
235            Self::LtU32 => "ult",
236
237            // Byte/memory comparisons
238            Self::Eq8Imm | Self::CmpReg => "cmp",
239            Self::CmpBlock => "cmp.blk",
240            Self::FrameMemClr => "clr.blk.f",
241
242            // Other comparisons
243            Self::TrapOnLessThan => "trap.lt",
244
245            // Branches
246            Self::BFalse => "b.false",
247            Self::BTrue => "b.true",
248            Self::B => "b",
249
250            // Call/Frame/Return
251            Self::Call => "call",
252            Self::Enter => "enter",
253            Self::Ret => "ret",
254
255            // Mem
256            Self::BlockCopy => "blk.cpy",
257            Self::LdPtrFromEffectiveFrameAddress => "lea",
258
259            // Move
260            Self::Mov8FromImmediateValue => "mov.b",
261            Self::Mov16FromImmediateValue => "mov.h",
262            Self::MovReg | Self::Mov32FromImmediateValue => "mov", // alias for `mov.w`
263            Self::MovEqualToZero => "meqz",
264
265            // Load. From memory to register
266            Self::Ld8FromPointerWithOffset | Self::Ld8FromAbsoluteAddress => "ld.b",
267            Self::Ld16FromPointerWithOffset => "ld.h",
268            Self::Ld32FromPointerWithOffset | Self::Ld32FromAbsoluteAddress => "ld", // alias for `ld.w`
269            Self::LdRegFromFrameUsingMask | Self::LdRegFromFrameRange => "ldmf",
270
271            // Store. From register to memory
272            Self::St32UsingPtrWithOffset => "st", // alias for `st.w`
273            Self::St16UsingPtrWithOffset => "st.h",
274            Self::St8UsingPtrWithOffset => "st.b",
275            Self::StRegToFrameUsingMask | Self::StRegToFrame => "stmf",
276
277            // Float functions
278            Self::FloatRound => "f.round",
279            Self::FloatFloor => "f.floor",
280            Self::FloatSqrt => "f.sqrt",
281            Self::FloatSign => "f.sign",
282            Self::FloatAbs => "f.abs",
283            Self::FloatPseudoRandom => "f.prnd",
284            Self::FloatSin => "f.sin",
285            Self::FloatCos => "f.cos",
286            Self::FloatAcos => "f.acos",
287            Self::FloatAsin => "f.asin",
288            Self::FloatAtan2 => "f.atan2",
289            Self::FloatMin => "f.min",
290            Self::FloatMax => "f.max",
291            Self::FloatClamp => "f.clamp",
292            Self::FloatToString => "f.to.str",
293
294            // Int functions
295            Self::IntToRnd => "i.rnd",
296            Self::IntToFloat => "i.tof",
297            Self::IntAbs => "i.abs",
298            Self::IntMin => "i.min",
299            Self::IntMax => "i.max",
300            Self::IntClamp => "i.clamp",
301            Self::IntToString => "i.tos",
302
303            // Other
304            Self::HostCall => "host",
305
306            // Bool
307            Self::BoolToString => "bool.to.str",
308
309            // Bool
310            Self::CodepointToString => "codepoint.to.str",
311
312            // Byte
313            Self::ByteToString => "byte.to.str",
314
315            // Range
316            Self::RangeInit => "range.init",
317            Self::RangeIterInit => "range.iter",
318            Self::RangeIterNext => "range.iter.next",
319
320            // Fixed capacity size array
321            Self::ArrayInitWithLenAndCapacity => "array.init",
322
323            // Vec
324            Self::VecPushAddr => "vec.push",
325            Self::VecRemoveIndex => "vec.rem",
326            Self::VecPop => "vec.pop",
327            Self::VecRemoveIndexGetValue => "vec.rem.v",
328            Self::VecGet => "vec.get",
329            Self::VecCopyRange => "vec.copy.range",
330            Self::VecSwap => "vec.swap",
331            Self::VecInit => "vec.init",
332            Self::VecCopy => "vec.copy",
333            Self::VecCmp => "vec.cmp",
334            Self::VecIterInit => "vec.iter",
335            Self::VecIterNext => "vec.iter.next",
336            Self::VecIterNextPair => "vec.iter.next.pair",
337
338            // Map
339            Self::MapInitWithCapacityAndKeyAndTupleSizeAddr => "map.init",
340            Self::MapGetEntryLocation => "map.entry",
341            Self::MapGetOrReserveEntryLocation => "map.entry.or_create",
342            Self::MapHas => "map.has",
343            Self::MapOverwrite => "map.overwrite",
344            Self::MapRemove => "map.rem",
345            Self::MapIterInit => "map.iter.init",
346            Self::MapIterNext => "map.iter.next",
347            Self::MapIterNextPair => "map.iter.next.pair",
348
349            // Sparse
350            Self::SparseInit => "sparse.init",
351            Self::SparseAddGiveEntryAddress => "sparse.add_entry_addr",
352            Self::SparseRemove => "sparse.remove",
353            Self::SparseGetEntryAddr => "sparse.entry_addr",
354            Self::SparseIsAlive => "sparse.is_alive",
355            // iter
356            Self::SparseIterInit => "sparse.iter.init",
357            Self::SparseIterNext => "sparse.iter.next",
358            Self::SparseIterNextPair => "sparse.iter.next.pair",
359
360            // Grid
361            Self::GridInit => "grid.init",
362            Self::GridGetEntryAddr => "grid.entry_addr",
363
364            // String
365            Self::StringAppend => "str.app",
366            Self::StringRepeat => "str.repeat",
367            Self::StringCmp => "str.cmp",
368            Self::StringToString => "str.tos",
369            Self::StringIterInit => "str.iter",
370            Self::StringIterNext => "str.iter.next",
371            Self::StringIterNextPair => "str.iter.next.pair",
372        }
373    }
374}
375impl Display for OpCode {
376    #[allow(clippy::too_many_lines)]
377    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
378        write!(f, "{}", self.as_string())
379    }
380}
381
382// Add this to your OpCode implementation
383impl From<u8> for OpCode {
384    fn from(value: u8) -> Self {
385        // Safety: This assumes the u8 value corresponds to a valid OpCode variant
386        // For production code, consider using TryFrom instead to validate the value
387        unsafe { std::mem::transmute(value) }
388    }
389}