// 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 . use alloc::borrow::ToOwned; use crate::Error; use core::fmt::Display; use core::mem::transmute; use core::str::FromStr; /// An Arm register. /// /// Some opcodes can only encode specific registers. /// And yet other opcodes only encode a single register (which is then inferred from the opcode in question). /// /// # Low registers /// /// The registers whose identifiers can fit into `3` bits (i.e. registers from `r0` to `r7`, inclusive) are called *low* registers. /// /// Some instructions (primarily on Thumb) can only encode low registers. /// In the case of Thumb, a few instructions can be used to move values to and from low registers. /// /// # High registers /// /// In contrast to low registers, registers that can only be addressed using `4` bíts are called *high registers*. /// /// Some instructions are pedantic about combining both low and high registers. #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] #[repr(u8)] pub enum Register { R0 = 0b0000, R1 = 0b0001, R2 = 0b0010, R3 = 0b0011, R4 = 0b0100, R5 = 0b0101, R6 = 0b0110, R7 = 0b0111, R8 = 0b1000, R9 = 0b1001, // Sb R10 = 0b1010, // Sl R11 = 0b1011, R12 = 0b1100, // Ip Sp = 0b1101, // R13 Lr = 0b1110, // R14 Pc = 0b1111, // R15 } impl Register { /// Converts the provided byte into a register identifier. /// If the byte's value is not a valid identifier, [`None`] is returned. /// /// This conversion is valid for all `4`-bit values. #[inline] #[must_use] pub const fn from_u8(value: u8) -> Option { if value <= 0b1111 { Some(unsafe { transmute::(value) }) } else { None } } /// Checks if the register is a low register. /// /// That is, it is any of `r0`, `r1`, `r2`, `r3`, `r4`, `r5`, `r6`, or `r7` -- or any alias herof. /// See also [`is_high`](Self::is_high). #[inline(always)] #[must_use] pub const fn is_low(self) -> bool { (self as u8) <= 0x7 } /// Checks if the register is a high register. /// /// That is, it is any of `r8`, `r9`, `r10`, `r11`, `r12`, `sp`, `lr`, or `pc` -- or any alias herof. /// See also [`is_low`](Self::is_low). #[inline(always)] #[must_use] pub const fn is_high(self) -> bool { (self as u8) > 0x7 } } impl Display for Register { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { use Register::*; match *self { R0 => write!(f, "r0"), R1 => write!(f, "r1"), R2 => write!(f, "r2"), R3 => write!(f, "r3"), R4 => write!(f, "r4"), R5 => write!(f, "r5"), R6 => write!(f, "r6"), R7 => write!(f, "r7"), R8 => write!(f, "r8"), R9 => write!(f, "r9"), R10 => write!(f, "r10"), R11 => write!(f, "r11"), R12 => write!(f, "r12"), Sp => write!(f, "sp"), Lr => write!(f, "lr"), Pc => write!(f, "pc"), } } } impl FromStr for Register { type Err = Error; fn from_str(s: &str) -> Result { use Register::*; match s.to_lowercase().as_str() { | "r0" | "a1" => Ok(R0), | "r1" | "a2" => Ok(R1), | "r2" | "a3" => Ok(R2), | "r3" | "a4" => Ok(R3), | "r4" | "v1" => Ok(R4), | "r5" | "v2" => Ok(R5), | "r6" | "v3" => Ok(R6), | "r7" | "v4" => Ok(R7), | "r8" | "v5" => Ok(R8), | "r9" | "sb" | "v6" => Ok(R9), | "r10" | "sl" | "v7" => Ok(R10), | "r11" | "v8" => Ok(R11), | "ip" | "r12" => Ok(R12), | "r13" | "sp" => Ok(Sp), | "lr" | "r14" => Ok(Lr), | "pc" | "r15" => Ok(Pc), _ => Err(Error::UnknownRegister(s.to_owned())) } } }