Skip to main content

cardinal_uxn/
lib.rs

1//! Uxn virtual machine
2
3#![cfg_attr(not(test), no_std)]
4#![warn(missing_docs)]
5#![cfg_attr(not(any(test, feature = "native")), forbid(unsafe_code))]
6
7//! Uxn VM core library
8
9/// Uxn disassembler module
10pub mod disassembler;
11
12#[cfg(feature = "native")]
13mod native;
14
15const fn keep(flags: u8) -> bool {
16    (flags & (1 << 2)) != 0
17}
18const fn short(flags: u8) -> bool {
19    (flags & (1 << 0)) != 0
20}
21const fn ret(flags: u8) -> bool {
22    (flags & (1 << 1)) != 0
23}
24
25/// Size of a device in port memory
26pub const DEV_SIZE: usize = 16;
27
28/// Simple circular stack, with room for 256 items
29#[derive(Copy, Clone, Debug, Eq, PartialEq)]
30pub struct Stack {
31    data: [u8; 256],
32
33    /// The index points to the last occupied slot, and increases on `push`
34    ///
35    /// If the buffer is empty or full, it points to `u8::MAX`.
36    index: u8,
37}
38
39impl Stack {
40    /// Returns an iterator over the stack from bottom to top
41    pub fn iter(&self) -> impl Iterator<Item = &u8> {
42        let len = self.len() as usize;
43        self.data[..len].iter()
44    }
45
46    /// Returns a mutable iterator over the stack from bottom to top
47    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut u8> {
48        let len = self.len() as usize;
49        self.data[..len].iter_mut()
50    }
51
52    #[inline]
53    /// Returns a pointer to the stack data
54    /// Returns a pointer to the stack data
55    pub fn as_ptr(&self) -> *const u8 {
56        self.data.as_ptr()
57    }
58
59    /// Returns a mutable pointer to the stack data
60    #[inline]
61    pub fn as_mut_ptr(&mut self) -> *mut u8 {
62        self.data.as_mut_ptr()
63    }
64
65    /// Returns the stack index (last occupied slot)
66    #[inline]
67    pub fn index(&self) -> u8 {
68        self.index
69    }
70
71    /// Gets the value at a given index (0 = bottom, index = top)
72    #[inline]
73    pub fn get(&self, idx: u8) -> u8 {
74        self.data[usize::from(idx)]
75    }
76}
77
78/// Uxn evaluation backend
79#[derive(Copy, Clone, Debug)]
80pub enum Backend {
81    /// Use a bytecode interpreter
82    Interpreter,
83
84    #[cfg(feature = "native")]
85    /// Use hand-written threaded assembly
86    Native,
87}
88
89/// Virtual stack, which is aware of `keep` and `short` modes
90///
91/// This type expects the user to perform all of their `pop()` calls first,
92/// followed by any `push(..)` calls.  `pop()` will either adjust the true index
93/// or a virtual index, depending on whether `keep` is set.
94struct StackView<'a, const FLAGS: u8> {
95    stack: &'a mut Stack,
96
97    /// Virtual index, used in `keep` mode
98    offset: u8,
99}
100
101impl<'a, const FLAGS: u8> StackView<'a, FLAGS> {
102    fn new(stack: &'a mut Stack) -> Self {
103        Self { stack, offset: 0 }
104    }
105
106    /// Pops a single value from the stack
107    ///
108    /// Returns a [`Value::Short`] if `self.short` is set, and a [`Value::Byte`]
109    /// otherwise.
110    ///
111    /// If `self.keep` is set, then only the view offset ([`StackView::offset`])
112    /// is changed; otherwise, the stack index ([`Stack::index`]) is changed.
113    #[inline]
114    fn pop(&mut self) -> Value {
115        if short(FLAGS) {
116            Value::Short(self.pop_short())
117        } else {
118            Value::Byte(self.pop_byte())
119        }
120    }
121
122    fn pop_byte(&mut self) -> u8 {
123        if keep(FLAGS) {
124            let v = self.stack.peek_byte_at(self.offset);
125            self.offset = self.offset.wrapping_add(1);
126            v
127        } else {
128            self.stack.pop_byte()
129        }
130    }
131
132    fn pop_short(&mut self) -> u16 {
133        if keep(FLAGS) {
134            let v = self.stack.peek_short_at(self.offset);
135            self.offset = self.offset.wrapping_add(2);
136            v
137        } else {
138            self.stack.pop_short()
139        }
140    }
141
142    fn push(&mut self, v: Value) {
143        self.stack.push(v);
144    }
145
146    fn reserve(&mut self, n: u8) {
147        self.stack.reserve(n);
148    }
149
150    /// Replaces the top item on the stack with the given value
151    fn emplace(&mut self, v: Value) {
152        match v {
153            Value::Short(v) => {
154                self.stack.emplace_short(v);
155            }
156            Value::Byte(v) => {
157                self.stack.emplace_byte(v);
158            }
159        }
160    }
161
162    fn push_byte(&mut self, v: u8) {
163        self.stack.push_byte(v);
164    }
165
166    fn push_short(&mut self, v: u16) {
167        self.stack.push_short(v);
168    }
169}
170
171impl Default for Stack {
172    fn default() -> Self {
173        Self {
174            data: [0u8; 256],
175            index: u8::MAX,
176        }
177    }
178}
179
180/// A value on the Uxn stack (byte or short)
181#[derive(Copy, Clone, Debug)]
182pub enum Value {
183    /// A 16-bit short value
184    Short(u16),
185    /// An 8-bit byte value
186    Byte(u8),
187}
188
189impl Value {
190    #[inline]
191    fn wrapping_add(&self, i: u8) -> Self {
192        match self {
193            Value::Short(v) => Value::Short(v.wrapping_add(u16::from(i))),
194            Value::Byte(v) => Value::Byte(v.wrapping_add(i)),
195        }
196    }
197    #[inline]
198    fn shr(&self, i: u32) -> Self {
199        match self {
200            Value::Short(v) => Value::Short(v.checked_shr(i).unwrap_or(0)),
201            Value::Byte(v) => Value::Byte(v.checked_shr(i).unwrap_or(0)),
202        }
203    }
204    #[inline]
205    fn shl(&self, i: u32) -> Self {
206        match self {
207            Value::Short(v) => Value::Short(v.checked_shl(i).unwrap_or(0)),
208            Value::Byte(v) => Value::Byte(v.checked_shl(i).unwrap_or(0)),
209        }
210    }
211}
212
213impl From<Value> for u16 {
214    fn from(v: Value) -> u16 {
215        match v {
216            Value::Short(v) => v,
217            Value::Byte(v) => u16::from(v),
218        }
219    }
220}
221
222impl Stack {
223    /// Returns a slice of the working stack data up to the current length
224    #[inline]
225    pub fn data_slice(&self) -> &[u8] {
226        let len = self.data.len();
227        &self.data[..len]
228    }
229
230    #[inline]
231    fn pop_byte(&mut self) -> u8 {
232        let out = self.data[usize::from(self.index)];
233        self.index = self.index.wrapping_sub(1);
234        out
235    }
236
237    #[inline]
238    fn pop_short(&mut self) -> u16 {
239        let lo = self.pop_byte();
240        let hi = self.pop_byte();
241        u16::from_le_bytes([lo, hi])
242    }
243
244    #[inline]
245    /// Push a byte onto the stack
246    pub fn push_byte(&mut self, v: u8) {
247        self.index = self.index.wrapping_add(1);
248        self.data[usize::from(self.index)] = v;
249    }
250
251    #[inline]
252    fn emplace_byte(&mut self, v: u8) {
253        self.data[usize::from(self.index)] = v;
254    }
255
256    #[inline]
257    fn emplace_short(&mut self, v: u16) {
258        let [lo, hi] = v.to_le_bytes();
259        self.data[usize::from(self.index.wrapping_sub(1))] = hi;
260        self.data[usize::from(self.index)] = lo;
261    }
262
263    #[inline]
264    fn reserve(&mut self, n: u8) {
265        self.index = self.index.wrapping_add(n);
266    }
267
268    #[inline]
269    fn push_short(&mut self, v: u16) {
270        let [lo, hi] = v.to_le_bytes();
271        self.push_byte(hi);
272        self.push_byte(lo);
273    }
274
275    #[inline]
276    /// Push a value (byte or short) onto the stack
277    pub fn push(&mut self, v: crate::Value) {
278        match v {
279            crate::Value::Short(v) => self.push_short(v),
280            crate::Value::Byte(v) => self.push_byte(v),
281        }
282    }
283
284    /// Peeks at a byte from the data stack
285    #[inline]
286    pub fn peek_byte_at(&self, offset: u8) -> u8 {
287        self.data[usize::from(self.index.wrapping_sub(offset))]
288    }
289
290    #[inline]
291    fn peek_short_at(&self, offset: u8) -> u16 {
292        let lo = self.peek_byte_at(offset);
293        let hi = self.peek_byte_at(offset.wrapping_add(1));
294        u16::from_le_bytes([lo, hi])
295    }
296
297    /// Returns the number of items in the stack
298    #[inline]
299    pub fn len(&self) -> u8 {
300        self.index.wrapping_add(1)
301    }
302
303    /// Checks whether the stack is empty
304    #[inline]
305    pub fn is_empty(&self) -> bool {
306        self.len() == 0
307    }
308
309    /// Sets the number of items in the stack
310    #[inline]
311    pub fn set_len(&mut self, n: u8) {
312        self.index = n.wrapping_sub(1);
313    }
314}
315
316/// The virtual machine itself
317pub struct Uxn<'a> {
318    /// Device memory
319    pub dev: [u8; 256],
320    /// 64 KiB of VM memory
321    pub ram: &'a mut [u8; 65536],
322    /// 256-byte data stack
323    pub stack: Stack,
324    /// 256-byte return stack
325    pub ret: Stack,
326
327    /// Preferred evaluation backend
328    pub backend: Backend,
329}
330
331macro_rules! op_cmp {
332    ($self:ident, $flags:ident, $f:expr) => {{
333        let mut s = $self.stack_view::<{ $flags }>();
334        #[allow(clippy::redundant_closure_call)]
335        let v = if short($flags) {
336            let b = s.pop_short();
337            let a = s.pop_short();
338            ($f)(a, b)
339        } else {
340            let b = s.pop_byte();
341            let a = s.pop_byte();
342            ($f)(a, b)
343        };
344        s.push_byte(u8::from(v));
345    }};
346}
347
348macro_rules! op_bin {
349    ($self:ident, $flags:ident, $f:expr) => {{
350        let mut s = $self.stack_view::<{ $flags }>();
351        #[allow(clippy::redundant_closure_call)]
352        if short($flags) {
353            let b = s.pop_short();
354            let a = s.pop_short();
355            let f: fn(u16, u16) -> u16 = $f;
356            s.push_short(f(a, b));
357        } else {
358            let b = s.pop_byte();
359            let a = s.pop_byte();
360            let f: fn(u8, u8) -> u8 = $f;
361            s.push_byte(f(a, b));
362        };
363    }};
364}
365
366impl<'a> Uxn<'a> {
367    /// Returns a slice of the working stack data up to the current length
368    pub fn stack_data(&self) -> &[u8] {
369        let len = self.stack.len() as usize;
370        &self.stack.data[..len]
371    }
372
373    /// Returns a slice of the return stack data up to the current length
374    pub fn ret_data(&self) -> &[u8] {
375        let len = self.ret.len() as usize;
376        &self.ret.data[..len]
377    }
378    /// Helper to perform a DEO operation for a given port and value
379    pub fn deo_helper(&mut self, dev: &mut dyn Device, port: u8, value: u8, pc: u16) {
380        // Uxn expects value first, then port
381        self.stack_mut().push_byte(value);
382        self.stack_mut().push_byte(port);
383        let _ = self.deo::<0b000>(dev, pc);
384    }
385    /// Build a new `Uxn` with zeroed memory
386    pub fn new(ram: &'a mut [u8; 65536], backend: Backend) -> Self {
387        Self {
388            dev: [0u8; 256],
389            ram,
390            stack: Stack::default(),
391            ret: Stack::default(),
392            backend,
393        }
394    }
395
396    /// Reads a byte from RAM at the program counter
397    #[inline]
398    fn next(&mut self, pc: &mut u16) -> u8 {
399        let out = self.ram[usize::from(*pc)];
400        *pc = pc.wrapping_add(1);
401        out
402    }
403
404    /// Reads a word from RAM at the program counter
405    #[inline]
406    fn next2(&mut self, pc: &mut u16) -> u16 {
407        let hi = self.next(pc);
408        let lo = self.next(pc);
409        u16::from_le_bytes([lo, hi])
410    }
411
412    #[inline]
413    fn ram_write(&mut self, addr: u16, v: Value) {
414        match v {
415            Value::Short(v) => {
416                let [lo, hi] = v.to_le_bytes();
417                self.ram[usize::from(addr)] = hi;
418                self.ram[usize::from(addr.wrapping_add(1))] = lo;
419            }
420            Value::Byte(v) => {
421                self.ram[usize::from(addr)] = v;
422            }
423        }
424    }
425
426    #[inline]
427    fn ram_read<const FLAGS: u8>(&self, addr: u16) -> Value {
428        if short(FLAGS) {
429            let hi = self.ram[usize::from(addr)];
430            let lo = self.ram[usize::from(addr.wrapping_add(1))];
431            Value::Short(u16::from_le_bytes([lo, hi]))
432        } else {
433            let v = self.ram[usize::from(addr)];
434            Value::Byte(v)
435        }
436    }
437
438    #[inline]
439    fn stack_view<const FLAGS: u8>(&mut self) -> StackView<'_, FLAGS> {
440        let stack = if ret(FLAGS) {
441            &mut self.ret
442        } else {
443            &mut self.stack
444        };
445        StackView::new(stack)
446    }
447
448    #[inline]
449    fn ret_stack_view<const FLAGS: u8>(&mut self) -> StackView<'_, FLAGS> {
450        let stack = if ret(FLAGS) {
451            &mut self.stack
452        } else {
453            &mut self.ret
454        };
455        StackView::new(stack)
456    }
457
458    /// Reads a word from RAM
459    ///
460    /// If the address is at the top of RAM, the second byte will wrap to 0
461    #[inline]
462    pub fn ram_read_word(&self, addr: u16) -> u16 {
463        let hi = self.ram[usize::from(addr)];
464        let lo = self.ram[usize::from(addr.wrapping_add(1))];
465        u16::from_le_bytes([lo, hi])
466    }
467
468    /// Writes to the given address in device memory
469    #[inline]
470    pub fn write_dev_mem(&mut self, addr: u8, value: u8) {
471        self.dev[usize::from(addr)] = value;
472    }
473
474    /// Runs the VM starting at the given address until it terminates
475    #[inline]
476    pub fn run<D: Device>(&mut self, dev: &mut D, mut pc: u16) -> u16 {
477        match self.backend {
478            Backend::Interpreter => loop {
479                let op = self.next(&mut pc);
480                let Some(next) = self.op(op, dev, pc) else {
481                    break pc;
482                };
483                pc = next;
484            },
485            #[cfg(feature = "native")]
486            Backend::Native => native::entry(self, dev, pc),
487        }
488    }
489
490    /// Runs until the program terminates or we hit a stop condition
491    ///
492    /// Returns the new program counter if the program terminated, or `None` if
493    /// the stop condition was reached.
494    ///
495    /// This function always uses the interpreter, ignoring the selected
496    /// backend.
497    #[inline]
498    pub fn run_until<D: Device, F: Fn(&Self, &D, usize) -> bool>(
499        &mut self,
500        dev: &mut D,
501        mut pc: u16,
502        stop: F,
503    ) -> Option<u16> {
504        for i in 0.. {
505            let op = self.next(&mut pc);
506            let Some(next) = self.op(op, dev, pc) else {
507                return Some(pc);
508            };
509            pc = next;
510            if stop(self, dev, i) {
511                return None;
512            }
513        }
514        unreachable!()
515    }
516
517    /// Converts raw ports memory into a [`Ports`] object
518    #[inline]
519    pub fn dev<D: Ports + zerocopy::KnownLayout + zerocopy::Immutable>(&self) -> &D {
520        self.dev_at(D::BASE)
521    }
522
523    /// Returns a reference to a device located at `pos`
524    #[inline]
525    pub fn dev_at<D: Ports + zerocopy::KnownLayout + zerocopy::Immutable>(&self, pos: u8) -> &D {
526        Self::check_dev_size::<D>();
527        D::ref_from_bytes(&self.dev[usize::from(pos)..][..DEV_SIZE]).unwrap()
528    }
529
530    /// Returns a reference to a device located at `pos`
531    #[inline]
532    pub fn dev_mut_at<D: Ports + zerocopy::KnownLayout>(&mut self, pos: u8) -> &mut D {
533        Self::check_dev_size::<D>();
534        let slice = &mut self.dev[usize::from(pos)..][..DEV_SIZE];
535        D::mut_from_bytes(slice).unwrap()
536    }
537
538    /// Returns a mutable reference to the given [`Ports`] object
539    #[inline]
540    pub fn dev_mut<D: Ports + zerocopy::KnownLayout>(&mut self) -> &mut D {
541        self.dev_mut_at(D::BASE)
542    }
543
544    /// Reads a byte from RAM
545    #[inline]
546    pub fn ram_read_byte(&self, addr: u16) -> u8 {
547        self.ram[usize::from(addr)]
548    }
549
550    /// Writes a byte to RAM
551    #[inline]
552    pub fn ram_write_byte(&mut self, addr: u16, v: u8) {
553        self.ram[usize::from(addr)] = v;
554    }
555
556    /// Shared borrow of the working stack
557    #[inline]
558    pub fn stack(&self) -> &Stack {
559        &self.stack
560    }
561
562    /// Mutable borrow of the working stack
563    #[inline]
564    pub fn stack_mut(&mut self) -> &mut Stack {
565        &mut self.stack
566    }
567
568    /// Shared borrow of the return stack
569    #[inline]
570    pub fn ret(&self) -> &Stack {
571        &self.ret
572    }
573
574    /// Mutable borrow of the return stack
575    #[inline]
576    pub fn ret_mut(&mut self) -> &mut Stack {
577        &mut self.ret
578    }
579
580    /// Resets system memory and loads the given ROM
581    ///
582    /// Returns trailing ROM data (or an empty slice), which should be loaded
583    /// into extension memory.
584    #[must_use]
585    pub fn reset<'b>(&mut self, rom: &'b [u8]) -> &'b [u8] {
586        self.dev.fill(0);
587        self.ram.fill(0);
588        self.stack = Stack::default();
589        self.ret = Stack::default();
590        let n = (self.ram.len() - 0x100).min(rom.len());
591        self.ram[0x100..][..n].copy_from_slice(&rom[..n]);
592        &rom[n..]
593    }
594
595    /// Asserts that the given [`Ports`] object is of size [`DEV_SIZE`]
596    #[inline]
597    fn check_dev_size<D: Ports>() {
598        struct AssertDevSize<D>(D);
599        impl<D> AssertDevSize<D> {
600            const ASSERT: () = if core::mem::size_of::<D>() != DEV_SIZE {
601                panic!("dev must be 16 bytes");
602            };
603        }
604        AssertDevSize::<D>::ASSERT
605    }
606
607    /// Executes a single operation
608    #[inline]
609    fn op<D: Device>(&mut self, op: u8, dev: &mut D, pc: u16) -> Option<u16> {
610        match op {
611            op::BRK => self.brk(pc),
612            op::INC => self.inc::<0b000>(pc),
613            op::POP => self.pop::<0b000>(pc),
614            op::NIP => self.nip::<0b000>(pc),
615            op::SWP => self.swp::<0b000>(pc),
616            op::ROT => self.rot::<0b000>(pc),
617            op::DUP => self.dup::<0b000>(pc),
618            op::OVR => self.ovr::<0b000>(pc),
619            op::EQU => self.equ::<0b000>(pc),
620            op::NEQ => self.neq::<0b000>(pc),
621            op::GTH => self.gth::<0b000>(pc),
622            op::LTH => self.lth::<0b000>(pc),
623            op::JMP => self.jmp::<0b000>(pc),
624            op::JCN => self.jcn::<0b000>(pc),
625            op::JSR => self.jsr::<0b000>(pc),
626            op::STH => self.sth::<0b000>(pc),
627            op::LDZ => self.ldz::<0b000>(pc),
628            op::STZ => self.stz::<0b000>(pc),
629            op::LDR => self.ldr::<0b000>(pc),
630            op::STR => self.str::<0b000>(pc),
631            op::LDA => self.lda::<0b000>(pc),
632            op::STA => self.sta::<0b000>(pc),
633            op::DEI => self.dei::<0b000>(dev, pc),
634            op::DEO => self.deo::<0b000>(dev, pc),
635            op::ADD => self.add::<0b000>(pc),
636            op::SUB => self.sub::<0b000>(pc),
637            op::MUL => self.mul::<0b000>(pc),
638            op::DIV => self.div::<0b000>(pc),
639            op::AND => self.and::<0b000>(pc),
640            op::ORA => self.ora::<0b000>(pc),
641            op::EOR => self.eor::<0b000>(pc),
642            op::SFT => self.sft::<0b000>(pc),
643            op::JCI => self.jci(pc),
644            op::INC2 => self.inc::<0b001>(pc),
645            op::POP2 => self.pop::<0b001>(pc),
646            op::NIP2 => self.nip::<0b001>(pc),
647            op::SWP2 => self.swp::<0b001>(pc),
648            op::ROT2 => self.rot::<0b001>(pc),
649            op::DUP2 => self.dup::<0b001>(pc),
650            op::OVR2 => self.ovr::<0b001>(pc),
651            op::EQU2 => self.equ::<0b001>(pc),
652            op::NEQ2 => self.neq::<0b001>(pc),
653            op::GTH2 => self.gth::<0b001>(pc),
654            op::LTH2 => self.lth::<0b001>(pc),
655            op::JMP2 => self.jmp::<0b001>(pc),
656            op::JCN2 => self.jcn::<0b001>(pc),
657            op::JSR2 => self.jsr::<0b001>(pc),
658            op::STH2 => self.sth::<0b001>(pc),
659            op::LDZ2 => self.ldz::<0b001>(pc),
660            op::STZ2 => self.stz::<0b001>(pc),
661            op::LDR2 => self.ldr::<0b001>(pc),
662            op::STR2 => self.str::<0b001>(pc),
663            op::LDA2 => self.lda::<0b001>(pc),
664            op::STA2 => self.sta::<0b001>(pc),
665            op::DEI2 => self.dei::<0b001>(dev, pc),
666            op::DEO2 => self.deo::<0b001>(dev, pc),
667            op::ADD2 => self.add::<0b001>(pc),
668            op::SUB2 => self.sub::<0b001>(pc),
669            op::MUL2 => self.mul::<0b001>(pc),
670            op::DIV2 => self.div::<0b001>(pc),
671            op::AND2 => self.and::<0b001>(pc),
672            op::ORA2 => self.ora::<0b001>(pc),
673            op::EOR2 => self.eor::<0b001>(pc),
674            op::SFT2 => self.sft::<0b001>(pc),
675            op::JMI => self.jmi(pc),
676            op::INCr => self.inc::<0b010>(pc),
677            op::POPr => self.pop::<0b010>(pc),
678            op::NIPr => self.nip::<0b010>(pc),
679            op::SWPr => self.swp::<0b010>(pc),
680            op::ROTr => self.rot::<0b010>(pc),
681            op::DUPr => self.dup::<0b010>(pc),
682            op::OVRr => self.ovr::<0b010>(pc),
683            op::EQUr => self.equ::<0b010>(pc),
684            op::NEQr => self.neq::<0b010>(pc),
685            op::GTHr => self.gth::<0b010>(pc),
686            op::LTHr => self.lth::<0b010>(pc),
687            op::JMPr => self.jmp::<0b010>(pc),
688            op::JCNr => self.jcn::<0b010>(pc),
689            op::JSRr => self.jsr::<0b010>(pc),
690            op::STHr => self.sth::<0b010>(pc),
691            op::LDZr => self.ldz::<0b010>(pc),
692            op::STZr => self.stz::<0b010>(pc),
693            op::LDRr => self.ldr::<0b010>(pc),
694            op::STRr => self.str::<0b010>(pc),
695            op::LDAr => self.lda::<0b010>(pc),
696            op::STAr => self.sta::<0b010>(pc),
697            op::DEIr => self.dei::<0b010>(dev, pc),
698            op::DEOr => self.deo::<0b010>(dev, pc),
699            op::ADDr => self.add::<0b010>(pc),
700            op::SUBr => self.sub::<0b010>(pc),
701            op::MULr => self.mul::<0b010>(pc),
702            op::DIVr => self.div::<0b010>(pc),
703            op::ANDr => self.and::<0b010>(pc),
704            op::ORAr => self.ora::<0b010>(pc),
705            op::EORr => self.eor::<0b010>(pc),
706            op::SFTr => self.sft::<0b010>(pc),
707            op::JSI => self.jsi(pc),
708            op::INC2r => self.inc::<0b011>(pc),
709            op::POP2r => self.pop::<0b011>(pc),
710            op::NIP2r => self.nip::<0b011>(pc),
711            op::SWP2r => self.swp::<0b011>(pc),
712            op::ROT2r => self.rot::<0b011>(pc),
713            op::DUP2r => self.dup::<0b011>(pc),
714            op::OVR2r => self.ovr::<0b011>(pc),
715            op::EQU2r => self.equ::<0b011>(pc),
716            op::NEQ2r => self.neq::<0b011>(pc),
717            op::GTH2r => self.gth::<0b011>(pc),
718            op::LTH2r => self.lth::<0b011>(pc),
719            op::JMP2r => self.jmp::<0b011>(pc),
720            op::JCN2r => self.jcn::<0b011>(pc),
721            op::JSR2r => self.jsr::<0b011>(pc),
722            op::STH2r => self.sth::<0b011>(pc),
723            op::LDZ2r => self.ldz::<0b011>(pc),
724            op::STZ2r => self.stz::<0b011>(pc),
725            op::LDR2r => self.ldr::<0b011>(pc),
726            op::STR2r => self.str::<0b011>(pc),
727            op::LDA2r => self.lda::<0b011>(pc),
728            op::STA2r => self.sta::<0b011>(pc),
729            op::DEI2r => self.dei::<0b011>(dev, pc),
730            op::DEO2r => self.deo::<0b011>(dev, pc),
731            op::ADD2r => self.add::<0b011>(pc),
732            op::SUB2r => self.sub::<0b011>(pc),
733            op::MUL2r => self.mul::<0b011>(pc),
734            op::DIV2r => self.div::<0b011>(pc),
735            op::AND2r => self.and::<0b011>(pc),
736            op::ORA2r => self.ora::<0b011>(pc),
737            op::EOR2r => self.eor::<0b011>(pc),
738            op::SFT2r => self.sft::<0b011>(pc),
739            op::LIT => self.lit::<0b100>(pc),
740            op::INCk => self.inc::<0b100>(pc),
741            op::POPk => self.pop::<0b100>(pc),
742            op::NIPk => self.nip::<0b100>(pc),
743            op::SWPk => self.swp::<0b100>(pc),
744            op::ROTk => self.rot::<0b100>(pc),
745            op::DUPk => self.dup::<0b100>(pc),
746            op::OVRk => self.ovr::<0b100>(pc),
747            op::EQUk => self.equ::<0b100>(pc),
748            op::NEQk => self.neq::<0b100>(pc),
749            op::GTHk => self.gth::<0b100>(pc),
750            op::LTHk => self.lth::<0b100>(pc),
751            op::JMPk => self.jmp::<0b100>(pc),
752            op::JCNk => self.jcn::<0b100>(pc),
753            op::JSRk => self.jsr::<0b100>(pc),
754            op::STHk => self.sth::<0b100>(pc),
755            op::LDZk => self.ldz::<0b100>(pc),
756            op::STZk => self.stz::<0b100>(pc),
757            op::LDRk => self.ldr::<0b100>(pc),
758            op::STRk => self.str::<0b100>(pc),
759            op::LDAk => self.lda::<0b100>(pc),
760            op::STAk => self.sta::<0b100>(pc),
761            op::DEIk => self.dei::<0b100>(dev, pc),
762            op::DEOk => self.deo::<0b100>(dev, pc),
763            op::ADDk => self.add::<0b100>(pc),
764            op::SUBk => self.sub::<0b100>(pc),
765            op::MULk => self.mul::<0b100>(pc),
766            op::DIVk => self.div::<0b100>(pc),
767            op::ANDk => self.and::<0b100>(pc),
768            op::ORAk => self.ora::<0b100>(pc),
769            op::EORk => self.eor::<0b100>(pc),
770            op::SFTk => self.sft::<0b100>(pc),
771            op::LIT2 => self.lit::<0b101>(pc),
772            op::INC2k => self.inc::<0b101>(pc),
773            op::POP2k => self.pop::<0b101>(pc),
774            op::NIP2k => self.nip::<0b101>(pc),
775            op::SWP2k => self.swp::<0b101>(pc),
776            op::ROT2k => self.rot::<0b101>(pc),
777            op::DUP2k => self.dup::<0b101>(pc),
778            op::OVR2k => self.ovr::<0b101>(pc),
779            op::EQU2k => self.equ::<0b101>(pc),
780            op::NEQ2k => self.neq::<0b101>(pc),
781            op::GTH2k => self.gth::<0b101>(pc),
782            op::LTH2k => self.lth::<0b101>(pc),
783            op::JMP2k => self.jmp::<0b101>(pc),
784            op::JCN2k => self.jcn::<0b101>(pc),
785            op::JSR2k => self.jsr::<0b101>(pc),
786            op::STH2k => self.sth::<0b101>(pc),
787            op::LDZ2k => self.ldz::<0b101>(pc),
788            op::STZ2k => self.stz::<0b101>(pc),
789            op::LDR2k => self.ldr::<0b101>(pc),
790            op::STR2k => self.str::<0b101>(pc),
791            op::LDA2k => self.lda::<0b101>(pc),
792            op::STA2k => self.sta::<0b101>(pc),
793            op::DEI2k => self.dei::<0b101>(dev, pc),
794            op::DEO2k => self.deo::<0b101>(dev, pc),
795            op::ADD2k => self.add::<0b101>(pc),
796            op::SUB2k => self.sub::<0b101>(pc),
797            op::MUL2k => self.mul::<0b101>(pc),
798            op::DIV2k => self.div::<0b101>(pc),
799            op::AND2k => self.and::<0b101>(pc),
800            op::ORA2k => self.ora::<0b101>(pc),
801            op::EOR2k => self.eor::<0b101>(pc),
802            op::SFT2k => self.sft::<0b101>(pc),
803            op::LITr => self.lit::<0b110>(pc),
804            op::INCkr => self.inc::<0b110>(pc),
805            op::POPkr => self.pop::<0b110>(pc),
806            op::NIPkr => self.nip::<0b110>(pc),
807            op::SWPkr => self.swp::<0b110>(pc),
808            op::ROTkr => self.rot::<0b110>(pc),
809            op::DUPkr => self.dup::<0b110>(pc),
810            op::OVRkr => self.ovr::<0b110>(pc),
811            op::EQUkr => self.equ::<0b110>(pc),
812            op::NEQkr => self.neq::<0b110>(pc),
813            op::GTHkr => self.gth::<0b110>(pc),
814            op::LTHkr => self.lth::<0b110>(pc),
815            op::JMPkr => self.jmp::<0b110>(pc),
816            op::JCNkr => self.jcn::<0b110>(pc),
817            op::JSRkr => self.jsr::<0b110>(pc),
818            op::STHkr => self.sth::<0b110>(pc),
819            op::LDZkr => self.ldz::<0b110>(pc),
820            op::STZkr => self.stz::<0b110>(pc),
821            op::LDRkr => self.ldr::<0b110>(pc),
822            op::STRkr => self.str::<0b110>(pc),
823            op::LDAkr => self.lda::<0b110>(pc),
824            op::STAkr => self.sta::<0b110>(pc),
825            op::DEIkr => self.dei::<0b110>(dev, pc),
826            op::DEOkr => self.deo::<0b110>(dev, pc),
827            op::ADDkr => self.add::<0b110>(pc),
828            op::SUBkr => self.sub::<0b110>(pc),
829            op::MULkr => self.mul::<0b110>(pc),
830            op::DIVkr => self.div::<0b110>(pc),
831            op::ANDkr => self.and::<0b110>(pc),
832            op::ORAkr => self.ora::<0b110>(pc),
833            op::EORkr => self.eor::<0b110>(pc),
834            op::SFTkr => self.sft::<0b110>(pc),
835            op::LIT2r => self.lit::<0b111>(pc),
836            op::INC2kr => self.inc::<0b111>(pc),
837            op::POP2kr => self.pop::<0b111>(pc),
838            op::NIP2kr => self.nip::<0b111>(pc),
839            op::SWP2kr => self.swp::<0b111>(pc),
840            op::ROT2kr => self.rot::<0b111>(pc),
841            op::DUP2kr => self.dup::<0b111>(pc),
842            op::OVR2kr => self.ovr::<0b111>(pc),
843            op::EQU2kr => self.equ::<0b111>(pc),
844            op::NEQ2kr => self.neq::<0b111>(pc),
845            op::GTH2kr => self.gth::<0b111>(pc),
846            op::LTH2kr => self.lth::<0b111>(pc),
847            op::JMP2kr => self.jmp::<0b111>(pc),
848            op::JCN2kr => self.jcn::<0b111>(pc),
849            op::JSR2kr => self.jsr::<0b111>(pc),
850            op::STH2kr => self.sth::<0b111>(pc),
851            op::LDZ2kr => self.ldz::<0b111>(pc),
852            op::STZ2kr => self.stz::<0b111>(pc),
853            op::LDR2kr => self.ldr::<0b111>(pc),
854            op::STR2kr => self.str::<0b111>(pc),
855            op::LDA2kr => self.lda::<0b111>(pc),
856            op::STA2kr => self.sta::<0b111>(pc),
857            op::DEI2kr => self.dei::<0b111>(dev, pc),
858            op::DEO2kr => self.deo::<0b111>(dev, pc),
859            op::ADD2kr => self.add::<0b111>(pc),
860            op::SUB2kr => self.sub::<0b111>(pc),
861            op::MUL2kr => self.mul::<0b111>(pc),
862            op::DIV2kr => self.div::<0b111>(pc),
863            op::AND2kr => self.and::<0b111>(pc),
864            op::ORA2kr => self.ora::<0b111>(pc),
865            op::EOR2kr => self.eor::<0b111>(pc),
866            op::SFT2kr => self.sft::<0b111>(pc),
867        }
868    }
869
870    /// Computes a jump, either relative (signed) or absolute
871    #[inline]
872    fn jump_offset(pc: u16, v: Value) -> u16 {
873        match v {
874            Value::Short(dst) => dst,
875            Value::Byte(offset) => {
876                let offset = i16::from(offset as i8);
877                pc.wrapping_add_signed(offset)
878            }
879        }
880    }
881
882    /// Break
883    /// ```text
884    /// BRK --
885    /// ```
886    ///
887    /// Ends the evaluation of the current vector. This opcode has no modes.
888    #[inline]
889    pub fn brk(&mut self, _: u16) -> Option<u16> {
890        None
891    }
892
893    /// Jump Conditional Instant
894    ///
895    /// ```text
896    /// JCI cond8 --
897    /// ```
898    ///
899    /// Pops a byte from the working stack and if it is not zero, moves
900    /// the `PC` to a relative address at a distance equal to the next short in
901    /// memory, otherwise moves `PC+2`. This opcode has no modes.
902    #[inline]
903    pub fn jci(&mut self, mut pc: u16) -> Option<u16> {
904        let dt = self.next2(&mut pc);
905        if self.stack.pop_byte() != 0 {
906            pc = pc.wrapping_add(dt);
907        }
908        Some(pc)
909    }
910
911    /// Jump Instant
912    ///
913    /// JMI  -- Moves the PC to a relative address at a distance equal to the
914    /// next short in memory. This opcode has no modes.
915    #[inline]
916    pub fn jmi(&mut self, mut pc: u16) -> Option<u16> {
917        let dt = self.next2(&mut pc);
918        Some(pc.wrapping_add(dt))
919    }
920
921    /// Jump Stash Return Instant
922    ///
923    /// ```text
924    /// JSI  --
925    /// ```
926    ///
927    /// Pushes `PC+2` to the return-stack and moves the `PC` to a relative
928    /// address at a distance equal to the next short in memory. This opcode has
929    /// no modes.
930    #[inline]
931    pub fn jsi(&mut self, mut pc: u16) -> Option<u16> {
932        let dt = self.next2(&mut pc);
933        self.ret.push(Value::Short(pc));
934        Some(pc.wrapping_add(dt))
935    }
936
937    /// Literal
938    ///
939    /// ```text
940    /// LIT -- a
941    /// ```
942    ///
943    /// Pushes the next bytes in memory, and moves the `PC+2`. The `LIT` opcode
944    /// always has the keep mode active. Notice how the `0x00` opcode, with the
945    /// keep bit toggled, is the location of the literal opcodes.
946    ///
947    /// ```text
948    /// LIT 12          ( 12 )
949    /// LIT2 abcd       ( ab cd )
950    /// ```
951    #[inline]
952    pub fn lit<const FLAGS: u8>(&mut self, mut pc: u16) -> Option<u16> {
953        let v = if short(FLAGS) {
954            Value::Short(self.next2(&mut pc))
955        } else {
956            Value::Byte(self.next(&mut pc))
957        };
958        self.stack_view::<FLAGS>().push(v);
959        Some(pc)
960    }
961
962    /// Increment
963    ///
964    /// ```text
965    /// INC a -- a+1
966    /// ```
967    ///
968    /// Increments the value at the top of the stack, by 1.
969    ///
970    /// ```text
971    /// #01 INC         ( 02 )
972    /// #0001 INC2      ( 00 02 )
973    /// #0001 INC2k     ( 00 01 00 02 )
974    /// ```
975    #[inline]
976    pub fn inc<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
977        let mut s = self.stack_view::<FLAGS>();
978        let v = s.pop();
979        s.push(v.wrapping_add(1));
980        Some(pc)
981    }
982
983    /// Pop
984    ///
985    /// ```text
986    /// POP a --
987    /// ```
988    ///
989    /// Removes the value at the top of the stack.
990    ///
991    /// ```text
992    /// #1234 POP    ( 12 )
993    /// #1234 POP2   ( )
994    /// #1234 POP2k  ( 12 34 )
995    /// ```
996    #[inline]
997    pub fn pop<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
998        self.stack_view::<FLAGS>().pop();
999        Some(pc)
1000    }
1001
1002    /// Nip
1003    ///
1004    /// ```text
1005    /// NIP a b -- b
1006    /// ```
1007    ///
1008    /// Removes the second value from the stack. This is practical to convert a
1009    /// short into a byte.
1010    ///
1011    /// ```text
1012    /// #1234 NIP          ( 34 )
1013    /// #1234 #5678 NIP2   ( 56 78 )
1014    /// #1234 #5678 NIP2k  ( 12 34 56 78 56 78 )
1015    /// ```
1016    #[inline]
1017    pub fn nip<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1018        let mut s = self.stack_view::<FLAGS>();
1019        let v = s.pop();
1020        let _ = s.pop();
1021        s.push(v);
1022        Some(pc)
1023    }
1024
1025    /// Swap
1026    ///
1027    /// ```text
1028    /// SWP a b -- b a
1029    /// ```
1030    ///
1031    /// Exchanges the first and second values at the top of the stack.
1032    ///
1033    /// ```text
1034    /// #1234 SWP          ( 34 12 )
1035    /// #1234 SWPk         ( 12 34 34 12 )
1036    /// #1234 #5678 SWP2   ( 56 78 12 34 )
1037    /// #1234 #5678 SWP2k  ( 12 34 56 78 56 78 12 34 )
1038    /// ```
1039    #[inline]
1040    pub fn swp<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1041        let mut s = self.stack_view::<FLAGS>();
1042        let b = s.pop();
1043        let a = s.pop();
1044        s.push(b);
1045        s.push(a);
1046        Some(pc)
1047    }
1048
1049    /// Rotate
1050    ///
1051    /// ```text
1052    /// ROT a b c -- b c a
1053    /// ```
1054    ///
1055    /// Rotates three values at the top of the stack, to the left, wrapping
1056    /// around.
1057    ///
1058    /// ```text
1059    /// #1234 #56 ROT            ( 34 56 12 )
1060    /// #1234 #56 ROTk           ( 12 34 56 34 56 12 )
1061    /// #1234 #5678 #9abc ROT2   ( 56 78 9a bc 12 34 )
1062    /// #1234 #5678 #9abc ROT2k  ( 12 34 56 78 9a bc 56 78 9a bc 12 34 )
1063    /// ```
1064    #[inline]
1065    pub fn rot<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1066        let mut s = self.stack_view::<FLAGS>();
1067        let c = s.pop();
1068        let b = s.pop();
1069        let a = s.pop();
1070        s.push(b);
1071        s.push(c);
1072        s.push(a);
1073        Some(pc)
1074    }
1075
1076    /// Duplicate
1077    ///
1078    /// ```text
1079    /// DUP a -- a a
1080    /// ```
1081    ///
1082    /// Duplicates the value at the top of the stack.
1083    ///
1084    /// ```text
1085    /// #1234 DUP   ( 12 34 34 )
1086    /// #12 DUPk    ( 12 12 12 )
1087    /// #1234 DUP2  ( 12 34 12 34 )
1088    /// ```
1089    #[inline]
1090    pub fn dup<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1091        let mut s = self.stack_view::<FLAGS>();
1092        let v = s.pop();
1093        s.push(v);
1094        s.push(v);
1095        Some(pc)
1096    }
1097
1098    /// Over
1099    ///
1100    /// ```text
1101    /// OVR a b -- a b a
1102    /// ```
1103    ///
1104    /// Duplicates the second value at the top of the stack.
1105    ///
1106    /// ```text
1107    /// #1234 OVR          ( 12 34 12 )
1108    /// #1234 OVRk         ( 12 34 12 34 12 )
1109    /// #1234 #5678 OVR2   ( 12 34 56 78 12 34 )
1110    /// #1234 #5678 OVR2k  ( 12 34 56 78 12 34 56 78 12 34 )
1111    /// ```
1112    #[inline]
1113    pub fn ovr<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1114        let mut s = self.stack_view::<FLAGS>();
1115        let b = s.pop();
1116        let a = s.pop();
1117        s.push(a);
1118        s.push(b);
1119        s.push(a);
1120        Some(pc)
1121    }
1122
1123    /// Equal
1124    ///
1125    /// ```text
1126    /// EQU a b -- bool8
1127    /// ```
1128    ///
1129    /// Pushes `01` to the stack if the two values at the top of the stack are
1130    /// equal, `00` otherwise.
1131    ///
1132    /// ```text
1133    /// #1212 EQU          ( 01 )
1134    /// #1234 EQUk         ( 12 34 00 )
1135    /// #abcd #ef01 EQU2   ( 00 )
1136    /// #abcd #abcd EQU2k  ( ab cd ab cd 01 )
1137    /// ```
1138    #[inline]
1139    pub fn equ<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1140        op_cmp!(self, FLAGS, |a, b| a == b);
1141        Some(pc)
1142    }
1143
1144    /// Not Equal
1145    ///
1146    /// ```text
1147    /// NEQ a b -- bool8
1148    /// ```
1149    ///
1150    /// Pushes `01` to the stack if the two values at the top of the stack are
1151    /// not equal, `00` otherwise.
1152    ///
1153    /// ```text
1154    /// #1212 NEQ          ( 00 )
1155    /// #1234 NEQk         ( 12 34 01 )
1156    /// #abcd #ef01 NEQ2   ( 01 )
1157    /// #abcd #abcd NEQ2k  ( ab cd ab cd 00 )
1158    /// ```
1159    #[inline]
1160    pub fn neq<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1161        op_cmp!(self, FLAGS, |a, b| a != b);
1162        Some(pc)
1163    }
1164
1165    /// Greater Than
1166    ///
1167    /// ```text
1168    /// GTH a b -- bool8
1169    /// ```
1170    ///
1171    /// Pushes `01` to the stack if the second value at the top of the stack is
1172    /// greater than the value at the top of the stack, `00` otherwise.
1173    ///
1174    /// ```text
1175    /// #1234 GTH          ( 00 )
1176    /// #3412 GTHk         ( 34 12 01 )
1177    /// #3456 #1234 GTH2   ( 01 )
1178    /// #1234 #3456 GTH2k  ( 12 34 34 56 00 )
1179    /// ```
1180    #[inline]
1181    pub fn gth<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1182        op_cmp!(self, FLAGS, |a, b| a > b);
1183        Some(pc)
1184    }
1185
1186    /// Lesser Than
1187    ///
1188    /// ```text
1189    /// LTH a b -- bool8
1190    /// ```
1191    ///
1192    /// Pushes `01` to the stack if the second value at the top of the stack is
1193    /// lesser than the value at the top of the stack, `00` otherwise.
1194    ///
1195    /// ```text
1196    /// #0101 LTH          ( 00 )
1197    /// #0100 LTHk         ( 01 00 00 )
1198    /// #0001 #0000 LTH2   ( 00 )
1199    /// #0001 #0000 LTH2k  ( 00 01 00 00 00 )
1200    /// ```
1201    #[inline]
1202    pub fn lth<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1203        op_cmp!(self, FLAGS, |a, b| a < b);
1204        Some(pc)
1205    }
1206
1207    /// Jump
1208    ///
1209    /// ```text
1210    /// JMP addr --
1211    /// ```
1212    ///
1213    /// Moves the PC by a relative distance equal to the signed byte on the top
1214    /// of the stack, or to an absolute address in short mode.
1215    ///
1216    /// ```text
1217    /// ,&skip-rel JMP BRK &skip-rel #01  ( 01 )
1218    /// ```
1219    #[inline]
1220    pub fn jmp<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1221        let mut s = self.stack_view::<FLAGS>();
1222        Some(Self::jump_offset(pc, s.pop()))
1223    }
1224
1225    /// Jump Conditional
1226    ///
1227    /// ```text
1228    /// JCN cond8 addr --
1229    /// ```
1230    ///
1231    /// If the byte preceeding the address is not `00`, moves the `PC` by a
1232    /// signed value equal to the byte on the top of the stack, or to an
1233    /// absolute address in short mode.
1234    ///
1235    /// ```text
1236    /// #abcd #01 ,&pass JCN SWP &pass POP  ( ab )
1237    /// #abcd #00 ,&fail JCN SWP &fail POP  ( cd )
1238    /// ```
1239    #[inline]
1240    pub fn jcn<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1241        let mut s = self.stack_view::<FLAGS>();
1242        let dst = s.pop();
1243        let cond = s.pop_byte();
1244        Some(if cond != 0 {
1245            Self::jump_offset(pc, dst)
1246        } else {
1247            pc
1248        })
1249    }
1250
1251    /// Jump Stash Return
1252    ///
1253    /// ```text
1254    /// JSR addr -- | ret16
1255    /// ```
1256    ///
1257    /// Pushes the `PC` to the return-stack and moves the `PC` by a signed value
1258    /// equal to the byte on the top of the stack, or to an absolute address in
1259    /// short mode.
1260    ///
1261    /// ```text
1262    /// ,&routine JSR                     ( | PC* )
1263    /// ,&get JSR #01 BRK &get #02 JMP2r  ( 02 01 )
1264    /// ```
1265    #[inline]
1266    pub fn jsr<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1267        self.ret_stack_view::<FLAGS>().push(Value::Short(pc));
1268        let mut s = self.stack_view::<FLAGS>();
1269        Some(Self::jump_offset(pc, s.pop()))
1270    }
1271
1272    /// Stash
1273    ///
1274    /// ```text
1275    /// STH a -- | a
1276    /// ```
1277    ///
1278    /// Moves the value at the top of the stack to the return stack. Note that
1279    /// with the `r`-mode, the stacks are exchanged and the value is moved from
1280    /// the return stack to the working stack.
1281    ///
1282    /// ```text
1283    /// #12 STH       ( | 12 )
1284    /// LITr 34 STHr  ( 34 )
1285    /// ```
1286    #[inline]
1287    pub fn sth<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1288        let v = self.stack_view::<FLAGS>().pop();
1289        self.ret_stack_view::<FLAGS>().push(v);
1290        Some(pc)
1291    }
1292
1293    /// Load Zero-Page
1294    ///
1295    /// ```text
1296    /// LDZ addr8 -- value
1297    /// ```
1298    /// Pushes the value at an address within the first 256 bytes of memory, to
1299    /// the top of the stack.
1300    ///
1301    /// ```text
1302    /// |00 @cell $2 |0100 .cell LDZ ( 00 )
1303    /// ```
1304    #[inline]
1305    pub fn ldz<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1306        let addr = self.stack_view::<FLAGS>().pop_byte();
1307        let v = self.ram_read::<FLAGS>(u16::from(addr));
1308        self.stack_view::<FLAGS>().push(v);
1309        Some(pc)
1310    }
1311
1312    /// Store Zero-Page
1313    ///
1314    /// ```text
1315    /// STZ val addr8 --
1316    /// ```
1317    /// Writes a value to an address within the first 256 bytes of memory.
1318    ///
1319    /// ```text
1320    /// |00 @cell $2 |0100 #abcd .cell STZ2  { ab cd }
1321    /// ```
1322    #[inline]
1323    pub fn stz<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1324        let mut s = self.stack_view::<FLAGS>();
1325        let addr = s.pop_byte();
1326        let v = s.pop();
1327        self.ram_write(u16::from(addr), v);
1328        Some(pc)
1329    }
1330
1331    /// Load Relative
1332    ///
1333    /// ```text
1334    /// LDR addr8 -- value
1335    /// ```
1336    ///
1337    /// Pushes a value at a relative address in relation to the PC, within a
1338    /// range between -128 and +127 bytes, to the top of the stack.
1339    ///
1340    /// ```text
1341    /// ,cell LDR2 BRK @cell abcd  ( ab cd )
1342    /// ```
1343    #[inline]
1344    pub fn ldr<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1345        let offset = self.stack_view::<FLAGS>().pop_byte() as i8;
1346        let addr = pc.wrapping_add_signed(i16::from(offset));
1347        let v = self.ram_read::<FLAGS>(addr);
1348        self.stack_view::<FLAGS>().push(v);
1349        Some(pc)
1350    }
1351
1352    /// Store Relative
1353    ///
1354    /// ```text
1355    /// STR val addr8 --
1356    /// ```
1357    ///
1358    /// Writes a value to a relative address in relation to the PC, within a
1359    /// range between -128 and +127 bytes.
1360    ///
1361    /// ```text
1362    /// #1234 ,cell STR2 BRK @cell $2  ( )
1363    /// ```
1364    #[inline]
1365    pub fn str<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1366        let mut s = self.stack_view::<FLAGS>();
1367        let offset = s.pop_byte() as i8;
1368        let addr = pc.wrapping_add_signed(i16::from(offset));
1369        let v = s.pop();
1370        self.ram_write(addr, v);
1371        Some(pc)
1372    }
1373
1374    /// Load Absolute
1375    ///
1376    /// ```text
1377    /// LDA addr16 -- value
1378    /// ```
1379    ///
1380    /// Pushes the value at a absolute address, to the top of the stack.
1381    ///
1382    /// ```text
1383    /// ;cell LDA BRK @cell abcd ( ab )
1384    /// ```
1385    #[inline]
1386    pub fn lda<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1387        let addr = self.stack_view::<FLAGS>().pop_short();
1388        let v = self.ram_read::<FLAGS>(addr);
1389        self.stack_view::<FLAGS>().push(v);
1390        Some(pc)
1391    }
1392
1393    /// Store Absolute
1394    ///
1395    /// ```text
1396    /// STA val addr16 --
1397    /// ```
1398    ///
1399    /// Writes a value to a absolute address.
1400    ///
1401    /// ```text
1402    /// #abcd ;cell STA BRK @cell $1 ( ab )
1403    /// ```
1404    #[inline]
1405    pub fn sta<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1406        let mut s = self.stack_view::<FLAGS>();
1407        let addr = s.pop_short();
1408        let v = s.pop();
1409        self.ram_write(addr, v);
1410        Some(pc)
1411    }
1412
1413    /// Device Input
1414    ///
1415    /// ```text
1416    /// DEI device8 -- value
1417    /// ```
1418    ///
1419    /// Pushes a value from the device page, to the top of the stack. The target
1420    /// device might capture the reading to trigger an I/O event.
1421    #[inline]
1422    pub fn dei<const FLAGS: u8>(&mut self, dev: &mut dyn Device, pc: u16) -> Option<u16> {
1423        let mut s = self.stack_view::<FLAGS>();
1424        let i = s.pop_byte();
1425
1426        // For compatibility with the C implementation, we'll
1427        // pre-emtively push a dummy value here, then use `emplace` to
1428        // replace it afterwards.  This is because the C implementation
1429        // `uxn.c` reserves stack space before calling `emu_deo/dei`,
1430        // which affects the behavior of `System.rst/wst`
1431        let v = if short(FLAGS) {
1432            s.reserve(2);
1433            dev.dei(self, i);
1434            let hi = self.dev[usize::from(i)];
1435            let j = i.wrapping_add(1);
1436            dev.dei(self, j);
1437            let lo = self.dev[usize::from(j)];
1438            Value::Short(u16::from_le_bytes([lo, hi]))
1439        } else {
1440            s.reserve(1);
1441            dev.dei(self, i);
1442            Value::Byte(self.dev[usize::from(i)])
1443        };
1444        self.stack_view::<FLAGS>().emplace(v);
1445        Some(pc)
1446    }
1447
1448    /// Device Output
1449    ///
1450    /// ```text
1451    /// DEO val device8 --
1452    /// ```
1453    ///
1454    /// Writes a value to the device page. The target device might capture the
1455    /// writing to trigger an I/O event.
1456    #[inline]
1457    pub fn deo<const FLAGS: u8>(&mut self, dev: &mut dyn Device, pc: u16) -> Option<u16> {
1458        let mut s = self.stack_view::<FLAGS>();
1459        let i = s.pop_byte();
1460        let mut run = true;
1461        match s.pop() {
1462            Value::Short(v) => {
1463                let [lo, hi] = v.to_le_bytes();
1464                let j = i.wrapping_add(1);
1465                self.dev[usize::from(i)] = hi;
1466                run &= dev.deo(self, i);
1467                self.dev[usize::from(j)] = lo;
1468                run &= dev.deo(self, j);
1469            }
1470            Value::Byte(v) => {
1471                self.dev[usize::from(i)] = v;
1472                run &= dev.deo(self, i);
1473            }
1474        }
1475        if run {
1476            Some(pc)
1477        } else {
1478            None
1479        }
1480    }
1481
1482    /// Add
1483    ///
1484    /// ```text
1485    /// ADD a b -- a+b
1486    /// ```
1487    /// Pushes the sum of the two values at the top of the stack.
1488    ///
1489    /// ```text
1490    /// #1a #2e ADD       ( 48 )
1491    /// #02 #5d ADDk      ( 02 5d 5f )
1492    /// #0001 #0002 ADD2  ( 00 03 )
1493    /// ```
1494    #[inline]
1495    pub fn add<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1496        op_bin!(self, FLAGS, |a, b| a.wrapping_add(b));
1497        Some(pc)
1498    }
1499
1500    /// Subtract
1501    ///
1502    /// ```text
1503    /// SUB a b -- a-b
1504    /// ```
1505    ///
1506    /// Pushes the difference of the first value minus the second, to the top of
1507    /// the stack.
1508    #[inline]
1509    pub fn sub<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1510        op_bin!(self, FLAGS, |a, b| a.wrapping_sub(b));
1511        Some(pc)
1512    }
1513
1514    /// Multiply
1515    ///
1516    /// ```text
1517    /// MUL a b -- a*b
1518    /// ```
1519    ///
1520    /// Pushes the product of the first and second values at the top of the
1521    /// stack.
1522    #[inline]
1523    pub fn mul<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1524        op_bin!(self, FLAGS, |a, b| a.wrapping_mul(b));
1525        Some(pc)
1526    }
1527
1528    /// Divide
1529    ///
1530    /// ```text
1531    /// DIV a b -- a/b
1532    /// ```
1533    ///
1534    /// Pushes the quotient of the first value over the second, to the top of
1535    /// the stack. A division by zero pushes zero on the stack. The rounding
1536    /// direction is toward zero.
1537    ///
1538    /// ```text
1539    /// #10 #02 DIV       ( 08 )
1540    /// #10 #03 DIVk      ( 10 03 05 )
1541    /// #0010 #0000 DIV2  ( 00 00 )
1542    /// ```
1543    #[inline]
1544    pub fn div<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1545        op_bin!(self, FLAGS, |a, b| a.checked_div(b).unwrap_or(0));
1546        Some(pc)
1547    }
1548
1549    /// And
1550    ///
1551    /// ```text
1552    /// AND a b -- a&b
1553    /// ```
1554    ///
1555    /// Pushes the result of the bitwise operation `AND`, to the top of the
1556    /// stack.
1557    #[inline]
1558    pub fn and<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1559        op_bin!(self, FLAGS, |a, b| a & b);
1560        Some(pc)
1561    }
1562
1563    /// Or
1564    ///
1565    /// ```text
1566    /// ORA a b -- a|b
1567    /// ```
1568    /// Pushes the result of the bitwise operation `OR`, to the top of the stack.
1569    #[inline]
1570    pub fn ora<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1571        op_bin!(self, FLAGS, |a, b| a | b);
1572        Some(pc)
1573    }
1574
1575    /// Exclusive Or
1576    ///
1577    /// ```text
1578    /// EOR a b -- a^b
1579    /// ```
1580    ///
1581    /// Pushes the result of the bitwise operation `XOR`, to the top of the
1582    /// stack.
1583    #[inline]
1584    pub fn eor<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1585        op_bin!(self, FLAGS, |a, b| a ^ b);
1586        Some(pc)
1587    }
1588
1589    /// Shift
1590    ///
1591    /// ```text
1592    /// SFT a shift8 -- c
1593    /// ```
1594    ///
1595    /// Shifts the bits of the second value of the stack to the left or right,
1596    /// depending on the control value at the top of the stack. The high nibble of
1597    /// the control value indicates how many bits to shift left, and the low nibble
1598    /// how many bits to shift right. The rightward shift is done first.
1599    ///
1600    /// ```text
1601    /// #34 #10 SFT        ( 68 )
1602    /// #34 #01 SFT        ( 1a )
1603    /// #34 #33 SFTk       ( 34 33 30 )
1604    /// #1248 #34 SFT2k    ( 12 48 34 09 20 )
1605    /// ```
1606    #[inline]
1607    pub fn sft<const FLAGS: u8>(&mut self, pc: u16) -> Option<u16> {
1608        let mut s = self.stack_view::<FLAGS>();
1609        let shift = s.pop_byte();
1610        let shr = u32::from(shift & 0xF);
1611        let shl = u32::from(shift >> 4);
1612        let v = s.pop();
1613        s.push(v.shr(shr).shl(shl));
1614        Some(pc)
1615    }
1616
1617    /// Returns a shared reference to the RAM buffer
1618    pub fn ram(&self) -> &[u8] {
1619        &self.ram[..]
1620    }
1621
1622    /// Returns a mutable reference to the RAM buffer
1623    pub fn ram_mut(&mut self) -> &mut [u8] {
1624        &mut self.ram[..]
1625    }
1626}
1627
1628/// Trait for a Uxn-compatible device
1629pub trait Device {
1630    /// Performs the `DEI` operation for the given target
1631    ///
1632    /// This function must write its output byte to `vm.dev[target]`; the CPU
1633    /// evaluation loop will then copy this value to the stack.
1634    fn dei(&mut self, vm: &mut Uxn, target: u8);
1635
1636    /// Performs the `DEO` operation on the given target
1637    ///
1638    /// The input byte will be written to `vm.dev[target]` before this function
1639    /// is called, and can be read by the function.
1640    ///
1641    /// Returns `true` if the CPU should keep running, `false` if it should
1642    /// exit.
1643    #[must_use]
1644    fn deo(&mut self, vm: &mut Uxn, target: u8) -> bool;
1645}
1646
1647/// Trait for a type which can be cast to a device ports `struct`
1648pub trait Ports:
1649    zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::FromZeros + zerocopy::Immutable
1650{
1651    /// Base address of the port, of the form `0xA0`
1652    const BASE: u8;
1653}
1654
1655/// Device which does nothing
1656pub struct EmptyDevice;
1657impl Device for EmptyDevice {
1658    fn dei(&mut self, _vm: &mut Uxn, _target: u8) {
1659        // nothing to do here
1660    }
1661    fn deo(&mut self, _vm: &mut Uxn, _target: u8) -> bool {
1662        // nothing to do here, keep running
1663        true
1664    }
1665}
1666
1667#[cfg(feature = "alloc")]
1668mod ram {
1669    extern crate alloc;
1670    use alloc::{boxed::Box, vec};
1671
1672    /// Helper type for building a RAM array of the appropriate size
1673    ///
1674    /// This is only available if the `"alloc"` feature is enabled
1675    pub struct UxnRam(Box<[u8; 65536]>);
1676
1677    impl UxnRam {
1678        /// Builds a new zero-initialized RAM
1679        pub fn new() -> Self {
1680            UxnRam(vec![0u8; 65536].into_boxed_slice().try_into().unwrap())
1681        }
1682
1683        /// Leaks memory, setting it to a static lifetime
1684        pub fn leak(self) -> &'static mut [u8; 65536] {
1685            Box::leak(self.0)
1686        }
1687    }
1688
1689    impl Default for UxnRam {
1690        fn default() -> Self {
1691            Self::new()
1692        }
1693    }
1694
1695    impl core::ops::Deref for UxnRam {
1696        type Target = [u8; 65536];
1697        fn deref(&self) -> &Self::Target {
1698            &self.0
1699        }
1700    }
1701    impl core::ops::DerefMut for UxnRam {
1702        fn deref_mut(&mut self) -> &mut Self::Target {
1703            &mut self.0
1704        }
1705    }
1706}
1707
1708#[cfg(feature = "alloc")]
1709pub use ram::UxnRam;
1710
1711////////////////////////////////////////////////////////////////////////////////
1712
1713/// Opcode names and constants
1714#[allow(non_upper_case_globals, missing_docs)]
1715pub mod op {
1716    pub const BRK: u8 = 0x0;
1717    pub const INC: u8 = 0x1;
1718    pub const POP: u8 = 0x2;
1719    pub const NIP: u8 = 0x3;
1720    pub const SWP: u8 = 0x4;
1721    pub const ROT: u8 = 0x5;
1722    pub const DUP: u8 = 0x6;
1723    pub const OVR: u8 = 0x7;
1724    pub const EQU: u8 = 0x8;
1725    pub const NEQ: u8 = 0x9;
1726    pub const GTH: u8 = 0xa;
1727    pub const LTH: u8 = 0xb;
1728    pub const JMP: u8 = 0xc;
1729    pub const JCN: u8 = 0xd;
1730    pub const JSR: u8 = 0xe;
1731    pub const STH: u8 = 0x0f;
1732    pub const LDZ: u8 = 0x10;
1733    pub const STZ: u8 = 0x11;
1734    pub const LDR: u8 = 0x12;
1735    pub const STR: u8 = 0x13;
1736    pub const LDA: u8 = 0x14;
1737    pub const STA: u8 = 0x15;
1738    pub const DEI: u8 = 0x16;
1739    pub const DEO: u8 = 0x17;
1740    pub const ADD: u8 = 0x18;
1741    pub const SUB: u8 = 0x19;
1742    pub const MUL: u8 = 0x1a;
1743    pub const DIV: u8 = 0x1b;
1744    pub const AND: u8 = 0x1c;
1745    pub const ORA: u8 = 0x1d;
1746    pub const EOR: u8 = 0x1e;
1747    pub const SFT: u8 = 0x1f;
1748    pub const JCI: u8 = 0x20;
1749    pub const INC2: u8 = 0x21;
1750    pub const POP2: u8 = 0x22;
1751    pub const NIP2: u8 = 0x23;
1752    pub const SWP2: u8 = 0x24;
1753    pub const ROT2: u8 = 0x25;
1754    pub const DUP2: u8 = 0x26;
1755    pub const OVR2: u8 = 0x27;
1756    pub const EQU2: u8 = 0x28;
1757    pub const NEQ2: u8 = 0x29;
1758    pub const GTH2: u8 = 0x2a;
1759    pub const LTH2: u8 = 0x2b;
1760    pub const JMP2: u8 = 0x2c;
1761    pub const JCN2: u8 = 0x2d;
1762    pub const JSR2: u8 = 0x2e;
1763    pub const STH2: u8 = 0x2f;
1764    pub const LDZ2: u8 = 0x30;
1765    pub const STZ2: u8 = 0x31;
1766    pub const LDR2: u8 = 0x32;
1767    pub const STR2: u8 = 0x33;
1768    pub const LDA2: u8 = 0x34;
1769    pub const STA2: u8 = 0x35;
1770    pub const DEI2: u8 = 0x36;
1771    pub const DEO2: u8 = 0x37;
1772    pub const ADD2: u8 = 0x38;
1773    pub const SUB2: u8 = 0x39;
1774    pub const MUL2: u8 = 0x3a;
1775    pub const DIV2: u8 = 0x3b;
1776    pub const AND2: u8 = 0x3c;
1777    pub const ORA2: u8 = 0x3d;
1778    pub const EOR2: u8 = 0x3e;
1779    pub const SFT2: u8 = 0x3f;
1780    pub const JMI: u8 = 0x40;
1781    pub const INCr: u8 = 0x41;
1782    pub const POPr: u8 = 0x42;
1783    pub const NIPr: u8 = 0x43;
1784    pub const SWPr: u8 = 0x44;
1785    pub const ROTr: u8 = 0x45;
1786    pub const DUPr: u8 = 0x46;
1787    pub const OVRr: u8 = 0x47;
1788    pub const EQUr: u8 = 0x48;
1789    pub const NEQr: u8 = 0x49;
1790    pub const GTHr: u8 = 0x4a;
1791    pub const LTHr: u8 = 0x4b;
1792    pub const JMPr: u8 = 0x4c;
1793    pub const JCNr: u8 = 0x4d;
1794    pub const JSRr: u8 = 0x4e;
1795    pub const STHr: u8 = 0x4f;
1796    pub const LDZr: u8 = 0x50;
1797    pub const STZr: u8 = 0x51;
1798    pub const LDRr: u8 = 0x52;
1799    pub const STRr: u8 = 0x53;
1800    pub const LDAr: u8 = 0x54;
1801    pub const STAr: u8 = 0x55;
1802    pub const DEIr: u8 = 0x56;
1803    pub const DEOr: u8 = 0x57;
1804    pub const ADDr: u8 = 0x58;
1805    pub const SUBr: u8 = 0x59;
1806    pub const MULr: u8 = 0x5a;
1807    pub const DIVr: u8 = 0x5b;
1808    pub const ANDr: u8 = 0x5c;
1809    pub const ORAr: u8 = 0x5d;
1810    pub const EORr: u8 = 0x5e;
1811    pub const SFTr: u8 = 0x5f;
1812    pub const JSI: u8 = 0x60;
1813    pub const INC2r: u8 = 0x61;
1814    pub const POP2r: u8 = 0x62;
1815    pub const NIP2r: u8 = 0x63;
1816    pub const SWP2r: u8 = 0x64;
1817    pub const ROT2r: u8 = 0x65;
1818    pub const DUP2r: u8 = 0x66;
1819    pub const OVR2r: u8 = 0x67;
1820    pub const EQU2r: u8 = 0x68;
1821    pub const NEQ2r: u8 = 0x69;
1822    pub const GTH2r: u8 = 0x6a;
1823    pub const LTH2r: u8 = 0x6b;
1824    pub const JMP2r: u8 = 0x6c;
1825    pub const JCN2r: u8 = 0x6d;
1826    pub const JSR2r: u8 = 0x6e;
1827    pub const STH2r: u8 = 0x6f;
1828    pub const LDZ2r: u8 = 0x70;
1829    pub const STZ2r: u8 = 0x71;
1830    pub const LDR2r: u8 = 0x72;
1831    pub const STR2r: u8 = 0x73;
1832    pub const LDA2r: u8 = 0x74;
1833    pub const STA2r: u8 = 0x75;
1834    pub const DEI2r: u8 = 0x76;
1835    pub const DEO2r: u8 = 0x77;
1836    pub const ADD2r: u8 = 0x78;
1837    pub const SUB2r: u8 = 0x79;
1838    pub const MUL2r: u8 = 0x7a;
1839    pub const DIV2r: u8 = 0x7b;
1840    pub const AND2r: u8 = 0x7c;
1841    pub const ORA2r: u8 = 0x7d;
1842    pub const EOR2r: u8 = 0x7e;
1843    pub const SFT2r: u8 = 0x7f;
1844    pub const LIT: u8 = 0x80;
1845    pub const INCk: u8 = 0x81;
1846    pub const POPk: u8 = 0x82;
1847    pub const NIPk: u8 = 0x83;
1848    pub const SWPk: u8 = 0x84;
1849    pub const ROTk: u8 = 0x85;
1850    pub const DUPk: u8 = 0x86;
1851    pub const OVRk: u8 = 0x87;
1852    pub const EQUk: u8 = 0x88;
1853    pub const NEQk: u8 = 0x89;
1854    pub const GTHk: u8 = 0x8a;
1855    pub const LTHk: u8 = 0x8b;
1856    pub const JMPk: u8 = 0x8c;
1857    pub const JCNk: u8 = 0x8d;
1858    pub const JSRk: u8 = 0x8e;
1859    pub const STHk: u8 = 0x8f;
1860    pub const LDZk: u8 = 0x90;
1861    pub const STZk: u8 = 0x91;
1862    pub const LDRk: u8 = 0x92;
1863    pub const STRk: u8 = 0x93;
1864    pub const LDAk: u8 = 0x94;
1865    pub const STAk: u8 = 0x95;
1866    pub const DEIk: u8 = 0x96;
1867    pub const DEOk: u8 = 0x97;
1868    pub const ADDk: u8 = 0x98;
1869    pub const SUBk: u8 = 0x99;
1870    pub const MULk: u8 = 0x9a;
1871    pub const DIVk: u8 = 0x9b;
1872    pub const ANDk: u8 = 0x9c;
1873    pub const ORAk: u8 = 0x9d;
1874    pub const EORk: u8 = 0x9e;
1875    pub const SFTk: u8 = 0x9f;
1876    pub const LIT2: u8 = 0xa0;
1877    pub const INC2k: u8 = 0xa1;
1878    pub const POP2k: u8 = 0xa2;
1879    pub const NIP2k: u8 = 0xa3;
1880    pub const SWP2k: u8 = 0xa4;
1881    pub const ROT2k: u8 = 0xa5;
1882    pub const DUP2k: u8 = 0xa6;
1883    pub const OVR2k: u8 = 0xa7;
1884    pub const EQU2k: u8 = 0xa8;
1885    pub const NEQ2k: u8 = 0xa9;
1886    pub const GTH2k: u8 = 0xaa;
1887    pub const LTH2k: u8 = 0xab;
1888    pub const JMP2k: u8 = 0xac;
1889    pub const JCN2k: u8 = 0xad;
1890    pub const JSR2k: u8 = 0xae;
1891    pub const STH2k: u8 = 0xaf;
1892    pub const LDZ2k: u8 = 0xb0;
1893    pub const STZ2k: u8 = 0xb1;
1894    pub const LDR2k: u8 = 0xb2;
1895    pub const STR2k: u8 = 0xb3;
1896    pub const LDA2k: u8 = 0xb4;
1897    pub const STA2k: u8 = 0xb5;
1898    pub const DEI2k: u8 = 0xb6;
1899    pub const DEO2k: u8 = 0xb7;
1900    pub const ADD2k: u8 = 0xb8;
1901    pub const SUB2k: u8 = 0xb9;
1902    pub const MUL2k: u8 = 0xba;
1903    pub const DIV2k: u8 = 0xbb;
1904    pub const AND2k: u8 = 0xbc;
1905    pub const ORA2k: u8 = 0xbd;
1906    pub const EOR2k: u8 = 0xbe;
1907    pub const SFT2k: u8 = 0xbf;
1908    pub const LITr: u8 = 0xc0;
1909    pub const INCkr: u8 = 0xc1;
1910    pub const POPkr: u8 = 0xc2;
1911    pub const NIPkr: u8 = 0xc3;
1912    pub const SWPkr: u8 = 0xc4;
1913    pub const ROTkr: u8 = 0xc5;
1914    pub const DUPkr: u8 = 0xc6;
1915    pub const OVRkr: u8 = 0xc7;
1916    pub const EQUkr: u8 = 0xc8;
1917    pub const NEQkr: u8 = 0xc9;
1918    pub const GTHkr: u8 = 0xca;
1919    pub const LTHkr: u8 = 0xcb;
1920    pub const JMPkr: u8 = 0xcc;
1921    pub const JCNkr: u8 = 0xcd;
1922    pub const JSRkr: u8 = 0xce;
1923    pub const STHkr: u8 = 0xcf;
1924    pub const LDZkr: u8 = 0xd0;
1925    pub const STZkr: u8 = 0xd1;
1926    pub const LDRkr: u8 = 0xd2;
1927    pub const STRkr: u8 = 0xd3;
1928    pub const LDAkr: u8 = 0xd4;
1929    pub const STAkr: u8 = 0xd5;
1930    pub const DEIkr: u8 = 0xd6;
1931    pub const DEOkr: u8 = 0xd7;
1932    pub const ADDkr: u8 = 0xd8;
1933    pub const SUBkr: u8 = 0xd9;
1934    pub const MULkr: u8 = 0xda;
1935    pub const DIVkr: u8 = 0xdb;
1936    pub const ANDkr: u8 = 0xdc;
1937    pub const ORAkr: u8 = 0xdd;
1938    pub const EORkr: u8 = 0xde;
1939    pub const SFTkr: u8 = 0xdf;
1940    pub const LIT2r: u8 = 0xe0;
1941    pub const INC2kr: u8 = 0xe1;
1942    pub const POP2kr: u8 = 0xe2;
1943    pub const NIP2kr: u8 = 0xe3;
1944    pub const SWP2kr: u8 = 0xe4;
1945    pub const ROT2kr: u8 = 0xe5;
1946    pub const DUP2kr: u8 = 0xe6;
1947    pub const OVR2kr: u8 = 0xe7;
1948    pub const EQU2kr: u8 = 0xe8;
1949    pub const NEQ2kr: u8 = 0xe9;
1950    pub const GTH2kr: u8 = 0xea;
1951    pub const LTH2kr: u8 = 0xeb;
1952    pub const JMP2kr: u8 = 0xec;
1953    pub const JCN2kr: u8 = 0xed;
1954    pub const JSR2kr: u8 = 0xee;
1955    pub const STH2kr: u8 = 0xef;
1956    pub const LDZ2kr: u8 = 0xf0;
1957    pub const STZ2kr: u8 = 0xf1;
1958    pub const LDR2kr: u8 = 0xf2;
1959    pub const STR2kr: u8 = 0xf3;
1960    pub const LDA2kr: u8 = 0xf4;
1961    pub const STA2kr: u8 = 0xf5;
1962    pub const DEI2kr: u8 = 0xf6;
1963    pub const DEO2kr: u8 = 0xf7;
1964    pub const ADD2kr: u8 = 0xf8;
1965    pub const SUB2kr: u8 = 0xf9;
1966    pub const MUL2kr: u8 = 0xfa;
1967    pub const DIV2kr: u8 = 0xfb;
1968    pub const AND2kr: u8 = 0xfc;
1969    pub const ORA2kr: u8 = 0xfd;
1970    pub const EOR2kr: u8 = 0xfe;
1971    pub const SFT2kr: u8 = 0xff;
1972
1973    pub const NAMES: [&str; 256] = [
1974        "BRK", "INC", "POP", "NIP", "SWP", "ROT", "DUP", "OVR", "EQU", "NEQ", "GTH", "LTH", "JMP",
1975        "JCN", "JSR", "STH", "LDZ", "STZ", "LDR", "STR", "LDA", "STA", "DEI", "DEO", "ADD", "SUB",
1976        "MUL", "DIV", "AND", "ORA", "EOR", "SFT", "JCI", "INC2", "POP2", "NIP2", "SWP2", "ROT2",
1977        "DUP2", "OVR2", "EQU2", "NEQ2", "GTH2", "LTH2", "JMP2", "JCN2", "JSR2", "STH2", "LDZ2",
1978        "STZ2", "LDR2", "STR2", "LDA2", "STA2", "DEI2", "DEO2", "ADD2", "SUB2", "MUL2", "DIV2",
1979        "AND2", "ORA2", "EOR2", "SFT2", "JMI", "INCr", "POPr", "NIPr", "SWPr", "ROTr", "DUPr",
1980        "OVRr", "EQUr", "NEQr", "GTHr", "LTHr", "JMPr", "JCNr", "JSRr", "STHr", "LDZr", "STZr",
1981        "LDRr", "STRr", "LDAr", "STAr", "DEIr", "DEOr", "ADDr", "SUBr", "MULr", "DIVr", "ANDr",
1982        "ORAr", "EORr", "SFTr", "JSI", "INC2r", "POP2r", "NIP2r", "SWP2r", "ROT2r", "DUP2r",
1983        "OVR2r", "EQU2r", "NEQ2r", "GTH2r", "LTH2r", "JMP2r", "JCN2r", "JSR2r", "STH2r", "LDZ2r",
1984        "STZ2r", "LDR2r", "STR2r", "LDA2r", "STA2r", "DEI2r", "DEO2r", "ADD2r", "SUB2r", "MUL2r",
1985        "DIV2r", "AND2r", "ORA2r", "EOR2r", "SFT2r", "LIT", "INCk", "POPk", "NIPk", "SWPk", "ROTk",
1986        "DUPk", "OVRk", "EQUk", "NEQk", "GTHk", "LTHk", "JMPk", "JCNk", "JSRk", "STHk", "LDZk",
1987        "STZk", "LDRk", "STRk", "LDAk", "STAk", "DEIk", "DEOk", "ADDk", "SUBk", "MULk", "DIVk",
1988        "ANDk", "ORAk", "EORk", "SFTk", "LIT2", "INC2k", "POP2k", "NIP2k", "SWP2k", "ROT2k",
1989        "DUP2k", "OVR2k", "EQU2k", "NEQ2k", "GTH2k", "LTH2k", "JMP2k", "JCN2k", "JSR2k", "STH2k",
1990        "LDZ2k", "STZ2k", "LDR2k", "STR2k", "LDA2k", "STA2k", "DEI2k", "DEO2k", "ADD2k", "SUB2k",
1991        "MUL2k", "DIV2k", "AND2k", "ORA2k", "EOR2k", "SFT2k", "LITr", "INCkr", "POPkr", "NIPkr",
1992        "SWPkr", "ROTkr", "DUPkr", "OVRkr", "EQUkr", "NEQkr", "GTHkr", "LTHkr", "JMPkr", "JCNkr",
1993        "JSRkr", "STHkr", "LDZkr", "STZkr", "LDRkr", "STRkr", "LDAkr", "STAkr", "DEIkr", "DEOkr",
1994        "ADDkr", "SUBkr", "MULkr", "DIVkr", "ANDkr", "ORAkr", "EORkr", "SFTkr", "LIT2r", "INC2kr",
1995        "POP2kr", "NIP2kr", "SWP2kr", "ROT2kr", "DUP2kr", "OVR2kr", "EQU2kr", "NEQ2kr", "GTH2kr",
1996        "LTH2kr", "JMP2kr", "JCN2kr", "JSR2kr", "STH2kr", "LDZ2kr", "STZ2kr", "LDR2kr", "STR2kr",
1997        "LDA2kr", "STA2kr", "DEI2kr", "DEO2kr", "ADD2kr", "SUB2kr", "MUL2kr", "DIV2kr", "AND2kr",
1998        "ORA2kr", "EOR2kr", "SFT2kr",
1999    ];
2000}
2001
2002#[cfg(all(feature = "alloc", test))]
2003mod test {
2004    use super::*;
2005
2006    /// Simple parser for textual opcodes
2007    fn decode_op(s: &str) -> Result<u8, &str> {
2008        let (s, ret) = s.strip_suffix('r').map(|s| (s, true)).unwrap_or((s, false));
2009        let (s, keep) = s.strip_suffix('k').map(|s| (s, true)).unwrap_or((s, false));
2010        let (s, short) = s.strip_suffix('2').map(|s| (s, true)).unwrap_or((s, false));
2011        let mode = (u8::from(keep) << 7) | (u8::from(ret) << 6) | (u8::from(short) << 5);
2012        let out = match s {
2013            "BRK" => op::BRK,
2014            "JCI" => op::JCI,
2015            "JMI" => op::JMI,
2016            "JSI" => op::JSI,
2017            "LIT" => op::LIT | mode,
2018
2019            "INC" => op::INC | mode,
2020            "POP" => op::POP | mode,
2021            "NIP" => op::NIP | mode,
2022            "SWP" => op::SWP | mode,
2023            "ROT" => op::ROT | mode,
2024            "DUP" => op::DUP | mode,
2025            "OVR" => op::OVR | mode,
2026            "EQU" => op::EQU | mode,
2027            "NEQ" => op::NEQ | mode,
2028            "GTH" => op::GTH | mode,
2029            "LTH" => op::LTH | mode,
2030            "JMP" => op::JMP | mode,
2031            "JCN" => op::JCN | mode,
2032            "JSR" => op::JSR | mode,
2033            "STH" => op::STH | mode,
2034            "LDZ" => op::LDZ | mode,
2035            "STZ" => op::STZ | mode,
2036            "LDR" => op::LDR | mode,
2037            "STR" => op::STR | mode,
2038            "LDA" => op::LDA | mode,
2039            "STA" => op::STA | mode,
2040            "DEI" => op::DEI | mode,
2041            "DEO" => op::DEO | mode,
2042            "ADD" => op::ADD | mode,
2043            "SUB" => op::SUB | mode,
2044            "MUL" => op::MUL | mode,
2045            "DIV" => op::DIV | mode,
2046            "AND" => op::AND | mode,
2047            "ORA" => op::ORA | mode,
2048            "EOR" => op::EOR | mode,
2049            "SFT" => op::SFT | mode,
2050            _ => return Err(s),
2051        };
2052        Ok(out)
2053    }
2054
2055    fn parse_and_test(s: &str) {
2056        let mut ram = UxnRam::new();
2057        let mut vm = Uxn::new(&mut ram, Backend::Interpreter);
2058        let mut iter = s.split_whitespace();
2059        let mut op = None;
2060        let mut dev = EmptyDevice;
2061        while let Some(i) = iter.next() {
2062            if let Some(s) = i.strip_prefix('#') {
2063                match s.len() {
2064                    2 => {
2065                        let v = u8::from_str_radix(s, 16).unwrap();
2066                        vm.stack.push_byte(v);
2067                    }
2068                    4 => {
2069                        let v = u16::from_str_radix(s, 16).unwrap();
2070                        vm.stack.push_short(v);
2071                    }
2072                    _ => panic!("invalid length for literal: {i:?}"),
2073                }
2074                continue;
2075            } else if i == "(" {
2076                let mut expected: Vec<u8> = vec![];
2077                for s in iter {
2078                    if s == ")" {
2079                        break;
2080                    } else {
2081                        expected.push(u8::from_str_radix(s, 16).unwrap());
2082                    }
2083                }
2084                vm.ram[0] = op.unwrap();
2085                vm.run(&mut dev, 0);
2086                let mut actual = vec![];
2087                while vm.stack.index != u8::MAX {
2088                    actual.push(vm.stack.pop_byte());
2089                }
2090                actual.reverse();
2091                if actual != expected {
2092                    panic!(
2093                        "failed to execute {:?}: got {actual:2x?}, \
2094                         expected {expected:2x?}",
2095                        s.trim()
2096                    );
2097                }
2098                break;
2099            } else {
2100                op = Some(decode_op(i).unwrap());
2101            }
2102        }
2103    }
2104
2105    #[test]
2106    fn opcodes() {
2107        const TEST_SUITE: &str = "
2108            #01 INC         ( 02 )
2109            #0001 INC2      ( 00 02 )
2110            #0001 INC2k     ( 00 01 00 02 )
2111            #1234 POP    ( 12 )
2112            #1234 POP2   ( )
2113            #1234 POP2k  ( 12 34 )
2114            #1234 NIP          ( 34 )
2115            #1234 #5678 NIP2   ( 56 78 )
2116            #1234 #5678 NIP2k  ( 12 34 56 78 56 78 )
2117            #1234 SWP          ( 34 12 )
2118            #1234 SWPk         ( 12 34 34 12 )
2119            #1234 #5678 SWP2   ( 56 78 12 34 )
2120            #1234 #5678 SWP2k  ( 12 34 56 78 56 78 12 34 )
2121            #1234 #56 ROT            ( 34 56 12 )
2122            #1234 #56 ROTk           ( 12 34 56 34 56 12 )
2123            #1234 #5678 #9abc ROT2   ( 56 78 9a bc 12 34 )
2124            #1234 #5678 #9abc ROT2k  ( 12 34 56 78 9a bc 56 78 9a bc 12 34 )
2125            #1234 DUP   ( 12 34 34 )
2126            #12 DUPk    ( 12 12 12 )
2127            #1234 DUP2  ( 12 34 12 34 )
2128            #1234 DUP2k  ( 12 34 12 34 12 34 )
2129            #1234 OVR          ( 12 34 12 )
2130            #1234 OVRk         ( 12 34 12 34 12 )
2131            #1234 #5678 OVR2   ( 12 34 56 78 12 34 )
2132            #1234 #5678 OVR2k  ( 12 34 56 78 12 34 56 78 12 34 )
2133            #1212 EQU          ( 01 )
2134            #1234 EQUk         ( 12 34 00 )
2135            #abcd #ef01 EQU2   ( 00 )
2136            #abcd #abcd EQU2k  ( ab cd ab cd 01 )
2137            #1212 NEQ          ( 00 )
2138            #1234 NEQk         ( 12 34 01 )
2139            #abcd #ef01 NEQ2   ( 01 )
2140            #abcd #abcd NEQ2k  ( ab cd ab cd 00 )
2141            #1234 GTH          ( 00 )
2142            #3412 GTHk         ( 34 12 01 )
2143            #3456 #1234 GTH2   ( 01 )
2144            #1234 #3456 GTH2k  ( 12 34 34 56 00 )
2145            #0101 LTH          ( 00 )
2146            #0100 LTHk         ( 01 00 00 )
2147            #0001 #0000 LTH2   ( 00 )
2148            #0001 #0000 LTH2k  ( 00 01 00 00 00 )
2149            #1a #2e ADD       ( 48 )
2150            #02 #5d ADDk      ( 02 5d 5f )
2151            #0001 #0002 ADD2  ( 00 03 )
2152            #10 #02 DIV       ( 08 )
2153            #10 #03 DIVk      ( 10 03 05 )
2154            #0010 #0000 DIV2  ( 00 00 )
2155            #0120 #0010 DIV2  ( 00 12 )
2156            #0120 #0010 DIV2k ( 01 20 00 10 00 12 )
2157            #34 #10 SFT        ( 68 )
2158            #34 #01 SFT        ( 1a )
2159            #34 #33 SFTk       ( 34 33 30 )
2160            #1248 #34 SFT2k    ( 12 48 34 09 20 )
2161            #1248 #34 SFT2     ( 09 20 )
2162        ";
2163        for line in TEST_SUITE.lines() {
2164            parse_and_test(line);
2165        }
2166
2167        #[allow(dead_code)]
2168        const HARD_TESTS: &str = "
2169            LIT 12          ( 12 )
2170            LIT2 abcd       ( ab cd )
2171            ,&skip-rel JMP BRK &skip-rel #01  ( 01 )
2172            #abcd #01 ,&pass JCN SWP &pass POP  ( ab )
2173            #abcd #00 ,&fail JCN SWP &fail POP  ( cd )
2174            ,&routine JSR                     ( | PC* )
2175            ,&get JSR #01 BRK &get #02 JMP2r  ( 02 01 )
2176            #12 STH       ( | 12 )
2177            LITr 34 STHr  ( 34 )
2178            |00 @cell $2 |0100 .cell LDZ ( 00 )
2179            |00 @cell $2 |0100 #abcd .cell STZ2  { ab cd }
2180            ,cell LDR2 BRK @cell abcd  ( ab cd )
2181            #1234 ,cell STR2 BRK @cell $2  ( )
2182            ;cell LDA BRK @cell abcd ( ab )
2183            #abcd ;cell STA BRK @cell $1 ( ab )
2184        ";
2185    }
2186
2187    // The optimizer is not strong enough to eliminate panics in debug builds!
2188    #[cfg(not(debug_assertions))]
2189    mod no_panic {
2190        // Here's the big idea:
2191        //
2192        // We define a `struct NoPanic` which calls an `extern "C"` function
2193        // when dropped.  Importantly, that C function doesn't exist!  We
2194        // construct an instance of that `struct` as a guard, then call our
2195        // potentially-panicking operation.  After that call completes, we
2196        // `forget` the guard.
2197        //
2198        // If no panics are possible, then the guard is _always_ forgotten, the
2199        // C function is never called, and we don't try to link against it.
2200        //
2201        // However, if panics _are_ possible, then the unwinding has to drop the
2202        // guard, which tries to call that C function.  This fails at link time,
2203        // because the function doesn't exist.
2204        //
2205        // This is borrowed from [no-panic](https://github.com/dtolnay/no-panic)
2206        macro_rules! init {
2207            ($vm:ident, $data:ident, $op:ident) => {
2208                struct NoPanic;
2209                extern "C" {
2210                    #[link_name = concat!(stringify!($op), "_may_panic")]
2211                    fn trigger() -> !;
2212                }
2213                impl ::core::ops::Drop for NoPanic {
2214                    fn drop(&mut self) {
2215                        unsafe {
2216                            trigger();
2217                        }
2218                    }
2219                }
2220                let mut ram = UxnRam::new();
2221                let mut $vm = Uxn::new(&mut ram, Backend::Interpreter);
2222                let _ = $vm.reset($data);
2223                for d in $data {
2224                    $vm.stack.push(Value::Byte(*d));
2225                    $vm.ret.push(Value::Byte(*d));
2226                }
2227            };
2228        }
2229        macro_rules! mode_fns {
2230            ($op:ident) => {
2231                #[test]
2232                fn $op() {
2233                    use $op::no_panic;
2234                    let data = std::hint::black_box(&[]);
2235                    no_panic::<0b000>(data);
2236                    no_panic::<0b001>(data);
2237                    no_panic::<0b010>(data);
2238                    no_panic::<0b011>(data);
2239                    no_panic::<0b100>(data);
2240                    no_panic::<0b101>(data);
2241                    no_panic::<0b110>(data);
2242                    no_panic::<0b111>(data);
2243                }
2244            };
2245        }
2246        macro_rules! no_panic {
2247            ($op:ident) => {
2248                mod $op {
2249                    use super::*;
2250
2251                    #[inline(never)]
2252                    pub fn no_panic<const FLAGS: u8>(data: &[u8]) {
2253                        let guard = NoPanic;
2254                        init!(vm, data, $op);
2255                        vm.$op::<FLAGS>(0x100);
2256                        core::mem::forget(guard);
2257                    }
2258                }
2259                mode_fns!($op);
2260            };
2261        }
2262        macro_rules! no_panic_modeless {
2263            ($op:ident) => {
2264                mod $op {
2265                    use super::*;
2266
2267                    #[inline(never)]
2268                    pub fn no_panic(data: &[u8]) {
2269                        let guard = NoPanic;
2270                        init!(vm, data, $op);
2271                        vm.$op(0x100);
2272                        core::mem::forget(guard);
2273                    }
2274                }
2275                #[test]
2276                fn $op() {
2277                    let data = std::hint::black_box(&[]);
2278                    $op::no_panic(data);
2279                }
2280            };
2281        }
2282        macro_rules! no_panic_dev {
2283            ($op:ident) => {
2284                mod $op {
2285                    use super::*;
2286
2287                    #[inline(never)]
2288                    pub fn no_panic<const FLAGS: u8>(data: &[u8]) {
2289                        let guard = NoPanic;
2290                        init!(vm, data, $op);
2291                        let mut dev = EmptyDevice;
2292                        vm.$op::<FLAGS>(&mut dev, 0x100);
2293                        core::mem::forget(guard);
2294                    }
2295                }
2296                mode_fns!($op);
2297            };
2298        }
2299
2300        use super::*;
2301
2302        no_panic_modeless!(brk);
2303        no_panic!(inc);
2304        no_panic!(pop);
2305        no_panic!(nip);
2306        no_panic!(swp);
2307        no_panic!(rot);
2308        no_panic!(dup);
2309        no_panic!(ovr);
2310        no_panic!(equ);
2311        no_panic!(neq);
2312        no_panic!(gth);
2313        no_panic!(lth);
2314        no_panic!(jmp);
2315        no_panic!(jcn);
2316        no_panic!(jsr);
2317        no_panic!(sth);
2318        no_panic!(ldz);
2319        no_panic!(stz);
2320        no_panic!(ldr);
2321        no_panic!(str);
2322        no_panic!(lda);
2323        no_panic!(sta);
2324        no_panic_dev!(dei);
2325        no_panic_dev!(deo);
2326        no_panic!(add);
2327        no_panic!(sub);
2328        no_panic!(mul);
2329        no_panic!(div);
2330        no_panic!(and);
2331        no_panic!(ora);
2332        no_panic!(eor);
2333        no_panic!(sft);
2334        no_panic_modeless!(jci);
2335        no_panic_modeless!(jmi);
2336        no_panic_modeless!(jsi);
2337        no_panic!(lit); // doesn't use KEEP, but that's fine
2338    }
2339}