many gpu things work now
This commit is contained in:
parent
9ada49a6d8
commit
f1ce5cfc9f
5 changed files with 157 additions and 20 deletions
|
@ -364,6 +364,7 @@ where
|
|||
IoAddress::Cgb(address) => {
|
||||
if let WramBanks::Cgb { banks: _, selected } = &self.ram.banks && let Some(cgb_peripherals) = &self.cgb_peripherals {
|
||||
match address {
|
||||
CgbIoAddress::CompatMode => self.gpu.get_compat_byte(),
|
||||
CgbIoAddress::PrepareSpeed => cgb_peripherals.double_speed.get(),
|
||||
CgbIoAddress::VramBank => self.gpu.vram.get_vram_bank(),
|
||||
CgbIoAddress::VramDma(address) => cgb_peripherals.vram_dma.get_register(address),
|
||||
|
@ -423,6 +424,7 @@ where
|
|||
IoAddress::Cgb(address) => {
|
||||
if let WramBanks::Cgb { banks: _, selected } = &mut self.ram.banks && let Some(cgb_peripherals) = &mut self.cgb_peripherals {
|
||||
match address {
|
||||
CgbIoAddress::CompatMode => self.gpu.set_compat_byte(data),
|
||||
CgbIoAddress::PrepareSpeed => cgb_peripherals.double_speed.set(data),
|
||||
CgbIoAddress::VramBank => self.gpu.vram.set_vram_bank(data),
|
||||
CgbIoAddress::VramDma(address) => cgb_peripherals.vram_dma.set_register(address, data),
|
||||
|
|
|
@ -47,6 +47,7 @@ pub(crate) enum IoAddress {
|
|||
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) enum CgbIoAddress {
|
||||
CompatMode,
|
||||
PrepareSpeed,
|
||||
VramBank,
|
||||
VramDma(VramDmaAddress),
|
||||
|
@ -122,7 +123,7 @@ impl TryInto<IoAddress> for u16 {
|
|||
0xFF10..0xFF27 => Ok(IoAddress::Audio(self.try_into().unwrap())),
|
||||
0xFF30..0xFF40 => Ok(IoAddress::WaveRam(self.try_into().unwrap())),
|
||||
0xFF40..0xFF4C => Ok(IoAddress::Video(self.try_into().unwrap())),
|
||||
0xFF4D..0xFF78 => Ok(IoAddress::Cgb(self.try_into().unwrap())),
|
||||
0xFF4C..0xFF78 => Ok(IoAddress::Cgb(self.try_into().unwrap())),
|
||||
0x0..0xFF00 | 0xFFFF => Err(AddressError::OutOfBounds),
|
||||
_ => Ok(IoAddress::Unused(self)),
|
||||
}
|
||||
|
@ -134,6 +135,7 @@ impl TryInto<CgbIoAddress> for u16 {
|
|||
|
||||
fn try_into(self) -> Result<CgbIoAddress, Self::Error> {
|
||||
match self {
|
||||
0xFF4C => Ok(CgbIoAddress::CompatMode),
|
||||
0xFF4D => Ok(CgbIoAddress::PrepareSpeed),
|
||||
0xFF4F => Ok(CgbIoAddress::VramBank),
|
||||
0xFF51..0xFF56 => Ok(CgbIoAddress::VramDma(self.try_into().unwrap())),
|
||||
|
@ -143,7 +145,7 @@ impl TryInto<CgbIoAddress> for u16 {
|
|||
0xFF70 => Ok(CgbIoAddress::WramBank),
|
||||
0xFF76 => Ok(CgbIoAddress::Pcm12),
|
||||
0xFF77 => Ok(CgbIoAddress::Pcm34),
|
||||
0x0..0xFF4D | 0xFF78..=0xFFFF => Err(AddressError::OutOfBounds),
|
||||
0x0..0xFF4C | 0xFF78..=0xFFFF => Err(AddressError::OutOfBounds),
|
||||
_ => Ok(CgbIoAddress::Unused(self)),
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +179,7 @@ impl AddressMarker for IoAddress {
|
|||
impl AddressMarker for CgbIoAddress {
|
||||
fn inner(&self) -> u16 {
|
||||
match self {
|
||||
CgbIoAddress::CompatMode => 0xFF4C,
|
||||
CgbIoAddress::PrepareSpeed => 0xFF4D,
|
||||
CgbIoAddress::VramBank => 0xFF4F,
|
||||
CgbIoAddress::VramDma(v) => v.inner(),
|
||||
|
|
|
@ -5,8 +5,8 @@ use self::{
|
|||
cgb::CgbData,
|
||||
tile_window::TileWindow,
|
||||
types::{
|
||||
ColourInner, GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object, ObjectFlags, Palette,
|
||||
Stat, TiledataArea, TilemapArea, Vram,
|
||||
BgAttributes, ColourInner, GpuInterrupts, Lcdc, Oam, ObjPalette, ObjSize, Object,
|
||||
ObjectFlags, Palette, Stat, TiledataArea, TilemapArea, Vram, VramBank,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
|
@ -396,11 +396,17 @@ where
|
|||
behind_bg_and_window: get_bit(flags, 7),
|
||||
y_flip: get_bit(flags, 6),
|
||||
x_flip: get_bit(flags, 5),
|
||||
palette: if get_bit(flags, 4) {
|
||||
dmg_palette: if get_bit(flags, 4) {
|
||||
ObjPalette::One
|
||||
} else {
|
||||
ObjPalette::Zero
|
||||
},
|
||||
cgb_vram_bank: if get_bit(flags, 3) {
|
||||
VramBank::Bank1
|
||||
} else {
|
||||
VramBank::Bank0
|
||||
},
|
||||
cgb_palette: flags & 0b111,
|
||||
},
|
||||
oam_location: (i - 0xFE00) as u8,
|
||||
});
|
||||
|
@ -429,13 +435,22 @@ where
|
|||
.get_addr(object.tile_index + if object_row >= 8 { 1 } else { 0 })
|
||||
+ (tile_row as u16 * 2))
|
||||
.unwrap();
|
||||
let lsbs = self.vram.get(tile_addr);
|
||||
let msbs = self.vram.get((tile_addr + 1).unwrap());
|
||||
let bank = if self.is_cgb_mode() {
|
||||
object.flags.cgb_vram_bank
|
||||
} else {
|
||||
VramBank::Bank0
|
||||
};
|
||||
let lsbs = self.vram.get_with_bank(tile_addr, bank).unwrap();
|
||||
let msbs = self
|
||||
.vram
|
||||
.get_with_bank((tile_addr + 1).unwrap(), bank)
|
||||
.unwrap();
|
||||
for px_x in 0..8 {
|
||||
let x_addr = if object.flags.x_flip { px_x } else { 7 - px_x };
|
||||
let lsb = get_bit(lsbs, x_addr);
|
||||
let msb = get_bit(msbs, x_addr);
|
||||
let (colour, is_zero) = match object.flags.palette {
|
||||
// maybe have to change this for cgb mode
|
||||
let (colour, is_zero) = match object.flags.dmg_palette {
|
||||
ObjPalette::Zero => self.obj_palette_0,
|
||||
ObjPalette::One => self.obj_palette_1,
|
||||
}
|
||||
|
@ -451,7 +466,16 @@ where
|
|||
if x_coord < WIDTH {
|
||||
let buffer_index = (scanline as usize * WIDTH) + x_coord;
|
||||
if !object.flags.behind_bg_and_window || self.is_bg_zero[x_coord] {
|
||||
let cgb_data = self.cgb_data.as_ref().map(|v| (v.palettes.obj, 0));
|
||||
let cgb_data = self.cgb_data.as_ref().map(|v| {
|
||||
(
|
||||
v.palettes.obj,
|
||||
if self.is_cgb_mode() {
|
||||
object.flags.cgb_palette
|
||||
} else {
|
||||
0
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
self.buffer[buffer_index] = colour.rgb_bytes(cgb_data).into();
|
||||
}
|
||||
|
@ -473,8 +497,6 @@ where
|
|||
return;
|
||||
}
|
||||
let tilemap_row = tile_line_y / 8;
|
||||
let tile_px_y = (tile_line_y) % 8;
|
||||
let tiledata_offset = tile_px_y * 2;
|
||||
let row_addr = ((tilemap_row as usize * 32) % 0x400) as u16;
|
||||
for x in 0..WIDTH {
|
||||
let (tile_line_x, did_wrap_x) = (x as u8).overflowing_sub(offset_x);
|
||||
|
@ -484,22 +506,49 @@ where
|
|||
|
||||
let tilemap_column = (tile_line_x / 8) as u16;
|
||||
|
||||
let tile_px_x = tile_line_x % 8;
|
||||
let tile_addr = (self
|
||||
.lcdc
|
||||
.tile_area
|
||||
.get_addr(self.vram.get(tilemap.get_addr(row_addr + (tilemap_column))))
|
||||
let tilemap_addr = tilemap.get_addr(row_addr + (tilemap_column));
|
||||
let attributes = if self.is_cgb_mode() {
|
||||
self.vram
|
||||
.get_with_bank(tilemap_addr, VramBank::Bank1)
|
||||
.map_or(BgAttributes::default(), BgAttributes::from_byte)
|
||||
} else {
|
||||
BgAttributes::default()
|
||||
};
|
||||
|
||||
let tile_px_y = if attributes.flip_v {
|
||||
7 - ((tile_line_y) % 8)
|
||||
} else {
|
||||
(tile_line_y) % 8
|
||||
};
|
||||
let tiledata_offset = tile_px_y * 2;
|
||||
|
||||
let tile_addr = (self.lcdc.tile_area.get_addr(self.vram.get(tilemap_addr))
|
||||
+ tiledata_offset as u16)
|
||||
.unwrap();
|
||||
|
||||
let lsbs = self.vram.get(tile_addr);
|
||||
let msbs = self.vram.get((tile_addr + 1).unwrap());
|
||||
let lsbs = self
|
||||
.vram
|
||||
.get_with_bank(tile_addr, attributes.tile_bank)
|
||||
.unwrap();
|
||||
let msbs = self
|
||||
.vram
|
||||
.get_with_bank((tile_addr + 1).unwrap(), attributes.tile_bank)
|
||||
.unwrap();
|
||||
|
||||
let tile_px_x = if attributes.flip_h {
|
||||
7 - (tile_line_x % 8)
|
||||
} else {
|
||||
tile_line_x % 8
|
||||
};
|
||||
let lsb = get_bit(lsbs, 7 - tile_px_x);
|
||||
let msb = get_bit(msbs, 7 - tile_px_x);
|
||||
let (colour, is_zero) = self.bg_palette.map_bits(lsb, msb);
|
||||
self.is_bg_zero[x] = is_zero;
|
||||
|
||||
let cgb_data = self.cgb_data.as_ref().map(|v| (v.palettes.bg, 0));
|
||||
let cgb_data = self
|
||||
.cgb_data
|
||||
.as_ref()
|
||||
.map(|v| (v.palettes.bg, attributes.palette));
|
||||
|
||||
self.buffer[(scanline as usize * WIDTH) + x] = colour.rgb_bytes(cgb_data).into();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use super::{Colour, Gpu};
|
|||
pub(super) struct CgbData {
|
||||
pub(super) palettes: CgbPaletteRegisters,
|
||||
pub(super) object_priority_mode: ObjectPriorityMode,
|
||||
compat_byte: u8,
|
||||
}
|
||||
|
||||
impl Default for CgbData {
|
||||
|
@ -19,6 +20,7 @@ impl Default for CgbData {
|
|||
Self {
|
||||
palettes: Default::default(),
|
||||
object_priority_mode: ObjectPriorityMode::Coordinate,
|
||||
compat_byte: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,4 +126,26 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_compat_byte(&self) -> u8 {
|
||||
if let Some(cgb_data) = &self.cgb_data {
|
||||
cgb_data.compat_byte
|
||||
} else {
|
||||
0xFF
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_compat_byte(&mut self, data: u8) {
|
||||
if let Some(cgb_data) = &mut self.cgb_data {
|
||||
cgb_data.compat_byte = data;
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn is_cgb_mode(&self) -> bool {
|
||||
if let Some(cgb_data) = &self.cgb_data {
|
||||
cgb_data.compat_byte != 0x04
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,7 +202,9 @@ pub(super) struct ObjectFlags {
|
|||
pub(super) behind_bg_and_window: bool,
|
||||
pub(super) y_flip: bool,
|
||||
pub(super) x_flip: bool,
|
||||
pub(super) palette: ObjPalette,
|
||||
pub(super) dmg_palette: ObjPalette,
|
||||
pub(super) cgb_vram_bank: VramBank,
|
||||
pub(super) cgb_palette: u8,
|
||||
}
|
||||
|
||||
pub(super) enum ObjPalette {
|
||||
|
@ -280,6 +282,27 @@ impl Vram {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_with_bank(&self, address: VramAddress, bank: VramBank) -> Option<u8> {
|
||||
match bank {
|
||||
VramBank::Bank0 => Some(self.bank0_get(address)),
|
||||
VramBank::Bank1 => self.bank1_get(address),
|
||||
}
|
||||
}
|
||||
|
||||
fn bank0_get(&self, address: VramAddress) -> u8 {
|
||||
match self {
|
||||
Vram::Dmg { inner } => inner[address.get_local() as usize],
|
||||
Vram::Cgb { inner, index: _ } => inner[0][address.get_local() as usize],
|
||||
}
|
||||
}
|
||||
|
||||
fn bank1_get(&self, address: VramAddress) -> Option<u8> {
|
||||
match self {
|
||||
Vram::Dmg { inner: _ } => None,
|
||||
Vram::Cgb { inner, index: _ } => Some(inner[1][address.get_local() as usize]),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set(&mut self, address: VramAddress, data: u8) {
|
||||
match self {
|
||||
Vram::Dmg { inner } => inner[address.get_local() as usize] = data,
|
||||
|
@ -336,3 +359,39 @@ pub struct GpuInterrupts {
|
|||
pub lcd_stat: bool,
|
||||
pub vblank: bool,
|
||||
}
|
||||
|
||||
pub(super) struct BgAttributes {
|
||||
pub(super) bg_priority: bool,
|
||||
pub(super) flip_v: bool,
|
||||
pub(super) flip_h: bool,
|
||||
pub(super) tile_bank: VramBank,
|
||||
pub(super) palette: u8,
|
||||
}
|
||||
|
||||
impl Default for BgAttributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bg_priority: Default::default(),
|
||||
flip_v: Default::default(),
|
||||
flip_h: Default::default(),
|
||||
tile_bank: VramBank::Bank0,
|
||||
palette: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BgAttributes {
|
||||
pub(super) fn from_byte(byte: u8) -> Self {
|
||||
Self {
|
||||
bg_priority: get_bit(byte, 7),
|
||||
flip_v: get_bit(byte, 6),
|
||||
flip_h: get_bit(byte, 5),
|
||||
tile_bank: if get_bit(byte, 3) {
|
||||
VramBank::Bank1
|
||||
} else {
|
||||
VramBank::Bank0
|
||||
},
|
||||
palette: byte & 0b111,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue