summaryrefslogtreecommitdiff
path: root/src/arm32/instruction
diff options
context:
space:
mode:
Diffstat (limited to 'src/arm32/instruction')
-rw-r--r--src/arm32/instruction/display.rs125
-rw-r--r--src/arm32/instruction/from_str.rs56
-rw-r--r--src/arm32/instruction/mod.rs92
-rw-r--r--src/arm32/instruction/test.rs89
4 files changed, 244 insertions, 118 deletions
diff --git a/src/arm32/instruction/display.rs b/src/arm32/instruction/display.rs
index f610782..b98294e 100644
--- a/src/arm32/instruction/display.rs
+++ b/src/arm32/instruction/display.rs
@@ -19,7 +19,7 @@
// fero General Public License along with Pollex.
// If not, see <https://www.gnu.org/licenses/>.
-use crate::arm32::{Flag, Instruction, Shifter};
+use crate::arm32::{Sflag, Instruction, Shifter};
use core::fmt::Display;
@@ -63,17 +63,22 @@ impl Display for Instruction {
Branch {
predicate,
immediate,
- } => write!(f, "B{predicate} <#{immediate}>"),
+ } => write!(f, "B{predicate} #{immediate}"),
BranchExchange {
predicate,
- register,
- } => write!(f, "BX{predicate} {register}"),
+ source,
+ } => write!(f, "BX{predicate} {source}"),
BranchLink {
predicate,
- immediate,
- } => write!(f, "BL{predicate} <#{immediate}>"),
+ source,
+ } => write!(f, "BL{predicate} #{source}"),
+
+ BranchLinkExchange {
+ predicate,
+ source,
+ } => write!(f, "BLX{predicate} {source}"),
Breakpoint {
immediate } => write!(f, "BKPT #{immediate}"),
@@ -112,16 +117,80 @@ impl Display for Instruction {
s,
} => write!(f, "ORR{predicate}{s} {destination}, {base}, {source}"),
+ Load {
+ predicate,
+ register,
+ address,
+ b,
+ t,
+ } => write!(f, "LDR{predicate}{b}{t} {register}, {address}"),
+
Move {
predicate,
destination,
source: Shifter::LogicalShiftLeftImmediate { source, shift: 0x0 },
- s: Flag::Off,
+ s: Sflag::Off,
} => write!(f, "CPY{predicate} {destination}, {source}"),
Move {
predicate,
destination,
+ source: Shifter::ArithmeticShiftRightImmediate { source, shift },
+ s,
+ } => write!(f, "ASR{predicate}{s} {destination}, {source}, #{shift}"),
+
+ Move {
+ predicate,
+ destination,
+ source: Shifter::ArithmeticShiftRightRegister { source, shift },
+ s,
+ } => write!(f, "ASR{predicate}{s} {destination}, {source}, {shift}"),
+
+ Move {
+ predicate,
+ destination,
+ source: Shifter::LogicalShiftLeftImmediate { source, shift },
+ s,
+ } if shift != 0x0 => write!(f, "LSL{predicate}{s} {destination}, {source}, #{shift}"),
+
+ Move {
+ predicate,
+ destination,
+ source: Shifter::LogicalShiftLeftRegister { source, shift },
+ s,
+ } => write!(f, "LSL{predicate}{s} {destination}, {source}, {shift}"),
+
+ Move {
+ predicate,
+ destination,
+ source: Shifter::LogicalShiftRightImmediate { source, shift },
+ s,
+ } => write!(f, "LSR{predicate}{s} {destination}, {source}, #{shift}"),
+
+ Move {
+ predicate,
+ destination,
+ source: Shifter::LogicalShiftRightRegister { source, shift },
+ s,
+ } => write!(f, "LSR{predicate}{s} {destination}, {source}, {shift}"),
+
+ Move {
+ predicate,
+ destination,
+ source: Shifter::RotateRightImmediate { source, shift },
+ s,
+ } => write!(f, "ROR{predicate}{s} {destination}, {source}, #{shift}"),
+
+ Move {
+ predicate,
+ destination,
+ source: Shifter::RotateRightRegister { source, shift },
+ s,
+ } => write!(f, "ROR{predicate}{s} {destination}, {source}, {shift}"),
+
+ Move {
+ predicate,
+ destination,
source,
s,
} => write!(f, "MOV{predicate}{s} {destination}, {source}"),
@@ -160,6 +229,14 @@ impl Display for Instruction {
predicate,
destination,
base,
+ source: Shifter::Immediate(0x0),
+ s,
+ } => write!(f, "NEG{predicate}{s} {destination}, {base}"),
+
+ ReverseSubtract {
+ predicate,
+ destination,
+ base,
source,
s,
} => write!(f, "RSB{predicate}{s} {destination}, {base}, {source}"),
@@ -191,6 +268,14 @@ impl Display for Instruction {
immediate,
} => write!(f, "SWI{predicate} #{immediate}"),
+ Store {
+ predicate,
+ register,
+ address,
+ b,
+ t,
+ } => write!(f, "STR{predicate}{b}{t} {register}, {address}"),
+
Subtract {
predicate,
destination,
@@ -206,6 +291,32 @@ impl Display for Instruction {
source,
s,
} => write!(f, "SBC{predicate}{s} {destination}, {base}, {source}"),
+
+ Swap {
+ predicate,
+ register,
+ address,
+ b,
+ } => write!(f, "SWP{predicate}{b} {register}, {address}"),
+
+ UnsignedSaturate {
+ predicate,
+ destination,
+ immediate,
+ source,
+ } => write!(f, "USAT{predicate} {destination}, #{immediate}, {source}"),
+
+ Test {
+ predicate,
+ lhs,
+ rhs,
+ } => write!(f, "TST{predicate} {lhs}, {rhs}"),
+
+ TestEquivalence {
+ predicate,
+ lhs,
+ rhs,
+ } => write!(f, "TEQ{predicate} {lhs}, {rhs}"),
}
}
}
diff --git a/src/arm32/instruction/from_str.rs b/src/arm32/instruction/from_str.rs
new file mode 100644
index 0000000..cbb0716
--- /dev/null
+++ b/src/arm32/instruction/from_str.rs
@@ -0,0 +1,56 @@
+// Copyright 2024 Gabriel Bjørnager Jensen.
+//
+// This file is part of Pollex.
+//
+// Pollex is free software: you can redistribute it
+// and/or modify it under the terms of the GNU Af-
+// fero General Public License as published by the
+// Free Software Foundation, either version 3 of
+// the License, or (at your option) any later ver-
+// sion.
+//
+// Pollex 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 Af-
+// fero General Public License along with Pollex.
+// If not, see <https://www.gnu.org/licenses/>.
+
+use crate::Error;
+use crate::arm32::{
+ Instruction,
+ Predicate,
+ Register,
+ Shifter,
+ Sflag,
+};
+
+use core::str::FromStr;
+
+impl FromStr for Instruction {
+ type Err = Error;
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ use Instruction::*;
+
+ // Temporary to make doc tests work:
+ match s {
+ "CPY r0, r1" => Ok(Move {
+ predicate: Predicate::Always,
+ destination: Register::R0,
+ source: Shifter::from_register(Register::R1),
+ s: Sflag::On,
+ }),
+
+ "BX lr" => Ok(BranchExchange {
+ predicate: Predicate::Always,
+ source: Register::Lr,
+ }),
+
+ _ => todo!(),
+ }
+ }
+} \ No newline at end of file
diff --git a/src/arm32/instruction/mod.rs b/src/arm32/instruction/mod.rs
index 7cc3718..2a08ff3 100644
--- a/src/arm32/instruction/mod.rs
+++ b/src/arm32/instruction/mod.rs
@@ -19,16 +19,17 @@
// fero General Public License along with Pollex.
// If not, see <https://www.gnu.org/licenses/>.
-#[cfg(test)]
-mod test;
-
mod display;
+mod from_str;
use crate::arm32::{
+ Address,
+ Bflag,
Predicate,
- Flag,
+ Sflag,
Register,
Shifter,
+ Tflag
};
/// An Arm32 instruction.
@@ -49,7 +50,7 @@ use crate::arm32::{
/// See [`Shifter`] for more information.
///
/// Also note that not all operands can be encoded in Arm instruction sets.
-/// Even the largest immediates usually have a limit at (24) significant figures.
+/// Even the largest immediates usually have a limit at `24` significant figures.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Instruction {
Add {
@@ -57,7 +58,7 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
AddCarry {
@@ -65,7 +66,7 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
And {
@@ -73,7 +74,7 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
BitClear {
@@ -81,22 +82,27 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
Branch {
predicate: Predicate,
- immediate: i32,
+ immediate: u32,
},
BranchExchange {
predicate: Predicate,
- register: Register,
+ source: Register,
},
BranchLink {
predicate: Predicate,
- immediate: i32,
+ source: u32,
+ },
+
+ BranchLinkExchange {
+ predicate: Predicate,
+ source: Shifter,
},
Breakpoint {
@@ -126,7 +132,7 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
InclusiveOr {
@@ -134,21 +140,29 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
+ },
+
+ Load {
+ predicate: Predicate,
+ register: Register,
+ address: Address,
+ b: Bflag,
+ t: Tflag,
},
Move {
predicate: Predicate,
destination: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
MoveNot {
predicate: Predicate,
destination: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
Multiply {
@@ -156,7 +170,7 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Register,
- s: Flag<'S'>,
+ s: Sflag,
},
MultiplyAccumulate {
@@ -165,7 +179,7 @@ pub enum Instruction {
base: Register,
source: Register,
shift: Register,
- s: Flag<'S'>,
+ s: Sflag,
},
Reverse {
@@ -179,7 +193,7 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
ReverseSubtractCarry {
@@ -187,7 +201,7 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
SaturatingAdd {
@@ -209,12 +223,20 @@ pub enum Instruction {
immediate: u32,
},
+ Store {
+ predicate: Predicate,
+ register: Register,
+ address: Address,
+ b: Bflag,
+ t: Tflag,
+ },
+
Subtract {
predicate: Predicate,
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
},
SubtractCarry {
@@ -222,6 +244,32 @@ pub enum Instruction {
destination: Register,
base: Register,
source: Shifter,
- s: Flag<'S'>,
+ s: Sflag,
+ },
+
+ Swap {
+ predicate: Predicate,
+ register: Register,
+ address: Address,
+ b: Bflag,
+ },
+
+ UnsignedSaturate {
+ predicate: Predicate,
+ destination: Register,
+ immediate: u32,
+ source: Shifter,
+ },
+
+ Test {
+ predicate: Predicate,
+ lhs: Register,
+ rhs: Shifter,
+ },
+
+ TestEquivalence {
+ predicate: Predicate,
+ lhs: Register,
+ rhs: Shifter,
},
}
diff --git a/src/arm32/instruction/test.rs b/src/arm32/instruction/test.rs
deleted file mode 100644
index d9067e9..0000000
--- a/src/arm32/instruction/test.rs
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2024 Gabriel Bjørnager Jensen.
-//
-// This file is part of Pollex.
-//
-// Pollex is free software: you can redistribute it
-// and/or modify it under the terms of the GNU Af-
-// fero General Public License as published by the
-// Free Software Foundation, either version 3 of
-// the License, or (at your option) any later ver-
-// sion.
-//
-// Pollex 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 Af-
-// fero General Public License along with Pollex.
-// If not, see <https://www.gnu.org/licenses/>.
-
-use crate::arm32::{
- Predicate,
- Flag,
- Instruction,
- Register,
- Shifter,
-};
-
-use alloc::format;
-use alloc::vec::Vec;
-
-#[test]
-fn test_arm32_instruction() {
- let tree = [
- Instruction::Add {
- predicate: Predicate::GreaterThanOrEqual,
- destination: Register::R1,
- base: Register::R2,
- source: Shifter::RotateRightImmediate { source: Register::R3, shift: 0x2 },
- s: Flag::Off,
- },
-
- Instruction::SaturatingSubtract {
- predicate: Predicate::LessThan,
- destination: Register::R4,
- base: Register::R5,
- source: Register::R6,
- },
-
- Instruction::InclusiveOr {
- predicate: Predicate::Always,
- destination: Register::R7,
- base: Register::R8,
- source: Shifter::LogicalShiftLeftImmediate { source: Register::R9, shift: 0x0 },
- s: Flag::On,
- },
-
- Instruction::MultiplyAccumulate {
- predicate: Predicate::Equal,
- destination: Register::R0,
- base: Register::Pc,
- source: Register::Pc,
- shift: Register::Lr,
- s: Flag::Off,
- },
-
- Instruction::Move {
- predicate: Predicate::NotEqual,
- destination: Register::R0,
- source: Shifter::LogicalShiftLeftImmediate { source: Register::Pc, shift: 0x0 },
- s: Flag::Off,
- },
- ];
-
- let mut displays = Vec::with_capacity(tree.len());
- for instruction in tree { displays.push(format!("{instruction}")) }
-
- assert_eq!(
- displays,
- [
- "ADDGE r1, r2, r3, ROR #2",
- "QSUBLT r4, r5, r6",
- "ORRS r7, r8, r9",
- "MLAEQ r0, pc, pc, lr",
- "CPYNE r0, pc"
- ],
- );
-}