start on ram hacking stuff

This commit is contained in:
Vivian Lim 2021-08-03 01:46:09 -07:00
parent 5842f5f430
commit a98a6eeb5e
7 changed files with 262 additions and 14 deletions

65
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,65 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'ferretro-dev-gui pokemon stadium'",
"cargo": {
"args": [
"build",
"--bin=ferretro-dev-gui",
"--package=ferretro-dev-gui"
],
"filter": {
"name": "ferretro-dev-gui",
"kind": "bin"
}
},
"args": ["--core", "/home/vivlim/.config/retroarch/cores/parallel_n64_libretro.so", "--rom", "/home/vivlim/games/roms/n64/Super Smash Bros. (U) [!].z64"],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'ferretro-dev-gui' pokeblue",
"cargo": {
"args": [
"build",
"--bin=ferretro-dev-gui",
"--package=ferretro-dev-gui"
],
"filter": {
"name": "ferretro-dev-gui",
"kind": "bin"
}
},
"args": ["--core", "/home/vivlim/.config/retroarch/cores/gambatte_libretro.so", "--rom", "/home/vivlim/games/roms/gbc/pokeblue.gb"],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in executable 'ferretro-dev-gui'",
"cargo": {
"args": [
"test",
"--no-run",
"--bin=ferretro-dev-gui",
"--package=ferretro-dev-gui"
],
"filter": {
"name": "ferretro-dev-gui",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
}
]
}

2
Cargo.lock generated
View File

@ -672,7 +672,7 @@ dependencies = [
[[package]]
name = "ferretro"
version = "0.1.0"
source = "git+ssh://git@vvn.space:2222/cinnabon/rustro.git?branch=viv/ffmpeg2#3cad3b1e29cfc76116399e3475113b59ee22e312"
source = "git+ssh://git@vvn.space:2222/cinnabon/rustro.git?branch=matriarch#d8d00386437960309d8fb21d4a107a65d42f942b"
dependencies = [
"cc",
"failure",

View File

@ -10,7 +10,7 @@ cc = "^1"
[dependencies]
crossbeam-channel = "^0.4"
structopt = "^0.3"
ferretro = { git = "ssh://git@vvn.space:2222/cinnabon/rustro.git", branch = "viv/ffmpeg2"}
ferretro = { git = "ssh://git@vvn.space:2222/cinnabon/rustro.git", branch = "matriarch" }
failure = "^0.1"
libloading = "^0.5"

View File

@ -19,7 +19,7 @@ use mini_gl_fb::glutin::platform::run_return::EventLoopExtRunReturn;
use failure::{Fallible};
use ferretro::retro;
use ferretro::retro::ffi::{GameGeometry, SystemInfo, SystemAvInfo};
use ferretro::retro::ffi::{GameGeometry, MemoryMap, SystemAvInfo, SystemInfo};
use ferretro::retro::constants::{InputIndex, JoypadButton, AnalogAxis, DeviceType};
use ferretro::retro::wrapped_types::{ControllerDescription2, InputDescriptor2, InputDeviceId, SubsystemInfo2, Variable2};
use ferretro::retro::wrapper::LibretroWrapper;
@ -40,7 +40,9 @@ use structopt::StructOpt;
use gilrs::{Button, GamepadId, Gilrs, Axis};
mod video;
mod memory;
use crate::video::video_buffer::{VideoBuffer, PixelFormat};
use crate::memory::libretro_memory_map::LibRetroMemoryMap;
struct MyEmulator {
pub retro: retro::wrapper::LibretroWrapper,
@ -60,6 +62,8 @@ struct MyEmulator {
video_buffer: Option<crate::video::video_buffer::VideoBuffer>,
pixel_format: Option<crate::video::video_buffer::PixelFormat>,
pub memory_map: Option<LibRetroMemoryMap>
}
impl MyEmulator {
@ -85,6 +89,10 @@ impl MyEmulator {
let mut gamepads = Gilrs::new().unwrap();
for (_id, gamepad) in gamepads.gamepads() {
println!("{} is {:?}", gamepad.name(), gamepad.power_info());
}
let emu = MyEmulator {
retro,
frame: 0,
@ -97,7 +105,8 @@ impl MyEmulator {
gamepads,
title,
video_buffer: None,
pixel_format: None
pixel_format: None,
memory_map: None,
};
let mut pin_emu = Box::pin(emu);
retro::wrapper::set_handler(pin_emu.as_mut());
@ -301,7 +310,8 @@ impl retro::wrapper::Handler for MyEmulator {
}
fn input_poll(&mut self) {
//self.gamepad_subsys.update();
// process events, but don't actually need the result. they'll be cached for when input_state reads them
while let Some(_) = self.gamepads.next_event() {}
}
fn input_state(&mut self, port: u32, device: InputDeviceId, index: InputIndex) -> i16 {
@ -315,9 +325,9 @@ impl retro::wrapper::Handler for MyEmulator {
}
}
InputDeviceId::Analog(axis) => {
let gilrs_axis = axis_map(index, axis);
let (gilrs_axis, scale) = axis_map(index, axis);
match gamepad.1.axis_data(gilrs_axis) {
Some(data) => data.value() as i16,
Some(data) => (data.value() * i16::max_value() as f32) as i16 * scale,
None => 0
}
},
@ -424,6 +434,11 @@ impl retro::wrapper::Handler for MyEmulator {
fn log_print(&mut self, level: retro::ffi::LogLevel, msg: &str) {
eprint!("[{:?}] {}", level, msg);
}
fn set_memory_maps(&mut self, ffi_memory_map: MemoryMap) -> bool {
self.memory_map = Some(LibRetroMemoryMap::create(&ffi_memory_map));
true
}
}
pub fn main() -> failure::Fallible<()> {
@ -484,15 +499,20 @@ fn button_map(retro_button: &JoypadButton) -> Option<Button> {
}
}
fn axis_map(index: InputIndex, axis: AnalogAxis) -> Axis {
fn axis_map(index: InputIndex, axis: AnalogAxis) -> (Axis, i16) {
match (index, axis) {
(InputIndex::Left, AnalogAxis::X) => Axis::LeftStickX,
(InputIndex::Left, AnalogAxis::Y) => Axis::LeftStickY,
(InputIndex::Right, AnalogAxis::X) => Axis::RightStickX,
(InputIndex::Right, AnalogAxis::Y) => Axis::RightStickY,
(InputIndex::Left, AnalogAxis::X) => (Axis::LeftStickX, 1),
(InputIndex::Left, AnalogAxis::Y) => (Axis::LeftStickY, -1),
(InputIndex::Right, AnalogAxis::X) => (Axis::RightStickX, 1),
(InputIndex::Right, AnalogAxis::Y) => (Axis::RightStickY, -1),
}
}
enum Flip {
Yes,
No,
}
fn build_savestate_filename(game_name: &PathBuf) -> PathBuf {
let mut index = 0;
@ -774,10 +794,11 @@ impl TrackedWindow for ConrodWindow {
}
Event::MainEventsCleared => {
let mut emu = self.emu.borrow_mut();
let memory = emu.retro.get_memory(2);
let mut ui = self.ui.set_widgets();
widget::Text::new(format!("frame {}", emu.frame).as_str())
.middle_of(ui.window)
widget::Text::new(format!("frame {}, memory size {:X} {:X}", emu.frame, memory.len(), memory.get(0xA4B3C).unwrap()).as_str())
.top_left_of(ui.window)
.color(conrod_core::color::WHITE)
.font_size(32)
.set(self.ids.text, &mut ui);
@ -787,6 +808,9 @@ impl TrackedWindow for ConrodWindow {
.set(self.ids.circle, &mut ui);
//widget::TextEdit::new(format!("{:X?}", memory[]))
self.display.gl_window().window().request_redraw();
}
Event::RedrawRequested(id) if self.matches_id(id) => {

View File

@ -0,0 +1,66 @@
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,
}

View File

@ -0,0 +1,91 @@
use crate::memory::libretro_memory_map::LibRetroMemoryMap;
pub struct MemorySliceHandle<'a> {
pub offset: usize,
pub length: usize,
pub bank_switch: usize,
pub slice: Option<&'a mut [u8]>,
pub last_read_value: Option<Vec<u8>>,
}
impl MemorySliceHandle<'_> {
pub fn create(offset: usize, length: usize, bank_switch: usize, memory_map: &LibRetroMemoryMap) -> Self {
let slice = memory_map.get_slice_from_region(offset, length, bank_switch);
MemorySliceHandle {
offset: offset,
length: length,
bank_switch: bank_switch,
slice,
last_read_value: None
}
}
pub fn write_to_slice(&mut self, data: Vec<u8>) -> Result<(), failure::Error> {
match &mut self.slice {
Some(slice) => {
if data.len() != slice.len() {
return Err(failure::err_msg("message size and slice size differ."));
}
// if last_read_value is set, update it as the same time that we write back to the emulator.
match &mut self.last_read_value {
None => {
let mut index: usize = 0;
for value in data.into_iter(){
slice[index] = value;
index += 1;
}
},
Some(last_read_value) => {
let mut index: usize = 0;
for value in data.into_iter(){
slice[index] = value;
last_read_value[index] = value;
index += 1;
}
}
}
Ok(())
},
None => {
println!("slice doesn't exist to write to.");
Ok(())
}
}
}
pub fn get_copy_if_changed_since_last_read(&mut self) -> Option<Vec<u8>> {
match &mut self.slice {
None => None,
Some(data) => match &mut self.last_read_value {
None => {
// last read value isn't allocated yet
let last = data.to_vec();
self.last_read_value = Some(last);
self.last_read_value.clone()
},
Some(last) => {
let mut index: usize = 0;
let mut any_changes = false;
for value in data.into_iter() {
if last[index] != *value {
last[index] = *value;
any_changes = true;
}
index += 1;
}
if any_changes {
return Some(last.clone());
}
None
}
}
}
}
}

2
src/memory/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod libretro_memory_map;
pub mod memory_slice_handle;