Support hypothetical big-endian users

This commit is contained in:
2025-02-15 18:33:18 -05:00
parent b888d1140a
commit f7cf960b62
5 changed files with 100 additions and 33 deletions
+78 -7
View File
@@ -39,11 +39,12 @@ impl MemoryClient {
MemoryView { region }
}
pub fn write<T: bytemuck::NoUninit>(&self, sim: SimId, address: u32, data: &T) {
let data = bytemuck::bytes_of(data).to_vec();
pub fn write<T: MemoryValue>(&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<u8>);
}
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<u8>) {
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<const N: usize, T: MemoryValue> 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::<T>()..(i + 1) * std::mem::size_of::<T>()])
})
}
#[inline]
fn to_bytes(&self, buffer: &mut Vec<u8>) {
for item in self {
item.to_bytes(buffer);
}
}
}
pub struct MemoryIter<'a, T> {
bytes: &'a [u8],
index: usize,
_phantom: std::marker::PhantomData<T>,
}
impl<'a, T> MemoryIter<'a, T> {
fn new(bytes: &'a [u8]) -> Self {
Self {
bytes,
index: 0,
_phantom: std::marker::PhantomData,
}
}
}
impl<T: MemoryValue> Iterator for MemoryIter<'_, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.bytes.len() {
return None;
}
let bytes = &self.bytes[self.index..self.index + std::mem::size_of::<T>()];
self.index += std::mem::size_of::<T>();
Some(T::from_bytes(bytes))
}
}
impl MemoryRef<'_> {
pub fn read<T: bytemuck::AnyBitPattern>(&self, index: usize) -> T {
pub fn read<T: MemoryValue>(&self, index: usize) -> T {
let from = index * size_of::<T>();
let to = from + size_of::<T>();
*bytemuck::from_bytes(&self.inner[from..to])
T::from_bytes(&self.inner[from..to])
}
pub fn range<T: bytemuck::AnyBitPattern>(&self, start: usize, count: usize) -> &[T] {
pub fn range<T: MemoryValue>(&self, start: usize, count: usize) -> MemoryIter<T> {
let from = start * size_of::<T>();
let to = from + (count * size_of::<T>());
bytemuck::cast_slice(&self.inner[from..to])
MemoryIter::new(&self.inner[from..to])
}
}