monistode_emulator/
stack.rs1use num_traits::{WrappingAdd, WrappingSub};
2
3use super::memory::{DoublablePrecision, TwoByteMemory};
4use std::{
5 marker::PhantomData,
6 ops::{Index, IndexMut},
7};
8
9pub trait Stack<T> {
13 fn push(&mut self, value: T);
14 fn pop(&mut self) -> T;
15 fn peek(&self) -> T;
16 fn peek_down_by(&self, n: u8) -> T;
17}
18
19pub struct TwoByteStack<'a, T: 'a, U, V>
20where
21 T: IndexMut<V>,
22 U: Into<V>,
23 T::Output: DoublablePrecision + Sized,
24{
25 data: TwoByteMemory<'a, T, U, V>,
26 pointer: &'a mut U,
27 downward: bool,
28 index: PhantomData<V>,
29}
30
31impl<'a, T, U, V> TwoByteStack<'a, T, U, V>
32where
33 T: IndexMut<V>,
34 U: Into<V> + From<u8> + WrappingAdd<Output = U> + WrappingSub<Output = U> + Copy,
35 T::Output: DoublablePrecision + Sized + Copy,
36{
37 #[inline]
38 pub fn new(data: &'a mut T, pointer: &'a mut U, downward: bool) -> Self {
39 TwoByteStack {
40 data: TwoByteMemory::new(data),
41 pointer,
42 downward,
43 index: PhantomData,
44 }
45 }
46}
47
48impl<'a, T: 'a, U, V> Stack<<<T as Index<V>>::Output as DoublablePrecision>::DoublePrecision>
49 for TwoByteStack<'a, T, U, V>
50where
51 T: IndexMut<V>,
52 U: Into<V> + From<u8> + WrappingAdd<Output = U> + WrappingSub<Output = U> + Copy,
53 T::Output: DoublablePrecision + Sized + Copy,
54{
55 #[inline]
56 fn push(&mut self, value: <T::Output as DoublablePrecision>::DoublePrecision) {
57 if self.downward {
58 *self.pointer = (*self.pointer).wrapping_sub(&U::from(2));
59 } else {
60 *self.pointer = (*self.pointer).wrapping_add(&U::from(2));
61 }
62 self.data.write(*self.pointer, value);
63 }
64
65 #[inline]
66 fn pop(&mut self) -> <T::Output as DoublablePrecision>::DoublePrecision {
67 let result = self.data.read(*self.pointer);
68 if self.downward {
69 *self.pointer = (*self.pointer).wrapping_add(&U::from(2));
70 } else {
71 *self.pointer = (*self.pointer).wrapping_sub(&U::from(2));
72 }
73 result
74 }
75
76 #[inline]
77 fn peek(&self) -> <T::Output as DoublablePrecision>::DoublePrecision {
78 self.data.read(*self.pointer)
79 }
80
81 #[inline]
82 fn peek_down_by(&self, offset: u8) -> <T::Output as DoublablePrecision>::DoublePrecision {
83 let mut pointer = *self.pointer;
84 if self.downward {
85 pointer = pointer.wrapping_add(&U::from(offset));
86 } else {
87 pointer = pointer.wrapping_sub(&U::from(offset));
88 }
89 self.data.read(pointer)
90 }
91}
92
93macro_rules! two_byte_stack {
94 ($name:ident[$register:ident: $indextype:ty] -> $itemtype:ty, based on $memory:ident) => {
97 #[inline]
98 pub fn $name(&mut self) -> TwoByteStack<'_, Memory<$itemtype>, $indextype, usize> {
99 TwoByteStack::new(&mut self.$memory, &mut self.registers.$register, false)
100 }
101 };
102 ($name:ident[$register:ident: $indextype:ty] -> $itemtype:ty, based on $memory:ident, growing downward) => {
103 #[inline]
104 pub fn $name(&mut self) -> TwoByteStack<'_, Memory<$itemtype>, $indextype, usize> {
105 TwoByteStack::new(&mut self.$memory, &mut self.registers.$register, true)
106 }
107 };
108}
109
110pub(crate) use two_byte_stack;