summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/luma.rs44
-rw-r--r--src/luma/application.rs34
-rw-r--r--src/luma/application/bootloader.rs12
-rw-r--r--src/luma/application/decode.rs48
-rw-r--r--src/luma/application/drop.rs29
-rw-r--r--src/luma/application/image.rs12
-rw-r--r--src/luma/application/initialise.rs55
-rw-r--r--src/luma/application/load.rs27
-rw-r--r--src/luma/application/log.rs30
-rw-r--r--src/luma/application/read.rs29
-rw-r--r--src/luma/application/run.rs38
-rw-r--r--src/luma/application/trap.rs33
-rw-r--r--src/luma/configuration.rs24
-rw-r--r--src/luma/configuration/create.rs31
-rw-r--r--src/luma/configuration/load.rs31
-rw-r--r--src/luma/configuration/new.rs23
-rw-r--r--src/luma/configuration/overwrite.rs23
-rw-r--r--src/luma/configuration/path.rs23
-rw-r--r--src/luma/device.rs62
-rw-r--r--src/luma/device/bootloader.rs33
-rw-r--r--src/luma/device/branch.rs38
-rw-r--r--src/luma/device/continue.rs32
-rw-r--r--src/luma/device/decode.rs101
-rw-r--r--src/luma/device/drop.rs34
-rw-r--r--src/luma/device/image.rs33
-rw-r--r--src/luma/device/log.rs50
-rw-r--r--src/luma/device/memory.rs30
-rw-r--r--src/luma/device/move.rs41
-rw-r--r--src/luma/device/new.rs66
-rw-r--r--src/luma/device/read.rs50
-rw-r--r--src/luma/device/store.rs50
-rw-r--r--src/luma/device/trap.rs59
-rw-r--r--src/luma/device/write.rs50
-rw-r--r--src/main.rs23
34 files changed, 1046 insertions, 252 deletions
diff --git a/src/luma.rs b/src/luma.rs
index 222e97e..a13c330 100644
--- a/src/luma.rs
+++ b/src/luma.rs
@@ -1,7 +1,29 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
pub mod application;
pub mod configuration;
+pub mod device;
pub struct VersionType<T> {
major: T,
@@ -10,27 +32,9 @@ pub struct VersionType<T> {
pub const VERSION: VersionType::<u32> = VersionType::<u32> {
major: 0x0,
- minor: 0x24,
+ minor: 0x25,
};
-#[allow(dead_code)]
-pub enum LogType {
- Branch( i32, u32),
- Continue( u32),
- Link( u32),
- Load( u8, u32),
- MoveRegister( u8, u8),
- MoveImmediate(u8, u32),
- Store( u32, u8),
-}
-
-#[allow(dead_code)]
-pub enum TrapKind {
- BadAlignment( u32, u32),
- InvalidOpcode(u32, u32),
- OutOfBounds( u32),
-}
-
pub const CONFIGURATION_VERSION: u32 = 0x0;
pub const MEMORY_SIZE: usize = 0x0E010000;
diff --git a/src/luma/application.rs b/src/luma/application.rs
index 4c34c9d..e41f75f 100644
--- a/src/luma/application.rs
+++ b/src/luma/application.rs
@@ -1,6 +1,28 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
use crate::luma::configuration::Configuration;
+use crate::luma::device::Device;
extern crate sdl2;
@@ -8,25 +30,17 @@ use sdl2::{Sdl, VideoSubsystem};
use sdl2::video::Window;
use std::sync::atomic::AtomicBool;
-pub mod bootloader;
-pub mod decode;
pub mod drop;
-pub mod image;
pub mod initialise;
pub mod load;
-pub mod log;
-pub mod read;
pub mod run;
-pub mod trap;
pub struct Application {
configuration: Configuration,
sdl: Sdl,
sdl_video: VideoSubsystem,
window: Window,
- memory: *mut u8,
- registers: [u32; 0x10],
- psr: u32,
+ device: Device,
}
pub static mut GOT_SIGNAL: AtomicBool = AtomicBool::new(false);
diff --git a/src/luma/application/bootloader.rs b/src/luma/application/bootloader.rs
deleted file mode 100644
index 2a69447..0000000
--- a/src/luma/application/bootloader.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::application::Application;
-use crate::luma::BOOTLOADER_SIZE;
-
-use std::slice;
-
-impl Application {
- 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/application/decode.rs b/src/luma/application/decode.rs
deleted file mode 100644
index bfb7765..0000000
--- a/src/luma/application/decode.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::application::Application;
-use crate::luma::{LogType, TrapKind};
-
-impl Application {
- pub fn decode(&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,
- _ => return self.trap(TrapKind::InvalidOpcode(self.registers[0xF] - 0x8, opcode)),
- };
- if !condition { return }
-
- if opcode & 0b00001110000000000000000000000000 == 0b00001010000000000000000000000000 {
- if opcode & 0b00000001000000000000000000000000 != 0x0 { // Check the L flag.
- self.registers[0xE] = self.registers[0xF] - 0x4;
-
- self.log(LogType::Link(self.registers[0xE]));
- }
-
- let offset = match opcode & 0b00000000100000000000000000000000 != 0x0 {
- false => (opcode & 0b00000000111111111111111111111111) as i32,
- true => 0x0 - (!(opcode - 0x1) & 0b00000000111111111111111111111111) as i32, // Inverted (absolute) offset.
- };
-
- (self.registers[0xF], _) = self.registers[0xF].overflowing_add_signed(offset * 0x4 + 0x8);
-
- self.log(LogType::Branch(offset, self.registers[0xF] - 0x8));
- return;
- }
-
- self.trap(TrapKind::InvalidOpcode(self.registers[0xF] - 0x8, opcode));
- }
-}
diff --git a/src/luma/application/drop.rs b/src/luma/application/drop.rs
index 5652610..9bef2c4 100644
--- a/src/luma/application/drop.rs
+++ b/src/luma/application/drop.rs
@@ -1,15 +1,30 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
-use crate::luma::application::Application;
-use crate::luma::MEMORY_SIZE;
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
-use std::alloc::{dealloc, Layout};
-use std::mem::size_of;
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::application::Application;
impl Drop for Application {
fn drop(&mut self) {
eprintln!("ending");
-
- unsafe { dealloc(self.memory, Layout::new::<[u32; MEMORY_SIZE / size_of::<u32>()]>()) };
}
}
diff --git a/src/luma/application/image.rs b/src/luma/application/image.rs
deleted file mode 100644
index 9f2aeae..0000000
--- a/src/luma/application/image.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::application::Application;
-use crate::luma::IMAGE_SIZE;
-
-use std::slice;
-
-impl Application {
- pub fn image<'a>(&mut self) -> &'a mut [u8] {
- return unsafe { slice::from_raw_parts_mut(self.memory.offset(0x08000000), IMAGE_SIZE) };
- }
-} \ No newline at end of file
diff --git a/src/luma/application/initialise.rs b/src/luma/application/initialise.rs
index 4777e51..8bf40b8 100644
--- a/src/luma/application/initialise.rs
+++ b/src/luma/application/initialise.rs
@@ -1,15 +1,36 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
-use crate::luma::{MEMORY_SIZE, SCREEN_HEIGHT, SCREEN_WIDTH};
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::{SCREEN_HEIGHT, SCREEN_WIDTH};
use crate::luma::application::{Application, GOT_SIGNAL};
use crate::luma::configuration::Configuration;
+use crate::luma::device::Device;
extern crate libc;
extern crate sdl2;
use libc::{c_int, sighandler_t, SIGINT, signal, SIGTERM};
-use std::alloc::{alloc_zeroed, Layout};
-use std::mem::{size_of, transmute};
+use std::mem::transmute;
use std::sync::atomic::Ordering;
fn signal_handler(sig: c_int) {
@@ -34,36 +55,12 @@ impl Application {
let window = sdl_video.window("luma", SCREEN_WIDTH as u32 * configuration.scale, SCREEN_HEIGHT as u32 * configuration.scale).position_centered().build().unwrap();
- 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}", memory as usize);
-
return Application {
configuration: configuration.clone(),
sdl: sdl,
sdl_video: sdl_video,
window: window,
- memory: memory,
- registers: [
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x08000008,
- ],
- psr: 0b00000000000000000000000000001111,
+ device: Device::new(),
};
}
}
diff --git a/src/luma/application/load.rs b/src/luma/application/load.rs
index bc56922..c3000ea 100644
--- a/src/luma/application/load.rs
+++ b/src/luma/application/load.rs
@@ -1,4 +1,25 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
use crate::luma::application::Application;
@@ -13,7 +34,7 @@ impl Application {
let mut bootloader = File::open(self.configuration.bootloader.clone()).expect("unable to open bootloader");
// Read bootloader:
- bootloader.read(self.bootloader()).expect("unable to read bootloader");
+ bootloader.read(self.device.bootloader()).expect("unable to read bootloader");
eprintln!("loading image \"{}\"", self.configuration.image);
@@ -21,6 +42,6 @@ impl Application {
let mut image = File::open(self.configuration.image.clone()).expect("unable to open image");
// Read image:
- image.read(self.image()).expect("unable to read image");
+ image.read(self.device.image()).expect("unable to read image");
}
}
diff --git a/src/luma/application/log.rs b/src/luma/application/log.rs
deleted file mode 100644
index 4e0eb88..0000000
--- a/src/luma/application/log.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::LogType;
-use crate::luma::application::Application;
-
-impl Application {
- pub fn log(&mut self, log_type: LogType) {
- let type_string = match log_type {
- LogType::Branch( _, _) => "branch ",
- LogType::Continue( _) => "continue",
- LogType::Link( _) => "link ",
- LogType::Load( _, _) => "load ",
- LogType::MoveRegister( _, _) => "move ",
- LogType::MoveImmediate(_, _) => "move ",
- LogType::Store( _, _) => "store ",
- };
-
- let message = match log_type {
- LogType::Branch( offset, address) => format!("pc{offset:+} => {address:#010X}"),
- LogType::Continue( address) => format!("pc => {address:#010X}"),
- LogType::Link( address) => format!("lr => {address:#010X}"),
- LogType::Load( register, address) => format!("r{register} => {address:#010X}"),
- LogType::MoveRegister( destination, source) => format!("r{destination} => r{source}"),
- LogType::MoveImmediate(register, immediate) => format!("r{register} => {immediate:#X}"),
- LogType::Store( address, register) => format!("{address:#010X} => r{register}"),
- };
-
- eprintln!("{type_string} : {message}");
- }
-}
diff --git a/src/luma/application/read.rs b/src/luma/application/read.rs
deleted file mode 100644
index 06003b7..0000000
--- a/src/luma/application/read.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::application::Application;
-use crate::luma::{MEMORY_SIZE, TrapKind};
-
-impl Application {
- #[allow(dead_code)]
- pub fn read_byte(&mut self, address: u32) -> u8 {
- if address >= MEMORY_SIZE as u32 { self.trap(TrapKind::OutOfBounds(address)) };
-
- 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(address)) };
- if address % 0x2 != 0x0 { self.trap(TrapKind::BadAlignment(address, 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(address)) };
- if address % 0x4 != 0x0 { self.trap(TrapKind::BadAlignment(address, 0x4)) };
-
- return unsafe { *(self.memory.offset(address as isize) as *mut u32) };
- }
-}
diff --git a/src/luma/application/run.rs b/src/luma/application/run.rs
index 8f7368a..14ab560 100644
--- a/src/luma/application/run.rs
+++ b/src/luma/application/run.rs
@@ -1,6 +1,27 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
-use crate::luma::{LogType, VERSION};
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::VERSION;
use crate::luma::application::{Application, GOT_SIGNAL};
use sdl2::event::Event;
@@ -19,9 +40,7 @@ impl Application {
let mut event_pump = self.sdl.event_pump().expect("unable to get event pump");
- eprintln!("starting emulation at {:#010X}",self.registers[0xF] - 0x8);
-
- 'main_loop: loop {
+ 'main_loop: for cycle in 0x0..u64::MAX {
// Check if we have recieved a signal:
if unsafe { GOT_SIGNAL.load(Ordering::Relaxed) } {
eprintln!("got interrupt");
@@ -36,13 +55,8 @@ impl Application {
}
}
- // Decode opcode:
- let opcode = self.read_word(self.registers[0xF] - 0x8);
- self.decode(opcode);
-
- // Continue:
- self.registers[0xF] += 0x4;
- self.log(LogType::Continue(self.registers[0xF]));
+ eprintln!("({cycle})");
+ self.device.decode();
sleep(Duration::from_secs(0x1));
}
diff --git a/src/luma/application/trap.rs b/src/luma/application/trap.rs
deleted file mode 100644
index f96ccbc..0000000
--- a/src/luma/application/trap.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2021-2023 Gabriel Jensen.
-
-use crate::luma::{MEMORY_SIZE, TrapKind};
-use crate::luma::application::Application;
-
-impl Application {
- pub fn trap(&mut self, kind: TrapKind) {
- let message = match kind {
- TrapKind::BadAlignment( address, alignment) => format!("bad alignment of address {address:#010X} (should be {alignment}-byte aligned)"),
- TrapKind::InvalidOpcode(address, opcode) => format!("invalid opcode {opcode:#010X} at {address:#010X}"),
- TrapKind::OutOfBounds( address) => format!("out-of-bounds address {address:#010X} (limit is {MEMORY_SIZE:#010X})"),
- };
-
- eprintln!("trap - {message}");
- eprintln!("\tr0: {:#010X}", self.registers[0x0]);
- eprintln!("\tr1: {:#010X}", self.registers[0x1]);
- eprintln!("\tr2: {:#010X}", self.registers[0x2]);
- eprintln!("\tr3: {:#010X}", self.registers[0x3]);
- eprintln!("\tr4: {:#010X}", self.registers[0x4]);
- eprintln!("\tr5: {:#010X}", self.registers[0x5]);
- eprintln!("\tr6: {:#010X}", self.registers[0x6]);
- eprintln!("\tr7: {:#010X}", self.registers[0x7]);
- eprintln!("\tr8: {:#010X}", self.registers[0x8]);
- eprintln!("\tr9: {:#010X}", self.registers[0x9]);
- eprintln!("\tr10: {:#010X}", self.registers[0xA]);
- eprintln!("\tr11: {:#010X}", self.registers[0xB]);
- eprintln!("\tr12: {:#010X}", self.registers[0xC]);
- eprintln!("\tsp: {:#010X}", self.registers[0xD]);
- eprintln!("\tlr: {:#010X}", self.registers[0xE]);
- eprintln!("\tpc: {:#010X}", self.registers[0xF]);
- eprintln!("\tcpsr: {:#034b}", self.psr);
- }
-}
diff --git a/src/luma/configuration.rs b/src/luma/configuration.rs
index efad017..20a858f 100644
--- a/src/luma/configuration.rs
+++ b/src/luma/configuration.rs
@@ -1,5 +1,27 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+pub mod create;
pub mod load;
pub mod new;
pub mod overwrite;
diff --git a/src/luma/configuration/create.rs b/src/luma/configuration/create.rs
new file mode 100644
index 0000000..96fb25d
--- /dev/null
+++ b/src/luma/configuration/create.rs
@@ -0,0 +1,31 @@
+// Copyright 2021-2023 Gabriel Jensen.
+
+use crate::luma::CONFIGURATION_VERSION;
+use crate::luma::configuration::Configuration;
+
+use std::fs::write;
+
+impl Configuration {
+ pub(super) fn create(&mut self) {
+ let configuration_path = Configuration::path();
+
+ eprintln!("creating configuration at {configuration_path}");
+
+ let default_configuration = format!(
+ "# This is the default configuration for the\n\
+ # Luma emulator.\n\
+ \n\
+ [luma]\n\
+ version = {CONFIGURATION_VERSION}\n\
+ \n\
+ [device]\n\
+ #bootloader = \"\"\n\
+ #image = \"\"\n\
+ \n\
+ [video]\n\
+ scale = 1\n"
+ );
+
+ write(configuration_path, default_configuration).unwrap();
+ }
+}
diff --git a/src/luma/configuration/load.rs b/src/luma/configuration/load.rs
index fd425d4..dac8570 100644
--- a/src/luma/configuration/load.rs
+++ b/src/luma/configuration/load.rs
@@ -1,4 +1,25 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
use crate::luma::CONFIGURATION_VERSION;
use crate::luma::configuration::Configuration;
@@ -39,7 +60,13 @@ impl Configuration {
eprintln!("loading configuration \"{configuration_path}\"");
- let contents = read_to_string(configuration_path).expect("unable to read configuration file");
+ let contents = match read_to_string(configuration_path) {
+ Ok( contents) => contents,
+ Err(_) => {
+ eprintln!("unable to read configuration file");
+ return self.create();
+ },
+ };
let configuration: Container = toml::from_str(contents.as_str()).expect("unable to parse configuration file");
diff --git a/src/luma/configuration/new.rs b/src/luma/configuration/new.rs
index 5742dd2..eea03a9 100644
--- a/src/luma/configuration/new.rs
+++ b/src/luma/configuration/new.rs
@@ -1,4 +1,25 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
use crate::luma::configuration::Configuration;
diff --git a/src/luma/configuration/overwrite.rs b/src/luma/configuration/overwrite.rs
index ab55ff3..3c06259 100644
--- a/src/luma/configuration/overwrite.rs
+++ b/src/luma/configuration/overwrite.rs
@@ -1,4 +1,25 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
use crate::luma::configuration::Configuration;
diff --git a/src/luma/configuration/path.rs b/src/luma/configuration/path.rs
index a1ff3fd..63b3ccd 100644
--- a/src/luma/configuration/path.rs
+++ b/src/luma/configuration/path.rs
@@ -1,4 +1,25 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
use crate::luma::configuration::Configuration;
diff --git a/src/luma/device.rs b/src/luma/device.rs
new file mode 100644
index 0000000..2a0e503
--- /dev/null
+++ b/src/luma/device.rs
@@ -0,0 +1,62 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+pub mod bootloader;
+pub mod branch;
+pub mod r#continue;
+pub mod decode;
+pub mod drop;
+pub mod image;
+pub mod store;
+pub mod log;
+pub mod memory;
+pub mod r#move;
+pub mod new;
+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),
+}
+
+#[allow(dead_code)]
+pub enum Trap {
+ BadAlignment( u32, u32),
+ InvalidOpcode(u32, u32),
+ OutOfBounds( u32),
+}
+
+pub struct Device {
+ memory: *mut u8,
+ registers: [u32; 0x10],
+ cpsr: u32,
+ spsr: [u32; 0x10], // We don't actually use all sixteen, we just have this many to enable us to directly use the mode number as the offset.
+}
diff --git a/src/luma/device/bootloader.rs b/src/luma/device/bootloader.rs
new file mode 100644
index 0000000..4af66fd
--- /dev/null
+++ b/src/luma/device/bootloader.rs
@@ -0,0 +1,33 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::Device;
+use crate::luma::BOOTLOADER_SIZE;
+
+use std::slice;
+
+impl Device {
+ 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/device/branch.rs b/src/luma/device/branch.rs
new file mode 100644
index 0000000..5654763
--- /dev/null
+++ b/src/luma/device/branch.rs
@@ -0,0 +1,38 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::{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]));
+ }
+
+ (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));
+ }
+}
diff --git a/src/luma/device/continue.rs b/src/luma/device/continue.rs
new file mode 100644
index 0000000..5aabbb8
--- /dev/null
+++ b/src/luma/device/continue.rs
@@ -0,0 +1,32 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::{Device, Log};
+
+impl Device {
+ pub fn r#continue(&mut self) {
+ self.registers[0xF] += 0x4;
+
+ self.log(Log::Continue(self.registers[0xF]));
+ }
+}
diff --git a/src/luma/device/decode.rs b/src/luma/device/decode.rs
new file mode 100644
index 0000000..bb31d62
--- /dev/null
+++ b/src/luma/device/decode.rs
@@ -0,0 +1,101 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::{Device, Trap};
+
+impl Device {
+ pub fn decode(&mut self) {
+ let opcode = self.read_word(self.registers[0xF] - 0x8);
+
+ let condition = match opcode & 0b11110000000000000000000000000000 {
+ 0b00000000000000000000000000000000 => self.cpsr & 0b01000000000000000000000000000000 != 0x00,
+ 0b00010000000000000000000000000000 => self.cpsr & 0b01000000000000000000000000000000 == 0x00,
+ 0b00100000000000000000000000000000 => self.cpsr & 0b00100000000000000000000000000000 != 0x00,
+ 0b00110000000000000000000000000000 => self.cpsr & 0b00100000000000000000000000000000 == 0x00,
+ 0b01000000000000000000000000000000 => self.cpsr & 0b10000000000000000000000000000000 != 0x00,
+ 0b01010000000000000000000000000000 => self.cpsr & 0b10000000000000000000000000000000 == 0x00,
+ 0b01100000000000000000000000000000 => self.cpsr & 0b00010000000000000000000000000000 != 0x00,
+ 0b01110000000000000000000000000000 => self.cpsr & 0b00010000000000000000000000000000 == 0x00,
+ 0b10000000000000000000000000000000 => self.cpsr & 0b00100000000000000000000000000000 != 0x00 && self.cpsr & 0b01000000000000000000000000000000 == 0x00,
+ 0b10010000000000000000000000000000 => self.cpsr & 0b00100000000000000000000000000000 == 0x00 && self.cpsr & 0b01000000000000000000000000000000 != 0x00,
+ 0b10100000000000000000000000000000 => self.cpsr & 0b00010000000000000000000000000000 >> 0x1C == self.cpsr & 0b10000000000000000000000000000000 >> 0x1F,
+ 0b10110000000000000000000000000000 => self.cpsr & 0b00010000000000000000000000000000 >> 0x1C != self.cpsr & 0b10000000000000000000000000000000 >> 0x1F,
+ 0b11000000000000000000000000000000 => self.cpsr & 0b01000000000000000000000000000000 == 0x00 && self.cpsr & 0b00010000000000000000000000000000 >> 0x1C == self.cpsr & 0b10000000000000000000000000000000 >> 0x1F,
+ 0b11010000000000000000000000000000 => self.cpsr & 0b01000000000000000000000000000000 != 0x00 || self.cpsr & 0b00010000000000000000000000000000 >> 0x1C != self.cpsr & 0b10000000000000000000000000000000 >> 0x1F,
+ 0b11100000000000000000000000000000 => true,
+ _ => return self.trap(Trap::InvalidOpcode(self.registers[0xF] - 0x8, opcode)),
+ };
+ if !condition { return self.r#continue() }
+
+ // load/store
+ 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;
+
+ self.store(register, base, immediate, u, b, l);
+ return self.r#continue();
+ }
+
+ // move
+ if opcode & 0b00001101111111100000111111110000 == 0b00000001101000000000000000000000 {
+ let destination = ((opcode & 0b00000000000000001111000000000000) >> 0xC) as u8;
+ let source = (opcode & 0b00000000000000000000000000001111) as u8;
+
+ let value = self.registers[source as usize];
+ self.registers[destination as usize] = value;
+
+ let s = opcode & 0b00000000000100000000000000000000 != 0x0;
+
+ self.r#move(destination, source, s);
+ 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();
+ }
+}
diff --git a/src/luma/device/drop.rs b/src/luma/device/drop.rs
new file mode 100644
index 0000000..6bb694b
--- /dev/null
+++ b/src/luma/device/drop.rs
@@ -0,0 +1,34 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::Device;
+use crate::luma::MEMORY_SIZE;
+
+use std::alloc::{dealloc, Layout};
+use std::mem::size_of;
+
+impl Drop for Device {
+ fn drop(&mut self) {
+ unsafe { dealloc(self.memory, Layout::new::<[u32; MEMORY_SIZE / size_of::<u32>()]>()) };
+ }
+}
diff --git a/src/luma/device/image.rs b/src/luma/device/image.rs
new file mode 100644
index 0000000..5fbb0be
--- /dev/null
+++ b/src/luma/device/image.rs
@@ -0,0 +1,33 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::Device;
+use crate::luma::IMAGE_SIZE;
+
+use std::slice;
+
+impl Device {
+ pub fn image<'a>(&mut self) -> &'a mut [u8] {
+ return unsafe { slice::from_raw_parts_mut(self.memory.offset(0x08000000), IMAGE_SIZE) };
+ }
+} \ No newline at end of file
diff --git a/src/luma/device/log.rs b/src/luma/device/log.rs
new file mode 100644
index 0000000..72b7982
--- /dev/null
+++ b/src/luma/device/log.rs
@@ -0,0 +1,50 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+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}");
+ }
+}
diff --git a/src/luma/device/memory.rs b/src/luma/device/memory.rs
new file mode 100644
index 0000000..f13e56b
--- /dev/null
+++ b/src/luma/device/memory.rs
@@ -0,0 +1,30 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::Device;
+
+impl Device {
+ pub fn memory(&mut self) -> *const u8{
+ return self.memory as *const u8;
+ }
+} \ No newline at end of file
diff --git a/src/luma/device/move.rs b/src/luma/device/move.rs
new file mode 100644
index 0000000..ba67146
--- /dev/null
+++ b/src/luma/device/move.rs
@@ -0,0 +1,41 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::{Device, Log};
+
+impl Device {
+ pub fn r#move(&mut self, destination: u8, source: u8, s: bool) {
+ let value = self.registers[source as usize];
+ self.registers[destination as usize] = value;
+
+ if s { // Check the s flag.
+ if destination == 0xF {
+ self.cpsr = self.spsr[(self.cpsr & 0b00000000000000000000000000001111) as usize]; // We ignore the fifth bit, as this is always set.
+ } else {
+ // TO-DO
+ }
+ }
+
+ self.log(Log::MoveRegister(destination, source, value));
+ }
+} \ No newline at end of file
diff --git a/src/luma/device/new.rs b/src/luma/device/new.rs
new file mode 100644
index 0000000..59a3380
--- /dev/null
+++ b/src/luma/device/new.rs
@@ -0,0 +1,66 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::MEMORY_SIZE;
+use crate::luma::device::Device;
+
+use std::alloc::{alloc_zeroed, Layout};
+use std::mem::size_of;
+
+impl Device {
+ pub fn new() -> Device {
+ eprintln!("creating new device");
+
+ 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}", memory as usize);
+
+ let start = 0x08000008;
+ eprintln!("starting emulation at {start:#08X}");
+
+ return Device {
+ memory: memory,
+ registers: [
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ start,
+ ],
+ cpsr: 0b00000000000000000000000000001111,
+ spsr: [0b00000000000000000000000000000000; 0x10],
+ };
+ }
+}
diff --git a/src/luma/device/read.rs b/src/luma/device/read.rs
new file mode 100644
index 0000000..0724075
--- /dev/null
+++ b/src/luma/device/read.rs
@@ -0,0 +1,50 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::{Device, Trap};
+use crate::luma::MEMORY_SIZE;
+
+impl Device {
+ #[allow(dead_code)]
+ pub fn read_byte(&mut self, address: u32) -> u8 {
+ if address >= MEMORY_SIZE as u32 { self.trap(Trap::OutOfBounds(address)) };
+
+ 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(Trap::OutOfBounds(address)) };
+ if address % 0x2 != 0x0 { self.trap(Trap::BadAlignment(address, 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(Trap::OutOfBounds(address)) };
+ if address % 0x4 != 0x0 { self.trap(Trap::BadAlignment(address, 0x4)) };
+
+ return unsafe { *(self.memory.offset(address as isize) as *mut u32) };
+ }
+}
diff --git a/src/luma/device/store.rs b/src/luma/device/store.rs
new file mode 100644
index 0000000..21fb3a7
--- /dev/null
+++ b/src/luma/device/store.rs
@@ -0,0 +1,50 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::{Device, Log};
+
+impl Device {
+ pub fn store(&mut self, register: u8, base: u8, immediate: u16, u: bool, _b: bool, l: bool) {
+ // TO-DO: Byte loads/stores.
+
+ let offset = if u {
+ 0x0 + immediate as i32
+ } else {
+ 0x0 - immediate as i32
+ };
+
+ let (address, _) = self.registers[base as usize].overflowing_add_signed(offset);
+
+ if l { // Check the l flag.
+ let value = self.read_word(address);
+ self.registers[register as usize] = value;
+
+ self.log(Log::Load(register, address, base, offset, value));
+ } else {
+ let value = self.registers[register as usize];
+ self.write_word(address, value);
+
+ self.log(Log::Store(address, register, base, offset, value));
+ }
+ }
+}
diff --git a/src/luma/device/trap.rs b/src/luma/device/trap.rs
new file mode 100644
index 0000000..8af3622
--- /dev/null
+++ b/src/luma/device/trap.rs
@@ -0,0 +1,59 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::MEMORY_SIZE;
+use crate::luma::device::{Device, Trap};
+
+impl Device {
+ pub fn trap(&mut self, kind: Trap) {
+ let message = match kind {
+ Trap::BadAlignment( address, alignment) => format!("bad alignment of address {address:#010X} (should be {alignment}-byte aligned)"),
+ Trap::InvalidOpcode(address, opcode) => format!("invalid opcode {opcode:#034b} at {address:#010X}"),
+ Trap::OutOfBounds( address) => format!("out-of-bounds address {address:#010X} (limit is {MEMORY_SIZE:#010X})"),
+ };
+
+ eprintln!("{message}");
+ eprintln!(" r0: {:#010X}", self.registers[0x0]);
+ eprintln!(" r1: {:#010X}", self.registers[0x1]);
+ eprintln!(" r2: {:#010X}", self.registers[0x2]);
+ eprintln!(" r3: {:#010X}", self.registers[0x3]);
+ eprintln!(" r4: {:#010X}", self.registers[0x4]);
+ eprintln!(" r5: {:#010X}", self.registers[0x5]);
+ eprintln!(" r6: {:#010X}", self.registers[0x6]);
+ eprintln!(" r7: {:#010X}", self.registers[0x7]);
+ eprintln!(" r8: {:#010X}", self.registers[0x8]);
+ eprintln!(" r9: {:#010X}", self.registers[0x9]);
+ eprintln!(" r10: {:#010X}", self.registers[0xA]);
+ eprintln!(" r11: {:#010X}", self.registers[0xB]);
+ eprintln!(" r12: {:#010X}", self.registers[0xC]);
+ eprintln!(" r13: {:#010X}", self.registers[0xD]);
+ eprintln!(" r14: {:#010X}", self.registers[0xE]);
+ eprintln!(" r15: {:#010X}", self.registers[0xF]);
+ eprintln!(" cpsr: {:#034b}", self.cpsr);
+ eprintln!(" spsr_fiq: {:#034b}", self.spsr[0x1]);
+ eprintln!(" spsr_irq: {:#034b}", self.spsr[0x2]);
+ eprintln!(" spsr_svc: {:#034b}", self.spsr[0x3]);
+ eprintln!(" spsr_abt: {:#034b}", self.spsr[0x7]);
+ eprintln!(" spsr_und: {:#034b}", self.spsr[0xB]);
+ }
+}
diff --git a/src/luma/device/write.rs b/src/luma/device/write.rs
new file mode 100644
index 0000000..e234bef
--- /dev/null
+++ b/src/luma/device/write.rs
@@ -0,0 +1,50 @@
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
+
+use crate::luma::device::{Device, Trap};
+use crate::luma::MEMORY_SIZE;
+
+impl Device {
+ #[allow(dead_code)]
+ pub fn write_byte(&mut self, address: u32, value: u8) {
+ if address >= MEMORY_SIZE as u32 { self.trap(Trap::OutOfBounds(address)) };
+
+ return unsafe { *(self.memory.offset(address as isize) as *mut u8) = value };
+ }
+
+ #[allow(dead_code)]
+ pub fn write_halfword(&mut self, address: u32, value: u16) {
+ if address >= MEMORY_SIZE as u32 { self.trap(Trap::OutOfBounds(address)) };
+ if address % 0x2 != 0x0 { self.trap(Trap::BadAlignment(address, 0x2)) };
+
+ return unsafe { *(self.memory.offset(address as isize) as *mut u16) = value };
+ }
+
+ #[allow(dead_code)]
+ pub fn write_word(&mut self, address: u32, value: u32) {
+ if address >= MEMORY_SIZE as u32 { self.trap(Trap::OutOfBounds(address)) };
+ if address % 0x4 != 0x0 { self.trap(Trap::BadAlignment(address, 0x4)) };
+
+ return unsafe { *(self.memory.offset(address as isize) as *mut u32) = value };
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 4ad9cf9..1d45ca3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,25 @@
-// Copyright 2021-2023 Gabriel Jensen.
+/*
+ Copyright 2021-2023 Gabriel Jensen.
+
+ This file is part of Luma.
+
+ Luma is free software: you can redistribute it
+ and/or modify it under the terms of the GNU
+ Affero General Public License as published by
+ the Free Software Foundation, either version 3
+ of the License, or (at your option) any later
+ version.
+
+ Luma is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even
+ the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU
+ Affero General Public License along with Luma. If not,
+ see <https://www.gnu.org/licenses/>.
+*/
mod luma;