Skip to content
Snippets Groups Projects
Verified Commit 4ca8872c authored by João Magalhães's avatar João Magalhães :rocket:
Browse files

feat: initial int and DMA support

parent d41afb79
No related branches found
No related tags found
No related merge requests found
Pipeline #893 passed
......@@ -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 {
......
......@@ -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;
}
}
......@@ -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);
}
......
......@@ -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 {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment