Skip to content

Commit

Permalink
unsafe ram sharing for libretro cheats
Browse files Browse the repository at this point in the history
  • Loading branch information
LLeny committed Oct 4, 2024
1 parent 5402814 commit 9f9a003
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 6 deletions.
10 changes: 10 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod rom;
pub mod suzy;
pub mod vectors;
pub mod consts;
mod shared_memory;

use bus::*;
use cartridge::*;
Expand All @@ -14,6 +15,7 @@ use log::trace;
use mikey::{video::{LYNX_SCREEN_HEIGHT, LYNX_SCREEN_WIDTH}, Mikey};
use ram::*;
use rom::Rom;
use shared_memory::SharedMemory;
use std::io::Error;
use suzy::{registers::{joystick_swap, Joystick, Switches}, Suzy};
use vectors::Vectors;
Expand Down Expand Up @@ -298,6 +300,14 @@ impl Lynx {
* 105. // 105 lines
)
}

pub fn ram_size(&self) -> usize {
RAM_MAX as usize
}

pub fn ram_data(&self) -> &SharedMemory {
self.ram.data()
}
}

impl Default for Lynx {
Expand Down
16 changes: 10 additions & 6 deletions src/ram.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
use log::trace;

use shared_memory::SharedMemory;
use crate::*;
use serde::{Serialize, Deserialize};
use super::bus::*;
use super::MMC_ADDR;

const RAM_MAX: u16 = 0xffff;
pub const RAM_MAX: u16 = 0xffff;


#[derive(Serialize, Deserialize)]
pub struct Ram {
data: Vec<u8>,
data: SharedMemory,
addr_r: u16,
data_r: u8,
ticks_to_done: i8,
Expand All @@ -20,7 +21,7 @@ pub struct Ram {
impl Ram {
pub fn new() -> Ram {
let mut r = Ram {
data: vec![0xFF; (RAM_MAX as usize) + 1],
data: SharedMemory::new((RAM_MAX as usize) + 1, 0xFF),
ticks_to_done: -1,
addr_r: 0,
data_r: 0,
Expand All @@ -45,8 +46,7 @@ impl Ram {

pub fn copy(&mut self, dest: u16, buf: &[u8]) {
assert!(dest as usize + buf.len() <= RAM_MAX as usize);
let d = dest as usize;
self.data[d..(d + buf.len())].copy_from_slice(buf);
self.data.copy(dest, buf);
}

pub fn peek(&mut self, bus: &Bus) {
Expand Down Expand Up @@ -102,6 +102,10 @@ impl Ram {
pub fn write(&self) -> bool {
self.write
}

pub fn data(&self) -> &SharedMemory {
&self.data
}
}

impl Default for Ram {
Expand Down
115 changes: 115 additions & 0 deletions src/shared_memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use std::cell::UnsafeCell;
use std::fmt;
use std::ops::{Index, IndexMut};
use serde::de::Visitor;
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

pub struct SharedMemory {
data: UnsafeCell<Vec<u8>>
}

// To share the RAM with Libretro, shouldn't have concurrent accesses
impl SharedMemory {
pub fn new(len: usize, fill_with: u8) -> Self {
Self {
data: UnsafeCell::new(vec![fill_with; len])
}
}

pub fn get_mut(&mut self) -> &mut Self {
self
}

pub fn fill(&mut self, v: u8) {
let ptr = self.data.get_mut();
(*ptr).fill(v);
}

pub fn copy(&mut self, dest: u16, buf: &[u8]) {
let d = dest as usize;
let ptr = self.data.get_mut();
(*ptr)[d..(d + buf.len())].copy_from_slice(buf);
}

// Libretro only
#[allow(clippy::mut_from_ref)]
pub unsafe fn as_mut_slice(&self) -> &mut [u8] {
let ptr = self.data.get();
unsafe { &mut (*ptr) }
}
}

impl Default for SharedMemory {
fn default() -> Self {
SharedMemory::new(0, 0xFF)
}
}

impl Index<usize> for SharedMemory {
type Output = u8;
fn index(&self, i: usize) -> &u8 {
let ptr = self.data.get();
unsafe { &(*ptr)[i] }
}
}

impl IndexMut<usize> for SharedMemory {
fn index_mut(&mut self, i: usize) -> &mut u8 {
let ptr = self.data.get_mut();
&mut (*ptr)[i]
}
}

impl Serialize for SharedMemory {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let ptr = self.data.get();
let mut seq = serializer.serialize_seq(Some(unsafe{(*ptr).len()}))?;
unsafe {
for e in (*ptr).iter() {
seq.serialize_element(&e)?;
}
}
seq.end()
}
}

struct SharedMemoryVisitor;

impl SharedMemoryVisitor {
fn new() -> Self {
Self {}
}
}

impl<'de> Visitor<'de> for SharedMemoryVisitor {
type Value = SharedMemory;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct SharedMemory")
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let mut mem = SharedMemory::default();
let ptr = mem.data.get_mut();
while let Some(value) = seq.next_element()? {
(*ptr).push(value);
}
Ok(mem)
}
}

impl<'de> Deserialize<'de> for SharedMemory {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_seq(SharedMemoryVisitor::new())
}
}

0 comments on commit 9f9a003

Please sign in to comment.