Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion harm/src/instructions/ldst.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Ivan Boldyrev
/* Copyright (C) 2026 Ivan Boldyrev
*
* This document is licensed under the BSD 3-clause license.
*/
Expand Down Expand Up @@ -32,6 +32,7 @@ mod strh;
mod stur;
mod sturb;
mod sturh;
mod unprivileged;

pub use self::increment::*;
pub use self::ldnp::*;
Expand All @@ -58,6 +59,7 @@ pub use self::strh::*;
pub use self::stur::*;
pub use self::sturb::*;
pub use self::sturh::*;
pub use self::unprivileged::*;
use crate::bits::{SBitValue, UBitValue};
use crate::sealed::Sealed;

Expand Down
4 changes: 2 additions & 2 deletions harm/src/instructions/ldst/ldur.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ pub trait MakeLdur<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Ldur, MakeLdur, LDUR, RegOrZero64, 64);
define_unscaled_imm_offset_rules!(Ldur, MakeLdur, LDUR, RegOrZero32, 32);
define_unscaled_imm_offset_rules!(Ldur, MakeLdur, LDUR, RegOrZero64, 64, "ldst_unscaled");
define_unscaled_imm_offset_rules!(Ldur, MakeLdur, LDUR, RegOrZero32, 32, "ldst_unscaled");

pub fn ldur<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
2 changes: 1 addition & 1 deletion harm/src/instructions/ldst/ldurb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub trait MakeLdurb<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Ldurb, MakeLdurb, LDURB, RegOrZero32, 32);
define_unscaled_imm_offset_rules!(Ldurb, MakeLdurb, LDURB, RegOrZero32, 32, "ldst_unscaled");

pub fn ldurb<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
2 changes: 1 addition & 1 deletion harm/src/instructions/ldst/ldurh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub trait MakeLdurh<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Ldurh, MakeLdurh, LDURH, RegOrZero32, 32);
define_unscaled_imm_offset_rules!(Ldurh, MakeLdurh, LDURH, RegOrZero32, 32, "ldst_unscaled");

pub fn ldurh<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
4 changes: 2 additions & 2 deletions harm/src/instructions/ldst/ldursb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ pub trait MakeLdursb<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Ldursb, MakeLdursb, LDURSB, RegOrZero64, 64);
define_unscaled_imm_offset_rules!(Ldursb, MakeLdursb, LDURSB, RegOrZero32, 32);
define_unscaled_imm_offset_rules!(Ldursb, MakeLdursb, LDURSB, RegOrZero64, 64, "ldst_unscaled");
define_unscaled_imm_offset_rules!(Ldursb, MakeLdursb, LDURSB, RegOrZero32, 32, "ldst_unscaled");

pub fn ldursb<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
4 changes: 2 additions & 2 deletions harm/src/instructions/ldst/ldursh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ pub trait MakeLdursh<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Ldursh, MakeLdursh, LDURSH, RegOrZero64, 64);
define_unscaled_imm_offset_rules!(Ldursh, MakeLdursh, LDURSH, RegOrZero32, 32);
define_unscaled_imm_offset_rules!(Ldursh, MakeLdursh, LDURSH, RegOrZero64, 64, "ldst_unscaled");
define_unscaled_imm_offset_rules!(Ldursh, MakeLdursh, LDURSH, RegOrZero32, 32, "ldst_unscaled");

pub fn ldursh<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
2 changes: 1 addition & 1 deletion harm/src/instructions/ldst/ldursw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub trait MakeLdursw<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Ldursw, MakeLdursw, LDURSW, RegOrZero64, 64);
define_unscaled_imm_offset_rules!(Ldursw, MakeLdursw, LDURSW, RegOrZero64, 64, "ldst_unscaled");

pub fn ldursw<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
4 changes: 2 additions & 2 deletions harm/src/instructions/ldst/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ specific range and alignment."]
}

macro_rules! define_unscaled_imm_offset_rules {
($name:ident, $make_name:ident, $mnem:ident, $rt:ty, $bitness:expr) => {
($name:ident, $make_name:ident, $mnem:ident, $rt:ty, $bitness:expr, $suffix:expr) => {
impl<Rt, Base> $make_name<Rt, (Base, UnscaledOffset)>
for $name<$rt, (RegOrSp64, UnscaledOffset)>
where
Expand Down Expand Up @@ -348,7 +348,7 @@ macro_rules! define_unscaled_imm_offset_rules {
#[inline]
fn to_code(&self) -> $crate::InstructionCode {
let (base, offset) = self.addr;
[<$mnem:upper _ $bitness _ldst_unscaled>](offset.into(), base.index(), self.rt.index())
[<$mnem:upper _ $bitness _ $suffix>](offset.into(), base.index(), self.rt.index())
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions harm/src/instructions/ldst/stur.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ pub trait MakeStur<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Stur, MakeStur, STUR, RegOrZero64, 64);
define_unscaled_imm_offset_rules!(Stur, MakeStur, STUR, RegOrZero32, 32);
define_unscaled_imm_offset_rules!(Stur, MakeStur, STUR, RegOrZero64, 64, "ldst_unscaled");
define_unscaled_imm_offset_rules!(Stur, MakeStur, STUR, RegOrZero32, 32, "ldst_unscaled");

pub fn stur<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
2 changes: 1 addition & 1 deletion harm/src/instructions/ldst/sturb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub trait MakeSturb<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Sturb, MakeSturb, STURB, RegOrZero32, 32);
define_unscaled_imm_offset_rules!(Sturb, MakeSturb, STURB, RegOrZero32, 32, "ldst_unscaled");

pub fn sturb<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
2 changes: 1 addition & 1 deletion harm/src/instructions/ldst/sturh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub trait MakeSturh<Rt, Addr>: Sealed {
fn new(rt: Rt, addr: Addr) -> Self::Output;
}

define_unscaled_imm_offset_rules!(Sturh, MakeSturh, STURH, RegOrZero32, 32);
define_unscaled_imm_offset_rules!(Sturh, MakeSturh, STURH, RegOrZero32, 32, "ldst_unscaled");

pub fn sturh<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
Expand Down
29 changes: 29 additions & 0 deletions harm/src/instructions/ldst/unprivileged.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* Copyright (C) 2026 Ivan Boldyrev
*
* This document is licensed under the BSD 3-clause license.
*/

//! Unprivileged (translated) load and store instructions.

mod ldtr;
mod ldtrb;
mod ldtrh;
mod ldtrsb;
mod ldtrsh;
mod ldtrsw;
mod sttr;
mod sttrb;
mod sttrh;

pub use self::ldtr::*;
pub use self::ldtrb::*;
pub use self::ldtrh::*;
pub use self::ldtrsb::*;
pub use self::ldtrsh::*;
pub use self::ldtrsw::*;
pub use self::sttr::*;
pub use self::sttrb::*;
pub use self::sttrh::*;

// Re-exported so the child modules can keep referring to `super::UnscaledOffset`.
use super::UnscaledOffset;
157 changes: 157 additions & 0 deletions harm/src/instructions/ldst/unprivileged/ldtr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/* Copyright (C) 2026 Ivan Boldyrev
*
* This document is licensed under the BSD 3-clause license.
*/

use aarchmrs_instructions::A64::ldst::ldst_unpriv::{
LDTR_32_ldst_unpriv::LDTR_32_ldst_unpriv, LDTR_64_ldst_unpriv::LDTR_64_ldst_unpriv,
};

use crate::bits::BitError;
use crate::instructions::RawInstruction;
use crate::register::{IntoReg, RegOrSp64, RegOrZero32, RegOrZero64, Register};
use crate::sealed::Sealed;

use super::UnscaledOffset;

/// A `LDTR` instruction with a destination and an address.
pub struct Ldtr<Rt, Addr> {
rt: Rt,
addr: Addr,
}

impl<Rt, Addr> Ldtr<Rt, Addr> {
pub fn rt(&self) -> &Rt {
&self.rt
}

pub fn addr(&self) -> &Addr {
&self.addr
}
}

impl<Rt, Addr> Sealed for Ldtr<Rt, Addr> {}

/// Defines possible ways to construct a `ldtr` instruction.
pub trait MakeLdtr<Rt, Addr>: Sealed {
/// Allows defining both fallible and infallible constructors.
type Output;

fn new(rt: Rt, addr: Addr) -> Self::Output;
}

pub fn ldtr<TargetInp, TargetOut, AddrInp, AddrOut>(
dst: TargetInp,
addr: AddrInp,
) -> <Ldtr<TargetOut, AddrOut> as MakeLdtr<TargetInp, AddrInp>>::Output
where
Ldtr<TargetOut, AddrOut>: MakeLdtr<TargetInp, AddrInp>,
{
Ldtr::new(dst, addr)
}

define_unscaled_imm_offset_rules!(Ldtr, MakeLdtr, LDTR, RegOrZero64, 64, "ldst_unpriv");
define_unscaled_imm_offset_rules!(Ldtr, MakeLdtr, LDTR, RegOrZero32, 32, "ldst_unpriv");

#[cfg(test)]
mod tests {
use harm_test_utils::test_cases;

use super::*;
use crate::instructions::InstructionSeq;
use crate::register::Reg32::*;
use crate::register::Reg64::*;
use RegOrSp64::SP;
use RegOrZero32::WZR;
use RegOrZero64::XZR;

// 'ldtr (x1|w1|xzr|wzr), [(x2|sp), (-1|1|255|-256|0)]
const LDTR_DB: &str = "
f85ff841 ldtr x1, [x2, -1]
f8401841 ldtr x1, [x2, 1]
f84ff841 ldtr x1, [x2, 255]
f8500841 ldtr x1, [x2, -256]
f8400841 ldtr x1, [x2, 0]
f8400841 ldtr x1, [x2]
f85ffbe1 ldtr x1, [sp, -1]
f8401be1 ldtr x1, [sp, 1]
f84ffbe1 ldtr x1, [sp, 255]
f8500be1 ldtr x1, [sp, -256]
f8400be1 ldtr x1, [sp, 0]
b85ff841 ldtr w1, [x2, -1]
b8401841 ldtr w1, [x2, 1]
b84ff841 ldtr w1, [x2, 255]
b8500841 ldtr w1, [x2, -256]
b8400841 ldtr w1, [x2, 0]
b85ffbe1 ldtr w1, [sp, -1]
b8401be1 ldtr w1, [sp, 1]
b84ffbe1 ldtr w1, [sp, 255]
b8500be1 ldtr w1, [sp, -256]
b8400be1 ldtr w1, [sp, 0]
f85ff85f ldtr xzr, [x2, -1]
f840185f ldtr xzr, [x2, 1]
f84ff85f ldtr xzr, [x2, 255]
f850085f ldtr xzr, [x2, -256]
f840085f ldtr xzr, [x2, 0]
f85ffbff ldtr xzr, [sp, -1]
f8401bff ldtr xzr, [sp, 1]
f84ffbff ldtr xzr, [sp, 255]
f8500bff ldtr xzr, [sp, -256]
f8400bff ldtr xzr, [sp, 0]
b85ff85f ldtr wzr, [x2, -1]
b840185f ldtr wzr, [x2, 1]
b84ff85f ldtr wzr, [x2, 255]
b850085f ldtr wzr, [x2, -256]
b840085f ldtr wzr, [x2, 0]
b85ffbff ldtr wzr, [sp, -1]
b8401bff ldtr wzr, [sp, 1]
b84ffbff ldtr wzr, [sp, 255]
b8500bff ldtr wzr, [sp, -256]
b8400bff ldtr wzr, [sp, 0]
";

test_cases! {
LDTR_DB, untested_ldtr_cases;
test_ldtr_x1_x2_m1, ldtr(X1, (X2, -1)).unwrap(), "ldtr x1, [x2, -1]";
test_ldtr_x1_x2_1, ldtr(X1, (X2, 1)).unwrap(), "ldtr x1, [x2, 1]";
test_ldtr_x1_x2_255, ldtr(X1, (X2, 255)).unwrap(), "ldtr x1, [x2, 255]";
test_ldtr_x1_x2_m256, ldtr(X1, (X2, -256)).unwrap(), "ldtr x1, [x2, -256]";
test_ldtr_x1_x2_0, ldtr(X1, (X2, 0)).unwrap(), "ldtr x1, [x2, 0]";
test_ldtr_x1_x2_simple, ldtr(X1, (X2,)), "ldtr x1, [x2]";
test_ldtr_x1_sp_m1, ldtr(X1, (SP, -1)).unwrap(), "ldtr x1, [sp, -1]";
test_ldtr_x1_sp_1, ldtr(X1, (SP, 1)).unwrap(), "ldtr x1, [sp, 1]";
test_ldtr_x1_sp_255, ldtr(X1, (SP, 255)).unwrap(), "ldtr x1, [sp, 255]";
test_ldtr_x1_sp_m256, ldtr(X1, (SP, -256)).unwrap(), "ldtr x1, [sp, -256]";
test_ldtr_x1_sp_0, ldtr(X1, (SP, 0)).unwrap(), "ldtr x1, [sp, 0]";
test_ldtr_w1_x2_m1, ldtr(W1, (X2, -1)).unwrap(), "ldtr w1, [x2, -1]";
test_ldtr_w1_x2_1, ldtr(W1, (X2, 1)).unwrap(), "ldtr w1, [x2, 1]";
test_ldtr_w1_x2_255, ldtr(W1, (X2, 255)).unwrap(), "ldtr w1, [x2, 255]";
test_ldtr_w1_x2_m256, ldtr(W1, (X2, -256)).unwrap(), "ldtr w1, [x2, -256]";
test_ldtr_w1_x2_0, ldtr(W1, (X2, 0)).unwrap(), "ldtr w1, [x2, 0]";
test_ldtr_w1_sp_m1, ldtr(W1, (SP, -1)).unwrap(), "ldtr w1, [sp, -1]";
test_ldtr_w1_sp_1, ldtr(W1, (SP, 1)).unwrap(), "ldtr w1, [sp, 1]";
test_ldtr_w1_sp_255, ldtr(W1, (SP, 255)).unwrap(), "ldtr w1, [sp, 255]";
test_ldtr_w1_sp_m256, ldtr(W1, (SP, -256)).unwrap(), "ldtr w1, [sp, -256]";
test_ldtr_w1_sp_0, ldtr(W1, (SP, 0)).unwrap(), "ldtr w1, [sp, 0]";
test_ldtr_xzr_x2_m1, ldtr(XZR, (X2, -1)).unwrap(), "ldtr xzr, [x2, -1]";
test_ldtr_xzr_x2_1, ldtr(XZR, (X2, 1)).unwrap(), "ldtr xzr, [x2, 1]";
test_ldtr_xzr_x2_255, ldtr(XZR, (X2, 255)).unwrap(), "ldtr xzr, [x2, 255]";
test_ldtr_xzr_x2_m256, ldtr(XZR, (X2, -256)).unwrap(), "ldtr xzr, [x2, -256]";
test_ldtr_xzr_x2_0, ldtr(XZR, (X2, 0)).unwrap(), "ldtr xzr, [x2, 0]";
test_ldtr_xzr_sp_m1, ldtr(XZR, (SP, -1)).unwrap(), "ldtr xzr, [sp, -1]";
test_ldtr_xzr_sp_1, ldtr(XZR, (SP, 1)).unwrap(), "ldtr xzr, [sp, 1]";
test_ldtr_xzr_sp_255, ldtr(XZR, (SP, 255)).unwrap(), "ldtr xzr, [sp, 255]";
test_ldtr_xzr_sp_m256, ldtr(XZR, (SP, -256)).unwrap(), "ldtr xzr, [sp, -256]";
test_ldtr_xzr_sp_0, ldtr(XZR, (SP, 0)).unwrap(), "ldtr xzr, [sp, 0]";
test_ldtr_wzr_x2_m1, ldtr(WZR, (X2, -1)).unwrap(), "ldtr wzr, [x2, -1]";
test_ldtr_wzr_x2_1, ldtr(WZR, (X2, 1)).unwrap(), "ldtr wzr, [x2, 1]";
test_ldtr_wzr_x2_255, ldtr(WZR, (X2, 255)).unwrap(), "ldtr wzr, [x2, 255]";
test_ldtr_wzr_x2_m256, ldtr(WZR, (X2, -256)).unwrap(), "ldtr wzr, [x2, -256]";
test_ldtr_wzr_x2_0, ldtr(WZR, (X2, 0)).unwrap(), "ldtr wzr, [x2, 0]";
test_ldtr_wzr_sp_m1, ldtr(WZR, (SP, -1)).unwrap(), "ldtr wzr, [sp, -1]";
test_ldtr_wzr_sp_1, ldtr(WZR, (SP, 1)).unwrap(), "ldtr wzr, [sp, 1]";
test_ldtr_wzr_sp_255, ldtr(WZR, (SP, 255)).unwrap(), "ldtr wzr, [sp, 255]";
test_ldtr_wzr_sp_m256, ldtr(WZR, (SP, -256)).unwrap(), "ldtr wzr, [sp, -256]";
test_ldtr_wzr_sp_0, ldtr(WZR, (SP, 0)).unwrap(), "ldtr wzr, [sp, 0]";
}
}
Loading