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",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "baseview"
|
name = "baseview"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -270,6 +276,19 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
|
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]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
@ -581,6 +600,50 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
|
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]]
|
[[package]]
|
||||||
name = "d3d12"
|
name = "d3d12"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -592,6 +655,41 @@ dependencies = [
|
||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "dasp_sample"
|
name = "dasp_sample"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -790,6 +888,8 @@ dependencies = [
|
||||||
"itertools",
|
"itertools",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rand",
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"serde_with",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -940,12 +1040,48 @@ version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hexf-parse"
|
name = "hexf-parse"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
|
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]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.2"
|
version = "1.9.2"
|
||||||
|
@ -954,6 +1090,7 @@ checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1154,6 +1291,15 @@ dependencies = [
|
||||||
"pkg-config",
|
"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]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
|
@ -1485,6 +1631,16 @@ dependencies = [
|
||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.15"
|
version = "0.2.15"
|
||||||
|
@ -1923,6 +2079,12 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scratch"
|
||||||
|
version = "1.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scroll"
|
name = "scroll"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -2008,6 +2170,34 @@ dependencies = [
|
||||||
"serde",
|
"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]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|
|
@ -15,3 +15,5 @@ async-ringbuf = "0.1.2"
|
||||||
futures = "0.3.26"
|
futures = "0.3.26"
|
||||||
once_cell = "1.17.1"
|
once_cell = "1.17.1"
|
||||||
itertools = "0.10.5"
|
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 once_cell::sync::OnceCell;
|
||||||
use processor::{
|
use processor::{
|
||||||
memory::{mmio::gpu::Colour, Rom},
|
memory::{mmio::gpu::Colour, Rom},
|
||||||
Cpu,
|
Cpu, CpuSaveState,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{self},
|
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;
|
pub use self::rom::Rom;
|
||||||
|
use self::{
|
||||||
|
mmio::{
|
||||||
|
apu::ApuSaveState,
|
||||||
|
gpu::{Colour, GpuSaveState},
|
||||||
|
Apu, Gpu, Joypad, Serial, Timer,
|
||||||
|
},
|
||||||
|
rom::RomSaveState,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::{AudioOutput, JoypadState, Renderer},
|
connect::{AudioOutput, JoypadState, Renderer},
|
||||||
processor::SplitRegister,
|
processor::SplitRegister,
|
||||||
|
@ -8,6 +15,7 @@ use crate::{
|
||||||
|
|
||||||
mod interrupts;
|
mod interrupts;
|
||||||
pub use interrupts::{Interrupt, Interrupts};
|
pub use interrupts::{Interrupt, Interrupts};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
pub mod mmio;
|
pub mod mmio;
|
||||||
pub(crate) mod rom;
|
pub(crate) mod rom;
|
||||||
|
|
||||||
|
@ -29,6 +37,44 @@ pub struct Memory<ColourFormat: From<Colour> + Clone> {
|
||||||
timers: Timer,
|
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> {
|
impl<ColourFormat: From<Colour> + Clone> Memory<ColourFormat> {
|
||||||
pub fn init(
|
pub fn init(
|
||||||
bootrom: Option<Vec<u8>>,
|
bootrom: Option<Vec<u8>>,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::util::get_bit;
|
use crate::util::get_bit;
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
|
||||||
struct InterruptRegister {
|
struct InterruptRegister {
|
||||||
vblank: bool,
|
vblank: bool,
|
||||||
lcd_stat: bool,
|
lcd_stat: bool,
|
||||||
|
@ -40,6 +42,7 @@ pub enum Interrupt {
|
||||||
Joypad,
|
Joypad,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
pub struct Interrupts {
|
pub struct Interrupts {
|
||||||
// 0xFFFF
|
// 0xFFFF
|
||||||
enable_register: InterruptRegister,
|
enable_register: InterruptRegister,
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use futures::executor;
|
use futures::executor;
|
||||||
use itertools::izip;
|
use itertools::izip;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
mod channels;
|
mod channels;
|
||||||
mod downsampler;
|
mod downsampler;
|
||||||
|
@ -47,6 +48,31 @@ pub struct Apu {
|
||||||
output: AudioOutput,
|
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;
|
const CYCLES_PER_FRAME: usize = 70224;
|
||||||
|
|
||||||
impl Apu {
|
impl Apu {
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::memory::Address,
|
processor::memory::Address,
|
||||||
util::{get_bit, set_or_clear_bit, Nibbles},
|
util::{get_bit, set_or_clear_bit, Nibbles},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub(super) enum EnvelopeMode {
|
pub(super) enum EnvelopeMode {
|
||||||
Increase,
|
Increase,
|
||||||
Decrease,
|
Decrease,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
struct Sweep {
|
struct Sweep {
|
||||||
pace: u8,
|
pace: u8,
|
||||||
mode: EnvelopeMode,
|
mode: EnvelopeMode,
|
||||||
|
@ -27,7 +30,7 @@ impl Default for Sweep {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
struct Envelope {
|
struct Envelope {
|
||||||
initial_volume: u8,
|
initial_volume: u8,
|
||||||
current_volume: u8,
|
current_volume: u8,
|
||||||
|
@ -72,6 +75,7 @@ impl Default for Envelope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
enum DutyCycle {
|
enum DutyCycle {
|
||||||
// 0b00
|
// 0b00
|
||||||
TwelvePointFive,
|
TwelvePointFive,
|
||||||
|
@ -120,6 +124,7 @@ impl DutyCycle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct PwmChannel {
|
pub(super) struct PwmChannel {
|
||||||
pub(super) enabled: bool,
|
pub(super) enabled: bool,
|
||||||
sweep: Sweep,
|
sweep: Sweep,
|
||||||
|
@ -297,7 +302,7 @@ impl PwmChannel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Copy)]
|
||||||
enum ShiftVolumePercent {
|
enum ShiftVolumePercent {
|
||||||
Zero,
|
Zero,
|
||||||
TwentyFive,
|
TwentyFive,
|
||||||
|
@ -316,6 +321,7 @@ impl ShiftVolumePercent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct WaveRam {
|
pub(super) struct WaveRam {
|
||||||
pub(super) data: [u8; 16],
|
pub(super) data: [u8; 16],
|
||||||
}
|
}
|
||||||
|
@ -330,6 +336,7 @@ impl WaveRam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct WaveChannel {
|
pub(super) struct WaveChannel {
|
||||||
pub(super) enabled: bool,
|
pub(super) enabled: bool,
|
||||||
dac_enabled: bool,
|
dac_enabled: bool,
|
||||||
|
@ -471,12 +478,13 @@ impl WaveChannel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, Serialize, Deserialize, Clone, Copy)]
|
||||||
enum LfsrWidth {
|
enum LfsrWidth {
|
||||||
FifteenBit,
|
FifteenBit,
|
||||||
SevenBit,
|
SevenBit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
struct Lfsr {
|
struct Lfsr {
|
||||||
clock_shift: u8,
|
clock_shift: u8,
|
||||||
width: LfsrWidth,
|
width: LfsrWidth,
|
||||||
|
@ -534,6 +542,7 @@ impl Default for Lfsr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct NoiseChannel {
|
pub(super) struct NoiseChannel {
|
||||||
pub(super) enabled: bool,
|
pub(super) enabled: bool,
|
||||||
length_enable: bool,
|
length_enable: bool,
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::channels::{NoiseChannel, PwmChannel, WaveChannel};
|
use super::channels::{NoiseChannel, PwmChannel, WaveChannel};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct Channels {
|
pub(super) struct Channels {
|
||||||
pub(super) one: PwmChannel,
|
pub(super) one: PwmChannel,
|
||||||
pub(super) two: 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) struct VinEnable {
|
||||||
pub(super) left: bool,
|
pub(super) left: bool,
|
||||||
pub(super) right: bool,
|
pub(super) right: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) enum Volume {
|
pub(super) enum Volume {
|
||||||
Muted,
|
Muted,
|
||||||
Enabled,
|
Enabled,
|
||||||
|
@ -53,6 +57,7 @@ impl Volume {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct ChannelVol {
|
pub(super) struct ChannelVol {
|
||||||
pub(super) left: Volume,
|
pub(super) left: Volume,
|
||||||
pub(super) right: Volume,
|
pub(super) right: Volume,
|
||||||
|
@ -67,6 +72,7 @@ impl Default for ChannelVol {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct Mixer {
|
pub(super) struct Mixer {
|
||||||
pub(super) vol_left: u8,
|
pub(super) vol_left: u8,
|
||||||
pub(super) vol_right: 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) struct DacSample {
|
||||||
pub(super) one: f32,
|
pub(super) one: f32,
|
||||||
pub(super) two: f32,
|
pub(super) two: f32,
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
util::{clear_bit, get_bit},
|
util::{clear_bit, get_bit},
|
||||||
HEIGHT, WIDTH,
|
HEIGHT, WIDTH,
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
pub use types::Colour;
|
pub use types::Colour;
|
||||||
|
|
||||||
mod addresses;
|
mod addresses;
|
||||||
|
@ -44,6 +45,55 @@ pub struct Gpu<Format: From<Colour>> {
|
||||||
prev_stat: bool,
|
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> {
|
impl<Format: From<Colour> + Clone> Gpu<Format> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
window: Box<dyn Renderer<Format>>,
|
window: Box<dyn Renderer<Format>>,
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::memory::Address,
|
processor::memory::Address,
|
||||||
util::{as_signed, get_bit},
|
util::{as_signed, get_bit},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub(super) enum DrawMode {
|
pub(super) enum DrawMode {
|
||||||
HBlank,
|
HBlank,
|
||||||
VBlank,
|
VBlank,
|
||||||
|
@ -11,7 +13,7 @@ pub(super) enum DrawMode {
|
||||||
Mode3,
|
Mode3,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub(super) enum TilemapArea {
|
pub(super) enum TilemapArea {
|
||||||
T9800,
|
T9800,
|
||||||
T9C00,
|
T9C00,
|
||||||
|
@ -26,7 +28,7 @@ impl TilemapArea {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub(super) enum TiledataArea {
|
pub(super) enum TiledataArea {
|
||||||
D8000,
|
D8000,
|
||||||
D9000,
|
D9000,
|
||||||
|
@ -41,7 +43,7 @@ impl TiledataArea {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||||
pub(super) enum ObjSize {
|
pub(super) enum ObjSize {
|
||||||
S8x8,
|
S8x8,
|
||||||
S8x16,
|
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) struct Lcdc {
|
||||||
pub(super) enable: bool,
|
pub(super) enable: bool,
|
||||||
pub(super) window_tilemap: TilemapArea,
|
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 {
|
pub enum Colour {
|
||||||
White,
|
White,
|
||||||
LightGray,
|
LightGray,
|
||||||
|
@ -138,7 +140,7 @@ impl Colour {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub(super) struct Palette {
|
pub(super) struct Palette {
|
||||||
pub(super) zero: Colour,
|
pub(super) zero: Colour,
|
||||||
pub(super) one: Colour,
|
pub(super) one: Colour,
|
||||||
|
@ -193,6 +195,7 @@ pub(super) struct Object {
|
||||||
pub(super) oam_location: u8,
|
pub(super) oam_location: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub(super) struct Stat {
|
pub(super) struct Stat {
|
||||||
pub(super) lyc_eq_ly_interrupt_enabled: bool,
|
pub(super) lyc_eq_ly_interrupt_enabled: bool,
|
||||||
pub(super) mode_2_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 {
|
pub struct Vram {
|
||||||
|
#[serde_as(as = "[_; 8192]")]
|
||||||
data: [u8; 8192],
|
data: [u8; 8192],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +239,10 @@ impl Default for Vram {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[serde_with::serde_as]
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub struct Oam {
|
pub struct Oam {
|
||||||
|
#[serde_as(as = "[_; 160]")]
|
||||||
pub data: [u8; 160],
|
pub data: [u8; 160],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::util::{clear_bit, get_bit};
|
use crate::util::{clear_bit, get_bit};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Joypad {
|
pub struct Joypad {
|
||||||
sel_action: bool,
|
sel_action: bool,
|
||||||
sel_direction: bool,
|
sel_direction: bool,
|
||||||
|
#[serde(skip)]
|
||||||
state: JoypadState,
|
state: JoypadState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
mod apu;
|
pub(crate) mod apu;
|
||||||
pub(crate) mod gpu;
|
pub(crate) mod gpu;
|
||||||
pub(crate) mod joypad;
|
pub(crate) mod joypad;
|
||||||
mod serial;
|
mod serial;
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
use std::io::{stdout, Write};
|
use std::io::{stdout, Write};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::util::get_bit;
|
use crate::util::get_bit;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
enum ClockSource {
|
enum ClockSource {
|
||||||
Internal,
|
Internal,
|
||||||
External,
|
External,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
enum ClockSpeed {
|
enum ClockSpeed {
|
||||||
Normal,
|
Normal,
|
||||||
Fast,
|
Fast,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
struct SerialControl {
|
struct SerialControl {
|
||||||
transfer_in_progress: bool,
|
transfer_in_progress: bool,
|
||||||
clock_speed: ClockSpeed,
|
clock_speed: ClockSpeed,
|
||||||
|
@ -30,6 +35,7 @@ impl Default for SerialControl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
pub struct Serial {
|
pub struct Serial {
|
||||||
byte: u8,
|
byte: u8,
|
||||||
output_byte: u8,
|
output_byte: u8,
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::util::{get_bit, set_or_clear_bit};
|
use crate::util::{get_bit, set_or_clear_bit};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
enum TimerRate {
|
enum TimerRate {
|
||||||
Sixteen,
|
Sixteen,
|
||||||
SixtyFour,
|
SixtyFour,
|
||||||
|
@ -36,6 +39,7 @@ impl TimerRate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
struct TimerControl {
|
struct TimerControl {
|
||||||
enable: bool,
|
enable: bool,
|
||||||
rate: TimerRate,
|
rate: TimerRate,
|
||||||
|
@ -56,6 +60,7 @@ pub struct TimerReturn {
|
||||||
pub timer_interrupt: bool,
|
pub timer_interrupt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
// 0xFF04
|
// 0xFF04
|
||||||
div: u8,
|
div: u8,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::processor::memory::Address;
|
use crate::processor::memory::Address;
|
||||||
use std::{
|
use std::{
|
||||||
fs::{File, OpenOptions},
|
fs::{File, OpenOptions},
|
||||||
|
@ -6,13 +8,17 @@ use std::{
|
||||||
str::from_utf8_unchecked,
|
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;
|
mod mbcs;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
struct MaybeBufferedSram {
|
struct MaybeBufferedSram {
|
||||||
buf: Vec<u8>,
|
buf: Vec<u8>,
|
||||||
length: usize,
|
length: usize,
|
||||||
|
#[serde(skip)]
|
||||||
inner: Option<File>,
|
inner: Option<File>,
|
||||||
unbuffered_writes: usize,
|
unbuffered_writes: usize,
|
||||||
}
|
}
|
||||||
|
@ -97,6 +103,30 @@ pub struct Rom {
|
||||||
mbc: Box<dyn Mbc>,
|
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 {
|
impl Rom {
|
||||||
pub fn load(data: Vec<u8>, save_path: Option<PathBuf>) -> Self {
|
pub fn load(data: Vec<u8>, save_path: Option<PathBuf>) -> Self {
|
||||||
let mut title_length = 0x143;
|
let mut title_length = 0x143;
|
||||||
|
|
|
@ -5,12 +5,14 @@ mod mbc2;
|
||||||
mod mbc3;
|
mod mbc3;
|
||||||
mod mbc5;
|
mod mbc5;
|
||||||
mod none;
|
mod none;
|
||||||
pub use mbc1::Mbc1;
|
pub use mbc1::{Mbc1, Mbc1SaveState};
|
||||||
pub use mbc2::Mbc2;
|
pub use mbc2::{Mbc2, Mbc2SaveState};
|
||||||
pub use mbc3::Mbc3;
|
pub use mbc3::{Mbc3, Mbc3SaveState};
|
||||||
pub use mbc5::Mbc5;
|
pub use mbc5::{Mbc5, Mbc5SaveState};
|
||||||
pub use none::None;
|
pub use none::None;
|
||||||
|
|
||||||
|
use super::MbcSaveState;
|
||||||
|
|
||||||
pub(super) const KB: usize = 1024;
|
pub(super) const KB: usize = 1024;
|
||||||
const ROM_BANK_SIZE: usize = 16 * KB;
|
const ROM_BANK_SIZE: usize = 16 * KB;
|
||||||
const RAM_BANK_SIZE: usize = 8 * 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(&mut self, address: Address, data: u8);
|
||||||
fn set_ram(&mut self, address: Address, data: u8);
|
fn set_ram(&mut self, address: Address, data: u8);
|
||||||
fn mbc_type(&self) -> String;
|
fn mbc_type(&self) -> String;
|
||||||
|
fn get_savestate(&self) -> MbcSaveState;
|
||||||
fn is_rumbling(&self) -> bool {
|
fn is_rumbling(&self) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::processor::memory::{rom::MaybeBufferedSram, Address};
|
|
||||||
|
|
||||||
#[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 {
|
enum BankingMode {
|
||||||
Simple,
|
Simple,
|
||||||
Advanced,
|
Advanced,
|
||||||
|
@ -20,6 +25,17 @@ pub struct Mbc1 {
|
||||||
bank_mode: BankingMode,
|
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 {
|
impl Mbc1 {
|
||||||
pub fn init(data: Vec<u8>, rom_size: u8, ram_size: u8, save_file: Option<PathBuf>) -> Self {
|
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;
|
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
||||||
|
@ -102,6 +118,18 @@ impl Mbc for Mbc1 {
|
||||||
ram.flush();
|
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 {
|
impl Mbc1 {
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
use std::path::PathBuf;
|
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};
|
use super::{rom_banks, Mbc, ROM_BANK_SIZE};
|
||||||
|
|
||||||
|
@ -12,6 +17,14 @@ pub struct Mbc2 {
|
||||||
ram_enabled: bool,
|
ram_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct Mbc2SaveState {
|
||||||
|
rom_len: usize,
|
||||||
|
rom_bank: u8,
|
||||||
|
ram: Vec<u8>,
|
||||||
|
ram_enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Mbc2 {
|
impl Mbc2 {
|
||||||
pub fn init(data: Vec<u8>, rom_size: u8, save_file: Option<PathBuf>) -> Self {
|
pub fn init(data: Vec<u8>, rom_size: u8, save_file: Option<PathBuf>) -> Self {
|
||||||
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
||||||
|
@ -75,4 +88,13 @@ impl Mbc for Mbc2 {
|
||||||
fn flush(&mut self) {
|
fn flush(&mut self) {
|
||||||
self.ram.flush();
|
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 super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::memory::{rom::MaybeBufferedSram, Address},
|
processor::memory::{
|
||||||
|
rom::{MaybeBufferedSram, MbcSaveState},
|
||||||
|
Address,
|
||||||
|
},
|
||||||
util::set_or_clear_bit,
|
util::set_or_clear_bit,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -8,7 +13,7 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
|
||||||
enum RtcRegister {
|
enum RtcRegister {
|
||||||
Seconds,
|
Seconds,
|
||||||
Minutes,
|
Minutes,
|
||||||
|
@ -17,6 +22,7 @@ enum RtcRegister {
|
||||||
Misc,
|
Misc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
enum RamBank {
|
enum RamBank {
|
||||||
Ram(u8),
|
Ram(u8),
|
||||||
Rtc(RtcRegister),
|
Rtc(RtcRegister),
|
||||||
|
@ -117,6 +123,17 @@ pub struct Mbc3 {
|
||||||
ram_size: usize,
|
ram_size: usize,
|
||||||
ram_enabled: bool,
|
ram_enabled: bool,
|
||||||
rtc: Option<Rtc>,
|
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 {
|
impl Mbc3 {
|
||||||
|
@ -257,4 +274,15 @@ impl Mbc for Mbc3 {
|
||||||
ram.flush();
|
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 std::path::PathBuf;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
processor::memory::{rom::MaybeBufferedSram, Address},
|
processor::memory::{
|
||||||
|
rom::{MaybeBufferedSram, MbcSaveState},
|
||||||
|
Address,
|
||||||
|
},
|
||||||
util::get_bit,
|
util::get_bit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,6 +24,18 @@ pub struct Mbc5 {
|
||||||
is_rumbling: bool,
|
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 {
|
impl Mbc5 {
|
||||||
pub fn init(
|
pub fn init(
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
|
@ -127,4 +144,17 @@ impl Mbc for Mbc5 {
|
||||||
ram.flush();
|
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 super::Mbc;
|
||||||
use crate::processor::memory::Address;
|
use crate::processor::memory::{rom::MbcSaveState, Address};
|
||||||
|
|
||||||
pub struct None {
|
pub struct None {
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
|
@ -27,4 +27,8 @@ impl Mbc for None {
|
||||||
fn mbc_type(&self) -> String {
|
fn mbc_type(&self) -> String {
|
||||||
String::from("None")
|
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;
|
use crate::verbose_println;
|
||||||
|
|
||||||
mod instructions;
|
mod instructions;
|
||||||
|
@ -27,6 +29,29 @@ pub struct Cpu<ColourFormat: From<Colour> + Clone> {
|
||||||
should_halt_bug: bool,
|
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> {
|
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> {
|
||||||
pub fn new(mut memory: Memory<ColourFormat>, run_bootrom: bool) -> Self {
|
pub fn new(mut memory: Memory<ColourFormat>, run_bootrom: bool) -> Self {
|
||||||
if !run_bootrom {
|
if !run_bootrom {
|
||||||
|
@ -138,7 +163,7 @@ pub enum Reg8 {
|
||||||
L,
|
L,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||||
pub struct Registers {
|
pub struct Registers {
|
||||||
pub af: u16,
|
pub af: u16,
|
||||||
pub bc: u16,
|
pub bc: u16,
|
||||||
|
|
Loading…
Reference in a new issue