Compare commits

..

No commits in common. "c68f24ea059a9a68c3c07a247467f7370a719530" and "2fc82faef62b34c44b98e333777dffec0bdd9f29" have entirely different histories.

6 changed files with 117 additions and 160 deletions

View File

@ -57,10 +57,7 @@ pub struct Bus {
impl Bus { impl Bus {
pub fn new() -> Self { pub fn new() -> Self {
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/metroid-2.gb".to_string()) {
// let game_rom = match ROM::load_file("ignore/dmg-acid2.gb".to_string()) {
// let game_rom = match ROM::load_file("ignore/mario-land.gb".to_string()) {
// let game_rom = match ROM::load_file("ignore/tetris.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()) {
@ -184,8 +181,18 @@ impl Bus {
self.write(address.wrapping_add(1), bytes[1]); self.write(address.wrapping_add(1), bytes[1]);
} }
pub fn set_interrupt_enable(&mut self, interrupt: Interrupt, val: bool) {
let byte = self.read(INTERRUPT_ENABLE_ADDRESS);
self.write(INTERRUPT_ENABLE_ADDRESS, interrupt.set(byte, val));
}
pub fn set_interrupt_flag(&mut self, interrupt: Interrupt, val: bool) { pub fn set_interrupt_flag(&mut self, interrupt: Interrupt, val: bool) {
let byte = self.read(INTERRUPT_FLAG_ADDRESS); let byte = self.read(INTERRUPT_FLAG_ADDRESS);
self.write(INTERRUPT_FLAG_ADDRESS, interrupt.set(byte, val)); self.write(INTERRUPT_FLAG_ADDRESS, interrupt.set(byte, val));
} }
pub fn get_interrupt(&mut self, interrupt: Interrupt) -> bool {
let byte = self.read(INTERRUPT_ENABLE_ADDRESS) & self.read(INTERRUPT_FLAG_ADDRESS);
interrupt.get(byte)
}
} }

View File

@ -844,7 +844,6 @@ 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 {
@ -857,7 +856,6 @@ 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(),
} }
} }
@ -917,23 +915,22 @@ impl CPU {
} }
pub fn check_interrupts(&mut self, bus: &mut Bus) -> Option<Interrupt> { pub fn check_interrupts(&mut self, bus: &mut Bus) -> Option<Interrupt> {
let interrupts = (bus.read(INTERRUPT_ENABLE_ADDRESS) & 0b00011111) & (bus.read(INTERRUPT_FLAG_ADDRESS) & 0b00011111); if (bus.read(INTERRUPT_ENABLE_ADDRESS) & 0b00011111) & (bus.read(INTERRUPT_FLAG_ADDRESS) & 0b00011111) != 0 {
if interrupts != 0 {
self.is_halted = false; self.is_halted = false;
} }
if !self.ime { if !self.ime {
return None; return None;
} }
if Interrupt::VBlank.get(interrupts) { if bus.get_interrupt(Interrupt::VBlank) {
return Some(Interrupt::VBlank); return Some(Interrupt::VBlank);
} else if Interrupt::LCDSTAT.get(interrupts) { } else if bus.get_interrupt(Interrupt::LCDSTAT) {
return Some(Interrupt::LCDSTAT); return Some(Interrupt::LCDSTAT);
} else if Interrupt::Timer.get(interrupts) { } else if bus.get_interrupt(Interrupt::Timer) {
return Some(Interrupt::Timer); return Some(Interrupt::Timer);
} else if Interrupt::Serial.get(interrupts) { } else if bus.get_interrupt(Interrupt::Serial) {
return Some(Interrupt::Serial); return Some(Interrupt::Serial);
} else if Interrupt::Joypad.get(interrupts) { } else if bus.get_interrupt(Interrupt::Joypad) {
return Some(Interrupt::Joypad); return Some(Interrupt::Joypad);
} }
None None
@ -956,7 +953,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 self.enable_logs { if !env::var("CPU_LOG").is_err() {
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().to_t()); self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
// 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 * 4] = [0; 144 * 160 * 4]; let mut frame: [u8; 144 * 160] = [0; 144 * 160];
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().to_t()); self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
// 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

@ -93,12 +93,11 @@ struct Sprite {
x: u8, x: u8,
y: u8, y: u8,
tile_number: u8, tile_number: u8,
palette: u8,
x_flip: bool, x_flip: bool,
y_flip: bool, y_flip: bool,
over_bg: bool, over_bg: bool,
palette_one: bool,
is_long: bool, is_long: bool,
bit_pixels: Option<[u8; 8]>,
} }
impl Sprite { impl Sprite {
@ -106,7 +105,7 @@ impl Sprite {
self.x self.x
} }
pub fn get_pixel(&mut self, lcd_x: u8, lcd_y: u8, bus: &Bus, last_bg_index: u8) -> Option<Pixel> { pub fn get_pixel(&self, lcd_x: u8, lcd_y: u8, bus: &Bus, last_bg_index: u8) -> Option<Pixel> {
if lcd_x < self.x.saturating_sub(8) || lcd_x >= self.x { if lcd_x < self.x.saturating_sub(8) || lcd_x >= self.x {
return None; return None;
} }
@ -119,8 +118,10 @@ impl Sprite {
true => 16, true => 16,
false => 8, false => 8,
}; };
let x = lcd_x.saturating_sub(self.x.saturating_sub(8)); let x = lcd_x.saturating_sub(self.x.saturating_sub(8));
let y = lcd_y.saturating_sub(self.y .saturating_sub(16)); let y = lcd_y.saturating_sub(self.y .saturating_sub(16));
let x = match self.x_flip { let x = match self.x_flip {
true => 7 - x, true => 7 - x,
false => x, false => x,
@ -130,38 +131,33 @@ impl Sprite {
false => y, false => y,
}; };
let bit_pixel_index = (x as usize).rem_euclid(8); let mut tile_number = self.tile_number;
let bit_pixel = match self.bit_pixels { if self.is_long && x <= 7 {
Some(bit_pixels_array) => { tile_number = tile_number & 0xFE;
bit_pixels_array[bit_pixel_index] } else if self.is_long && x > 7 {
}, tile_number = tile_number | 0x01;
None => { }
let mut tile_number = self.tile_number;
if self.is_long && x <= 7 { let tile_line = y.rem_euclid(height) * 2;
tile_number = tile_number & 0xFE; let addr = 0x8000 + (tile_number as u16 * 16) + tile_line as u16;
} else if self.is_long && x > 7 {
tile_number = tile_number | 0x01;
}
let tile_line = y.rem_euclid(height) * 2; let tile_byte_1 = bus.read(addr);
let addr = 0x8000 + (tile_number as u16 * 16) + tile_line as u16; let tile_byte_2 = bus.read(addr + 1);
let tile_byte_1 = bus.read(addr); let pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
let tile_byte_2 = bus.read(addr + 1);
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
self.bit_pixels = Some(bit_pixels_array);
bit_pixels_array[bit_pixel_index] let index = (x as usize).rem_euclid(8);
}
};
if bit_pixel == 0 { if pixels[index] == 0 {
return None; return None;
} }
Some(PPU::get_pixel(PPU::get_palette(bit_pixel, self.palette))) let palette = match self.palette_one {
true => bus.read(OBJECT_PALETTE_1_ADDRESS),
false => bus.read(OBJECT_PALETTE_0_ADDRESS),
};
Some(PPU::get_pixel(PPU::get_palette(pixels[index], palette)))
} }
} }
@ -171,15 +167,6 @@ 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,
bg_palette: u8,
lcd_control_cache: Option<u8>,
current_background_pixels: Option<[u8; 8]>,
current_window_pixels: Option<[u8; 8]>,
lcd_y: u8,
scroll_x: u8,
scroll_y: u8,
window_x: u8,
window_y: u8,
} }
impl PPU { impl PPU {
@ -190,15 +177,6 @@ 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,
bg_palette: 0,
lcd_control_cache: None,
current_background_pixels: None,
current_window_pixels: None,
lcd_y: 0,
scroll_x: 0,
scroll_y: 0,
window_x: 0,
window_y: 0,
} }
} }
@ -211,18 +189,12 @@ 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]) {
self.lcd_control_cache = None; if !PPU::get_lcd_control(bus, LCDControl::LCDEnable) {
if !self.get_lcd_control(bus, LCDControl::LCDEnable) {
self.increment_cycles(cycles); self.increment_cycles(cycles);
return; return;
} }
self.lcd_y = bus.read(LCD_Y_ADDRESS);
self.scroll_x = bus.read(SCROLL_X_ADDRESS);
self.scroll_y = bus.read(SCROLL_Y_ADDRESS);
self.window_x = bus.read(WINDOW_X_ADDRESS);
self.window_y = bus.read(WINDOW_Y_ADDRESS);
if self.lcd_y < 144 { if PPU::get_lcd_y(bus) < 144 {
if self.cycles.0 <= 80 && !PPU::get_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM)) { if self.cycles.0 <= 80 && !PPU::get_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM)) {
// Mode 2 OAM scan // Mode 2 OAM scan
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM), true); PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM), true);
@ -237,7 +209,7 @@ impl PPU {
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::HBlank), true); PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::HBlank), true);
self.stat_interrupt(bus); self.stat_interrupt(bus);
} }
} else if self.lcd_y >= 144 && !PPU::get_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::VBlank)) { } else if PPU::get_lcd_y(bus) >= 144 && !PPU::get_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::VBlank)) {
// Mode 1 Vertical blank // Mode 1 Vertical blank
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::VBlank), true); PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::VBlank), true);
bus.set_interrupt_flag(Interrupt::VBlank, true); bus.set_interrupt_flag(Interrupt::VBlank, true);
@ -250,14 +222,13 @@ impl PPU {
if self.cycles.0 > 456 { if self.cycles.0 > 456 {
self.reset_cycles(); self.reset_cycles();
self.lcd_y = self.lcd_y.wrapping_add(1); PPU::set_lcd_y(bus, PPU::get_lcd_y(bus).wrapping_add(1));
// Frame completed // Frame completed
if self.lcd_y > 153 { if PPU::get_lcd_y(bus) > 153 {
self.lcd_y = 0; PPU::set_lcd_y(bus, 0);
self.window_y_counter = 0; self.window_y_counter = 0;
} }
bus.force_write(LCD_Y_ADDRESS, self.lcd_y);
// self.check_lyc(bus); // self.check_lyc(bus);
self.stat_interrupt(bus); self.stat_interrupt(bus);
} }
@ -265,7 +236,7 @@ impl PPU {
fn stat_interrupt(&mut self, bus: &mut Bus) { fn stat_interrupt(&mut self, bus: &mut Bus) {
let prev_state = self.state; let prev_state = self.state;
let lyc_compare = self.lcd_y == bus.read(LCD_Y_COMPARE_ADDRESS); let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
PPU::set_lcd_status(bus, LCDStatus::LYCFlag, lyc_compare); PPU::set_lcd_status(bus, LCDStatus::LYCFlag, lyc_compare);
self.state = self.state =
( (
@ -288,7 +259,7 @@ impl PPU {
} }
fn check_lyc(&mut self, bus: &mut Bus) { fn check_lyc(&mut self, bus: &mut Bus) {
let lyc_compare = self.lcd_y == bus.read(LCD_Y_COMPARE_ADDRESS); let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
PPU::set_lcd_status(bus, LCDStatus::LYCFlag, lyc_compare); PPU::set_lcd_status(bus, LCDStatus::LYCFlag, lyc_compare);
if !self.state && lyc_compare && PPU::get_lcd_status(bus, LCDStatus::LYCInterrupt) { if !self.state && lyc_compare && PPU::get_lcd_status(bus, LCDStatus::LYCInterrupt) {
bus.set_interrupt_flag(Interrupt::LCDSTAT, true); bus.set_interrupt_flag(Interrupt::LCDSTAT, true);
@ -298,12 +269,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 !self.get_lcd_control(bus, LCDControl::ObjectEnable) { if !PPU::get_lcd_control(bus, LCDControl::ObjectEnable) {
return; return;
} }
let palette_0 = bus.read(OBJECT_PALETTE_0_ADDRESS); let long_sprites = PPU::get_lcd_control(bus, LCDControl::ObjectSize);
let palette_1 = bus.read(OBJECT_PALETTE_1_ADDRESS);
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,
@ -325,7 +294,7 @@ impl PPU {
false => 8, false => 8,
}; };
let lcd_y = self.lcd_y.saturating_add(16); let lcd_y = PPU::get_lcd_y(bus).saturating_add(16);
if lcd_y < y || lcd_y > (y + sprite_height - 1) { if lcd_y < y || lcd_y > (y + sprite_height - 1) {
addr += 4; addr += 4;
@ -341,14 +310,10 @@ impl PPU {
y, y,
tile_number, tile_number,
is_long: long_sprites, is_long: long_sprites,
palette: match get_bit(attributes, BitIndex::I4) { palette_one: get_bit(attributes, BitIndex::I4),
true => palette_1,
false => palette_0,
},
x_flip: get_bit(attributes, BitIndex::I5), x_flip: get_bit(attributes, BitIndex::I5),
y_flip: get_bit(attributes, BitIndex::I6), y_flip: get_bit(attributes, BitIndex::I6),
over_bg: get_bit(attributes, BitIndex::I7), over_bg: get_bit(attributes, BitIndex::I7),
bit_pixels: None,
}); });
addr += 4; addr += 4;
@ -356,9 +321,9 @@ impl PPU {
self.sprite_buffer.sort_by(|a, b| a.x().cmp(&b.x())); self.sprite_buffer.sort_by(|a, b| a.x().cmp(&b.x()));
} }
fn find_sprite_pixel(&mut self, lcd_x: u8, bus: &Bus) -> Option<Pixel> { fn find_sprite_pixel(&self, lcd_x: u8, bus: &Bus) -> Option<Pixel> {
let lcd_y = self.lcd_y; let lcd_y = PPU::get_lcd_y(bus);
for sprite in &mut self.sprite_buffer { for sprite in &self.sprite_buffer {
if let Some(pixel) = sprite.get_pixel(lcd_x, lcd_y, bus, self.last_bg_index) { if let Some(pixel) = sprite.get_pixel(lcd_x, lcd_y, bus, self.last_bg_index) {
return Some(pixel); return Some(pixel);
} }
@ -367,15 +332,32 @@ impl PPU {
return None; return None;
} }
pub fn get_lcd_control(&mut self, bus: &Bus, control: LCDControl) -> bool { fn get_lcd_y(bus: &Bus) -> u8 {
let byte = match self.lcd_control_cache { bus.read(LCD_Y_ADDRESS)
Some(byte) => byte, }
None => {
let byte = bus.read(LCD_CONTROL_ADDRESS); fn set_lcd_y(bus: &mut Bus, val: u8) {
self.lcd_control_cache = Some(byte); bus.force_write(LCD_Y_ADDRESS, val);
byte }
},
}; fn get_scroll_x(bus: &Bus) -> u8 {
bus.read(SCROLL_X_ADDRESS)
}
fn get_scroll_y(bus: &Bus) -> u8 {
bus.read(SCROLL_Y_ADDRESS)
}
fn get_window_x(bus: &Bus) -> u8 {
bus.read(WINDOW_X_ADDRESS)
}
fn get_window_y(bus: &Bus) -> u8 {
bus.read(WINDOW_Y_ADDRESS)
}
pub fn get_lcd_control(bus: &Bus, control: LCDControl) -> bool {
let byte = bus.read(LCD_CONTROL_ADDRESS);
control.get(byte) control.get(byte)
} }
@ -433,12 +415,12 @@ impl PPU {
} }
fn get_window_pixel(&mut self, lcd_x: u8, bus: &Bus) -> Option<Pixel> { fn get_window_pixel(&mut self, lcd_x: u8, bus: &Bus) -> Option<Pixel> {
let lcd_y = self.lcd_y; let lcd_y = PPU::get_lcd_y(bus);
let window_x = self.window_x; let window_x = PPU::get_window_x(bus);
let window_y = self.window_y; let window_y = PPU::get_window_y(bus);
if if
!self.get_lcd_control(bus, LCDControl::WindowEnable) || !PPU::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 ||
@ -450,78 +432,49 @@ 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 bit_pixel_index = (x as usize).rem_euclid(8); let default_mode = PPU::get_lcd_control(bus, LCDControl::TileAddressMode);
if bit_pixel_index == 0 { let tilemap_area = match PPU::get_lcd_control(bus, LCDControl::WindowTileMapAddress) {
self.current_window_pixels = None; true => 0x9C00,
} false => 0x9800,
let bit_pixel = match self.current_window_pixels {
Some(bit_pixels_array) => {
bit_pixels_array[bit_pixel_index]
},
None => {
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,
};
let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, tilemap_area, default_mode, bus);
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
self.current_window_pixels = Some(bit_pixels_array);
bit_pixels_array[bit_pixel_index]
},
}; };
let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, tilemap_area, default_mode, bus);
self.last_bg_index = bit_pixel & 0b11; let palette = bus.read(BACKGROUND_PALETTE_ADDRESS);
let pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
let index = pixels[(x as usize).rem_euclid(8)];
self.last_bg_index = index & 0b11;
Some(PPU::get_pixel(PPU::get_palette(bit_pixel, self.bg_palette))) Some(PPU::get_pixel(PPU::get_palette(index, palette)))
} }
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 !self.get_lcd_control(bus, LCDControl::BackgroundPriority) { if !PPU::get_lcd_control(bus, LCDControl::BackgroundPriority) {
return None; return None;
} }
let lcd_y = self.lcd_y; let lcd_y = PPU::get_lcd_y(bus);
let y = lcd_y.wrapping_add(self.scroll_y); let palette = bus.read(BACKGROUND_PALETTE_ADDRESS);
let x = lcd_x.wrapping_add(self.scroll_x); let y = lcd_y.wrapping_add(PPU::get_scroll_y(bus));
let bit_pixel_index = x.rem_euclid(8) as usize; let x = lcd_x.wrapping_add(PPU::get_scroll_x(bus));
if bit_pixel_index == 0 { let default_mode = PPU::get_lcd_control(bus, LCDControl::TileAddressMode);
self.current_background_pixels = None; let tilemap_area = match PPU::get_lcd_control(bus, LCDControl::BackgroundTileMapAddress) {
} true => 0x9C00,
false => 0x9800,
let bit_pixel = match self.current_background_pixels {
Some(bit_pixels_array) => {
bit_pixels_array[bit_pixel_index]
},
None => {
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,
};
let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, tilemap_area, default_mode, bus);
let bit_pixels_array = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
self.current_background_pixels = Some(bit_pixels_array);
bit_pixels_array[bit_pixel_index]
},
}; };
self.last_bg_index = bit_pixel & 0b11; let (tile_byte_1, tile_byte_2) = PPU::get_tile_bytes(x, y, tilemap_area, default_mode, bus);
Some(PPU::get_pixel(PPU::get_palette(bit_pixel, self.bg_palette))) let bg_pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
let index = bg_pixels[x.rem_euclid(8) as usize];
self.last_bg_index = index & 0b11;
Some(PPU::get_pixel(PPU::get_palette(index, palette)))
} }
fn draw_line(&mut self, bus: &Bus, frame_buffer: &mut [u8]) { fn draw_line(&mut self, bus: &Bus, frame_buffer: &mut [u8]) {
let lcd_y = self.lcd_y; let lcd_y = PPU::get_lcd_y(bus);
if lcd_y as u32 >= LCD_HEIGHT { if lcd_y as u32 >= LCD_HEIGHT {
return; return;
} }
self.current_background_pixels = None;
self.current_window_pixels = None;
self.bg_palette = bus.read(BACKGROUND_PALETTE_ADDRESS);
let mut lcd_x: u8 = 0; let mut lcd_x: u8 = 0;
let mut window_drawn = false; let mut window_drawn = false;
while (lcd_x as u32) < LCD_WIDTH { while (lcd_x as u32) < LCD_WIDTH {

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.0 { while count < cycles.to_t().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);