Dirty bit detection for Video RAM

The DMD library now keeps track of when writes to video RAM occur, and
sets a dirty bit. This dirty bit is reset when the video RAM is
requested by the library user, and can be used to avoid repainting when
video ram has not changed.
This commit is contained in:
Seth Morabito 2022-09-13 11:40:38 -07:00
parent 03d0d36061
commit 31f1008458
2 changed files with 48 additions and 7 deletions

View File

@ -63,6 +63,7 @@ pub struct Bus {
vid: Mem, // TODO: Figure out what device this really is
bbram: Mem, // TODO: change to BBRAM when implemented
ram: Mem,
video_ram_dirty: bool,
}
impl Bus {
@ -74,6 +75,7 @@ impl Bus {
vid: Mem::new(0x500000, 0x2, false),
bbram: Mem::new(0x600000, 0x2000, false),
ram: Mem::new(0x700000, mem_size, false),
video_ram_dirty: false,
}
}
@ -105,6 +107,18 @@ impl Bus {
Err(BusError::NoDevice(address))
}
fn video_ram_range(&self) -> Range<usize> {
let vid_register = (u16::from(self.vid[0]) << 8 | u16::from(self.vid[1])) as usize;
let start = vid_register * 4;
let end = start + 0x19000;
start..end
}
fn is_video_ram(&self, address: usize) -> bool {
(0x700000..0x800000).contains(&address)
&& self.video_ram_range().contains(&(address - 0x700000))
}
pub fn read_byte(&mut self, address: usize, access: AccessCode) -> Result<u8, BusError> {
self.get_device(address)?.read_byte(address, access)
}
@ -140,6 +154,9 @@ impl Bus {
}
pub fn write_byte(&mut self, address: usize, val: u8) -> Result<(), BusError> {
if self.is_video_ram(address) {
self.video_ram_dirty = true;
}
self.get_device(address)?.write_byte(address, val, AccessCode::Write)
}
@ -147,6 +164,9 @@ impl Bus {
if address & 1 != 0 {
return Err(BusError::Alignment(address));
}
if self.is_video_ram(address) {
self.video_ram_dirty = true;
}
self.get_device(address)?.write_half(address, val, AccessCode::Write)
}
@ -154,6 +174,9 @@ impl Bus {
if address & 3 != 0 {
return Err(BusError::Alignment(address));
}
if self.is_video_ram(address) {
self.video_ram_dirty = true;
}
self.get_device(address)?.write_word(address, val, AccessCode::Write)
}
@ -161,11 +184,14 @@ impl Bus {
self.get_device(address)?.load(address, data)
}
pub fn video_ram(&self) -> &[u8] {
let vid_register = (u16::from(self.vid[0]) << 8 | u16::from(self.vid[1])) as usize;
let start = vid_register * 4;
let end = start + 0x19000;
self.ram.as_slice(start..end)
pub fn video_ram(&mut self) -> &[u8] {
self.video_ram_dirty = false;
let range = self.video_ram_range();
self.ram.as_slice(range)
}
pub fn video_ram_dirty(&self) -> bool {
self.video_ram_dirty
}
pub fn service(&mut self) {

View File

@ -64,10 +64,14 @@ impl Dmd {
Ok(())
}
pub fn video_ram(&self) -> &[u8] {
pub fn video_ram(&mut self) -> &[u8] {
self.bus.video_ram()
}
pub fn video_ram_dirty(&self) -> bool {
self.bus.video_ram_dirty()
}
pub fn get_pc(&self) -> u32 {
self.cpu.get_pc()
}
@ -167,11 +171,22 @@ fn dmd_init(version: u8) -> c_int {
#[no_mangle]
fn dmd_video_ram() -> *const u8 {
match DMD.lock() {
Ok(dmd) => dmd.video_ram().as_ptr(),
Ok(mut dmd) => dmd.video_ram().as_ptr(),
Err(_) => ptr::null(),
}
}
#[no_mangle]
fn dmd_video_ram_dirty() -> c_int {
match DMD.lock() {
Ok(dmd) => match dmd.video_ram_dirty() {
true => 1,
false => 0,
},
Err(_) => 0,
}
}
#[no_mangle]
fn dmd_step() -> c_int {
match DMD.lock() {