diff --git a/src/cpu.rs b/src/cpu.rs index 082ba62..c98fc06 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -11,8 +11,8 @@ pub struct CPU { } impl CPU { - pub fn new(mode: GBMode, rom: Vec) -> CPU { - CPU { + pub fn new(mode: GBMode, rom: Vec) -> Self { + Self { reg: Registers::new(mode), mem: MMU::new(rom), halted: false, diff --git a/src/gpu.rs b/src/gpu.rs new file mode 100644 index 0000000..79285ae --- /dev/null +++ b/src/gpu.rs @@ -0,0 +1,97 @@ +use bitflags::{bitflags, Flags}; + +pub const SCREEN_W: usize = 160; +pub const SCREEN_H: usize = 144; + +pub struct GPU { + sy: u8, + sx: u8, + ly: u8, + lyc: u8, + wy: u8, + wx: u8, + lcdc: LCDC, + lcds: LCDS, + ram: [u8; 0x4000] +} + +bitflags! { + pub struct LCDC: u8 { + // LCD & PPU enable: 0 = Off; 1 = On + const LCD_ENABLE = 0b1000_0000; + // Window tile map area: 0 = 9800–9BFF; 1 = 9C00–9FFF + const WINDOW_AREA = 0b0100_0000; + // Window enable: 0 = Off; 1 = On + const WINDOW_ENABLE = 0b0010_0000; + // BG & Window tile data area: 0 = 8800–97FF; 1 = 8000–8FFF + const TILE_DATA_AREA = 0b0001_0000; + // BG tile map area: 0 = 9800–9BFF; 1 = 9C00–9FFF + const TILE_MAP_AREA = 0b0000_1000; + // OBJ size: 0 = 8×8; 1 = 8×16 + const OBJ_SIZE = 0b0000_01000; + // OBJ enable: 0 = Off; 1 = On + const OBJ_ENABLE = 0b0000_0010; + // BG & Window enable (GB) / priority (CGB): 0 = Off; 1 = On + const WINDOW_PRIORITY = 0b0000_0001; + } +} + +bitflags! { + pub struct LCDS: u8 { + // LYC int select (Read/Write): If set, selects the LYC == LY condition for the STAT interrupt. + const LYC_SELECT = 0b0100_0000; + // Mode 2 int select (Read/Write): If set, selects the Mode 2 condition for the STAT interrupt. + const MODE_2_SELECT = 0b0010_0000; + // Mode 1 int select (Read/Write): If set, selects the Mode 1 condition for the STAT interrupt. + const MODE_1_SELECT = 0b0001_0000; + // Mode 0 int select (Read/Write): If set, selects the Mode 0 condition for the STAT interrupt. + const MODE_0_SELECT = 0b0000_1000; + // LYC == LY (Read-only): Set when LY contains the same value as LYC; it is constantly updated. + const LYC_EQUALS = 0b0000_0100; + // PPU mode (Read-only): Indicates the PPU’s current status. + } +} +impl GPU { + pub fn new() -> Self { + Self { + sy: 0, + sx: 0, + ly: 0, + lyc: 0, + wy: 0, + wx: 0, + lcdc: LCDC::empty(), + lcds: LCDS::empty(), + ram: [0; 0x4000] + } + } + + pub fn read(&self, a: u16) -> u8 { + match a { + 0xFF40 => self.lcdc.bits(), + 0xFF41 => self.lcds.bits(), + 0xFF42 => self.sy, + 0xFF43 => self.sx, + 0xFF44 => self.ly, + 0xFF45 => self.lyc, + 0xFF4A => self.wy, + 0xFF4B => self.wx, + _ => 0x00, + } + } + + pub fn write(&mut self, a: u16, v: u8) { + match a { + 0xFF40 => self.lcdc = LCDC::from_bits(v).unwrap(), + // TODO: Don't allow read-only bits to be set! + 0xFF41 => self.lcds = LCDS::from_bits(v).unwrap(), + 0xFF42 => self.sy = v, + 0xFF43 => self.sx = v, + 0xFF44 => print!("Attempted to write to LY!"), + 0xFF45 => self.lyc = v, + 0xFF4A => self.wy = v, + 0xFF4B => self.wx = v, + _ => {}, + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 11a1098..0c965e8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,7 @@ mod cpu; mod mmu; mod mode; mod registers; +mod gpu; #[derive(Parser)] struct Args { diff --git a/src/mmu.rs b/src/mmu.rs index e8bde96..a1e1645 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -1,6 +1,8 @@ +use crate::gpu::GPU; + pub struct MMU { rom: Vec, - gpu: [u8; 0x2000], + gpu: GPU, wram: [u8; 0x8000], hram: [u8; 0x7F], interrupt: u8, @@ -8,10 +10,10 @@ pub struct MMU { } impl MMU { - pub fn new(rom: Vec) -> MMU { - MMU { + pub fn new(rom: Vec) -> Self { + Self { rom, - gpu: [0; 0x2000], + gpu: GPU::new(), wram: [0; 0x8000], hram: [0; 0x7f], interrupt: 0, @@ -22,11 +24,12 @@ impl MMU { pub fn read(&self, a: u16) -> u8 { match a { 0x0000..=0x7FFF => self.rom[a as usize], - 0x8000..=0x9FFF => self.gpu[a as usize - 0x8000], + 0x8000..=0x9FFF => self.gpu.read(a), 0xC000..=0xCFFF => self.wram[a as usize - 0xC000], 0xD000..=0xDFFF => self.wram[a as usize - 0xD000 + 0x1000 * self.wram_bank], 0xE000..=0xEFFF => self.wram[a as usize - 0xE000], 0xF000..=0xFDFF => self.wram[a as usize - 0xF000 + 0x1000 * self.wram_bank], + 0xFF40..=0xFF4F => self.gpu.read(a), 0xFF80..=0xFFFE => self.hram[a as usize - 0xFF80], 0xFFFF => self.interrupt, _ => 0x00, @@ -36,11 +39,12 @@ impl MMU { pub fn write(&mut self, a: u16, v: u8) { match a { 0x0000..=0x7FFF => self.rom[a as usize] = v, - 0x8000..=0x9FFF => self.gpu[a as usize - 0x8000] = v, + 0x8000..=0x9FFF => self.gpu.write(a, v), 0xC000..=0xCFFF => self.wram[a as usize - 0xC000] = v, 0xD000..=0xDFFF => self.wram[a as usize - 0xD000 + 0x1000 * self.wram_bank] = v, 0xE000..=0xEFFF => self.wram[a as usize - 0xE000] = v, 0xF000..=0xFDFF => self.wram[a as usize - 0xF000 + 0x1000 * self.wram_bank] = v, + 0xFF40..=0xFF4F => self.gpu.write(a, v), 0xFF80..=0xFFFE => self.hram[a as usize - 0xFF80] = v, 0xFFFF => self.interrupt = v, _ => {},