Some refactors

This commit is contained in:
Franco Colmenarez 2021-11-01 13:04:09 -05:00
parent af15c0ef68
commit aed56708fd
5 changed files with 74 additions and 51 deletions

View File

@ -5,7 +5,14 @@ use crate::utils::{
join_bytes join_bytes
}; };
use crate::rom::ROM; use crate::rom::ROM;
use crate::ppu::{PPU, LCDStatus, LCDStatusModeFlag, LCD_STATUS_ADDRESS, LCD_CONTROL_ADDRESS, LCD_Y_ADDRESS}; use crate::ppu::{
PPU,
LCDStatus,
LCDStatusModeFlag,
LCD_STATUS_ADDRESS,
LCD_CONTROL_ADDRESS,
LCD_Y_ADDRESS
};
use crate::cpu::{Interrupt}; use crate::cpu::{Interrupt};
use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS}; use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS};
use crate::joypad::{Joypad, JOYPAD_ADDRESS}; use crate::joypad::{Joypad, JOYPAD_ADDRESS};
@ -69,7 +76,26 @@ impl Bus {
_ => panic!("Could not read ROM"), _ => panic!("Could not read ROM"),
}; };
let mut data = [0x00; 0x10000]; let mut data = [0x00; 0x10000];
data[JOYPAD_ADDRESS as usize] = 0b11001111; data[0xFF01] = 0x00;
data[0xFF02] = 0x7E;
data[0xFF04] = 0x18;
data[0xFF05] = 0x00;
data[0xFF06] = 0x00;
data[0xFF07] = 0xF8;
data[0xFF0F] = 0xE1;
data[0xFF40] = 0x91;
data[0xFF41] = 0x81;
data[0xFF42] = 0x00;
data[0xFF43] = 0x00;
data[0xFF44] = 0x91;
data[0xFF45] = 0x00;
data[0xFF46] = 0xFF;
data[0xFF47] = 0xFC;
data[0xFF4A] = 0x00;
data[0xFF4B] = 0x00;
Self { Self {
data, data,
game_rom, game_rom,
@ -80,9 +106,6 @@ impl Bus {
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) { if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) {
return self.game_rom.read(address); return self.game_rom.read(address);
} }
if address == JOYPAD_ADDRESS {
println!("Joypad read {:08b}", self.data[address as usize]);
}
self.data[address as usize] self.data[address as usize]
} }
@ -108,15 +131,10 @@ impl Bus {
self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM
} else if address == TIMER_DIVIDER_REGISTER_ADDRESS { } else if address == TIMER_DIVIDER_REGISTER_ADDRESS {
self.data[address as usize] = 0x00; self.data[address as usize] = 0x00;
} else if address == LCD_STATUS_ADDRESS {
// Prevent user from modifying LCD Status mode
let byte = self.data[address as usize];
self.data[address as usize] = (data & 0b1111_1100) | (byte & 0b0000_0011);
} else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) { } else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) {
self.data[address as usize] = data; self.data[address as usize] = data;
self.data[LCD_Y_ADDRESS as usize] = 0x00; self.data[LCD_Y_ADDRESS as usize] = 0x00;
} else if address == JOYPAD_ADDRESS { } else if address == JOYPAD_ADDRESS {
println!("Joypad write: {:08b}", data);
let byte = self.data[JOYPAD_ADDRESS as usize]; let byte = self.data[JOYPAD_ADDRESS as usize];
self.data[JOYPAD_ADDRESS as usize] = (data & 0b00110000) | 0b11000000 | (byte & 0b00001111); self.data[JOYPAD_ADDRESS as usize] = (data & 0b00110000) | 0b11000000 | (byte & 0b00001111);
} else { } else {

View File

@ -923,6 +923,7 @@ impl CPU {
if bus.read(INTERRUPT_ENABLE_ADDRESS) & bus.read(INTERRUPT_FLAG_ADDRESS) != 0 { if bus.read(INTERRUPT_ENABLE_ADDRESS) & bus.read(INTERRUPT_FLAG_ADDRESS) != 0 {
self.is_halted = false; self.is_halted = false;
} }
if bus.get_interrupt(Interrupt::VBlank) { if bus.get_interrupt(Interrupt::VBlank) {
return Some(Interrupt::VBlank); return Some(Interrupt::VBlank);
} else if bus.get_interrupt(Interrupt::LCDSTAT) { } else if bus.get_interrupt(Interrupt::LCDSTAT) {
@ -1778,21 +1779,27 @@ impl CPU {
}, },
// Enable interrupts // Enable interrupts
Opcode::EI => { Opcode::EI => {
println!("EI");
self.registers.increment(Register::PC, 1); self.registers.increment(Register::PC, 1);
self.ime = true; self.ime = true;
}, },
// Disable interrupts // Disable interrupts
Opcode::DI => { Opcode::DI => {
println!("DI");
self.registers.increment(Register::PC, 1); self.registers.increment(Register::PC, 1);
self.ime = false; self.ime = false;
}, },
// Same as enabling interrupts and then executing RET // Same as enabling interrupts and then executing RET
Opcode::RETI => { Opcode::RETI => {
println!("RETI");
let prev_pc = self.registers.get(Register::PC);
self.exec(Opcode::EI, bus); self.exec(Opcode::EI, bus);
self.exec(Opcode::RET(OpcodeParameter::NoParam), bus); self.exec(Opcode::RET(OpcodeParameter::NoParam), bus);
self.registers.set(Register::PC, prev_pc.wrapping_add(1));
}, },
// Don't execute instructions until an interrupt is requested // Don't execute instructions until an interrupt is requested
Opcode::HALT => { Opcode::HALT => {
println!("HALT");
self.registers.increment(Register::PC, 1); self.registers.increment(Register::PC, 1);
self.is_halted = true; self.is_halted = true;
}, },

View File

@ -96,7 +96,7 @@ impl Emulator {
self.joypad.release(Button::Select); self.joypad.release(Button::Select);
} }
if change { if change {
self.bus.force_write(JOYPAD_ADDRESS, self.joypad.get(&self.bus)); self.joypad.update(&mut self.bus);
self.bus.set_interrupt_flag(Interrupt::Joypad, true); self.bus.set_interrupt_flag(Interrupt::Joypad, true);
} }
} }

View File

@ -68,15 +68,12 @@ impl Joypad {
}; };
} }
pub fn get(&self, bus: &Bus) -> u8 { pub fn update(&self, bus: &mut Bus) {
let byte = bus.read(JOYPAD_ADDRESS); let byte = bus.read(JOYPAD_ADDRESS);
let direction = !get_bit(byte, BitIndex::I4); let direction = !get_bit(byte, BitIndex::I4);
let action = !get_bit(byte, BitIndex::I5); let action = !get_bit(byte, BitIndex::I5);
let action = true; let data = 0b11000000 |
let direction = true;
0b11000000 |
(byte & 0b00110000) | (byte & 0b00110000) |
( (
(!((direction && self.down) || (action && self.start)) as u8) << 3 (!((direction && self.down) || (action && self.start)) as u8) << 3
@ -86,6 +83,8 @@ impl Joypad {
(!((direction && self.left) || (action && self.b)) as u8) << 1 (!((direction && self.left) || (action && self.b)) as u8) << 1
) | ( ) | (
(!((direction && self.right) || (action && self.a)) as u8) (!((direction && self.right) || (action && self.a)) as u8)
) );
println!("New joypad write: {:08b}", data);
bus.force_write(JOYPAD_ADDRESS, data);
} }
} }

View File

@ -7,6 +7,27 @@ use crate::utils::{
use crate::bus::{Bus, AddressRange, BANK_ZERO, VIDEO_RAM}; use crate::bus::{Bus, AddressRange, BANK_ZERO, VIDEO_RAM};
use crate::cpu::{Cycles, Interrupt}; use crate::cpu::{Cycles, Interrupt};
pub const LCD_WIDTH: u32 = 160;
pub const LCD_HEIGHT: u32 = 144;
pub const WIDTH: u32 = LCD_WIDTH;
pub const HEIGHT: u32 = LCD_HEIGHT;
pub const FRAME_BUFFER_LENGTH: u32 = WIDTH * HEIGHT;
pub const LCD_CONTROL_ADDRESS: u16 = 0xFF40;
pub const LCD_STATUS_ADDRESS: u16 = 0xFF41;
pub const SCROLL_Y_ADDRESS: u16 = 0xFF42;
pub const SCROLL_X_ADDRESS: u16 = 0xFF43;
pub const LCD_Y_ADDRESS: u16 = 0xFF44;
pub const LCD_Y_COMPARE_ADDRESS: u16 = 0xFF45;
pub const DMA_ADDRESS: u16 = 0xFF46;
pub const BACKGROUND_PALETTE_ADDRESS: u16 = 0xFF47;
pub const OBJECT_PALETTE_0_ADDRESS: u16 = 0xFF48;
pub const OBJECT_PALETTE_1_ADDRESS: u16 = 0xFF49;
pub const WINDOW_X_ADDRESS: u16 = 0xFF4A;
pub const WINDOW_Y_ADDRESS: u16 = 0xFF4B;
pub const TILE_MAP_ADDRESS: u16 = 0x9800;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
enum Pixel { enum Pixel {
White, White,
@ -31,7 +52,7 @@ pub enum LCDControl {
} }
impl LCDControl { impl LCDControl {
fn get_bit_index(&self) -> BitIndex { fn index(&self) -> BitIndex {
match self { match self {
LCDControl::LCDEnable => BitIndex::I7, LCDControl::LCDEnable => BitIndex::I7,
LCDControl::WindowTileMapAddress => BitIndex::I6, LCDControl::WindowTileMapAddress => BitIndex::I6,
@ -45,11 +66,11 @@ impl LCDControl {
} }
pub fn get(&self, byte: u8) -> bool { pub fn get(&self, byte: u8) -> bool {
get_bit(byte, self.get_bit_index()) get_bit(byte, self.index())
} }
pub fn set(&self, byte: u8, val: bool) -> u8 { pub fn set(&self, byte: u8, val: bool) -> u8 {
set_bit(byte, val, self.get_bit_index()) set_bit(byte, val, self.index())
} }
} }
@ -69,27 +90,6 @@ pub enum LCDStatus {
ModeFlag(LCDStatusModeFlag), ModeFlag(LCDStatusModeFlag),
} }
pub const LCD_WIDTH: u32 = 160;
pub const LCD_HEIGHT: u32 = 144;
pub const WIDTH: u32 = LCD_WIDTH;
pub const HEIGHT: u32 = LCD_HEIGHT;
pub const FRAME_BUFFER_LENGTH: u32 = WIDTH * HEIGHT;
pub const LCD_CONTROL_ADDRESS: u16 = 0xFF40;
pub const LCD_STATUS_ADDRESS: u16 = 0xFF41;
pub const SCROLL_Y_ADDRESS: u16 = 0xFF42;
pub const SCROLL_X_ADDRESS: u16 = 0xFF43;
pub const LCD_Y_ADDRESS: u16 = 0xFF44;
pub const LCD_Y_COMPARE_ADDRESS: u16 = 0xFF45;
pub const DMA_ADDRESS: u16 = 0xFF46;
pub const BACKGROUND_PALETTE_ADDRESS: u16 = 0xFF47;
pub const OBJECT_PALETTE_0_ADDRESS: u16 = 0xFF48;
pub const OBJECT_PALETTE_1_ADDRESS: u16 = 0xFF49;
pub const WINDOW_X_ADDRESS: u16 = 0xFF4A;
pub const WINDOW_Y_ADDRESS: u16 = 0xFF4B;
pub const TILE_MAP_ADDRESS: u16 = 0x9800;
pub struct PPU { pub struct PPU {
cycles: Cycles, cycles: Cycles,
rgba_frame: [[u8; 4]; FRAME_BUFFER_LENGTH as usize], rgba_frame: [[u8; 4]; FRAME_BUFFER_LENGTH as usize],
@ -125,8 +125,8 @@ impl PPU {
} }
pub fn cycle(&mut self, bus: &mut Bus) { pub fn cycle(&mut self, bus: &mut Bus) {
self.increment_cycles(Cycles(1));
if !PPU::get_lcd_control(bus, LCDControl::LCDEnable) { if !PPU::get_lcd_control(bus, LCDControl::LCDEnable) {
self.increment_cycles(Cycles(1));
return; return;
} }
@ -156,11 +156,13 @@ impl PPU {
} }
} }
self.increment_cycles(Cycles(1));
// Horizontal scan completed // Horizontal scan completed
if self.cycles.0 > 456 { if self.cycles.0 > 456 {
self.reset_cycles(); self.reset_cycles();
PPU::set_lcd_y(bus, PPU::get_lcd_y(bus) + 1); PPU::set_lcd_y(bus, PPU::get_lcd_y(bus).wrapping_add(1));
let lyc_compare = PPU::get_lcd_y(bus) == 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);
@ -249,15 +251,14 @@ impl PPU {
bus.write(LCD_STATUS_ADDRESS, byte); bus.write(LCD_STATUS_ADDRESS, byte);
} }
fn get_tile_bytes(x: u8, y: u8, tile_number: TileNumber, default_method: bool, bus: &Bus) -> (u8, u8) { fn get_tile_bytes(x: u8, y: u8, tile_number_type: TileNumber, default_method: bool, bus: &Bus) -> (u8, u8) {
let index_x = x as u16 / 8; let index_x = x as u16 / 8;
let index_y = (y as u16 / 8) * 32; let index_y = (y as u16 / 8) * 32;
let index = index_x + index_y; let index = index_x + index_y;
let tile_line = (y).rem_euclid(8) * 2; let tile_line = (y).rem_euclid(8) * 2;
let tile_number = match tile_number { let tile_number = match tile_number_type {
TileNumber::Base(base) => bus.read(base + index as u16), TileNumber::Base(base) => bus.read(base + index as u16),
TileNumber::Absolute(num) => bus.read(0x8000 + num as u16), TileNumber::Absolute(num) => bus.read(0x8000 + num as u16),
} as u16; } as u16;
let addr = if default_method { let addr = if default_method {
0x8000 + tile_line as u16 + (tile_number * 16) 0x8000 + tile_line as u16 + (tile_number * 16)
@ -276,7 +277,7 @@ impl PPU {
let window_x = (PPU::get_window_x(bus) as i8 - 7) as u8; let window_x = (PPU::get_window_x(bus) as i8 - 7) as u8;
let window_y = PPU::get_window_y(bus); let window_y = PPU::get_window_y(bus);
if window_x != lcd_x || window_y != lcd_y { if !PPU::get_lcd_control(bus, LCDControl::WindowEnable) || window_x != lcd_x || window_y != lcd_y {
return None; return None;
} }
@ -319,11 +320,9 @@ impl PPU {
for pixel in bg_pixels { for pixel in bg_pixels {
let idx = lcd_x as usize + (lcd_y as usize * LCD_WIDTH as usize); let idx = lcd_x as usize + (lcd_y as usize * LCD_WIDTH as usize);
self.rgba_frame[idx] = PPU::get_rgba(pixel); self.rgba_frame[idx] = PPU::get_rgba(pixel);
if PPU::get_lcd_control(bus, LCDControl::WindowEnable) {
if let Some(window_pixel) = PPU::get_window_pixel(lcd_x, bus) { if let Some(window_pixel) = PPU::get_window_pixel(lcd_x, bus) {
self.rgba_frame[idx] = PPU::get_rgba(window_pixel); self.rgba_frame[idx] = PPU::get_rgba(window_pixel);
} }
}
lcd_x += 1; lcd_x += 1;
} }