bios boots! ish!
This commit is contained in:
parent
c56e167c6b
commit
7d90d516ed
|
@ -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!()
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
90
lib/src/processor/memory/mmio/gpu/cgb.rs
Normal file
90
lib/src/processor/memory/mmio/gpu/cgb.rs
Normal 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!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue