diff options
Diffstat (limited to 'src/arm32/instruction_codec')
-rw-r--r-- | src/arm32/instruction_codec/encode_arm.rs | 87 | ||||
-rw-r--r-- | src/arm32/instruction_codec/encode_thumb.rs | 92 | ||||
-rw-r--r-- | src/arm32/instruction_codec/mod.rs | 3 |
3 files changed, 150 insertions, 32 deletions
diff --git a/src/arm32/instruction_codec/encode_arm.rs b/src/arm32/instruction_codec/encode_arm.rs index 73dc3d9..9c63f81 100644 --- a/src/arm32/instruction_codec/encode_arm.rs +++ b/src/arm32/instruction_codec/encode_arm.rs @@ -19,7 +19,7 @@ // fero General Public License along with Pollex. // If not, see <https://www.gnu.org/licenses/>. -use crate::Result; +use crate::{assert_or_err, Error, Result}; use crate::arm32::{ ArmOpcode, Instruction, @@ -36,35 +36,51 @@ impl InstructionCodec { pub fn encode_arm(&mut self, instruction: Instruction) -> Result<ArmOpcode> { use Instruction::*; - let mut opcode = 0b00000000_00000000_00000000_00000000; + let mut opcode = 0b00000000_00000000_00000000_00000000_u32; match instruction { - Branch { predicate, .. } => { + Branch { + predicate, + .. + } => { opcode |= 0b00001011_00000000_00000000_00000000; opcode |= (predicate as u32) << 0x1C; }, - BranchLink { predicate, .. } => { + BranchLink { + predicate, + .. + } => { opcode |= 0b00001010_00000000_00000000_00000000; opcode |= (predicate as u32) << 0x1C; }, - Breakpoint { immediate } => { + Breakpoint { + immediate, + } => { opcode |= 0b11100001_00100000_00000000_01110000; opcode |= immediate & 0b00000000_00000000_00000000_00001111; opcode |= (immediate & 0b00000000_00000000_11111111_11110000) << 0x4; }, - Move { predicate, destination, source, s } => { + Move { + predicate, + destination, + source, + s, + } => { opcode |= 0b00000001_10100000_00000000_00000000; opcode |= (destination as u32) << 0xC; opcode |= u32::from(s) << 0x14; opcode |= (predicate as u32) << 0x1C; - opcode = add_shifter(opcode, source); + opcode = add_shifter(opcode, source)?; }, - SoftwareInterrupt { predicate, immediate } => { + SoftwareInterrupt { + predicate, + immediate, + } => { opcode |= 0b00001111_00000000_00000000_00000000; opcode |= immediate & 0b00000000_11111111_11111111_11111111; opcode |= (predicate as u32) << 0x1C; @@ -78,41 +94,50 @@ impl InstructionCodec { } } -fn add_shifter(mut opcode: u32, shifter: Shifter) -> u32 { +fn add_shifter(mut opcode: u32, shifter: Shifter) -> Result<u32> { + use Shifter::*; + match shifter { - | Shifter::ArithmeticShiftRightImmediate { source, shift } - | Shifter::LogicalShiftLeftImmediate { source, shift } - | Shifter::LogicalShiftRightImmediate { source, shift } - | Shifter::RotateRightImmediate { source, shift } + LogicalShiftLeftImmediate { source, shift: 0x0 } + => { + opcode |= source as u32; + }, + + | ArithmeticShiftRightImmediate { source, shift } + | LogicalShiftLeftImmediate { source, shift } + | LogicalShiftRightImmediate { source, shift } + | RotateRightImmediate { source, shift } => { let code = match shifter { - Shifter::LogicalShiftLeftImmediate { .. } => 0b00, - Shifter::LogicalShiftRightImmediate { .. } => 0b01, - Shifter::ArithmeticShiftRightImmediate { .. } => 0b10, - Shifter::RotateRightImmediate { .. } => 0b11, + LogicalShiftLeftImmediate { .. } => 0b00, + LogicalShiftRightImmediate { .. } => 0b01, + ArithmeticShiftRightImmediate { .. } => 0b10, + RotateRightImmediate { .. } => 0b11, _ => unreachable!(), }; + assert_or_err!(shift != 0x0, Error::IllegalImmediate); + opcode |= source as u32; opcode |= code << 0x5; opcode |= shift << 0x7; }, - Shifter::RotateRightExtend { .. } => { + RotateRightExtend { .. } => { todo!() }, - | Shifter::ArithmeticShiftRightRegister { source, .. } - | Shifter::LogicalShiftLeftRegister { source, .. } - | Shifter::LogicalShiftRightRegister { source, .. } - | Shifter::RotateRightRegister { source, .. } + | ArithmeticShiftRightRegister { source, .. } + | LogicalShiftLeftRegister { source, .. } + | LogicalShiftRightRegister { source, .. } + | RotateRightRegister { source, .. } => { let _code = match shifter { - Shifter::LogicalShiftLeftRegister { .. } => 0b00, - Shifter::LogicalShiftRightRegister { .. } => 0b01, - Shifter::ArithmeticShiftRightRegister { .. } => 0b10, - Shifter::RotateRightRegister { .. } => 0b11, + LogicalShiftLeftRegister { .. } => 0b00, + LogicalShiftRightRegister { .. } => 0b01, + ArithmeticShiftRightRegister { .. } => 0b10, + RotateRightRegister { .. } => 0b11, _ => unreachable!(), }; @@ -121,18 +146,18 @@ fn add_shifter(mut opcode: u32, shifter: Shifter) -> u32 { opcode |= source as u32; }, - Shifter::Immediate { immediate } => { - let (immediate, rotate) = if immediate <= 0xFF { - (immediate, 0x00) + Immediate { source } => { + let (source, rotate) = if source <= 0xFF { + (source, 0x00) } else { todo!() }; opcode |= 0b00000010_00000000_00000000_00000000; - opcode |= immediate; + opcode |= source; opcode |= rotate << 0x8; }, } - opcode + Ok(opcode) } diff --git a/src/arm32/instruction_codec/encode_thumb.rs b/src/arm32/instruction_codec/encode_thumb.rs new file mode 100644 index 0000000..f2fa0b8 --- /dev/null +++ b/src/arm32/instruction_codec/encode_thumb.rs @@ -0,0 +1,92 @@ +// 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::{assert_or_err, Error, Result}; +use crate::arm32::{ + Instruction, + InstructionCodec, + Predicate, + Shifter, + ThumbOpcode, +}; + +impl InstructionCodec { + /// Encodes the given Thumb instruction. + /// + /// # Errors + /// + /// If the given instruction cannot be encoded for Thumb, an error is returned. + pub fn encode_thumb(&mut self, instruction: Instruction) -> Result<ThumbOpcode> { + use Instruction::*; + + let mut opcode = 0b00000000_00000000_u16; + + match instruction { + Move { + predicate, + destination, + source, + s, + } => { + assert_or_err!(predicate == Predicate::Always, Error::IllegalPredicate); + + if s.is_on() { + if let Shifter::Immediate { source } = source { + assert_or_err!(destination.is_low(), Error::IllegalRegister); + assert_or_err!(source <= 0xFF, Error::IllegalRegister); + + opcode |= 0b00100000_00000000; + opcode |= source as u16; + opcode |= (destination as u16) << 0x8; + + } else if let Shifter::LogicalShiftLeftImmediate { source, shift: 0x0 } = source { + assert_or_err!(destination.is_low(), Error::IllegalRegister); + assert_or_err!(source.is_low(), Error::IllegalRegister); + + opcode |= 0b00100000_00000000; + opcode |= destination as u16; + opcode |= (source as u16) << 0x3; + } else { + return Err(Error::IllegalInstruction); + } + } else if let Shifter::LogicalShiftLeftImmediate { source, shift: 0x0 } = source { + opcode |= 0b01000110_00000000; + + let h0 = destination.is_high(); + let h1 = source.is_high(); + + opcode |= destination as u16 & 0b00000000_00000111; + opcode |= (source as u16 & 0b00000000_00000111) << 0x3; + opcode |= u16::from(h0) << 0x6; + opcode |= u16::from(h1) << 0x7; + } else { + // TODO: Shifters &c. + todo!(); + } + } + + _ => return Err(Error::IllegalInstruction), + } + + self.address += ThumbOpcode::SIZE; + Ok(opcode.into()) + } +} diff --git a/src/arm32/instruction_codec/mod.rs b/src/arm32/instruction_codec/mod.rs index f8d2a8c..841d335 100644 --- a/src/arm32/instruction_codec/mod.rs +++ b/src/arm32/instruction_codec/mod.rs @@ -23,13 +23,14 @@ mod test; mod encode_arm; +mod encode_thumb; use core::num::Wrapping; /// Codec for encoding and decoding instruction. /// /// Arm instructions can be encoded/decoded using the [`encode_arm`](InstructionCodec::encode_arm) and `decode_arm` (soon). -/// Thumb instruction will similarly be manipulated using `encode_thumb` and `decode_thumb`. +/// Thumb instruction will similarly be manipulated using [`encode_thumb`](InstructionCodec::encode_thumb) and `decode_thumb`. /// /// This structure keeps track of the adress at which instructions are to be placed (see *Rationale*). /// If encoding causes this internal address to go past `0xFFFFFFFF`, the value is safely wrapped to the origin (i.e. `0x00000000`). |