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}