save state beginning work
This commit is contained in:
parent
962b2af282
commit
77838fec27
190
Cargo.lock
generated
190
Cargo.lock
generated
|
@ -140,6 +140,12 @@ dependencies = [
|
|||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "baseview"
|
||||
version = "0.1.0"
|
||||
|
@ -270,6 +276,19 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.6.0"
|
||||
|
@ -581,6 +600,50 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "d3d12"
|
||||
version = "0.5.0"
|
||||
|
@ -592,6 +655,41 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dasp_sample"
|
||||
version = "0.11.0"
|
||||
|
@ -790,6 +888,8 @@ dependencies = [
|
|||
"itertools",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_with",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -940,12 +1040,48 @@ version = "0.3.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hexf-parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys 0.8.3",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.2"
|
||||
|
@ -954,6 +1090,7 @@ checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
|||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1154,6 +1291,15 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.1.4"
|
||||
|
@ -1485,6 +1631,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
|
@ -1923,6 +2079,12 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
|
||||
|
||||
[[package]]
|
||||
name = "scroll"
|
||||
version = "0.11.0"
|
||||
|
@ -2008,6 +2170,34 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ea48c9627169d206b35905699f513f513c303ab9d964a59b44fdcf66c1d1ab7"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chrono",
|
||||
"hex",
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with_macros",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e6b7e52858f9f06c25e1c566bbb4ab428200cb3b30053ea09dc50837de7538b"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
|
|
|
@ -15,3 +15,5 @@ async-ringbuf = "0.1.2"
|
|||
futures = "0.3.26"
|
||||
once_cell = "1.17.1"
|
||||
itertools = "0.10.5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_with = "2.3.0"
|
||||
|
|
|
@ -5,7 +5,7 @@ use connect::{AudioOutput, EmulatorMessage, Renderer, RomFile};
|
|||
use once_cell::sync::OnceCell;
|
||||
use processor::{
|
||||
memory::{mmio::gpu::Colour, Rom},
|
||||
Cpu,
|
||||
Cpu, CpuSaveState,
|
||||
};
|
||||
use std::{
|
||||
fs::{self},
|
||||
|
@ -162,4 +162,8 @@ impl<ColourFormat: From<Colour> + Clone> EmulatorCore<ColourFormat> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_save_state(&self) -> CpuSaveState<ColourFormat> {
|
||||
CpuSaveState::create(&self.cpu)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
use self::mmio::{gpu::Colour, Apu, Gpu, Joypad, Serial, Timer};
|
||||
pub use self::rom::Rom;
|
||||
use self::{
|
||||
mmio::{
|
||||
apu::ApuSaveState,
|
||||
gpu::{Colour, GpuSaveState},
|
||||
Apu, Gpu, Joypad, Serial, Timer,
|
||||
},
|
||||
rom::RomSaveState,
|
||||
};
|
||||
use crate::{
|
||||
connect::{AudioOutput, JoypadState, Renderer},
|
||||
processor::SplitRegister,
|
||||
|
@ -8,6 +15,7 @@ use crate::{
|
|||
|
||||
mod interrupts;
|
||||
pub use interrupts::{Interrupt, Interrupts};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub mod mmio;
|
||||
pub(crate) mod rom;
|
||||
|
||||
|
@ -29,6 +37,44 @@ pub struct Memory<ColourFormat: From<Colour> + Clone> {
|
|||
timers: Timer,
|
||||
}
|
||||
|
||||
#[serde_with::serde_as]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct MemorySaveState<ColourFormat: From<Colour> + Clone> {
|
||||
rom: RomSaveState,
|
||||
#[serde_as(as = "[_; 8192]")]
|
||||
ram: [u8; 8192],
|
||||
#[serde_as(as = "[_; 128]")]
|
||||
cpu_ram: [u8; 128],
|
||||
pub(super) interrupts: Interrupts,
|
||||
pub(super) ime: bool,
|
||||
pub(super) ime_scheduled: u8,
|
||||
dma_addr: u8,
|
||||
joypad: Joypad,
|
||||
gpu: GpuSaveState<ColourFormat>,
|
||||
apu: ApuSaveState,
|
||||
serial: Serial,
|
||||
timers: Timer,
|
||||
}
|
||||
|
||||
impl<ColourFormat: From<Colour> + Clone> MemorySaveState<ColourFormat> {
|
||||
pub fn create(memory: &Memory<ColourFormat>) -> Self {
|
||||
Self {
|
||||
rom: RomSaveState::create(&memory.rom),
|
||||
ram: memory.ram,
|
||||
cpu_ram: memory.cpu_ram,
|
||||
interrupts: memory.interrupts,
|
||||
ime: memory.ime,
|
||||
ime_scheduled: memory.ime_scheduled,
|
||||
dma_addr: memory.dma_addr,
|
||||
joypad: memory.joypad,
|
||||
gpu: GpuSaveState::create(&memory.gpu),
|
||||
apu: ApuSaveState::create(&memory.apu),
|
||||
serial: memory.serial,
|
||||
timers: memory.timers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<ColourFormat: From<Colour> + Clone> Memory<ColourFormat> {
|
||||
pub fn init(
|
||||
bootrom: Option<Vec<u8>>,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::util::get_bit;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
|
||||
struct InterruptRegister {
|
||||
vblank: bool,
|
||||
lcd_stat: bool,
|
||||
|
@ -40,6 +42,7 @@ pub enum Interrupt {
|
|||
Joypad,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||
pub struct Interrupts {
|
||||
// 0xFFFF
|
||||
enable_register: InterruptRegister,
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::{
|
|||
};
|
||||
use futures::executor;
|
||||
use itertools::izip;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
mod channels;
|
||||
mod downsampler;
|
||||
|
@ -47,6 +48,31 @@ pub struct Apu {
|
|||
output: AudioOutput,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ApuSaveState {
|
||||
apu_enable: bool,
|
||||
channels: Channels,
|
||||
vin: VinEnable,
|
||||
mixer: Mixer,
|
||||
div_apu: u8,
|
||||
buffer: Vec<DacSample>,
|
||||
out_buffer: Vec<[f32; 2]>,
|
||||
}
|
||||
|
||||
impl ApuSaveState {
|
||||
pub fn create(apu: &Apu) -> Self {
|
||||
Self {
|
||||
apu_enable: apu.apu_enable,
|
||||
channels: apu.channels,
|
||||
vin: apu.vin,
|
||||
mixer: apu.mixer,
|
||||
div_apu: apu.div_apu,
|
||||
buffer: apu.buffer.clone(),
|
||||
out_buffer: apu.out_buffer.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const CYCLES_PER_FRAME: usize = 70224;
|
||||
|
||||
impl Apu {
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
processor::memory::Address,
|
||||
util::{get_bit, set_or_clear_bit, Nibbles},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub(super) enum EnvelopeMode {
|
||||
Increase,
|
||||
Decrease,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
struct Sweep {
|
||||
pace: u8,
|
||||
mode: EnvelopeMode,
|
||||
|
@ -27,7 +30,7 @@ impl Default for Sweep {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
struct Envelope {
|
||||
initial_volume: u8,
|
||||
current_volume: u8,
|
||||
|
@ -72,6 +75,7 @@ impl Default for Envelope {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
enum DutyCycle {
|
||||
// 0b00
|
||||
TwelvePointFive,
|
||||
|
@ -120,6 +124,7 @@ impl DutyCycle {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct PwmChannel {
|
||||
pub(super) enabled: bool,
|
||||
sweep: Sweep,
|
||||
|
@ -297,7 +302,7 @@ impl PwmChannel {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
|
||||
enum ShiftVolumePercent {
|
||||
Zero,
|
||||
TwentyFive,
|
||||
|
@ -316,6 +321,7 @@ impl ShiftVolumePercent {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct WaveRam {
|
||||
pub(super) data: [u8; 16],
|
||||
}
|
||||
|
@ -330,6 +336,7 @@ impl WaveRam {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct WaveChannel {
|
||||
pub(super) enabled: bool,
|
||||
dac_enabled: bool,
|
||||
|
@ -471,12 +478,13 @@ impl WaveChannel {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, Serialize, Deserialize, Clone, Copy)]
|
||||
enum LfsrWidth {
|
||||
FifteenBit,
|
||||
SevenBit,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
struct Lfsr {
|
||||
clock_shift: u8,
|
||||
width: LfsrWidth,
|
||||
|
@ -534,6 +542,7 @@ impl Default for Lfsr {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct NoiseChannel {
|
||||
pub(super) enabled: bool,
|
||||
length_enable: bool,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::channels::{NoiseChannel, PwmChannel, WaveChannel};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct Channels {
|
||||
pub(super) one: PwmChannel,
|
||||
pub(super) two: PwmChannel,
|
||||
|
@ -18,12 +21,13 @@ impl Default for Channels {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct VinEnable {
|
||||
pub(super) left: bool,
|
||||
pub(super) right: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) enum Volume {
|
||||
Muted,
|
||||
Enabled,
|
||||
|
@ -53,6 +57,7 @@ impl Volume {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct ChannelVol {
|
||||
pub(super) left: Volume,
|
||||
pub(super) right: Volume,
|
||||
|
@ -67,6 +72,7 @@ impl Default for ChannelVol {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct Mixer {
|
||||
pub(super) vol_left: u8,
|
||||
pub(super) vol_right: u8,
|
||||
|
@ -89,7 +95,7 @@ impl Default for Mixer {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
pub(super) struct DacSample {
|
||||
pub(super) one: f32,
|
||||
pub(super) two: f32,
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
|||
util::{clear_bit, get_bit},
|
||||
HEIGHT, WIDTH,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use types::Colour;
|
||||
|
||||
mod addresses;
|
||||
|
@ -44,6 +45,55 @@ pub struct Gpu<Format: From<Colour>> {
|
|||
prev_stat: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct GpuSaveState<Format: From<Colour>> {
|
||||
buffer: Vec<Format>,
|
||||
vram: Vram,
|
||||
oam: Oam,
|
||||
is_bg_zero: Vec<bool>,
|
||||
lcdc: Lcdc,
|
||||
stat: Stat,
|
||||
mode_clock: usize,
|
||||
scanline: u8,
|
||||
lyc: u8,
|
||||
window_lc: u8,
|
||||
has_window_been_enabled: bool,
|
||||
bg_palette: Palette,
|
||||
obj_palette_0: Palette,
|
||||
obj_palette_1: Palette,
|
||||
scx: u8,
|
||||
scy: u8,
|
||||
wx: u8,
|
||||
wy: u8,
|
||||
prev_stat: bool,
|
||||
}
|
||||
|
||||
impl<Format: From<Colour> + Clone> GpuSaveState<Format> {
|
||||
pub fn create(gpu: &Gpu<Format>) -> Self {
|
||||
Self {
|
||||
buffer: gpu.buffer.clone(),
|
||||
vram: gpu.vram,
|
||||
oam: gpu.oam,
|
||||
is_bg_zero: gpu.is_bg_zero.clone(),
|
||||
lcdc: gpu.lcdc,
|
||||
stat: gpu.stat,
|
||||
mode_clock: gpu.mode_clock,
|
||||
scanline: gpu.scanline,
|
||||
lyc: gpu.lyc,
|
||||
window_lc: gpu.window_lc,
|
||||
has_window_been_enabled: gpu.has_window_been_enabled,
|
||||
bg_palette: gpu.bg_palette,
|
||||
obj_palette_0: gpu.obj_palette_0,
|
||||
obj_palette_1: gpu.obj_palette_1,
|
||||
scx: gpu.scx,
|
||||
scy: gpu.scy,
|
||||
wx: gpu.wx,
|
||||
wy: gpu.wy,
|
||||
prev_stat: gpu.prev_stat,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Format: From<Colour> + Clone> Gpu<Format> {
|
||||
pub fn new(
|
||||
window: Box<dyn Renderer<Format>>,
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
processor::memory::Address,
|
||||
util::{as_signed, get_bit},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
pub(super) enum DrawMode {
|
||||
HBlank,
|
||||
VBlank,
|
||||
|
@ -11,7 +13,7 @@ pub(super) enum DrawMode {
|
|||
Mode3,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
pub(super) enum TilemapArea {
|
||||
T9800,
|
||||
T9C00,
|
||||
|
@ -26,7 +28,7 @@ impl TilemapArea {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
pub(super) enum TiledataArea {
|
||||
D8000,
|
||||
D9000,
|
||||
|
@ -41,7 +43,7 @@ impl TiledataArea {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
pub(super) enum ObjSize {
|
||||
S8x8,
|
||||
S8x16,
|
||||
|
@ -56,7 +58,7 @@ impl ObjSize {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
pub(super) struct Lcdc {
|
||||
pub(super) enable: bool,
|
||||
pub(super) window_tilemap: TilemapArea,
|
||||
|
@ -83,7 +85,7 @@ impl Default for Lcdc {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Colour {
|
||||
White,
|
||||
LightGray,
|
||||
|
@ -138,7 +140,7 @@ impl Colour {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub(super) struct Palette {
|
||||
pub(super) zero: Colour,
|
||||
pub(super) one: Colour,
|
||||
|
@ -193,6 +195,7 @@ pub(super) struct Object {
|
|||
pub(super) oam_location: u8,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub(super) struct Stat {
|
||||
pub(super) lyc_eq_ly_interrupt_enabled: bool,
|
||||
pub(super) mode_2_interrupt_enabled: bool,
|
||||
|
@ -213,7 +216,10 @@ impl Default for Stat {
|
|||
}
|
||||
}
|
||||
|
||||
#[serde_with::serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub struct Vram {
|
||||
#[serde_as(as = "[_; 8192]")]
|
||||
data: [u8; 8192],
|
||||
}
|
||||
|
||||
|
@ -233,7 +239,10 @@ impl Default for Vram {
|
|||
}
|
||||
}
|
||||
|
||||
#[serde_with::serde_as]
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub struct Oam {
|
||||
#[serde_as(as = "[_; 160]")]
|
||||
pub data: [u8; 160],
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::util::{clear_bit, get_bit};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Joypad {
|
||||
sel_action: bool,
|
||||
sel_direction: bool,
|
||||
#[serde(skip)]
|
||||
state: JoypadState,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
mod apu;
|
||||
pub(crate) mod apu;
|
||||
pub(crate) mod gpu;
|
||||
pub(crate) mod joypad;
|
||||
mod serial;
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
use std::io::{stdout, Write};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::util::get_bit;
|
||||
|
||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||
enum ClockSource {
|
||||
Internal,
|
||||
External,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||
enum ClockSpeed {
|
||||
Normal,
|
||||
Fast,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||
struct SerialControl {
|
||||
transfer_in_progress: bool,
|
||||
clock_speed: ClockSpeed,
|
||||
|
@ -30,6 +35,7 @@ impl Default for SerialControl {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||
pub struct Serial {
|
||||
byte: u8,
|
||||
output_byte: u8,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::util::{get_bit, set_or_clear_bit};
|
||||
|
||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||
enum TimerRate {
|
||||
Sixteen,
|
||||
SixtyFour,
|
||||
|
@ -36,6 +39,7 @@ impl TimerRate {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||
struct TimerControl {
|
||||
enable: bool,
|
||||
rate: TimerRate,
|
||||
|
@ -56,6 +60,7 @@ pub struct TimerReturn {
|
|||
pub timer_interrupt: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||
pub struct Timer {
|
||||
// 0xFF04
|
||||
div: u8,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::processor::memory::Address;
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
|
@ -6,13 +8,17 @@ use std::{
|
|||
str::from_utf8_unchecked,
|
||||
};
|
||||
|
||||
use self::mbcs::{Mbc, Mbc1, Mbc2, Mbc3, Mbc5, None};
|
||||
use self::mbcs::{
|
||||
Mbc, Mbc1, Mbc1SaveState, Mbc2, Mbc2SaveState, Mbc3, Mbc3SaveState, Mbc5, Mbc5SaveState, None,
|
||||
};
|
||||
|
||||
mod mbcs;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct MaybeBufferedSram {
|
||||
buf: Vec<u8>,
|
||||
length: usize,
|
||||
#[serde(skip)]
|
||||
inner: Option<File>,
|
||||
unbuffered_writes: usize,
|
||||
}
|
||||
|
@ -97,6 +103,30 @@ pub struct Rom {
|
|||
mbc: Box<dyn Mbc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct RomSaveState {
|
||||
title: String,
|
||||
mbc: MbcSaveState,
|
||||
}
|
||||
|
||||
impl RomSaveState {
|
||||
pub fn create(rom: &Rom) -> Self {
|
||||
Self {
|
||||
title: rom.title.clone(),
|
||||
mbc: rom.mbc.get_savestate(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
enum MbcSaveState {
|
||||
Mbc1(Mbc1SaveState),
|
||||
Mbc2(Mbc2SaveState),
|
||||
Mbc3(Mbc3SaveState),
|
||||
Mbc5(Mbc5SaveState),
|
||||
None,
|
||||
}
|
||||
|
||||
impl Rom {
|
||||
pub fn load(data: Vec<u8>, save_path: Option<PathBuf>) -> Self {
|
||||
let mut title_length = 0x143;
|
||||
|
|
|
@ -5,12 +5,14 @@ mod mbc2;
|
|||
mod mbc3;
|
||||
mod mbc5;
|
||||
mod none;
|
||||
pub use mbc1::Mbc1;
|
||||
pub use mbc2::Mbc2;
|
||||
pub use mbc3::Mbc3;
|
||||
pub use mbc5::Mbc5;
|
||||
pub use mbc1::{Mbc1, Mbc1SaveState};
|
||||
pub use mbc2::{Mbc2, Mbc2SaveState};
|
||||
pub use mbc3::{Mbc3, Mbc3SaveState};
|
||||
pub use mbc5::{Mbc5, Mbc5SaveState};
|
||||
pub use none::None;
|
||||
|
||||
use super::MbcSaveState;
|
||||
|
||||
pub(super) const KB: usize = 1024;
|
||||
const ROM_BANK_SIZE: usize = 16 * KB;
|
||||
const RAM_BANK_SIZE: usize = 8 * KB;
|
||||
|
@ -23,6 +25,7 @@ pub(super) trait Mbc: Send {
|
|||
fn set(&mut self, address: Address, data: u8);
|
||||
fn set_ram(&mut self, address: Address, data: u8);
|
||||
fn mbc_type(&self) -> String;
|
||||
fn get_savestate(&self) -> MbcSaveState;
|
||||
fn is_rumbling(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use crate::processor::memory::{rom::MaybeBufferedSram, Address};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use crate::processor::memory::{
|
||||
rom::{MaybeBufferedSram, MbcSaveState},
|
||||
Address,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
enum BankingMode {
|
||||
Simple,
|
||||
Advanced,
|
||||
|
@ -20,6 +25,17 @@ pub struct Mbc1 {
|
|||
bank_mode: BankingMode,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Mbc1SaveState {
|
||||
rom_len: usize,
|
||||
rom_bank: u8,
|
||||
ram_enabled: bool,
|
||||
ram: Option<Vec<u8>>,
|
||||
ram_bank: u8,
|
||||
upper_banks: u8,
|
||||
bank_mode: BankingMode,
|
||||
}
|
||||
|
||||
impl Mbc1 {
|
||||
pub fn init(data: Vec<u8>, rom_size: u8, ram_size: u8, save_file: Option<PathBuf>) -> Self {
|
||||
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
||||
|
@ -102,6 +118,18 @@ impl Mbc for Mbc1 {
|
|||
ram.flush();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_savestate(&self) -> MbcSaveState {
|
||||
MbcSaveState::Mbc1(Mbc1SaveState {
|
||||
rom_len: self.rom_len,
|
||||
rom_bank: self.rom_bank,
|
||||
ram_enabled: self.ram_enabled,
|
||||
ram: self.ram.as_ref().map(|v| v.buf.clone()),
|
||||
ram_bank: self.ram_bank,
|
||||
upper_banks: self.upper_banks,
|
||||
bank_mode: self.bank_mode,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Mbc1 {
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use crate::processor::memory::{rom::MaybeBufferedSram, Address};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::processor::memory::{
|
||||
rom::{MaybeBufferedSram, MbcSaveState},
|
||||
Address,
|
||||
};
|
||||
|
||||
use super::{rom_banks, Mbc, ROM_BANK_SIZE};
|
||||
|
||||
|
@ -12,6 +17,14 @@ pub struct Mbc2 {
|
|||
ram_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Mbc2SaveState {
|
||||
rom_len: usize,
|
||||
rom_bank: u8,
|
||||
ram: Vec<u8>,
|
||||
ram_enabled: bool,
|
||||
}
|
||||
|
||||
impl Mbc2 {
|
||||
pub fn init(data: Vec<u8>, rom_size: u8, save_file: Option<PathBuf>) -> Self {
|
||||
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
||||
|
@ -75,4 +88,13 @@ impl Mbc for Mbc2 {
|
|||
fn flush(&mut self) {
|
||||
self.ram.flush();
|
||||
}
|
||||
|
||||
fn get_savestate(&self) -> MbcSaveState {
|
||||
MbcSaveState::Mbc2(Mbc2SaveState {
|
||||
rom_len: self.rom_len,
|
||||
rom_bank: self.rom_bank,
|
||||
ram: self.ram.buf.clone(),
|
||||
ram_enabled: self.ram_enabled,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use crate::{
|
||||
processor::memory::{rom::MaybeBufferedSram, Address},
|
||||
processor::memory::{
|
||||
rom::{MaybeBufferedSram, MbcSaveState},
|
||||
Address,
|
||||
},
|
||||
util::set_or_clear_bit,
|
||||
};
|
||||
use std::{
|
||||
|
@ -8,7 +13,7 @@ use std::{
|
|||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
||||
enum RtcRegister {
|
||||
Seconds,
|
||||
Minutes,
|
||||
|
@ -17,6 +22,7 @@ enum RtcRegister {
|
|||
Misc,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
enum RamBank {
|
||||
Ram(u8),
|
||||
Rtc(RtcRegister),
|
||||
|
@ -117,6 +123,17 @@ pub struct Mbc3 {
|
|||
ram_size: usize,
|
||||
ram_enabled: bool,
|
||||
rtc: Option<Rtc>,
|
||||
// TODO - save/load rtc!!
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Mbc3SaveState {
|
||||
rom_bank: u8,
|
||||
rom_size: usize,
|
||||
ram: Option<Vec<u8>>,
|
||||
ram_bank: RamBank,
|
||||
ram_size: usize,
|
||||
ram_enabled: bool,
|
||||
}
|
||||
|
||||
impl Mbc3 {
|
||||
|
@ -257,4 +274,15 @@ impl Mbc for Mbc3 {
|
|||
ram.flush();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_savestate(&self) -> MbcSaveState {
|
||||
MbcSaveState::Mbc3(Mbc3SaveState {
|
||||
rom_bank: self.rom_bank,
|
||||
rom_size: self.rom_size,
|
||||
ram: self.ram.as_ref().map(|v| v.buf.clone()),
|
||||
ram_bank: self.ram_bank,
|
||||
ram_size: self.ram_size,
|
||||
ram_enabled: self.ram_enabled,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
processor::memory::{rom::MaybeBufferedSram, Address},
|
||||
processor::memory::{
|
||||
rom::{MaybeBufferedSram, MbcSaveState},
|
||||
Address,
|
||||
},
|
||||
util::get_bit,
|
||||
};
|
||||
|
||||
|
@ -19,6 +24,18 @@ pub struct Mbc5 {
|
|||
is_rumbling: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Mbc5SaveState {
|
||||
rom_bank: u16,
|
||||
rom_size: usize,
|
||||
ram: Option<Vec<u8>>,
|
||||
ram_bank: u8,
|
||||
ram_size: usize,
|
||||
ram_enabled: bool,
|
||||
rumble: bool,
|
||||
is_rumbling: bool,
|
||||
}
|
||||
|
||||
impl Mbc5 {
|
||||
pub fn init(
|
||||
data: Vec<u8>,
|
||||
|
@ -127,4 +144,17 @@ impl Mbc for Mbc5 {
|
|||
ram.flush();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_savestate(&self) -> MbcSaveState {
|
||||
MbcSaveState::Mbc5(Mbc5SaveState {
|
||||
rom_bank: self.rom_bank,
|
||||
rom_size: self.rom_size,
|
||||
ram: self.ram.as_ref().map(|v| v.buf.clone()),
|
||||
ram_bank: self.ram_bank,
|
||||
ram_size: self.ram_size,
|
||||
ram_enabled: self.ram_enabled,
|
||||
rumble: self.rumble,
|
||||
is_rumbling: self.is_rumbling,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::Mbc;
|
||||
use crate::processor::memory::Address;
|
||||
use crate::processor::memory::{rom::MbcSaveState, Address};
|
||||
|
||||
pub struct None {
|
||||
data: Vec<u8>,
|
||||
|
@ -27,4 +27,8 @@ impl Mbc for None {
|
|||
fn mbc_type(&self) -> String {
|
||||
String::from("None")
|
||||
}
|
||||
|
||||
fn get_savestate(&self) -> MbcSaveState {
|
||||
MbcSaveState::None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use self::memory::{mmio::gpu::Colour, Interrupt, Memory};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use self::memory::{mmio::gpu::Colour, Interrupt, Memory, MemorySaveState};
|
||||
use crate::verbose_println;
|
||||
|
||||
mod instructions;
|
||||
|
@ -27,6 +29,29 @@ pub struct Cpu<ColourFormat: From<Colour> + Clone> {
|
|||
should_halt_bug: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CpuSaveState<ColourFormat: From<Colour> + Clone> {
|
||||
memory: MemorySaveState<ColourFormat>,
|
||||
reg: Registers,
|
||||
last_instruction: u8,
|
||||
last_instruction_addr: u16,
|
||||
halted: bool,
|
||||
should_halt_bug: bool,
|
||||
}
|
||||
|
||||
impl<ColourFormat: From<Colour> + Clone> CpuSaveState<ColourFormat> {
|
||||
pub fn create(cpu: &Cpu<ColourFormat>) -> Self {
|
||||
Self {
|
||||
memory: MemorySaveState::create(&cpu.memory),
|
||||
reg: cpu.reg,
|
||||
last_instruction: cpu.last_instruction,
|
||||
last_instruction_addr: cpu.last_instruction_addr,
|
||||
halted: cpu.halted,
|
||||
should_halt_bug: cpu.should_halt_bug,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> {
|
||||
pub fn new(mut memory: Memory<ColourFormat>, run_bootrom: bool) -> Self {
|
||||
if !run_bootrom {
|
||||
|
@ -138,7 +163,7 @@ pub enum Reg8 {
|
|||
L,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct Registers {
|
||||
pub af: u16,
|
||||
pub bc: u16,
|
||||
|
|
Loading…
Reference in a new issue