Fix affine backgrounds

Writing to reference point BGnX and BGnY should update the internal PPU
registers also inside VBLANK period.

fixes #79


Former-commit-id: a5237319ccab1aab023bb05878c81a198310fb21
Former-commit-id: 0c9ce4476111eea46e7372b48af77c862c0d2f6a
This commit is contained in:
Michel Heily 2020-05-09 18:50:35 +03:00
parent 84cb8c1808
commit b745e07fa3

View file

@ -132,6 +132,26 @@ impl Bus for IoDevices {
return; return;
} }
let io_addr = addr + IO_BASE; let io_addr = addr + IO_BASE;
macro_rules! write_reference_point {
(low bg $coord:ident $internal:ident) => {{
let i = ((io_addr - REG_BG2X_L) / 0x10) as usize;
let t = io.gpu.bg_aff[i].$coord as u32;
io.gpu.bg_aff[i].$coord = ((t & 0xffff0000) + (value as u32)) as i32;
let new_value = ((t & 0xffff0000) + (value as u32)) as i32;
io.gpu.bg_aff[i].$coord = new_value;
io.gpu.bg_aff[i].$internal = new_value;
}};
(high bg $coord:ident $internal:ident) => {{
let i = ((io_addr - REG_BG2X_L) / 0x10) as usize;
let t = io.gpu.bg_aff[i].$coord;
let new_value =
(t & 0xffff) | ((sign_extend_i32((value & 0xfff) as i32, 12)) << 16);
io.gpu.bg_aff[i].$coord = new_value;
io.gpu.bg_aff[i].$internal = new_value;
}};
}
match io_addr { match io_addr {
REG_DISPCNT => io.gpu.dispcnt.0 = value, REG_DISPCNT => io.gpu.dispcnt.0 = value,
REG_DISPSTAT => io.gpu.dispstat.0 = value | (io.gpu.dispstat.0 & 7), REG_DISPSTAT => io.gpu.dispstat.0 = value | (io.gpu.dispstat.0 & 7),
@ -147,40 +167,10 @@ impl Bus for IoDevices {
REG_BG2VOFS => io.gpu.backgrounds[2].bgvofs = value & 0x1ff, REG_BG2VOFS => io.gpu.backgrounds[2].bgvofs = value & 0x1ff,
REG_BG3HOFS => io.gpu.backgrounds[3].bghofs = value & 0x1ff, REG_BG3HOFS => io.gpu.backgrounds[3].bghofs = value & 0x1ff,
REG_BG3VOFS => io.gpu.backgrounds[3].bgvofs = value & 0x1ff, REG_BG3VOFS => io.gpu.backgrounds[3].bgvofs = value & 0x1ff,
REG_BG2X_L | REG_BG3X_L => { REG_BG2X_L | REG_BG3X_L => write_reference_point!(low bg x internal_x),
let index = (io_addr - REG_BG2X_L) / 0x10; REG_BG2Y_L | REG_BG3Y_L => write_reference_point!(low bg y internal_y),
let t = io.gpu.bg_aff[index as usize].x as u32; REG_BG2X_H | REG_BG3X_H => write_reference_point!(high bg x internal_x),
io.gpu.bg_aff[index as usize].x = ((t & 0xffff0000) + (value as u32)) as i32; REG_BG2Y_H | REG_BG3Y_H => write_reference_point!(high bg y internal_y),
if !io.gpu.state.is_vblank() {
io.gpu.bg_aff[index as usize].internal_x = io.gpu.bg_aff[index as usize].x;
}
}
REG_BG2Y_L | REG_BG3Y_L => {
let index = (io_addr - REG_BG2X_L) / 0x10;
let t = io.gpu.bg_aff[index as usize].y as u32;
io.gpu.bg_aff[index as usize].y = ((t & 0xffff0000) + (value as u32)) as i32;
if !io.gpu.state.is_vblank() {
io.gpu.bg_aff[index as usize].internal_y = io.gpu.bg_aff[index as usize].y;
}
}
REG_BG2X_H | REG_BG3X_H => {
let index = (io_addr - REG_BG2X_L) / 0x10;
let t = io.gpu.bg_aff[index as usize].x;
io.gpu.bg_aff[index as usize].x =
(t & 0xffff) | ((sign_extend_i32((value & 0xfff) as i32, 12)) << 16);
if !io.gpu.state.is_vblank() {
io.gpu.bg_aff[index as usize].internal_x = io.gpu.bg_aff[index as usize].x;
}
}
REG_BG2Y_H | REG_BG3Y_H => {
let index = (io_addr - REG_BG2X_L) / 0x10;
let t = io.gpu.bg_aff[index as usize].y;
io.gpu.bg_aff[index as usize].y =
(t & 0xffff) | ((sign_extend_i32((value & 0xfff) as i32, 12)) << 16);
if !io.gpu.state.is_vblank() {
io.gpu.bg_aff[index as usize].internal_y = io.gpu.bg_aff[index as usize].y;
}
}
REG_BG2PA => io.gpu.bg_aff[0].pa = value as i16, REG_BG2PA => io.gpu.bg_aff[0].pa = value as i16,
REG_BG2PB => io.gpu.bg_aff[0].pb = value as i16, REG_BG2PB => io.gpu.bg_aff[0].pb = value as i16,
REG_BG2PC => io.gpu.bg_aff[0].pc = value as i16, REG_BG2PC => io.gpu.bg_aff[0].pc = value as i16,