summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.txt8
-rw-r--r--Cargo.toml2
-rw-r--r--src/luma.rs12
-rw-r--r--src/luma/app.rs17
-rw-r--r--src/luma/app/ini.rs28
-rw-r--r--src/luma/app/new.rs12
-rw-r--r--src/luma/app/prspar.rs26
-rw-r--r--src/luma/app/run.rs38
-rw-r--r--src/luma/application.rs17
-rw-r--r--src/luma/application/drop.rs (renamed from src/luma/app/drop.rs)4
-rw-r--r--src/luma/application/end.rs (renamed from src/luma/app/end.rs)4
-rw-r--r--src/luma/application/initialise.rs28
-rw-r--r--src/luma/application/new.rs12
-rw-r--r--src/luma/application/parse_parameters.rs26
-rw-r--r--src/luma/application/run.rs38
-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
-rw-r--r--src/luma/emulator.rs22
-rw-r--r--src/luma/emulator/bootloader.rs12
-rw-r--r--src/luma/emulator/drop.rs13
-rw-r--r--src/luma/emulator/image.rs12
-rw-r--r--src/luma/emulator/new.rs39
-rw-r--r--src/luma/emulator/opcode.rs45
-rw-r--r--src/luma/emulator/read.rs29
-rw-r--r--src/luma/emulator/run.rs29
-rw-r--r--src/luma/emulator/trap.rs36
-rw-r--r--src/main.rs6
33 files changed, 380 insertions, 379 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index aed1576..1639ad2 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,3 +1,11 @@
+# 0.28
+
+* Support bl;
+* Update register format;
+* Unify trap functions;
+* Add memory read helper functions;
+* Update naming convention;
+
# 0.27
* Update trap function;
diff --git a/Cargo.toml b/Cargo.toml
index 0322d2f..a2c9615 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "luma"
-version = "0.31.0"
+version = "0.32.0"
edition = "2021"
[[bin]]
diff --git a/src/luma.rs b/src/luma.rs
index dd6c837..e4a9395 100644
--- a/src/luma.rs
+++ b/src/luma.rs
@@ -1,11 +1,11 @@
// Copyright 2021-2023 Gabriel Jensen.
-pub mod app;
-pub mod emu;
+pub mod application;
+pub mod emulator;
-pub const VER: u32 = 0x1F;
+pub const VERSION: u32 = 0x20;
-pub const MEMSIZ: usize = 0x0E010000;
+pub const MEMORY_SIZE: usize = 0x0E010000;
-pub const BTLSIZ: usize = 0x00004000;
-pub const IMGSIZ: usize = 0x02000000;
+pub const BOOTLOADER_SIZE: usize = 0x00004000;
+pub const IMAGE_SIZE: usize = 0x02000000;
diff --git a/src/luma/app.rs b/src/luma/app.rs
deleted file mode 100644
index 1b85a5c..0000000
--- a/src/luma/app.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use std::sync::atomic::AtomicBool;
-
-pub mod drop;
-pub mod end;
-pub mod ini;
-pub mod new;
-pub mod prspar;
-pub mod run;
-
-pub struct App {
- btl: String,
- img: String,
-}
-
-pub static mut GOTSIG: AtomicBool = AtomicBool::new(false);
diff --git a/src/luma/app/ini.rs b/src/luma/app/ini.rs
deleted file mode 100644
index 2c4e86f..0000000
--- a/src/luma/app/ini.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::app::{App, GOTSIG};
-
-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");
-
- 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
deleted file mode 100644
index 7bdad01..0000000
--- a/src/luma/app/new.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::app::App;
-
-impl App {
- pub fn new() -> App {
- return App {
- btl: "bootloader.bin".to_string(),
- img: "image.agb".to_string(),
- };
- }
-}
diff --git a/src/luma/app/prspar.rs b/src/luma/app/prspar.rs
deleted file mode 100644
index 2353787..0000000
--- a/src/luma/app/prspar.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::app::App;
-
-use std::env::args;
-
-impl App {
- pub fn prspar(&mut self) {
- eprintln!("parsing parameters");
-
- let arg: Vec<String> = args().collect();
- let num = arg.len();
-
- if num >= 0x2 {
- self.img = arg[0x1].clone();
- }
-
- if num >= 0x3 {
- self.btl = arg[0x2].clone();
- }
-
- if num > 0x3 {
- self.end(0x1,Some(format!("invalid number of parameters ({num})").as_str()));
- }
- }
-}
diff --git a/src/luma/app/run.rs b/src/luma/app/run.rs
deleted file mode 100644
index b18cb20..0000000
--- a/src/luma/app/run.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::VER;
-use crate::luma::app::App;
-use crate::luma::emu::Emu;
-
-use std::fs::File;
-use std::io::Read;
-
-impl App {
- pub fn run(&mut self) {
- eprintln!("luma {VER}");
-
- self.prspar();
-
- self.ini();
-
- let mut emu = Emu::new();
-
- eprintln!("loading booatloader \"{}\"",self.btl);
-
- // Open bootloader:
- let mut btl = File::open(self.btl.clone()).expect("unable to open bootloader");
-
- // Read bootloader:
- btl.read(emu.btl()).expect("unable to read bootloader");
-
- eprintln!("loading image \"{}\"",self.img);
-
- // Open image:
- let mut img = File::open(self.img.clone()).expect("unable to open image");
-
- // Read image:
- img.read(emu.img()).expect("unable to read image");
-
- emu.run();
- }
-}
diff --git a/src/luma/application.rs b/src/luma/application.rs
new file mode 100644
index 0000000..4f095c2
--- /dev/null
+++ b/src/luma/application.rs
@@ -0,0 +1,17 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use std::sync::atomic::AtomicBool;
+
+pub mod drop;
+pub mod end;
+pub mod initialise;
+pub mod new;
+pub mod parse_parameters;
+pub mod run;
+
+pub struct Application {
+ bootloader: String,
+ image: String,
+}
+
+pub static mut GOT_SIGNAL: AtomicBool = AtomicBool::new(false);
diff --git a/src/luma/app/drop.rs b/src/luma/application/drop.rs
index 443f9e7..8fb7cf1 100644
--- a/src/luma/app/drop.rs
+++ b/src/luma/application/drop.rs
@@ -1,8 +1,8 @@
// Copyright 2021-2023 Gabriel Jensen.
-use crate::luma::app::App;
+use crate::luma::application::Application;
-impl Drop for App {
+impl Drop for Application {
fn drop(&mut self) {
self.end(0x0,None);
}
diff --git a/src/luma/app/end.rs b/src/luma/application/end.rs
index e02a0ae..4e6f4fa 100644
--- a/src/luma/app/end.rs
+++ b/src/luma/application/end.rs
@@ -1,10 +1,10 @@
// Copyright 2021-2023 Gabriel Jensen.
-use crate::luma::app::App;
+use crate::luma::application::Application;
use std::process::exit;
-impl App {
+impl Application {
pub fn end(&mut self, cod: u8, msg: Option<&str>) {
if cod != 0x0 {
eprintln!("error: {}", msg.unwrap());
diff --git a/src/luma/application/initialise.rs b/src/luma/application/initialise.rs
new file mode 100644
index 0000000..9b6848b
--- /dev/null
+++ b/src/luma/application/initialise.rs
@@ -0,0 +1,28 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::application::{Application, GOT_SIGNAL};
+
+extern crate libc;
+
+use libc::{c_int, sighandler_t, SIGINT, signal, SIGTERM};
+use std::mem::transmute;
+use std::sync::atomic::Ordering;
+
+fn signal_handler(sig: c_int) {
+ unsafe {
+ signal(sig, transmute::<fn(c_int), sighandler_t>(signal_handler));
+
+ GOT_SIGNAL.store(true, Ordering::Relaxed);
+ }
+}
+
+impl Application {
+ pub fn initialise(&mut self) {
+ eprintln!("initialising");
+
+ unsafe {
+ signal(SIGINT, transmute::<fn(c_int), sighandler_t>(signal_handler));
+ signal(SIGTERM, transmute::<fn(c_int), sighandler_t>(signal_handler));
+ }
+ }
+}
diff --git a/src/luma/application/new.rs b/src/luma/application/new.rs
new file mode 100644
index 0000000..41d25a7
--- /dev/null
+++ b/src/luma/application/new.rs
@@ -0,0 +1,12 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::application::Application;
+
+impl Application {
+ pub fn new() -> Application {
+ return Application {
+ bootloader: "bootloader.bin".to_string(),
+ image: "image.agb".to_string(),
+ };
+ }
+}
diff --git a/src/luma/application/parse_parameters.rs b/src/luma/application/parse_parameters.rs
new file mode 100644
index 0000000..46e619d
--- /dev/null
+++ b/src/luma/application/parse_parameters.rs
@@ -0,0 +1,26 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::application::Application;
+
+use std::env::args;
+
+impl Application {
+ pub fn parse_parameters(&mut self) {
+ eprintln!("parsing parameters");
+
+ let parameters: Vec<String> = args().collect();
+ let number = parameters.len();
+
+ if number >= 0x2 {
+ self.image = parameters[0x1].clone();
+ }
+
+ if number >= 0x3 {
+ self.bootloader = parameters[0x2].clone();
+ }
+
+ if number > 0x3 {
+ self.end(0x1, Some(format!("invalid number of parameters ({number})").as_str()));
+ }
+ }
+}
diff --git a/src/luma/application/run.rs b/src/luma/application/run.rs
new file mode 100644
index 0000000..23419be
--- /dev/null
+++ b/src/luma/application/run.rs
@@ -0,0 +1,38 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::VERSION;
+use crate::luma::application::Application;
+use crate::luma::emulator::Emulator;
+
+use std::fs::File;
+use std::io::Read;
+
+impl Application {
+ pub fn run(&mut self) {
+ eprintln!("luma {VERSION}");
+
+ self.parse_parameters();
+
+ self.initialise();
+
+ let mut emulator = Emulator::new();
+
+ eprintln!("loading booatloader \"{}\"",self.bootloader);
+
+ // Open bootloader:
+ let mut bootloader = File::open(self.bootloader.clone()).expect("unable to open bootloader");
+
+ // Read bootloader:
+ bootloader.read(emulator.bootloader()).expect("unable to read bootloader");
+
+ eprintln!("loading image \"{}\"",self.image);
+
+ // Open image:
+ let mut image = File::open(self.image.clone()).expect("unable to open image");
+
+ // Read image:
+ image.read(emulator.image()).expect("unable to read image");
+
+ emulator.run();
+ }
+}
diff --git a/src/luma/emu.rs b/src/luma/emu.rs
deleted file mode 100644
index aa32437..0000000
--- a/src/luma/emu.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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
deleted file mode 100644
index 7bca72e..0000000
--- a/src/luma/emu/btl.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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
deleted file mode 100644
index cb92361..0000000
--- a/src/luma/emu/drop.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// 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
deleted file mode 100644
index d7f78e7..0000000
--- a/src/luma/emu/img.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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
deleted file mode 100644
index 85fe790..0000000
--- a/src/luma/emu/new.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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
deleted file mode 100644
index 328ac88..0000000
--- a/src/luma/emu/opc.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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
deleted file mode 100644
index 3fb3ddc..0000000
--- a/src/luma/emu/run.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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
deleted file mode 100644
index 8ea4393..0000000
--- a/src/luma/emu/trp.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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}");
- }
-}
diff --git a/src/luma/emulator.rs b/src/luma/emulator.rs
new file mode 100644
index 0000000..2a108eb
--- /dev/null
+++ b/src/luma/emulator.rs
@@ -0,0 +1,22 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+pub mod bootloader;
+pub mod drop;
+pub mod read;
+pub mod image;
+pub mod new;
+pub mod opcode;
+pub mod run;
+pub mod trap;
+
+pub enum TrapKind {
+ BadAlignment,
+ InvalidOpcode,
+ OutOfBounds,
+}
+
+pub struct Emulator {
+ memory: *mut u8,
+ registers: [u32; 0x10],
+ psr: u32,
+}
diff --git a/src/luma/emulator/bootloader.rs b/src/luma/emulator/bootloader.rs
new file mode 100644
index 0000000..9aca8eb
--- /dev/null
+++ b/src/luma/emulator/bootloader.rs
@@ -0,0 +1,12 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::BOOTLOADER_SIZE;
+use crate::luma::emulator::Emulator;
+
+use std::slice;
+
+impl Emulator {
+ pub fn bootloader<'a>(&mut self) -> &'a mut [u8] {
+ return unsafe { slice::from_raw_parts_mut(self.memory.offset(0x00000000), BOOTLOADER_SIZE) };
+ }
+}
diff --git a/src/luma/emulator/drop.rs b/src/luma/emulator/drop.rs
new file mode 100644
index 0000000..6f87867
--- /dev/null
+++ b/src/luma/emulator/drop.rs
@@ -0,0 +1,13 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::MEMORY_SIZE;
+use crate::luma::emulator::Emulator;
+
+use std::alloc::{dealloc, Layout};
+use std::mem::size_of;
+
+impl Drop for Emulator {
+ fn drop(&mut self) {
+ unsafe { dealloc(self.memory, Layout::new::<[u32; MEMORY_SIZE / size_of::<u32>()]>()) };
+ }
+}
diff --git a/src/luma/emulator/image.rs b/src/luma/emulator/image.rs
new file mode 100644
index 0000000..d62dc9a
--- /dev/null
+++ b/src/luma/emulator/image.rs
@@ -0,0 +1,12 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::IMAGE_SIZE;
+use crate::luma::emulator::Emulator;
+
+use std::slice;
+
+impl Emulator {
+ pub fn image<'a>(&mut self) -> &'a mut [u8] {
+ return unsafe { slice::from_raw_parts_mut(self.memory.offset(0x08000000), IMAGE_SIZE) };
+ }
+}
diff --git a/src/luma/emulator/new.rs b/src/luma/emulator/new.rs
new file mode 100644
index 0000000..e3ab7ef
--- /dev/null
+++ b/src/luma/emulator/new.rs
@@ -0,0 +1,39 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::MEMORY_SIZE;
+use crate::luma::emulator::Emulator;
+
+use std::alloc::{alloc_zeroed, Layout};
+use std::mem::size_of;
+
+impl Emulator {
+ pub fn new() -> Emulator {
+ let memory = unsafe { alloc_zeroed(Layout::new::<[u32; MEMORY_SIZE / size_of::<u32>()]>()) };
+ if memory.is_null() { panic!("unable to allocate memory buffer") }
+
+ eprintln!("allocated memory buffer at 0x{:0X}", memory as usize);
+
+ return Emulator {
+ memory: memory,
+ registers: [
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x08000008,
+ ],
+ psr: 0b00000000000000000000000000001111,
+ };
+ }
+}
diff --git a/src/luma/emulator/opcode.rs b/src/luma/emulator/opcode.rs
new file mode 100644
index 0000000..b074aa7
--- /dev/null
+++ b/src/luma/emulator/opcode.rs
@@ -0,0 +1,45 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::emulator::{Emulator, TrapKind};
+
+impl Emulator {
+ pub fn opcode(&mut self, opcode: u32) {
+ let condition = match opcode & 0b11110000000000000000000000000 {
+ 0b00000000000000000000000000000 => self.psr & 0b01000000000000000000000000000000 != 0x00,
+ 0b00010000000000000000000000000 => self.psr & 0b01000000000000000000000000000000 == 0x00,
+ 0b00100000000000000000000000000 => self.psr & 0b00100000000000000000000000000000 != 0x00,
+ 0b00110000000000000000000000000 => self.psr & 0b00100000000000000000000000000000 == 0x00,
+ 0b01000000000000000000000000000 => self.psr & 0b10000000000000000000000000000000 != 0x00,
+ 0b01010000000000000000000000000 => self.psr & 0b10000000000000000000000000000000 == 0x00,
+ 0b01100000000000000000000000000 => self.psr & 0b00010000000000000000000000000000 != 0x00,
+ 0b01110000000000000000000000000 => self.psr & 0b00010000000000000000000000000000 == 0x00,
+ 0b10000000000000000000000000000 => self.psr & 0b00100000000000000000000000000000 != 0x00 && self.psr & 0b01000000000000000000000000000000 == 0x00,
+ 0b10010000000000000000000000000 => self.psr & 0b00100000000000000000000000000000 == 0x00 && self.psr & 0b01000000000000000000000000000000 != 0x00,
+ 0b10100000000000000000000000000 => self.psr & 0b00010000000000000000000000000000 >> 0x1C == self.psr & 0b10000000000000000000000000000000 >> 0x1F,
+ 0b10110000000000000000000000000 => self.psr & 0b00010000000000000000000000000000 >> 0x1C != self.psr & 0b10000000000000000000000000000000 >> 0x1F,
+ 0b11000000000000000000000000000 => self.psr & 0b01000000000000000000000000000000 == 0x00 && self.psr & 0b00010000000000000000000000000000 >> 0x1C == self.psr & 0b10000000000000000000000000000000 >> 0x1F,
+ 0b11010000000000000000000000000 => self.psr & 0b01000000000000000000000000000000 != 0x00 || self.psr & 0b00010000000000000000000000000000 >> 0x1C != self.psr & 0b10000000000000000000000000000000 >> 0x1F,
+ 0b11100000000000000000000000000 => true,
+ _ => { self.trap(TrapKind::InvalidOpcode, Some(self.registers[0xF] - 0x8), Some(opcode), None); unreachable!(); },
+ };
+ if !condition { return };
+
+ if opcode & 0b00001110000000000000000000000000 == 0b00001010000000000000000000000000 {
+ let off = opcode & 0b00000000111111111111111111111111; // Offset from pc.
+ let inv = !(opcode - 0x1) & 0b00000000111111111111111111111111; // Inverted offset.
+
+ if opcode & 0b00000001000000000000000000000000 != 0x0 { self.registers[0xE] = self.registers[0xF] - 0x4; }
+
+ self.registers[0xF] = match (off & 0b00000000100000000000000000000000) != 0x0 { // If negative...
+ false => self.registers[0xF] + off * 0x4 + 0x8,
+ true => self.registers[0xF] - inv * 0x4 + 0x8,
+ };
+
+ eprintln!("branch: {:024b} => {:08X}", off, self.registers[0xF] - 0x8);
+ return;
+ }
+
+ self.trap(TrapKind::InvalidOpcode, Some(self.registers[0xF] - 0x8), Some(opcode), None);
+ unreachable!();
+ }
+}
diff --git a/src/luma/emulator/read.rs b/src/luma/emulator/read.rs
new file mode 100644
index 0000000..f374e4d
--- /dev/null
+++ b/src/luma/emulator/read.rs
@@ -0,0 +1,29 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::MEMORY_SIZE;
+use crate::luma::emulator::{Emulator, TrapKind};
+
+impl Emulator {
+ #[allow(dead_code)]
+ pub fn read_byte(&mut self, address: u32) -> u8 {
+ if address >= MEMORY_SIZE as u32 { self.trap(TrapKind::OutOfBounds, Some(address), None, None) };
+
+ return unsafe { *(self.memory.offset(address as isize) as *mut u8) };
+ }
+
+ #[allow(dead_code)]
+ pub fn read_halfword(&mut self, address: u32) -> u16 {
+ if address >= MEMORY_SIZE as u32 { self.trap(TrapKind::OutOfBounds, Some(address), None, None) };
+ if address % 0x2 != 0x0 { self.trap(TrapKind::BadAlignment, Some(address), None, Some(0x2)) };
+
+ return unsafe { *(self.memory.offset(address as isize) as *mut u16) };
+ }
+
+ #[allow(dead_code)]
+ pub fn read_word(&mut self, address: u32) -> u32 {
+ if address >= MEMORY_SIZE as u32 { self.trap(TrapKind::OutOfBounds, Some(address), None, None) };
+ if address % 0x4 != 0x0 { self.trap(TrapKind::BadAlignment, Some(address), None, Some(0x4)) };
+
+ return unsafe { *(self.memory.offset(address as isize) as *mut u32) };
+ }
+}
diff --git a/src/luma/emulator/run.rs b/src/luma/emulator/run.rs
new file mode 100644
index 0000000..001bbe4
--- /dev/null
+++ b/src/luma/emulator/run.rs
@@ -0,0 +1,29 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::application::GOT_SIGNAL;
+use crate::luma::emulator::Emulator;
+
+use std::sync::atomic::Ordering;
+
+impl Emulator {
+ pub fn run(&mut self) {
+ eprintln!("starting emulation");
+
+ eprintln!("starting at 0x{:08X}",self.registers[0xF] - 0x8);
+
+ loop {
+ // Check if we have recieved a signal:
+ if unsafe { GOT_SIGNAL.load(Ordering::Relaxed) } {
+ eprintln!("got interrupt");
+ break;
+ }
+
+ // Decode opcode:
+ let opcode = self.read_word(self.registers[0xF] - 0x8);
+ self.opcode(opcode);
+
+ // Continue:
+ self.registers[0xF] += 0x4;
+ }
+ }
+}
diff --git a/src/luma/emulator/trap.rs b/src/luma/emulator/trap.rs
new file mode 100644
index 0000000..fa833e5
--- /dev/null
+++ b/src/luma/emulator/trap.rs
@@ -0,0 +1,36 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::MEMORY_SIZE;
+use crate::luma::emulator::{Emulator, TrapKind};
+
+impl Emulator {
+ pub fn trap(&mut self, kind: TrapKind, address: Option<u32>, opcode: Option<u32>, alignment: Option<u32>) {
+ let message = match kind {
+ TrapKind::BadAlignment => format!("bad alignment of address 0x{:08X} (should be {}-byte aligned)", address.unwrap(), alignment.unwrap()),
+ TrapKind::InvalidOpcode => format!("invalid opcode 0x{:08X} at 0x{:08X}", opcode.unwrap(), address.unwrap()),
+ TrapKind::OutOfBounds => format!("out-of-bounds address 0x{:08X} (limit is 0x{MEMORY_SIZE:08X})", address.unwrap()),
+ };
+
+ eprintln!("trap - {message}");
+ eprintln!();
+ eprintln!("\tr0: {:08X}", self.registers[0x0]);
+ eprintln!("\tr1: {:08X}", self.registers[0x1]);
+ eprintln!("\tr2: {:08X}", self.registers[0x2]);
+ eprintln!("\tr3: {:08X}", self.registers[0x3]);
+ eprintln!("\tr4: {:08X}", self.registers[0x4]);
+ eprintln!("\tr5: {:08X}", self.registers[0x5]);
+ eprintln!("\tr6: {:08X}", self.registers[0x6]);
+ eprintln!("\tr7: {:08X}", self.registers[0x7]);
+ eprintln!("\tr8: {:08X}", self.registers[0x8]);
+ eprintln!("\tr9: {:08X}", self.registers[0x9]);
+ eprintln!("\tr10: {:08X}", self.registers[0xA]);
+ eprintln!("\tr11: {:08X}", self.registers[0xB]);
+ eprintln!("\tr12: {:08X}", self.registers[0xC]);
+ eprintln!("\tsp: {:08X}", self.registers[0xD]);
+ eprintln!("\tlr: {:08X}", self.registers[0xE]);
+ eprintln!("\tpc: {:08X}", self.registers[0xF]);
+ eprintln!("\topsr: {:032b}", self.psr);
+
+ panic!("{message}");
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index aaa0e2b..82d3609 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,9 +2,9 @@
mod luma;
-use crate::luma::app::App;
+use crate::luma::application::Application;
fn main() {
- let mut app = App::new();
- app.run();
+ let mut application = Application::new();
+ application.run();
}