metaemu_machine/
types.rs

1use fugue::ir::{AddressSpace, AddressValue, IntoAddress};
2use fugue::ir::il::Location;
3use fugue::ir::il::pcode::{PCode, PCodeOp};
4
5use std::sync::Arc;
6
7#[derive(Debug, Clone)]
8#[derive(serde::Deserialize, serde::Serialize)]
9pub enum Bound<A: IntoAddress> {
10    Address(A),
11    Steps(usize),
12    AddressOrSteps(A, usize),
13    AddressReachCountOrSteps(A, usize, usize),
14    Unbounded,
15}
16
17impl<A> Bound<A> where A: IntoAddress {
18    pub fn address(address: A) -> Bound<A> {
19        Self::Address(address)
20    }
21    pub fn address_or_steps(address: A, steps: usize) -> Bound<A> {
22        Self::AddressOrSteps(address, steps)
23    }
24    pub fn address_reach_count_or_steps(address: A, addr_reach_count: usize, steps: usize) -> Bound<A> {
25        Self::AddressReachCountOrSteps(address, addr_reach_count, steps)
26    }
27
28    pub fn in_space(self, space: &AddressSpace) -> Bound<AddressValue> {
29        match self {
30            Self::Address(address) => Bound::Address(address.into_address_value(&*space)),
31            Self::Steps(steps) => Bound::Steps(steps),
32            Self::AddressOrSteps(address, steps) => Bound::AddressOrSteps(address.into_address_value(&*space), steps),
33            Self::AddressReachCountOrSteps(address, address_reach_count, steps) => {
34                Bound::AddressReachCountOrSteps(address.into_address_value(&*space), address_reach_count, steps)
35            }
36            Self::Unbounded => Bound::Unbounded,
37        }
38    }
39}
40
41impl Bound<AddressValue> {
42    pub fn steps(steps: usize) -> Bound<AddressValue> {
43        Self::Steps(steps)
44    }
45
46    pub fn unbounded() -> Bound<AddressValue> {
47        Self::Unbounded
48    }
49
50    // Decrease step count
51    // Used for counting down from the specified step count
52    pub fn deplete(self, address: &AddressValue) -> Self {
53        match self {
54            Self::Steps(steps) => Self::Steps(steps.checked_sub(1).unwrap_or(0)),
55            Self::AddressOrSteps(address, steps) => Self::AddressOrSteps(address, steps.checked_sub(1).unwrap_or(0)),
56            Self::AddressReachCountOrSteps(address_target, addr_reach_count, steps) => {
57                let addr_reach_count_new = if *address == address_target {
58                    addr_reach_count.checked_sub(1).unwrap_or(0)
59                } else {
60                    addr_reach_count
61                };
62                Self::AddressReachCountOrSteps(
63                    address_target, 
64                    addr_reach_count_new, 
65                    steps.checked_sub(1).unwrap_or(0)
66                )
67            }
68            _ => self,
69        }
70        // if let Self::Steps(steps) = self {
71        //     Self::Steps(steps.checked_sub(1).unwrap_or(0))
72        // } else if let Self::AddressOrSteps(address, steps ) = self {
73        //     Self::AddressOrSteps(address, ()steps.checked_sub(1).unwrap_or(0))
74        // }{
75        //     self
76        // }
77    }
78
79    pub fn reached(&self, address: &AddressValue) -> bool {
80        match self {
81            Self::Address(ref target) => target == address,
82            Self::Steps(steps) => *steps == 0,
83            Self::AddressOrSteps(ref target, steps) => target == address || *steps == 0,
84            Self::AddressReachCountOrSteps(ref _target, addr_reach_count, steps) => {
85                *addr_reach_count == 0 || *steps == 0
86            }
87            Self::Unbounded => false,
88        }
89    }
90}
91
92#[derive(Debug, Clone)]
93#[derive(serde::Deserialize, serde::Serialize)]
94pub enum Branch {
95    Next,
96    Local(isize),
97    Global(AddressValue),
98}
99
100#[derive(Debug, Clone)]
101#[derive(serde::Deserialize, serde::Serialize)]
102pub enum Outcome<R> {
103    Halt(R),
104    Branch(Branch),
105}
106
107#[derive(Debug, Clone)]
108#[derive(serde::Deserialize, serde::Serialize)]
109pub enum OrOutcome<S, R> {
110    Halt(R),
111    Branch(Location),
112    Continue(S),
113}
114
115impl<T, R> From<T> for OrOutcome<T, R> {
116    fn from(t: T) -> Self {
117        Self::Continue(t)
118    }
119}
120
121#[derive(Debug, Clone)]
122#[derive(serde::Deserialize, serde::Serialize)]
123pub enum StepOutcome<R> {
124    Halt(R),
125    Reached,
126    Branch(AddressValue),
127}
128
129#[derive(Debug, Clone)]
130#[derive(serde::Deserialize, serde::Serialize)]
131pub enum BranchOutcome {
132    Local,
133    Global(AddressValue),
134}
135
136#[derive(Debug, Clone)]
137#[derive(serde::Deserialize, serde::Serialize)]
138pub struct StepState {
139    pcode: Arc<PCode>,
140    position: usize,
141}
142
143impl From<PCode> for StepState {
144    fn from(pcode: PCode) -> Self {
145        Self {
146            pcode: Arc::new(pcode),
147            position: 0,
148        }
149    }
150}
151
152impl StepState {
153    #[inline(always)]
154    pub fn address(&self) -> AddressValue {
155        self.pcode.address()
156    }
157
158    pub fn location(&self) -> Location {
159        Location::new(self.pcode.address(), self.position)
160    }
161
162    pub fn operations(&self) -> &PCode {
163        &*self.pcode
164    }
165
166    pub fn with_location(self, location: &Location) -> Self {
167        assert_eq!(self.pcode.address, *location.address());
168        Self { position: location.position(), ..self }
169    }
170
171    #[inline(always)]
172    pub fn current(&self) -> Option<&PCodeOp> {
173        self.pcode.operations().get(self.position)
174    }
175
176    pub fn fallthrough(&self) -> AddressValue {
177        self.address() + self.pcode.length()
178    }
179
180    pub fn branch(&mut self, action: &Branch) -> BranchOutcome {
181        match action {
182            Branch::Next => {
183                self.position += 1;
184            },
185            Branch::Local(offset) => {
186                if offset.is_negative() {
187                    let abs = offset.wrapping_abs() as usize;
188                    if abs <= self.position {
189                        self.position -= abs;
190                    } else {
191                        panic!("negative local branch out of range")
192                    }
193                } else {
194                    self.position += *offset as usize;
195                }
196            },
197            Branch::Global(address) => {
198                return BranchOutcome::Global(address.clone())
199            }
200        }
201
202        if self.position < self.pcode.operations.len() {
203            BranchOutcome::Local
204        } else {
205            BranchOutcome::Global(self.fallthrough())
206        }
207    }
208
209    pub fn branch_location(&self, action: Branch) -> Location {
210        match action {
211            Branch::Next => {
212                if self.position + 1 < self.pcode.operations.len() {
213                    Location::new(self.address(), self.position + 1)
214                } else {
215                    Location::from(self.fallthrough())
216                }
217            },
218            Branch::Local(offset) => {
219                let npos = if offset.is_negative() {
220                    let abs = offset.wrapping_abs() as usize;
221                    if abs <= self.position {
222                        self.position - abs
223                    } else {
224                        panic!("negative local branch out of range")
225                    }
226                } else {
227                    self.position + offset as usize
228                };
229
230                if npos < self.pcode.operations.len() {
231                    Location::new(self.address(), npos)
232                } else {
233                    Location::from(self.fallthrough())
234                }
235            },
236            Branch::Global(address) => {
237                Location::from(address)
238            }
239        }
240    }
241}