mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-23 10:12:11 +00:00
Enabling lcd and vblank flag registers
This commit is contained in:
parent
c401726da5
commit
f90900a4c1
32
src/bus.rs
32
src/bus.rs
@ -1,5 +1,12 @@
|
||||
use crate::utils::{join_bytes};
|
||||
use crate::utils::{
|
||||
get_bit,
|
||||
set_bit,
|
||||
BitIndex,
|
||||
join_bytes
|
||||
};
|
||||
use crate::rom::ROM;
|
||||
use crate::ppu::{PPU, LCDStatus, LCDStatusModeFlag};
|
||||
use crate::cpu::{InterruptFlag};
|
||||
|
||||
pub struct AddressRange {
|
||||
begin: u16,
|
||||
@ -32,6 +39,7 @@ pub const NOT_USABLE: AddressRange = AddressRange{begin: 0xFEA0,
|
||||
pub const IO_REGISTERS: AddressRange = AddressRange{begin: 0xFF00, end: 0xFF7F};
|
||||
pub const HIGH_RAM: AddressRange = AddressRange{begin: 0xFF80, end: 0xFFFE};
|
||||
pub const INTERRUPT_ENABLE_REGISTER: AddressRange = AddressRange{begin: 0xFFFF, end: 0xFFFF};
|
||||
pub const INTERRUPT_FLAG_ADDRESS: u16 = 0xFF0F;
|
||||
|
||||
pub struct Bus {
|
||||
game_rom: ROM,
|
||||
@ -65,6 +73,10 @@ impl Bus {
|
||||
pub fn read(&self, address: u16) -> u8 {
|
||||
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) {
|
||||
return self.game_rom.read(address);
|
||||
} else if VIDEO_RAM.in_range(address) {
|
||||
if PPU::get_lcd_status(self, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
||||
return 0xFF
|
||||
}
|
||||
} else if IO_REGISTERS.in_range(address) {
|
||||
return self.data[address as usize];
|
||||
}
|
||||
@ -91,8 +103,13 @@ impl Bus {
|
||||
} else if ECHO_RAM.in_range(address) {
|
||||
self.data[address as usize] = data;
|
||||
self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM
|
||||
} else if VIDEO_RAM.in_range(address) {
|
||||
//if !PPU::get_lcd_status(self, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
||||
self.data[address as usize] = data;
|
||||
// }
|
||||
} else {
|
||||
self.data[address as usize] = data;
|
||||
}
|
||||
self.data[address as usize] = data;
|
||||
}
|
||||
|
||||
pub fn write_16bit(&mut self, address: u16, data: u16) {
|
||||
@ -100,4 +117,15 @@ impl Bus {
|
||||
self.write(address, bytes[0]);
|
||||
self.write(address.wrapping_add(1), bytes[1]);
|
||||
}
|
||||
|
||||
pub fn set_flag(&mut self, flag: InterruptFlag, val: bool) {
|
||||
let byte = self.read(INTERRUPT_FLAG_ADDRESS);
|
||||
self.write(INTERRUPT_FLAG_ADDRESS, match flag {
|
||||
InterruptFlag::VBlank => set_bit(byte, val, BitIndex::I0),
|
||||
InterruptFlag::LCDSTAT => set_bit(byte, val, BitIndex::I1),
|
||||
InterruptFlag::Timer => set_bit(byte, val, BitIndex::I2),
|
||||
InterruptFlag::Serial => set_bit(byte, val, BitIndex::I3),
|
||||
InterruptFlag::Joypad => set_bit(byte, val, BitIndex::I4),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
103
src/ppu.rs
103
src/ppu.rs
@ -5,7 +5,7 @@ use crate::utils::{
|
||||
to_bit_index,
|
||||
};
|
||||
use crate::bus::{Bus, AddressRange, BANK_ZERO, VIDEO_RAM};
|
||||
use crate::cpu::{Cycles};
|
||||
use crate::cpu::{Cycles, InterruptFlag};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum Pixel {
|
||||
@ -90,28 +90,37 @@ impl PPU {
|
||||
pub fn do_cycle(&mut self, bus: &mut Bus) {
|
||||
// Mode 1 Vertical blank
|
||||
if PPU::get_lcd_y(bus) >= 144 {
|
||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::VBlank), true);
|
||||
if PPU::get_lcd_y(bus) == 144 {
|
||||
bus.set_flag(InterruptFlag::VBlank, true);
|
||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::VBlank), true);
|
||||
}
|
||||
} else {
|
||||
if self.cycles.0 <= 80 {
|
||||
if self.cycles.0 == 0 {
|
||||
// Mode 2 OAM scan
|
||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::SearchingOAM), true);
|
||||
} else if self.cycles.0 <= 80 + 172 {
|
||||
} else if self.cycles.0 == 80 + 1 {
|
||||
// Mode 3 drawing pixel line. This could also last 289 cycles
|
||||
if !PPU::get_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD)) {
|
||||
self.draw_line(bus);
|
||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD), true);
|
||||
}
|
||||
} else if self.cycles.0 <= 80 + 172 + 204 {
|
||||
bus.set_flag(InterruptFlag::LCDSTAT, true);
|
||||
self.draw_line(bus);
|
||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD), true);
|
||||
} else if self.cycles.0 == 80 + 172 + 1 {
|
||||
// Mode 0 Horizontal blank. This could last 87 or 204 cycles depending on the mode 3
|
||||
bus.set_flag(InterruptFlag::LCDSTAT, true);
|
||||
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::HBlank), true);
|
||||
}
|
||||
}
|
||||
|
||||
let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
|
||||
PPU::set_lcd_status(bus, LCDStatus::LYCInterrupt, lyc_compare);
|
||||
if lyc_compare {
|
||||
bus.set_flag(InterruptFlag::LCDSTAT, true);
|
||||
}
|
||||
self.increment_cycles(Cycles(1));
|
||||
|
||||
// Horizontal scan completed
|
||||
if self.cycles.0 > 456 {
|
||||
self.reset_cycles();
|
||||
|
||||
PPU::set_lcd_y(bus, PPU::get_lcd_y(bus) + 1);
|
||||
|
||||
// Frame completed
|
||||
@ -145,36 +154,36 @@ impl PPU {
|
||||
bus.write(SCROLL_Y_ADDRESS, val);
|
||||
}
|
||||
|
||||
fn get_lcd_control(bus: &Bus, control: LCDControl) -> bool {
|
||||
pub fn get_lcd_control(bus: &Bus, control: LCDControl) -> bool {
|
||||
let byte = bus.read(LCD_CONTROL_ADDRESS);
|
||||
match control {
|
||||
LCDControl::DisplayEnable => get_bit(byte, BitIndex::I7),
|
||||
LCDControl::WindowTileMapAddress => get_bit(byte, BitIndex::I6),
|
||||
LCDControl::WindowEnable => get_bit(byte, BitIndex::I5),
|
||||
LCDControl::BackgroundWindowTileAddress => get_bit(byte, BitIndex::I4),
|
||||
LCDControl::BackgroundTileMapAddress => get_bit(byte, BitIndex::I3),
|
||||
LCDControl::ObjectSize => get_bit(byte, BitIndex::I2),
|
||||
LCDControl::ObjectEnable => get_bit(byte, BitIndex::I1),
|
||||
LCDControl::BackgroundPriority => get_bit(byte, BitIndex::I0),
|
||||
LCDControl::DisplayEnable => get_bit(byte, BitIndex::I7),
|
||||
LCDControl::WindowTileMapAddress => get_bit(byte, BitIndex::I6),
|
||||
LCDControl::WindowEnable => get_bit(byte, BitIndex::I5),
|
||||
LCDControl::BackgroundWindowTileAddress => get_bit(byte, BitIndex::I4),
|
||||
LCDControl::BackgroundTileMapAddress => get_bit(byte, BitIndex::I3),
|
||||
LCDControl::ObjectSize => get_bit(byte, BitIndex::I2),
|
||||
LCDControl::ObjectEnable => get_bit(byte, BitIndex::I1),
|
||||
LCDControl::BackgroundPriority => get_bit(byte, BitIndex::I0),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_lcd_control(bus: &mut Bus, control: LCDControl, val: bool) {
|
||||
let mut byte = bus.read(LCD_CONTROL_ADDRESS);
|
||||
byte = match control {
|
||||
LCDControl::DisplayEnable => set_bit(byte, val, BitIndex::I7),
|
||||
LCDControl::WindowTileMapAddress => set_bit(byte, val, BitIndex::I6),
|
||||
LCDControl::WindowEnable => set_bit(byte, val, BitIndex::I5),
|
||||
LCDControl::DisplayEnable => set_bit(byte, val, BitIndex::I7),
|
||||
LCDControl::WindowTileMapAddress => set_bit(byte, val, BitIndex::I6),
|
||||
LCDControl::WindowEnable => set_bit(byte, val, BitIndex::I5),
|
||||
LCDControl::BackgroundWindowTileAddress => set_bit(byte, val, BitIndex::I4),
|
||||
LCDControl::BackgroundTileMapAddress => set_bit(byte, val, BitIndex::I3),
|
||||
LCDControl::ObjectSize => set_bit(byte, val, BitIndex::I2),
|
||||
LCDControl::ObjectEnable => set_bit(byte, val, BitIndex::I1),
|
||||
LCDControl::BackgroundPriority => set_bit(byte, val, BitIndex::I0),
|
||||
LCDControl::BackgroundTileMapAddress => set_bit(byte, val, BitIndex::I3),
|
||||
LCDControl::ObjectSize => set_bit(byte, val, BitIndex::I2),
|
||||
LCDControl::ObjectEnable => set_bit(byte, val, BitIndex::I1),
|
||||
LCDControl::BackgroundPriority => set_bit(byte, val, BitIndex::I0),
|
||||
};
|
||||
bus.write(LCD_CONTROL_ADDRESS, byte);
|
||||
}
|
||||
|
||||
fn get_lcd_status(bus: &Bus, status: LCDStatus) -> bool {
|
||||
pub fn get_lcd_status(bus: &Bus, status: LCDStatus) -> bool {
|
||||
let byte = bus.read(LCD_STATUS_ADDRESS);
|
||||
match status {
|
||||
LCDStatus::LYCInterrupt => get_bit(byte, BitIndex::I6),
|
||||
@ -237,48 +246,6 @@ impl PPU {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_background(&mut self, bus: &mut Bus) {
|
||||
let mut lcd_y: u8 = 0;
|
||||
PPU::set_lcd_y(bus, lcd_y);
|
||||
while lcd_y < 144 {
|
||||
self.draw_line(bus);
|
||||
lcd_y += 1;
|
||||
PPU::set_lcd_y(bus, lcd_y);
|
||||
}
|
||||
}
|
||||
|
||||
/* pub fn draw_background_old(&mut self, bus: &Bus) {
|
||||
let mut idx = 0;
|
||||
// let mut tile_line: u16 = 0;
|
||||
let mut lcd_y: u8 = 0;
|
||||
while lcd_y < 144 {
|
||||
let mut lcd_x: u8 = 0;
|
||||
while lcd_x < 160 {
|
||||
let y = lcd_y.wrapping_add(PPU::get_scroll_y(bus));
|
||||
let x = lcd_x.wrapping_add(PPU::get_scroll_x(bus));
|
||||
let index_x = (x as u16 / 8);
|
||||
let index_y = (y as u16 / 8) * 32;
|
||||
let index = index_x + index_y;
|
||||
let tile_line = (y).rem_euclid(8) * 2;
|
||||
let index_byte = (bus.read(0x9800 + index as u16) as u16) * 16;
|
||||
|
||||
let tile_byte_1 = bus.read(0x8000 + tile_line as u16 + index_byte);
|
||||
let tile_byte_2 = bus.read(0x8000 + tile_line as u16 + index_byte + 1);
|
||||
|
||||
let pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2);
|
||||
|
||||
for pixel in pixels {
|
||||
self.rgba_frame[idx] = PPU::get_rgba(pixel);
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
lcd_x += 8;
|
||||
}
|
||||
lcd_y += 1;
|
||||
// tile_line += 2;
|
||||
}
|
||||
} */
|
||||
|
||||
fn get_pixel(two_bit_pixel: u8) -> Pixel {
|
||||
match two_bit_pixel {
|
||||
|
Loading…
Reference in New Issue
Block a user