diff --git a/examples/sdl/src/main.rs b/examples/sdl/src/main.rs index 584239cb788ae2206d9d2c51ca1fc50e1199a912..e2de571ce8d1a106c96d71e2644c62b0a00476bd 100644 --- a/examples/sdl/src/main.rs +++ b/examples/sdl/src/main.rs @@ -83,7 +83,7 @@ fn main() { let mut game_boy = GameBoy::new(); game_boy.load_boot_dmg_bootix(); - //game_boy.load_rom_file("../../res/roms.prop/tetris.gb"); + game_boy.load_rom_file("../../res/roms.prop/tetris.gb"); //game_boy.load_rom_file("../../res/roms.prop/alleyway.gb"); //game_boy.load_rom_file("../../res/roms/firstwhite.gb"); @@ -97,7 +97,7 @@ fn main() { //game_boy.load_rom_file("../../res/roms/paradius/cpu/06-ld r,r.gb"); // PASSED //game_boy.load_rom_file("../../res/roms/paradius/cpu/07-jr,jp,call,ret,rst.gb"); // PASSED //game_boy.load_rom_file("../../res/roms/paradius/cpu/08-misc instrs.gb"); // PASSED - game_boy.load_rom_file("../../res/roms/paradius/cpu/09-op r,r.gb"); // NO FINISH + //game_boy.load_rom_file("../../res/roms/paradius/cpu/09-op r,r.gb"); // NO FINISH //game_boy.load_rom_file("../../res/roms/paradius/cpu/11-op a,(hl).gb"); // NO FINISH 'main: loop { diff --git a/src/cpu.rs b/src/cpu.rs index ceed42e7a000b49bae2acf29fb157ae185ddf76f..794c1364b4eb85323e468c3de7c2041aef46a739 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -18,6 +18,7 @@ pub struct Cpu { pub e: u8, pub h: u8, pub l: u8, + ime: bool, zero: bool, sub: bool, half_carry: bool, @@ -65,6 +66,7 @@ impl Cpu { e: 0x0, h: 0x0, l: 0x0, + ime: false, zero: false, sub: false, half_carry: false, @@ -90,6 +92,19 @@ impl Cpu { panic!("Invalid PC area at 0x{:04x}", pc); } + if self.ime { + // @todo aggregate all of this interrupts in the MMU + if self.mmu.ppu().int_vblank() { + println!("VAI FAZER HANDLING VBLANK"); + let pc = self.pc; + self.disable_int(); + self.push_word(pc); + self.pc = 0x40; + self.mmu.ppu().ack_vblank(); + return 16; + } + } + // fetches the current instruction and increments // the PC (program counter) accordingly let mut opcode = self.mmu.read(self.pc); @@ -313,11 +328,11 @@ impl Cpu { #[inline(always)] pub fn enable_int(&mut self) { - // @todo implement this one + self.ime = true; } #[inline(always)] pub fn disable_int(&mut self) { - // @todo implement this one + self.ime = false; } } diff --git a/src/mmu.rs b/src/mmu.rs index 2d9ace7f3ddcb2dad4deceb1a4297ac7b719ae3d..770a651b261de52a1a2fdd5f0e0a5040c76ab934 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -152,7 +152,17 @@ impl Mmu { _ => println!("Writing to unknown IO control 0x{:04x}", addr), }, 0x40 | 0x60 | 0x70 => { - self.ppu.write(addr, value); + match addr & 0x00ff { + 0x0046 => { + // @todo must increment the cycle count by 160 + // and make this a separated dma.rs file + println!("GOING TO START DMA transfer to 0x{:x}00", value); + let data = self.read_many((value as u16) << 8, 160); + self.write_many(0xfe00, &data); + println!("FINISHED DMA transfer") + } + _ => self.ppu.write(addr, value), + } } 0x50 => match addr & 0x00ff { 0x50 => self.boot_active = false, @@ -168,6 +178,23 @@ impl Mmu { } } + pub fn write_many(&mut self, addr: u16, data: &Vec<u8>) { + for index in 0..data.len() { + self.write(addr + index as u16, data[index]) + } + } + + pub fn read_many(&mut self, addr: u16, count: u16) -> Vec<u8> { + let mut data: Vec<u8> = vec![]; + + for index in 0..count { + let byte = self.read(addr + index); + data.push(byte); + } + + return data; + } + pub fn write_boot(&mut self, addr: u16, buffer: &[u8]) { self.boot[addr as usize..addr as usize + buffer.len()].clone_from_slice(buffer); } diff --git a/src/ppu.rs b/src/ppu.rs index d8110299bfd678fd5d094c1d42fb4831d2af8563..a42bd364ade444470de6f92f705e8851496a7839 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -84,6 +84,8 @@ pub struct Ppu { bg_tile: bool, // Controls if the window is meant to be drawn. switch_window: bool, + // Controls the offset of the map that is going to be drawn + // for the window section of the screen. window_map: bool, /// Flag that controls if the LCD screen is ON and displaying /// content. @@ -92,6 +94,9 @@ pub struct Ppu { stat_vblank: bool, stat_oam: bool, stat_lyc: bool, + // Boolean value set when the V-Blank interrupt should be handled + // by the next CPU clock. + int_vblank: bool, } #[derive(Clone, Copy, PartialEq)] @@ -130,6 +135,7 @@ impl Ppu { stat_vblank: false, stat_oam: false, stat_lyc: false, + int_vblank: false, } } @@ -166,6 +172,7 @@ impl Ppu { // in case we've reached the end of the // screen we're now entering the v-blank if self.ly == 144 { + self.int_vblank = true; self.mode = PpuMode::VBlank; // self.drawData // @todo implement this one @@ -289,6 +296,33 @@ impl Ppu { } } + pub fn fill_frame_buffer(&mut self, color: Pixel) { + for index in (0..self.frame_buffer.len()).step_by(RGB_SIZE) { + self.frame_buffer[index] = color[0]; + self.frame_buffer[index + 1] = color[1]; + self.frame_buffer[index + 2] = color[2]; + } + } + + pub fn int_vblank(&self) -> bool { + self.int_vblank + } + + pub fn ack_vblank(&mut self) { + self.int_vblank = false; + } + + /// Prints the tile data information to the stdout, this is + /// useful for debugging purposes. + pub fn draw_tile_stdout(&self, tile_index: usize) { + for y in 0..8 { + for x in 0..8 { + print!("{}", self.tiles[tile_index][y as usize][x as usize]); + } + print!("\n"); + } + } + /// Updates the tile structure with the value that has /// just been written to a location on the VRAM associated /// with tiles. @@ -378,25 +412,6 @@ impl Ppu { } } - pub fn fill_frame_buffer(&mut self, color: Pixel) { - for index in (0..self.frame_buffer.len()).step_by(RGB_SIZE) { - self.frame_buffer[index] = color[0]; - self.frame_buffer[index + 1] = color[1]; - self.frame_buffer[index + 2] = color[2]; - } - } - - /// Prints the tile data information to the stdout, this is - /// useful for debugging purposes. - pub fn draw_tile_stdout(&self, tile_index: usize) { - for y in 0..8 { - for x in 0..8 { - print!("{}", self.tiles[tile_index][y as usize][x as usize]); - } - print!("\n"); - } - } - /// Obtains the current level of the LCD interrupt by /// checking the current PPU state in various sections. fn interrupt_level(&self) -> bool {