ferretro-synced/src/emulator/libretro_memory_map.rs

66 lines
2.4 KiB
Rust

use std::convert::TryFrom;
use ferretro::retro::ffi::{MemoryMap};
pub struct LibRetroMemoryMap {
regions: Vec<LibRetroMemoryRegion>,
}
impl LibRetroMemoryMap {
pub fn get_slice_from_region(&self, offset: usize, length: usize, bank_switch: usize) -> Option<&'static mut [u8]> {
match self.find_bank(offset, length, bank_switch) {
Some(ptr) => Some(unsafe { std::slice::from_raw_parts_mut(ptr as *mut u8, length) }),
None => None
}
}
fn find_bank(&self, offset: usize, length: usize, bank_switch: usize) -> Option<*const std::ffi::c_void> {
if self.regions.len() == 0 {
return None;
}
for item in self.regions.iter() {
if (item.start <= offset) && (offset < item.end) {
if offset + length > item.end {
println!("({:x}, {:x}) overruns ({:x}, {:x}) memory bank.", offset, length, item.start, item.end);
return None;
}
let bank_size = item.end - item.start;
let relative_offset = isize::try_from(offset - item.start + (bank_size * bank_switch)).unwrap();
return unsafe { Some(item.pointer.offset(relative_offset)) }
}
}
println!("({:x}, {:x}) address range not found in any memory map region.", offset, length);
None
}
pub fn create(memory_map: &MemoryMap) -> Self {
let mut regions: Vec<LibRetroMemoryRegion> = Vec::new();
let num_descriptors = isize::try_from(memory_map.num_descriptors).unwrap();
for i in 0..num_descriptors {
let region = unsafe { &*memory_map.descriptors.offset(i) };
let mut length = region.len;
if region.select > 0 { // FIXME: hack for oversized SRAM eating addr space
length = (!region.select + 1) & 0xffffffff;
println!("truncating memory region {:x} from size {:x} to {:x} banks of size {:x}", region.start, region.len, region.len/length, length)
}
regions.push(LibRetroMemoryRegion {
start: region.start,
end: region.start + length,
pointer: region.ptr,
})
}
LibRetroMemoryMap {
regions: regions
}
}
}
struct LibRetroMemoryRegion {
start: usize,
end: usize,
pointer: *const std::ffi::c_void,
}