summaryrefslogtreecommitdiff
path: root/src/luma/cpu/decode_arm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/luma/cpu/decode_arm.rs')
-rw-r--r--src/luma/cpu/decode_arm.rs256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/luma/cpu/decode_arm.rs b/src/luma/cpu/decode_arm.rs
new file mode 100644
index 0000000..9b4377c
--- /dev/null
+++ b/src/luma/cpu/decode_arm.rs
@@ -0,0 +1,256 @@
+/*
+ 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::{Error, log};
+use crate::luma::cpu::Cpu;
+use crate::luma::instruction::Instruction;
+
+use std::hint::unreachable_unchecked;
+
+impl Cpu {
+ #[must_use]
+ pub(super) fn decode_arm(&mut self) -> Instruction {
+ let state = self.state.lock().unwrap();
+
+ let address = state.read_register(0xF).wrapping_sub(0x8);
+ let opcode = state.read_word(address);
+
+ drop(state);
+
+ log(&format!("{opcode:#034b} @ {address:#010X} - ({})", self.cycle));
+
+ return decode(address, opcode);
+ }
+}
+
+#[must_use]
+fn decode(address: u32, opcode: u32) -> Instruction {
+ use Instruction::*;
+
+ match (opcode & 0b00001110000000000000000000000000).wrapping_shr(0x19) {
+ 0b000 => {
+ match (opcode & 0b00000000000000000000000000010000).wrapping_shr(0x4) {
+ 0b0 => {
+ let _source = (opcode & 0b00000000000000000000000000001111) as u8;
+
+ let _destination = (opcode & 0b00000000000000001111000000000000).wrapping_shr(0xC) as u8;
+
+ let _base = (opcode & 0b00000000000011110000000000000000).wrapping_shr(0x10) as u8;
+
+ let _s = opcode & 0b00000000000100000000000000000000 != 0x0;
+
+ match (opcode & 0b00000001111000000000000000000000).wrapping_shr(0x15) {
+ 0b0000 => {},
+
+ 0b0001 => {},
+
+ 0b0010 => {},
+
+ 0b0011 => {},
+
+ 0b0100 => {},
+
+ 0b0101 => {},
+
+ 0b0110 => {},
+
+ 0b0111 => {},
+
+ 0b1000 => {},
+
+ 0b1001 => {},
+
+ 0b1010 => {},
+
+ 0b1011 => {},
+
+ 0b1100 => {},
+
+ 0b1101 => {},
+
+ 0b1110 => {},
+
+ 0b1111 => {},
+
+ _ => unsafe { unreachable_unchecked() },
+ }
+ },
+
+ 0b1 => {
+ let source = (opcode & 0b00000000000000000000000000001111) as u8;
+
+ let _shift = (opcode & 0b00000000000000000000000011110000) as u8;
+
+ let _destination = (opcode & 0b00000000000000001111000000000000).wrapping_shr(0xC) as u8;
+
+ let _base = (opcode & 0b00000000000011110000000000000000).wrapping_shr(0x10) as u8;
+
+ let _s = opcode & 0b00000000000100000000000000000000 != 0x0;
+
+ match (opcode & 0b00000001111000000000000000000000).wrapping_shr(0x15) {
+ 0b0000 => {},
+
+ 0b0001 => {},
+
+ 0b0010 => {},
+
+ 0b0011 => {},
+
+ 0b0100 => {},
+
+ 0b0101 => {},
+
+ 0b0110 => {},
+
+ 0b0111 => {},
+
+ 0b1000 => {},
+
+ 0b1001 => {
+ // Unpredictable if any of shift, destination, or
+ // base is non-zero. Unpredictable if s is true.
+
+ return BranchExchange(source);
+ },
+
+ 0b1010 => {},
+
+ 0b1011 => {},
+
+ 0b1100 => {},
+
+ 0b1101 => {},
+
+ 0b1110 => {},
+
+ 0b1111 => {},
+
+ _ => unsafe { unreachable_unchecked() },
+ }
+ },
+
+ _ => unsafe { unreachable_unchecked() },
+ }
+ },
+
+ 0b001 => {
+ let immediate = (opcode & 0b00000000000000000000000011111111) as u8;
+
+ let rotate = (opcode & 0b00000000000000000000111100000000).wrapping_shr(0x8) as u8;
+
+ let destination = (opcode & 0b00000000000000001111000000000000).wrapping_shr(0xC) as u8;
+
+ let base = (opcode & 0b00000000000011110000000000000000).wrapping_shr(0x10) as u8;
+
+ let _s = opcode & 0b00000000000100000000000000000000 != 0x0;
+
+ let immediate = (immediate as u32).rotate_right(rotate as u32);
+
+ match (opcode & 0b00000001111000000000000000000000).wrapping_shr(0x15) {
+ 0b0000 => {},
+
+ 0b0001 => {},
+
+ 0b0010 => {},
+
+ 0b0011 => {},
+
+ 0b0100 => return AddImmediate(destination, base, immediate),
+
+ 0b0101 => {},
+
+ 0b0110 => {},
+
+ 0b0111 => {},
+
+ 0b1000 => {},
+
+ 0b1001 => {},
+
+ 0b1010 => {},
+
+ 0b1011 => {},
+
+ 0b1100 => {},
+
+ // Unpredictable if base is non-zero.
+ 0b1101 => return MoveImmediate(destination, immediate),
+
+ 0b1110 => {},
+
+ 0b1111 => {},
+
+ _ => unsafe { unreachable_unchecked() },
+ }
+ },
+
+ 0b010 => {
+ let immediate = (opcode & 0b00000000000000000000111111111111) as u16;
+
+ let register = (opcode & 0b00000000000000001111000000000000).wrapping_shr(0xC) as u8;
+
+ let base = (opcode & 0b00000000000011110000000000000000).wrapping_shr(0x10) as u8;
+
+ let l = opcode & 0b00000000000100000000000000000000 != 0x0;
+ let _w = opcode & 0b00000000001000000000000000000000 != 0x0;
+ let _b = opcode & 0b00000000010000000000000000000000 != 0x0;
+ let u = opcode & 0b00000000100000000000000000000000 != 0x0;
+ let _p = opcode & 0b00000001000000000000000000000000 != 0x0;
+
+ let offset = match u {
+ false => 0x0 - immediate as i16,
+ true => 0x0 + immediate as i16,
+ };
+
+ return match l {
+ false => StoreImmediateOffset(register, base, offset),
+ true => LoadImmediateOffset( register, base, offset),
+ };
+ },
+
+ 0b011 => {},
+
+ 0b100 => {},
+
+ 0b101 => {
+ let offset = opcode & 0b00000000111111111111111111111111;
+ let offset = (offset << 0x8) as i32 >> 0x6;
+
+ let l = opcode & 0b00000001000000000000000000000000 != 0x0;
+
+ return match l {
+ false => Branch( offset),
+ true => BranchLink(offset),
+ };
+ },
+
+ 0b110 => {},
+
+ 0b111 => {},
+
+ _ => unsafe { unreachable_unchecked() },
+ }
+
+ Error::InvalidArmOpcode(address, opcode).trap();
+ return Undefined;
+}