summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.txt8
-rw-r--r--Cargo.toml2
-rw-r--r--README.txt1
-rw-r--r--src/luma.rs2
-rw-r--r--src/luma/application/run.rs5
-rw-r--r--src/luma/device.rs22
-rw-r--r--src/luma/device/branch.rs36
-rw-r--r--src/luma/device/decode.rs53
-rw-r--r--src/luma/device/log.rs46
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;
diff --git a/Cargo.toml b/Cargo.toml
index db95cf6..c751c14 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "luma"
-version = "0.37.0"
+version = "0.38.0"
authors = ["Gabriel Jensen"]
edition = "2021"
description = "AGB emulator."
diff --git a/README.txt b/README.txt
index 8f84e00..bb28492 100644
--- a/README.txt
+++ b/README.txt
@@ -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}");
+ }
}
}