chore: Refactor into crates

Been wanting to do this for a long time.
This does impose performance issues when building with the vanilla
release profile, as cargo does not perform optimizations across crate
boundary (we care mostly about inlining).
so I added release-lto profile

Also fixed some broken stuff I found across the project, meh


Former-commit-id: 06d03263cc6245313f3ea22c715479ab6da7c4d4
Former-commit-id: f93abd10c67ea8a3b8072b47462be5eca4f3e02b
This commit is contained in:
Michel Heily 2022-09-04 23:54:44 +03:00
parent 1535062e6c
commit 28fb9ffa70
36 changed files with 225 additions and 147 deletions

29
Cargo.lock generated
View file

@ -69,6 +69,22 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "arm7tdmi"
version = "0.1.0"
dependencies = [
"ansi_term 0.12.1",
"bit",
"byteorder",
"cfg-if 1.0.0",
"colored",
"enum-primitive-derive",
"num 0.2.1",
"num-traits 0.2.12",
"rustboyadvance-utils",
"serde",
]
[[package]] [[package]]
name = "arrayref" name = "arrayref"
version = "0.3.6" version = "0.3.6"
@ -1351,6 +1367,7 @@ name = "rustboyadvance-core"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"arm7tdmi",
"arrayvec 0.5.2", "arrayvec 0.5.2",
"bincode", "bincode",
"bit", "bit",
@ -1371,14 +1388,13 @@ dependencies = [
"goblin", "goblin",
"hex-literal", "hex-literal",
"hexdump", "hexdump",
"instant",
"lazy_static 1.4.0", "lazy_static 1.4.0",
"log 0.4.11", "log 0.4.11",
"memmem", "memmem",
"nom", "nom",
"num 0.2.1", "num 0.2.1",
"num-traits 0.2.12", "num-traits 0.2.12",
"ringbuf", "rustboyadvance-utils",
"rustyline", "rustyline",
"serde", "serde",
"sha2", "sha2",
@ -1433,11 +1449,20 @@ dependencies = [
"log 0.4.11", "log 0.4.11",
"ringbuf", "ringbuf",
"rustboyadvance-core", "rustboyadvance-core",
"rustboyadvance-utils",
"sdl2 0.33.0", "sdl2 0.33.0",
"spin_sleep", "spin_sleep",
"winres", "winres",
] ]
[[package]]
name = "rustboyadvance-utils"
version = "0.1.0"
dependencies = [
"instant",
"ringbuf",
]
[[package]] [[package]]
name = "rustboyadvance-wasm" name = "rustboyadvance-wasm"
version = "0.1.0" version = "0.1.0"

View file

@ -1,6 +1,8 @@
[workspace] [workspace]
members = [ members = [
"core", "core",
"arm7tdmi",
"utils",
"platform/rustboyadvance-sdl2", "platform/rustboyadvance-sdl2",
"platform/rustboyadvance-libretro", "platform/rustboyadvance-libretro",
"platform/rustboyadvance-minifb", "platform/rustboyadvance-minifb",

21
arm7tdmi/Cargo.toml Normal file
View file

@ -0,0 +1,21 @@
[package]
name = "arm7tdmi"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rustboyadvance-utils = {"path" = "../utils" }
bit = "^0.1"
cfg-if = "1.0.0"
serde = { version = "1.0.104", features = ["derive", "rc"] }
ansi_term = "0.12.1"
colored = "1.9"
byteorder = "1"
num = "0.2.1"
num-traits = "0.2"
enum-primitive-derive = "^0.1"
[build-dependencies]
bit = "^0.1"

View file

@ -1,3 +1,4 @@
/// This build script creates ARM_LUT and THUMB_LUT opcode lookup table used cpu.rs
use std::env; use std::env;
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
@ -6,7 +7,7 @@ use std::path::Path;
extern crate bit; extern crate bit;
use bit::BitIndex; use bit::BitIndex;
// copied and slightly adjusted from src/core/arm7tdmi/thumb/mod.rs // copied and slightly adjusted from arm7tdmi/thumb/mod.rs
fn thumb_decode(i: u16) -> (&'static str, String) { fn thumb_decode(i: u16) -> (&'static str, String) {
let offset5 = i.bit_range(6..11) as u8; let offset5 = i.bit_range(6..11) as u8;
let load = i.bit(11); let load = i.bit(11);
@ -180,7 +181,7 @@ trait BitAsInt<T: From<bool>>: BitIndex {
impl BitAsInt<u32> for u32 {} impl BitAsInt<u32> for u32 {}
/// Returns a string representation of rustboyadvance_ng::core::arm7tdmi::arm::ArmFormat enum member /// Returns a string representation of arm7tdmi::arm::ArmFormat enum member
/// # Arguments /// # Arguments
/// * `i` - A 32bit ARM instruction /// * `i` - A 32bit ARM instruction
/// ///
@ -368,7 +369,7 @@ fn arm_decode(i: u32) -> (&'static str, String) {
} }
fn generate_thumb_lut(file: &mut fs::File) -> Result<(), std::io::Error> { fn generate_thumb_lut(file: &mut fs::File) -> Result<(), std::io::Error> {
writeln!(file, "impl<I: MemoryInterface> Core<I> {{")?; writeln!(file, "impl<I: MemoryInterface> Arm7tdmiCore<I> {{")?;
writeln!( writeln!(
file, file,
" pub const THUMB_LUT: [ThumbInstructionInfo<I>; 1024] = [" " pub const THUMB_LUT: [ThumbInstructionInfo<I>; 1024] = ["
@ -380,7 +381,7 @@ fn generate_thumb_lut(file: &mut fs::File) -> Result<(), std::io::Error> {
file, file,
" /* {:#x} */ " /* {:#x} */
ThumbInstructionInfo {{ ThumbInstructionInfo {{
handler_fn: Core::{}, handler_fn: Arm7tdmiCore::{},
#[cfg(feature = \"debugger\")] #[cfg(feature = \"debugger\")]
fmt: ThumbFormat::{}, fmt: ThumbFormat::{},
}},", }},",
@ -395,7 +396,7 @@ fn generate_thumb_lut(file: &mut fs::File) -> Result<(), std::io::Error> {
} }
fn generate_arm_lut(file: &mut fs::File) -> Result<(), std::io::Error> { fn generate_arm_lut(file: &mut fs::File) -> Result<(), std::io::Error> {
writeln!(file, "impl<I: MemoryInterface> Core<I> {{")?; writeln!(file, "impl<I: MemoryInterface> Arm7tdmiCore<I> {{")?;
writeln!( writeln!(
file, file,
" pub const ARM_LUT: [ArmInstructionInfo<I>; 4096] = [" " pub const ARM_LUT: [ArmInstructionInfo<I>; 4096] = ["
@ -406,7 +407,7 @@ fn generate_arm_lut(file: &mut fs::File) -> Result<(), std::io::Error> {
file, file,
" /* {:#x} */ " /* {:#x} */
ArmInstructionInfo {{ ArmInstructionInfo {{
handler_fn: Core::{}, handler_fn: Arm7tdmiCore::{},
#[cfg(feature = \"debugger\")] #[cfg(feature = \"debugger\")]
fmt: ArmFormat::{}, fmt: ArmFormat::{},
}} ,", }} ,",

View file

@ -1,7 +1,6 @@
use bit::BitIndex; use bit::BitIndex;
use super::memory::MemoryInterface; use crate::{memory::MemoryInterface, registers_consts::REG_PC, Arm7tdmiCore};
use super::{Core, REG_PC};
#[derive(Debug, Primitive, Eq, PartialEq)] #[derive(Debug, Primitive, Eq, PartialEq)]
pub enum AluOpCode { pub enum AluOpCode {
@ -110,7 +109,7 @@ impl BarrelShifterValue {
} }
} }
impl<I: MemoryInterface> Core<I> { impl<I: MemoryInterface> Arm7tdmiCore<I> {
pub fn lsl(&mut self, val: u32, amount: u32, carry: &mut bool) -> u32 { pub fn lsl(&mut self, val: u32, amount: u32, carry: &mut bool) -> u32 {
match amount { match amount {
0 => val, 0 => val,

View file

@ -1,17 +1,19 @@
use crate::bit::BitIndex; use crate::bit::BitIndex;
use super::super::alu::*; use crate::{
use crate::arm7tdmi::psr::RegPSR; alu::*,
use crate::arm7tdmi::CpuAction; memory::{MemoryAccess, MemoryInterface},
use crate::arm7tdmi::{Addr, Core, CpuMode, CpuState, REG_LR, REG_PC}; psr::RegPSR,
registers_consts::{REG_LR, REG_PC},
Arm7tdmiCore, CpuAction, CpuMode, CpuState,
};
use super::super::memory::{MemoryAccess, MemoryInterface};
use MemoryAccess::*; use MemoryAccess::*;
use super::ArmDecodeHelper; use super::ArmDecodeHelper;
use super::*; use super::*;
impl<I: MemoryInterface> Core<I> { impl<I: MemoryInterface> Arm7tdmiCore<I> {
pub fn arm_undefined(&mut self, insn: u32) -> CpuAction { pub fn arm_undefined(&mut self, insn: u32) -> CpuAction {
panic!( panic!(
"executing undefined arm instruction {:08x} at @{:08x}", "executing undefined arm instruction {:08x} at @{:08x}",

View file

@ -5,11 +5,12 @@ pub mod exec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::alu::*; use super::alu::*;
use crate::arm7tdmi::{Addr, InstructionDecoder}; use super::memory::Addr;
use super::InstructionDecoder;
use crate::bit::BitIndex; use bit::BitIndex;
use crate::byteorder::{LittleEndian, ReadBytesExt}; use byteorder::{LittleEndian, ReadBytesExt};
use crate::num::FromPrimitive; use num::FromPrimitive;
use std::io; use std::io;

View file

@ -4,7 +4,7 @@ pub use super::exception::Exception;
use super::{arm::ArmCond, psr::RegPSR, Addr, CpuMode, CpuState}; use super::{arm::ArmCond, psr::RegPSR, Addr, CpuMode, CpuState};
use crate::util::{Shared, WeakPointer}; use rustboyadvance_utils::{Shared, WeakPointer};
use super::memory::{MemoryAccess, MemoryInterface}; use super::memory::{MemoryAccess, MemoryInterface};
use MemoryAccess::*; use MemoryAccess::*;
@ -19,14 +19,14 @@ use super::arm::ArmFormat;
#[cfg_attr(not(feature = "debugger"), repr(transparent))] #[cfg_attr(not(feature = "debugger"), repr(transparent))]
pub struct ThumbInstructionInfo<I: MemoryInterface> { pub struct ThumbInstructionInfo<I: MemoryInterface> {
pub handler_fn: fn(&mut Core<I>, insn: u16) -> CpuAction, pub handler_fn: fn(&mut Arm7tdmiCore<I>, insn: u16) -> CpuAction,
#[cfg(feature = "debugger")] #[cfg(feature = "debugger")]
pub fmt: ThumbFormat, pub fmt: ThumbFormat,
} }
#[cfg_attr(not(feature = "debugger"), repr(transparent))] #[cfg_attr(not(feature = "debugger"), repr(transparent))]
pub struct ArmInstructionInfo<I: MemoryInterface> { pub struct ArmInstructionInfo<I: MemoryInterface> {
pub handler_fn: fn(&mut Core<I>, insn: u32) -> CpuAction, pub handler_fn: fn(&mut Arm7tdmiCore<I>, insn: u32) -> CpuAction,
#[cfg(feature = "debugger")] #[cfg(feature = "debugger")]
pub fmt: ArmFormat, pub fmt: ArmFormat,
} }
@ -104,7 +104,7 @@ impl Default for DebuggerState {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Core<I: MemoryInterface> { pub struct Arm7tdmiCore<I: MemoryInterface> {
pub pc: u32, pub pc: u32,
pub(super) bus: Shared<I>, pub(super) bus: Shared<I>,
@ -121,10 +121,10 @@ pub struct Core<I: MemoryInterface> {
pub dbg: DebuggerState, pub dbg: DebuggerState,
} }
impl<I: MemoryInterface> Core<I> { impl<I: MemoryInterface> Arm7tdmiCore<I> {
pub fn new(bus: Shared<I>) -> Core<I> { pub fn new(bus: Shared<I>) -> Arm7tdmiCore<I> {
let cpsr = RegPSR::new(0x0000_00D3); let cpsr = RegPSR::new(0x0000_00D3);
Core { Arm7tdmiCore {
bus, bus,
pc: 0, pc: 0,
gpr: [0; 15], gpr: [0; 15],
@ -139,12 +139,12 @@ impl<I: MemoryInterface> Core<I> {
} }
} }
pub fn weak_ptr(&mut self) -> WeakPointer<Core<I>> { pub fn weak_ptr(&mut self) -> WeakPointer<Arm7tdmiCore<I>> {
WeakPointer::new(self as *mut Core<I>) WeakPointer::new(self as *mut Arm7tdmiCore<I>)
} }
pub fn from_saved_state(bus: Shared<I>, state: SavedCpuState) -> Core<I> { pub fn from_saved_state(bus: Shared<I>, state: SavedCpuState) -> Arm7tdmiCore<I> {
Core { Arm7tdmiCore {
bus, bus,
pc: state.pc, pc: state.pc,

View file

@ -1,5 +1,5 @@
use super::cpu::Core;
use super::memory::MemoryInterface; use super::memory::MemoryInterface;
use super::Arm7tdmiCore;
use super::{CpuMode, CpuState}; use super::{CpuMode, CpuState};
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
@ -16,7 +16,7 @@ pub enum Exception {
Fiq = 0x1c, Fiq = 0x1c,
} }
impl<I: MemoryInterface> Core<I> { impl<I: MemoryInterface> Arm7tdmiCore<I> {
pub fn exception(&mut self, e: Exception, lr: u32) { pub fn exception(&mut self, e: Exception, lr: u32) {
use Exception::*; use Exception::*;
let (new_mode, irq_disable, fiq_disable) = match e { let (new_mode, irq_disable, fiq_disable) = match e {

View file

@ -1,3 +1,12 @@
#[macro_use]
extern crate serde;
#[macro_use]
extern crate enum_primitive_derive;
use bit;
use num;
use num_traits;
use std::fmt; use std::fmt;
use num::Num; use num::Num;
@ -14,16 +23,17 @@ pub use cpu::*;
pub mod alu; pub mod alu;
pub mod memory; pub mod memory;
pub use alu::*; pub use alu::*;
use memory::Addr;
pub mod exception; pub mod exception;
pub mod psr; pub mod psr;
pub use psr::*; pub use psr::*;
pub mod disass; pub mod disass;
pub mod registers_consts {
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;
}
pub(self) use crate::Addr;
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub enum DecodedInstruction { pub enum DecodedInstruction {

View file

@ -1,7 +1,8 @@
use super::cpu::Core; use super::Arm7tdmiCore;
use super::Addr;
use std::fmt; use std::fmt;
pub type Addr = u32;
#[derive(Serialize, Deserialize, Debug, Copy, Clone)] #[derive(Serialize, Deserialize, Debug, Copy, Clone)]
pub enum MemoryAccess { pub enum MemoryAccess {
NonSeq = 0, NonSeq = 0,
@ -35,7 +36,7 @@ pub enum MemoryAccessWidth {
MemoryAccess32, MemoryAccess32,
} }
/// A trait meant to abstract memory accesses and report the access type back to the user of the arm7tdmi::Core /// A trait meant to abstract memory accesses and report the access type back to the user of the arm7tdmi::Arm7tdmiCore
/// ///
/// struct Memory { /// struct Memory {
/// data: [u8; 0x4000] /// data: [u8; 0x4000]
@ -60,7 +61,7 @@ pub enum MemoryAccessWidth {
/// } /// }
/// ///
/// let mem = Shared::new(Memory { ... }); /// let mem = Shared::new(Memory { ... });
/// let cpu = arm7tdmi::Core::new(mem.clone()) /// let cpu = arm7tdmi::Arm7tdmiCore::new(mem.clone())
/// ///
pub trait MemoryInterface { pub trait MemoryInterface {
/// Read a byte /// Read a byte
@ -80,7 +81,7 @@ pub trait MemoryInterface {
fn idle_cycle(&mut self); fn idle_cycle(&mut self);
} }
impl<I: MemoryInterface> MemoryInterface for Core<I> { impl<I: MemoryInterface> MemoryInterface for Arm7tdmiCore<I> {
#[inline] #[inline]
fn load_8(&mut self, addr: u32, access: MemoryAccess) -> u8 { fn load_8(&mut self, addr: u32, access: MemoryAccess) -> u8 {
self.bus.load_8(addr, access) self.bus.load_8(addr, access)
@ -117,7 +118,7 @@ impl<I: MemoryInterface> MemoryInterface for Core<I> {
} }
/// Implementation of memory access helpers /// Implementation of memory access helpers
impl<I: MemoryInterface> Core<I> { impl<I: MemoryInterface> Arm7tdmiCore<I> {
#[inline] #[inline]
pub(super) fn store_aligned_32(&mut self, addr: Addr, value: u32, access: MemoryAccess) { pub(super) fn store_aligned_32(&mut self, addr: Addr, value: u32, access: MemoryAccess) {
self.store_32(addr & !0x3, value, access); self.store_32(addr & !0x3, value, access);

View file

@ -1,13 +1,17 @@
use crate::arm7tdmi::*; use crate::{
exception::Exception,
memory::{MemoryAccess, MemoryInterface},
registers_consts::*,
Arm7tdmiCore, CpuAction,
};
use crate::bit::BitIndex; use bit::BitIndex;
use super::super::memory::{MemoryAccess, MemoryInterface};
use super::ThumbDecodeHelper; use super::ThumbDecodeHelper;
use super::*; use super::*;
use MemoryAccess::*; use MemoryAccess::*;
impl<I: MemoryInterface> Core<I> { impl<I: MemoryInterface> Arm7tdmiCore<I> {
/// Format 1 /// Format 1
/// Execution Time: 1S /// Execution Time: 1S
pub(in super::super) fn exec_thumb_move_shifted_reg<const BS_OP: u8, const IMM: u8>( pub(in super::super) fn exec_thumb_move_shifted_reg<const BS_OP: u8, const IMM: u8>(

View file

@ -1,9 +1,10 @@
use super::alu::*; use super::alu::*;
use super::arm::*; use super::arm::*;
use super::{Addr, InstructionDecoder}; use super::memory::Addr;
use crate::bit::BitIndex; use super::InstructionDecoder;
use crate::byteorder::{LittleEndian, ReadBytesExt}; use bit::BitIndex;
use crate::num::FromPrimitive; use byteorder::{LittleEndian, ReadBytesExt};
use num::FromPrimitive;
#[cfg(feature = "debugger")] #[cfg(feature = "debugger")]
pub mod disass; pub mod disass;

View file

@ -5,6 +5,8 @@ authors = ["Michel Heily <michelheily@gmail.com>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
arm7tdmi = { "path" = "../arm7tdmi" }
rustboyadvance-utils = { "path" = "../utils" }
cfg-if = "1.0.0" cfg-if = "1.0.0"
serde = { version = "1.0.104", features = ["derive", "rc"] } serde = { version = "1.0.104", features = ["derive", "rc"] }
bincode = "1.2.1" bincode = "1.2.1"
@ -35,7 +37,6 @@ hex-literal = "0.2.1"
rustyline = { version = "6.0.0", optional = true } rustyline = { version = "6.0.0", optional = true }
nom = { version = "5.0.0", optional = true } nom = { version = "5.0.0", optional = true }
gdbstub = { version = "0.1.2", optional = true, features = ["std"] } gdbstub = { version = "0.1.2", optional = true, features = ["std"] }
ringbuf = "0.2.2"
goblin = { version = "0.2", optional = true } goblin = { version = "0.2", optional = true }
fuzzy-matcher = { version = "0.3.4", optional = true } fuzzy-matcher = { version = "0.3.4", optional = true }
bit_reverse = "0.1.8" bit_reverse = "0.1.8"
@ -43,12 +44,6 @@ yaml-rust = "0.4"
lazy_static = "1.4.0" lazy_static = "1.4.0"
smart-default = "0.6.0" smart-default = "0.6.0"
[target.'cfg(target_arch="wasm32")'.dependencies]
instant = { version = "0.1.2", features = ["wasm-bindgen"] }
[build-dependencies]
bit = "^0.1"
[dev-dependencies] [dev-dependencies]
criterion = "0.3" criterion = "0.3"

View file

@ -1,7 +1,8 @@
use super::arm7tdmi; use super::bus::{Bus, DebugRead};
use super::bus::{Addr, Bus, DebugRead};
use super::util::WeakPointer;
use super::SysBus; use super::SysBus;
use arm7tdmi::{memory::Addr, Arm7tdmiCore};
use rustboyadvance_utils::WeakPointer;
/// Struct representing the sytem ROM /// Struct representing the sytem ROM
#[derive(Clone)] #[derive(Clone)]
@ -11,7 +12,7 @@ pub struct Bios {
/// Last read value /// Last read value
last_opcode: u32, last_opcode: u32,
/// Arm pointer - used only to read the PC register /// Arm pointer - used only to read the PC register
arm_core: WeakPointer<arm7tdmi::Core<SysBus>>, arm_core: WeakPointer<Arm7tdmiCore<SysBus>>,
} }
impl Bios { impl Bios {
@ -23,7 +24,7 @@ impl Bios {
} }
} }
pub(super) fn connect_arm_core(&mut self, arm_ptr: WeakPointer<arm7tdmi::Core<SysBus>>) { pub(super) fn connect_arm_core(&mut self, arm_ptr: WeakPointer<Arm7tdmiCore<SysBus>>) {
self.arm_core = arm_ptr; self.arm_core = arm_ptr;
} }

View file

@ -1,4 +1,4 @@
pub type Addr = u32; pub use arm7tdmi::memory::Addr; // re-export
pub trait Bus { pub trait Bus {
fn read_32(&mut self, addr: Addr) -> u32 { fn read_32(&mut self, addr: Addr) -> u32 {

View file

@ -8,7 +8,7 @@ use serde::de::{self, Deserialize, Deserializer, SeqAccess, Visitor};
use serde::ser::{Serialize, SerializeStruct, Serializer}; use serde::ser::{Serialize, SerializeStruct, Serializer};
use super::BackupMemoryInterface; use super::BackupMemoryInterface;
use crate::util::write_bin_file; use rustboyadvance_utils::write_bin_file;
#[derive(Debug)] #[derive(Debug)]
pub struct BackupFile { pub struct BackupFile {

View file

@ -6,7 +6,7 @@ use std::io::prelude::*;
use std::io::Cursor; use std::io::Cursor;
use std::path::Path; use std::path::Path;
use crate::util::read_bin_file; use rustboyadvance_utils::read_bin_file;
use zip::ZipArchive; use zip::ZipArchive;
#[cfg(feature = "elf_support")] #[cfg(feature = "elf_support")]

View file

@ -7,7 +7,7 @@ use crate::arm7tdmi::thumb::ThumbInstruction;
use crate::arm7tdmi::CpuState; use crate::arm7tdmi::CpuState;
use crate::bus::{Addr, Bus, DebugRead}; use crate::bus::{Addr, Bus, DebugRead};
use crate::disass::Disassembler; use crate::disass::Disassembler;
use crate::util::{read_bin_file, write_bin_file}; use rustboyadvance_utils::{read_bin_file, write_bin_file};
// use super::palette_view::create_palette_view; // use super::palette_view::create_palette_view;
// use super::tile_view::create_tile_view; // use super::tile_view::create_tile_view;

View file

@ -5,7 +5,6 @@ use std::rc::Rc;
use bincode; use bincode;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::arm7tdmi;
use super::cartridge::Cartridge; use super::cartridge::Cartridge;
use super::dma::DmaController; use super::dma::DmaController;
use super::gpu::*; use super::gpu::*;
@ -15,14 +14,16 @@ use super::sched::{EventType, Scheduler, SchedulerConnect, SharedScheduler};
use super::sound::SoundController; use super::sound::SoundController;
use super::sysbus::SysBus; use super::sysbus::SysBus;
use super::timer::Timers; use super::timer::Timers;
use super::util::Shared;
#[cfg(not(feature = "no_video_interface"))] #[cfg(not(feature = "no_video_interface"))]
use super::VideoInterface; use super::VideoInterface;
use super::{AudioInterface, InputInterface}; use super::{AudioInterface, InputInterface};
use arm7tdmi::{self, Arm7tdmiCore};
use rustboyadvance_utils::Shared;
pub struct GameBoyAdvance { pub struct GameBoyAdvance {
pub cpu: Box<arm7tdmi::Core<SysBus>>, pub cpu: Box<Arm7tdmiCore<SysBus>>,
pub sysbus: Shared<SysBus>, pub sysbus: Shared<SysBus>,
pub io_devs: Shared<IoDevices>, pub io_devs: Shared<IoDevices>,
pub scheduler: SharedScheduler, pub scheduler: SharedScheduler,
@ -103,7 +104,7 @@ impl GameBoyAdvance {
gamepak, gamepak,
)); ));
let cpu = Box::new(arm7tdmi::Core::new(sysbus.clone())); let cpu = Box::new(Arm7tdmiCore::new(sysbus.clone()));
let mut gba = GameBoyAdvance { let mut gba = GameBoyAdvance {
cpu, cpu,
@ -150,7 +151,7 @@ impl GameBoyAdvance {
decoded.ewram, decoded.ewram,
decoded.iwram, decoded.iwram,
)); ));
let mut arm7tdmi = Box::new(arm7tdmi::Core::from_saved_state( let mut arm7tdmi = Box::new(Arm7tdmiCore::from_saved_state(
sysbus.clone(), sysbus.clone(),
decoded.cpu_state, decoded.cpu_state,
)); ));

View file

@ -10,6 +10,44 @@ use gdbstub::{Access, Target, TargetState};
use std::io::Cursor; use std::io::Cursor;
use gdbstub;
use gdbstub::GdbStub;
use std::fmt;
use std::net::TcpListener;
use std::net::ToSocketAddrs;
pub fn spawn_and_run_gdb_server<A: ToSocketAddrs + fmt::Display>(
#[allow(unused)] target: &mut GameBoyAdvance,
#[allow(unused)] addr: A,
) -> Result<(), Box<dyn std::error::Error>> {
#[cfg(feature = "gdb")]
{
info!("spawning gdbserver, listening on {}", addr);
let sock = TcpListener::bind(addr)?;
let (stream, addr) = sock.accept()?;
info!("got connection from {}", addr);
let mut gdb = GdbStub::new(stream);
let result = match gdb.run(target) {
Ok(state) => {
info!("Disconnected from GDB. Target state: {:?}", state);
Ok(())
}
Err(gdbstub::Error::TargetError(e)) => Err(e),
Err(e) => return Err(e.into()),
};
info!("Debugger session ended, result={:?}", result);
}
#[cfg(not(feature = "gdb"))]
{
error!("failed. please compile me with 'gdb' feature")
}
Ok(())
}
impl Target for GameBoyAdvance { impl Target for GameBoyAdvance {
type Usize = u32; type Usize = u32;
type Error = (); type Error = ();

View file

@ -3,8 +3,11 @@ use std::cell::RefCell;
#[cfg(not(feature = "no_video_interface"))] #[cfg(not(feature = "no_video_interface"))]
use std::rc::Rc; use std::rc::Rc;
use num::FromPrimitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use rustboyadvance_utils::index2d;
use super::bus::*; 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};
@ -13,8 +16,6 @@ pub use super::sysbus::consts::*;
#[cfg(not(feature = "no_video_interface"))] #[cfg(not(feature = "no_video_interface"))]
use super::VideoInterface; use super::VideoInterface;
use crate::num::FromPrimitive;
mod render; mod render;
use render::Point; use render::Point;

View file

@ -7,6 +7,7 @@ use super::super::Rgb15;
use super::{utils, MODE5_VIEWPORT, SCREEN_VIEWPORT}; use super::{utils, MODE5_VIEWPORT, SCREEN_VIEWPORT};
use crate::Bus; use crate::Bus;
use rustboyadvance_utils::index2d;
impl Gpu { impl Gpu {
pub(in super::super) fn render_mode3(&mut self, bg: usize) { pub(in super::super) fn render_mode3(&mut self, bg: usize) {

View file

@ -1,6 +1,8 @@
use super::super::regs::*; use super::super::regs::*;
use super::super::*; use super::super::*;
use rustboyadvance_utils::index2d;
const OVRAM: u32 = 0x0601_0000; const OVRAM: u32 = 0x0601_0000;
const PALRAM_OFS_FG: u32 = 0x200; const PALRAM_OFS_FG: u32 = 0x200;
const ATTRS_SIZE: u32 = 2 * 3 + 2; const ATTRS_SIZE: u32 = 2 * 3 + 2;

View file

@ -7,6 +7,8 @@ use super::{utils, ViewPort};
use crate::Bus; use crate::Bus;
use rustboyadvance_utils::index2d;
impl Gpu { impl Gpu {
pub(in super::super) fn render_reg_bg(&mut self, bg: usize) { pub(in super::super) fn render_reg_bg(&mut self, bg: usize) {
let (h_ofs, v_ofs) = (self.bg_hofs[bg] as u32, self.bg_vofs[bg] as u32); let (h_ofs, v_ofs) = (self.bg_hofs[bg] as u32, self.bg_vofs[bg] as u32);

View file

@ -9,17 +9,13 @@ extern crate debug_stub_derive;
#[macro_use] #[macro_use]
extern crate enum_primitive_derive; extern crate enum_primitive_derive;
use num;
use num_traits; use num_traits;
use bit;
#[macro_use] #[macro_use]
extern crate bitfield; extern crate bitfield;
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
use byteorder;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
@ -36,9 +32,7 @@ use zip;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
#[macro_use] pub use arm7tdmi;
pub mod util;
pub mod arm7tdmi;
pub use arm7tdmi::disass; pub use arm7tdmi::disass;
mod bios; mod bios;
pub mod cartridge; pub mod cartridge;
@ -140,10 +134,10 @@ pub mod prelude {
#[cfg(feature = "debugger")] #[cfg(feature = "debugger")]
pub use super::debugger::Debugger; pub use super::debugger::Debugger;
pub use super::gpu::{DISPLAY_HEIGHT, DISPLAY_WIDTH}; pub use super::gpu::{DISPLAY_HEIGHT, DISPLAY_WIDTH};
pub use super::util::{read_bin_file, write_bin_file};
pub use super::Bus; pub use super::Bus;
#[cfg(not(feature = "no_video_interface"))] #[cfg(not(feature = "no_video_interface"))]
pub use super::VideoInterface; pub use super::VideoInterface;
pub use super::{AudioInterface, InputInterface, StereoSample}; pub use super::{AudioInterface, InputInterface, StereoSample};
pub use super::{GBAError, GBAResult, GameBoyAdvance}; pub use super::{GBAError, GBAResult, GameBoyAdvance};
pub use rustboyadvance_utils::{read_bin_file, write_bin_file};
} }

View file

@ -1,7 +1,7 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::BinaryHeap; use std::collections::BinaryHeap;
use super::util::Shared; use rustboyadvance_utils::Shared;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -271,17 +271,19 @@ mod test {
let mut sched = holder.sched.clone(); let mut sched = holder.sched.clone();
holder holder
.sched .sched
.push(EventType::Gpu(GpuEvent::VBlankHDraw), 240); .schedule((EventType::Gpu(GpuEvent::VBlankHDraw), 240));
holder holder
.sched .sched
.push(EventType::Apu(ApuEvent::Psg1Generate), 60); .schedule((EventType::Apu(ApuEvent::Psg1Generate), 60));
holder.sched.push(EventType::Apu(ApuEvent::Sample), 512);
holder holder
.sched .sched
.push(EventType::Apu(ApuEvent::Psg2Generate), 13); .schedule((EventType::Apu(ApuEvent::Sample), 512));
holder holder
.sched .sched
.push(EventType::Apu(ApuEvent::Psg4Generate), 72); .schedule((EventType::Apu(ApuEvent::Psg2Generate), 13));
holder
.sched
.schedule((EventType::Apu(ApuEvent::Psg4Generate), 72));
assert_eq!( assert_eq!(
sched.events.pop(), sched.events.pop(),
@ -300,17 +302,19 @@ mod test {
let mut sched = holder.sched.clone(); let mut sched = holder.sched.clone();
holder holder
.sched .sched
.push(EventType::Gpu(GpuEvent::VBlankHDraw), 240); .schedule((EventType::Gpu(GpuEvent::VBlankHDraw), 240));
holder holder
.sched .sched
.push(EventType::Apu(ApuEvent::Psg1Generate), 60); .schedule((EventType::Apu(ApuEvent::Psg1Generate), 60));
holder.sched.push(EventType::Apu(ApuEvent::Sample), 512);
holder holder
.sched .sched
.push(EventType::Apu(ApuEvent::Psg2Generate), 13); .schedule((EventType::Apu(ApuEvent::Sample), 512));
holder holder
.sched .sched
.push(EventType::Apu(ApuEvent::Psg4Generate), 72); .schedule((EventType::Apu(ApuEvent::Psg2Generate), 13));
holder
.sched
.schedule((EventType::Apu(ApuEvent::Psg4Generate), 72));
println!("all events"); println!("all events");
for e in sched.events.iter() { for e in sched.events.iter() {

View file

@ -1,6 +1,5 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::arm7tdmi;
use super::arm7tdmi::memory::*; use super::arm7tdmi::memory::*;
use super::bios::Bios; use super::bios::Bios;
use super::bus::*; use super::bus::*;
@ -8,7 +7,8 @@ use super::cartridge::Cartridge;
use super::dma::DmaNotifer; use super::dma::DmaNotifer;
use super::iodev::{IoDevices, WaitControl}; use super::iodev::{IoDevices, WaitControl};
use super::sched::*; use super::sched::*;
use super::util::{Shared, WeakPointer}; use arm7tdmi::{self, Arm7tdmiCore};
use rustboyadvance_utils::{Shared, WeakPointer};
pub mod consts { pub mod consts {
pub const WORK_RAM_SIZE: usize = 256 * 1024; pub const WORK_RAM_SIZE: usize = 256 * 1024;
@ -145,7 +145,7 @@ impl CycleLookupTables {
pub struct SysBus { pub struct SysBus {
pub io: Shared<IoDevices>, pub io: Shared<IoDevices>,
scheduler: Shared<Scheduler>, scheduler: Shared<Scheduler>,
arm_core: WeakPointer<arm7tdmi::Core<SysBus>>, arm_core: WeakPointer<Arm7tdmiCore<SysBus>>,
bios: Bios, bios: Bios,
ewram: Box<[u8]>, ewram: Box<[u8]>,
@ -225,7 +225,7 @@ impl SysBus {
} }
/// must be called whenever this object is instanciated /// must be called whenever this object is instanciated
pub fn init(&mut self, arm_core: WeakPointer<arm7tdmi::Core<SysBus>>) { pub fn init(&mut self, arm_core: WeakPointer<Arm7tdmiCore<SysBus>>) {
self.arm_core = arm_core.clone(); self.arm_core = arm_core.clone();
self.bios.connect_arm_core(arm_core.clone()); self.bios.connect_arm_core(arm_core.clone());
let ptr = SysBusPtr::new(self as *mut SysBus); let ptr = SysBusPtr::new(self as *mut SysBus);
@ -268,10 +268,9 @@ impl SysBus {
/// `addr` is considered to be an address of /// `addr` is considered to be an address of
fn read_invalid(&mut self, addr: Addr) -> u32 { fn read_invalid(&mut self, addr: Addr) -> u32 {
warn!("invalid read @{:08x}", addr); warn!("invalid read @{:08x}", addr);
use super::arm7tdmi::CpuState;
let value = match self.arm_core.cpsr.state() { let value = match self.arm_core.cpsr.state() {
CpuState::ARM => self.arm_core.get_prefetched_opcode(), arm7tdmi::CpuState::ARM => self.arm_core.get_prefetched_opcode(),
CpuState::THUMB => { arm7tdmi::CpuState::THUMB => {
// For THUMB code the result consists of two 16bit fragments and depends on the address area // For THUMB code the result consists of two 16bit fragments and depends on the address area
// and alignment where the opcode was stored. // and alignment where the opcode was stored.

View file

@ -6,6 +6,7 @@ edition = "2018"
[dependencies] [dependencies]
rustboyadvance-core = { path = "../../core/", features = ["elf_support"] } rustboyadvance-core = { path = "../../core/", features = ["elf_support"] }
rustboyadvance-utils = { path = "../../utils/" }
sdl2 = { version = "0.33.0", features = ["image"] } sdl2 = { version = "0.33.0", features = ["image"] }
ringbuf = "0.2.2" ringbuf = "0.2.2"
bytesize = "1.0.0" bytesize = "1.0.0"

View file

@ -41,9 +41,11 @@ use input::create_input;
use video::{create_video_interface, SCREEN_HEIGHT, SCREEN_WIDTH}; use video::{create_video_interface, SCREEN_HEIGHT, SCREEN_WIDTH};
use rustboyadvance_core::cartridge::BackupType; use rustboyadvance_core::cartridge::BackupType;
#[cfg(feature = "gdb")]
use rustboyadvance_core::gdb::spawn_and_run_gdb_server;
use rustboyadvance_core::prelude::*; use rustboyadvance_core::prelude::*;
use rustboyadvance_core::util::spawn_and_run_gdb_server;
use rustboyadvance_core::util::FpsCounter; use rustboyadvance_utils::FpsCounter;
const LOG_DIR: &str = ".logs"; const LOG_DIR: &str = ".logs";
const DEFAULT_GDB_SERVER_ADDR: &'static str = "localhost:1337"; const DEFAULT_GDB_SERVER_ADDR: &'static str = "localhost:1337";
@ -237,6 +239,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
} }
#[cfg(feature = "gdb")]
if with_gdbserver { if with_gdbserver {
spawn_and_run_gdb_server(&mut gba, DEFAULT_GDB_SERVER_ADDR)?; spawn_and_run_gdb_server(&mut gba, DEFAULT_GDB_SERVER_ADDR)?;
} }

12
utils/Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "rustboyadvance-utils"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ringbuf = "0.2.2"
[target.'cfg(target_arch="wasm32")'.dependencies]
instant = { version = "0.1.2", features = ["wasm-bindgen"] }

View file

@ -22,49 +22,6 @@ fn now() -> Instant {
instant::Instant::now() instant::Instant::now()
} }
use crate::GameBoyAdvance;
#[cfg(feature = "gdb")]
use gdbstub;
#[cfg(feature = "gdb")]
use gdbstub::GdbStub;
use std::fmt;
#[cfg(feature = "gdb")]
use std::net::TcpListener;
use std::net::ToSocketAddrs;
pub fn spawn_and_run_gdb_server<A: ToSocketAddrs + fmt::Display>(
#[allow(unused)] target: &mut GameBoyAdvance,
#[allow(unused)] addr: A,
) -> Result<(), Box<dyn std::error::Error>> {
#[cfg(feature = "gdb")]
{
info!("spawning gdbserver, listening on {}", addr);
let sock = TcpListener::bind(addr)?;
let (stream, addr) = sock.accept()?;
info!("got connection from {}", addr);
let mut gdb = GdbStub::new(stream);
let result = match gdb.run(target) {
Ok(state) => {
info!("Disconnected from GDB. Target state: {:?}", state);
Ok(())
}
Err(gdbstub::Error::TargetError(e)) => Err(e),
Err(e) => return Err(e.into()),
};
info!("Debugger session ended, result={:?}", result);
}
#[cfg(not(feature = "gdb"))]
{
error!("failed. please compile me with 'gdb' feature")
}
Ok(())
}
pub fn read_bin_file(filename: &Path) -> io::Result<Vec<u8>> { pub fn read_bin_file(filename: &Path) -> io::Result<Vec<u8>> {
let mut buf = Vec::new(); let mut buf = Vec::new();
let mut file = File::open(filename)?; let mut file = File::open(filename)?;