diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..67fe5ea --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/gba-suite"] + path = external/gba-suite + url = https://github.com/jsmolka/gba-suite.git diff --git a/README.md b/README.md index 4613ab6..aa5c427 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,12 @@ crashes when entering in-game menu, other than that works fine. ![Pokemon Emerald](media/screenshot1.png) ![Kirby - Nightmare in Dreamland](media/screenshot2.png) ![Dragon Ball - Legacy of Goku 2](media/screenshot3.png) -# Links +# Links and attribution - [ARM7TDMI Technical Reference Manual](http://infocenter.arm.com/help/topic/com.arm.doc.ddi0210c/DDI0210B.pdf) Technical Reference Manuals are **fun**. - [GBATEK](http://problemkaputt.de/gbatek.htm) - A single webpage written by *no$gba* developer Martin Korth. + A single webpage written by *no$gba* developer Martin Korth. This page has pretty much everything. Seriously, it's the best. - [TONC](https://www.coranac.com/tonc/text/) A comprehensive GBA dev guide that I used a-lot in order to understand the GBA system. @@ -71,5 +71,5 @@ crashes when entering in-game menu, other than that works fine. - [NanoboyAdvance](https://github.com/fleroviux/NanoboyAdvance) A GameBoy Advance emulator written in C++17 by a nice person called fleroviux. I've used this for debugging. -- [Eggvance](https://github.com/jsmolka/eggvance/tree/master/tests) - A GameBoy Advance emulator written in C++, with really useful CPU test roms. \ No newline at end of file +- [Eggvance gba-suite](https://github.com/jsmolka/gba-suite) + Incredible test suite for the arm7tdmi interpreter that I'm using, written by Julian Smolka. \ No newline at end of file diff --git a/external/gba-suite b/external/gba-suite new file mode 160000 index 0000000..854c1fb --- /dev/null +++ b/external/gba-suite @@ -0,0 +1 @@ +Subproject commit 854c1fb3a02fc8d94d04041b2948826708d81011 diff --git a/src/core/cartridge.rs b/src/core/cartridge.rs index 13da096..6579029 100644 --- a/src/core/cartridge.rs +++ b/src/core/cartridge.rs @@ -122,6 +122,15 @@ impl Cartridge { bytes: rom_bin.into_boxed_slice(), }) } + + pub fn from_bytes(bytes: &[u8]) -> Cartridge { + let header = CartridgeHeader::parse(&bytes); + + Cartridge { + header: header, + bytes: bytes.into(), + } + } } impl Bus for Cartridge { diff --git a/src/core/gba.rs b/src/core/gba.rs index a0fec85..a92a288 100644 --- a/src/core/gba.rs +++ b/src/core/gba.rs @@ -182,3 +182,67 @@ impl GameBoyAdvance { io.intc.request_irqs(irqs); } } + +#[cfg(test)] +mod tests { + use super::*; + use std::cell::RefCell; + use std::rc::Rc; + + use super::super::arm7tdmi; + use super::super::cartridge::Cartridge; + + struct DummyInterface {} + + impl DummyInterface { + fn new() -> DummyInterface { + DummyInterface {} + } + } + + impl VideoInterface for DummyInterface {} + impl AudioInterface for DummyInterface {} + impl InputInterface for DummyInterface {} + + fn make_mock_gba(rom: &[u8]) -> GameBoyAdvance { + let bios = vec![0; 0x4000]; + let cpu = arm7tdmi::Core::new(); + let cartridge = Cartridge::from_bytes(rom); + let dummy = Rc::new(RefCell::new(DummyInterface::new())); + let mut gba = GameBoyAdvance::new( + cpu, + bios, + cartridge, + dummy.clone(), + dummy.clone(), + dummy.clone(), + ); + gba.skip_bios(); + + gba + } + + #[test] + fn test_arm7tdmi_arm_eggvance() { + let mut gba = make_mock_gba(include_bytes!("../../external/gba-suite/arm/arm.gba")); + + for _ in 0..10 { + gba.frame(); + } + + assert_eq!(0x080019e0, gba.cpu.pc); + assert_eq!(0, gba.cpu.gpr[12]); + } + + #[test] + fn test_arm7tdmi_thumb_eggvance() { + let mut gba = make_mock_gba(include_bytes!("../../external/gba-suite/thumb/thumb.gba")); + + for _ in 0..10 { + gba.frame(); + } + + assert_eq!(0x800091a, gba.cpu.pc); + assert_eq!(0, gba.cpu.gpr[7]); + } +} diff --git a/src/lib.rs b/src/lib.rs index 307f0a9..0a8d82d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,20 +43,25 @@ pub mod disass; pub mod debugger; pub trait VideoInterface { - fn render(&mut self, buffer: &[u32]); + #[allow(unused_variables)] + fn render(&mut self, buffer: &[u32]) {} } pub type StereoSample = (i16, i16); pub trait AudioInterface { - fn get_sample_rate(&self) -> i32; + fn get_sample_rate(&self) -> i32 { + 44100 + } #[allow(unused_variables)] fn push_sample(&mut self, samples: StereoSample) {} } pub trait InputInterface { - fn poll(&mut self) -> u16; + fn poll(&mut self) -> u16 { + core::keypad::KEYINPUT_ALL_RELEASED + } } pub mod prelude {