Optimizations

This commit is contained in:
Franco Colmenarez 2021-11-10 20:57:58 -05:00
parent 2fc82faef6
commit 0ce0c11488
6 changed files with 32 additions and 19 deletions

View File

@ -57,7 +57,8 @@ pub struct Bus {
impl Bus { impl Bus {
pub fn new() -> Self { 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("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.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.gb".to_string()) {

View File

@ -844,6 +844,7 @@ pub struct CPU {
is_halted: bool, is_halted: bool,
ime: bool, // Interrupt Master Enable ime: bool, // Interrupt Master Enable
ei_delay: bool, ei_delay: bool,
enable_logs: bool,
} }
impl CPU { impl CPU {
@ -856,6 +857,7 @@ impl CPU {
is_halted: false, is_halted: false,
ei_delay: false, ei_delay: false,
ime: true, 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 program_counter = self.registers.get(Register::PC);
let parameter_bytes = OpcodeParameterBytes::from_address(program_counter, bus); let parameter_bytes = OpcodeParameterBytes::from_address(program_counter, bus);
let (opcode, cycles) = parameter_bytes.parse_opcode(); let (opcode, cycles) = parameter_bytes.parse_opcode();
if !env::var("CPU_LOG").is_err() { if self.enable_logs {
self.log(parameter_bytes); self.log(parameter_bytes);
self.increment_exec_calls_count(); self.increment_exec_calls_count();
} }

View File

@ -106,7 +106,7 @@ impl Emulator {
self.timer.reset(&mut self.bus); self.timer.reset(&mut self.bus);
} }
self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles().to_t(), frame_buffer); 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 // 1 CPU cycle = 238.42ns
// thread::sleep(time::Duration::from_nanos((self.cpu.get_last_op_cycles().0 * 238).try_into().unwrap())); // 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) { pub fn cpu_loop(&mut self) {
let mut exit = false; 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 { while !exit {
self.cpu.run(&mut self.bus); self.cpu.run(&mut self.bus);
if self.bus.reset_timer { if self.bus.reset_timer {
@ -124,7 +124,7 @@ impl Emulator {
self.timer.reset(&mut self.bus); self.timer.reset(&mut self.bus);
} }
self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles().to_t(), &mut frame); 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() >= 1258895; // log 1
exit = self.cpu.get_exec_calls_count() >= 161502; // log 2 exit = self.cpu.get_exec_calls_count() >= 161502; // log 2

View File

@ -167,6 +167,7 @@ pub struct PPU {
sprite_buffer: Vec<Sprite>, sprite_buffer: Vec<Sprite>,
window_y_counter: u8, window_y_counter: u8,
last_bg_index: u8, last_bg_index: u8,
lcd_control_cache: Option<u8>,
} }
impl PPU { impl PPU {
@ -177,6 +178,7 @@ impl PPU {
sprite_buffer: Vec::new(), sprite_buffer: Vec::new(),
window_y_counter: 0, window_y_counter: 0,
last_bg_index: 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]) { 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); self.increment_cycles(cycles);
return; return;
} }
@ -269,10 +272,10 @@ impl PPU {
fn oam_search(&mut self, bus: &Bus) { fn oam_search(&mut self, bus: &Bus) {
self.sprite_buffer = Vec::new(); self.sprite_buffer = Vec::new();
if !PPU::get_lcd_control(bus, LCDControl::ObjectEnable) { if !self.get_lcd_control(bus, LCDControl::ObjectEnable) {
return; 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(); let mut addr = SPRITE_ATTRIBUTE_TABLE.begin();
while addr <= SPRITE_ATTRIBUTE_TABLE.end() { while addr <= SPRITE_ATTRIBUTE_TABLE.end() {
// The gameboy only supports 10 sprites per line, // The gameboy only supports 10 sprites per line,
@ -356,8 +359,15 @@ impl PPU {
bus.read(WINDOW_Y_ADDRESS) bus.read(WINDOW_Y_ADDRESS)
} }
pub fn get_lcd_control(bus: &Bus, control: LCDControl) -> bool { 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); let byte = bus.read(LCD_CONTROL_ADDRESS);
self.lcd_control_cache = Some(byte);
byte
},
};
control.get(byte) control.get(byte)
} }
@ -420,7 +430,7 @@ impl PPU {
let window_y = PPU::get_window_y(bus); let window_y = PPU::get_window_y(bus);
if if
!PPU::get_lcd_control(bus, LCDControl::WindowEnable) || !self.get_lcd_control(bus, LCDControl::WindowEnable) ||
lcd_x < window_x.saturating_sub(7) || lcd_x < window_x.saturating_sub(7) ||
lcd_y < window_y || lcd_y < window_y ||
window_y >= 144 || window_y >= 144 ||
@ -432,8 +442,8 @@ impl PPU {
let x = lcd_x.wrapping_sub(window_x.saturating_sub(7)); let x = lcd_x.wrapping_sub(window_x.saturating_sub(7));
let y = self.window_y_counter; let y = self.window_y_counter;
let default_mode = PPU::get_lcd_control(bus, LCDControl::TileAddressMode); let default_mode = self.get_lcd_control(bus, LCDControl::TileAddressMode);
let tilemap_area = match PPU::get_lcd_control(bus, LCDControl::WindowTileMapAddress) { let tilemap_area = match self.get_lcd_control(bus, LCDControl::WindowTileMapAddress) {
true => 0x9C00, true => 0x9C00,
false => 0x9800, false => 0x9800,
}; };
@ -448,7 +458,7 @@ impl PPU {
} }
fn get_background_pixel(&mut self, lcd_x: u8, bus: &Bus) -> Option<Pixel> { fn get_background_pixel(&mut self, lcd_x: u8, bus: &Bus) -> Option<Pixel> {
if !PPU::get_lcd_control(bus, LCDControl::BackgroundPriority) { if !self.get_lcd_control(bus, LCDControl::BackgroundPriority) {
return None; return None;
} }
let lcd_y = PPU::get_lcd_y(bus); 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 y = lcd_y.wrapping_add(PPU::get_scroll_y(bus));
let x = lcd_x.wrapping_add(PPU::get_scroll_x(bus)); let x = lcd_x.wrapping_add(PPU::get_scroll_x(bus));
let default_mode = PPU::get_lcd_control(bus, LCDControl::TileAddressMode); let default_mode = self.get_lcd_control(bus, LCDControl::TileAddressMode);
let tilemap_area = match PPU::get_lcd_control(bus, LCDControl::BackgroundTileMapAddress) { let tilemap_area = match self.get_lcd_control(bus, LCDControl::BackgroundTileMapAddress) {
true => 0x9C00, true => 0x9C00,
false => 0x9800, false => 0x9800,
}; };

View File

@ -66,7 +66,7 @@ pub fn start_eventloop() {
Event::MainEventsCleared => { Event::MainEventsCleared => {
emulator.run(Cycles(70224), pixels.get_frame()); emulator.run(Cycles(70224), pixels.get_frame());
thread::sleep(time::Duration::from_millis(1)); // thread::sleep(time::Duration::from_millis(1));
window.request_redraw(); window.request_redraw();
}, },
Event::RedrawRequested(_) => { Event::RedrawRequested(_) => {

View File

@ -31,15 +31,15 @@ impl Timer {
pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles) { pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles) {
let mut count = 0; let mut count = 0;
while count < cycles.to_t().0 { while count < cycles.0 {
self.cycle(bus); self.cycle(bus);
count += 1; count += 1;
} }
bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, self.divider.to_be_bytes()[0]);
} }
fn cycle(&mut self, bus: &mut Bus) { fn cycle(&mut self, bus: &mut Bus) {
self.divider = self.divider.wrapping_add(1); 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); let result = Timer::is_timer_enabled(bus) && self.get_tima_rate(bus);