Skip to content

Commit

Permalink
first version of save and reload
Browse files Browse the repository at this point in the history
  • Loading branch information
xxrlzzz committed Mar 11, 2022
1 parent 3640888 commit e3e9b08
Show file tree
Hide file tree
Showing 22 changed files with 488 additions and 119 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
/assets

/target

Cargo.lock
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "3.0.0-rc.7", features = ["derive"] }
log = { version = "0.4", features = ["std"] }
lazy_static = "*"
serde = { version = "1.0", features = ["derive"] }
serde_bytes = "0.11.5"
serde_json = "1.0.59"
sfml = "0.16.0"
ini = "1.3.0"
queues = "1.0.2"
portaudio = "*"
clap = { version = "3.0.0-rc.7", features = ["derive"] }
portaudio = "*"
35 changes: 32 additions & 3 deletions src/apu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ pub mod sound_filter;
pub mod sound_wave;

use log::{info, warn};
use serde::{Deserialize, Serialize};

use crate::common::{
bit_eq,
types::{Address, Byte},
use crate::{
bus::main_bus::{IORegister, RegisterHandler, APU_ADDR, JOY2},
common::{
bit_eq,
types::{Address, Byte},
},
};

use self::{
Expand Down Expand Up @@ -34,11 +38,13 @@ lazy_static! {
/**
* Reference https://www.nesdev.org/apu_ref.txt
*/
#[derive(Serialize, Deserialize)]
pub struct Apu {
cycle: u64,
frame_period: Byte,
frame_value: Byte,
frame_irq: bool,
#[serde(skip)]
player: PortAudioPlayer,
sample_rate: f64,

Expand Down Expand Up @@ -263,3 +269,26 @@ impl Apu {
}
}
}

impl RegisterHandler for Apu {
fn read(&mut self, address: IORegister) -> Option<Byte> {
match address {
APU_ADDR => Some(self.read_status()),
_ => None,
}
}

fn write(&mut self, address: IORegister, value: Byte) -> bool {
match address as Address {
0x4000..=0x4013 | JOY2 | APU_ADDR => {
self.write_register(address, value);
true
}
_ => false,
}
}

fn dma(&mut self, _: *const Byte) -> bool {
false
}
}
4 changes: 4 additions & 0 deletions src/apu/portaudio_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use portaudio::{

use std::sync::mpsc;

#[derive(Default)]
pub struct PortAudioPlayer {
stream: Option<Stream<NonBlocking, Output<f32>>>,
sender: Option<mpsc::Sender<f32>>,
Expand Down Expand Up @@ -67,6 +68,9 @@ impl PortAudioPlayer {
pub fn start(&mut self) -> Result<(), Error> {
if let Some(ref mut stream) = self.stream {
stream.start()?
} else {
self.init()?;
self.start()?;
}
Ok(())
}
Expand Down
5 changes: 5 additions & 0 deletions src/apu/sound_filter.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::f32::consts::PI;

use serde::{Deserialize, Serialize};

pub trait Filter {
fn step(&mut self, x: f32) -> f32;
}

#[derive(Serialize, Deserialize)]
pub(crate) struct SoundFilter {
b0: f32,
b1: f32,
Expand Down Expand Up @@ -50,6 +54,7 @@ impl Filter for SoundFilter {
y
}
}

pub(crate) type SoundFilterChain = Vec<SoundFilter>;

impl Filter for SoundFilterChain {
Expand Down
7 changes: 7 additions & 0 deletions src/apu/sound_wave.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use serde::{Deserialize, Serialize};

use crate::common::{
bit_eq,
types::{Address, Byte},
Expand Down Expand Up @@ -28,6 +30,7 @@ const DMC_TABLE: [Byte; 16] = [
214, 190, 170, 160, 143, 127, 113, 107, 95, 80, 71, 64, 53, 42, 36, 27,
];

#[derive(Serialize, Deserialize)]
struct Envelope {
enabled: bool,
length_enabled: bool,
Expand Down Expand Up @@ -120,6 +123,7 @@ impl Envelope {
}
}

#[derive(Serialize, Deserialize)]
pub(crate) struct Pulse {
channel: Byte,
sweep_reload: bool,
Expand Down Expand Up @@ -241,6 +245,7 @@ impl Pulse {
}
}

#[derive(Serialize, Deserialize)]
pub(crate) struct Noise {
timer_period: Address,
timer_value: Address,
Expand Down Expand Up @@ -310,6 +315,7 @@ impl Noise {
}
}

#[derive(Serialize, Deserialize)]
pub(crate) struct Triangle {
enabled: bool,
length_enabled: bool,
Expand Down Expand Up @@ -402,6 +408,7 @@ impl Triangle {
}
}

#[derive(Serialize, Deserialize)]
pub(crate) struct DMC {
enabled: bool,
value: Byte,
Expand Down
95 changes: 72 additions & 23 deletions src/bus/main_bus.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
use log::{error, warn};
use log::{error, info, warn};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use sfml::window::Key;
use std::cell::RefCell;
use std::rc::Rc;

use crate::apu::Apu;
use crate::common::types::*;
use crate::controller::Controller;
use crate::mapper::factory::load_mapper;
use crate::mapper::Mapper;
use crate::ppu::Ppu;

type IORegister = u16;
pub type IORegister = u16;

pub const PPU_CTRL: IORegister = 0x2000;
pub const PPU_MASK: IORegister = 0x2001;
Expand All @@ -24,13 +27,23 @@ pub const APU_ADDR: IORegister = 0x4015;
pub const JOY1: IORegister = 0x4016;
pub const JOY2: IORegister = 0x4017;

pub trait RegisterHandler {
fn read(&mut self, address: IORegister) -> Option<Byte>;
fn write(&mut self, address: IORegister, value: Byte) -> bool;
fn dma(&mut self, page: *const Byte) -> bool;
}

#[derive(Default, Serialize, Deserialize)]
pub struct MainBus {
ram: Vec<Byte>,
ext_ram: Vec<Byte>,
#[serde(skip)]
mapper: Option<Rc<RefCell<dyn Mapper>>>,
ppu: Rc<RefCell<Ppu>>,
apu: Rc<RefCell<Apu>>,
#[serde(skip)]
registers: Vec<Rc<RefCell<dyn RegisterHandler>>>,
#[serde(skip)]
control1: Controller,
#[serde(skip)]
control2: Controller,

skip_dma_cycles: bool,
Expand All @@ -42,22 +55,57 @@ impl MainBus {
ram: vec![0; 0x800],
ext_ram: vec![],
mapper: None,
ppu,
apu,
registers: vec![ppu, apu],
control1: Controller::new(),
control2: Controller::new(),

skip_dma_cycles: false,
}
}

pub fn save(&self) -> Value {
json!({
"ram": serde_json::to_string(&self.ram).unwrap(),
"ext_ram":serde_json::to_string(&self.ext_ram).unwrap(),
"mapper" : self.mapper.as_ref().map(|m| m.borrow().save()).unwrap_or(String::new()),
"skip_dma_cycles": self.skip_dma_cycles,
"mapper_type": self.mapper.as_ref().unwrap().borrow().mapper_type(),
})
}

pub fn load(
json: &serde_json::Value,
ppu: Rc<RefCell<Ppu>>,
apu: Rc<RefCell<Apu>>,
ctl1: Controller,
ctl2: Controller,
) -> Self {
let mapper_type = json.get("mapper_type").unwrap().as_u64().unwrap();
let mapper_content = json.get("mapper").unwrap().as_str().unwrap();
let mapper = load_mapper(mapper_type as Byte, mapper_content);
ppu.borrow_mut().set_mapper_for_bus(mapper.clone());
Self {
ram: serde_json::from_str(json.get("ram").unwrap().as_str().unwrap()).unwrap(),
ext_ram: serde_json::from_str(json.get("ext_ram").unwrap().as_str().unwrap()).unwrap(),
mapper: Some(mapper),
registers: vec![ppu, apu],
control1: ctl1,
control2: ctl2,
skip_dma_cycles: json.get("skip_dma_cycles").unwrap().as_bool().unwrap(),
}
}

pub fn set_mapper(&mut self, mapper: Rc<RefCell<dyn Mapper>>) {
self.mapper = Some(mapper);
if self.mapper.as_ref().unwrap().borrow().has_extended_ram() {
self.ext_ram.resize(0x2000, 0);
}
}

pub fn control(&self) -> (Controller, Controller) {
(self.control1.clone(), self.control2.clone())
}

pub fn set_controller_keys(&mut self, p1: Vec<Key>, p2: Vec<Key>) {
self.control1.set_key_bindings(p1);
self.control2.set_key_bindings(p2);
Expand All @@ -80,13 +128,6 @@ impl MainBus {
addr
};
match mapped_addr {
PPU_CTRL => self.ppu.borrow_mut().control(value),
PPU_MASK => self.ppu.borrow_mut().set_mask(value),
PPU_ADDR => self.ppu.borrow_mut().set_data_address(value as Address),
OAM_ADDR => self.ppu.borrow_mut().set_oam_address(value),
PPU_SCROL => self.ppu.borrow_mut().set_scroll(value),
PPU_DATA => self.ppu.borrow_mut().set_data(value),
OAM_DATA => self.ppu.borrow_mut().set_oam_data(value),
JOY1 => {
self.control1.strobe(value);
self.control2.strobe(value);
Expand All @@ -96,15 +137,22 @@ impl MainBus {
unsafe {
let ptr = self.get_page_ptr(value);
if let Some(ptr) = ptr {
self.ppu.borrow_mut().do_dma(ptr);
for reg in &mut self.registers {
if reg.borrow_mut().dma(ptr) {
break;
}
}
}
}
}
0x4000..=0x4013 | JOY2 | APU_ADDR => {
self.apu.borrow_mut().write_register(mapped_addr, value)
_ => {
for reg in &mut self.registers {
if reg.borrow_mut().write(mapped_addr, value) {
break;
}
}
}
_ => {}
};
}
} else if addr < 0x6000 {
warn!("Expansion ROM write attempted. This currently unsupported");
} else if addr < 0x8000 {
Expand Down Expand Up @@ -133,15 +181,16 @@ impl MainBus {
addr
};
return match mapped_addr {
PPU_STATUS => self.ppu.borrow_mut().get_status(),
PPU_DATA => self.ppu.borrow_mut().get_data(),
OAM_ADDR => self.ppu.borrow().get_oam_data(),
APU_ADDR => self.apu.borrow().read_status(),
JOY1 => self.control1.read(),
JOY2 => self.control2.read(),
_ => {
for reg in &mut self.registers {
if let Some(value) = reg.borrow_mut().read(mapped_addr) {
return value;
}
}
warn!("Attempt to read at {:#x} without callback registered", addr);
0
return 0;
}
};
}
Expand Down
1 change: 1 addition & 0 deletions src/bus/message_bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub enum Message {
PpuRender(Vec<Vec<Color>>),
}

#[derive(Default)]
pub struct MessageBus {
queue: Queue<Message>,
}
Expand Down
3 changes: 3 additions & 0 deletions src/bus/picture_bus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use log::info;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::rc::Rc;
use std::vec::Vec;
Expand All @@ -14,6 +15,7 @@ mod name_table_mirroring {
pub const ONE_SCREEN_HIGHER: u8 = 10;
}

#[derive(Serialize, Deserialize)]
pub struct PictureBus {
ram: Vec<Byte>,
// Indices where they start in RAM vector.
Expand All @@ -22,6 +24,7 @@ pub struct PictureBus {
name_table2: usize,
name_table3: usize,
palette: Vec<Byte>,
#[serde(skip)]
mapper: Option<Rc<RefCell<dyn Mapper>>>,
}

Expand Down
3 changes: 3 additions & 0 deletions src/cartridge.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use crate::common::bit_eq;
use crate::common::types::*;
use log::{error, info};
use serde::Deserialize;
use serde::Serialize;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::vec::Vec;

pub static BANK_SIZE: usize = 0x4000;

#[derive(Serialize, Deserialize)]
pub struct Cartridge {
prg_rom: Vec<Byte>,
chr_rom: Vec<Byte>,
Expand Down
1 change: 1 addition & 0 deletions src/controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod key_binding_parser;

use key_binding_parser::TOTAL_BUTTONS;

#[derive(Default, Clone)]
pub struct Controller {
enable_strobe: bool,
key_states: u8,
Expand Down
Loading

0 comments on commit e3e9b08

Please sign in to comment.