Implement all memory mappings. Reformat many files.

Former-commit-id: c0a62b610e62d2db2a4daf4aeef40068820daa52
This commit is contained in:
Michel Heily 2019-07-01 17:45:29 +03:00
parent 22c175d9cc
commit 6b225d776d
11 changed files with 219 additions and 146 deletions

View file

@ -1,10 +1,10 @@
use std::fmt; use std::fmt;
use crate::arm7tdmi::{Addr, reg_string, REG_PC};
use super::{ use super::{
ArmCond, ArmHalfwordTransferType, ArmInstruction, ArmInstructionFormat, ArmOpCode, ArmCond, ArmHalfwordTransferType, ArmInstruction, ArmInstructionFormat, ArmOpCode,
ArmRegisterShift, ArmShiftType, ArmShiftedValue, ArmRegisterShift, ArmShiftType, ArmShiftedValue,
}; };
use crate::arm7tdmi::{reg_string, Addr, REG_PC};
impl fmt::Display for ArmCond { impl fmt::Display for ArmCond {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

View file

@ -1,8 +1,8 @@
use crate::bit::BitIndex; use crate::bit::BitIndex;
use crate::arm7tdmi::bus::{Bus, MemoryAccess, MemoryAccessType::*, MemoryAccessWidth::*};
use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction}; use crate::arm7tdmi::cpu::{Core, CpuExecResult, CpuPipelineAction};
use crate::arm7tdmi::exception::Exception; use crate::arm7tdmi::exception::Exception;
use crate::arm7tdmi::bus::{Bus, MemoryAccess, MemoryAccessType::*, MemoryAccessWidth::*};
use crate::arm7tdmi::{Addr, CpuError, CpuInstruction, CpuResult, CpuState, REG_PC}; use crate::arm7tdmi::{Addr, CpuError, CpuInstruction, CpuResult, CpuState, REG_PC};
use crate::sysbus::SysBus; use crate::sysbus::SysBus;
@ -15,7 +15,11 @@ use super::{
impl Core { impl Core {
pub fn exec_arm(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult { pub fn exec_arm(&mut self, sysbus: &mut SysBus, insn: ArmInstruction) -> CpuExecResult {
if !self.check_arm_cond(insn.cond) { if !self.check_arm_cond(insn.cond) {
self.add_cycles(self.pc + (self.word_size() as u32), sysbus, Seq + MemoryAccess32); self.add_cycles(
insn.pc + (self.word_size() as u32),
sysbus,
Seq + MemoryAccess32,
);
self.add_cycle(); self.add_cycle();
return Ok(CpuPipelineAction::IncPC); return Ok(CpuPipelineAction::IncPC);
} }
@ -48,7 +52,11 @@ impl Core {
// +2S // +2S
self.add_cycles(self.pc, sysbus, Seq + MemoryAccess32); self.add_cycles(self.pc, sysbus, Seq + MemoryAccess32);
self.add_cycles(self.pc + (self.word_size() as u32), sysbus, Seq + MemoryAccess32); self.add_cycles(
self.pc + (self.word_size() as u32),
sysbus,
Seq + MemoryAccess32,
);
Ok(CpuPipelineAction::Flush) Ok(CpuPipelineAction::Flush)
} }
@ -73,7 +81,11 @@ impl Core {
// +2S // +2S
self.add_cycles(self.pc, sysbus, Seq + MemoryAccess32); self.add_cycles(self.pc, sysbus, Seq + MemoryAccess32);
self.add_cycles(self.pc + (self.word_size() as u32), sysbus, Seq + MemoryAccess32); self.add_cycles(
self.pc + (self.word_size() as u32),
sysbus,
Seq + MemoryAccess32,
);
Ok(CpuPipelineAction::Flush) Ok(CpuPipelineAction::Flush)
} }
@ -208,7 +220,11 @@ impl Core {
} }
// +1S // +1S
self.add_cycles(self.pc + (self.word_size() as u32), sysbus, Seq + MemoryAccess32); self.add_cycles(
self.pc + (self.word_size() as u32),
sysbus,
Seq + MemoryAccess32,
);
Ok(pipeline_action) Ok(pipeline_action)
} }
@ -219,12 +235,16 @@ impl Core {
ArmShiftedValue::ShiftedRegister { ArmShiftedValue::ShiftedRegister {
reg, reg,
shift, shift,
added: Some(added) added: Some(added),
} => { } => {
let abs = self.register_shift(reg, shift).unwrap(); let abs = self.register_shift(reg, shift).unwrap();
if added { abs } else { -abs } if added {
abs
} else {
-abs
}
} }
_ => panic!("bad barrel shift") _ => panic!("bad barrel shift"),
} }
} }
@ -240,7 +260,6 @@ impl Core {
sysbus: &mut SysBus, sysbus: &mut SysBus,
insn: ArmInstruction, insn: ArmInstruction,
) -> CpuResult<CpuPipelineAction> { ) -> CpuResult<CpuPipelineAction> {
if insn.write_back_flag() && insn.rd() == insn.rn() { if insn.write_back_flag() && insn.rd() == insn.rn() {
return Err(CpuError::IllegalInstruction); return Err(CpuError::IllegalInstruction);
} }
@ -258,7 +277,7 @@ impl Core {
let effective_addr = (addr as i32).wrapping_add(offset) as Addr; let effective_addr = (addr as i32).wrapping_add(offset) as Addr;
addr = if insn.pre_index_flag() { addr = if insn.pre_index_flag() {
effective_addr effective_addr
} else { } else {
addr addr
}; };
@ -273,7 +292,11 @@ impl Core {
sysbus.read_32(addr) sysbus.read_32(addr)
}; };
// +1S // +1S
self.add_cycles(self.pc + (self.word_size() as u32), sysbus, Seq + MemoryAccess32); self.add_cycles(
self.pc + (self.word_size() as u32),
sysbus,
Seq + MemoryAccess32,
);
self.set_reg(insn.rd(), data); self.set_reg(insn.rd(), data);
@ -284,7 +307,11 @@ impl Core {
// +1S // +1S
self.add_cycles(self.pc, sysbus, Seq + MemoryAccess32); self.add_cycles(self.pc, sysbus, Seq + MemoryAccess32);
// +1N // +1N
self.add_cycles(self.pc + (self.word_size() as u32), sysbus, NonSeq + MemoryAccess32); self.add_cycles(
self.pc + (self.word_size() as u32),
sysbus,
NonSeq + MemoryAccess32,
);
pipeline_action = CpuPipelineAction::Flush; pipeline_action = CpuPipelineAction::Flush;
} }
} else { } else {
@ -293,11 +320,11 @@ impl Core {
if insn.transfer_size() == 1 { if insn.transfer_size() == 1 {
// +1N // +1N
self.add_cycles(dest, sysbus, NonSeq + MemoryAccess8); self.add_cycles(dest, sysbus, NonSeq + MemoryAccess8);
sysbus.write_8(addr, value as u8); sysbus.write_8(addr, value as u8).expect("bus error");
} else { } else {
// +1N // +1N
self.add_cycles(dest, sysbus, NonSeq + MemoryAccess32); self.add_cycles(dest, sysbus, NonSeq + MemoryAccess32);
sysbus.write_32(addr, value); sysbus.write_32(addr, value).expect("bus error");
}; };
} }
@ -305,6 +332,6 @@ impl Core {
self.set_reg(insn.rn(), effective_addr as u32) self.set_reg(insn.rn(), effective_addr as u32)
} }
Ok(CpuPipelineAction::IncPC) Ok(pipeline_action)
} }
} }

View file

@ -1,19 +1,20 @@
use super::Addr;
use std::io; use std::io;
use std::ops::Add; use std::ops::Add;
use super::Addr;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
pub enum MemoryAccessType { pub enum MemoryAccessType {
NonSeq, NonSeq,
Seq Seq,
} }
pub enum MemoryAccessWidth { pub enum MemoryAccessWidth {
MemoryAccess8, MemoryAccess8,
MemoryAccess16, MemoryAccess16,
MemoryAccess32 MemoryAccess32,
} }
impl Add<MemoryAccessWidth> for MemoryAccessType { impl Add<MemoryAccessWidth> for MemoryAccessType {
type Output = MemoryAccess; type Output = MemoryAccess;
@ -22,17 +23,40 @@ impl Add<MemoryAccessWidth> for MemoryAccessType {
} }
} }
pub struct MemoryAccess(MemoryAccessType, MemoryAccessWidth); pub struct MemoryAccess(pub MemoryAccessType, pub MemoryAccessWidth);
pub trait Bus { pub trait Bus {
fn read_32(&self, addr: Addr) -> u32; fn read_32(&self, addr: Addr) -> u32 {
fn read_16(&self, addr: Addr) -> u16; self.get_bytes(addr, 4).read_u32::<LittleEndian>().unwrap()
fn read_8(&self, addr: Addr) -> u8; }
fn write_32(&mut self, addr: Addr, value: u32) -> Result<(), io::Error>;
fn write_16(&mut self, addr: Addr, value: u16) -> Result<(), io::Error>; fn read_16(&self, addr: Addr) -> u16 {
fn write_8(&mut self, addr: Addr, value: u8) -> Result<(), io::Error>; self.get_bytes(addr, 2).read_u16::<LittleEndian>().unwrap()
}
fn read_8(&self, addr: Addr) -> u8 {
self.get_bytes(addr, 1)[0]
}
fn write_32(&mut self, addr: Addr, value: u32) -> Result<(), io::Error> {
self.get_bytes_mut(addr, 4).write_u32::<LittleEndian>(value)
}
fn write_16(&mut self, addr: Addr, value: u16) -> Result<(), io::Error> {
self.get_bytes_mut(addr, 2).write_u16::<LittleEndian>(value)
}
fn write_8(&mut self, addr: Addr, value: u8) -> Result<(), io::Error> {
self.get_bytes_mut(addr, 1).write_u8(value)
}
/// Return a slice of bytes
/// Will panic if requested range is out of bounds
fn get_bytes(&self, addr: Addr, len: usize) -> &[u8];
/// Return a mutable slice of bytes
/// Will panic if requested range is out of bounds
fn get_bytes_mut(&mut self, addr: Addr, len: usize) -> &mut [u8];
fn get_bytes(&self, addr: Addr, size: usize) -> Option<&[u8]>;
/// returns the number of cycles needed for this memory access /// returns the number of cycles needed for this memory access
fn get_cycles(&self, addr: Addr, access: MemoryAccess) -> usize; fn get_cycles(&self, addr: Addr, access: MemoryAccess) -> usize;
} }

View file

@ -1,6 +1,6 @@
use std::ops::Add;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::ops::Add;
use ansi_term::{Colour, Style}; use ansi_term::{Colour, Style};
@ -8,10 +8,10 @@ use crate::sysbus::SysBus;
pub use super::exception::Exception; pub use super::exception::Exception;
use super::{ use super::{
CpuState, CpuMode, reg_string, CpuResult, Addr, arm::*,
psr::RegPSR,
bus::{Bus, MemoryAccess, MemoryAccessType::*, MemoryAccessWidth::*}, bus::{Bus, MemoryAccess, MemoryAccessType::*, MemoryAccessWidth::*},
arm::* psr::RegPSR,
reg_string, Addr, CpuMode, CpuResult, CpuState,
}; };
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -198,9 +198,7 @@ impl Core {
let action = self.exec_arm(sysbus, d)?; let action = self.exec_arm(sysbus, d)?;
Ok((Some(d), action)) Ok((Some(d), action))
} }
None => { None => Ok((None, CpuPipelineAction::IncPC)),
Ok((None, CpuPipelineAction::IncPC))
},
}; };
self.pipeline.fetched = Some((self.pc, new_fetched)); self.pipeline.fetched = Some((self.pc, new_fetched));

View file

@ -1,14 +1,14 @@
use std::fmt; use std::fmt;
pub mod arm; pub mod arm;
use arm::{ArmInstruction, ArmDecodeError}; use arm::{ArmDecodeError, ArmInstruction};
pub mod cpu; pub mod cpu;
pub use cpu::*;
pub mod bus; pub mod bus;
mod exception; mod exception;
mod psr; mod psr;
pub const REG_PC: usize = 15; 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;

View file

@ -5,11 +5,17 @@ subcommands:
- debug: - debug:
about: debug the bios with the arm core emulation about: debug the bios with the arm core emulation
args: args:
- BIOS: - bios:
help: Sets the bios file to use help: Sets the bios file to use
required: false required: false
default_value: gba_bios.bin default_value: gba_bios.bin
index: 1 index: 1
- game_rom:
short: g
long: game-rom
takes_value: true
help: Sets the game-rom file to use
required: true
- disass: - disass:
about: disassemble an arm binary file about: disassemble an arm binary file
args: args:

View file

@ -8,9 +8,9 @@ use clap::{App, ArgMatches};
extern crate rustboyadvance_ng; extern crate rustboyadvance_ng;
use rustboyadvance_ng::arm7tdmi; use rustboyadvance_ng::arm7tdmi;
use rustboyadvance_ng::sysbus::SysBus;
use rustboyadvance_ng::debugger::{Debugger, DebuggerError}; use rustboyadvance_ng::debugger::{Debugger, DebuggerError};
use rustboyadvance_ng::disass::Disassembler; use rustboyadvance_ng::disass::Disassembler;
use rustboyadvance_ng::sysbus::SysBus;
use rustboyadvance_ng::util::read_bin_file; use rustboyadvance_ng::util::read_bin_file;
#[derive(Debug)] #[derive(Debug)]
@ -18,7 +18,7 @@ pub enum GBAError {
IO(io::Error), IO(io::Error),
ArmDecodeError(arm7tdmi::arm::ArmDecodeError), ArmDecodeError(arm7tdmi::arm::ArmDecodeError),
CpuError(arm7tdmi::CpuError), CpuError(arm7tdmi::CpuError),
DebuggerError(DebuggerError) DebuggerError(DebuggerError),
} }
pub type GBAResult<T> = Result<T, GBAError>; pub type GBAResult<T> = Result<T, GBAError>;
@ -59,11 +59,10 @@ fn run_disass(matches: &ArgMatches) -> GBAResult<()> {
} }
fn run_debug(matches: &ArgMatches) -> GBAResult<()> { fn run_debug(matches: &ArgMatches) -> GBAResult<()> {
let gba_bios_path = matches.value_of("BIOS").unwrap_or_default(); let bios_bin = read_bin_file(matches.value_of("bios").unwrap_or_default())?;
println!("Loading BIOS: {}", gba_bios_path); let rom_bin = read_bin_file(matches.value_of("game_rom").unwrap())?;
let bios_bin = read_bin_file(gba_bios_path)?;
let sysbus = SysBus::new(bios_bin); let sysbus = SysBus::new(bios_bin, rom_bin);
let mut core = arm7tdmi::cpu::Core::new(); let mut core = arm7tdmi::cpu::Core::new();
core.reset(); core.reset();
core.set_verbose(true); core.set_verbose(true);

View file

@ -1,5 +1,5 @@
use crate::arm7tdmi::{reg_string, REG_PC};
use crate::arm7tdmi::bus::Bus; use crate::arm7tdmi::bus::Bus;
use crate::arm7tdmi::{reg_string, REG_PC};
use crate::debugger::Debugger; use crate::debugger::Debugger;
use crate::disass::Disassembler; use crate::disass::Disassembler;
@ -59,11 +59,11 @@ impl Command {
match debugger.cpu.step_debugger(&mut debugger.sysbus) { match debugger.cpu.step_debugger(&mut debugger.sysbus) {
Ok(insn) => { Ok(insn) => {
println!( println!(
"@0x{:08x}:\n\t{}", "@0x{:08x}:\n\t{}",
insn.pc, insn.pc,
Colour::Yellow.italic().paint(format!("{} ", insn)) Colour::Yellow.italic().paint(format!("{} ", insn))
); );
}, }
Err(e) => { Err(e) => {
println!("{}: {}", "cpu encountered an error".red(), e); println!("{}: {}", "cpu encountered an error".red(), e);
println!("cpu: {:x?}", debugger.cpu); println!("cpu: {:x?}", debugger.cpu);
@ -72,23 +72,11 @@ impl Command {
}; };
}, },
HexDump(addr, nbytes) => { HexDump(addr, nbytes) => {
let bytes = match debugger.sysbus.get_bytes(addr, nbytes) { let bytes = debugger.sysbus.get_bytes(addr, nbytes);
Some(bytes) => bytes,
None => {
println!("requested content out of bounds");
return;
}
};
hexdump::hexdump(bytes); hexdump::hexdump(bytes);
} }
Disass(addr, n) => { Disass(addr, n) => {
let bytes = match debugger.sysbus.get_bytes(addr, 4 * n) { let bytes = debugger.sysbus.get_bytes(addr, 4 * n);
Some(bytes) => bytes,
None => {
println!("requested content out of bounds");
return;
}
};
let disass = Disassembler::new(addr, bytes); let disass = Disassembler::new(addr, bytes);
for (_, line) in disass { for (_, line) in disass {
println!("{}", line) println!("{}", line)

View file

@ -171,7 +171,7 @@ impl Debugger {
if let Some(Command::Disass(addr, n)) = self.previous_command { if let Some(Command::Disass(addr, n)) = self.previous_command {
(addr + (4 * n as u32), 10) (addr + (4 * n as u32), 10)
} else { } else {
(self.cpu.get_reg(15), 10) (self.cpu.get_next_pc(), 10)
} }
} }
_ => { _ => {

View file

@ -1,132 +1,163 @@
use std::io; use std::io;
use super::arm7tdmi::bus::{Bus, MemoryAccess, MemoryAccessWidth};
use super::arm7tdmi::Addr; use super::arm7tdmi::Addr;
use super::arm7tdmi::bus::{Bus, MemoryAccess, MemoryAccessType, MemoryAccessWidth};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
const VIDEO_RAM_SIZE: usize = 128 * 1024; const VIDEO_RAM_SIZE: usize = 128 * 1024;
const WORK_RAM_SIZE: usize = 256 * 1024; const WORK_RAM_SIZE: usize = 256 * 1024;
const INTERNAL_RAM: usize = 32 * 1024; const INTERNAL_RAM: usize = 32 * 1024;
const PALETTE_AM_SIZE: usize = 1 * 1024; const PALETTE_RAM_SIZE: usize = 1 * 1024;
const OAM_SIZE: usize = 1 * 1024; const OAM_SIZE: usize = 1 * 1024;
const BIOS_SIZE: usize = 16 * 1024;
const GAMEPAK_ROM_SIZE: usize = 32 * 1024 * 1024;
#[derive(Debug)] #[derive(Debug)]
struct BiosROM(Vec<u8>); struct BoxedMemory(Box<[u8]>, WaitState);
impl Bus for BiosROM { #[derive(Debug)]
fn read_32(&self, addr: Addr) -> u32 { struct WaitState {
let addr = addr as usize; access8: usize,
(&self.0[addr..addr + 4]) access16: usize,
.read_u32::<LittleEndian>() access32: usize,
.unwrap() }
}
fn read_16(&self, addr: Addr) -> u16 { impl WaitState {
let addr = addr as usize; fn new(access8: usize, access16: usize, access32: usize) -> WaitState {
(&self.0[addr..addr + 4]) WaitState {
.read_u16::<LittleEndian>() access8,
.unwrap() access16,
} access32,
fn read_8(&self, addr: Addr) -> u8 {
self.0[addr as usize]
}
fn write_32(&mut self, addr: Addr, value: u32) -> Result<(), io::Error> {
let mut wrt = io::Cursor::new(&mut self.0);
wrt.set_position(addr as u64);
wrt.write_u32::<LittleEndian>(value)
}
fn write_16(&mut self, addr: Addr, value: u16) -> Result<(), io::Error> {
let mut wrt = io::Cursor::new(&mut self.0);
wrt.set_position(addr as u64);
wrt.write_u16::<LittleEndian>(value)
}
fn write_8(&mut self, addr: Addr, value: u8) -> Result<(), io::Error> {
let mut wrt = io::Cursor::new(&mut self.0);
wrt.write_u8(value)
}
fn get_bytes(&self, addr: Addr, size: usize) -> Option<&[u8]> {
let addr = addr as usize;
if addr + size > self.0.len() {
None
} else {
Some(&self.0[addr..addr + size])
} }
} }
fn get_cycles(&self, _addr: Addr, _access: MemoryAccess) -> usize {
1
}
} }
#[derive(Debug)] impl Default for WaitState {
enum SysBusDevice { fn default() -> WaitState {
BiosROM(BiosROM) WaitState::new(1, 1, 1)
}
}
impl Bus for BoxedMemory {
fn get_bytes(&self, addr: Addr, size: usize) -> &[u8] {
let addr = addr as usize;
&self.0[addr..addr + size]
}
fn get_bytes_mut(&mut self, addr: Addr, size: usize) -> &mut [u8] {
let addr = addr as usize;
&mut self.0[addr..addr + size]
}
fn get_cycles(&self, _addr: Addr, access: MemoryAccess) -> usize {
match access.1 {
MemoryAccessWidth::MemoryAccess8 => self.1.access8,
MemoryAccessWidth::MemoryAccess16 => self.1.access16,
MemoryAccessWidth::MemoryAccess32 => self.1.access32,
}
}
} }
#[derive(Debug)] #[derive(Debug)]
pub struct SysBus { pub struct SysBus {
bios: BiosROM bios: BoxedMemory,
onboard_work_ram: BoxedMemory,
internal_work_ram: BoxedMemory,
/// Currently model the IOMem as regular buffer, later make it into something more sophisticated.
ioregs: BoxedMemory,
palette_ram: BoxedMemory,
vram: BoxedMemory,
oam: BoxedMemory,
gamepak_flashrom: BoxedMemory,
} }
impl SysBus { impl SysBus {
pub fn new(bios_rom: Vec<u8>) -> SysBus { pub fn new(bios_rom: Vec<u8>, game_rom: Vec<u8>) -> SysBus {
SysBus { bios: BiosROM(bios_rom) } SysBus {
} bios: BoxedMemory(bios_rom.into_boxed_slice(), Default::default()),
onboard_work_ram: BoxedMemory(
fn map(&self, addr: Addr) -> & impl Bus { vec![0; WORK_RAM_SIZE].into_boxed_slice(),
match addr as usize { Default::default(),
0...BIOS_SIZE => &self.bios, ),
_ => panic!("unmapped address") internal_work_ram: BoxedMemory(
vec![0; INTERNAL_RAM].into_boxed_slice(),
Default::default(),
),
ioregs: BoxedMemory(vec![0; 1024].into_boxed_slice(), Default::default()),
palette_ram: BoxedMemory(
vec![0; PALETTE_RAM_SIZE].into_boxed_slice(),
WaitState::new(1, 1, 2),
),
vram: BoxedMemory(
vec![0; VIDEO_RAM_SIZE].into_boxed_slice(),
WaitState::new(1, 1, 2),
),
oam: BoxedMemory(vec![0; OAM_SIZE].into_boxed_slice(), Default::default()),
gamepak_flashrom: BoxedMemory(game_rom.into_boxed_slice(), WaitState::new(5, 5, 8)),
} }
} }
fn map(&self, addr: Addr) -> &impl Bus {
match addr as usize {
0x0000_0000...0x0000_3fff => &self.bios,
0x0200_0000...0x0203_ffff => &self.onboard_work_ram,
0x0300_0000...0x0300_7fff => &self.internal_work_ram,
0x0400_0000...0x0400_03fe => &self.ioregs,
0x0500_0000...0x0500_03ff => &self.palette_ram,
0x0600_0000...0x0601_7fff => &self.vram,
0x0700_0000...0x0700_03ff => &self.oam,
0x0800_0000...0x09ff_ffff => &self.gamepak_flashrom,
_ => panic!("unmapped address @0x{:08x}", addr),
}
}
/// TODO proc-macro for generating this function
fn map_mut(&mut self, addr: Addr) -> &mut impl Bus { fn map_mut(&mut self, addr: Addr) -> &mut impl Bus {
match addr as usize { match addr as usize {
0...BIOS_SIZE => &mut self.bios, 0x0000_0000...0x0000_3fff => &mut self.bios,
_ => panic!("unmapped address") 0x0200_0000...0x0203_ffff => &mut self.onboard_work_ram,
0x0300_0000...0x0300_7fff => &mut self.internal_work_ram,
0x0400_0000...0x0400_03fe => &mut self.ioregs,
0x0500_0000...0x0500_03ff => &mut self.palette_ram,
0x0600_0000...0x0601_7fff => &mut self.vram,
0x0700_0000...0x0700_03ff => &mut self.oam,
0x0800_0000...0x09ff_ffff => &mut self.gamepak_flashrom,
_ => panic!("unmapped address @0x{:08x}", addr),
} }
} }
} }
impl Bus for SysBus { impl Bus for SysBus {
fn read_32(&self, addr: Addr) -> u32 { fn read_32(&self, addr: Addr) -> u32 {
self.map(addr).read_32(addr) self.map(addr).read_32(addr & 0xff_ffff)
} }
fn read_16(&self, addr: Addr) -> u16 { fn read_16(&self, addr: Addr) -> u16 {
self.map(addr).read_16(addr) self.map(addr).read_16(addr & 0xff_ffff)
} }
fn read_8(&self, addr: Addr) -> u8 { fn read_8(&self, addr: Addr) -> u8 {
self.map(addr).read_8(addr) self.map(addr).read_8(addr & 0xff_ffff)
} }
fn write_32(&mut self, addr: Addr, value: u32) -> Result<(), io::Error> { fn write_32(&mut self, addr: Addr, value: u32) -> Result<(), io::Error> {
self.map_mut(addr).write_32(addr, value) self.map_mut(addr).write_32(addr & 0xff_ffff, value)
} }
fn write_16(&mut self, addr: Addr, value: u16) -> Result<(), io::Error> { fn write_16(&mut self, addr: Addr, value: u16) -> Result<(), io::Error> {
self.map_mut(addr).write_16(addr, value) self.map_mut(addr).write_16(addr & 0xff_ffff, value)
} }
fn write_8(&mut self, addr: Addr, value: u8) -> Result<(), io::Error> { fn write_8(&mut self, addr: Addr, value: u8) -> Result<(), io::Error> {
self.map_mut(addr).write_8(addr, value) self.map_mut(addr).write_8(addr & 0xff_ffff, value)
} }
fn get_bytes(&self, addr: Addr, size: usize) -> &[u8] {
self.map(addr).get_bytes(addr & 0xff_ffff, size)
}
fn get_bytes(&self, addr: Addr, size: usize) -> Option<&[u8]> { fn get_bytes_mut(&mut self, addr: Addr, size: usize) -> &mut [u8] {
self.map(addr).get_bytes(addr, size) self.map_mut(addr).get_bytes_mut(addr & 0xff_ffff, size)
} }
fn get_cycles(&self, addr: Addr, access: MemoryAccess) -> usize { fn get_cycles(&self, addr: Addr, access: MemoryAccess) -> usize {
self.map(addr).get_cycles(addr, access) self.map(addr).get_cycles(addr & 0xff_ffff, access)
} }
} }