gpu: refactor: Big refactor preparations

1) Decouple SysBus from Gpu
2) Split Gpu rendering function into separate modules
3) Cleanup


Former-commit-id: 0435ad1c9c1de72ed50769fabfea7c5f33b670e0
This commit is contained in:
Michel Heily 2019-12-29 23:03:57 +02:00
parent 885bce2aa4
commit b00fbfb38c
23 changed files with 389 additions and 379 deletions

View file

@ -6,7 +6,7 @@ edition = "2018"
default-run= "rba-sdl2" default-run= "rba-sdl2"
[dependencies] [dependencies]
byteorder = "*" byteorder = "1"
num = "0.2.0" num = "0.2.0"
num-traits = "0.2" num-traits = "0.2"
enum-primitive-derive = "^0.1" enum-primitive-derive = "^0.1"

View file

@ -1,11 +1,11 @@
use crate::bit::BitIndex; use crate::bit::BitIndex;
use super::super::alu::*; use super::super::alu::*;
use crate::core::arm7tdmi::bus::Bus;
use crate::core::arm7tdmi::cpu::{Core, CpuExecResult}; use crate::core::arm7tdmi::cpu::{Core, CpuExecResult};
use crate::core::arm7tdmi::psr::RegPSR; use crate::core::arm7tdmi::psr::RegPSR;
use crate::core::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, REG_LR, REG_PC}; use crate::core::arm7tdmi::{Addr, CpuError, CpuMode, CpuResult, CpuState, REG_LR, REG_PC};
use crate::core::sysbus::SysBus; use crate::core::sysbus::SysBus;
use crate::core::Bus;
use super::*; use super::*;

View file

@ -4,11 +4,12 @@ use ansi_term::{Colour, Style};
pub use super::exception::Exception; pub use super::exception::Exception;
use super::{ use super::{
arm::*, bus::Bus, psr::RegPSR, reg_string, thumb::ThumbInstruction, Addr, CpuMode, CpuResult, arm::*, psr::RegPSR, reg_string, thumb::ThumbInstruction, Addr, CpuMode, CpuResult, CpuState,
CpuState, DecodedInstruction, InstructionDecoder, DecodedInstruction, InstructionDecoder,
}; };
use super::super::sysbus::{ use crate::core::bus::Bus;
use crate::core::sysbus::{
MemoryAccess, MemoryAccessType, MemoryAccessType::*, MemoryAccessWidth::*, SysBus, MemoryAccess, MemoryAccessType, MemoryAccessType::*, MemoryAccessWidth::*, SysBus,
}; };

View file

@ -12,8 +12,6 @@ pub mod cpu;
pub use cpu::*; pub use cpu::*;
pub mod alu; pub mod alu;
pub use alu::*; pub use alu::*;
pub mod bus;
pub use bus::*;
pub mod exception; pub mod exception;
pub mod psr; pub mod psr;
@ -21,7 +19,7 @@ pub const REG_PC: usize = 15;
pub const REG_LR: usize = 14; pub const REG_LR: usize = 14;
pub const REG_SP: usize = 13; pub const REG_SP: usize = 13;
pub type Addr = u32; pub(self) use crate::core::{Addr, Bus};
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
pub enum DecodedInstruction { pub enum DecodedInstruction {

View file

@ -1,7 +1,7 @@
use crate::core::arm7tdmi::bus::Bus;
use crate::core::arm7tdmi::cpu::{Core, CpuExecResult}; use crate::core::arm7tdmi::cpu::{Core, CpuExecResult};
use crate::core::arm7tdmi::*; use crate::core::arm7tdmi::*;
use crate::core::sysbus::SysBus; use crate::core::sysbus::SysBus;
use crate::core::Bus;
use crate::bit::BitIndex; use crate::bit::BitIndex;

View file

@ -343,9 +343,10 @@ impl ThumbInstruction {
#[cfg(test)] #[cfg(test)]
/// All instructions constants were generated using an ARM assembler. /// All instructions constants were generated using an ARM assembler.
mod tests { mod tests {
use super::super::Core;
use super::*; use super::*;
use crate::core::arm7tdmi::{Bus, Core};
use crate::core::sysbus::BoxedMemory; use crate::core::sysbus::BoxedMemory;
use crate::core::Bus;
#[test] #[test]
fn mov_low_reg() { fn mov_low_reg() {

View file

@ -1,4 +1,4 @@
use super::Addr; pub type Addr = u32;
pub trait Bus { pub trait Bus {
fn read_32(&self, addr: Addr) -> u32; fn read_32(&self, addr: Addr) -> u32;

View file

@ -8,8 +8,7 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use zip::ZipArchive; use zip::ZipArchive;
use super::super::util::read_bin_file; use super::super::util::read_bin_file;
use super::arm7tdmi::{bus::Bus, Addr}; use super::{Addr, Bus, GBAResult};
use super::{GBAError, GBAResult};
/// From GBATEK /// From GBATEK
/// ///

View file

@ -2,10 +2,9 @@ extern crate bit_set;
use bit_set::BitSet; use bit_set::BitSet;
use super::arm7tdmi::{Addr, Bus};
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B}; use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
use super::sysbus::SysBus; use super::sysbus::SysBus;
use super::{Interrupt, IrqBitmask}; use super::{Addr, Bus, Interrupt, IrqBitmask};
use num::FromPrimitive; use num::FromPrimitive;

View file

@ -29,8 +29,8 @@ impl GameBoyAdvance {
audio_device: Rc<RefCell<dyn AudioInterface>>, audio_device: Rc<RefCell<dyn AudioInterface>>,
input_device: Rc<RefCell<dyn InputInterface>>, input_device: Rc<RefCell<dyn InputInterface>>,
) -> GameBoyAdvance { ) -> GameBoyAdvance {
let gpu = Gpu::new(video_device.clone()); let gpu = Box::new(Gpu::new(video_device.clone()));
let sound_controller = SoundController::new(audio_device.clone()); let sound_controller = Box::new(SoundController::new(audio_device.clone()));
let io = IoDevices::new(gpu, sound_controller); let io = IoDevices::new(gpu, sound_controller);
GameBoyAdvance { GameBoyAdvance {
cpu: cpu, cpu: cpu,
@ -48,6 +48,7 @@ impl GameBoyAdvance {
pub fn frame(&mut self) { pub fn frame(&mut self) {
self.key_poll(); self.key_poll();
self.sysbus.io.gpu.clear();
while self.sysbus.io.gpu.vcount != DISPLAY_HEIGHT { while self.sysbus.io.gpu.vcount != DISPLAY_HEIGHT {
self.step(); self.step();
} }

View file

@ -1,38 +1,48 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc;
use std::fmt; use std::fmt;
use std::rc::Rc;
use super::arm7tdmi::{Addr, Bus}; use super::super::VideoInterface;
use super::*; use super::interrupt::IrqBitmask;
use crate::VideoInterface; use super::sysbus::{BoxedMemory, SysBus};
use super::Bus;
use crate::bitfield::Bit; use crate::bitfield::Bit;
use crate::num::FromPrimitive; use crate::num::FromPrimitive;
mod render;
mod mosaic; mod mosaic;
mod obj;
use obj::ObjInfo;
mod sfx;
mod rgb15; mod rgb15;
mod sfx;
pub use rgb15::Rgb15; pub use rgb15::Rgb15;
pub mod regs; pub mod regs;
pub use regs::*; pub use regs::*;
pub const VRAM_ADDR: Addr = 0x0600_0000; #[allow(unused)]
pub mod consts {
pub const VIDEO_RAM_SIZE: usize = 128 * 1024;
pub const PALETTE_RAM_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;
const CYCLES_PIXEL: usize = 4; pub(super) const CYCLES_PIXEL: usize = 4;
const CYCLES_HDRAW: usize = 960; pub(super) const CYCLES_HDRAW: usize = 960;
const CYCLES_HBLANK: usize = 272; pub(super) const CYCLES_HBLANK: usize = 272;
const CYCLES_SCANLINE: usize = 1232; pub(super) const CYCLES_SCANLINE: usize = 1232;
const CYCLES_VDRAW: usize = 197120; pub(super) const CYCLES_VDRAW: usize = 197120;
const CYCLES_VBLANK: usize = 83776; pub(super) const CYCLES_VBLANK: usize = 83776;
pub const TILE_SIZE: u32 = 0x20; pub const TILE_SIZE: u32 = 0x20;
}
pub use self::consts::*;
pub type FrameBuffer<T> = [T; DISPLAY_WIDTH * DISPLAY_HEIGHT];
#[derive(Debug, Primitive, Copy, Clone)] #[derive(Debug, Primitive, Copy, Clone)]
pub enum PixelFormat { pub enum PixelFormat {
@ -146,6 +156,23 @@ pub struct BgAffine {
pub y: i32, pub y: i32,
} }
#[derive(Debug, Copy, Clone)]
pub struct ObjBufferEntry {
pub(super) color: Rgb15,
pub(super) priority: u16,
pub(super) window: bool,
}
impl Default for ObjBufferEntry {
fn default() -> ObjBufferEntry {
ObjBufferEntry {
window: false,
color: Rgb15::TRANSPARENT,
priority: 4,
}
}
}
type VideoDeviceRcRefCell = Rc<RefCell<dyn VideoInterface>>; type VideoDeviceRcRefCell = Rc<RefCell<dyn VideoInterface>>;
#[derive(DebugStub)] #[derive(DebugStub)]
@ -173,11 +200,15 @@ pub struct Gpu {
pub bldalpha: BlendAlpha, pub bldalpha: BlendAlpha,
pub bldy: u16, pub bldy: u16,
pub palette_ram: BoxedMemory,
pub vram: BoxedMemory,
pub oam: BoxedMemory,
#[debug_stub = "Sprite Buffer"] #[debug_stub = "Sprite Buffer"]
pub obj_buffer: [ObjInfo; DISPLAY_WIDTH], pub obj_buffer: FrameBuffer<ObjBufferEntry>,
#[debug_stub = "Frame Buffer"] #[debug_stub = "Frame Buffer"]
pub frame_buffer: [u32; DISPLAY_WIDTH * DISPLAY_HEIGHT], pub(super) frame_buffer: FrameBuffer<u32>,
} }
impl Gpu { impl Gpu {
@ -201,210 +232,95 @@ impl Gpu {
state: HDraw, state: HDraw,
vcount: 0, vcount: 0,
cycles: 0, cycles: 0,
obj_buffer: [Default::default(); DISPLAY_WIDTH],
palette_ram: BoxedMemory::new(vec![0; PALETTE_RAM_SIZE].into_boxed_slice()),
vram: BoxedMemory::new(vec![0; VIDEO_RAM_SIZE].into_boxed_slice()),
oam: BoxedMemory::new(vec![0; OAM_SIZE].into_boxed_slice()),
obj_buffer: [Default::default(); DISPLAY_WIDTH * DISPLAY_HEIGHT],
frame_buffer: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT], frame_buffer: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT],
} }
} }
/// helper method that reads the palette index from a base address and x + y /// helper method that reads the palette index from a base address and x + y
pub fn read_pixel_index( pub fn read_pixel_index(&self, addr: u32, x: u32, y: u32, format: PixelFormat) -> usize {
&self,
sb: &SysBus,
addr: Addr,
x: u32,
y: u32,
format: PixelFormat,
) -> usize {
let ofs = addr - VRAM_ADDR; let ofs = addr - VRAM_ADDR;
match format { match format {
PixelFormat::BPP4 => { PixelFormat::BPP4 => {
let byte = sb.vram.read_8(ofs + index2d!(Addr, x / 2, y, 4)); let byte = self.vram.read_8(ofs + index2d!(u32, x / 2, y, 4));
if x & 1 != 0 { if x & 1 != 0 {
(byte >> 4) as usize (byte >> 4) as usize
} else { } else {
(byte & 0xf) as usize (byte & 0xf) as usize
} }
} }
PixelFormat::BPP8 => sb.vram.read_8(ofs + index2d!(Addr, x, y, 8)) as usize, PixelFormat::BPP8 => self.vram.read_8(ofs + index2d!(u32, x, y, 8)) as usize,
} }
} }
pub fn get_palette_color( pub fn get_palette_color(&self, index: u32, palette_index: u32, offset: u32) -> Rgb15 {
&self,
sb: &SysBus,
index: u32,
palette_index: u32,
offset: u32,
) -> Rgb15 {
if index == 0 || (palette_index != 0 && index % 16 == 0) { if index == 0 || (palette_index != 0 && index % 16 == 0) {
return Rgb15::TRANSPARENT; return Rgb15::TRANSPARENT;
} }
Rgb15( Rgb15(
sb.palette_ram self.palette_ram
.read_16(offset + 2 * index + 0x20 * palette_index), .read_16(offset + 2 * index + 0x20 * palette_index),
) )
} }
fn render_pixel(&mut self, x: i32, y: i32, p: Rgb15) { pub(super) fn obj_buffer_get(&self, x: usize, y: usize) -> &ObjBufferEntry {
&self.obj_buffer[index2d!(x, y, DISPLAY_WIDTH)]
}
pub(super) fn obj_buffer_get_mut(&mut self, x: usize, y: usize) -> &mut ObjBufferEntry {
&mut self.obj_buffer[index2d!(x, y, DISPLAY_WIDTH)]
}
pub(super) fn render_pixel(&mut self, x: i32, y: i32, p: Rgb15) {
self.frame_buffer[index2d!(usize, x, y, DISPLAY_WIDTH)] = p.to_rgb24(); self.frame_buffer[index2d!(usize, x, y, DISPLAY_WIDTH)] = p.to_rgb24();
} }
fn scanline_reg_bg(&mut self, bg: usize, sb: &mut SysBus) { pub fn render_scanline(&mut self) {
let (h_ofs, v_ofs) = (self.bg[bg].bghofs as u32, self.bg[bg].bgvofs as u32);
let tileset_base = self.bg[bg].bgcnt.char_block();
let tilemap_base = self.bg[bg].bgcnt.screen_block();
let (tile_size, pixel_format) = self.bg[bg].bgcnt.tile_format();
let (bg_width, bg_height) = self.bg[bg].bgcnt.size_regular();
let screen_y = self.vcount as u32;
let mut screen_x = 0;
// calculate the bg coords at the top-left corner, including wraparound
let bg_x = (screen_x + h_ofs) % bg_width;
let bg_y = (screen_y + v_ofs) % bg_height;
// calculate the initial screen entry index
// | (256,256) | (512,256) | (256,512) | (512,512) |
// |-----------|-----------|-------------|-----------|
// | | | [1] | [2][3] |
// | [0] | [0][1] | [0] | [0][1] |
// |___________|___________|_____________|___________|
//
let mut sbb = match (bg_width, bg_height) {
(256, 256) => 0,
(512, 256) => bg_x / 256,
(256, 512) => bg_y / 256,
(512, 512) => index2d!(u32, bg_x / 256, bg_y / 256, 2),
_ => unreachable!(),
} as u32;
let mut se_row = (bg_x / 8) % 32;
let se_column = (bg_y / 8) % 32;
// this will be non-zero if the h-scroll lands in a middle of a tile
let mut start_tile_x = bg_x % 8;
let tile_py = (bg_y % 8) as u32;
loop {
let mut map_addr =
tilemap_base + SCREEN_BLOCK_SIZE * sbb + 2 * index2d!(u32, se_row, se_column, 32);
for _ in se_row..32 {
let entry = TileMapEntry(sb.vram.read_16(map_addr - VRAM_ADDR));
let tile_addr = tileset_base + entry.tile_index() * tile_size;
for tile_px in start_tile_x..8 {
let index = self.read_pixel_index(
sb,
tile_addr,
if entry.x_flip() { 7 - tile_px } else { tile_px },
if entry.y_flip() { 7 - tile_py } else { tile_py },
pixel_format,
);
let palette_bank = match pixel_format {
PixelFormat::BPP4 => entry.palette_bank() as u32,
PixelFormat::BPP8 => 0u32,
};
let color = self.get_palette_color(sb, index as u32, palette_bank, 0);
self.bg[bg].line[screen_x as usize] = color;
screen_x += 1;
if (DISPLAY_WIDTH as u32) == screen_x {
return;
}
}
start_tile_x = 0;
map_addr += 2;
}
se_row = 0;
if bg_width == 512 {
sbb = sbb ^ 1;
}
}
}
fn scanline_aff_bg(&mut self, bg: usize, sb: &mut SysBus) {
// TODO
self.bg[bg].line = Scanline::default();
}
fn scanline_mode3(&mut self, bg: usize, sb: &mut SysBus) {
let y = self.vcount;
for x in 0..DISPLAY_WIDTH {
let pixel_index = index2d!(u32, x, y, DISPLAY_WIDTH);
let pixel_ofs = 2 * pixel_index;
let color = Rgb15(sb.vram.read_16(pixel_ofs));
self.bg[bg].line[x] = color;
}
}
fn scanline_mode4(&mut self, bg: usize, sb: &mut SysBus) {
let page_ofs: u32 = match self.dispcnt.display_frame() {
0 => 0x0600_0000 - VRAM_ADDR,
1 => 0x0600_a000 - VRAM_ADDR,
_ => unreachable!(),
};
let y = self.vcount;
for x in 0..DISPLAY_WIDTH {
let bitmap_index = index2d!(x, y, DISPLAY_WIDTH);
let bitmap_ofs = page_ofs + (bitmap_index as u32);
let index = sb.vram.read_8(bitmap_ofs as Addr) as u32;
let color = self.get_palette_color(sb, index, 0, 0);
self.bg[bg].line[x] = color;
}
}
pub fn render_scanline(&mut self, sb: &mut SysBus) {
// TODO - also render objs
match self.dispcnt.mode() { match self.dispcnt.mode() {
0 => { 0 => {
for bg in 0..4 { for bg in 0..4 {
if self.dispcnt.disp_bg(bg) { if self.dispcnt.disp_bg(bg) {
self.scanline_reg_bg(bg, sb); self.render_reg_bg(bg);
} }
} }
} }
1 => { 1 => {
if self.dispcnt.disp_bg(2) { if self.dispcnt.disp_bg(2) {
self.scanline_aff_bg(2, sb); self.render_aff_bg(2);
} }
if self.dispcnt.disp_bg(1) { if self.dispcnt.disp_bg(1) {
self.scanline_reg_bg(1, sb); self.render_reg_bg(1);
} }
if self.dispcnt.disp_bg(0) { if self.dispcnt.disp_bg(0) {
self.scanline_reg_bg(0, sb); self.render_reg_bg(0);
} }
} }
2 => { 2 => {
if self.dispcnt.disp_bg(3) { if self.dispcnt.disp_bg(3) {
self.scanline_aff_bg(3, sb); self.render_aff_bg(3);
} }
if self.dispcnt.disp_bg(2) { if self.dispcnt.disp_bg(2) {
self.scanline_aff_bg(2, sb); self.render_aff_bg(2);
} }
} }
3 => { 3 => {
self.scanline_mode3(2, sb); self.render_mode3(2);
} }
4 => { 4 => {
self.scanline_mode4(2, sb); self.render_mode4(2);
} }
_ => panic!("{:?} not supported", self.dispcnt.mode()), _ => panic!("{:?} not supported", self.dispcnt.mode()),
} }
if self.dispcnt.disp_obj() { if self.dispcnt.disp_obj() {
self.render_objs(sb); self.render_objs();
} }
self.mosaic_sfx(); self.mosaic_sfx();
let post_sfx_line = self.composite_sfx(sb); self.composite_sfx_to_framebuffer();
for x in 0..DISPLAY_WIDTH {
self.frame_buffer[x + self.vcount * DISPLAY_WIDTH] = post_sfx_line[x].to_rgb24();
}
}
pub fn get_framebuffer(&self) -> &[u32] {
&self.frame_buffer
} }
fn update_vcount(&mut self, value: usize, irqs: &mut IrqBitmask) { fn update_vcount(&mut self, value: usize, irqs: &mut IrqBitmask) {
@ -418,6 +334,13 @@ impl Gpu {
} }
} }
// Clears the gpu internal buffer
pub fn clear(&mut self) {
for x in self.obj_buffer.iter_mut() {
*x = Default::default();
}
}
// Returns the new gpu state // Returns the new gpu state
pub fn step(&mut self, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask) { pub fn step(&mut self, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask) {
self.cycles += cycles; self.cycles += cycles;
@ -443,7 +366,7 @@ impl Gpu {
self.update_vcount(self.vcount + 1, irqs); self.update_vcount(self.vcount + 1, irqs);
if self.vcount < DISPLAY_HEIGHT { if self.vcount < DISPLAY_HEIGHT {
self.render_scanline(sb); self.render_scanline();
self.state = HDraw; self.state = HDraw;
} else { } else {
self.state = VBlank; self.state = VBlank;
@ -465,7 +388,7 @@ impl Gpu {
} else { } else {
self.update_vcount(0, irqs); self.update_vcount(0, irqs);
self.dispstat.set_vblank_flag(false); self.dispstat.set_vblank_flag(false);
self.render_scanline(sb); self.render_scanline();
self.state = HDraw; self.state = HDraw;
} }
} }
@ -473,12 +396,3 @@ impl Gpu {
} }
} }
} }
bitfield! {
struct TileMapEntry(u16);
u16;
u32, tile_index, _: 9, 0;
x_flip, _ : 10;
y_flip, _ : 11;
palette_bank, _ : 15, 12;
}

3
src/core/gpu/render.rs Normal file
View file

@ -0,0 +1,3 @@
pub(super) mod bitmap;
pub(super) mod obj;
pub(super) mod text;

View file

@ -0,0 +1,38 @@
//! Rendering for modes 4-5
use super::super::consts::*;
use super::super::Gpu;
use super::super::Rgb15;
use crate::core::Bus;
impl Gpu {
pub(in super::super) fn render_mode3(&mut self, bg: usize) {
let y = self.vcount;
for x in 0..DISPLAY_WIDTH {
let pixel_index = index2d!(u32, x, y, DISPLAY_WIDTH);
let pixel_ofs = 2 * pixel_index;
let color = Rgb15(self.vram.read_16(pixel_ofs));
self.bg[bg].line[x] = color;
}
}
pub(in super::super) fn render_mode4(&mut self, bg: usize) {
let page_ofs: u32 = match self.dispcnt.display_frame() {
0 => 0x0600_0000 - VRAM_ADDR,
1 => 0x0600_a000 - VRAM_ADDR,
_ => unreachable!(),
};
let y = self.vcount;
for x in 0..DISPLAY_WIDTH {
let bitmap_index = index2d!(x, y, DISPLAY_WIDTH);
let bitmap_ofs = page_ofs + (bitmap_index as u32);
let index = self.vram.read_8(bitmap_ofs) as u32;
let color = self.get_palette_color(index, 0, 0);
self.bg[bg].line[x] = color;
}
}
}

View file

@ -1,6 +1,5 @@
use super::super::SysBus; use super::super::regs::*;
use super::regs::*; use super::super::*;
use super::*;
const OVRAM: u32 = 0x0601_0000; const OVRAM: u32 = 0x0601_0000;
const PALRAM_OFS_FG: u32 = 0x200; const PALRAM_OFS_FG: u32 = 0x200;
@ -10,21 +9,6 @@ struct ObjAttrs(Attribute0, Attribute1, Attribute2);
const AFFINE_FILL: u32 = 2 * 3; const AFFINE_FILL: u32 = 2 * 3;
impl AffineMatrix {
fn from_index(sb: &SysBus, index: u32) -> AffineMatrix {
let mut offset = AFFINE_FILL + index * 16 * 2;
let pa = sb.oam.read_16(offset) as i16 as i32;
offset += 2 + AFFINE_FILL;
let pb = sb.oam.read_16(offset) as i16 as i32;
offset += 2 + AFFINE_FILL;
let pc = sb.oam.read_16(offset) as i16 as i32;
offset += 2 + AFFINE_FILL;
let pd = sb.oam.read_16(offset) as i16 as i32;
AffineMatrix { pa, pb, pc, pd }
}
}
impl ObjAttrs { impl ObjAttrs {
fn size(&self) -> (i32, i32) { fn size(&self) -> (i32, i32) {
match (self.1.size(), self.0.shape()) { match (self.1.size(), self.0.shape()) {
@ -71,22 +55,11 @@ impl ObjAttrs {
let attr1 = (self.1).0; let attr1 = (self.1).0;
((attr1 >> 9) & 0x1f) as u32 ((attr1 >> 9) & 0x1f) as u32
} }
fn affine_matrix(&self, sb: &SysBus) -> AffineMatrix {
AffineMatrix::from_index(sb, self.affine_index())
}
fn is_hidden(&self) -> bool { fn is_hidden(&self) -> bool {
self.0.objtype() == ObjType::Hidden self.0.objtype() == ObjType::Hidden
} }
} }
fn read_obj_attrs(sb: &SysBus, obj: usize) -> ObjAttrs {
let addr = ATTRS_SIZE * (obj as u32);
let attr0 = Attribute0(sb.oam.read_16(addr + 0));
let attr1 = Attribute1(sb.oam.read_16(addr + 2));
let attr2 = Attribute2(sb.oam.read_16(addr + 4));
ObjAttrs(attr0, attr1, attr2)
}
impl Gpu { impl Gpu {
fn obj_tile_base(&self) -> u32 { fn obj_tile_base(&self) -> u32 {
match self.dispcnt.mode() { match self.dispcnt.mode() {
@ -95,7 +68,28 @@ impl Gpu {
} }
} }
fn render_affine_obj(&mut self, sb: &SysBus, obj: ObjAttrs, _obj_num: usize) { fn get_affine_matrix(&self, affine_index: u32) -> AffineMatrix {
let mut offset = AFFINE_FILL + affine_index * 16 * 2;
let pa = self.oam.read_16(offset) as i16 as i32;
offset += 2 + AFFINE_FILL;
let pb = self.oam.read_16(offset) as i16 as i32;
offset += 2 + AFFINE_FILL;
let pc = self.oam.read_16(offset) as i16 as i32;
offset += 2 + AFFINE_FILL;
let pd = self.oam.read_16(offset) as i16 as i32;
AffineMatrix { pa, pb, pc, pd }
}
fn read_obj_attrs(&self, obj: usize) -> ObjAttrs {
let addr = ATTRS_SIZE * (obj as u32);
let attr0 = Attribute0(self.oam.read_16(addr + 0));
let attr1 = Attribute1(self.oam.read_16(addr + 2));
let attr2 = Attribute2(self.oam.read_16(addr + 4));
ObjAttrs(attr0, attr1, attr2)
}
fn render_affine_obj(&mut self, obj: ObjAttrs, _obj_num: usize) {
let screen_y = self.vcount as i32; let screen_y = self.vcount as i32;
let (ref_x, ref_y) = obj.coords(); let (ref_x, ref_y) = obj.coords();
@ -131,7 +125,7 @@ impl Gpu {
} }
}; };
let affine_matrix = obj.affine_matrix(sb); let affine_matrix = self.get_affine_matrix(obj.affine_index());
let half_width = bbox_w / 2; let half_width = bbox_w / 2;
let half_height = bbox_h / 2; let half_height = bbox_h / 2;
@ -145,7 +139,11 @@ impl Gpu {
if screen_x >= screen_width { if screen_x >= screen_width {
break; break;
} }
if self.obj_buffer[screen_x as usize].priority <= obj.2.priority() { if self
.obj_buffer_get(screen_x as usize, screen_y as usize)
.priority
<= obj.2.priority()
{
continue; continue;
} }
@ -159,25 +157,16 @@ impl Gpu {
let tile_addr = tile_base let tile_addr = tile_base
+ index2d!(u32, texture_x / 8, texture_y / 8, tile_array_width) + index2d!(u32, texture_x / 8, texture_y / 8, tile_array_width)
* (tile_size as u32); * (tile_size as u32);
let pixel_index = self.read_pixel_index( let pixel_index =
sb, self.read_pixel_index(tile_addr, tile_x as u32, tile_y as u32, pixel_format);
tile_addr,
tile_x as u32,
tile_y as u32,
pixel_format,
);
let pixel_color = let pixel_color =
self.get_palette_color(sb, pixel_index as u32, palette_bank, PALRAM_OFS_FG); self.get_palette_color(pixel_index as u32, palette_bank, PALRAM_OFS_FG);
if pixel_color != Rgb15::TRANSPARENT { self.write_obj_pixel(screen_x as usize, screen_y as usize, pixel_color, &obj);
let mut current_obj = &mut self.obj_buffer[screen_x as usize];
current_obj.color = pixel_color;
current_obj.priority = obj.2.priority();
}
} }
} }
} }
fn render_normal_obj(&mut self, sb: &SysBus, obj: ObjAttrs, _obj_num: usize) { fn render_normal_obj(&mut self, obj: ObjAttrs, _obj_num: usize) {
let screen_y = self.vcount as i32; let screen_y = self.vcount as i32;
let (ref_x, ref_y) = obj.coords(); let (ref_x, ref_y) = obj.coords();
@ -217,7 +206,11 @@ impl Gpu {
if screen_x >= screen_width { if screen_x >= screen_width {
break; break;
} }
if self.obj_buffer[screen_x as usize].priority <= obj.2.priority() { if self
.obj_buffer_get(screen_x as usize, screen_y as usize)
.priority
<= obj.2.priority()
{
continue; continue;
} }
let mut sprite_y = screen_y - ref_y; let mut sprite_y = screen_y - ref_y;
@ -237,49 +230,42 @@ impl Gpu {
let tile_addr = tile_base let tile_addr = tile_base
+ index2d!(u32, sprite_x / 8, sprite_y / 8, tile_array_width) * (tile_size as u32); + index2d!(u32, sprite_x / 8, sprite_y / 8, tile_array_width) * (tile_size as u32);
let pixel_index = let pixel_index =
self.read_pixel_index(sb, tile_addr, tile_x as u32, tile_y as u32, pixel_format); self.read_pixel_index(tile_addr, tile_x as u32, tile_y as u32, pixel_format);
let pixel_color = let pixel_color =
self.get_palette_color(sb, pixel_index as u32, palette_bank, PALRAM_OFS_FG); self.get_palette_color(pixel_index as u32, palette_bank, PALRAM_OFS_FG);
self.write_obj_pixel(screen_x as usize, screen_y as usize, pixel_color, &obj);
}
}
fn write_obj_pixel(&mut self, x: usize, y: usize, pixel_color: Rgb15, attrs: &ObjAttrs) {
let mut current_obj = self.obj_buffer_get_mut(x, y);
match attrs.0.objmode() {
ObjMode::Normal | ObjMode::Sfx => {
if pixel_color != Rgb15::TRANSPARENT { if pixel_color != Rgb15::TRANSPARENT {
let mut current_obj = &mut self.obj_buffer[screen_x as usize];
current_obj.color = pixel_color; current_obj.color = pixel_color;
current_obj.priority = obj.2.priority(); current_obj.priority = attrs.2.priority();
}
}
ObjMode::Window => {
current_obj.window = true;
}
ObjMode::Forbidden => {
panic!("Forbidden sprite mode!");
} }
} }
} }
pub fn render_objs(&mut self, sb: &SysBus) { pub(in super::super) fn render_objs(&mut self) {
// reset the scanline
self.obj_buffer = [Default::default(); DISPLAY_WIDTH];
for obj_num in 0..128 { for obj_num in 0..128 {
let obj = read_obj_attrs(sb, obj_num); let obj = self.read_obj_attrs(obj_num);
match obj.0.objtype() { match obj.0.objtype() {
ObjType::Hidden => continue, ObjType::Hidden => continue,
ObjType::Normal => self.render_normal_obj(sb, obj, obj_num), ObjType::Normal => self.render_normal_obj(obj, obj_num),
ObjType::Affine | ObjType::AffineDoubleSize => { ObjType::Affine | ObjType::AffineDoubleSize => self.render_affine_obj(obj, obj_num),
self.render_affine_obj(sb, obj, obj_num)
} }
} }
} }
} }
}
#[derive(Debug, Copy, Clone)]
pub struct ObjInfo {
pub(super) color: Rgb15,
pub(super) priority: u16,
pub(super) mode: ObjMode,
}
impl Default for ObjInfo {
fn default() -> ObjInfo {
ObjInfo {
mode: ObjMode::Normal,
color: Rgb15::TRANSPARENT,
priority: 4,
}
}
}
#[derive(Debug, Primitive, Copy, Clone, PartialEq)] #[derive(Debug, Primitive, Copy, Clone, PartialEq)]
pub enum ObjMode { pub enum ObjMode {

View file

@ -0,0 +1,94 @@
//! Rendering for modes 0-3
use super::super::consts::*;
use super::super::{Gpu, PixelFormat, Scanline, SCREEN_BLOCK_SIZE};
use crate::core::Bus;
impl Gpu {
pub(in super::super) fn render_reg_bg(&mut self, bg: usize) {
let (h_ofs, v_ofs) = (self.bg[bg].bghofs as u32, self.bg[bg].bgvofs as u32);
let tileset_base = self.bg[bg].bgcnt.char_block();
let tilemap_base = self.bg[bg].bgcnt.screen_block();
let (tile_size, pixel_format) = self.bg[bg].bgcnt.tile_format();
let (bg_width, bg_height) = self.bg[bg].bgcnt.size_regular();
let screen_y = self.vcount as u32;
let mut screen_x = 0;
// calculate the bg coords at the top-left corner, including wraparound
let bg_x = (screen_x + h_ofs) % bg_width;
let bg_y = (screen_y + v_ofs) % bg_height;
// calculate the initial screen entry index
// | (256,256) | (512,256) | (256,512) | (512,512) |
// |-----------|-----------|-------------|-----------|
// | | | [1] | [2][3] |
// | [0] | [0][1] | [0] | [0][1] |
// |___________|___________|_____________|___________|
//
let mut sbb = match (bg_width, bg_height) {
(256, 256) => 0,
(512, 256) => bg_x / 256,
(256, 512) => bg_y / 256,
(512, 512) => index2d!(u32, bg_x / 256, bg_y / 256, 2),
_ => unreachable!(),
} as u32;
let mut se_row = (bg_x / 8) % 32;
let se_column = (bg_y / 8) % 32;
// this will be non-zero if the h-scroll lands in a middle of a tile
let mut start_tile_x = bg_x % 8;
let tile_py = (bg_y % 8) as u32;
loop {
let mut map_addr =
tilemap_base + SCREEN_BLOCK_SIZE * sbb + 2 * index2d!(u32, se_row, se_column, 32);
for _ in se_row..32 {
let entry = TileMapEntry(self.vram.read_16(map_addr - VRAM_ADDR));
let tile_addr = tileset_base + entry.tile_index() * tile_size;
for tile_px in start_tile_x..8 {
let index = self.read_pixel_index(
tile_addr,
if entry.x_flip() { 7 - tile_px } else { tile_px },
if entry.y_flip() { 7 - tile_py } else { tile_py },
pixel_format,
);
let palette_bank = match pixel_format {
PixelFormat::BPP4 => entry.palette_bank() as u32,
PixelFormat::BPP8 => 0u32,
};
let color = self.get_palette_color(index as u32, palette_bank, 0);
self.bg[bg].line[screen_x as usize] = color;
screen_x += 1;
if (DISPLAY_WIDTH as u32) == screen_x {
return;
}
}
start_tile_x = 0;
map_addr += 2;
}
se_row = 0;
if bg_width == 512 {
sbb = sbb ^ 1;
}
}
}
pub(in super::super) fn render_aff_bg(&mut self, bg: usize) {
// TODO
self.bg[bg].line = Scanline::default();
}
}
bitfield! {
struct TileMapEntry(u16);
u16;
u32, tile_index, _: 9, 0;
x_flip, _ : 10;
y_flip, _ : 11;
palette_bank, _ : 15, 12;
}

View file

@ -1,5 +1,4 @@
use std::cmp; use std::cmp;
use std::ops::Sub;
use super::regs::*; use super::regs::*;
use super::*; use super::*;
@ -42,20 +41,20 @@ struct Layer {
impl Gpu { impl Gpu {
fn get_top_layer( fn get_top_layer(
&self, &self,
sb: &SysBus,
screen_x: usize, screen_x: usize,
bflags: BlendFlags, bflags: BlendFlags,
wflags: WindowFlags, wflags: WindowFlags,
) -> Option<Layer> { ) -> Option<Layer> {
// priorities are 0-4 when 0 is the highest // priorities are 0-4 when 0 is the highest
'outer: for priority in 0..4 { 'outer: for priority in 0..4 {
let obj = self.obj_buffer_get(screen_x, self.vcount);
if bflags.contains(BlendFlags::OBJ) if bflags.contains(BlendFlags::OBJ)
&& wflags.contains(WindowFlags::OBJ) && wflags.contains(WindowFlags::OBJ)
&& !self.obj_buffer[screen_x].color.is_transparent() && !obj.color.is_transparent()
&& self.obj_buffer[screen_x].priority == priority && obj.priority == priority
{ {
return Some(Layer { return Some(Layer {
color: self.obj_buffer[screen_x].color, color: obj.color,
blend_flag: BlendFlags::OBJ, blend_flag: BlendFlags::OBJ,
}); });
} }
@ -75,7 +74,7 @@ impl Gpu {
} }
} }
} }
let backdrop = sb.palette_ram.read_16(0); let backdrop = self.palette_ram.read_16(0);
if bflags.contains(BlendFlags::BACKDROP) { if bflags.contains(BlendFlags::BACKDROP) {
return Some(Layer { return Some(Layer {
color: Rgb15(backdrop), color: Rgb15(backdrop),
@ -110,17 +109,11 @@ impl Gpu {
} }
} }
fn sfx_blend_alpha( fn sfx_blend_alpha(&self, x: usize, _y: usize, wflags: WindowFlags) -> Option<Rgb15> {
&self,
sb: &SysBus,
x: usize,
_y: usize,
wflags: WindowFlags,
) -> Option<Rgb15> {
let top_layers = self.bldcnt.top(); let top_layers = self.bldcnt.top();
let bottom_layers = self.bldcnt.bottom(); let bottom_layers = self.bldcnt.bottom();
if let Some(top_layer) = self.get_top_layer(sb, x, top_layers, wflags) { if let Some(top_layer) = self.get_top_layer(x, top_layers, wflags) {
if let Some(bot_layer) = self.get_top_layer(sb, x, bottom_layers, wflags) { if let Some(bot_layer) = self.get_top_layer(x, bottom_layers, wflags) {
let eva = self.bldalpha.eva(); let eva = self.bldalpha.eva();
let evb = self.bldalpha.evb(); let evb = self.bldalpha.evb();
return Some(top_layer.color.blend_with(bot_layer.color, eva, evb)); return Some(top_layer.color.blend_with(bot_layer.color, eva, evb));
@ -133,7 +126,6 @@ impl Gpu {
fn sfx_blend_bw( fn sfx_blend_bw(
&self, &self,
sb: &SysBus,
fadeto: Rgb15, fadeto: Rgb15,
x: usize, x: usize,
_y: usize, _y: usize,
@ -142,21 +134,19 @@ impl Gpu {
let top_layers = self.bldcnt.top(); let top_layers = self.bldcnt.top();
let evy = self.bldy; let evy = self.bldy;
if let Some(layer) = self.get_top_layer(sb, x, top_layers, wflags) { if let Some(layer) = self.get_top_layer(x, top_layers, wflags) {
return Some(layer.color.blend_with(fadeto, 16 - evy, evy)); return Some(layer.color.blend_with(fadeto, 16 - evy, evy));
} }
None None
} }
pub fn composite_sfx(&self, sb: &SysBus) -> Scanline<Rgb15> { pub fn composite_sfx_to_framebuffer(&mut self) {
let mut line: Scanline<Rgb15> = Scanline::default();
let y = self.vcount; let y = self.vcount;
for x in 0..DISPLAY_WIDTH { for x in 0..DISPLAY_WIDTH {
let window = self.get_active_window_type(x, y); let window = self.get_active_window_type(x, y);
let wflags = self.get_window_flags(window); let wflags = self.get_window_flags(window);
let toplayer = self let toplayer = self.get_top_layer(x, BlendFlags::all(), wflags).unwrap();
.get_top_layer(sb, x, BlendFlags::all(), wflags)
.unwrap();
let bldmode = if wflags.sfx_enabled() { let bldmode = if wflags.sfx_enabled() {
self.bldcnt.mode() self.bldcnt.mode()
@ -164,41 +154,37 @@ impl Gpu {
BldMode::BldNone BldMode::BldNone
}; };
match bldmode { let pixel = match bldmode {
BldMode::BldAlpha => { BldMode::BldAlpha => {
if self.bldcnt.top().contains(toplayer.blend_flag) if self.bldcnt.top().contains(toplayer.blend_flag)
|| self.bldcnt.bottom().contains(toplayer.blend_flag) || self.bldcnt.bottom().contains(toplayer.blend_flag)
{ {
line[x] = self self.sfx_blend_alpha(x, y, wflags).unwrap_or(toplayer.color)
.sfx_blend_alpha(sb, x, y, wflags)
.unwrap_or(toplayer.color);
} else { } else {
line[x] = toplayer.color; toplayer.color
} }
} }
BldMode::BldWhite => { BldMode::BldWhite => {
let result = if self.bldcnt.top().contains(toplayer.blend_flag) { let result = if self.bldcnt.top().contains(toplayer.blend_flag) {
self.sfx_blend_bw(sb, Rgb15::WHITE, x, y, wflags) self.sfx_blend_bw(Rgb15::WHITE, x, y, wflags)
.unwrap_or(toplayer.color) .unwrap_or(toplayer.color)
} else { } else {
toplayer.color toplayer.color
}; };
line[x] = result; result
} }
BldMode::BldBlack => { BldMode::BldBlack => {
let result = if self.bldcnt.top().contains(toplayer.blend_flag) { let result = if self.bldcnt.top().contains(toplayer.blend_flag) {
self.sfx_blend_bw(sb, Rgb15::BLACK, x, y, wflags) self.sfx_blend_bw(Rgb15::BLACK, x, y, wflags)
.unwrap_or(toplayer.color) .unwrap_or(toplayer.color)
} else { } else {
toplayer.color toplayer.color
}; };
line[x] = result; result
} }
BldMode::BldNone => { BldMode::BldNone => toplayer.color,
line[x] = toplayer.color; };
self.render_pixel(x as i32, y as i32, pixel);
} }
} }
} }
line
}
}

View file

@ -1,4 +1,3 @@
use super::arm7tdmi::{Addr, Bus};
use super::dma::DmaController; use super::dma::DmaController;
use super::gpu::regs::WindowFlags; use super::gpu::regs::WindowFlags;
use super::gpu::*; use super::gpu::*;
@ -7,8 +6,9 @@ use super::keypad;
use super::sound::SoundController; use super::sound::SoundController;
use super::sysbus::BoxedMemory; use super::sysbus::BoxedMemory;
use super::timer::Timers; use super::timer::Timers;
use super::{Addr, Bus};
use consts::*; use self::consts::*;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum HaltState { pub enum HaltState {
@ -19,8 +19,8 @@ pub enum HaltState {
pub struct IoDevices { pub struct IoDevices {
pub intc: InterruptController, pub intc: InterruptController,
pub gpu: Gpu, pub gpu: Box<Gpu>,
pub sound: SoundController, pub sound: Box<SoundController>,
pub timers: Timers, pub timers: Timers,
pub dmac: DmaController, pub dmac: DmaController,
pub keyinput: u16, pub keyinput: u16,
@ -32,7 +32,7 @@ pub struct IoDevices {
} }
impl IoDevices { impl IoDevices {
pub fn new(gpu: Gpu, sound_controller: SoundController) -> IoDevices { pub fn new(gpu: Box<Gpu>, sound_controller: Box<SoundController>) -> IoDevices {
IoDevices { IoDevices {
gpu: gpu, gpu: gpu,
sound: sound_controller, sound: sound_controller,

View file

@ -10,18 +10,18 @@ pub use interrupt::Interrupt;
pub use interrupt::IrqBitmask; pub use interrupt::IrqBitmask;
pub mod gba; pub mod gba;
pub use gba::GameBoyAdvance; pub use gba::GameBoyAdvance;
pub mod bus;
pub mod dma; pub mod dma;
pub mod keypad; pub mod keypad;
pub mod timer; pub mod timer;
pub use bus::*;
pub use super::{AudioInterface, InputInterface, VideoInterface};
use crate::debugger; use crate::debugger;
use zip; use zip;
pub trait SyncedIoDevice {
fn step(&mut self, cycles: usize, sb: &mut SysBus, irqs: &mut IrqBitmask);
}
#[derive(Debug)] #[derive(Debug)]
pub enum GBAError { pub enum GBAError {
IO(::std::io::Error), IO(::std::io::Error),

View file

@ -3,17 +3,13 @@ use std::ops::Add;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use super::arm7tdmi::bus::Bus;
use super::arm7tdmi::Addr;
use super::cartridge::Cartridge; use super::cartridge::Cartridge;
use super::gpu::GpuState; use super::gpu::{GpuState, VIDEO_RAM_SIZE};
use super::iodev::IoDevices; use super::iodev::IoDevices;
use super::{Addr, Bus};
const VIDEO_RAM_SIZE: usize = 128 * 1024;
const WORK_RAM_SIZE: usize = 256 * 1024; const WORK_RAM_SIZE: usize = 256 * 1024;
const INTERNAL_RAM_SIZE: usize = 32 * 1024; const INTERNAL_RAM_SIZE: usize = 32 * 1024;
const PALETTE_RAM_SIZE: usize = 1 * 1024;
const OAM_SIZE: usize = 1 * 1024;
pub const BIOS_ADDR: u32 = 0x0000_0000; pub const BIOS_ADDR: u32 = 0x0000_0000;
pub const EWRAM_ADDR: u32 = 0x0200_0000; pub const EWRAM_ADDR: u32 = 0x0200_0000;
@ -144,9 +140,6 @@ pub struct SysBus {
bios: BoxedMemory, bios: BoxedMemory,
onboard_work_ram: BoxedMemory, onboard_work_ram: BoxedMemory,
internal_work_ram: BoxedMemory, internal_work_ram: BoxedMemory,
pub palette_ram: BoxedMemory,
pub vram: BoxedMemory,
pub oam: BoxedMemory,
gamepak: Cartridge, gamepak: Cartridge,
dummy: DummyBus, dummy: DummyBus,
@ -161,9 +154,6 @@ impl SysBus {
bios: BoxedMemory::new(bios_rom.into_boxed_slice()), bios: BoxedMemory::new(bios_rom.into_boxed_slice()),
onboard_work_ram: BoxedMemory::new(vec![0; WORK_RAM_SIZE].into_boxed_slice()), onboard_work_ram: BoxedMemory::new(vec![0; WORK_RAM_SIZE].into_boxed_slice()),
internal_work_ram: BoxedMemory::new(vec![0; INTERNAL_RAM_SIZE].into_boxed_slice()), internal_work_ram: BoxedMemory::new(vec![0; INTERNAL_RAM_SIZE].into_boxed_slice()),
palette_ram: BoxedMemory::new(vec![0; PALETTE_RAM_SIZE].into_boxed_slice()),
vram: BoxedMemory::new(vec![0; VIDEO_RAM_SIZE].into_boxed_slice()),
oam: BoxedMemory::new(vec![0; OAM_SIZE].into_boxed_slice()),
gamepak: gamepak, gamepak: gamepak,
dummy: DummyBus([0; 4]), dummy: DummyBus([0; 4]),
@ -190,15 +180,15 @@ impl SysBus {
ofs & 0x7ff ofs & 0x7ff
} }
}), }),
PALRAM_ADDR => (&self.palette_ram, ofs & 0x3ff), PALRAM_ADDR => (&self.io.gpu.palette_ram, ofs & 0x3ff),
VRAM_ADDR => (&self.vram, { VRAM_ADDR => (&self.io.gpu.vram, {
let mut ofs = ofs & ((VIDEO_RAM_SIZE as u32) - 1); let mut ofs = ofs & ((VIDEO_RAM_SIZE as u32) - 1);
if ofs > 0x18000 { if ofs > 0x18000 {
ofs -= 0x8000; ofs -= 0x8000;
} }
ofs ofs
}), }),
OAM_ADDR => (&self.oam, ofs & 0x3ff), OAM_ADDR => (&self.io.gpu.oam, ofs & 0x3ff),
GAMEPAK_WS0_ADDR | GAMEPAK_MIRROR_WS0_ADDR | GAMEPAK_WS1_ADDR | GAMEPAK_WS2_ADDR => { GAMEPAK_WS0_ADDR | GAMEPAK_MIRROR_WS0_ADDR | GAMEPAK_WS1_ADDR | GAMEPAK_WS2_ADDR => {
(&self.gamepak, addr & 0x01ff_ffff) (&self.gamepak, addr & 0x01ff_ffff)
} }
@ -220,15 +210,15 @@ impl SysBus {
ofs & 0x7ff ofs & 0x7ff
} }
}), }),
PALRAM_ADDR => (&mut self.palette_ram, ofs & 0x3ff), PALRAM_ADDR => (&mut self.io.gpu.palette_ram, ofs & 0x3ff),
VRAM_ADDR => (&mut self.vram, { VRAM_ADDR => (&mut self.io.gpu.vram, {
let mut ofs = ofs & ((VIDEO_RAM_SIZE as u32) - 1); let mut ofs = ofs & ((VIDEO_RAM_SIZE as u32) - 1);
if ofs > 0x18000 { if ofs > 0x18000 {
ofs -= 0x8000; ofs -= 0x8000;
} }
ofs ofs
}), }),
OAM_ADDR => (&mut self.oam, ofs & 0x3ff), OAM_ADDR => (&mut self.io.gpu.oam, ofs & 0x3ff),
GAMEPAK_WS0_ADDR | GAMEPAK_MIRROR_WS0_ADDR | GAMEPAK_WS1_ADDR | GAMEPAK_WS2_ADDR => { GAMEPAK_WS0_ADDR | GAMEPAK_MIRROR_WS0_ADDR | GAMEPAK_WS1_ADDR | GAMEPAK_WS2_ADDR => {
(&mut self.gamepak, addr & 0x01ff_ffff) (&mut self.gamepak, addr & 0x01ff_ffff)
} }

View file

@ -3,10 +3,10 @@ use std::sync::Arc;
use std::time; use std::time;
use crate::core::arm7tdmi::arm::ArmInstruction; use crate::core::arm7tdmi::arm::ArmInstruction;
use crate::core::arm7tdmi::bus::Bus;
use crate::core::arm7tdmi::thumb::ThumbInstruction; use crate::core::arm7tdmi::thumb::ThumbInstruction;
use crate::core::arm7tdmi::{Addr, CpuState}; use crate::core::arm7tdmi::CpuState;
use crate::core::GBAError; use crate::core::GBAError;
use crate::core::{Addr, Bus};
use crate::disass::Disassembler; use crate::disass::Disassembler;
use crate::{AudioInterface, InputInterface, VideoInterface}; use crate::{AudioInterface, InputInterface, VideoInterface};

View file

@ -1,6 +1,6 @@
extern crate ctrlc; extern crate ctrlc;
use std::fs::File; use std::fs::File;
use std::io::{self, prelude::*, BufReader}; use std::io::{prelude::*, BufReader};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
@ -9,10 +9,9 @@ use rustyline::Editor;
use colored::*; use colored::*;
use super::core::arm7tdmi::{Addr, Bus, CpuError}; use super::core::arm7tdmi::CpuError;
use super::core::GameBoyAdvance; use super::core::GameBoyAdvance;
use super::core::{Addr, Bus};
use super::{AudioInterface, InputInterface, VideoInterface};
mod parser; mod parser;
use parser::{parse_expr, DerefType, Expr, Value}; use parser::{parse_expr, DerefType, Expr, Value};

View file

@ -1,6 +1,7 @@
use std::marker::PhantomData; use std::marker::PhantomData;
use super::core::arm7tdmi::{Addr, InstructionDecoder, InstructionDecoderError}; use super::core::arm7tdmi::{InstructionDecoder, InstructionDecoderError};
use super::core::Addr;
use std::io::ErrorKind; use std::io::ErrorKind;
pub struct Disassembler<'a, D> pub struct Disassembler<'a, D>