debug.rsannotateddebug.rssource156 lines · 3.4 KB · raw
1use crate::num::{GetBit, U16Ext};
2
3#[allow(clippy::len_without_is_empty)]
4pub trait DebugMemoryView {
5    fn len(&self) -> usize;
6
7    fn read(&self, address: usize) -> u8;
8
9    fn write(&mut self, address: usize, value: u8);
10}
11
12pub struct DebugBytesView<'a>(pub &'a mut [u8]);
13
14impl DebugMemoryView for DebugBytesView<'_> {
15    fn len(&self) -> usize {
16        self.0.len()
17    }
18
19    fn read(&self, address: usize) -> u8 {
20        self.0.get(address).copied().unwrap_or(0)
21    }
22
23    fn write(&mut self, address: usize, value: u8) {
24        if address >= self.len() {
25            return;
26        }
27
28        self.0[address] = value;
29    }
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum Endian {
34    Little,
35    Big,
36}
37
38pub struct DebugWordsView<'a>(pub &'a mut [u16], pub Endian);
39
40impl DebugMemoryView for DebugWordsView<'_> {
41    fn len(&self) -> usize {
42        2 * self.0.len()
43    }
44
45    fn read(&self, mut address: usize) -> u8 {
46        if address >= self.len() {
47            return 0;
48        }
49
50        if self.1 == Endian::Little {
51            address ^= 1;
52        }
53
54        let word = self.0[address >> 1];
55        word.to_be_bytes()[address & 1]
56    }
57
58    fn write(&mut self, mut address: usize, value: u8) {
59        if address >= self.len() {
60            return;
61        }
62
63        if self.1 == Endian::Little {
64            address ^= 1;
65        }
66
67        let word_addr = address >> 1;
68        let word = &mut self.0[word_addr];
69        if !address.bit(0) {
70            word.set_msb(value);
71        } else {
72            word.set_lsb(value);
73        }
74    }
75}
76
77pub struct DebugLongwordsView<'a>(pub &'a mut [u32], pub Endian);
78
79impl DebugMemoryView for DebugLongwordsView<'_> {
80    fn len(&self) -> usize {
81        4 * self.0.len()
82    }
83
84    fn read(&self, mut address: usize) -> u8 {
85        if address >= self.len() {
86            return 0;
87        }
88
89        if self.1 == Endian::Little {
90            address ^= 3;
91        }
92
93        let longword_addr = address >> 2;
94        let longword_addr = self.0[longword_addr];
95        longword_addr.to_be_bytes()[address & 3]
96    }
97
98    fn write(&mut self, mut address: usize, value: u8) {
99        if address >= self.len() {
100            return;
101        }
102
103        if self.1 == Endian::Little {
104            address ^= 3;
105        }
106
107        let longword_addr = address >> 2;
108        let mut longword_bytes = self.0[longword_addr].to_be_bytes();
109        longword_bytes[address & 3] = value;
110        self.0[longword_addr] = u32::from_be_bytes(longword_bytes);
111    }
112}
113
114pub struct DebugViewWithWriteHook<'a> {
115    wrapped: Box<dyn DebugMemoryView + 'a>,
116    write_hook: Box<dyn FnMut(usize, u8) + 'a>,
117}
118
119impl<'a> DebugViewWithWriteHook<'a> {
120    #[must_use]
121    pub fn new(
122        wrapped: Box<dyn DebugMemoryView + 'a>,
123        write_hook: Box<dyn FnMut(usize, u8) + 'a>,
124    ) -> Self {
125        Self { wrapped, write_hook }
126    }
127}
128
129impl DebugMemoryView for DebugViewWithWriteHook<'_> {
130    fn len(&self) -> usize {
131        self.wrapped.len()
132    }
133
134    fn read(&self, address: usize) -> u8 {
135        self.wrapped.read(address)
136    }
137
138    fn write(&mut self, address: usize, value: u8) {
139        self.wrapped.write(address, value);
140        (self.write_hook)(address, value);
141    }
142}
143
144pub struct EmptyDebugView;
145
146impl DebugMemoryView for EmptyDebugView {
147    fn len(&self) -> usize {
148        0
149    }
150
151    fn read(&self, _address: usize) -> u8 {
152        0
153    }
154
155    fn write(&mut self, _address: usize, _value: u8) {}
156}