diff --git a/frontends/sdl/src/main.rs b/frontends/sdl/src/main.rs index a31475eb966499c10a55db1537e6812207068186..2bbebc802c027d6b7a06ecee96c9e0ae370172a0 100644 --- a/frontends/sdl/src/main.rs +++ b/frontends/sdl/src/main.rs @@ -8,6 +8,7 @@ use audio::Audio; use boytacean::{ devices::printer::PrinterDevice, gb::{AudioProvider, GameBoy, GameBoyMode}, + gen::VERSION, pad::PadKey, ppu::{PaletteInfo, PpuMode, DISPLAY_HEIGHT, DISPLAY_WIDTH}, }; @@ -455,9 +456,14 @@ impl Emulator { } fn main() { + let mode = GameBoyMode::Cgb; + + // prints the current version of the emulator (informational message) + println!("Boytacean v{} - {}", VERSION, mode); + // creates a new Game Boy instance and loads both the boot ROM // and the initial game ROM to "start the engine" - let mut game_boy = GameBoy::new(GameBoyMode::Cgb); + let mut game_boy = GameBoy::new(mode); let mut printer = Box::<PrinterDevice>::default(); printer.set_callback(|image_buffer| { let file_name = format!("printer-{}.png", Utc::now().format("%Y%m%d-%H%M%S")); diff --git a/src/gb.rs b/src/gb.rs index 602468dc7fd93f772a6e3815048d78ddb44dfeec..47560371d358d14c0cc8e2e0c5567fcb6426c073 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -13,7 +13,12 @@ use crate::{ util::read_file, }; -use std::{cell::RefCell, collections::VecDeque, rc::Rc}; +use std::{ + cell::RefCell, + collections::VecDeque, + fmt::{self, Display, Formatter}, + rc::Rc, +}; #[cfg(feature = "wasm")] use wasm_bindgen::prelude::*; @@ -43,6 +48,22 @@ pub enum GameBoyMode { Sgb = 3, } +impl GameBoyMode { + pub fn description(&self) -> &'static str { + match self { + GameBoyMode::Dmg => "Game Boy (DMG)", + GameBoyMode::Cgb => "Game Boy Color (CGB)", + GameBoyMode::Sgb => "Super Game Boy (SGB)", + } + } +} + +impl Display for GameBoyMode { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.description()) + } +} + #[cfg_attr(feature = "wasm", wasm_bindgen)] #[derive(Clone, Copy, PartialEq, Eq)] pub struct GameBoyConfig { diff --git a/src/mmu.rs b/src/mmu.rs index 509352dac504e56bcf25e6b77e88e92823c2937d..301d32988283477eda33813766feec825850199a 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -66,7 +66,7 @@ pub struct Mmu { ram: Vec<u8>, /// The RAM bank to be used in the read and write operation of - /// the 0xD000-0xDFFF memory range (CGB Only). + /// the 0xD000-0xDFFF memory range (CGB only). ram_bank: u8, ram_offset: u16, @@ -309,7 +309,7 @@ impl Mmu { // 0xFF50 - Boot active flag 0x50 => self.boot_active = false, - // 0xFF70 - SVBK: WRAM bank (CGB Mode only) + // 0xFF70 - SVBK: WRAM bank (CGB only) 0x70 => { let mut ram_bank = value & 0x7; if ram_bank == 0x0 { diff --git a/src/ppu.rs b/src/ppu.rs index 99f6042cb14dd7b8fe9df3deb1e2bab20b3efa6c..8811a1aba264600e35debae4e1bfd727f0ce0c19 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -227,6 +227,14 @@ pub struct Ppu { /// The palette that is going to be used for sprites/objects #1. palette_obj_1: Palette, + /// The complete set of background palettes that are going to be + /// used in CGB emulation to provide the full set of colors. + palettes_color_bg: [Palette; 8], + + /// The complete set of object/sprite palettes that are going to be + /// used in CGB emulation to provide the full set of colors. + palettes_color_obj: [Palette; 8], + /// The complete set of palettes in binary data so that they can /// be re-read if required by the system. palettes: [u8; 3], @@ -293,13 +301,27 @@ pub struct Ppu { /// content. switch_lcd: bool, - // Internal window counter value used to control the ines that + // Internal window counter value used to control the lines that // were effectively rendered as part of the window tile drawing process. // A line is only considered rendered when the WX and WY registers // are within the valid screen range and the window switch register // is valid. window_counter: u8, + /// If the auto increment of the background color palette is enabled + /// so that the next address is going to be set on every write. + auto_increment_bg: bool, + + /// The current address in usage for the background color palettes. + palette_address_bg: u8, + + /// If the auto increment of the object/sprite color palette is enabled + /// so that the next address is going to be set on every write. + auto_increment_obj: bool, + + /// The current address in usage for the object/sprite color palettes. + palette_address_obj: u8, + /// Flag that controls if the frame currently in rendering is the /// first one, preventing actions. first_frame: bool, @@ -355,6 +377,8 @@ impl Ppu { palette: [[0u8; RGB_SIZE]; PALETTE_SIZE], palette_obj_0: [[0u8; RGB_SIZE]; PALETTE_SIZE], palette_obj_1: [[0u8; RGB_SIZE]; PALETTE_SIZE], + palettes_color_bg: [[[0u8; RGB_SIZE]; PALETTE_SIZE]; 8], + palettes_color_obj: [[[0u8; RGB_SIZE]; PALETTE_SIZE]; 8], palettes: [0u8; 3], scy: 0x0, scx: 0x0, @@ -373,6 +397,10 @@ impl Ppu { window_map: false, switch_lcd: false, window_counter: 0x0, + auto_increment_bg: false, + palette_address_bg: 0x0, + auto_increment_obj: false, + palette_address_obj: 0x0, first_frame: false, frame_index: 0, stat_hblank: false, @@ -393,6 +421,8 @@ impl Ppu { self.palette = [[0u8; RGB_SIZE]; PALETTE_SIZE]; self.palette_obj_0 = [[0u8; RGB_SIZE]; PALETTE_SIZE]; self.palette_obj_1 = [[0u8; RGB_SIZE]; PALETTE_SIZE]; + self.palettes_color_bg = [[[0u8; RGB_SIZE]; PALETTE_SIZE]; 8]; + self.palettes_color_obj = [[[0u8; RGB_SIZE]; PALETTE_SIZE]; 8]; self.palettes = [0u8; 3]; self.scy = 0x0; self.scx = 0x0; @@ -408,6 +438,11 @@ impl Ppu { self.switch_window = false; self.window_map = false; self.switch_lcd = false; + self.window_counter = 0; + self.auto_increment_bg = false; + self.palette_address_bg = 0x0; + self.auto_increment_obj = false; + self.palette_address_obj = 0x0; self.first_frame = false; self.frame_index = 0; self.stat_hblank = false; @@ -537,6 +572,8 @@ impl Ppu { 0xff4b => self.wx, // 0xFF4F — VBK (CGB only) 0xff4f => 0xff, + // 0xFF68 — BCPS/BGPI (CGB only) + 0xff68 => self.palette_address_bg | if self.auto_increment_bg { 0x80 } else { 0x00 }, _ => { warnln!("Reading from unknown PPU location 0x{:04x}", addr); 0xff @@ -605,6 +642,11 @@ impl Ppu { 0xff4b => self.wx = value, // 0xFF4F — VBK (CGB only) 0xff4f => (), + // 0xFF68 — BCPS/BGPI (CGB only) + 0xff68 => { + self.palette_address_bg = value & 0x3f; + self.auto_increment_bg = value & 0x80 == 0x80; + } 0xff7f => (), _ => warnln!("Writing in unknown PPU location 0x{:04x}", addr), }