diff options
-rw-r--r-- | CHANGELOG.txt | 8 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | README.txt | 1 | ||||
-rw-r--r-- | src/luma.rs | 2 | ||||
-rw-r--r-- | src/luma/application/run.rs | 5 | ||||
-rw-r--r-- | src/luma/device.rs | 22 | ||||
-rw-r--r-- | src/luma/device/branch.rs | 36 | ||||
-rw-r--r-- | src/luma/device/decode.rs | 53 | ||||
-rw-r--r-- | src/luma/device/log.rs | 46 |
9 files changed, 108 insertions, 67 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 17b0e91..9bab8ae 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,11 @@ +# 0.26 + +* Support bx; +* Fix ldr|str; +* Remove logging in release builds; +* Fix version number being in decimal; +* Update readme; + # 0.25 * Support load and store instructions; @@ -1,6 +1,6 @@ [package] name = "luma" -version = "0.37.0" +version = "0.38.0" authors = ["Gabriel Jensen"] edition = "2021" description = "AGB emulator." @@ -47,6 +47,7 @@ Currently, the emulator supports the following ARM instructions only. Others will be skipped. * b{cond}{l} + * bx Rm * ldr{cond} Rn, +/-offset * mov{cond} Rd, Rn * mov{cons}s r15, Rn diff --git a/src/luma.rs b/src/luma.rs index a13c330..316274e 100644 --- a/src/luma.rs +++ b/src/luma.rs @@ -32,7 +32,7 @@ pub struct VersionType<T> { pub const VERSION: VersionType::<u32> = VersionType::<u32> { major: 0x0, - minor: 0x25, + minor: 0x26, }; pub const CONFIGURATION_VERSION: u32 = 0x0; diff --git a/src/luma/application/run.rs b/src/luma/application/run.rs index 14ab560..d4052ad 100644 --- a/src/luma/application/run.rs +++ b/src/luma/application/run.rs @@ -32,7 +32,7 @@ use std::time::Duration; impl Application { pub fn run(&mut self) { eprintln!(); - eprintln!("luma {}.{}", VERSION.major, VERSION.minor); + eprintln!("luma {:X}.{:X}", VERSION.major, VERSION.minor); eprintln!("Copyright 2021-2023 Gabriel Jensen."); eprintln!(); @@ -55,7 +55,8 @@ impl Application { } } - eprintln!("({cycle})"); + if cfg!(debug_assertions) { eprintln!("({cycle})"); } + self.device.decode(); sleep(Duration::from_secs(0x1)); diff --git a/src/luma/device.rs b/src/luma/device.rs index 2a0e503..7b84cf7 100644 --- a/src/luma/device.rs +++ b/src/luma/device.rs @@ -36,24 +36,28 @@ pub mod read; pub mod trap; pub mod write; -#[allow(dead_code)] pub enum Log { - Branch( i32, u32), - Continue( u32), - Link( u32), - Load( u8, u32, u8, i32, u32), - MoveRegister( u8, u8, u32), - MoveImmediate(u8, u32), - Store( u32, u8, u8, i32, u32), + BranchOffset( i32, u32), + BranchRegister(u8, u32), + Continue( u32), + Link( u32), + Load( u8, u32, u8, i32, u32), + MoveRegister( u8, u8, u32), + MoveImmediate( u8, u32), + Store( u32, u8, u8, i32, u32), } -#[allow(dead_code)] pub enum Trap { BadAlignment( u32, u32), InvalidOpcode(u32, u32), OutOfBounds( u32), } +pub enum Branch { + Offset( i32, bool), + Register(u8), +} + pub struct Device { memory: *mut u8, registers: [u32; 0x10], diff --git a/src/luma/device/branch.rs b/src/luma/device/branch.rs index 5654763..13cf895 100644 --- a/src/luma/device/branch.rs +++ b/src/luma/device/branch.rs @@ -21,18 +21,34 @@ see <https://www.gnu.org/licenses/>. */ -use crate::luma::device::{Device, Log}; +use crate::luma::device::{Branch, Device, Log}; impl Device { - pub fn branch(&mut self, offset: i32, l: bool) { - if l { // Check the l flag. - self.registers[0xE] = self.registers[0xF] - 0x4; - - self.log(Log::Link(self.registers[0xE])); + pub fn branch(&mut self, kind: Branch) { + match kind { + Branch::Offset( offset, l) => { + if l { // Check the l flag. + self.registers[0xE] = self.registers[0xF] - 0x4; + + self.log(Log::Link(self.registers[0xE])); + } + + (self.registers[0xF], _) = self.registers[0xF].overflowing_add_signed(offset + 0x8); // Add extra eight to move to the new fetch instruction. + + self.log(Log::BranchOffset(offset, self.registers[0xF] - 0x8)); + }, + Branch::Register(register) => { + let value = self.registers[register as usize]; + + self.cpsr ^= (value & 0b00000000000000000000000000000001) << 0x5; + + let address = value & 0b11111111111111111111111111111110; + self.registers[0xF] = address + 0x8; + + if value & 0b00000000000000000000000000000001 != 0x0 { eprintln!("switching to thumb") } + + self.log(Log::BranchRegister(register, address)); + }, } - - (self.registers[0xF], _) = self.registers[0xF].overflowing_add_signed(offset + 0x8); // Add extra eight to move to the new fetch instruction. - - self.log(Log::Branch(offset, self.registers[0xF] - 0x8)); } } diff --git a/src/luma/device/decode.rs b/src/luma/device/decode.rs index bb31d62..cfd051a 100644 --- a/src/luma/device/decode.rs +++ b/src/luma/device/decode.rs @@ -21,7 +21,7 @@ see <https://www.gnu.org/licenses/>. */ -use crate::luma::device::{Device, Trap}; +use crate::luma::device::{Branch, Device, Trap}; impl Device { pub fn decode(&mut self) { @@ -47,7 +47,31 @@ impl Device { }; if !condition { return self.r#continue() } - // load/store + // b{cond}{l} + if opcode & 0b00001110000000000000000000000000 == 0b00001010000000000000000000000000 { + let link = opcode & 0b00000001000000000000000000000000 != 0x0; + + let offset = { + let mut offset = opcode & 0b00000000111111111111111111111111; + + if offset & 0b00000000100000000000000000000000 != 0x0 { offset |= 0b00111111000000000000000000000000 } // Sign-extend. + + offset <<= 0x2; + + offset as i32 + }; + + return self.branch(Branch::Offset(offset, link)); + } + + // bx + if opcode & 0b00001111111111111111111111110000 == 0b00000001001011111111111100010000 { + let register = (opcode & 0b00000000000000000000000000001111) as u8; + + return self.branch(Branch::Register(register)); + } + + // ldr|str{cond}{b} if opcode & 0b00001111001000000000000000000000 == 0b00000101000000000000000000000000 { let register = ((opcode & 0b00000000000000001111000000000000) >> 0xC) as u8; @@ -55,15 +79,15 @@ impl Device { let immediate = (opcode & 0b00000000000000000000111111111111) as u16; - let u = 0b00000000100000000000000000000000 != 0x0; - let b = 0b00000000010000000000000000000000 != 0x0; - let l = 0b00000000000100000000000000000000 != 0x0; + let u = opcode & 0b00000000100000000000000000000000 != 0x0; + let b = opcode & 0b00000000010000000000000000000000 != 0x0; + let l = opcode & 0b00000000000100000000000000000000 != 0x0; self.store(register, base, immediate, u, b, l); return self.r#continue(); } - // move + // mov{cond}{s} if opcode & 0b00001101111111100000111111110000 == 0b00000001101000000000000000000000 { let destination = ((opcode & 0b00000000000000001111000000000000) >> 0xC) as u8; let source = (opcode & 0b00000000000000000000000000001111) as u8; @@ -77,23 +101,6 @@ impl Device { return self.r#continue(); } - // branch - if opcode & 0b00001110000000000000000000000000 == 0b00001010000000000000000000000000 { - let link = opcode & 0b00000001000000000000000000000000 != 0x0; - - let offset = { - let mut offset = opcode & 0b00000000111111111111111111111111; - - if offset & 0b00000000100000000000000000000000 != 0x0 { offset |= 0b00111111000000000000000000000000 } // Sign-extend. - - offset <<= 0x2; - - offset as i32 - }; - - return self.branch(offset, link); - } - self.trap(Trap::InvalidOpcode(self.registers[0xF] - 0x8, opcode)); self.r#continue(); diff --git a/src/luma/device/log.rs b/src/luma/device/log.rs index 72b7982..47bef4c 100644 --- a/src/luma/device/log.rs +++ b/src/luma/device/log.rs @@ -25,26 +25,30 @@ use crate::luma::device::{Device, Log}; impl Device { pub fn log(&mut self, kind: Log) { - let kind_string = match kind { - Log::Branch( ..) => "branch ", - Log::Continue( ..) => "continue", - Log::Link( ..) => "link ", - Log::Load( ..) => "load ", - Log::MoveRegister( ..) => "move ", - Log::MoveImmediate(..) => "move ", - Log::Store( ..) => "store ", - }; - - let message = match kind { - Log::Branch( offset, address) => format!("r15{offset:+} => {address:#010X}"), - Log::Continue( address) => format!("r15 => {address:#010X}"), - Log::Link( address) => format!("r14 => {address:#010X}"), - Log::Load( register, address, base, offset, value) => format!("r{register} => r{base}{offset:+}={address:#010X} ({value:#010X})"), - Log::MoveRegister( destination, source, value) => format!("r{destination} => r{source} ({value:#010X})"), - Log::MoveImmediate(register, immediate) => format!("r{register} => {immediate:#X}"), - Log::Store( address, register, base, offset, value) => format!("r{base}{offset:+}={address:#010X} => r{register} ({value:#010X})"), - }; - - eprintln!("{kind_string} : {message}"); + if cfg!(debug_assertions) { // This optimises the function away. + let kind_string = match kind { + Log::BranchOffset( ..) => "branch ", + Log::BranchRegister(..) => "branch ", + Log::Continue( ..) => "continue", + Log::Link( ..) => "link ", + Log::Load( ..) => "load ", + Log::MoveRegister( ..) => "move ", + Log::MoveImmediate( ..) => "move ", + Log::Store( ..) => "store ", + }; + + let message = match kind { + Log::BranchOffset( offset, address) => format!("r15{offset:+} => {address:#010X}"), + Log::BranchRegister(register, address) => format!("r15 => r{register} ({address:#08X})"), + Log::Continue( address) => format!("r15 => {address:#010X}"), + Log::Link( address) => format!("r14 => {address:#010X}"), + Log::Load( register, address, base, offset, value) => format!("r{register} => r{base}{offset:+}={address:#010X} ({value:#010X})"), + Log::MoveRegister( destination, source, value) => format!("r{destination} => r{source} ({value:#010X})"), + Log::MoveImmediate( register, immediate) => format!("r{register} => {immediate:#X}"), + Log::Store( address, register, base, offset, value) => format!("r{base}{offset:+}={address:#010X} => r{register} ({value:#010X})"), + }; + + eprintln!("{kind_string} : {message}"); + } } } |