diff --git a/src/main.rs b/src/main.rs index 0d17e5b..c90016b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,8 +21,8 @@ use nes_emu::{ use tokio::runtime::Runtime; use tracing_subscriber::EnvFilter; -const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "even_odd.nes"); -// const ROM_FILE: &str = "./Super Mario Bros. (World).nes"; +// const ROM_FILE: &str = concat!(env!("ROM_DIR"), "/", "even_odd.nes"); +const ROM_FILE: &str = "./Super Mario Bros. (World).nes"; extern crate nes_emu; @@ -174,15 +174,10 @@ impl Emulator { if let Some(WindowType::Main) = self.windows.get(&id) { self.main_win_size = size; } - println!("New size for {:?}, {:?}", id, size); - // return iced::window::set_min_size(id, size.into()) - // .then(move |_: ()| iced::window::resize(id, size)); return Task::future(async { tokio::time::sleep(Duration::from_millis(50)).await; }) - .then(move |_| { - iced::window::resize(id, size) - }); + .then(move |_| iced::window::resize(id, size)); } } // self.image.0.clone_from(self.nes.image()); @@ -249,27 +244,6 @@ impl Emulator { } } - // fn cpu_state(&self) -> Element<'_, Message> { - // row![column![ - // // text!("Registers").font(Font::MONOSPACE), - // text!("{:?}", self.nes).font(Font::MONOSPACE), - // ],] - // .width(Fill) - // .into() - // } - - // fn controls(&self) -> Element<'_, Message> { - // row![ - // button("Clock tick").on_press(Message::Tick(1)), - // button("CPU tick").on_press(Message::CPU), - // button("Next Frame").on_press(Message::Frame), - // button("Next DMA").on_press(Message::DMA), - // button("Next DBG").on_press(Message::DebugInt), - // ] - // .width(Fill) - // .into() - // } - fn dropdowns(&self) -> Element<'_, Message> { row![ header_menu( diff --git a/src/ppu.rs b/src/ppu.rs index 43f9bb1..8a9d29c 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -83,6 +83,10 @@ pub struct Background { state: BackgroundState, + cur_nametable: u8, + cur_attr: u8, + cur_high: u8, + cur_low: u8, cur_shift_high: u8, cur_shift_low: u8, } @@ -99,70 +103,326 @@ pub struct Mask { } const COLORS: &'static [Color; 0b100_0000] = &[ - Color { r: 0x66, g: 0x66, b: 0x66 }, // 00 - Color { r: 0x00, g: 0x2A, b: 0x88 }, // 01 - Color { r: 0x14, g: 0x12, b: 0xA7 }, // 02 - Color { r: 0x3B, g: 0x00, b: 0xA4 }, // 03 - Color { r: 0x5C, g: 0x00, b: 0x7E }, // 04 - Color { r: 0x6E, g: 0x00, b: 0x40 }, // 05 - Color { r: 0x6C, g: 0x06, b: 0x00 }, // 06 - Color { r: 0x56, g: 0x1D, b: 0x00 }, // 07 - Color { r: 0x33, g: 0x35, b: 0x00 }, // 08 - Color { r: 0x0B, g: 0x48, b: 0x00 }, // 09 - Color { r: 0x00, g: 0x52, b: 0x00 }, // 0A - Color { r: 0x00, g: 0x4F, b: 0x08 }, // 0B - Color { r: 0x00, g: 0x40, b: 0x4D }, // 0C - Color { r: 0x00, g: 0x00, b: 0x00 }, // 0D - Color { r: 0x00, g: 0x00, b: 0x00 }, // 0E - Color { r: 0x00, g: 0x00, b: 0x00 }, // 0F - Color { r: 0xAD, g: 0xAD, b: 0xAD }, // 10 - Color { r: 0x15, g: 0x5F, b: 0xD9 }, // 11 - Color { r: 0x42, g: 0x40, b: 0xFF }, // 12 - Color { r: 0x75, g: 0x27, b: 0xFE }, // 13 - Color { r: 0xA0, g: 0x1A, b: 0xCC }, // 14 - Color { r: 0xB7, g: 0x1E, b: 0x7B }, // 15 - Color { r: 0xB5, g: 0x31, b: 0x20 }, // 16 - Color { r: 0x99, g: 0x4E, b: 0x00 }, // 17 - Color { r: 0x6B, g: 0x6D, b: 0x00 }, // 18 - Color { r: 0x38, g: 0x87, b: 0x00 }, // 19 - Color { r: 0x0C, g: 0x93, b: 0x00 }, // 1A - Color { r: 0x00, g: 0x8F, b: 0x32 }, // 1B - Color { r: 0x00, g: 0x7C, b: 0x8D }, // 1C - Color { r: 0x00, g: 0x00, b: 0x00 }, // 1D - Color { r: 0x00, g: 0x00, b: 0x00 }, // 1E - Color { r: 0x00, g: 0x00, b: 0x00 }, // 1F - Color { r: 0xFF, g: 0xFE, b: 0xFF }, // 20 - Color { r: 0x64, g: 0xB0, b: 0xFF }, // 21 - Color { r: 0x92, g: 0x90, b: 0xFF }, // 22 - Color { r: 0xC6, g: 0x76, b: 0xFF }, // 23 - Color { r: 0xF3, g: 0x6A, b: 0xFF }, // 24 - Color { r: 0xFE, g: 0x6E, b: 0xCC }, // 25 - Color { r: 0xFE, g: 0x81, b: 0x70 }, // 26 - Color { r: 0xEA, g: 0x9E, b: 0x22 }, // 27 - Color { r: 0xBC, g: 0xBE, b: 0x00 }, // 28 - Color { r: 0x88, g: 0xD8, b: 0x00 }, // 29 - Color { r: 0x5C, g: 0xE4, b: 0x30 }, // 2A - Color { r: 0x45, g: 0xE0, b: 0x82 }, // 2B - Color { r: 0x48, g: 0xCD, b: 0xDE }, // 2C - Color { r: 0x4F, g: 0x4F, b: 0x4F }, // 2D - Color { r: 0x00, g: 0x00, b: 0x00 }, // 2E - Color { r: 0x00, g: 0x00, b: 0x00 }, // 2F - Color { r: 0xFF, g: 0xFE, b: 0xFF }, // 30 - Color { r: 0xC0, g: 0xDF, b: 0xFF }, // 31 - Color { r: 0xD3, g: 0xD2, b: 0xFF }, // 32 - Color { r: 0xE8, g: 0xC8, b: 0xFF }, // 33 - Color { r: 0xFB, g: 0xC2, b: 0xFF }, // 34 - Color { r: 0xFE, g: 0xC4, b: 0xEA }, // 35 - Color { r: 0xFE, g: 0xCC, b: 0xC5 }, // 36 - Color { r: 0xF7, g: 0xD8, b: 0xA5 }, // 37 - Color { r: 0xE4, g: 0xE5, b: 0x94 }, // 38 - Color { r: 0xCF, g: 0xEF, b: 0x96 }, // 39 - Color { r: 0xBD, g: 0xF4, b: 0xAB }, // 3A - Color { r: 0xB3, g: 0xF3, b: 0xCC }, // 3B - Color { r: 0xB5, g: 0xEB, b: 0xF2 }, // 3C - Color { r: 0xB8, g: 0xB8, b: 0xB8 }, // 3D - Color { r: 0x00, g: 0x00, b: 0x00 }, // 3E - Color { r: 0x00, g: 0x00, b: 0x00 }, // 3F + Color { + r: 0x66, + g: 0x66, + b: 0x66, + }, // 00 + Color { + r: 0x00, + g: 0x2A, + b: 0x88, + }, // 01 + Color { + r: 0x14, + g: 0x12, + b: 0xA7, + }, // 02 + Color { + r: 0x3B, + g: 0x00, + b: 0xA4, + }, // 03 + Color { + r: 0x5C, + g: 0x00, + b: 0x7E, + }, // 04 + Color { + r: 0x6E, + g: 0x00, + b: 0x40, + }, // 05 + Color { + r: 0x6C, + g: 0x06, + b: 0x00, + }, // 06 + Color { + r: 0x56, + g: 0x1D, + b: 0x00, + }, // 07 + Color { + r: 0x33, + g: 0x35, + b: 0x00, + }, // 08 + Color { + r: 0x0B, + g: 0x48, + b: 0x00, + }, // 09 + Color { + r: 0x00, + g: 0x52, + b: 0x00, + }, // 0A + Color { + r: 0x00, + g: 0x4F, + b: 0x08, + }, // 0B + Color { + r: 0x00, + g: 0x40, + b: 0x4D, + }, // 0C + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 0D + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 0E + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 0F + Color { + r: 0xAD, + g: 0xAD, + b: 0xAD, + }, // 10 + Color { + r: 0x15, + g: 0x5F, + b: 0xD9, + }, // 11 + Color { + r: 0x42, + g: 0x40, + b: 0xFF, + }, // 12 + Color { + r: 0x75, + g: 0x27, + b: 0xFE, + }, // 13 + Color { + r: 0xA0, + g: 0x1A, + b: 0xCC, + }, // 14 + Color { + r: 0xB7, + g: 0x1E, + b: 0x7B, + }, // 15 + Color { + r: 0xB5, + g: 0x31, + b: 0x20, + }, // 16 + Color { + r: 0x99, + g: 0x4E, + b: 0x00, + }, // 17 + Color { + r: 0x6B, + g: 0x6D, + b: 0x00, + }, // 18 + Color { + r: 0x38, + g: 0x87, + b: 0x00, + }, // 19 + Color { + r: 0x0C, + g: 0x93, + b: 0x00, + }, // 1A + Color { + r: 0x00, + g: 0x8F, + b: 0x32, + }, // 1B + Color { + r: 0x00, + g: 0x7C, + b: 0x8D, + }, // 1C + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 1D + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 1E + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 1F + Color { + r: 0xFF, + g: 0xFE, + b: 0xFF, + }, // 20 + Color { + r: 0x64, + g: 0xB0, + b: 0xFF, + }, // 21 + Color { + r: 0x92, + g: 0x90, + b: 0xFF, + }, // 22 + Color { + r: 0xC6, + g: 0x76, + b: 0xFF, + }, // 23 + Color { + r: 0xF3, + g: 0x6A, + b: 0xFF, + }, // 24 + Color { + r: 0xFE, + g: 0x6E, + b: 0xCC, + }, // 25 + Color { + r: 0xFE, + g: 0x81, + b: 0x70, + }, // 26 + Color { + r: 0xEA, + g: 0x9E, + b: 0x22, + }, // 27 + Color { + r: 0xBC, + g: 0xBE, + b: 0x00, + }, // 28 + Color { + r: 0x88, + g: 0xD8, + b: 0x00, + }, // 29 + Color { + r: 0x5C, + g: 0xE4, + b: 0x30, + }, // 2A + Color { + r: 0x45, + g: 0xE0, + b: 0x82, + }, // 2B + Color { + r: 0x48, + g: 0xCD, + b: 0xDE, + }, // 2C + Color { + r: 0x4F, + g: 0x4F, + b: 0x4F, + }, // 2D + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 2E + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 2F + Color { + r: 0xFF, + g: 0xFE, + b: 0xFF, + }, // 30 + Color { + r: 0xC0, + g: 0xDF, + b: 0xFF, + }, // 31 + Color { + r: 0xD3, + g: 0xD2, + b: 0xFF, + }, // 32 + Color { + r: 0xE8, + g: 0xC8, + b: 0xFF, + }, // 33 + Color { + r: 0xFB, + g: 0xC2, + b: 0xFF, + }, // 34 + Color { + r: 0xFE, + g: 0xC4, + b: 0xEA, + }, // 35 + Color { + r: 0xFE, + g: 0xCC, + b: 0xC5, + }, // 36 + Color { + r: 0xF7, + g: 0xD8, + b: 0xA5, + }, // 37 + Color { + r: 0xE4, + g: 0xE5, + b: 0x94, + }, // 38 + Color { + r: 0xCF, + g: 0xEF, + b: 0x96, + }, // 39 + Color { + r: 0xBD, + g: 0xF4, + b: 0xAB, + }, // 3A + Color { + r: 0xB3, + g: 0xF3, + b: 0xCC, + }, // 3B + Color { + r: 0xB5, + g: 0xEB, + b: 0xF2, + }, // 3C + Color { + r: 0xB8, + g: 0xB8, + b: 0xB8, + }, // 3D + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 3E + Color { + r: 0x00, + g: 0x00, + b: 0x00, + }, // 3F ]; pub struct Palette { @@ -170,6 +430,13 @@ pub struct Palette { ram: [u8; 0x20], } +impl Palette { + pub fn color(&self, idx: u8) -> Color { + debug_assert!(idx < 0x20, "Palette index out of range"); + self.colors[(self.ram[idx as usize] & 0x3F) as usize] + } +} + pub struct PPU { // registers: PPURegisters, frame_count: usize, @@ -228,14 +495,9 @@ impl PPU { palette: Palette { colors: COLORS, ram: [ - 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2A, 0x2B, - 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3A, 0x3B, - 0x3C, 0x3D, 0x3E, 0x3F, + 0x09, 0x01, 0x00, 0x01, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, + 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, ], }, vblank: false, @@ -260,8 +522,12 @@ impl PPU { w: false, vram_column: false, state: BackgroundState::NameTableBytePre, + cur_high: 0, + cur_low: 0, cur_shift_high: 0, cur_shift_low: 0, + cur_nametable: 0, + cur_attr: 0, }, oam: OAM { mem: vec![0u8; 256], @@ -412,27 +678,55 @@ impl PPU { } else if self.pixel < 257 { // self.dbg_int = true; if self.scanline < 240 { + // Determine background color + let a = self.background.cur_shift_high & 0x80; + let b = self.background.cur_shift_low & 0x80; + let val = (a >> 6) | (b >> 7); + debug_assert!(val < 4); + + // Write to screen self.render_buffer.write( self.scanline, self.pixel - 1, - Color { r: 255, g: 0, b: 0 }, + self.palette.color(val) + // self.palette.colors[val as usize], ); // TODO: this should come from shift registers + self.background.cur_shift_high <<= 1; + self.background.cur_shift_low <<= 1; } self.background.state = match self.background.state { BackgroundState::NameTableByte => { // TODO: Fetch name table byte + let addr = 0x2000 + self.pixel / 8 + self.scanline / 8; + let val = self.memory.read(addr as u16).reg_map(|_, _| todo!()); + self.background.cur_nametable = val; + // self.background.v; BackgroundState::AttrTableBytePre } BackgroundState::AttrTableByte => { // TODO: Fetch attr table byte + // let addr = 0x2000 + self.pixel / 8 + self.scanline / 8; + // let val = self.memory.read(addr as u16).reg_map(|_, _| todo!()); + // self.background.cur_attr = val; BackgroundState::PatternTableTileLowPre } BackgroundState::PatternTableTileLow => { // TODO: Fetch + let addr = self.background.cur_nametable as u16 * 16 + + (self.scanline % 8) as u16; + let val = self.memory.read(addr).reg_map(|_, _| todo!()); + self.background.cur_low = val; BackgroundState::PatternTableTileHighPre } BackgroundState::PatternTableTileHigh => { // TODO: Fetch + let addr = self.background.cur_nametable as u16 * 16 + + 8 + + (self.scanline % 8) as u16; + let val = self.memory.read(addr).reg_map(|_, _| todo!()); + self.background.cur_high = val; + self.background.cur_shift_low = self.background.cur_low; + self.background.cur_shift_high = self.background.cur_high; BackgroundState::NameTableBytePre } BackgroundState::NameTableBytePre => BackgroundState::NameTableByte, @@ -523,7 +817,7 @@ impl PPU { let high = self.memory.peek(name + y_off + 8).unwrap(); for bit in 0..8 { frame.fill_rectangle( - Point::new( + Point::new( x as f32 * 8. + 8. - bit as f32, y as f32 * 8. + y_off as f32, ), @@ -598,7 +892,7 @@ impl PPU { frame.fill_rectangle( Point::new(x as f32 * 10., y as f32 * 10.), Size::new(10., 10.), - self.palette.colors[(self.palette.ram[x + y * 4] & 0x3F) as usize] + self.palette.colors[(self.palette.ram[x + y * 4] & 0x3F) as usize], ); } }