use std::{ collections::HashMap, sync::{Arc, Mutex, MutexGuard}, }; use bytemuck::BoxBytes; use crate::emulator::{EmulatorClient, EmulatorCommand, SimId}; pub struct MemoryMonitor { client: EmulatorClient, regions: HashMap>>, } impl MemoryMonitor { pub fn new(client: EmulatorClient) -> Self { Self { client, regions: HashMap::new(), } } pub fn view(&mut self, sim: SimId, start: u32, length: usize) -> MemoryView { let region = MemoryRegion { sim, start, length }; let memory = self.regions.entry(region).or_insert_with(|| { let mut buf = aligned_memory(start, length); let (tx, rx) = oneshot::channel(); self.client .send_command(EmulatorCommand::ReadMemory(sim, start, length, vec![], tx)); let bytes = pollster::block_on(rx).unwrap(); buf.copy_from_slice(&bytes); #[expect(clippy::arc_with_non_send_sync)] // TODO: remove after bytemuck upgrade Arc::new(Mutex::new(buf)) }); MemoryView { memory: memory.clone(), } } } fn aligned_memory(start: u32, length: usize) -> BoxBytes { if start % 4 == 0 && length % 4 == 0 { let memory = vec![0u32; length / 4].into_boxed_slice(); return bytemuck::box_bytes_of(memory); } if start % 2 == 0 && length % 2 == 0 { let memory = vec![0u16; length / 2].into_boxed_slice(); return bytemuck::box_bytes_of(memory); } let memory = vec![0u8; length].into_boxed_slice(); bytemuck::box_bytes_of(memory) } pub struct MemoryView { memory: Arc>, } // SAFETY: BoxBytes is supposed to be Send+Sync, will be in a new version unsafe impl Send for MemoryView {} impl MemoryView { pub fn borrow(&self) -> MemoryRef<'_> { MemoryRef { inner: self.memory.lock().unwrap(), } } } pub struct MemoryRef<'a> { inner: MutexGuard<'a, BoxBytes>, } impl MemoryRef<'_> { pub fn read(&self, index: usize) -> T { let from = index * size_of::(); let to = from + size_of::(); *bytemuck::from_bytes(&self.inner[from..to]) } pub fn range(&self, start: usize, count: usize) -> &[T] { let from = start * size_of::(); let to = from + (count * size_of::()); bytemuck::cast_slice(&self.inner[from..to]) } } #[derive(Clone, Copy, PartialEq, Eq, Hash)] struct MemoryRegion { sim: SimId, start: u32, length: usize, }