Skip to content

Commit

Permalink
Support bx; Fix ldr|str; Remove logging in release builds; Fix versio…
Browse files Browse the repository at this point in the history
…n number being in decimal; Update readme;
  • Loading branch information
bjoernager committed Jul 1, 2023
1 parent 9a19307 commit b8b1d07
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 67 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "luma"
version = "0.37.0"
version = "0.38.0"
authors = ["Gabriel Jensen"]
edition = "2021"
description = "AGB emulator."
Expand Down
1 change: 1 addition & 0 deletions README.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/luma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions src/luma/application/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!();

Expand All @@ -55,7 +55,8 @@ impl Application {
}
}

eprintln!("({cycle})");
if cfg!(debug_assertions) { eprintln!("({cycle})"); }

self.device.decode();

sleep(Duration::from_secs(0x1));
Expand Down
22 changes: 13 additions & 9 deletions src/luma/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
36 changes: 26 additions & 10 deletions src/luma/device/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
53 changes: 30 additions & 23 deletions src/luma/device/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -47,23 +47,47 @@ 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;

let base = ((opcode & 0b00000000000011110000000000000000) >> 0x10) as u8;

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;
Expand All @@ -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();
Expand Down
46 changes: 25 additions & 21 deletions src/luma/device/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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}");
}
}
}

0 comments on commit b8b1d07

Please sign in to comment.