diff options
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; @@ -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(); } |