diff options
-rw-r--r-- | CHANGELOG.txt | 7 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | src/luma.rs | 25 | ||||
-rw-r--r-- | src/luma/app.rs | 8 | ||||
-rw-r--r-- | src/luma/app/drop.rs | 9 | ||||
-rw-r--r-- | src/luma/app/emu.rs | 64 | ||||
-rw-r--r-- | src/luma/app/end.rs | 4 | ||||
-rw-r--r-- | src/luma/app/ini.rs | 24 | ||||
-rw-r--r-- | src/luma/app/new.rs | 7 | ||||
-rw-r--r-- | src/luma/app/run.rs | 34 | ||||
-rw-r--r-- | src/luma/app/trp.rs | 29 | ||||
-rw-r--r-- | src/luma/emu.rs | 34 | ||||
-rw-r--r-- | src/luma/emu/btl.rs | 12 | ||||
-rw-r--r-- | src/luma/emu/drop.rs | 13 | ||||
-rw-r--r-- | src/luma/emu/img.rs | 12 | ||||
-rw-r--r-- | src/luma/emu/new.rs | 39 | ||||
-rw-r--r-- | src/luma/emu/opc.rs | 54 | ||||
-rw-r--r-- | src/luma/emu/run.rs | 35 | ||||
-rw-r--r-- | src/luma/emu/trp.rs | 45 |
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; @@ -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(®, 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}"); + } +} |