mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-23 10:12:11 +00:00
Some refactors
This commit is contained in:
parent
af15c0ef68
commit
aed56708fd
38
src/bus.rs
38
src/bus.rs
@ -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 {
|
||||||
|
@ -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;
|
||||||
},
|
},
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
67
src/ppu.rs
67
src/ppu.rs
@ -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,10 +320,8 @@ 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;
|
||||||
|
Loading…
Reference in New Issue
Block a user