diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 29930b9..b3d9a6c 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -10,49 +10,24 @@ - - - - - - - - - - - + - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + @@ -111,6 +98,7 @@ }]]> + @@ -129,7 +117,7 @@ 1703977798818 - + - @@ -157,6 +153,7 @@ - \ No newline at end of file diff --git a/gameboy-lib/Cargo.lock b/gameboy-lib/Cargo.lock index 44a4097..09715de 100644 --- a/gameboy-lib/Cargo.lock +++ b/gameboy-lib/Cargo.lock @@ -18,6 +18,8 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "gameboy" version = "0.1.0" dependencies = [ + "serde", + "serde_derive", "wasm-bindgen", ] @@ -35,27 +37,47 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "proc-macro2" -version = "1.0.72" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a293318316cf6478ec1ad2a21c49390a8d5b5eae9fab736467d93fbc0edc29c5" +checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] +[[package]] +name = "serde" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" -version = "2.0.43" +version = "2.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" dependencies = [ "proc-macro2", "quote", diff --git a/gameboy-lib/Cargo.toml b/gameboy-lib/Cargo.toml index 0b61605..6ecc392 100644 --- a/gameboy-lib/Cargo.toml +++ b/gameboy-lib/Cargo.toml @@ -6,7 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] +serialize = ["serde", "serde_derive"] wasm = ["wasm-bindgen"] [dependencies] -wasm-bindgen = { version = "0.2.84", optional = true} \ No newline at end of file +wasm-bindgen = { version = "0.2.84", optional = true} +serde = { version = "1.0.194", optional = true } +serde_derive = { version = "1.0.194", optional = true } \ No newline at end of file diff --git a/gameboy-lib/src/cpu/cpu.rs b/gameboy-lib/src/cpu/cpu.rs index 4c43a1e..cc512a9 100644 --- a/gameboy-lib/src/cpu/cpu.rs +++ b/gameboy-lib/src/cpu/cpu.rs @@ -1,11 +1,13 @@ +use serde_derive::Serialize; use crate::cpu::instructions::{JumpCondition, Target16Bit}; use crate::cpu::registers::{Register8BitName, Registers}; -use crate::memory::memory::Memory; +use crate::memory::Memory; use super::instructions::Target8Bit; use super::instructions::{Instruction, Source16Bit}; use super::registers::Register16BitName; +#[cfg_attr(feature = "serialize", derive(Serialize))] pub struct CPU { pub register: Registers, pub pc: u16, diff --git a/gameboy-lib/src/cpu/registers/flag_register.rs b/gameboy-lib/src/cpu/registers/flag_register.rs index 4a56b8a..8df3fab 100644 --- a/gameboy-lib/src/cpu/registers/flag_register.rs +++ b/gameboy-lib/src/cpu/registers/flag_register.rs @@ -1,4 +1,7 @@ +use serde_derive::Serialize; + #[derive(Copy, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serialize", derive(Serialize))] pub struct FlagRegister { pub zero: bool, pub subtract: bool, diff --git a/gameboy-lib/src/cpu/registers/mod.rs b/gameboy-lib/src/cpu/registers/mod.rs index b21a91d..8d1d804 100644 --- a/gameboy-lib/src/cpu/registers/mod.rs +++ b/gameboy-lib/src/cpu/registers/mod.rs @@ -1,3 +1,4 @@ +use serde_derive::Serialize; use super::registers::flag_register::FlagRegister; use super::registers::register::Register; use super::registers::register_8bit::Register8Bit; @@ -9,6 +10,7 @@ mod register_8bit; mod stack_pointer; #[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize))] pub struct Registers { a: Register8Bit, b: Register8Bit, diff --git a/gameboy-lib/src/cpu/registers/register_8bit.rs b/gameboy-lib/src/cpu/registers/register_8bit.rs index 4e3375b..cae9a93 100644 --- a/gameboy-lib/src/cpu/registers/register_8bit.rs +++ b/gameboy-lib/src/cpu/registers/register_8bit.rs @@ -1,6 +1,8 @@ +use serde_derive::Serialize; use super::register::Register; #[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize))] pub struct Register8Bit { name: String, value: u8, diff --git a/gameboy-lib/src/cpu/registers/stack_pointer.rs b/gameboy-lib/src/cpu/registers/stack_pointer.rs index a81415b..d5e1011 100644 --- a/gameboy-lib/src/cpu/registers/stack_pointer.rs +++ b/gameboy-lib/src/cpu/registers/stack_pointer.rs @@ -1,6 +1,8 @@ +use serde_derive::Serialize; use super::Register; #[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize))] pub struct StackPointer { name: String, value: u16 diff --git a/gameboy-lib/src/lib.rs b/gameboy-lib/src/lib.rs index cc98f6f..443c1d4 100644 --- a/gameboy-lib/src/lib.rs +++ b/gameboy-lib/src/lib.rs @@ -1,6 +1,4 @@ use crate::cpu::cpu::CPU; -use crate::cpu::registers::Registers; -use crate::memory::memory::Memory; pub mod cpu; pub mod memory; @@ -25,4 +23,4 @@ impl GameBoy { self.cpu.step(); } } -} \ No newline at end of file +} diff --git a/gameboy-lib/src/memory/memory.rs b/gameboy-lib/src/memory.rs similarity index 62% rename from gameboy-lib/src/memory/memory.rs rename to gameboy-lib/src/memory.rs index 9a17c9f..2a403fe 100644 --- a/gameboy-lib/src/memory/memory.rs +++ b/gameboy-lib/src/memory.rs @@ -1,4 +1,4 @@ -use crate::memory::observer::{Event, Publisher, Subject}; +use serde_derive::Serialize; pub const BOOT_ROM_BEGIN: usize = 0x00; pub const BOOT_ROM_END: usize = 0xFF; @@ -6,17 +6,16 @@ pub const BOOT_ROM_SIZE: usize = BOOT_ROM_END - BOOT_ROM_BEGIN + 1; #[derive(Clone)] +#[cfg_attr(feature = "serialize", derive(Serialize))] pub struct Memory { - publisher: Publisher, - pub memory: [u8; 0xFFFF], + pub memory: Vec, } impl Default for Memory { fn default() -> Self { Memory { - publisher: Publisher::default(), - memory: [0; 0xFFFF], + memory: vec![0; 0xFFFF], } } } @@ -28,32 +27,18 @@ impl Memory { } } - pub fn events(&mut self) -> &mut Publisher { - return &mut self.publisher; - } - pub fn write_byte(&mut self, address: u16, value: u8) { // println!("[MEM] Writing memory: address: 0x{:x} value: 0x{:x}", address, value); self.memory[address as usize] = value; - self.publisher.notify(Event::Write, self.create_subject(value, address)); } pub fn read_byte(&self, address: u16) -> u8 { let mem_value = self.memory[address as usize]; // println!("[MEM] Reading memory: address: 0x{:x} value: 0x{:x}", address, mem_value); - self.publisher.notify(Event::Read, self.create_subject(mem_value, address)); return mem_value; } pub fn read_next_word(&self, pc: u16) -> u16 { ((self.read_byte(pc + 2) as u16) << 8) | (self.read_byte(pc + 1) as u16) } - - fn create_subject(&self, value: u8, address: u16) -> Subject { - return Subject { - value, - address, - memory: self.memory.clone(), - }; - } } diff --git a/gameboy-lib/src/memory/mod.rs b/gameboy-lib/src/memory/mod.rs deleted file mode 100644 index 58cdea1..0000000 --- a/gameboy-lib/src/memory/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod observer; -pub mod memory; \ No newline at end of file diff --git a/gameboy-lib/src/memory/observer.rs b/gameboy-lib/src/memory/observer.rs deleted file mode 100644 index bbe1e3b..0000000 --- a/gameboy-lib/src/memory/observer.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::collections::HashMap; - -#[derive(PartialEq, Eq, Hash, Clone)] -pub enum Event { - Write, - Read, -} - -#[derive(Clone)] -pub struct Subject { - pub value: u8, - pub address: u16, - pub memory: [u8; 0xFFFF], -} - -pub type Subscriber = fn(subject: Subject); - -#[derive(Default, Clone)] -pub struct Publisher { - events: HashMap>, -} - -impl Publisher { - pub fn subscribe(&mut self, event: Event, listener: Subscriber) { - self.events.entry(event.clone()).or_default(); - self.events.get_mut(&event).unwrap().push(listener); - } - - pub fn unsubscribe(&mut self, event: Event, listener: Subscriber) { - self.events.get_mut(&event).unwrap().retain(|&x| x != listener); - } - - pub fn notify(&self, event: Event, subject: Subject) { - let listeners = self.events.get(&event); - if let Some(listeners) = listeners { - for listener in listeners { - listener(subject.clone()); - } - } - } -} \ No newline at end of file diff --git a/gameboy-web/gameboy-wasm/Cargo.toml b/gameboy-web/gameboy-wasm/Cargo.toml index 3b6161b..f2818ab 100644 --- a/gameboy-web/gameboy-wasm/Cargo.toml +++ b/gameboy-web/gameboy-wasm/Cargo.toml @@ -11,15 +11,13 @@ crate-type = ["cdylib", "rlib"] default = ["console_error_panic_hook"] [dependencies] -gameboy = { path = "../../gameboy-lib", features = ["wasm"] } -wasm-bindgen = "0.2.84" - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for -# code size when deploying. +gameboy = { path = "../../gameboy-lib", features = ["wasm", "serialize"] } +wasm-bindgen = { version = "0.2.84", features = ["serde-serialize"] } console_error_panic_hook = { version = "0.1.7", optional = true } log = "0.4.20" +serde = "1.0.194" +serde_derive = "1.0.194" +serde-wasm-bindgen = "0.6.3" [dev-dependencies] wasm-bindgen-test = "0.3.34" diff --git a/gameboy-web/gameboy-wasm/src/lib.rs b/gameboy-web/gameboy-wasm/src/lib.rs index 659e164..eb2fcec 100644 --- a/gameboy-web/gameboy-wasm/src/lib.rs +++ b/gameboy-web/gameboy-wasm/src/lib.rs @@ -1,9 +1,8 @@ mod utils; use std::ops::Deref; +use serde_derive::Serialize; use wasm_bindgen::prelude::*; -use gameboy::GameBoy; -use gameboy::memory::observer::Event; #[wasm_bindgen] extern "C" { @@ -13,26 +12,25 @@ extern "C" { } #[wasm_bindgen] -pub fn start_gameboy() { - log("Starting..."); - let boot_rom = load_boot_rom(); - let mut gameboy: GameBoy = GameBoy::new(); - let mut memory = &mut gameboy.cpu.memory; +#[derive(Serialize)] +pub struct CPU(gameboy::cpu::cpu::CPU); - memory.events().subscribe(Event::Write, |subject| { - log(format!("[MEM WASM] Writing value: 0x{:x}: 0x{:x}", subject.address, subject.value).as_str()) - }); - - memory.events().subscribe(Event::Read, |subject| { - log(format!("[MEM WASM] Reading value: 0x{:x}: 0x{:x}", subject.address, subject.value).as_str()) - }); - - gameboy.start_gameboy(boot_rom); - - log("End"); +#[wasm_bindgen] +impl CPU { + #[wasm_bindgen(constructor)] + pub fn new() -> CPU { + utils::set_panic_hook(); + let cpu = gameboy::cpu::cpu::CPU::default(); + return CPU(cpu); + } + + pub fn to_json(&self) -> Result { + Ok(serde_wasm_bindgen::to_value(&self)?) + } } -fn load_boot_rom() -> Vec { +#[wasm_bindgen] +pub fn load_boot_rom() -> Vec { let boot_rom = "31FEFFAF21FF9F32CB7C20FB2126FF0E113E8032E20C3EF3E2323E77773EFCE0471104012110801ACD9500CD9600137BFE3420F311D80006081A1322230520F93E19EA1099212F990E0C3D2808320D20F92E0F18F3673E6457E0423E91E040041E020E0CF044FE9020FA0D20F71D20F20E13247C1E83FE6228061EC1FE6420067BE20C3E87E2F04290E0421520D205204F162018CB4F0604C5CB1117C1CB11170520F522232223C9CEED6666CC0D000B03730083000C000D0008111F8889000EDCCC6EE6DDDDD999BBBB67636E0EECCCDDDC999FBBB9333E3C42B9A5B9A5423C21040111A8001A13BE20FE237DFE3420F506197886230520FB8620FE3E01E050"; boot_rom.chars() .collect::>() diff --git a/gameboy-web/src/App.tsx b/gameboy-web/src/App.tsx index 207f181..90a88be 100644 --- a/gameboy-web/src/App.tsx +++ b/gameboy-web/src/App.tsx @@ -1,5 +1,5 @@ import {useEffect, useState} from "react"; -import init, {start_gameboy} from "gameboy-wasm"; +import init, {load_boot_rom, CPU} from "gameboy-wasm"; function App() { @@ -10,13 +10,16 @@ function App() { }, []) const handleButton = () => { - start_gameboy() + const cpu = new CPU(); + const cpuAsJson = cpu.to_json(); + const memory = cpuAsJson.memory; + console.log("Memory", memory) } return ( - + ) }