1#![cfg_attr(not(test), no_std)]
4#![warn(missing_docs)]
5#![cfg_attr(not(any(test, feature = "native")), forbid(unsafe_code))]
6
7pub 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
25pub const DEV_SIZE: usize = 16;
27
28#[derive(Copy, Clone, Debug, Eq, PartialEq)]
30pub struct Stack {
31 data: [u8; 256],
32
33 index: u8,
37}
38
39impl Stack {
40 pub fn iter(&self) -> impl Iterator<Item = &u8> {
42 let len = self.len() as usize;
43 self.data[..len].iter()
44 }
45
46 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 pub fn as_ptr(&self) -> *const u8 {
56 self.data.as_ptr()
57 }
58
59 #[inline]
61 pub fn as_mut_ptr(&mut self) -> *mut u8 {
62 self.data.as_mut_ptr()
63 }
64
65 #[inline]
67 pub fn index(&self) -> u8 {
68 self.index
69 }
70
71 #[inline]
73 pub fn get(&self, idx: u8) -> u8 {
74 self.data[usize::from(idx)]
75 }
76}
77
78#[derive(Copy, Clone, Debug)]
80pub enum Backend {
81 Interpreter,
83
84 #[cfg(feature = "native")]
85 Native,
87}
88
89struct StackView<'a, const FLAGS: u8> {
95 stack: &'a mut Stack,
96
97 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 #[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 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#[derive(Copy, Clone, Debug)]
182pub enum Value {
183 Short(u16),
185 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 #[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 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 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 #[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 #[inline]
299 pub fn len(&self) -> u8 {
300 self.index.wrapping_add(1)
301 }
302
303 #[inline]
305 pub fn is_empty(&self) -> bool {
306 self.len() == 0
307 }
308
309 #[inline]
311 pub fn set_len(&mut self, n: u8) {
312 self.index = n.wrapping_sub(1);
313 }
314}
315
316pub struct Uxn<'a> {
318 pub dev: [u8; 256],
320 pub ram: &'a mut [u8; 65536],
322 pub stack: Stack,
324 pub ret: Stack,
326
327 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 pub fn stack_data(&self) -> &[u8] {
369 let len = self.stack.len() as usize;
370 &self.stack.data[..len]
371 }
372
373 pub fn ret_data(&self) -> &[u8] {
375 let len = self.ret.len() as usize;
376 &self.ret.data[..len]
377 }
378 pub fn deo_helper(&mut self, dev: &mut dyn Device, port: u8, value: u8, pc: u16) {
380 self.stack_mut().push_byte(value);
382 self.stack_mut().push_byte(port);
383 let _ = self.deo::<0b000>(dev, pc);
384 }
385 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 #[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 #[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 #[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 #[inline]
470 pub fn write_dev_mem(&mut self, addr: u8, value: u8) {
471 self.dev[usize::from(addr)] = value;
472 }
473
474 #[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 #[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 #[inline]
519 pub fn dev<D: Ports + zerocopy::KnownLayout + zerocopy::Immutable>(&self) -> &D {
520 self.dev_at(D::BASE)
521 }
522
523 #[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 #[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 #[inline]
540 pub fn dev_mut<D: Ports + zerocopy::KnownLayout>(&mut self) -> &mut D {
541 self.dev_mut_at(D::BASE)
542 }
543
544 #[inline]
546 pub fn ram_read_byte(&self, addr: u16) -> u8 {
547 self.ram[usize::from(addr)]
548 }
549
550 #[inline]
552 pub fn ram_write_byte(&mut self, addr: u16, v: u8) {
553 self.ram[usize::from(addr)] = v;
554 }
555
556 #[inline]
558 pub fn stack(&self) -> &Stack {
559 &self.stack
560 }
561
562 #[inline]
564 pub fn stack_mut(&mut self) -> &mut Stack {
565 &mut self.stack
566 }
567
568 #[inline]
570 pub fn ret(&self) -> &Stack {
571 &self.ret
572 }
573
574 #[inline]
576 pub fn ret_mut(&mut self) -> &mut Stack {
577 &mut self.ret
578 }
579
580 #[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 #[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 #[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 #[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 #[inline]
889 pub fn brk(&mut self, _: u16) -> Option<u16> {
890 None
891 }
892
893 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 pub fn ram(&self) -> &[u8] {
1619 &self.ram[..]
1620 }
1621
1622 pub fn ram_mut(&mut self) -> &mut [u8] {
1624 &mut self.ram[..]
1625 }
1626}
1627
1628pub trait Device {
1630 fn dei(&mut self, vm: &mut Uxn, target: u8);
1635
1636 #[must_use]
1644 fn deo(&mut self, vm: &mut Uxn, target: u8) -> bool;
1645}
1646
1647pub trait Ports:
1649 zerocopy::IntoBytes + zerocopy::FromBytes + zerocopy::FromZeros + zerocopy::Immutable
1650{
1651 const BASE: u8;
1653}
1654
1655pub struct EmptyDevice;
1657impl Device for EmptyDevice {
1658 fn dei(&mut self, _vm: &mut Uxn, _target: u8) {
1659 }
1661 fn deo(&mut self, _vm: &mut Uxn, _target: u8) -> bool {
1662 true
1664 }
1665}
1666
1667#[cfg(feature = "alloc")]
1668mod ram {
1669 extern crate alloc;
1670 use alloc::{boxed::Box, vec};
1671
1672 pub struct UxnRam(Box<[u8; 65536]>);
1676
1677 impl UxnRam {
1678 pub fn new() -> Self {
1680 UxnRam(vec![0u8; 65536].into_boxed_slice().try_into().unwrap())
1681 }
1682
1683 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#[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 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 #[cfg(not(debug_assertions))]
2189 mod no_panic {
2190 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); }
2339}