core: Handle 8bit writes to video memory

fixes #96


Former-commit-id: efdb6c0af0ef6ee2a74042b8725306103703fcfe
Former-commit-id: 1f0e7f7135649ab13c4adcb72bc5e9b432a4905f
This commit is contained in:
Michel Heily 2020-05-18 21:11:49 +03:00
parent 63bf7d6dbb
commit 309ae2f795
2 changed files with 67 additions and 20 deletions

View file

@ -5,9 +5,10 @@ use std::rc::Rc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::interrupt::IrqBitmask; use super::interrupt::IrqBitmask;
pub use super::sysbus::consts::*;
use super::sysbus::{BoxedMemory, SysBus}; use super::sysbus::{BoxedMemory, SysBus};
use super::Bus;
use super::VideoInterface; use super::VideoInterface;
use super::{Addr, Bus};
use crate::bitfield::Bit; use crate::bitfield::Bit;
use crate::num::FromPrimitive; use crate::num::FromPrimitive;
@ -30,11 +31,11 @@ pub use regs::*;
#[allow(unused)] #[allow(unused)]
pub mod consts { pub mod consts {
pub use super::VRAM_ADDR;
pub const VIDEO_RAM_SIZE: usize = 128 * 1024; pub const VIDEO_RAM_SIZE: usize = 128 * 1024;
pub const PALETTE_RAM_SIZE: usize = 1 * 1024; pub const PALETTE_RAM_SIZE: usize = 1 * 1024;
pub const OAM_SIZE: usize = 1 * 1024; pub const OAM_SIZE: usize = 1 * 1024;
pub const VRAM_ADDR: u32 = 0x0600_0000;
pub const DISPLAY_WIDTH: usize = 240; pub const DISPLAY_WIDTH: usize = 240;
pub const DISPLAY_HEIGHT: usize = 160; pub const DISPLAY_HEIGHT: usize = 160;
pub const VBLANK_LINES: usize = 68; pub const VBLANK_LINES: usize = 68;
@ -203,6 +204,68 @@ pub struct Gpu {
pub(super) frame_buffer: Vec<u32>, pub(super) frame_buffer: Vec<u32>,
} }
impl Bus for Gpu {
fn read_8(&self, addr: Addr) -> u8 {
let page = (addr >> 24) as usize;
match page {
PAGE_PALRAM => self.palette_ram.read_8(addr & 0x3ff),
PAGE_VRAM => {
// complicated
let mut ofs = addr & ((VIDEO_RAM_SIZE as u32) - 1);
if ofs > 0x18000 {
ofs -= 0x8000;
}
self.vram.read_8(ofs)
}
PAGE_OAM => self.oam.read_8(addr & 0x3ff),
_ => unreachable!(),
}
}
fn write_16(&mut self, addr: Addr, value: u16) {
let page = (addr >> 24) as usize;
match page {
PAGE_PALRAM => self.palette_ram.write_16(addr & 0x3fe, value),
PAGE_VRAM => {
let mut ofs = addr & ((VIDEO_RAM_SIZE as u32) - 1);
if ofs > 0x18000 {
ofs -= 0x8000;
}
self.vram.write_16(ofs, value)
}
PAGE_OAM => self.oam.write_16(addr & 0x3fe, value),
_ => unreachable!(),
}
}
fn write_8(&mut self, addr: Addr, value: u8) {
fn expand_value(value: u8) -> u16 {
(value as u16) * 0x101
}
let page = (addr >> 24) as usize;
match page {
PAGE_PALRAM => self.oam.write_16(addr & 0x3fe, expand_value(value)),
PAGE_VRAM => {
let mut ofs = addr & ((VIDEO_RAM_SIZE as u32) - 1);
if ofs > 0x18000 {
ofs -= 0x8000;
}
let obj_offset = if self.dispcnt.mode() >= 3 {
0x14000
} else {
0x10000
};
if ofs < obj_offset {
self.vram.write_16(ofs & !1, expand_value(value));
}
}
PAGE_OAM => { /* OAM can't be written with 8bit store */ }
_ => unreachable!(),
};
}
}
impl Gpu { impl Gpu {
pub fn new() -> Gpu { pub fn new() -> Gpu {
Gpu { Gpu {

View file

@ -255,15 +255,7 @@ macro_rules! memory_map {
}; };
$sb.io.$read_fn(addr) $sb.io.$read_fn(addr)
} }
PALRAM_ADDR => $sb.io.gpu.palette_ram.$read_fn($addr & 0x3ff), PALRAM_ADDR | VRAM_ADDR | OAM_ADDR => $sb.io.gpu.$read_fn($addr),
VRAM_ADDR => {
let mut ofs = $addr & ((VIDEO_RAM_SIZE as u32) - 1);
if ofs > 0x18000 {
ofs -= 0x8000;
}
$sb.io.gpu.vram.$read_fn(ofs)
}
OAM_ADDR => $sb.io.gpu.oam.$read_fn($addr & 0x3ff),
GAMEPAK_WS0_LO | GAMEPAK_WS0_HI | GAMEPAK_WS1_LO | GAMEPAK_WS1_HI | GAMEPAK_WS2_LO => { GAMEPAK_WS0_LO | GAMEPAK_WS0_HI | GAMEPAK_WS1_LO | GAMEPAK_WS1_HI | GAMEPAK_WS2_LO => {
$sb.cartridge.$read_fn($addr) $sb.cartridge.$read_fn($addr)
} }
@ -289,15 +281,7 @@ macro_rules! memory_map {
}; };
$sb.io.$write_fn(addr, $value) $sb.io.$write_fn(addr, $value)
} }
PALRAM_ADDR => $sb.io.gpu.palette_ram.$write_fn($addr & 0x3ff, $value), PALRAM_ADDR | VRAM_ADDR | OAM_ADDR => $sb.io.gpu.$write_fn($addr, $value),
VRAM_ADDR => {
let mut ofs = $addr & ((VIDEO_RAM_SIZE as u32) - 1);
if ofs > 0x18000 {
ofs -= 0x8000;
}
$sb.io.gpu.vram.$write_fn(ofs, $value)
}
OAM_ADDR => $sb.io.gpu.oam.$write_fn($addr & 0x3ff, $value),
GAMEPAK_WS0_LO | GAMEPAK_WS0_HI => {} GAMEPAK_WS0_LO | GAMEPAK_WS0_HI => {}
GAMEPAK_WS2_HI => $sb.cartridge.$write_fn($addr, $value), GAMEPAK_WS2_HI => $sb.cartridge.$write_fn($addr, $value),
SRAM_LO | SRAM_HI => $sb.cartridge.$write_fn($addr, $value), SRAM_LO | SRAM_HI => $sb.cartridge.$write_fn($addr, $value),