Refactor Bus traits into the arm7tdmi crate

Former-commit-id: 0027611bd4c777dcb7a4d3de6b0cc90cd649faa8
Former-commit-id: 41e30b29f97aee9e5d256a4f8d0c92ac1c761ac7
This commit is contained in:
Michel Heily 2022-09-06 02:04:50 +03:00
parent 716a4d11ae
commit a289900f6a
15 changed files with 112 additions and 112 deletions

View file

@ -146,7 +146,7 @@ impl InstructionDecoder for ArmInstruction {
fn decode(raw: u32, addr: Addr) -> Self { fn decode(raw: u32, addr: Addr) -> Self {
let fmt = ArmFormat::from(raw); let fmt = ArmFormat::from(raw);
ArmInstruction {fmt, raw, pc: addr } ArmInstruction { fmt, raw, pc: addr }
} }
fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Self { fn decode_from_bytes(bytes: &[u8], addr: Addr) -> Self {

View file

@ -21,10 +21,9 @@ pub mod alu;
pub mod memory; pub mod memory;
pub use alu::*; pub use alu::*;
use memory::Addr; use memory::Addr;
pub mod disass;
pub mod exception; pub mod exception;
pub mod psr; pub mod psr;
pub use psr::*;
pub mod disass;
pub mod registers_consts { pub mod registers_consts {
pub const REG_PC: usize = 15; pub const REG_PC: usize = 15;

View file

@ -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]
}
}

View file

@ -30,6 +30,7 @@ impl From<bool> for CpuState {
} }
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
#[repr(transparent)]
pub struct RegPSR { pub struct RegPSR {
raw: u32, raw: u32,
} }

View file

@ -1,6 +1,8 @@
use super::bus::{Bus, DebugRead};
use super::SysBus; use super::SysBus;
use arm7tdmi::{memory::Addr, Arm7tdmiCore}; use arm7tdmi::{
memory::{Addr, BusIO, DebugRead},
Arm7tdmiCore,
};
use rustboyadvance_utils::WeakPointer; use rustboyadvance_utils::WeakPointer;
@ -35,7 +37,7 @@ impl Bios {
} }
/// Impl of Bus trait for Bios /// Impl of Bus trait for Bios
impl Bus for Bios { impl BusIO for Bios {
#[inline] #[inline]
fn read_32(&mut self, addr: Addr) -> u32 { fn read_32(&mut self, addr: Addr) -> u32 {
if self.read_allowed() { if self.read_allowed() {

View file

@ -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]
}
}

View file

@ -152,8 +152,9 @@ impl EepromChip {
RxInstruction => { RxInstruction => {
// If instruction was recvd, proceed to recv the address // If instruction was recvd, proceed to recv the address
if self.rx_count >= 2 { if self.rx_count >= 2 {
let insn = SpiInstruction::from_u64(self.rx_buffer).unwrap_or_else(|| panic!("invalid spi command {:#010b}", let insn = SpiInstruction::from_u64(self.rx_buffer).unwrap_or_else(|| {
self.rx_buffer as u8)); panic!("invalid spi command {:#010b}", self.rx_buffer as u8)
});
next_state = Some(RxAddress(insn)); next_state = Some(RxAddress(insn));
self.reset_rx_buffer(); self.reset_rx_buffer();
} }

View file

@ -150,7 +150,6 @@ impl Flash {
pub fn read(&self, addr: u32) -> u8 { pub fn read(&self, addr: u32) -> u8 {
let offset = (addr & 0xffff) as usize; let offset = (addr & 0xffff) as usize;
if self.mode == FlashMode::ChipId { if self.mode == FlashMode::ChipId {
match offset { match offset {
0 => (self.chip_id & 0xff) as u8, 0 => (self.chip_id & 0xff) as u8,

View file

@ -216,8 +216,7 @@ fn create_backup(backup_type: BackupType, rom_path: Option<PathBuf>) -> BackupMe
} }
fn detect_backup_type(bytes: &[u8]) -> Option<BackupType> { fn detect_backup_type(bytes: &[u8]) -> Option<BackupType> {
const ID_STRINGS: &[&str] = const ID_STRINGS: &[&str] = &["EEPROM", "SRAM", "FLASH_", "FLASH512_", "FLASH1M_"];
&["EEPROM", "SRAM", "FLASH_", "FLASH512_", "FLASH1M_"];
for i in 0..5 { for i in 0..5 {
let search = TwoWaySearcher::new(ID_STRINGS[i].as_bytes()); let search = TwoWaySearcher::new(ID_STRINGS[i].as_bytes());

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::bus::*; use arm7tdmi::memory::{Addr, BusIO, DebugRead};
pub mod header; pub mod header;
use header::CartridgeHeader; 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 { fn read_8(&mut self, addr: Addr) -> u8 {
let offset = (addr & 0x01ff_ffff) as usize; let offset = (addr & 0x01ff_ffff) as usize;
match addr & 0xff000000 { match addr & 0xff000000 {

View file

@ -397,8 +397,8 @@ mod tests {
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use super::super::bus::Bus; use crate::cartridge::GamepakBuilder;
use super::super::cartridge::GamepakBuilder; use arm7tdmi::memory::BusIO;
struct DummyInterface {} struct DummyInterface {}

View file

@ -6,9 +6,9 @@ use std::rc::Rc;
use num::FromPrimitive; use num::FromPrimitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use arm7tdmi::memory::{Addr, BusIO, DebugRead};
use rustboyadvance_utils::index2d; use rustboyadvance_utils::index2d;
use super::bus::*;
use super::dma::{DmaNotifer, TIMING_HBLANK, TIMING_VBLANK}; use super::dma::{DmaNotifer, TIMING_HBLANK, TIMING_VBLANK};
use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags}; use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags};
use super::sched::{EventType, FutureEvent, GpuEvent, Scheduler}; 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 { fn read_8(&mut self, addr: Addr) -> u8 {
let page = (addr >> 24) as usize; let page = (addr >> 24) as usize;
match page { match page {

View file

@ -1,6 +1,7 @@
use std::cmp; use std::cmp;
use super::bus::*; use arm7tdmi::memory::{Addr, BusIO, DebugRead};
use super::dma::DmaController; use super::dma::DmaController;
use super::gpu::regs::GpuMemoryMappedIO; use super::gpu::regs::GpuMemoryMappedIO;
use super::gpu::regs::WindowFlags; 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 { fn read_16(&mut self, addr: Addr) -> u16 {
let io = self; let io = self;
let io_addr = addr + IO_BASE; let io_addr = addr + IO_BASE;

View file

@ -10,7 +10,6 @@ extern crate debug_stub_derive;
#[macro_use] #[macro_use]
extern crate enum_primitive_derive; extern crate enum_primitive_derive;
#[macro_use] #[macro_use]
extern crate bitfield; extern crate bitfield;
#[macro_use] #[macro_use]
@ -27,8 +26,6 @@ extern crate smart_default;
extern crate cfg_if; extern crate cfg_if;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;

View file

@ -1,8 +1,9 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::arm7tdmi::memory::*; use super::arm7tdmi::memory::{
Addr, BusIO, DebugRead, MemoryAccess, MemoryAccessWidth, MemoryInterface,
};
use super::bios::Bios; use super::bios::Bios;
use super::bus::*;
use super::cartridge::Cartridge; use super::cartridge::Cartridge;
use super::dma::DmaNotifer; use super::dma::DmaNotifer;
use super::iodev::{IoDevices, WaitControl}; use super::iodev::{IoDevices, WaitControl};
@ -305,7 +306,7 @@ impl SysBus {
} }
/// Todo - implement bound checks for EWRAM/IWRAM /// Todo - implement bound checks for EWRAM/IWRAM
impl Bus for SysBus { impl BusIO for SysBus {
#[inline] #[inline]
fn read_32(&mut self, addr: Addr) -> u32 { fn read_32(&mut self, addr: Addr) -> u32 {
match addr & 0xff000000 { match addr & 0xff000000 {