bios boots! ish!

This commit is contained in:
Alex Janka 2023-04-20 16:45:45 +10:00
parent c56e167c6b
commit 7d90d516ed
5 changed files with 201 additions and 15 deletions

View file

@ -212,7 +212,7 @@ where
user_mode: false, user_mode: false,
dma: OamDma::default(), dma: OamDma::default(),
joypad: Joypad::default(), joypad: Joypad::default(),
gpu: Gpu::new(output.window, output.tile_window), gpu: Gpu::new(cgb, output.window, output.tile_window),
apu: Apu::new(output.audio), apu: Apu::new(output.audio),
serial: Serial::new(output.serial_target), serial: Serial::new(output.serial_target),
timers: Timer::init(), timers: Timer::init(),
@ -339,7 +339,15 @@ where
IoAddress::Cgb(address) => { IoAddress::Cgb(address) => {
if let WramBanks::Cgb { banks: _, selected } = &self.ram.banks { if let WramBanks::Cgb { banks: _, selected } = &self.ram.banks {
match address { match address {
CgbIoAddress::PrepareSpeed => todo!(),
CgbIoAddress::VramBank => self.gpu.vram.get_vram_bank(),
CgbIoAddress::VramDma(_) => todo!(),
CgbIoAddress::Infrared => todo!(),
CgbIoAddress::Palette(address) => self.gpu.get_cgb_palette(address),
CgbIoAddress::ObjPriority => todo!(),
CgbIoAddress::WramBank => ((*selected) & 0b111) as u8, CgbIoAddress::WramBank => ((*selected) & 0b111) as u8,
CgbIoAddress::Pcm12 => todo!(),
CgbIoAddress::Pcm34 => todo!(),
CgbIoAddress::Unused(v) => { CgbIoAddress::Unused(v) => {
println!("attempt to get 0x{v:0>4X}"); println!("attempt to get 0x{v:0>4X}");
todo!() todo!()
@ -391,7 +399,15 @@ where
IoAddress::Cgb(address) => { IoAddress::Cgb(address) => {
if let WramBanks::Cgb { banks: _, selected } = &mut self.ram.banks { if let WramBanks::Cgb { banks: _, selected } = &mut self.ram.banks {
match address { match address {
CgbIoAddress::PrepareSpeed => todo!(),
CgbIoAddress::VramBank => self.gpu.vram.set_vram_bank(data),
CgbIoAddress::VramDma(_) => todo!(),
CgbIoAddress::Infrared => todo!(),
CgbIoAddress::Palette(address) => self.gpu.set_cgb_palette(address, data),
CgbIoAddress::ObjPriority => todo!(),
CgbIoAddress::WramBank => *selected = (data & 0b111).max(1) as usize, CgbIoAddress::WramBank => *selected = (data & 0b111).max(1) as usize,
CgbIoAddress::Pcm12 => todo!(),
CgbIoAddress::Pcm34 => todo!(),
CgbIoAddress::Unused(v) => { CgbIoAddress::Unused(v) => {
println!("attempt to set 0x{v:0>4X} to 0x{data:0>2X}"); println!("attempt to set 0x{v:0>4X} to 0x{data:0>2X}");
todo!() todo!()

View file

@ -23,6 +23,9 @@ pub(crate) type AudioAddress = BoundedAddress<0xFF10, 0xFF27>;
pub(crate) type WaveRamAddress = BoundedAddress<0xFF30, 0xFF40>; pub(crate) type WaveRamAddress = BoundedAddress<0xFF30, 0xFF40>;
pub(crate) type VideoAddress = BoundedAddress<0xFF40, 0xFF4C>; pub(crate) type VideoAddress = BoundedAddress<0xFF40, 0xFF4C>;
pub(crate) type VramDmaAddress = BoundedAddress<0xFF51, 0xFF56>;
pub(crate) type CgbPaletteAddress = BoundedAddress<0xFF68, 0xFF6C>;
pub(crate) enum RomAddress { pub(crate) enum RomAddress {
Bank0(Bank0Address), Bank0(Bank0Address),
MappedBank(MappedBankAddress), MappedBank(MappedBankAddress),
@ -41,7 +44,15 @@ pub(crate) enum IoAddress {
} }
pub(crate) enum CgbIoAddress { pub(crate) enum CgbIoAddress {
PrepareSpeed,
VramBank,
VramDma(VramDmaAddress),
Infrared,
Palette(CgbPaletteAddress),
ObjPriority,
WramBank, WramBank,
Pcm12,
Pcm34,
Unused(u16), Unused(u16),
} }
@ -119,7 +130,15 @@ impl TryInto<CgbIoAddress> for u16 {
fn try_into(self) -> Result<CgbIoAddress, Self::Error> { fn try_into(self) -> Result<CgbIoAddress, Self::Error> {
match self { match self {
0xFF4D => Ok(CgbIoAddress::PrepareSpeed),
0xFF4F => Ok(CgbIoAddress::VramBank),
0xFF51..0xFF56 => Ok(CgbIoAddress::VramDma(self.try_into().unwrap())),
0xFF56 => Ok(CgbIoAddress::Infrared),
0xFF68..0xFF6C => Ok(CgbIoAddress::Palette(self.try_into().unwrap())),
0xFF6C => Ok(CgbIoAddress::ObjPriority),
0xFF70 => Ok(CgbIoAddress::WramBank), 0xFF70 => Ok(CgbIoAddress::WramBank),
0xFF76 => Ok(CgbIoAddress::Pcm12),
0xFF77 => Ok(CgbIoAddress::Pcm34),
0x0..0xFF4D | 0xFF78..=0xFFFF => Err(AddressError::OutOfBounds), 0x0..0xFF4D | 0xFF78..=0xFFFF => Err(AddressError::OutOfBounds),
_ => Ok(CgbIoAddress::Unused(self)), _ => Ok(CgbIoAddress::Unused(self)),
} }
@ -154,8 +173,16 @@ impl AddressMarker for IoAddress {
impl AddressMarker for CgbIoAddress { impl AddressMarker for CgbIoAddress {
fn inner(&self) -> u16 { fn inner(&self) -> u16 {
match self { match self {
CgbIoAddress::Unused(v) => *v, CgbIoAddress::PrepareSpeed => 0xFF4D,
CgbIoAddress::VramBank => 0xFF4F,
CgbIoAddress::VramDma(v) => v.inner(),
CgbIoAddress::Infrared => 0xFF56,
CgbIoAddress::Palette(v) => v.inner(),
CgbIoAddress::ObjPriority => 0xFF6C,
CgbIoAddress::WramBank => 0xFF70, CgbIoAddress::WramBank => 0xFF70,
CgbIoAddress::Pcm12 => 0xFF76,
CgbIoAddress::Pcm34 => 0xFF77,
CgbIoAddress::Unused(v) => *v,
} }
} }
} }

View file

@ -1,6 +1,7 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use self::{ use self::{
cgb::CgbData,
tile_window::TileWindow, tile_window::TileWindow,
types::{ types::{
DrawMode, GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags, Palette, DrawMode, GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags, Palette,
@ -20,6 +21,7 @@ use serde::{Deserialize, Serialize};
pub use types::Colour; pub use types::Colour;
mod addresses; mod addresses;
mod cgb;
mod tile_window; mod tile_window;
mod types; mod types;
@ -52,6 +54,7 @@ where
wx: u8, wx: u8,
wy: u8, wy: u8,
prev_stat: bool, prev_stat: bool,
cgb_data: Option<CgbData>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -79,6 +82,7 @@ where
wx: u8, wx: u8,
wy: u8, wy: u8,
prev_stat: bool, prev_stat: bool,
cgb_data: Option<CgbData>,
#[serde(skip)] #[serde(skip)]
spooky: PhantomData<R>, spooky: PhantomData<R>,
} }
@ -91,7 +95,7 @@ where
pub fn create(gpu: &Gpu<ColourFormat, R>) -> Self { pub fn create(gpu: &Gpu<ColourFormat, R>) -> Self {
Self { Self {
buffer: gpu.buffer.clone(), buffer: gpu.buffer.clone(),
vram: gpu.vram, vram: gpu.vram.clone(),
oam: gpu.oam, oam: gpu.oam,
is_bg_zero: gpu.is_bg_zero.clone(), is_bg_zero: gpu.is_bg_zero.clone(),
lcdc: gpu.lcdc, lcdc: gpu.lcdc,
@ -109,6 +113,7 @@ where
wx: gpu.wx, wx: gpu.wx,
wy: gpu.wy, wy: gpu.wy,
prev_stat: gpu.prev_stat, prev_stat: gpu.prev_stat,
cgb_data: gpu.cgb_data,
spooky: PhantomData, spooky: PhantomData,
} }
} }
@ -119,7 +124,7 @@ where
ColourFormat: From<Colour> + Clone, ColourFormat: From<Colour> + Clone,
R: Renderer<ColourFormat>, R: Renderer<ColourFormat>,
{ {
pub fn new(window: R, tile_window_renderer: Option<R>) -> Self { pub fn new(cgb: bool, window: R, tile_window_renderer: Option<R>) -> Self {
let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer { let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer {
tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT); tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT);
Some(TileWindow::new(tile_window_renderer)) Some(TileWindow::new(tile_window_renderer))
@ -130,7 +135,7 @@ where
Self { Self {
buffer, buffer,
vram: Vram::default(), vram: Vram::new(cgb),
oam: Oam::default(), oam: Oam::default(),
window, window,
is_bg_zero: vec![true; WIDTH], is_bg_zero: vec![true; WIDTH],
@ -150,6 +155,7 @@ where
wx: 0, wx: 0,
wy: 0, wy: 0,
prev_stat: false, prev_stat: false,
cgb_data: if cgb { Some(CgbData::default()) } else { None },
} }
} }
@ -187,6 +193,7 @@ where
wx: state.wx, wx: state.wx,
wy: state.wy, wy: state.wy,
prev_stat: state.prev_stat, prev_stat: state.prev_stat,
cgb_data: state.cgb_data,
} }
} }

View file

@ -0,0 +1,90 @@
use serde::{Deserialize, Serialize};
use crate::{
connect::Renderer,
processor::memory::addresses::{AddressMarker, CgbPaletteAddress},
util::get_bit,
};
use super::{Colour, Gpu};
#[derive(Serialize, Deserialize, Clone, Copy, Default)]
pub(super) struct CgbData {
palettes: CgbPaletteRegisters,
}
#[derive(Serialize, Deserialize, Clone, Copy, Default)]
struct CgbPaletteRegisters {
bg: CgbPalette,
obj: CgbPalette,
}
#[serde_with::serde_as]
#[derive(Serialize, Deserialize, Clone, Copy)]
struct CgbPalette {
auto_increment: bool,
index: u8,
#[serde_as(as = "[_; 0x40]")]
data: [u8; 0x40],
}
impl Default for CgbPalette {
fn default() -> Self {
Self {
auto_increment: false,
index: 0,
data: [0; 0x40],
}
}
}
impl CgbPalette {
fn set_control(&mut self, data: u8) {
self.index = data & 0b111111;
self.auto_increment = get_bit(data, 7);
}
fn get_control(&self) -> u8 {
(if self.auto_increment { 1 << 7 } else { 0 } | (self.index & 0b111111))
}
fn set_data(&mut self, data: u8) {
self.data[self.index as usize] = data;
}
fn get_data(&self) -> u8 {
self.data[self.index as usize]
}
}
impl<ColourFormat, R> Gpu<ColourFormat, R>
where
ColourFormat: From<Colour> + Clone,
R: Renderer<ColourFormat>,
{
pub(crate) fn get_cgb_palette(&self, address: CgbPaletteAddress) -> u8 {
if let Some(cgb_data) = &self.cgb_data {
match address.inner() {
0xFF68 => cgb_data.palettes.bg.get_control(),
0xFF69 => cgb_data.palettes.bg.get_data(),
0xFF6A => cgb_data.palettes.obj.get_control(),
0xFF6B => cgb_data.palettes.obj.get_data(),
_ => unreachable!(),
}
} else {
0xFF
}
}
pub(crate) fn set_cgb_palette(&mut self, address: CgbPaletteAddress, data: u8) {
if let Some(cgb_data) = &mut self.cgb_data {
match address.inner() {
0xFF68 => cgb_data.palettes.bg.set_control(data),
0xFF69 => cgb_data.palettes.bg.set_data(data),
0xFF6A => cgb_data.palettes.obj.set_control(data),
0xFF6B => cgb_data.palettes.obj.set_data(data),
_ => unreachable!(),
}
}
}
}

View file

@ -219,26 +219,72 @@ impl Default for Stat {
} }
} }
#[serde_with::serde_as]
#[derive(Serialize, Deserialize, Clone, Copy)] #[derive(Serialize, Deserialize, Clone, Copy)]
pub struct Vram { pub enum VramBank {
#[serde_as(as = "[_; 8192]")] Bank0 = 0,
data: [u8; 8192], Bank1 = 1,
}
#[serde_with::serde_as]
#[derive(Serialize, Deserialize, Clone)]
pub enum Vram {
Dmg {
#[serde_as(as = "Box<[_; 8192]>")]
inner: Box<[u8; 8192]>,
},
Cgb {
#[serde_as(as = "Box<[[_; 8192];2]>")]
inner: Box<[[u8; 8192]; 2]>,
index: VramBank,
},
} }
impl Vram { impl Vram {
pub(crate) fn new(cgb: bool) -> Self {
if cgb {
Self::Cgb {
inner: Box::new([[0; 8192]; 2]),
index: VramBank::Bank0,
}
} else {
Self::Dmg {
inner: Box::new([0; 8192]),
}
}
}
pub(crate) fn get(&self, address: VramAddress) -> u8 { pub(crate) fn get(&self, address: VramAddress) -> u8 {
self.data[address.get_local() as usize] match self {
Vram::Dmg { inner } => inner[address.get_local() as usize],
Vram::Cgb { inner, index } => inner[*index as usize][address.get_local() as usize],
}
} }
pub(crate) fn set(&mut self, address: VramAddress, data: u8) { pub(crate) fn set(&mut self, address: VramAddress, data: u8) {
self.data[address.get_local() as usize] = data; match self {
Vram::Dmg { inner } => inner[address.get_local() as usize] = data,
Vram::Cgb { inner, index } => {
inner[*index as usize][address.get_local() as usize] = data
}
} }
} }
impl Default for Vram { pub(crate) fn get_vram_bank(&self) -> u8 {
fn default() -> Self { if let Vram::Cgb { inner: _, index } = self {
Self { data: [0x0; 8192] } (*index as u8) | (!1)
} else {
0xFF
}
}
pub(crate) fn set_vram_bank(&mut self, data: u8) {
if let Vram::Cgb { inner: _, index } = self {
*index = if data & 0b1 == 0 {
VramBank::Bank0
} else {
VramBank::Bank1
}
}
} }
} }