diff --git a/src/bus.rs b/src/bus.rs index c552dae..a480ee0 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -57,7 +57,8 @@ pub struct Bus { impl Bus { pub fn new() -> Self { - let game_rom = match ROM::load_file("ignore/metroid-2.gb".to_string()) { + let game_rom = match ROM::load_file("/home/fran/Development/Personal/Rust/rmg-001/ignore/mario-land.gb".to_string()) { + // let game_rom = match ROM::load_file("ignore/mario-land.gb".to_string()) { // let game_rom = match ROM::load_file("ignore/mooneye/emulator-only/mbc1/bits_bank1.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.gb".to_string()) { diff --git a/src/cpu.rs b/src/cpu.rs index 3146f15..730f863 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -844,6 +844,7 @@ pub struct CPU { is_halted: bool, ime: bool, // Interrupt Master Enable ei_delay: bool, + enable_logs: bool, } impl CPU { @@ -856,6 +857,7 @@ impl CPU { is_halted: false, ei_delay: false, ime: true, + enable_logs: !env::var("CPU_LOG").is_err(), } } @@ -953,7 +955,7 @@ impl CPU { let program_counter = self.registers.get(Register::PC); let parameter_bytes = OpcodeParameterBytes::from_address(program_counter, bus); let (opcode, cycles) = parameter_bytes.parse_opcode(); - if !env::var("CPU_LOG").is_err() { + if self.enable_logs { self.log(parameter_bytes); self.increment_exec_calls_count(); } diff --git a/src/emulator.rs b/src/emulator.rs index 56d4807..2b7199a 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -106,7 +106,7 @@ impl Emulator { self.timer.reset(&mut self.bus); } self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles().to_t(), frame_buffer); - self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); + self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles().to_t()); // 1 CPU cycle = 238.42ns // thread::sleep(time::Duration::from_nanos((self.cpu.get_last_op_cycles().0 * 238).try_into().unwrap())); @@ -116,7 +116,7 @@ impl Emulator { pub fn cpu_loop(&mut self) { let mut exit = false; - let mut frame: [u8; 144 * 160] = [0; 144 * 160]; + let mut frame: [u8; 144 * 160 * 4] = [0; 144 * 160 * 4]; while !exit { self.cpu.run(&mut self.bus); if self.bus.reset_timer { @@ -124,7 +124,7 @@ impl Emulator { self.timer.reset(&mut self.bus); } self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles().to_t(), &mut frame); - self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); + self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles().to_t()); // exit = self.cpu.get_exec_calls_count() >= 1258895; // log 1 exit = self.cpu.get_exec_calls_count() >= 161502; // log 2 diff --git a/src/ppu.rs b/src/ppu.rs index 5f621be..9e55cab 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -167,6 +167,7 @@ pub struct PPU { sprite_buffer: Vec, window_y_counter: u8, last_bg_index: u8, + lcd_control_cache: Option, } impl PPU { @@ -177,6 +178,7 @@ impl PPU { sprite_buffer: Vec::new(), window_y_counter: 0, last_bg_index: 0, + lcd_control_cache: None, } } @@ -189,7 +191,8 @@ impl PPU { } pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles, frame_buffer: &mut [u8]) { - if !PPU::get_lcd_control(bus, LCDControl::LCDEnable) { + self.lcd_control_cache = None; + if !self.get_lcd_control(bus, LCDControl::LCDEnable) { self.increment_cycles(cycles); return; } @@ -269,10 +272,10 @@ impl PPU { fn oam_search(&mut self, bus: &Bus) { self.sprite_buffer = Vec::new(); - if !PPU::get_lcd_control(bus, LCDControl::ObjectEnable) { + if !self.get_lcd_control(bus, LCDControl::ObjectEnable) { return; } - let long_sprites = PPU::get_lcd_control(bus, LCDControl::ObjectSize); + let long_sprites = self.get_lcd_control(bus, LCDControl::ObjectSize); let mut addr = SPRITE_ATTRIBUTE_TABLE.begin(); while addr <= SPRITE_ATTRIBUTE_TABLE.end() { // The gameboy only supports 10 sprites per line, @@ -356,8 +359,15 @@ impl PPU { bus.read(WINDOW_Y_ADDRESS) } - pub fn get_lcd_control(bus: &Bus, control: LCDControl) -> bool { - let byte = bus.read(LCD_CONTROL_ADDRESS); + pub fn get_lcd_control(&mut self, bus: &Bus, control: LCDControl) -> bool { + let byte = match self.lcd_control_cache { + Some(byte) => byte, + None => { + let byte = bus.read(LCD_CONTROL_ADDRESS); + self.lcd_control_cache = Some(byte); + byte + }, + }; control.get(byte) } @@ -420,7 +430,7 @@ impl PPU { let window_y = PPU::get_window_y(bus); if - !PPU::get_lcd_control(bus, LCDControl::WindowEnable) || + !self.get_lcd_control(bus, LCDControl::WindowEnable) || lcd_x < window_x.saturating_sub(7) || lcd_y < window_y || window_y >= 144 || @@ -432,8 +442,8 @@ impl PPU { let x = lcd_x.wrapping_sub(window_x.saturating_sub(7)); let y = self.window_y_counter; - let default_mode = PPU::get_lcd_control(bus, LCDControl::TileAddressMode); - let tilemap_area = match PPU::get_lcd_control(bus, LCDControl::WindowTileMapAddress) { + let default_mode = self.get_lcd_control(bus, LCDControl::TileAddressMode); + let tilemap_area = match self.get_lcd_control(bus, LCDControl::WindowTileMapAddress) { true => 0x9C00, false => 0x9800, }; @@ -448,7 +458,7 @@ impl PPU { } fn get_background_pixel(&mut self, lcd_x: u8, bus: &Bus) -> Option { - if !PPU::get_lcd_control(bus, LCDControl::BackgroundPriority) { + if !self.get_lcd_control(bus, LCDControl::BackgroundPriority) { return None; } let lcd_y = PPU::get_lcd_y(bus); @@ -456,8 +466,8 @@ impl PPU { let y = lcd_y.wrapping_add(PPU::get_scroll_y(bus)); let x = lcd_x.wrapping_add(PPU::get_scroll_x(bus)); - let default_mode = PPU::get_lcd_control(bus, LCDControl::TileAddressMode); - let tilemap_area = match PPU::get_lcd_control(bus, LCDControl::BackgroundTileMapAddress) { + let default_mode = self.get_lcd_control(bus, LCDControl::TileAddressMode); + let tilemap_area = match self.get_lcd_control(bus, LCDControl::BackgroundTileMapAddress) { true => 0x9C00, false => 0x9800, }; diff --git a/src/render.rs b/src/render.rs index 544876b..1067bb4 100644 --- a/src/render.rs +++ b/src/render.rs @@ -66,7 +66,7 @@ pub fn start_eventloop() { Event::MainEventsCleared => { emulator.run(Cycles(70224), pixels.get_frame()); - thread::sleep(time::Duration::from_millis(1)); + // thread::sleep(time::Duration::from_millis(1)); window.request_redraw(); }, Event::RedrawRequested(_) => { diff --git a/src/timer.rs b/src/timer.rs index f326253..8502807 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -31,15 +31,15 @@ impl Timer { pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles) { let mut count = 0; - while count < cycles.to_t().0 { + while count < cycles.0 { self.cycle(bus); count += 1; } + bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, self.divider.to_be_bytes()[0]); } fn cycle(&mut self, bus: &mut Bus) { self.divider = self.divider.wrapping_add(1); - bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, self.divider.to_be_bytes()[0]); let result = Timer::is_timer_enabled(bus) && self.get_tima_rate(bus);