summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.txt7
-rw-r--r--Cargo.toml2
-rw-r--r--src/luma.rs25
-rw-r--r--src/luma/app.rs8
-rw-r--r--src/luma/app/drop.rs9
-rw-r--r--src/luma/app/emu.rs64
-rw-r--r--src/luma/app/end.rs4
-rw-r--r--src/luma/app/ini.rs24
-rw-r--r--src/luma/app/new.rs7
-rw-r--r--src/luma/app/run.rs34
-rw-r--r--src/luma/app/trp.rs29
-rw-r--r--src/luma/emu.rs34
-rw-r--r--src/luma/emu/btl.rs12
-rw-r--r--src/luma/emu/drop.rs13
-rw-r--r--src/luma/emu/img.rs12
-rw-r--r--src/luma/emu/new.rs39
-rw-r--r--src/luma/emu/opc.rs54
-rw-r--r--src/luma/emu/run.rs35
-rw-r--r--src/luma/emu/trp.rs45
19 files changed, 302 insertions, 155 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 6c0152c..aed1576 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,3 +1,10 @@
+# 0.27
+
+* Update trap function;
+* Add emulator helper structure;
+* Support conditional instructions;
+* Set signal handlers;
+
# 0.26
* Repurpose project for emulating the AGB;
diff --git a/Cargo.toml b/Cargo.toml
index 6528a73..0322d2f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "luma"
-version = "0.30.0"
+version = "0.31.0"
edition = "2021"
[[bin]]
diff --git a/src/luma.rs b/src/luma.rs
index 57c2768..dd6c837 100644
--- a/src/luma.rs
+++ b/src/luma.rs
@@ -1,30 +1,11 @@
// Copyright 2021-2023 Gabriel Jensen.
pub mod app;
+pub mod emu;
-pub const VER: u32 = 0x1E;
+pub const VER: u32 = 0x1F;
pub const MEMSIZ: usize = 0x0E010000;
pub const BTLSIZ: usize = 0x00004000;
-pub const IMGSIZ: usize = 0x06000000;
-
-pub struct Reg {
- r0: u32,
- r1: u32,
- r2: u32,
- r3: u32,
- r4: u32,
- r5: u32,
- r6: u32,
- r7: u32,
- r8: u32,
- r9: u32,
- r10: u32,
- r11: u32,
- r12: u32,
- sp: u32,
- lr: u32,
- pc: u32,
- cpsr: u32,
-}
+pub const IMGSIZ: usize = 0x02000000;
diff --git a/src/luma/app.rs b/src/luma/app.rs
index d12dbfa..1b85a5c 100644
--- a/src/luma/app.rs
+++ b/src/luma/app.rs
@@ -1,15 +1,17 @@
// Copyright 2021-2023 Gabriel Jensen.
-pub mod emu;
+use std::sync::atomic::AtomicBool;
+
+pub mod drop;
pub mod end;
pub mod ini;
pub mod new;
pub mod prspar;
pub mod run;
-pub mod trp;
pub struct App {
btl: String,
img: String,
- mem: *mut u8,
}
+
+pub static mut GOTSIG: AtomicBool = AtomicBool::new(false);
diff --git a/src/luma/app/drop.rs b/src/luma/app/drop.rs
new file mode 100644
index 0000000..443f9e7
--- /dev/null
+++ b/src/luma/app/drop.rs
@@ -0,0 +1,9 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::app::App;
+
+impl Drop for App {
+ fn drop(&mut self) {
+ self.end(0x0,None);
+ }
+}
diff --git a/src/luma/app/emu.rs b/src/luma/app/emu.rs
deleted file mode 100644
index 3dad048..0000000
--- a/src/luma/app/emu.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::{MEMSIZ, Reg};
-use crate::luma::app::App;
-
-impl App {
- pub fn emu(&mut self) {
- eprintln!("starting emulation");
-
- // Initialise registers:
- let mut reg = Reg {
- r0: 0x00000000,
- r1: 0x00000000,
- r2: 0x00000000,
- r3: 0x00000000,
- r4: 0x00000000,
- r5: 0x00000000,
- r6: 0x00000000,
- r7: 0x00000000,
- r8: 0x00000000,
- r9: 0x00000000,
- r10: 0x00000000,
- r11: 0x00000000,
- r12: 0x00000000,
- sp: 0x00000000,
- lr: 0x00000000,
- pc: 0x08000008,
- cpsr: 0b00000000000000000000000000001111,
- };
-
- //let mem = self.mem; // For convenience.
-
- eprintln!("starting at 0x{:08X}",reg.pc - 0x8);
-
- loop {
- // Check the current address:
- if reg.pc >= MEMSIZ as u32 {
- self.end(0x1, Some(format!("out-of-bounds address {:X}",reg.pc).as_str()));
- }
-
- // Decode opcode:
- let opc = unsafe { *(self.mem.add((reg.pc - 0x8) as usize) as *mut u32) };
-
- // Currently, we only support the bal.w instruction.
- if opc & 0b11111111000000000000000000000000 == 0b11101010000000000000000000000000 {
- let off: u32 = opc & 0b00000000111111111111111111111111;
- let abs: u32 = !(opc - 0x1) & 0b00000000111111111111111111111111;
-
- reg.pc = match (off & 0b00000000100000000000000000000000) != 0x0 { // If negative...
- false => reg.pc + off * 0x4 + 0x8,
- true => reg.pc - abs * 0x4 + 0x8,
- };
- eprintln!("branch {off:X} => {:X}",reg.pc);
-
- continue;
- } else {
- self.trp(&reg, opc);
- }
-
- // Continue:
- reg.pc += 0x4;
- }
- }
-}
diff --git a/src/luma/app/end.rs b/src/luma/app/end.rs
index db2c842..e02a0ae 100644
--- a/src/luma/app/end.rs
+++ b/src/luma/app/end.rs
@@ -1,9 +1,7 @@
// Copyright 2021-2023 Gabriel Jensen.
-use crate::luma::MEMSIZ;
use crate::luma::app::App;
-use std::alloc::{dealloc, Layout};
use std::process::exit;
impl App {
@@ -14,8 +12,6 @@ impl App {
eprintln!("ending");
- unsafe { dealloc(self.mem, Layout::new::<[u32; MEMSIZ/0x20usize]>()) };
-
exit(cod as i32);
}
}
diff --git a/src/luma/app/ini.rs b/src/luma/app/ini.rs
index f4ee5e7..2c4e86f 100644
--- a/src/luma/app/ini.rs
+++ b/src/luma/app/ini.rs
@@ -1,16 +1,28 @@
// Copyright 2021-2023 Gabriel Jensen.
-use crate::luma::MEMSIZ;
-use crate::luma::app::App;
+use crate::luma::app::{App, GOTSIG};
-use std::alloc::{alloc_zeroed, Layout};
+extern crate libc;
+
+use libc::{c_int, sighandler_t, SIGINT, signal, SIGTERM};
+use std::mem::transmute;
+use std::sync::atomic::Ordering;
+
+fn sighnd(sig: c_int) {
+ unsafe {
+ signal(sig, transmute::<fn(c_int), sighandler_t>(sighnd));
+
+ GOTSIG.store(true, Ordering::Relaxed);
+ }
+}
impl App {
pub fn ini(&mut self) {
eprintln!("initialising");
- self.mem = unsafe { alloc_zeroed(Layout::new::<[u32; MEMSIZ]>()) };
-
- eprintln!("allocated memory buffer at 0x{:0X}", self.mem as usize);
+ unsafe {
+ signal(SIGINT, transmute::<fn(c_int), sighandler_t>(sighnd));
+ signal(SIGTERM, transmute::<fn(c_int), sighandler_t>(sighnd));
+ }
}
}
diff --git a/src/luma/app/new.rs b/src/luma/app/new.rs
index 1b30f3e..7bdad01 100644
--- a/src/luma/app/new.rs
+++ b/src/luma/app/new.rs
@@ -2,16 +2,11 @@
use crate::luma::app::App;
-use std::ptr::null;
-
impl App {
pub fn new() -> App {
- let app = App {
+ return App {
btl: "bootloader.bin".to_string(),
img: "image.agb".to_string(),
- mem: null::<u8>() as *mut u8,
};
-
- return app;
}
}
diff --git a/src/luma/app/run.rs b/src/luma/app/run.rs
index 3abbc0a..b18cb20 100644
--- a/src/luma/app/run.rs
+++ b/src/luma/app/run.rs
@@ -1,11 +1,11 @@
// Copyright 2021-2023 Gabriel Jensen.
-use crate::luma::{BTLSIZ, IMGSIZ, VER};
+use crate::luma::VER;
use crate::luma::app::App;
+use crate::luma::emu::Emu;
use std::fs::File;
use std::io::Read;
-use std::slice;
impl App {
pub fn run(&mut self) {
@@ -15,30 +15,24 @@ impl App {
self.ini();
- {
- eprintln!("loading booatloader \"{}\"",self.btl);
+ let mut emu = Emu::new();
- // Open bootloader:
- let mut btl = File::open(self.btl.clone()).expect("unable to open bootloader");
+ eprintln!("loading booatloader \"{}\"",self.btl);
- // Read bootloader:
- let slc = unsafe { slice::from_raw_parts_mut(self.mem.offset(0x00000000), BTLSIZ) };
- btl.read(slc).expect("unable to read bootloader");
- }
+ // Open bootloader:
+ let mut btl = File::open(self.btl.clone()).expect("unable to open bootloader");
- {
- eprintln!("loading image \"{}\"",self.img);
+ // Read bootloader:
+ btl.read(emu.btl()).expect("unable to read bootloader");
- // Open image:
- let mut img = File::open(self.img.clone()).expect("unable to open image");
+ eprintln!("loading image \"{}\"",self.img);
- // Read image:
- let slc = unsafe { slice::from_raw_parts_mut(self.mem.offset(0x08000000), IMGSIZ) };
- img.read(slc).expect("unable to read image");
- }
+ // Open image:
+ let mut img = File::open(self.img.clone()).expect("unable to open image");
- self.emu();
+ // Read image:
+ img.read(emu.img()).expect("unable to read image");
- self.end(0x0,None);
+ emu.run();
}
}
diff --git a/src/luma/app/trp.rs b/src/luma/app/trp.rs
deleted file mode 100644
index 7ec4cec..0000000
--- a/src/luma/app/trp.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::Reg;
-use crate::luma::app::App;
-
-impl App {
- pub fn trp(&mut self, reg: &Reg, opc: u32) {
- eprintln!("trap - register dump:");
- eprintln!("\tr0: {:08X}", reg.r0);
- eprintln!("\tr1: {:08X}", reg.r1);
- eprintln!("\tr2: {:08X}", reg.r2);
- eprintln!("\tr3: {:08X}", reg.r3);
- eprintln!("\tr4: {:08X}", reg.r4);
- eprintln!("\tr5: {:08X}", reg.r5);
- eprintln!("\tr6: {:08X}", reg.r6);
- eprintln!("\tr7: {:08X}", reg.r7);
- eprintln!("\tr8: {:08X}", reg.r8);
- eprintln!("\tr9: {:08X}", reg.r9);
- eprintln!("\tr10: {:08X}", reg.r10);
- eprintln!("\tr11: {:08X}", reg.r11);
- eprintln!("\tr12: {:08X}", reg.r12);
- eprintln!("\tsp: {:08X}", reg.sp);
- eprintln!("\tlr: {:08X}", reg.lr);
- eprintln!("\tpc: {:08X}", reg.pc);
- eprintln!("\tcpsr: {:032b}", reg.cpsr);
-
- self.end(0x1, Some(format!("invalid opcode 0x{opc:08X} at 0x{:08X}",reg.pc-0x8).as_str()));
- }
-}
diff --git a/src/luma/emu.rs b/src/luma/emu.rs
new file mode 100644
index 0000000..aa32437
--- /dev/null
+++ b/src/luma/emu.rs
@@ -0,0 +1,34 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+pub mod btl;
+pub mod drop;
+pub mod img;
+pub mod new;
+pub mod opc;
+pub mod run;
+pub mod trp;
+
+pub struct Reg {
+ r0: u32,
+ r1: u32,
+ r2: u32,
+ r3: u32,
+ r4: u32,
+ r5: u32,
+ r6: u32,
+ r7: u32,
+ r8: u32,
+ r9: u32,
+ r10: u32,
+ r11: u32,
+ r12: u32,
+ sp: u32,
+ lr: u32,
+ pc: u32,
+ cpsr: u32,
+}
+
+pub struct Emu {
+ mem: *mut u8,
+ reg: Reg,
+}
diff --git a/src/luma/emu/btl.rs b/src/luma/emu/btl.rs
new file mode 100644
index 0000000..7bca72e
--- /dev/null
+++ b/src/luma/emu/btl.rs
@@ -0,0 +1,12 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::BTLSIZ;
+use crate::luma::emu::Emu;
+
+use std::slice;
+
+impl Emu {
+ pub fn btl<'a>(&mut self) -> &'a mut [u8] {
+ return unsafe { slice::from_raw_parts_mut(self.mem.offset(0x00000000), BTLSIZ) };
+ }
+}
diff --git a/src/luma/emu/drop.rs b/src/luma/emu/drop.rs
new file mode 100644
index 0000000..cb92361
--- /dev/null
+++ b/src/luma/emu/drop.rs
@@ -0,0 +1,13 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::MEMSIZ;
+use crate::luma::emu::Emu;
+
+use std::alloc::{dealloc, Layout};
+use std::mem::size_of;
+
+impl Drop for Emu {
+ fn drop(&mut self) {
+ unsafe { dealloc(self.mem, Layout::new::<[u32; MEMSIZ / size_of::<u32>()]>()) };
+ }
+}
diff --git a/src/luma/emu/img.rs b/src/luma/emu/img.rs
new file mode 100644
index 0000000..d7f78e7
--- /dev/null
+++ b/src/luma/emu/img.rs
@@ -0,0 +1,12 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::IMGSIZ;
+use crate::luma::emu::Emu;
+
+use std::slice;
+
+impl Emu {
+ pub fn img<'a>(&mut self) -> &'a mut [u8] {
+ return unsafe { slice::from_raw_parts_mut(self.mem.offset(0x08000000), IMGSIZ) };
+ }
+}
diff --git a/src/luma/emu/new.rs b/src/luma/emu/new.rs
new file mode 100644
index 0000000..85fe790
--- /dev/null
+++ b/src/luma/emu/new.rs
@@ -0,0 +1,39 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::MEMSIZ;
+use crate::luma::emu::{Emu, Reg};
+
+use std::alloc::{alloc_zeroed, Layout};
+use std::mem::size_of;
+
+impl Emu {
+ pub fn new() -> Emu {
+ let mem = unsafe { alloc_zeroed(Layout::new::<[u32; MEMSIZ / size_of::<u32>()]>()) };
+ if mem.is_null() { panic!("unable to allocate memory buffer") }
+
+ eprintln!("allocated memory buffer at 0x{:0X}", mem as usize);
+
+ return Emu {
+ mem: mem,
+ reg: Reg {
+ r0: 0x00000000,
+ r1: 0x00000000,
+ r2: 0x00000000,
+ r3: 0x00000000,
+ r4: 0x00000000,
+ r5: 0x00000000,
+ r6: 0x00000000,
+ r7: 0x00000000,
+ r8: 0x00000000,
+ r9: 0x00000000,
+ r10: 0x00000000,
+ r11: 0x00000000,
+ r12: 0x00000000,
+ sp: 0x00000000,
+ lr: 0x00000000,
+ pc: 0x08000008,
+ cpsr: 0b00000000000000000000000000001111,
+ },
+ };
+ }
+}
diff --git a/src/luma/emu/opc.rs b/src/luma/emu/opc.rs
new file mode 100644
index 0000000..328ac88
--- /dev/null
+++ b/src/luma/emu/opc.rs
@@ -0,0 +1,54 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::emu::Emu;
+
+use std::hint::unreachable_unchecked;
+
+fn cndexe(cpsr: u32, cnd: u8) -> Option<bool> {
+ return match cnd {
+ 0b0000 => Some((cpsr & 0b01000000000000000000000000000000) != 0x00),
+ 0b0001 => Some((cpsr & 0b01000000000000000000000000000000) == 0x00),
+ 0b0010 => Some((cpsr & 0b00100000000000000000000000000000) != 0x00),
+ 0b0011 => Some((cpsr & 0b00100000000000000000000000000000) == 0x00),
+ 0b0100 => Some((cpsr & 0b10000000000000000000000000000000) != 0x00),
+ 0b0101 => Some((cpsr & 0b10000000000000000000000000000000) == 0x00),
+ 0b0110 => Some((cpsr & 0b00010000000000000000000000000000) != 0x00),
+ 0b0111 => Some((cpsr & 0b00010000000000000000000000000000) == 0x00),
+ 0b1000 => Some((cpsr & 0b00100000000000000000000000000000) != 0x00 && (cpsr & 0b01000000000000000000000000000000) == 0x00),
+ 0b1001 => Some((cpsr & 0b00100000000000000000000000000000) == 0x00 && (cpsr & 0b01000000000000000000000000000000) != 0x00),
+ 0b1010 => Some((cpsr & 0b00010000000000000000000000000000) >> 0x1C == (cpsr & 0b10000000000000000000000000000000) >> 0x1F),
+ 0b1011 => Some((cpsr & 0b00010000000000000000000000000000) >> 0x1C != (cpsr & 0b10000000000000000000000000000000) >> 0x1F),
+ 0b1100 => Some((cpsr & 0b01000000000000000000000000000000) == 0x00 && (cpsr & 0b00010000000000000000000000000000) >> 0x1C == (cpsr & 0b10000000000000000000000000000000) >> 0x1F),
+ 0b1101 => Some((cpsr & 0b01000000000000000000000000000000) != 0x00 || (cpsr & 0b00010000000000000000000000000000) >> 0x1C != (cpsr & 0b10000000000000000000000000000000) >> 0x1F),
+ 0b1110 => Some(true),
+ _ => None,
+ }
+}
+
+impl Emu {
+ pub fn opc(&mut self, opc: u32) {
+ // Currently, we only support the bal.w instruction.
+ if opc & 0b00001111000000000000000000000000 == 0b00001010000000000000000000000000 {
+ let off = opc & 0b00000000111111111111111111111111; // Offset from pc.
+ let inv = !(opc - 0x1) & 0b00000000111111111111111111111111; // Inverted offset.
+
+ let cnd = ((opc & 0b11110000000000000000000000000) >> 0x19) as u8;
+ match cndexe(self.reg.cpsr, cnd) {
+ None => self.trpcnd(cnd),
+ Some(false) => return,
+ Some(true) => {},
+ }
+
+ self.reg.pc = match (off & 0b00000000100000000000000000000000) != 0x0 { // If negative...
+ false => self.reg.pc + off * 0x4 + 0x8,
+ true => self.reg.pc - inv * 0x4 + 0x8,
+ };
+ eprintln!("branch {off:X} => {:X}", self.reg.pc);
+
+ return;
+ }
+
+ self.trpopc(self.reg.pc - 0x8, opc);
+ unsafe { unreachable_unchecked() };
+ }
+}
diff --git a/src/luma/emu/run.rs b/src/luma/emu/run.rs
new file mode 100644
index 0000000..3fb3ddc
--- /dev/null
+++ b/src/luma/emu/run.rs
@@ -0,0 +1,35 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::MEMSIZ;
+use crate::luma::app::GOTSIG;
+use crate::luma::emu::Emu;
+
+use std::sync::atomic::Ordering;
+
+impl Emu {
+ pub fn run(&mut self) {
+ eprintln!("starting emulation");
+
+ eprintln!("starting at 0x{:08X}",self.reg.pc - 0x8);
+
+ loop {
+ // Check if we have recieved a signal:
+ if unsafe { GOTSIG.load(Ordering::Relaxed) } {
+ eprintln!("got interrupt");
+ break;
+ }
+
+ // Check the current address:
+ if self.reg.pc >= MEMSIZ as u32 {
+ self.trpadr(self.reg.pc);
+ }
+
+ // Decode opcode:
+ let opc = unsafe { *(self.mem.add((self.reg.pc - 0x8) as usize) as *mut u32) };
+ self.opc(opc);
+
+ // Continue:
+ self.reg.pc += 0x4;
+ }
+ }
+}
diff --git a/src/luma/emu/trp.rs b/src/luma/emu/trp.rs
new file mode 100644
index 0000000..8ea4393
--- /dev/null
+++ b/src/luma/emu/trp.rs
@@ -0,0 +1,45 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::emu::Emu;
+
+impl Emu {
+ pub fn trpadr(&mut self, adr: u32) {
+ self.trp(format!("out-of-range address {adr:08X}"));
+ }
+
+ pub fn trpcnd(&mut self, cnd: u8) {
+ self.trp(format!("invalid condition {cnd:02X}"));
+ }
+
+ pub fn trpopc(&mut self, adr: u32, opc: u32) {
+ self.trp(format!("invalid opcode {opc:08X} at {adr:08X}"));
+ }
+
+ pub fn trpreg(&mut self, reg: u8) {
+ self.trp(format!("invalid register {reg:02X}"));
+ }
+
+ fn trp(&mut self, msg: String) {
+ eprintln!("trap - {msg}");
+ eprintln!();
+ eprintln!("\tr0: {:08X}", self.reg.r0);
+ eprintln!("\tr1: {:08X}", self.reg.r1);
+ eprintln!("\tr2: {:08X}", self.reg.r2);
+ eprintln!("\tr3: {:08X}", self.reg.r3);
+ eprintln!("\tr4: {:08X}", self.reg.r4);
+ eprintln!("\tr5: {:08X}", self.reg.r5);
+ eprintln!("\tr6: {:08X}", self.reg.r6);
+ eprintln!("\tr7: {:08X}", self.reg.r7);
+ eprintln!("\tr8: {:08X}", self.reg.r8);
+ eprintln!("\tr9: {:08X}", self.reg.r9);
+ eprintln!("\tr10: {:08X}", self.reg.r10);
+ eprintln!("\tr11: {:08X}", self.reg.r11);
+ eprintln!("\tr12: {:08X}", self.reg.r12);
+ eprintln!("\tsp: {:08X}", self.reg.sp);
+ eprintln!("\tlr: {:08X}", self.reg.lr);
+ eprintln!("\tpc: {:08X}", self.reg.pc);
+ eprintln!("\tcpsr: {:032b}", self.reg.cpsr);
+
+ panic!("{msg}");
+ }
+}