diff --git a/Cargo.lock b/Cargo.lock index 1ce3631..c5379a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -217,9 +217,9 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" dependencies = [ "async-task", "concurrent-queue", @@ -313,9 +313,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" +checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" dependencies = [ "async-io", "async-lock", @@ -468,10 +468,10 @@ dependencies = [ ] [[package]] -name = "byteorder" -version = "1.5.0" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" @@ -493,13 +493,39 @@ dependencies = [ "thiserror", ] +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.6.0", + "log", + "polling", + "rustix", + "slab", + "thiserror", +] + [[package]] name = "calloop-wayland-source" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" dependencies = [ - "calloop", + "calloop 0.12.4", + "rustix", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop 0.13.0", "rustix", "wayland-backend", "wayland-client", @@ -507,9 +533,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" dependencies = [ "jobserver", "libc", @@ -794,7 +820,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.4", + "libloading 0.8.5", ] [[package]] @@ -1342,7 +1368,7 @@ dependencies = [ "glutin_glx_sys", "glutin_wgl_sys", "icrate", - "libloading 0.8.4", + "libloading 0.8.5", "objc2 0.4.1", "once_cell", "raw-window-handle 0.5.2", @@ -1463,7 +1489,7 @@ dependencies = [ "bitflags 2.6.0", "com", "libc", - "libloading 0.8.4", + "libloading 0.8.5", "thiserror", "widestring", "winapi", @@ -1531,12 +1557,12 @@ dependencies = [ [[package]] name = "image" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +checksum = "99314c8a2152b8ddb211f924cdae532d8c5e4c8bb54728e12fff1b0cd5963a10" dependencies = [ "bytemuck", - "byteorder", + "byteorder-lite", "num-traits", "png", ] @@ -1619,7 +1645,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" dependencies = [ "libc", - "libloading 0.8.4", + "libloading 0.8.5", "pkg-config", ] @@ -1653,9 +1679,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2552,8 +2578,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ "bitflags 2.6.0", - "calloop", - "calloop-wayland-source", + "calloop 0.12.4", + "calloop-wayland-source 0.2.0", "cursor-icon", "libc", "log", @@ -2564,20 +2590,45 @@ dependencies = [ "wayland-client", "wayland-csd-frame", "wayland-cursor", - "wayland-protocols", - "wayland-protocols-wlr", + "wayland-protocols 0.31.2", + "wayland-protocols-wlr 0.2.0", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.6.0", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix", + "thiserror", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols 0.32.3", + "wayland-protocols-wlr 0.3.3", "wayland-scanner", "xkeysym", ] [[package]] name = "smithay-clipboard" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c091e7354ea8059d6ad99eace06dd13ddeedbb0ac72d40a9a6e7ff790525882d" +checksum = "cc8216eec463674a0e90f29e0ae41a4db573ec5b56b1c6c1c71615d249b6d846" dependencies = [ "libc", - "smithay-client-toolkit", + "smithay-client-toolkit 0.19.2", "wayland-backend", ] @@ -2656,18 +2707,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -2928,9 +2979,9 @@ checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-backend" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "269c04f203640d0da2092d1b8d89a2d081714ae3ac2f1b53e99f205740517198" +checksum = "f90e11ce2ca99c97b940ee83edbae9da2d56a08f9ea8158550fd77fa31722993" dependencies = [ "cc", "downcast-rs", @@ -2942,9 +2993,9 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.4" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bd0f46c069d3382a36c8666c1b9ccef32b8b04f41667ca1fef06a1adcc2982" +checksum = "7e321577a0a165911bdcfb39cf029302479d7527b517ee58ab0f6ad09edf0943" dependencies = [ "bitflags 2.6.0", "rustix", @@ -2965,9 +3016,9 @@ dependencies = [ [[package]] name = "wayland-cursor" -version = "0.31.4" +version = "0.31.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09414bcf0fd8d9577d73e9ac4659ebc45bcc9cff1980a350543ad8e50ee263b2" +checksum = "6ef9489a8df197ebf3a8ce8a7a7f0a2320035c3743f3c1bd0bdbccf07ce64f95" dependencies = [ "rustix", "wayland-client", @@ -2986,6 +3037,18 @@ dependencies = [ "wayland-scanner", ] +[[package]] +name = "wayland-protocols" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62989625a776e827cc0f15d41444a3cea5205b963c3a25be48ae1b52d6b4daaa" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + [[package]] name = "wayland-protocols-plasma" version = "0.2.0" @@ -2995,7 +3058,7 @@ dependencies = [ "bitflags 2.6.0", "wayland-backend", "wayland-client", - "wayland-protocols", + "wayland-protocols 0.31.2", "wayland-scanner", ] @@ -3008,15 +3071,28 @@ dependencies = [ "bitflags 2.6.0", "wayland-backend", "wayland-client", - "wayland-protocols", + "wayland-protocols 0.31.2", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd993de54a40a40fbe5601d9f1fbcaef0aebcc5fda447d7dc8f6dcbaae4f8953" +dependencies = [ + "bitflags 2.6.0", + "wayland-backend", + "wayland-client", + "wayland-protocols 0.32.3", "wayland-scanner", ] [[package]] name = "wayland-scanner" -version = "0.31.3" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf466fc49a4feb65a511ca403fec3601494d0dee85dbf37fff6fa0dd4eec3b6" +checksum = "d7b56f89937f1cf2ee1f1259cf2936a17a1f45d8f0aa1019fae6d470d304cfa6" dependencies = [ "proc-macro2", "quick-xml", @@ -3025,9 +3101,9 @@ dependencies = [ [[package]] name = "wayland-sys" -version = "0.31.3" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a6754825230fa5b27bafaa28c30b3c9e72c55530581220cef401fa422c0fae7" +checksum = "43676fe2daf68754ecf1d72026e4e6c15483198b5d24e888b74d3f22f887a148" dependencies = [ "dlib", "log", @@ -3146,7 +3222,7 @@ dependencies = [ "js-sys", "khronos-egl", "libc", - "libloading 0.8.4", + "libloading 0.8.5", "log", "metal", "naga", @@ -3449,7 +3525,7 @@ dependencies = [ "atomic-waker", "bitflags 2.6.0", "bytemuck", - "calloop", + "calloop 0.12.4", "cfg_aliases 0.1.1", "core-foundation", "core-graphics", @@ -3469,14 +3545,14 @@ dependencies = [ "raw-window-handle 0.6.2", "redox_syscall 0.3.5", "rustix", - "smithay-client-toolkit", + "smithay-client-toolkit 0.18.1", "smol_str", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", "wayland-backend", "wayland-client", - "wayland-protocols", + "wayland-protocols 0.31.2", "wayland-protocols-plasma", "web-sys", "web-time", @@ -3515,7 +3591,7 @@ dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", - "libloading 0.8.4", + "libloading 0.8.5", "once_cell", "rustix", "x11rb-protocol", @@ -3529,9 +3605,9 @@ checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" [[package]] name = "xcursor" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" +checksum = "d491ee231a51ae64a5b762114c3ac2104b967aadba1de45c86ca42cf051513b7" [[package]] name = "xdg-home" diff --git a/Cargo.toml b/Cargo.toml index bd2b72a..c9584ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ egui = "0.28.1" enum_dispatch = "0.3.13" env_logger = "0.11.3" gb-core = { path = "./core/gb-core" } -image = { version = "0.25.1", default-features = false } +image = { version = "0.25.2", default-features = false } itertools = "0.13.0" libretro-rs = "0.1.3" log = "0.4.22" @@ -63,6 +63,6 @@ rfd = "0.14.1" sdl2 = "0.37.0" serde = { version = "1.0.204", features = ["derive"] } serde_json = "1.0.120" -thiserror = "1.0.62" +thiserror = "1.0.63" wasm-bindgen = "0.2.92" web-sys = "0.3.69" diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 92cc294..2ab8535 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -25,9 +25,27 @@ cargo +nightly fmt --all && cargo clippy --all-targets https://github.com/flamegraph-rs/flamegraph ```sh +# cargo +cargo install flamegraph + # Arch sudo pacman -S cargo-flamegraph cargo flamegraph --dev -- roms/rom.gb CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -- roms/rom.gb ``` + +## Upgrading packages + +```sh +# cargo +cargo install cargo-edit + +# brew +brew install cargo-edit + +# Arch +sudo pacman -S cargo-edit + +cargo upgrade -i && cargo update +``` diff --git a/core/gb-core/src/cartridge.rs b/core/gb-core/src/cartridge.rs index 2599c32..055d209 100644 --- a/core/gb-core/src/cartridge.rs +++ b/core/gb-core/src/cartridge.rs @@ -61,8 +61,11 @@ impl Cartridge { log::info!("RAM banks: {ram_banks}"); log::info!("CGB flag: {cgb_flag}"); log::info!("SGB flag: {sgb_flag:?}"); - log::info!("Old licensee code: {:#04X}", licensee_code.old()); - log::info!("New licensee code: {}", licensee_code.new_as_string()); + log::info!("Old licensee code: {:#04X}", licensee_code.old_code()); + log::info!( + "New licensee code: {}", + licensee_code.new_code().unwrap_or("--") + ); Ok(Self { rom, diff --git a/core/gb-core/src/cartridge/compatibility_palettes.rs b/core/gb-core/src/cartridge/compatibility_palettes.rs index ed799f3..944389b 100644 --- a/core/gb-core/src/cartridge/compatibility_palettes.rs +++ b/core/gb-core/src/cartridge/compatibility_palettes.rs @@ -2,12 +2,11 @@ // 1. https://gbdev.io/pandocs/Power_Up_Sequence.html#compatibility-palettes // 2. https://github.com/LIJI32/SameBoy/blob/master/BootROMs/cgb_boot.asm -use self::{ - palette_combinations::PALETTE_COMBINATIONS, - palette_id_lookup_table::PALETTE_ID_LOOKUP_TABLE, - title_checksum_lookup_table::TITLE_CHECKSUM_LOOKUP_TABLE, -}; -use super::{licensee_code::LicenseeCode, title::Title}; +use palette_id::get_palette_id; +use palette_id_index::get_palette_id_index; +use palettes::get_palettes_from_id; + +use crate::cartridge::{licensee_code::LicenseeCode, title::Title}; pub struct CompatibilityPalettes { pub bg0: [u16; 4], @@ -16,49 +15,24 @@ pub struct CompatibilityPalettes { } impl CompatibilityPalettes { - pub const DEFAULT: Self = PALETTE_COMBINATIONS[0].into_palettes(); + pub const DEFAULT: Self = get_palettes_from_id(0); pub fn from_header_info(licensee_code: &LicenseeCode, title: &Title) -> Self { - match licensee_code.old() { - 0x33 => { - if !(licensee_code.new_as_string() == "01" - || u16::from_le_bytes(*licensee_code.new_as_bytes()) == 0x01) - { - return Self::DEFAULT; - } - } - - 0x01 => (), - - _ => return Self::DEFAULT, - }; - - let title_checksum = title.checksum(); + if !licensee_code.is_nintendo() { + return Self::DEFAULT; + } - let Some(checksum_index) = TITLE_CHECKSUM_LOOKUP_TABLE - .into_iter() - .position(|x| x == title_checksum) - else { + let Some(palette_id_index) = get_palette_id_index(title) else { return Self::DEFAULT; }; - let palette_id = if checksum_index <= 64 { - PALETTE_ID_LOOKUP_TABLE[checksum_index] - } else { - let fourth_byte = title.as_bytes()[3]; - let row = title_row_lookup_table::find_row(checksum_index - 65, fourth_byte); - let index = checksum_index + (14 * row); - - PALETTE_ID_LOOKUP_TABLE[index] - }; + let palette_id = get_palette_id(palette_id_index); - PALETTE_COMBINATIONS[palette_id].into_palettes() + get_palettes_from_id(palette_id) } } -mod palette_combinations; -mod palette_id_lookup_table; -mod palette_lookup_table; -mod palette_lookup_type; -mod title_checksum_lookup_table; -mod title_row_lookup_table; +mod palette; +mod palette_id; +mod palette_id_index; +mod palettes; diff --git a/core/gb-core/src/cartridge/compatibility_palettes/palette_lookup_table.rs b/core/gb-core/src/cartridge/compatibility_palettes/palette.rs similarity index 89% rename from core/gb-core/src/cartridge/compatibility_palettes/palette_lookup_table.rs rename to core/gb-core/src/cartridge/compatibility_palettes/palette.rs index 1e9b43a..1d49903 100644 --- a/core/gb-core/src/cartridge/compatibility_palettes/palette_lookup_table.rs +++ b/core/gb-core/src/cartridge/compatibility_palettes/palette.rs @@ -2,7 +2,10 @@ // 1. https://gbdev.io/pandocs/Power_Up_Sequence.html#compatibility-palettes // 2. https://github.com/LIJI32/SameBoy/blob/master/BootROMs/cgb_boot.asm -pub const fn from_index_start(id: usize) -> [u16; 4] { +/// **Fourth step** +/// +/// Returns the palette from the id obtained in the previous step. +pub const fn palette_from_id(id: usize) -> [u16; 4] { [ PALETTE_LOOKUP_TABLE[id], PALETTE_LOOKUP_TABLE[id + 1], @@ -11,7 +14,7 @@ pub const fn from_index_start(id: usize) -> [u16; 4] { ] } -pub const PALETTE_LOOKUP_TABLE: [u16; 120] = [ +const PALETTE_LOOKUP_TABLE: [u16; 120] = [ 0x7FFF, 0x32BF, 0x00D0, 0x0000, // 0 0x639F, 0x4279, 0x15B0, 0x04CB, // 1 0x7FFF, 0x6E31, 0x454A, 0x0000, // 2 diff --git a/core/gb-core/src/cartridge/compatibility_palettes/palette_id_lookup_table.rs b/core/gb-core/src/cartridge/compatibility_palettes/palette_id.rs similarity index 89% rename from core/gb-core/src/cartridge/compatibility_palettes/palette_id_lookup_table.rs rename to core/gb-core/src/cartridge/compatibility_palettes/palette_id.rs index 4b93781..a38bc63 100644 --- a/core/gb-core/src/cartridge/compatibility_palettes/palette_id_lookup_table.rs +++ b/core/gb-core/src/cartridge/compatibility_palettes/palette_id.rs @@ -2,7 +2,15 @@ // 1. https://gbdev.io/pandocs/Power_Up_Sequence.html#compatibility-palettes // 2. https://github.com/LIJI32/SameBoy/blob/master/BootROMs/cgb_boot.asm -pub const PALETTE_ID_LOOKUP_TABLE: [usize; 94] = [ +/// **Second step** +/// +/// Used to obtain the palette id given its index from the lookup table. +pub const fn get_palette_id(index: usize) -> usize { + PALETTE_ID[index] +} + +/// Indexeded by the index of the title checksum. +const PALETTE_ID: [usize; 94] = [ 0, // Default Palette 4, // ALLEY WAY 5, // YAKUMAN diff --git a/core/gb-core/src/cartridge/compatibility_palettes/palette_id_index.rs b/core/gb-core/src/cartridge/compatibility_palettes/palette_id_index.rs new file mode 100644 index 0000000..9f6d2c0 --- /dev/null +++ b/core/gb-core/src/cartridge/compatibility_palettes/palette_id_index.rs @@ -0,0 +1,63 @@ +// Taken from +// 1. https://gbdev.io/pandocs/Power_Up_Sequence.html#compatibility-palettes +// 2. https://github.com/LIJI32/SameBoy/blob/master/BootROMs/cgb_boot.asm + +use crate::cartridge::title::Title; + +/// **First step** +/// +/// Used to obtain the index of the palette id. +pub fn get_palette_id_index(title: &Title) -> Option { + let title_checksum = title.checksum(); + + let checksum_index = TITLE_CHECKSUM + .into_iter() + .position(|x| x == title_checksum)?; + + if checksum_index <= 64 { + Some(checksum_index) + } else { + let fourth_byte = title.as_bytes()[3]; + let row = find_title_row(checksum_index - 65, fourth_byte); + let index = checksum_index + (14 * row); + + Some(index) + } +} + +/// The index will be the index that corresponds to the value of the title checksum in this table. +const TITLE_CHECKSUM: [u8; 79] = [ + 0x00, 0x88, 0x16, 0x36, 0xD1, 0xDB, 0xF2, 0x3C, 0x8C, 0x92, 0x3D, 0x5C, 0x58, 0xC9, 0x3E, 0x70, + 0x1D, 0x59, 0x69, 0x19, 0x35, 0xA8, 0x14, 0xAA, 0x75, 0x95, 0x99, 0x34, 0x6F, 0x15, 0xFF, 0x97, + 0x4B, 0x90, 0x17, 0x10, 0x39, 0xF7, 0xF6, 0xA2, 0x49, 0x4E, 0x43, 0x68, 0xE0, 0x8B, 0xF0, 0xCE, + 0x0C, 0x29, 0xE8, 0xB7, 0x86, 0x9A, 0x52, 0x01, 0x9D, 0x71, 0x9C, 0xBD, 0x5D, 0x6D, 0x67, 0x3F, + 0x6B, // <-- 64 + // Ambiguous. Refer to the fourth byte in the title if the index is >64. + 0xB3, 0x46, 0x28, 0xA5, 0xC6, 0xD3, 0x27, 0x61, 0x18, 0x66, 0x6A, 0xBF, 0x0D, 0xF4, +]; + +/// If the index of the checksum is <= 64, don't use this. +/// If > 64, this will return the index of the palette id lookup table. +fn find_title_row(column: usize, fourth_byte: u8) -> usize { + const TITLE_ROW_LOOKUP_TABLE: [&str; 3] = ["BEFAARBEKEK R-", "URAR INAILICE ", "R"]; + + if let Some(ch) = TITLE_ROW_LOOKUP_TABLE[0].as_bytes().get(column) { + if *ch == fourth_byte { + return 0; + } + } + + if let Some(ch) = TITLE_ROW_LOOKUP_TABLE[1].as_bytes().get(column) { + if *ch == fourth_byte { + return 1; + } + } + + if let Some(ch) = TITLE_ROW_LOOKUP_TABLE[2].as_bytes().get(column) { + if *ch == fourth_byte { + return 2; + } + } + + 0 +} diff --git a/core/gb-core/src/cartridge/compatibility_palettes/palette_lookup_type.rs b/core/gb-core/src/cartridge/compatibility_palettes/palette_lookup_type.rs deleted file mode 100644 index db826a1..0000000 --- a/core/gb-core/src/cartridge/compatibility_palettes/palette_lookup_type.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Taken from -// 1. https://gbdev.io/pandocs/Power_Up_Sequence.html#compatibility-palettes -// 2. https://github.com/LIJI32/SameBoy/blob/master/BootROMs/cgb_boot.asm - -use super::{palette_lookup_table::from_index_start, CompatibilityPalettes}; - -/// (OBJ0, OBJ1, BG0) -#[derive(Debug, Clone, Copy)] -pub enum PaletteLookupKind { - Normal(usize, usize, usize), - Raw(usize, usize, usize), -} - -impl PaletteLookupKind { - pub const fn into_palettes(self) -> CompatibilityPalettes { - let (obj0, obj1, bg0) = match self { - Self::Normal(obj0, obj1, bg0) => (obj0 * 4, obj1 * 4, bg0 * 4), - Self::Raw(obj0, obj1, bg0) => (obj0, obj1, bg0), - }; - - CompatibilityPalettes { - bg0: from_index_start(bg0), - obj0: from_index_start(obj0), - obj1: from_index_start(obj1), - } - } -} diff --git a/core/gb-core/src/cartridge/compatibility_palettes/palette_combinations.rs b/core/gb-core/src/cartridge/compatibility_palettes/palettes.rs similarity index 61% rename from core/gb-core/src/cartridge/compatibility_palettes/palette_combinations.rs rename to core/gb-core/src/cartridge/compatibility_palettes/palettes.rs index 88589d3..d35d42a 100644 --- a/core/gb-core/src/cartridge/compatibility_palettes/palette_combinations.rs +++ b/core/gb-core/src/cartridge/compatibility_palettes/palettes.rs @@ -2,10 +2,36 @@ // 1. https://gbdev.io/pandocs/Power_Up_Sequence.html#compatibility-palettes // 2. https://github.com/LIJI32/SameBoy/blob/master/BootROMs/cgb_boot.asm -use super::palette_lookup_type::PaletteLookupKind::{self, Normal, Raw}; +use super::palette::palette_from_id; +use crate::cartridge::compatibility_palettes::CompatibilityPalettes; + +/// **Third step** +/// +/// From the palette id, get each palette for BG0, OBJ1 and OBJ2. +pub const fn get_palettes_from_id(id: usize) -> CompatibilityPalettes { + let (obj0, obj1, bg0) = match PALETTE_COMBINATIONS[id] { + PaletteLookupKind::Normal(obj0, obj1, bg0) => (obj0 * 4, obj1 * 4, bg0 * 4), + PaletteLookupKind::Raw(obj0, obj1, bg0) => (obj0, obj1, bg0), + }; + + CompatibilityPalettes { + bg0: palette_from_id(bg0), + obj0: palette_from_id(obj0), + obj1: palette_from_id(obj1), + } +} + +/// (OBJ0, OBJ1, BG0) +#[derive(Debug, Clone, Copy)] +enum PaletteLookupKind { + Normal(usize, usize, usize), + Raw(usize, usize, usize), +} + +use PaletteLookupKind::{Normal, Raw}; #[allow(clippy::erasing_op)] -pub const PALETTE_COMBINATIONS: [PaletteLookupKind; 51] = [ +const PALETTE_COMBINATIONS: [PaletteLookupKind; 51] = [ Normal(4, 4, 29), Normal(18, 18, 18), Normal(20, 20, 20), diff --git a/core/gb-core/src/cartridge/compatibility_palettes/title_checksum_lookup_table.rs b/core/gb-core/src/cartridge/compatibility_palettes/title_checksum_lookup_table.rs deleted file mode 100644 index a1d8e7e..0000000 --- a/core/gb-core/src/cartridge/compatibility_palettes/title_checksum_lookup_table.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Taken from -// 1. https://gbdev.io/pandocs/Power_Up_Sequence.html#compatibility-palettes -// 2. https://github.com/LIJI32/SameBoy/blob/master/BootROMs/cgb_boot.asm - -pub const TITLE_CHECKSUM_LOOKUP_TABLE: [u8; 79] = [ - 0x00, 0x88, 0x16, 0x36, 0xD1, 0xDB, 0xF2, 0x3C, 0x8C, 0x92, 0x3D, 0x5C, 0x58, 0xC9, 0x3E, 0x70, - 0x1D, 0x59, 0x69, 0x19, 0x35, 0xA8, 0x14, 0xAA, 0x75, 0x95, 0x99, 0x34, 0x6F, 0x15, 0xFF, 0x97, - 0x4B, 0x90, 0x17, 0x10, 0x39, 0xF7, 0xF6, 0xA2, 0x49, 0x4E, 0x43, 0x68, 0xE0, 0x8B, 0xF0, 0xCE, - 0x0C, 0x29, 0xE8, 0xB7, 0x86, 0x9A, 0x52, 0x01, 0x9D, 0x71, 0x9C, 0xBD, 0x5D, 0x6D, 0x67, 0x3F, - 0x6B, // - // Ambiguous. Refer to the fourth letter. - 0xB3, 0x46, 0x28, 0xA5, 0xC6, 0xD3, 0x27, 0x61, 0x18, 0x66, 0x6A, 0xBF, 0x0D, 0xF4, -]; diff --git a/core/gb-core/src/cartridge/compatibility_palettes/title_row_lookup_table.rs b/core/gb-core/src/cartridge/compatibility_palettes/title_row_lookup_table.rs deleted file mode 100644 index 403a214..0000000 --- a/core/gb-core/src/cartridge/compatibility_palettes/title_row_lookup_table.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Taken from -// 1. https://gbdev.io/pandocs/Power_Up_Sequence.html#compatibility-palettes -// 2. https://github.com/LIJI32/SameBoy/blob/master/BootROMs/cgb_boot.asm - -pub const TITLE_ROW_LOOKUP_TABLE: [&str; 3] = ["BEFAARBEKEK R-", "URAR INAILICE ", "R"]; - -pub fn find_row(column: usize, byte: u8) -> usize { - if let Some(ch) = TITLE_ROW_LOOKUP_TABLE[0].as_bytes().get(column) { - if *ch == byte { - return 0; - } - } - - if let Some(ch) = TITLE_ROW_LOOKUP_TABLE[1].as_bytes().get(column) { - if *ch == byte { - return 1; - } - } - - if let Some(ch) = TITLE_ROW_LOOKUP_TABLE[2].as_bytes().get(column) { - if *ch == byte { - return 2; - } - } - - 0 -} diff --git a/core/gb-core/src/cartridge/header.rs b/core/gb-core/src/cartridge/header.rs index 6505bf3..bc4856a 100644 --- a/core/gb-core/src/cartridge/header.rs +++ b/core/gb-core/src/cartridge/header.rs @@ -2,8 +2,8 @@ use super::error::Error; /// Not the actual start, we're starting at 0 for convenience, as 0..0x100 is the bootrom area. /// The actual start is at 0x100. -pub const HEADER_START: usize = 0; -pub const HEADER_END: usize = 0x014F; +const HEADER_START: usize = 0; +const HEADER_END: usize = 0x014F; pub const HEADER_SIZE: usize = HEADER_START + HEADER_END + 1; diff --git a/core/gb-core/src/cartridge/licensee_code.rs b/core/gb-core/src/cartridge/licensee_code.rs index 1b7ed35..1c43e62 100644 --- a/core/gb-core/src/cartridge/licensee_code.rs +++ b/core/gb-core/src/cartridge/licensee_code.rs @@ -1,42 +1,131 @@ use super::{error::Error, header::Header}; -pub const OLD_LICENSEE_CODE_ADDRESS: usize = 0x014B; +const OLD_LICENSEE_CODE_ADDRESS: usize = 0x014B; -pub const NEW_LICENSEE_CODE_ADDRESS_BEGIN: usize = 0x0144; -pub const NEW_LICENSEE_CODE_ADDRESS_END: usize = 0x0145; +const NEW_LICENSEE_CODE_ADDRESS_BEGIN: usize = 0x0144; +const NEW_LICENSEE_CODE_ADDRESS_END: usize = 0x0145; pub struct LicenseeCode { - old: u8, - new_bytes: [u8; 2], + old_code: u8, + new_code: Option, } impl LicenseeCode { pub fn from_header(header: &Header) -> Result { - let old_licensee_code = header[OLD_LICENSEE_CODE_ADDRESS]; - let new_licensee_code_bytes = - &header[NEW_LICENSEE_CODE_ADDRESS_BEGIN..=NEW_LICENSEE_CODE_ADDRESS_END]; + let old_code = header[OLD_LICENSEE_CODE_ADDRESS]; - Ok(Self { - old: old_licensee_code, - new_bytes: new_licensee_code_bytes + let new_code = if old_code == 0x33 { + let new_bytes: [u8; 2] = header + [NEW_LICENSEE_CODE_ADDRESS_BEGIN..=NEW_LICENSEE_CODE_ADDRESS_END] .try_into() - .map_err(|_err| Error::InvalidRom)?, - }) + .map_err(|_err| Error::InvalidRom)?; + + Some(Self::new_bytes_to_string(new_bytes)) + } else { + None + }; + + Ok(Self { old_code, new_code }) } - pub fn old(&self) -> u8 { - self.old + pub fn old_code(&self) -> u8 { + self.old_code } - pub fn new_as_bytes(&self) -> &[u8; 2] { - &self.new_bytes + pub fn new_code(&self) -> Option<&str> { + self.new_code.as_deref() } - pub fn new_as_string(&self) -> String { - String::from_utf8_lossy(&self.new_bytes) - .trim() + pub fn is_nintendo(&self) -> bool { + (self.old_code() == 0x01) || (self.old_code() == 0x33 && self.new_code() == Some("01")) + } + + fn new_bytes_to_string(bytes: [u8; 2]) -> String { + String::from_utf8_lossy(&bytes) .chars() - .filter(char::is_ascii) + .map(|c| if c.is_alphanumeric() { c } else { '?' }) .collect() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::cartridge::header::HEADER_SIZE; + + #[test] + fn test_old_licensee_code() { + // 0x01 + let header = generate_header(0x01, [0, 0]); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.old_code(), 0x01); + assert!(licensee_code.is_nintendo()); + + // 0x42 (not Nintendo) + let header = generate_header(0x42, [0, 0]); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.old_code(), 0x42); + assert!(!licensee_code.is_nintendo()); + } + + #[test] + fn test_new_licensee_code() { + let header = generate_header(0x33, [b'0', b'1']); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.new_code(), Some("01")); + assert!(licensee_code.is_nintendo()); + + let header = generate_header(0x33, [b'4', b'2']); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.new_code(), Some("42")); + assert!(!licensee_code.is_nintendo()); + + let header = generate_header(0x33, [b'A', b'B']); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.new_code(), Some("AB")); + assert!(!licensee_code.is_nintendo()); + } + + #[test] + fn test_invalid_new_licensee_code() { + let header = generate_header(0x42, [1, 2]); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.new_code(), None); + + let header = generate_header(0x42, [1, b'2']); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.new_code(), None); + } + + #[test] + fn test_weird_new_licensee_code() { + let header = generate_header(0x33, [1, 2]); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.new_code(), Some("??")); + + let header = generate_header(0x33, [1, b'2']); + let licensee_code = LicenseeCode::from_header(&header).unwrap(); + + assert_eq!(licensee_code.new_code(), Some("?2")); + } + + fn generate_header(old: u8, new: [u8; 2]) -> Header { + let mut header = [0; HEADER_SIZE]; + + header[OLD_LICENSEE_CODE_ADDRESS] = old; + + let new_code_slice = + &mut header[NEW_LICENSEE_CODE_ADDRESS_BEGIN..=NEW_LICENSEE_CODE_ADDRESS_END]; + new_code_slice.copy_from_slice(&new); + + header + } +}