diff options
Diffstat (limited to 'src')
38 files changed, 1131 insertions, 514 deletions
diff --git a/src/luma.rs b/src/luma.rs index 16c1941..6830045 100644 --- a/src/luma.rs +++ b/src/luma.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; @@ -32,9 +32,14 @@ pub struct VersionType<T> { pub const VERSION: VersionType::<u32> = VersionType::<u32> { major: 0x0, - minor: 0x29, + minor: 0x2A, }; +pub struct WidthHeight<T> { + width: T, + height: T, +} + pub const CONFIGURATION_VERSION: u32 = 0x0; pub const MEMORY_SIZE: usize = 0x0E010000; @@ -42,5 +47,7 @@ pub const MEMORY_SIZE: usize = 0x0E010000; pub const BOOTLOADER_SIZE: usize = 0x00004000; pub const IMAGE_SIZE: usize = 0x02000000; -pub const SCREEN_WIDTH: u8 = 0xF0; -pub const SCREEN_HEIGHT: u8 = 0xA0; +pub const SCREEN_SIZE: WidthHeight::<u8> = WidthHeight::<u8> { + width: 0xF0, + height: 0xA0, +}; diff --git a/src/luma/application.rs b/src/luma/application.rs index e41f75f..7894b29 100644 --- a/src/luma/application.rs +++ b/src/luma/application.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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/application/drop.rs b/src/luma/application/drop.rs index 9bef2c4..a5ad544 100644 --- a/src/luma/application/drop.rs +++ b/src/luma/application/drop.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; diff --git a/src/luma/application/initialise.rs b/src/luma/application/initialise.rs index 8bf40b8..02b05bf 100644 --- a/src/luma/application/initialise.rs +++ b/src/luma/application/initialise.rs @@ -3,25 +3,25 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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::{SCREEN_SIZE}; use crate::luma::application::{Application, GOT_SIGNAL}; use crate::luma::configuration::Configuration; use crate::luma::device::Device; @@ -53,7 +53,7 @@ impl Application { let sdl = sdl2::init().expect("unable to initialise sdl2"); let sdl_video = sdl.video().expect("unable to initialise sdl2"); - let window = sdl_video.window("luma", SCREEN_WIDTH as u32 * configuration.scale, SCREEN_HEIGHT as u32 * configuration.scale).position_centered().build().unwrap(); + let window = sdl_video.window("luma", SCREEN_SIZE.width as u32 * configuration.scale, SCREEN_SIZE.height as u32 * configuration.scale).position_centered().build().unwrap(); return Application { configuration: configuration.clone(), diff --git a/src/luma/application/load.rs b/src/luma/application/load.rs index c3000ea..338f120 100644 --- a/src/luma/application/load.rs +++ b/src/luma/application/load.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; diff --git a/src/luma/application/run.rs b/src/luma/application/run.rs index 9cba12c..2e47712 100644 --- a/src/luma/application/run.rs +++ b/src/luma/application/run.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; @@ -59,7 +59,7 @@ impl Application { (self.device.decode)(&mut self.device); - sleep(Duration::from_secs(0x1)); + sleep(Duration::from_millis(250)); } } } diff --git a/src/luma/configuration.rs b/src/luma/configuration.rs index 20a858f..17e7221 100644 --- a/src/luma/configuration.rs +++ b/src/luma/configuration.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; diff --git a/src/luma/configuration/create.rs b/src/luma/configuration/create.rs index 96fb25d..143fbac 100644 --- a/src/luma/configuration/create.rs +++ b/src/luma/configuration/create.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; diff --git a/src/luma/configuration/load.rs b/src/luma/configuration/load.rs index dac8570..d08bcd5 100644 --- a/src/luma/configuration/load.rs +++ b/src/luma/configuration/load.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; @@ -64,7 +64,7 @@ impl Configuration { Ok( contents) => contents, Err(_) => { eprintln!("unable to read configuration file"); - return self.create(); + return self.create(); }, }; diff --git a/src/luma/configuration/new.rs b/src/luma/configuration/new.rs index eea03a9..7875d64 100644 --- a/src/luma/configuration/new.rs +++ b/src/luma/configuration/new.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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 3c06259..2d37c55 100644 --- a/src/luma/configuration/overwrite.rs +++ b/src/luma/configuration/overwrite.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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 63b3ccd..19d8145 100644 --- a/src/luma/configuration/path.rs +++ b/src/luma/configuration/path.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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 index c3d5092..30f1bb1 100644 --- a/src/luma/device.rs +++ b/src/luma/device.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; @@ -30,11 +30,17 @@ pub mod decode_thumb; pub mod drop; pub mod exchange; pub mod image; +pub mod interrupt; +pub mod link; +pub mod load; pub mod log; pub mod memory; pub mod r#move; pub mod new; +pub mod pop; +pub mod push; pub mod read; +pub mod shift; pub mod store; pub mod thumb; pub mod trap; @@ -47,9 +53,18 @@ pub enum Trap { OutOfBounds( u32), } -pub enum Branch { - Offset( i32, bool), - Register(u8), +pub enum Log { + Branch, + Continue, + Exchange, + Interrupt, + Link, + Load, + Move, + Pop, + Push, + Shift, + Store, } pub enum Move { @@ -58,8 +73,8 @@ pub enum Move { } pub struct Device { - pub decode: fn(&mut Device), - + pub decode: fn(&mut Device), + memory: *mut u8, registers: [u32; 0x10], cpsr: u32, diff --git a/src/luma/device/bootloader.rs b/src/luma/device/bootloader.rs index 4af66fd..2f84f70 100644 --- a/src/luma/device/bootloader.rs +++ b/src/luma/device/bootloader.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; diff --git a/src/luma/device/branch.rs b/src/luma/device/branch.rs index 6bc2320..0bed178 100644 --- a/src/luma/device/branch.rs +++ b/src/luma/device/branch.rs @@ -3,83 +3,107 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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::{Branch, Device}; +use crate::luma::device::{Device, Log}; impl Device { - pub fn branch(&mut self, kind: Branch) { - match kind { - Branch::Offset(offset, l) => { - if l { // Check the l flag. - // Store the address of the following instruction - // in r14 (lr). - - let pc_offset: u32 = match self.thumb() { - false => 0x4, - true => 0x2, - }; - - self.registers[0xE] = self.registers[0xF] - pc_offset; - - self.log("link", format!("r14 => r15-{pc_offset}={:#010X}", self.registers[0xE])); - } - - // Add the offset to r15 (pc). - - let (address, _) = self.registers[0xF].overflowing_add_signed(offset); - - // Add extra offset to move to the new fetch - // instruction. - let pc_offset = match self.thumb() { - false => 0x8, - true => 0x4, - }; - - self.registers[0xF] = address + pc_offset; - - self.log("branch", format!("r15 => r15{offset:+}+{pc_offset} ({:#010X})", self.registers[0xF])); - }, - Branch::Register(register) => { - // Use the address stored in 'register' as the new - // value in r15 (pc). - - let value = self.registers[register as usize]; - - let t = value & 0b00000000000000000000000000000001 != 0x0; - - self.cpsr = self.cpsr & 0b11111111111111111111111111011111 | (t as u32) << 0x5; - self.exchange(t); - - let address = value & 0b11111111111111111111111111111110; - - // Add extra offset to move to the new fetch - // instruction. - let pc_offset: u32 = match t { - false => 0x8, - true => 0x4, - }; - - self.registers[0xF] = address + pc_offset; - - self.log("branch", format!("r15 => r{register}{pc_offset:+} ({:#010X})", self.registers[0xF])); - }, - } + pub fn arm_branch(&mut self, offset: i32, l: bool) { + // Add the offset to r15 (pc). Conditionally link. + + if l { self.arm_link() } + + let (address, _) = self.registers[0xF].overflowing_add_signed(offset); + + // Add extra offset to move to the new fetch + // instruction. + self.registers[0xF] = address + 0x8; + + self.log(Log::Branch, format!("pc => pc{offset:+}+8 ({:#010X})", self.registers[0xF])); + } + + pub fn arm_branch_exchange(&mut self, register: u8) { + // Use the address stored in 'register' as the new + // value in r15 (pc). + + let value = self.registers[register as usize]; + + let t = value & 0b00000000000000000000000000000001 != 0x0; + + self.cpsr = self.cpsr & 0b11111111111111111111111111011111 | (t as u32) << 0x5; + self.exchange(t); + + // Add extra offset to move to the new fetch + // instruction. + let pc_offset: u32 = match t { + false => 0x8, + true => 0x4, + }; + + self.registers[0xF] = (value & 0b11111111111111111111111111111110) + pc_offset; + + self.log(Log::Branch, format!("pc => r{register}{pc_offset:+} ({:#010X})", self.registers[0xF])); + } + + pub fn thumb_branch(&mut self, offset: i32) { + let (address, _) = self.registers[0xF].overflowing_add_signed(offset); + + self.registers[0xF] = address + 0x4; + + self.log(Log::Branch, format!("pc => pc{offset:+}+4 ({:#010X})", self.registers[0xF])); } + + pub fn thumb_branch_exchange(&mut self, register: u8) { + let value = self.registers[register as usize]; + + let t = value & 0b00000000000000000000000000000001 != 0x0; + + self.cpsr = self.cpsr & 0b11111111111111111111111111011111 | (t as u32) << 0x5; + self.exchange(t); + + // Add extra offset to move to the new fetch + // instruction. + let pc_offset: u32 = match t { + false => 0x8, + true => 0x4, + }; + + self.registers[0xF] = (value & 0b11111111111111111111111111111110) + pc_offset; + + self.log(Log::Branch, format!("pc => r{register}{pc_offset:+} ({:#010X})", self.registers[0xF])); + } + + pub fn thumb_branch_link0(&mut self, offset: i32) { + let (address, _) = self.registers[0xF].overflowing_add_signed(offset); + self.registers[0xE] = address; + + self.log(Log::Branch, format!("lr => pc{offset:+}+4 ({:#010X})", self.registers[0xF])); + } + + pub fn thumb_branch_link1(&mut self, offset: i32) { + let (address, _) = self.registers[0xE].overflowing_add_signed(offset); + + self.thumb_link(); + + (self.registers[0xF], _) = address.overflowing_add(0x4); + + self.log(Log::Branch, format!("pc => pc{offset:+}+4 ({:#010X})", self.registers[0xF])); + } + } diff --git a/src/luma/device/check_condition.rs b/src/luma/device/check_condition.rs index b202448..7b84d8a 100644 --- a/src/luma/device/check_condition.rs +++ b/src/luma/device/check_condition.rs @@ -3,28 +3,46 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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 check_condition(&self, condition: u8) -> bool { + // Code Id. Predicates + // 0 eq Z==1 + // 1 ne Z==0 + // 2 cs, hs C==1 + // 3 cc, lo C==0 + // 4 mi N==1 + // 5 pl N==0 + // 6 vs V==1 + // 7 vc V==0 + // 8 hi C==1 && Z==0 + // 9 ls C==0 && Z==1 + // A ge N==V + // B lt N!=V + // C gt Z==0 && N==V + // D le Z==1 && N!=V + // E al true + // F nv false + return match condition { 0x0 => self.cpsr & 0b01000000000000000000000000000000 != 0x00, 0x1 => self.cpsr & 0b01000000000000000000000000000000 == 0x00, @@ -41,7 +59,7 @@ impl Device { 0xC => self.cpsr & 0b01000000000000000000000000000000 == 0x00 && self.cpsr & 0b00010000000000000000000000000000 >> 0x1C == self.cpsr & 0b10000000000000000000000000000000 >> 0x1F, 0xD => self.cpsr & 0b01000000000000000000000000000000 != 0x00 || self.cpsr & 0b00010000000000000000000000000000 >> 0x1C != self.cpsr & 0b10000000000000000000000000000000 >> 0x1F, 0xE => true, - 0xF => false, // Unpredictable, but we ignore it. + 0xF => false, _ => unreachable!(), } } diff --git a/src/luma/device/continue.rs b/src/luma/device/continue.rs index e1f43ec..519cf81 100644 --- a/src/luma/device/continue.rs +++ b/src/luma/device/continue.rs @@ -3,36 +3,42 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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::device::{Device, Log}; impl Device { - pub fn r#continue(&mut self) { - let offset = if self.thumb() { - 0x2 - } else { - 0x4 - }; + pub fn arm_continue(&mut self) { + // Increment the program counter by one + // instruction. - self.registers[0xF] += offset; + (self.registers[0xF], _) = self.registers[0xF].overflowing_add(0x4); - self.log("continue", format!("r15 => r15{offset:+}={:#010X}", self.registers[0xF])); + self.log(Log::Continue, format!("pc => pc+4={:#010X}", self.registers[0xF])); + } + + pub fn thumb_continue(&mut self) { + // Increment the program counter by one + // instruction. + + (self.registers[0xF], _) = self.registers[0xF].overflowing_add(0x2); + + self.log(Log::Continue, format!("pc => pc+2={:#010X}", self.registers[0xF])); } } diff --git a/src/luma/device/decode_arm.rs b/src/luma/device/decode_arm.rs index 4aa3216..3cd0ed9 100644 --- a/src/luma/device/decode_arm.rs +++ b/src/luma/device/decode_arm.rs @@ -3,94 +3,105 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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::{Branch, Device, Move, Trap}; +use crate::luma::device::{Device, Move, Trap}; impl Device { pub fn decode_arm(&mut self) { debug_assert!(!self.thumb()); - let address = self.registers[0xF] - 0x8; + let (address, _) = self.registers[0xF].overflowing_sub(0x8); let opcode = self.read_word(address); if cfg!(debug_assertions) { eprintln!("{opcode:#034b} @ {address:#010X}") } - let condition = ((opcode & 0b11110000000000000000000000000000) >> 0x1C) as u8; - if !self.check_condition(condition) { return self.r#continue() } - - // b{cond}{l} +/-offset_24 + // b{cond}{l} Offset24 if opcode & 0b00001110000000000000000000000000 == 0b00001010000000000000000000000000 { - let link = opcode & 0b00000001000000000000000000000000 != 0x0; - - let offset = { - let mut offset = opcode & 0b00000000111111111111111111111111; + let condition = ((opcode & 0b11110000000000000000000000000000) >> 0x1C) as u8; + if !self.check_condition(condition) { return self.arm_continue() } - if offset & 0b00000000100000000000000000000000 != 0x0 { offset |= 0b00111111000000000000000000000000 } // Sign-extend. + let immediate = opcode & 0b00000000111111111111111111111111; - offset <<= 0x2; + let l = opcode & 0b00000001000000000000000000000000 != 0x0; - offset as i32 - }; + let offset = ((immediate << 0x8) as i32) >> 0x6; - return self.branch(Branch::Offset(offset, link)); + return self.arm_branch(offset, l); } // bx{cond} Rm if opcode & 0b00001111111111111111111111110000 == 0b00000001001011111111111100010000 { + let condition = ((opcode & 0b11110000000000000000000000000000) >> 0x1C) as u8; + if !self.check_condition(condition) { return self.arm_continue() } + let register = (opcode & 0b00000000000000000000000000001111) as u8; - return self.branch(Branch::Register(register)); + return self.arm_branch_exchange(register); } - // ldr|str{cond}{b} Rn, +/-offset_12 + // ldr|str{cond}{b} Rd, [Rn, Offset12] if opcode & 0b00001111001000000000000000000000 == 0b00000101000000000000000000000000 { - let register = ((opcode & 0b00000000000000001111000000000000) >> 0xC) as u8; - - let base = ((opcode & 0b00000000000011110000000000000000) >> 0x10) as u8; + let condition = ((opcode & 0b11110000000000000000000000000000) >> 0x1C) as u8; + if !self.check_condition(condition) { return self.arm_continue() } let immediate = (opcode & 0b00000000000000000000111111111111) as u16; - let u = opcode & 0b00000000100000000000000000000000 != 0x0; - let b = opcode & 0b00000000010000000000000000000000 != 0x0; + let register = ((opcode & 0b00000000000000001111000000000000) >> 0xC) as u8; + + let base = ((opcode & 0b00000000000011110000000000000000) >> 0x10) as u8; + let l = opcode & 0b00000000000100000000000000000000 != 0x0; + let b = opcode & 0b00000000010000000000000000000000 != 0x0; + let u = opcode & 0b00000000100000000000000000000000 != 0x0; - self.store(register, base, immediate, u, b, l); - return self.r#continue(); + self.arm_store(register, base, immediate, u, b, l); + return self.arm_continue(); } // mov{cond}{s} Rd, Rn if opcode & 0b00001101111111100000111111110000 == 0b00000001101000000000000000000000 { - let destination = ((opcode & 0b00000000000000001111000000000000) >> 0xC) as u8; - let source = (opcode & 0b00000000000000000000000000001111) as u8; + let condition = ((opcode & 0b11110000000000000000000000000000) >> 0x1C) as u8; + if !self.check_condition(condition) { return self.arm_continue() } - let value = self.registers[source as usize]; - self.registers[destination as usize] = value; + let source = (opcode & 0b00000000000000000000000000001111) as u8; + + let destination = ((opcode & 0b00000000000000001111000000000000) >> 0xC) as u8; let s = opcode & 0b00000000000100000000000000000000 != 0x0; - - self.r#move(destination, Move::Register(source), s); - return self.r#continue(); + + self.arm_move(destination, Move::Register(source), s); + return self.arm_continue(); + } + + // svc{cond} Immediate24 + if opcode & 0b00001111000000000000000000000000 == 0b00001111000000000000000000000000 { + let condition = ((opcode & 0b11110000000000000000000000000000) >> 0x1C) as u8; + if !self.check_condition(condition) { return self.arm_continue() } + + let immediate = opcode & 0b00000000111111111111111111111111; + + return self.interrupt(immediate); } self.trap(Trap::InvalidArmOpcode(self.registers[0xF] - 0x8, opcode)); - self.r#continue(); + self.arm_continue(); } } diff --git a/src/luma/device/decode_thumb.rs b/src/luma/device/decode_thumb.rs index 5ccd9ee..deafdfa 100644 --- a/src/luma/device/decode_thumb.rs +++ b/src/luma/device/decode_thumb.rs @@ -3,70 +3,155 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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::{Branch, Device, Move, Trap}; +use crate::luma::device::{Device, Trap}; impl Device { pub fn decode_thumb(&mut self) { debug_assert!(self.thumb()); - let address = self.registers[0xF] - 0x4; + let (address, _) = self.registers[0xF].overflowing_sub(0x4); let opcode = self.read_halfword(address); if cfg!(debug_assertions) { eprintln!("{opcode:#018b} @ {address:#010X}") } // b if opcode & 0b1111100000000000 == 0b1110000000000000 { - let offset = { - let mut offset = (opcode & 0b0000011111111111) as u32; + let immediate = opcode & 0b0000011111111111; - offset <<= 0x1; + let offset = (((immediate as u32) << 0x15) as i32) >> 0x14; - if offset & 0b00000000000000000000100000000000 != 0x0 { offset |= 0b11111111111111111111000000000000 } + return self.thumb_branch(offset); + } + + // b{cond}, svc Immediate8 + if opcode & 0b1111000000000000 == 0b1101000000000000 { + let condition = ((opcode & 0b0000111100000000) >> 0x8) as u8; + + if condition == 0xF { + let immediate = (opcode & 0b0000000011111111) as u8; - offset as i32 - }; + return self.interrupt(immediate as u32); + } - return self.branch(Branch::Offset(offset, false)); + if !self.check_condition(condition) { return self.thumb_continue() } + + let immediate = opcode & 0b0000000011111111; + + let offset = (((immediate as u32) << 0x18) as i32) >> 0x17; + + return self.thumb_branch(offset); } - // b{cond} - if opcode & 0b1111000000000000 == 0b1101000000000000 { - let offset = { - let mut offset = (opcode & 0b0000000011111111) as u32; + // bl Offset11 + if opcode & 0b1111100000000000 == 0b1111000000000000 { + let immediate = opcode & 0b0000011111111111; - offset <<= 0x1; + let offset = (((immediate as u32) << 0x15) as i32) >> 0x9; - if offset & 0b00000000000000000000000100000000 != 0x0 { offset |= 0b11111111111111111111111000000000 } + self.thumb_branch_link0(offset); + return self.thumb_continue(); + } + + // bl Offset11 + if opcode & 0b1111100000000000 == 0b1111100000000000 { + let immediate = opcode & 0b0000011111111111; - offset as i32 - }; + let offset = ((immediate as u32) << 0x1) as i32; - return self.branch(Branch::Offset(offset, false)); + return self.thumb_branch_link1(offset); } - // bx + // bx Rm if opcode & 0b1111111110000111 == 0b0100011100000000 { let register = ((opcode & 0b0000000001111000) >> 0x3) as u8; - return self.branch(Branch::Register(register)); + return self.thumb_branch_exchange(register); + } + + // ldr Rd, [Rn, Immediate5] + if opcode & 0b1111100000000000 == 0b0110100000000000 { + let destination = (opcode & 0b0000000000000111) as u8; + + let base = ((opcode & 0b0000000000111000) >> 0x3) as u8; + + let immediate = ((opcode & 0b0000011111000000) >> 0x5) as u8; + + self.thumb_load_immediate(destination, base, immediate); + return self.thumb_continue(); + } + + // ldr Rd, [Rn, Rm] + if opcode & 0b1111111000000000 == 0b0101100000000000 { + let destination = (opcode & 0b0000000000000111) as u8; + + let base = ((opcode & 0b0000000000111000) >> 0x3) as u8; + + let offset = ((opcode & 0b0000000111000000) >> 0x5) as u8; + + self.thumb_load_register(destination, base, offset); + return self.thumb_continue(); + } + + // ldr Rd, [r13, Immediate8] + if opcode & 0b1111100000000000 == 0b1001100000000000 { + let destination = ((opcode & 0b0000011100000000) >> 0x8) as u8; + + let immediate = (opcode & 0b0000000011111111) as u8; + + self.thumb_load_sp(destination, immediate); + return self.thumb_continue(); + } + + // ldr Rd, [r15, Immediate8] + if opcode & 0b1111100000000000 == 0b0100100000000000 { + let destination = ((opcode & 0b0000011100000000) >> 0x8) as u8; + + let immediate = (opcode & 0b0000000011111111) as u8; + + self.thumb_load_pc(destination, immediate); + return self.thumb_continue(); + } + + // lsl Rd, Rm, Immediate5 + if opcode & 0b1111100000000000 == 0b0000000000000000 { + let destination = (opcode & 0b0000000000000111) as u8; + + let source = ((opcode & 0b0000000000111000) >> 0x3) as u8; + + let immediate = ((opcode & 0b0000011111000000) >> 0x5) as u8; + + self.thumb_shift_left(destination, source, immediate); + return self.thumb_continue(); + } + + // lsr Rd, Rm, Immediate5 + if opcode & 0b1111100000000000 == 0b0000100000000000 { + let destination = (opcode & 0b0000000000000111) as u8; + + let source = ((opcode & 0b0000000000111000) >> 0x3) as u8; + + let immediate = ((opcode & 0b0000011111000000) >> 0x5) as u8; + + self.thumb_shift_right(destination, source, immediate); + return self.thumb_continue(); } // mov Rd, Rm @@ -75,18 +160,18 @@ impl Device { let source = ((opcode & 0b0000000001111000) >> 0x3) as u8; - self.r#move(destination, Move::Register(source), false); - return self.r#continue(); + self.thumb_move_high(destination, source); + return self.thumb_continue(); } - // movs Rd, immediate_8 + // movs Rd, Immediate8 if opcode & 0b1111100000000000 == 0b0010000000000000 { let destination = ((opcode & 0b0000011100000000) >> 0x8) as u8; let immediate = (opcode & 0b0000000011111111) as u8; - self.r#move(destination, Move::Immediate(immediate), true); - return self.r#continue(); + self.thumb_move_immediate(destination, immediate); + return self.thumb_continue(); } // movs Rd, Rn @@ -95,12 +180,44 @@ impl Device { let source = ((opcode & 0b0000000000111000) >> 0x3) as u8; - self.r#move(destination, Move::Register(source), true); - return self.r#continue(); + self.thumb_move(destination, source); + return self.thumb_continue(); + } + + // pop Registers + if opcode & 0b1111111000000000 == 0b1011110000000000 { + let list = (opcode & 0b0000000011111111) as u8; + + let r = opcode & 0b0000000100000000 != 0x0; + + self.thumb_pop(list, r); + if !r { return self.thumb_continue() } + } + + // push Registers + if opcode & 0b1111111000000000 == 0b1011010000000000 { + let list = (opcode & 0b0000000011111111) as u8; + + let r = opcode & 0b0000000100000000 != 0x0; + + self.thumb_push(list, r); + return self.thumb_continue(); + } + + // strh Rd, [Rn, Immediate5] + if opcode & 0b1111100000000000 == 0b1000000000000000 { + let source = (opcode & 0b0000000000000111) as u8; + + let base = ((opcode & 0b0000000000000111) >> 0x3) as u8; + + let immediate = ((opcode & 0b0000011111000000) >> 0x6) as u8; + + self.thumb_store_halfword_immediate(source, base, immediate); + return self.thumb_continue(); } self.trap(Trap::InvalidThumbOpcode(address, opcode)); - self.r#continue(); + self.thumb_continue(); } } diff --git a/src/luma/device/drop.rs b/src/luma/device/drop.rs index 6bb694b..da5c727 100644 --- a/src/luma/device/drop.rs +++ b/src/luma/device/drop.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; diff --git a/src/luma/device/exchange.rs b/src/luma/device/exchange.rs index 32a2f8a..7248792 100644 --- a/src/luma/device/exchange.rs +++ b/src/luma/device/exchange.rs @@ -3,35 +3,38 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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::device::{Device, Log}; impl Device { pub fn exchange(&mut self, thumb: bool) { + // Conditionally exchanges the instruction set. + // cpsr is set by the caller. + + self.log(Log::Exchange, format!("T => {thumb}")); + let decoders = [ Device::decode_arm, Device::decode_thumb, ]; self.decode = decoders[thumb as usize]; - - self.log("exchange", format!("T => {thumb}")); } } diff --git a/src/luma/device/image.rs b/src/luma/device/image.rs index 5fbb0be..2bb2230 100644 --- a/src/luma/device/image.rs +++ b/src/luma/device/image.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; diff --git a/src/luma/device/interrupt.rs b/src/luma/device/interrupt.rs new file mode 100644 index 0000000..61fd7bf --- /dev/null +++ b/src/luma/device/interrupt.rs @@ -0,0 +1,44 @@ +/* + 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 interrupt(&mut self, immediate: u32) { + self.log(Log::Interrupt, format!("{immediate:#010X}")); + + self.spsr[0b0011] = self.cpsr; + self.log(Log::Interrupt, format!("spsr_svc => cpsr ({:#034b})", self.spsr[0b0011])); + + // Enter svc mode. + // Enter ARM state. + // Disable IRQ exceptions. + self.cpsr = self.cpsr & 0b11111111111111111111111101000000 | 0b00000000000000000000000010010011; + self.log(Log::Interrupt, format!("cpsr => {:#034b}", self.cpsr)); + + self.exchange(false); + + self.registers[0xF] = 0x00000008; + self.log(Log::Interrupt, format!("pc => {:#010X}", self.registers[0xF])); + } +} diff --git a/src/luma/device/link.rs b/src/luma/device/link.rs new file mode 100644 index 0000000..24975d4 --- /dev/null +++ b/src/luma/device/link.rs @@ -0,0 +1,44 @@ +/* + 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 arm_link(&mut self) { + // Store the address of the following instruction + // in the link register. + + (self.registers[0xE], _) = self.registers[0xF].overflowing_sub(0x4); + + self.log(Log::Link, format!("lr => pc-4 ({:#010X})", self.registers[0xE])); + } + + pub fn thumb_link(&mut self) { + // Store the address of the following instruction + // in the link register. + + (self.registers[0xE], _) = self.registers[0xF].overflowing_sub(0x2); + + self.log(Log::Link, format!("lr => pc ({:#010X})", self.registers[0xE])); + } +} diff --git a/src/luma/device/load.rs b/src/luma/device/load.rs new file mode 100644 index 0000000..7769300 --- /dev/null +++ b/src/luma/device/load.rs @@ -0,0 +1,87 @@ +/* + 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 thumb_load_immediate(&mut self, destination: u8, base: u8, immediate: u8) { + // Load word from memory using immediate offset. + + let base_value = self.registers[base as usize]; + + let offset = (immediate as u32) << 0x2; + + let address = base_value + offset; + + let value = self.read_word(address); + self.registers[destination as usize] = value; + + self.log(Log::Load, format!("r{destination} => r{base}{offset:+}={address:#010X} ({value:#010X})")); + } + + pub fn thumb_load_register(&mut self, destination: u8, base: u8, offset: u8) { + // Load word from memory using register offset. + + let base_value = self.registers[base as usize]; + let offset_value = self.registers[offset as usize] as i32; + + let (address, _) = base_value.overflowing_add_signed(offset_value); + + let value = self.read_word(address); + self.registers[destination as usize] = value; + + self.log(Log::Load, format!("r{destination} => r{base}+r{offset}={address:#010X} ({value:#010X})")); + } + + pub fn thumb_load_pc(&mut self, destination: u8, immediate: u8) { + // Load word from memory using offset relative to + // the program counter. + + let offset = (immediate as u32) << 0x2; + + let base = self.registers[0xF] & 0b11111111111111111111111111111100; + + let address = base + offset; + + let value = self.read_word(address); + self.registers[destination as usize] = value; + + self.log(Log::Load, format!("r{destination} => pc{offset:+}={address:#010X} ({value:#010X})")); + } + + pub fn thumb_load_sp(&mut self, destination: u8, immediate: u8) { + // Load word from memory using offset relative to + // the stack pointer. + + let offset = (immediate as u32) << 0x2; + + let base = self.registers[0xD]; + + let address = base + offset; + + let value = self.read_word(address); + self.registers[destination as usize] = value; + + self.log(Log::Load, format!("r{destination} => sp{offset:+}={address:#010X} ({value:#010X})")); + } +} diff --git a/src/luma/device/log.rs b/src/luma/device/log.rs index e0ace5d..bc7369c 100644 --- a/src/luma/device/log.rs +++ b/src/luma/device/log.rs @@ -3,33 +3,42 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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::device::{Device, Log}; impl Device { - pub fn log(&mut self, keyword: &str, message: String) { + pub fn log(&mut self, kind: Log, message: String) { if cfg!(debug_assertions) { // This optimises the function away. - let padding: usize = 0x8; - - assert!(keyword.len() <= padding); - let keyword = keyword.to_string() + &" ".to_string().repeat(padding - keyword.len()); + let keyword = match kind { + Log::Branch => "branch ", + Log::Continue => "continue ", + Log::Exchange => "exchange ", + Log::Interrupt => "interrupt", + Log::Link => "link ", + Log::Load => "load ", + Log::Move => "move ", + Log::Pop => "pop ", + Log::Push => "push ", + Log::Shift => "shift ", + Log::Store => "store ", + }; eprintln!("{keyword} : {message}"); } diff --git a/src/luma/device/memory.rs b/src/luma/device/memory.rs index 652b133..0398a41 100644 --- a/src/luma/device/memory.rs +++ b/src/luma/device/memory.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; diff --git a/src/luma/device/move.rs b/src/luma/device/move.rs index 9818f68..2952266 100644 --- a/src/luma/device/move.rs +++ b/src/luma/device/move.rs @@ -3,28 +3,28 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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, Move}; +use crate::luma::device::{Device, Log, Move}; impl Device { - pub fn r#move(&mut self, destination: u8, kind: Move, s: bool) { + pub fn arm_move(&mut self, destination: u8, kind: Move, s: bool) { let value = match kind { Move::Immediate(immediate) => immediate as u32, Move::Register( source) => self.registers[source as usize], @@ -37,12 +37,47 @@ impl Device { self.cpsr = self.spsr[(self.cpsr & 0b00000000000000000000000000001111) as usize]; // We ignore the fifth bit, as this is always set. } else { // TO-DO + todo!(); } } - self.log("move", match kind { + self.log(Log::Move, match kind { Move::Immediate(..) => format!("r{destination} => {value:#04X}"), Move::Register( source) => format!("r{destination} => r{source} ({value:#010X})"), }); } + + pub fn thumb_move(&mut self, destination: u8, source: u8) { + // Move between high and low registers. Condition + // flags are set. + + let value = self.registers[source as usize]; + self.registers[destination as usize] = value; + + // TO-DO: Conditions. + + self.log(Log::Move, format!("r{destination} => r{source} ({value:#010X})")); + } + + pub fn thumb_move_high(&mut self, destination: u8, source: u8) { + // Move between registers. One or both registers + // are a high register. Condition flags are not + // set. + + let value = self.registers[source as usize]; + self.registers[destination as usize] = value; + + self.log(Log::Move, format!("r{destination} => r{source} ({value:#010X})")); + } + + pub fn thumb_move_immediate(&mut self, destination: u8, immediate: u8) { + // Move immediate to low register. Condition flags + // are set. + + self.registers[destination as usize] = immediate as u32; + + // TO-DO: Conditions. + + self.log(Log::Move, format!("r{destination} => {immediate:#04X}")); + } }
\ No newline at end of file diff --git a/src/luma/device/new.rs b/src/luma/device/new.rs index c3aec4f..d11e0f8 100644 --- a/src/luma/device/new.rs +++ b/src/luma/device/new.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; @@ -57,7 +57,7 @@ impl Device { 0x00000000, 0x00000000, 0x00000000, - 0x00000000, + 0x03007F00, start, ], cpsr: 0b00000000000000000000000000001111, diff --git a/src/luma/device/pop.rs b/src/luma/device/pop.rs new file mode 100644 index 0000000..cdf08ce --- /dev/null +++ b/src/luma/device/pop.rs @@ -0,0 +1,58 @@ +/* + 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 thumb_pop(&mut self, list: u8, r: bool) { + // Return true if branching. + + let ammount = list.count_ones() as u8 + r as u8; + + let mut address = self.registers[0xE]; + + for index in 0x0..0x7 { + let pop = (list >> index) & 0b00000001 != 0x0; + + if pop { + let value = self.read_word(address); + + self.registers[index as usize] = value; + self.log(Log::Pop, format!("r{index} => {address:#010X} ({value:#010X})")); + + address += 0x4; + } + } + + if r { + let value = self.read_word(address); + + // We ignore the T flag. + (self.registers[0xF], _) = (value & 0b11111111111111111111111111111110).overflowing_add(0x4); + self.log(Log::Pop, format!("pc => {address:#010X}+4 ({value:#010X})")); + } + + self.registers[0xE] = address - 0x4; + self.log(Log::Pop, format!("sp => sp{:+} ({:#010X})", ammount * 0x4, self.registers[0xE])); + } +} diff --git a/src/luma/device/push.rs b/src/luma/device/push.rs new file mode 100644 index 0000000..65ca3d9 --- /dev/null +++ b/src/luma/device/push.rs @@ -0,0 +1,58 @@ +/* + 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 thumb_push(&mut self, list: u8, r: bool) { + let ammount = list.count_ones() as u8 + r as u8; + + let (start, _) = self.registers[0xE].overflowing_sub(ammount as u32 * 0x4); + + let mut address = start; + + for index in 0x0..0x7 { + let push = (list >> index) & 0b00000001 != 0x0; + + if push { + let value = self.registers[index as usize]; + + self.write_word(address, value); + self.log(Log::Push, format!("{address:#010X} => r{index} ({value:#010X})")); + + address += 0x4; + } + } + + if r { + let value = self.registers[0xD]; + + self.write_word(address, value); + self.log(Log::Push, format!("{address:#010X} = lr ({value:#010X})")); + } + + self.registers[0xE] = start; + + self.log(Log::Push, format!("sp => sp-{} ({start:#010X})", ammount * 0x4)); + } +} diff --git a/src/luma/device/read.rs b/src/luma/device/read.rs index 5622136..f0ea176 100644 --- a/src/luma/device/read.rs +++ b/src/luma/device/read.rs @@ -3,36 +3,34 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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)) } @@ -40,7 +38,6 @@ impl Device { 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)) } diff --git a/src/luma/device/shift.rs b/src/luma/device/shift.rs new file mode 100644 index 0000000..5b19a92 --- /dev/null +++ b/src/luma/device/shift.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 thumb_shift_left(&mut self, destination: u8, source: u8, immediate: u8) { + let source_value = self.registers[source as usize]; + + let (value, _) = source_value.overflowing_shl(immediate as u32); + + self.registers[destination as usize] = value; + + // TO-DO: Set condition flags. + + self.log(Log::Shift, format!("r{destination} => r{source} << {immediate} ({value:#010X})")); + } + + pub fn thumb_shift_right(&mut self, destination: u8, source: u8, immediate: u8) { + let source_value = self.registers[source as usize]; + + let (value, _) = source_value.overflowing_shr(immediate as u32); + + self.registers[destination as usize] = value; + + // TO-DO: Set condition flags. + + self.log(Log::Shift, format!("r{destination} => r{source} << {immediate} ({value:#010X})")); + } +} diff --git a/src/luma/device/store.rs b/src/luma/device/store.rs index e1df1a0..981b502 100644 --- a/src/luma/device/store.rs +++ b/src/luma/device/store.rs @@ -3,30 +3,30 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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::device::{Device, Log}; impl Device { - pub fn store(&mut self, register: u8, base: u8, immediate: u16, u: bool, _b: bool, l: bool) { + pub fn arm_store(&mut self, destination: u8, base: u8, immediate: u16, u: bool, _b: bool, l: bool) { // TO-DO: Byte loads/stores. - + // The U flag determins the sign of the offset // (set = unsigned). let offset = if u { @@ -39,20 +39,36 @@ impl Device { if l { // Check the L flag. // If the L flag is set, we perform a memory-to- - // register load instead. + // destination load instead. let value = self.read_word(address); - self.registers[register as usize] = value; + self.registers[destination as usize] = value; - self.log("load", format!("r{register} => r{base}{offset:+}={address:#010X} ({value:#010X})")); + self.log(Log::Load, format!("r{destination} => r{base}{offset:+}={address:#010X} ({value:#010X})")); } else { - // Otherwise, we perform a register-to-memory + // Otherwise, we perform a destination-to-memory // store. - let value = self.registers[register as usize]; + let value = self.registers[destination as usize]; self.write_word(address, value); - self.log("store", format!("r{base}{offset:+}={address:#010X} => r{register} ({value:#010X})")); + self.log(Log::Store, format!("r{base}{offset:+}={address:#010X} => r{destination} ({value:#010X})")); } } + + pub fn thumb_store_halfword_immediate(&mut self, source: u8, base: u8, immediate: u8) { + // Load halfword from memory using immediate offset. + + let base_value = self.registers[base as usize]; + + let offset = (immediate as u32) << 0x1; + + let (address, _) = base_value.overflowing_add(offset); + + let value = (self.registers[source as usize] & 0b00000000000000001111111111111111) as u16; + self.write_halfword(address, value); + + self.log(Log::Store, format!("r{source} => r{base}{immediate:+} ({value:#06X})")); + } + } diff --git a/src/luma/device/thumb.rs b/src/luma/device/thumb.rs index 130a164..aeb7059 100644 --- a/src/luma/device/thumb.rs +++ b/src/luma/device/thumb.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; diff --git a/src/luma/device/trap.rs b/src/luma/device/trap.rs index 11e3343..9e5f003 100644 --- a/src/luma/device/trap.rs +++ b/src/luma/device/trap.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; @@ -27,10 +27,10 @@ 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::InvalidArmOpcode( address, opcode) => format!("invalid opcode {opcode:#034b} at {address:#010X}"), - Trap::InvalidThumbOpcode(address, opcode) => format!("invalid opcode {opcode:#018b} at {address:#010X}"), - Trap::OutOfBounds( address) => format!("out-of-bounds address {address:#010X} (limit is {MEMORY_SIZE:#010X})"), + Trap::BadAlignment( address, alignment) => format!("bad alignment of address {address:#010X} (should be {alignment}-byte aligned)"), + Trap::InvalidArmOpcode( address, opcode) => format!("invalid opcode {opcode:#034b} at {address:#010X}"), + Trap::InvalidThumbOpcode(address, opcode) => format!("invalid opcode {opcode:#018b} at {address:#010X}"), + Trap::OutOfBounds( address) => format!("out-of-bounds address {address:#010X} (limit is {MEMORY_SIZE:#010X})"), }; eprintln!("{message}"); diff --git a/src/luma/device/write.rs b/src/luma/device/write.rs index 1d29cbf..05a8901 100644 --- a/src/luma/device/write.rs +++ b/src/luma/device/write.rs @@ -3,36 +3,34 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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)) } @@ -40,7 +38,6 @@ impl Device { 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)) } diff --git a/src/main.rs b/src/main.rs index 1d45ca3..564e193 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,22 +3,22 @@ This file is part of Luma. - Luma is free software: you can redistribute it - and/or modify it under the terms of the GNU + 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 + 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 + 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/>. + 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; |