diff --git a/src/core/bus.rs b/src/core/bus.rs index 3784007..514fb4c 100644 --- a/src/core/bus.rs +++ b/src/core/bus.rs @@ -6,6 +6,7 @@ use crate::core::pad::{ Pad, Key }; use crate::core::ppu::*; use crate::core::hram::HRam; use crate::core::apu::Apu; +use crate::core::timer::Timer; use std::path::Path; @@ -20,6 +21,7 @@ pub struct Bus { apu: Apu, interrupt: Interrupt, pad: Pad, + pub timer: Timer, } impl Bus { @@ -32,6 +34,7 @@ impl Bus { apu: Apu::new(), interrupt: Interrupt::new(), pad: Pad::new(), + timer: Timer::new(), } } @@ -44,6 +47,7 @@ impl Bus { apu: Apu::new(), interrupt: Interrupt::new(), pad: Pad::new(), + timer: Timer::new(), } } @@ -112,6 +116,9 @@ impl Bus { }, _ => (), } + if self.timer.tick() { + self.interrupt.set_irq(InterruptKind::Timer); + }; } } @@ -137,6 +144,8 @@ impl Io for Bus { // I/O ports 0xFF00 => self.pad.read8(), // 0xFF00 ..= 0xFF3B => self.ioports.read8(addr), + // Timer + 0xFF04 ..= 0xFF07 => self.timer.read8(addr), // Interrupt Flag Register 0xFF0F => self.interrupt.read8(addr), // LCD Registers @@ -170,7 +179,9 @@ impl Io for Bus { // Empty but unusable for I/O 0xFEA0 ..= 0xFEFF => (), // I/O ports - 0xFF00 => self.pad.write8(data), + 0xFF00 => self.pad.write8(data), + // Timer + 0xFF04 ..= 0xFF07 => self.timer.write8(addr, data), // Sound Channel 1 - Tone & Sweep 0xFF10 ..= 0xFF14 | // Sound Channel 2 - Tone diff --git a/src/core/cpu.rs b/src/core/cpu.rs index 53f6425..c2a4a46 100644 --- a/src/core/cpu.rs +++ b/src/core/cpu.rs @@ -29,6 +29,7 @@ pub struct Cpu { sp: u16, pc: u16, bus: Bus, + halt: bool, debug: bool, } @@ -53,10 +54,11 @@ impl Cpu { c: 0x13, e: 0xD8, l: 0x4D, - f: Flags::Z | Flags::N | Flags::H | Flags::C, + f: Flags::from_bits_truncate(0xB0), sp: 0xFFFE, pc: 0x100, bus: Bus::no_cartridge(), + halt: false, debug: false, } } @@ -70,10 +72,11 @@ impl Cpu { c: 0x13, e: 0xD8, l: 0x4D, - f: Flags::Z | Flags::N | Flags::H | Flags::C, + f: Flags::from_bits_truncate(0xB0), sp: 0xFFFE, pc: 0x100, bus: Bus::from_path(path), + halt: false, debug: false, } } @@ -98,17 +101,12 @@ impl Cpu { } fn step(&mut self) { - // if self.pc == 0x0150 { - // println!("break"); - // self.debug = true; - // } - // if self.debug { - // use std::io::stdin; - // let mut input = String::new(); - // stdin().read_line(&mut input).unwrap(); - // println!("{}", self); - // } - + if self.halt { + if self.bus.has_irq() { + self.halt = false; + } + return; + } if self.bus.has_irq() && self.bus.is_enabled_irq() { self.resolve_irq(); return; @@ -119,15 +117,15 @@ impl Cpu { } fn resolve_irq(&mut self) { + let pc = self.pc; + self.push((pc>>8) as u8); + self.push((pc&0xFF) as u8); + let addr = self.bus.isr_addr(); if addr == None { return; } - let pc = self.pc; - self.push((pc>>8) as u8); - self.push((pc&0xFF) as u8); - self.pc = addr.unwrap() as u16; self.bus.disable_irq(); } @@ -1629,8 +1627,8 @@ impl Cpu { name: "HALT", opcode: 0x76, cycles: 4, - operation: |_| { - // TODO + operation: |cpu| { + cpu.halt = true; Ok(()) }, }, diff --git a/src/core/interrupt.rs b/src/core/interrupt.rs index f693578..212cdea 100644 --- a/src/core/interrupt.rs +++ b/src/core/interrupt.rs @@ -31,6 +31,7 @@ const TIMER_ISR_ADDR: usize = 0x0050; const SERIAL_ISR_ADDR: usize = 0x0058; const JOYPAD_ISR_ADDR: usize = 0x0060; +#[derive(Debug)] pub enum InterruptKind { Vblank, LcdcStatus, diff --git a/src/core/mod.rs b/src/core/mod.rs index 77a2b25..40fe2a5 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -8,4 +8,5 @@ pub mod pad; pub mod ppu; pub mod hram; pub mod apu; -pub mod mbc; \ No newline at end of file +pub mod mbc; +pub mod timer; \ No newline at end of file diff --git a/src/core/pad.rs b/src/core/pad.rs index 87683f0..8507146 100644 --- a/src/core/pad.rs +++ b/src/core/pad.rs @@ -1,8 +1,6 @@ #[macro_use] use bitflags::*; -use std::fmt; - bitflags!{ struct P1: u8 { const P15 = 0b00100000; @@ -11,10 +9,23 @@ bitflags!{ const P12 = 0b00000100; const P11 = 0b00000010; const P10 = 0b00000001; - const NONE = 0b00000000; } } +bitflags!{ + struct KeyState: u8 { + const START = 0b10000000; + const SELECT = 0b01000000; + const B = 0b00100000; + const A = 0b00010000; + const DOWN = 0b00001000; + const UP = 0b00000100; + const LEFT = 0b00000010; + const RIGHT = 0b00000001; + } +} + +#[derive(Debug)] pub enum Key { Right, Left, @@ -28,53 +39,60 @@ pub enum Key { pub struct Pad { register: P1, -} - -impl fmt::Display for Pad { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Pad {{ 0b{:08b} }}", self.register) - } + state: KeyState, } impl Pad { pub fn new() -> Self { Pad { - register: P1::P15 | P1::P14 | P1::P13 | P1::P12 | P1::P11 | P1::P10, + register: P1::P13 | P1::P12 | P1::P11 | P1::P10, + state: KeyState::A | KeyState::B | + KeyState::SELECT | KeyState::START | + KeyState::RIGHT | KeyState::LEFT | + KeyState::UP | KeyState::DOWN, } } pub fn read8(&self) -> u8 { - self.register.bits() + if !self.register.contains(P1::P15) { + return self.register.bits() & 0xF0 | (self.state.bits() >> 4) & 0x0F; + } + + if !self.register.contains(P1::P14) { + return self.register.bits() & 0xF0 | self.state.bits() & 0x0F; + } + + self.register.bits() & 0x0F } pub fn write8(&mut self, data: u8) { self.register = P1::from_bits_truncate(data); } - fn _update(&mut self) { - if self.register.contains(P1::P14) | self.register.contains(P1::P15) { - self.register.insert(P1::P10 | P1::P11 | P1::P12 | P1::P13); - } - } - pub fn push_key(&mut self, key: Key) { match key { - Key::Right | Key::A => self.register.remove(P1::P10), - Key::Left | Key::B => self.register.remove(P1::P11), - Key::Up | Key::Select => self.register.remove(P1::P12), - Key::Down | Key::Start => self.register.remove(P1::P13), + Key::Right => self.state.remove(KeyState::RIGHT), + Key::A => self.state.remove(KeyState::A), + Key::Left => self.state.remove(KeyState::LEFT), + Key::B => self.state.remove(KeyState::B), + Key::Up => self.state.remove(KeyState::UP), + Key::Select => self.state.remove(KeyState::SELECT), + Key::Down => self.state.remove(KeyState::DOWN), + Key::Start => self.state.remove(KeyState::START), } - // self.update(); } pub fn release_key(&mut self, key: Key) { match key { - Key::Right | Key::A => self.register.insert(P1::P10), - Key::Left | Key::B => self.register.insert(P1::P11), - Key::Up | Key::Select => self.register.insert(P1::P12), - Key::Down | Key::Start => self.register.insert(P1::P13), + Key::Right => self.state.insert(KeyState::RIGHT), + Key::A => self.state.insert(KeyState::A), + Key::Left => self.state.insert(KeyState::LEFT), + Key::B => self.state.insert(KeyState::B), + Key::Up => self.state.insert(KeyState::UP), + Key::Select => self.state.insert(KeyState::SELECT), + Key::Down => self.state.insert(KeyState::DOWN), + Key::Start => self.state.insert(KeyState::START), } - // self.update(); } } \ No newline at end of file diff --git a/src/core/ppu.rs b/src/core/ppu.rs index e95e5de..7431d87 100644 --- a/src/core/ppu.rs +++ b/src/core/ppu.rs @@ -190,8 +190,8 @@ impl Io for Ppu { self.oam_dma_started = true; }, 0xFF47 => self.bgp = Bgp::from(data), - 0xFF48 => self.obp0 = 0, - 0xFF49 => self.obp1 = 0, + 0xFF48 => self.obp0 = 0xFF, + 0xFF49 => self.obp1 = 0xFF, 0xFF4A => self.wy = data, 0xFF4B => self.wx = data, // ToDo: LCD Color Palettes (CGB only) @@ -242,15 +242,15 @@ impl Ppu { let mut lcdc_irq = false; if self.clock >= CYCLE_PER_LINE { - vblank_irq = true; if self.ly == SCREEN_HEIGHT as u8 { + vblank_irq = true; self.build_sprite(); if self.stat.contains(Stat::INTR_LYC) { lcdc_irq = true; } } else if self.ly >= SCREEN_HEIGHT as u8 + LCD_BLANK_HEIGHT { self.ly = 0; - // self.build_bg(); + self.build_bg(); } else if self.ly < SCREEN_HEIGHT as u8 { self.build_bg(); // if self.window_enabled() { diff --git a/src/core/timer.rs b/src/core/timer.rs new file mode 100644 index 0000000..84fd63d --- /dev/null +++ b/src/core/timer.rs @@ -0,0 +1,111 @@ +#[macro_use] +use bitflags::*; + +use crate::core::io::Io; + +bitflags! { + struct Tac: u8 { + const TIMER_EN = 0b00000100; + const CLK_SEL1 = 0b00000010; + const CLK_SEL0 = 0b00000001; + } +} + +const TAC00_DIV: u16 = 1024; +const TAC01_DIV: u16 = 16; +const TAC10_DIV: u16 = 64; +const TAC11_DIV: u16 = 256; +const DIV: u16 = 256; + +#[derive(Debug)] +pub struct Timer { + div: u8, + tima: u8, + tma: u8, + tac: Tac, + count: u16 +} + +impl Timer { + pub fn new() -> Self { + Timer { + div: 0, + tima: 0, + tma: 0, + tac: Tac::empty(), + count: 0, + } + } + + pub fn tick(&mut self) -> bool { + let mut overflow = false; + self.count = self.count.wrapping_add(1); + if self.tac.contains(Tac::TIMER_EN) { + match self.tac.bits() & 0b11 { + 0b00 => { + if self.count % TAC00_DIV == 0 { + self.tima = self.tima.wrapping_add(1); + if self.tima == 0 { + self.tima = self.tma; + overflow = true; + } + } + }, + 0b10 => { + if self.count % TAC01_DIV == 0 { + self.tima = self.tima.wrapping_add(1); + if self.tima == 0 { + self.tima = self.tma; + overflow = true; + } + } + }, + 0b01 => { + if self.count % TAC10_DIV == 0 { + self.tima = self.tima.wrapping_add(1); + if self.tima == 0 { + self.tima = self.tma; + overflow = true; + } + } + }, + 0b11 => { + if self.count % TAC11_DIV == 0 { + self.tima = self.tima.wrapping_add(1); + if self.tima == 0 { + self.tima = self.tma; + overflow = true; + } + } + }, + _ => panic!(), + } + } + if self.count % DIV == 0 { self.div = self.div.wrapping_add(1); } + + overflow + } + +} + +impl Io for Timer { + fn read8(&self, addr: usize) -> u8 { + match addr { + 0xFF04 => self.div, + 0xFF05 => self.tima, + 0xFF06 => self.tma, + 0xFF07 => self.tac.bits(), + _ => panic!("can't read from: {:04x}", addr), + } + } + + fn write8(&mut self, addr: usize, data: u8) { + match addr { + 0xFF04 => self.div = 0, + 0xFF05 => self.tima = data, + 0xFF06 => self.tma = data, + 0xFF07 => self.tac = Tac::from_bits_truncate(data), + _ => panic!("can't write to: {:04x}", addr), + } + } +} \ No newline at end of file diff --git a/src/gui/window.rs b/src/gui/window.rs index 747bf0f..79eeacf 100644 --- a/src/gui/window.rs +++ b/src/gui/window.rs @@ -103,9 +103,6 @@ impl EventHandler for MainWindow { keymod: KeyMods, repeat: bool ) { - println!("Key pressed: {:?}, modifier {:?}, repeat: {}", - keycode, keymod, repeat); - match keycode { KeyCode::Left => self.cpu.push_key(Key::Left), KeyCode::Right => self.cpu.push_key(Key::Right), @@ -145,7 +142,7 @@ impl EventHandler for MainWindow { pub fn run(path: &Path) { let (mut ctx, mut event_loop) = ContextBuilder::new("GBR", "Noboru") - .window_setup(ggez::conf::WindowSetup::default().vsync(true)) + .window_setup(ggez::conf::WindowSetup::default().vsync(false)) .window_mode(ggez::conf::WindowMode::default().dimensions(SCREEN_WIDTH as f32, SCREEN_HEIGHT as f32)) .build() .unwrap();