From f7cf960b62de9edaacc9078aa72db2fb55d93e89 Mon Sep 17 00:00:00 2001 From: Simon Gellis Date: Sat, 15 Feb 2025 16:14:03 -0500 Subject: [PATCH] Support hypothetical big-endian users --- src/memory.rs | 85 ++++++++++++++++++++++++++++++++++--- src/window/vram/bgmap.rs | 24 +++++------ src/window/vram/chardata.rs | 12 +++--- src/window/vram/object.rs | 8 ++-- src/window/vram/utils.rs | 4 +- 5 files changed, 100 insertions(+), 33 deletions(-) diff --git a/src/memory.rs b/src/memory.rs index 9b54c8a..769326f 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -39,11 +39,12 @@ impl MemoryClient { MemoryView { region } } - pub fn write(&self, sim: SimId, address: u32, data: &T) { - let data = bytemuck::bytes_of(data).to_vec(); + pub fn write(&self, sim: SimId, address: u32, data: &T) { + let mut buffer = vec![]; + data.to_bytes(&mut buffer); let (tx, _) = oneshot::channel(); self.client - .send_command(EmulatorCommand::WriteMemory(sim, address, data, tx)); + .send_command(EmulatorCommand::WriteMemory(sim, address, buffer, tx)); } } @@ -74,17 +75,87 @@ pub struct MemoryRef<'a> { inner: RwLockReadGuard<'a, BoxBytes>, } +pub trait MemoryValue { + fn from_bytes(bytes: &[u8]) -> Self; + fn to_bytes(&self, buffer: &mut Vec); +} + +macro_rules! primitive_memory_value_impl { + ($T:ty, $L: expr) => { + impl MemoryValue for $T { + #[inline] + fn from_bytes(bytes: &[u8]) -> Self { + let bytes: [u8; std::mem::size_of::<$T>()] = std::array::from_fn(|i| bytes[i]); + <$T>::from_le_bytes(bytes) + } + #[inline] + fn to_bytes(&self, buffer: &mut Vec) { + buffer.extend_from_slice(&self.to_le_bytes()) + } + } + }; +} + +primitive_memory_value_impl!(u8, 1); +primitive_memory_value_impl!(u16, 2); +primitive_memory_value_impl!(u32, 4); + +impl MemoryValue for [T; N] { + #[inline] + fn from_bytes(bytes: &[u8]) -> Self { + std::array::from_fn(|i| { + T::from_bytes(&bytes[i * std::mem::size_of::()..(i + 1) * std::mem::size_of::()]) + }) + } + #[inline] + fn to_bytes(&self, buffer: &mut Vec) { + for item in self { + item.to_bytes(buffer); + } + } +} + +pub struct MemoryIter<'a, T> { + bytes: &'a [u8], + index: usize, + _phantom: std::marker::PhantomData, +} + +impl<'a, T> MemoryIter<'a, T> { + fn new(bytes: &'a [u8]) -> Self { + Self { + bytes, + index: 0, + _phantom: std::marker::PhantomData, + } + } +} + +impl Iterator for MemoryIter<'_, T> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + if self.index >= self.bytes.len() { + return None; + } + let bytes = &self.bytes[self.index..self.index + std::mem::size_of::()]; + self.index += std::mem::size_of::(); + Some(T::from_bytes(bytes)) + } +} + impl MemoryRef<'_> { - pub fn read(&self, index: usize) -> T { + pub fn read(&self, index: usize) -> T { let from = index * size_of::(); let to = from + size_of::(); - *bytemuck::from_bytes(&self.inner[from..to]) + T::from_bytes(&self.inner[from..to]) } - pub fn range(&self, start: usize, count: usize) -> &[T] { + pub fn range(&self, start: usize, count: usize) -> MemoryIter { let from = start * size_of::(); let to = from + (count * size_of::()); - bytemuck::cast_slice(&self.inner[from..to]) + MemoryIter::new(&self.inner[from..to]) } } diff --git a/src/window/vram/bgmap.rs b/src/window/vram/bgmap.rs index 93bca1a..8760347 100644 --- a/src/window/vram/bgmap.rs +++ b/src/window/vram/bgmap.rs @@ -239,30 +239,26 @@ impl BgMapRenderer { let brightness = self.brightness.borrow(); let palettes = self.palettes.borrow(); - let brts = brightness.range::(0, 8); + let brts = brightness.read::<[u8; 8]>(0); let colors = if generic_palette { [utils::generic_palette(Color32::RED); 4] } else { - [0, 2, 4, 6].map(|i| utils::parse_palette(palettes.read(i), brts, Color32::RED)) + [0, 2, 4, 6].map(|i| utils::parse_palette(palettes.read(i), &brts, Color32::RED)) }; - for (i, cell) in bgmaps - .range::(bgmap_index * 4096, 4096) - .iter() - .enumerate() - { + for (i, cell) in bgmaps.range::(bgmap_index * 4096, 4096).enumerate() { let CellData { char_index, vflip, hflip, palette_index, - } = CellData::parse(*cell); - let char = chardata.range::(char_index * 8, 8); + } = CellData::parse(cell); + let char = chardata.read::<[u16; 8]>(char_index); let palette = &colors[palette_index]; for row in 0..8 { let y = row + (i / 64) * 8; - for (col, pixel) in utils::read_char_row(char, hflip, vflip, row).enumerate() { + for (col, pixel) in utils::read_char_row(&char, hflip, vflip, row).enumerate() { let x = col + (i % 64) * 8; image.write((x, y), palette[pixel as usize]); } @@ -276,7 +272,7 @@ impl BgMapRenderer { let brightness = self.brightness.borrow(); let palettes = self.palettes.borrow(); - let brts = brightness.range::(0, 8); + let brts = brightness.read::<[u8; 8]>(0); let cell = bgmaps.read::(index); @@ -286,15 +282,15 @@ impl BgMapRenderer { hflip, palette_index, } = CellData::parse(cell); - let char = chardata.range::(char_index * 8, 8); + let char = chardata.read::<[u16; 8]>(char_index); let palette = if generic_palette { utils::generic_palette(Color32::RED) } else { - utils::parse_palette(palettes.read(palette_index * 2), brts, Color32::RED) + utils::parse_palette(palettes.read(palette_index * 2), &brts, Color32::RED) }; for row in 0..8 { - for (col, pixel) in utils::read_char_row(char, hflip, vflip, row).enumerate() { + for (col, pixel) in utils::read_char_row(&char, hflip, vflip, row).enumerate() { image.write((col, row), palette[pixel as usize]); } } diff --git a/src/window/vram/chardata.rs b/src/window/vram/chardata.rs index dc102d3..1cde8d4 100644 --- a/src/window/vram/chardata.rs +++ b/src/window/vram/chardata.rs @@ -221,8 +221,8 @@ impl CharacterDataWindow { }; let palette = self.palettes.borrow().read(offset); let brightnesses = self.brightness.borrow(); - let brts = brightnesses.range(0, 8); - utils::parse_palette(palette, brts, Color32::RED) + let brts = brightnesses.read(0); + utils::parse_palette(palette, &brts, Color32::RED) } fn show_chardata(&mut self, ui: &mut Ui) { @@ -321,7 +321,7 @@ impl CharDataRenderer { let palette = self.load_palette(palette); let chardata = self.chardata.borrow(); let character = chardata.range::(index * 8, 8); - for (row, pixels) in character.iter().enumerate() { + for (row, pixels) in character.enumerate() { for col in 0..8 { let char = (pixels >> (col * 2)) & 0x03; image.write((col, row), palette[char as usize]); @@ -332,7 +332,7 @@ impl CharDataRenderer { fn render_character_data(&self, image: &mut VramImage, palette: VramPalette) { let palette = self.load_palette(palette); let chardata = self.chardata.borrow(); - for (row, pixels) in chardata.range::(0, 8 * 2048).iter().enumerate() { + for (row, pixels) in chardata.range::(0, 8 * 2048).enumerate() { let char_index = row / 8; let row_index = row % 8; let x = (char_index % 16) * 8; @@ -350,7 +350,7 @@ impl CharDataRenderer { }; let palette = self.palettes.borrow().read(offset); let brightnesses = self.brightness.borrow(); - let brts = brightnesses.range(0, 8); - utils::parse_palette(palette, brts, Color32::RED) + let brts = brightnesses.read(0); + utils::parse_palette(palette, &brts, Color32::RED) } } diff --git a/src/window/vram/object.rs b/src/window/vram/object.rs index 6313779..8c2aae3 100644 --- a/src/window/vram/object.rs +++ b/src/window/vram/object.rs @@ -282,7 +282,7 @@ impl ObjectRenderer { return; } - let brts = brightness.range::(0, 8); + let brts = brightness.read::<[u8; 8]>(0); let (x, y) = if use_pos { let x = match eye { Eye::Left => obj.x - obj.parallax, @@ -298,11 +298,11 @@ impl ObjectRenderer { Eye::Right => params.right_color, }; - let char = chardata.range::(obj.data.char_index * 8, 8); + let char = chardata.read::<[u16; 8]>(obj.data.char_index); let palette = if params.generic_palette { utils::generic_palette(color) } else { - utils::parse_palette(palettes.read(8 + obj.data.palette_index * 2), brts, color) + utils::parse_palette(palettes.read(8 + obj.data.palette_index * 2), &brts, color) }; for row in 0..8 { @@ -311,7 +311,7 @@ impl ObjectRenderer { continue; } for (col, pixel) in - utils::read_char_row(char, obj.data.hflip, obj.data.vflip, row).enumerate() + utils::read_char_row(&char, obj.data.hflip, obj.data.vflip, row).enumerate() { let real_x = x + col as i16; if !(0..384).contains(&real_x) { diff --git a/src/window/vram/utils.rs b/src/window/vram/utils.rs index 6b0b469..d95319c 100644 --- a/src/window/vram/utils.rs +++ b/src/window/vram/utils.rs @@ -10,7 +10,7 @@ pub fn generic_palette(color: Color32) -> [Color32; 4] { GENERIC_PALETTE.map(|brt| shade(brt, color)) } -pub fn parse_palette(palette: u8, brts: &[u8], color: Color32) -> [Color32; 4] { +pub fn parse_palette(palette: u8, brts: &[u8; 8], color: Color32) -> [Color32; 4] { let shades = [ Color32::BLACK, shade(brts[0], color), @@ -117,7 +117,7 @@ impl CellData { } pub fn read_char_row( - char: &[u16], + char: &[u16; 8], hflip: bool, vflip: bool, row: usize,