Refactor Bus traits into the arm7tdmi crate
Former-commit-id: 0027611bd4c777dcb7a4d3de6b0cc90cd649faa8 Former-commit-id: 41e30b29f97aee9e5d256a4f8d0c92ac1c761ac7
This commit is contained in:
parent
716a4d11ae
commit
a289900f6a
|
@ -21,10 +21,9 @@ pub mod alu;
|
|||
pub mod memory;
|
||||
pub use alu::*;
|
||||
use memory::Addr;
|
||||
pub mod disass;
|
||||
pub mod exception;
|
||||
pub mod psr;
|
||||
pub use psr::*;
|
||||
pub mod disass;
|
||||
|
||||
pub mod registers_consts {
|
||||
pub const REG_PC: usize = 15;
|
||||
|
|
|
@ -169,3 +169,90 @@ impl<I: MemoryInterface> Arm7tdmiCore<I> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple trait for accessing bus peripherals (higher level API than the low-level MemoryInterface)
|
||||
pub trait BusIO {
|
||||
fn read_32(&mut self, addr: Addr) -> u32 {
|
||||
self.read_16(addr) as u32 | (self.read_16(addr + 2) as u32) << 16
|
||||
}
|
||||
|
||||
fn read_16(&mut self, addr: Addr) -> u16 {
|
||||
self.default_read_16(addr)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn default_read_16(&mut self, addr: Addr) -> u16 {
|
||||
self.read_8(addr) as u16 | (self.read_8(addr + 1) as u16) << 8
|
||||
}
|
||||
|
||||
fn read_8(&mut self, addr: Addr) -> u8;
|
||||
|
||||
fn write_32(&mut self, addr: Addr, value: u32) {
|
||||
self.write_16(addr, (value & 0xffff) as u16);
|
||||
self.write_16(addr + 2, (value >> 16) as u16);
|
||||
}
|
||||
|
||||
fn write_16(&mut self, addr: Addr, value: u16) {
|
||||
self.default_write_16(addr, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn default_write_16(&mut self, addr: Addr, value: u16) {
|
||||
self.write_8(addr, (value & 0xff) as u8);
|
||||
self.write_8(addr + 1, ((value >> 8) & 0xff) as u8);
|
||||
}
|
||||
|
||||
fn write_8(&mut self, addr: Addr, value: u8);
|
||||
|
||||
fn get_bytes(&mut self, range: std::ops::Range<u32>) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
for b in range {
|
||||
bytes.push(self.read_8(b));
|
||||
}
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait for reading memory as if we were an all-powerfull debugger
|
||||
pub trait DebugRead: BusIO {
|
||||
fn debug_read_32(&mut self, addr: Addr) -> u32 {
|
||||
self.debug_read_16(addr) as u32 | (self.debug_read_16(addr + 2) as u32) << 16
|
||||
}
|
||||
|
||||
fn debug_read_16(&mut self, addr: Addr) -> u16 {
|
||||
self.debug_read_8(addr) as u16 | (self.debug_read_8(addr + 1) as u16) << 8
|
||||
}
|
||||
|
||||
fn debug_read_8(&mut self, addr: Addr) -> u8;
|
||||
|
||||
fn debug_get_bytes(&mut self, range: std::ops::Range<u32>) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
for b in range {
|
||||
bytes.push(self.debug_read_8(b));
|
||||
}
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
/// The caller is assumed to handle out of bound accesses,
|
||||
/// For performance reasons, this impl trusts that 'addr' is within the array range.
|
||||
impl BusIO for Box<[u8]> {
|
||||
#[inline]
|
||||
fn read_8(&mut self, addr: Addr) -> u8 {
|
||||
unsafe { *self.get_unchecked(addr as usize) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_8(&mut self, addr: Addr, value: u8) {
|
||||
unsafe {
|
||||
*self.get_unchecked_mut(addr as usize) = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugRead for Box<[u8]> {
|
||||
#[inline]
|
||||
fn debug_read_8(&mut self, addr: Addr) -> u8 {
|
||||
self[addr as usize]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ impl From<bool> for CpuState {
|
|||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct RegPSR {
|
||||
raw: u32,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use super::bus::{Bus, DebugRead};
|
||||
use super::SysBus;
|
||||
use arm7tdmi::{memory::Addr, Arm7tdmiCore};
|
||||
use arm7tdmi::{
|
||||
memory::{Addr, BusIO, DebugRead},
|
||||
Arm7tdmiCore,
|
||||
};
|
||||
|
||||
use rustboyadvance_utils::WeakPointer;
|
||||
|
||||
|
@ -35,7 +37,7 @@ impl Bios {
|
|||
}
|
||||
|
||||
/// Impl of Bus trait for Bios
|
||||
impl Bus for Bios {
|
||||
impl BusIO for Bios {
|
||||
#[inline]
|
||||
fn read_32(&mut self, addr: Addr) -> u32 {
|
||||
if self.read_allowed() {
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
pub use arm7tdmi::memory::Addr; // re-export
|
||||
|
||||
pub trait Bus {
|
||||
fn read_32(&mut self, addr: Addr) -> u32 {
|
||||
self.read_16(addr) as u32 | (self.read_16(addr + 2) as u32) << 16
|
||||
}
|
||||
|
||||
fn read_16(&mut self, addr: Addr) -> u16 {
|
||||
self.default_read_16(addr)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn default_read_16(&mut self, addr: Addr) -> u16 {
|
||||
self.read_8(addr) as u16 | (self.read_8(addr + 1) as u16) << 8
|
||||
}
|
||||
|
||||
fn read_8(&mut self, addr: Addr) -> u8;
|
||||
|
||||
fn write_32(&mut self, addr: Addr, value: u32) {
|
||||
self.write_16(addr, (value & 0xffff) as u16);
|
||||
self.write_16(addr + 2, (value >> 16) as u16);
|
||||
}
|
||||
|
||||
fn write_16(&mut self, addr: Addr, value: u16) {
|
||||
self.default_write_16(addr, value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn default_write_16(&mut self, addr: Addr, value: u16) {
|
||||
self.write_8(addr, (value & 0xff) as u8);
|
||||
self.write_8(addr + 1, ((value >> 8) & 0xff) as u8);
|
||||
}
|
||||
|
||||
fn write_8(&mut self, addr: Addr, value: u8);
|
||||
|
||||
fn get_bytes(&mut self, range: std::ops::Range<u32>) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
for b in range {
|
||||
bytes.push(self.read_8(b));
|
||||
}
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait for reading memory as if we were an all-powerfull debugger
|
||||
pub trait DebugRead: Bus {
|
||||
fn debug_read_32(&mut self, addr: Addr) -> u32 {
|
||||
self.debug_read_16(addr) as u32 | (self.debug_read_16(addr + 2) as u32) << 16
|
||||
}
|
||||
|
||||
fn debug_read_16(&mut self, addr: Addr) -> u16 {
|
||||
self.debug_read_8(addr) as u16 | (self.debug_read_8(addr + 1) as u16) << 8
|
||||
}
|
||||
|
||||
fn debug_read_8(&mut self, addr: Addr) -> u8;
|
||||
|
||||
fn debug_get_bytes(&mut self, range: std::ops::Range<u32>) -> Vec<u8> {
|
||||
let mut bytes = Vec::new();
|
||||
for b in range {
|
||||
bytes.push(self.debug_read_8(b));
|
||||
}
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
/// The caller is assumed to handle out of bound accesses,
|
||||
/// For performance reasons, this impl trusts that 'addr' is within the array range.
|
||||
impl Bus for Box<[u8]> {
|
||||
#[inline]
|
||||
fn read_8(&mut self, addr: Addr) -> u8 {
|
||||
unsafe { *self.get_unchecked(addr as usize) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_8(&mut self, addr: Addr, value: u8) {
|
||||
unsafe {
|
||||
*self.get_unchecked_mut(addr as usize) = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DebugRead for Box<[u8]> {
|
||||
#[inline]
|
||||
fn debug_read_8(&mut self, addr: Addr) -> u8 {
|
||||
self[addr as usize]
|
||||
}
|
||||
}
|
|
@ -152,8 +152,9 @@ impl EepromChip {
|
|||
RxInstruction => {
|
||||
// If instruction was recvd, proceed to recv the address
|
||||
if self.rx_count >= 2 {
|
||||
let insn = SpiInstruction::from_u64(self.rx_buffer).unwrap_or_else(|| panic!("invalid spi command {:#010b}",
|
||||
self.rx_buffer as u8));
|
||||
let insn = SpiInstruction::from_u64(self.rx_buffer).unwrap_or_else(|| {
|
||||
panic!("invalid spi command {:#010b}", self.rx_buffer as u8)
|
||||
});
|
||||
next_state = Some(RxAddress(insn));
|
||||
self.reset_rx_buffer();
|
||||
}
|
||||
|
|
|
@ -150,7 +150,6 @@ impl Flash {
|
|||
pub fn read(&self, addr: u32) -> u8 {
|
||||
let offset = (addr & 0xffff) as usize;
|
||||
|
||||
|
||||
if self.mode == FlashMode::ChipId {
|
||||
match offset {
|
||||
0 => (self.chip_id & 0xff) as u8,
|
||||
|
|
|
@ -216,8 +216,7 @@ fn create_backup(backup_type: BackupType, rom_path: Option<PathBuf>) -> BackupMe
|
|||
}
|
||||
|
||||
fn detect_backup_type(bytes: &[u8]) -> Option<BackupType> {
|
||||
const ID_STRINGS: &[&str] =
|
||||
&["EEPROM", "SRAM", "FLASH_", "FLASH512_", "FLASH1M_"];
|
||||
const ID_STRINGS: &[&str] = &["EEPROM", "SRAM", "FLASH_", "FLASH512_", "FLASH1M_"];
|
||||
|
||||
for i in 0..5 {
|
||||
let search = TwoWaySearcher::new(ID_STRINGS[i].as_bytes());
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::bus::*;
|
||||
use arm7tdmi::memory::{Addr, BusIO, DebugRead};
|
||||
|
||||
pub mod header;
|
||||
use header::CartridgeHeader;
|
||||
|
@ -109,7 +109,7 @@ fn is_gpio_access(addr: u32) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
impl Bus for Cartridge {
|
||||
impl BusIO for Cartridge {
|
||||
fn read_8(&mut self, addr: Addr) -> u8 {
|
||||
let offset = (addr & 0x01ff_ffff) as usize;
|
||||
match addr & 0xff000000 {
|
||||
|
|
|
@ -397,8 +397,8 @@ mod tests {
|
|||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::super::bus::Bus;
|
||||
use super::super::cartridge::GamepakBuilder;
|
||||
use crate::cartridge::GamepakBuilder;
|
||||
use arm7tdmi::memory::BusIO;
|
||||
|
||||
struct DummyInterface {}
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@ use std::rc::Rc;
|
|||
use num::FromPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use arm7tdmi::memory::{Addr, BusIO, DebugRead};
|
||||
use rustboyadvance_utils::index2d;
|
||||
|
||||
use super::bus::*;
|
||||
use super::dma::{DmaNotifer, TIMING_HBLANK, TIMING_VBLANK};
|
||||
use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags};
|
||||
use super::sched::{EventType, FutureEvent, GpuEvent, Scheduler};
|
||||
|
@ -455,7 +455,7 @@ impl Gpu {
|
|||
}
|
||||
}
|
||||
|
||||
impl Bus for Gpu {
|
||||
impl BusIO for Gpu {
|
||||
fn read_8(&mut self, addr: Addr) -> u8 {
|
||||
let page = (addr >> 24) as usize;
|
||||
match page {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::cmp;
|
||||
|
||||
use super::bus::*;
|
||||
use arm7tdmi::memory::{Addr, BusIO, DebugRead};
|
||||
|
||||
use super::dma::DmaController;
|
||||
use super::gpu::regs::GpuMemoryMappedIO;
|
||||
use super::gpu::regs::WindowFlags;
|
||||
|
@ -92,7 +93,7 @@ impl SchedulerConnect for IoDevices {
|
|||
}
|
||||
}
|
||||
|
||||
impl Bus for IoDevices {
|
||||
impl BusIO for IoDevices {
|
||||
fn read_16(&mut self, addr: Addr) -> u16 {
|
||||
let io = self;
|
||||
let io_addr = addr + IO_BASE;
|
||||
|
|
|
@ -10,7 +10,6 @@ extern crate debug_stub_derive;
|
|||
#[macro_use]
|
||||
extern crate enum_primitive_derive;
|
||||
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitfield;
|
||||
#[macro_use]
|
||||
|
@ -27,8 +26,6 @@ extern crate smart_default;
|
|||
|
||||
extern crate cfg_if;
|
||||
|
||||
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::arm7tdmi::memory::*;
|
||||
use super::arm7tdmi::memory::{
|
||||
Addr, BusIO, DebugRead, MemoryAccess, MemoryAccessWidth, MemoryInterface,
|
||||
};
|
||||
use super::bios::Bios;
|
||||
use super::bus::*;
|
||||
use super::cartridge::Cartridge;
|
||||
use super::dma::DmaNotifer;
|
||||
use super::iodev::{IoDevices, WaitControl};
|
||||
|
@ -305,7 +306,7 @@ impl SysBus {
|
|||
}
|
||||
|
||||
/// Todo - implement bound checks for EWRAM/IWRAM
|
||||
impl Bus for SysBus {
|
||||
impl BusIO for SysBus {
|
||||
#[inline]
|
||||
fn read_32(&mut self, addr: Addr) -> u32 {
|
||||
match addr & 0xff000000 {
|
||||
|
|
Reference in a new issue