Refactor Bus traits into the arm7tdmi crate
Former-commit-id: 0027611bd4c777dcb7a4d3de6b0cc90cd649faa8 Former-commit-id: 41e30b29f97aee9e5d256a4f8d0c92ac1c761ac7
This commit is contained in:
parent
716a4d11ae
commit
a289900f6a
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
|
||||||
|
#[repr(transparent)]
|
||||||
pub struct RegPSR {
|
pub struct RegPSR {
|
||||||
raw: u32,
|
raw: u32,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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 => {
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Reference in a new issue