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
3 changes: 3 additions & 0 deletions harm/src/instructions/ldst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ pub(crate) mod macros;
mod increment;
mod shift_extend;

mod args;
mod exclusive;
mod ldnp;
mod ldp;
mod ldpsw;
Expand All @@ -34,6 +36,7 @@ mod sturb;
mod sturh;
mod unprivileged;

pub use self::exclusive::*;
pub use self::increment::*;
pub use self::ldnp::*;
pub use self::ldp::*;
Expand Down
6 changes: 6 additions & 0 deletions harm/src/instructions/ldst/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* Copyright (C) 2026 Ivan Boldyrev
*
* This document is licensed under the BSD 3-clause license.
*/

pub(crate) mod reg_addr;
83 changes: 83 additions & 0 deletions harm/src/instructions/ldst/args/reg_addr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use crate::{
register::{IntoReg, RegOrSp64, RegOrZero32, RegOrZero64},
sealed::Sealed,
};

#[derive(Debug, Clone, Copy)]
pub struct RegAddr<Reg> {
pub reg: Reg,
pub addr: RegOrSp64,
}

impl Sealed for RegAddr<RegOrZero32> {}
impl Sealed for RegAddr<RegOrZero64> {}

pub trait MakeRegAddr<RegInp, AddrRegInp>: Sealed {
fn new(reg: RegInp, addr: AddrRegInp) -> Self;
}

impl<Reg: IntoReg<RegOrZero32>, Addr: IntoReg<RegOrSp64>> MakeRegAddr<Reg, Addr>
for RegAddr<RegOrZero32>
{
fn new(reg: Reg, addr: Addr) -> Self {
Self {
reg: reg.into_reg(),
addr: addr.into_reg(),
}
}
}

impl<Reg: IntoReg<RegOrZero64>, Addr: IntoReg<RegOrSp64>> MakeRegAddr<Reg, Addr>
for RegAddr<RegOrZero64>
{
fn new(reg: Reg, addr: Addr) -> Self {
Self {
reg: reg.into_reg(),
addr: addr.into_reg(),
}
}
}

#[derive(Debug, Clone, Copy)]
pub struct Reg32Addr {
pub reg: RegOrZero32,
pub addr: RegOrSp64,
}

impl Sealed for Reg32Addr {}

pub trait MakeReg32Addr<Reg32Inp, AddrRegInp>: Sealed {
fn new(reg: Reg32Inp, addr: AddrRegInp) -> Self;
}

impl<Reg: IntoReg<RegOrZero32>, Addr: IntoReg<RegOrSp64>> MakeReg32Addr<Reg, Addr> for Reg32Addr {
fn new(reg: Reg, addr: Addr) -> Self {
Self {
reg: reg.into_reg(),
addr: addr.into_reg(),
}
}
}

#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub struct Reg64Addr {
pub reg: RegOrZero64,
pub addr: RegOrSp64,
}

impl Sealed for Reg64Addr {}

#[allow(dead_code)]
pub trait MakeReg64Addr<Reg64Inp, AddrRegInp>: Sealed {
fn new(reg: Reg64Inp, addr: AddrRegInp) -> Self;
}

impl<Reg: IntoReg<RegOrZero64>, Addr: IntoReg<RegOrSp64>> MakeReg64Addr<Reg, Addr> for Reg64Addr {
fn new(reg: Reg, addr: Addr) -> Self {
Self {
reg: reg.into_reg(),
addr: addr.into_reg(),
}
}
}
25 changes: 25 additions & 0 deletions harm/src/instructions/ldst/exclusive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Copyright (C) 2026 Ivan Boldyrev
*
* This document is licensed under the BSD 3-clause license.
*/

//! Load-Exclusive/Store-Exclusive (`LDXR`, `STXR`, `LDXRB`, etc.) instructions.

pub mod exclusive_args;
mod ldxp;
mod ldxr;
mod ldxrb;
mod ldxrh;
mod stxp;
mod stxr;
mod stxrb;
mod stxrh;

pub use self::ldxp::*;
pub use self::ldxr::*;
pub use self::ldxrb::*;
pub use self::ldxrh::*;
pub use self::stxp::*;
pub use self::stxr::*;
pub use self::stxrb::*;
pub use self::stxrh::*;
173 changes: 173 additions & 0 deletions harm/src/instructions/ldst/exclusive/exclusive_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
use crate::{
register::{IntoReg, RegOrSp64, RegOrZero32, RegOrZero64},
sealed::Sealed,
};

pub struct ExclusiveStoreArgs<Reg> {
pub status: RegOrZero32,
pub reg: Reg,
pub addr: RegOrSp64,
}

impl Sealed for ExclusiveStoreArgs<RegOrZero32> {}
impl Sealed for ExclusiveStoreArgs<RegOrZero64> {}

pub trait MakeExclusiveStoreArgs<StatusInp, RegInp, AddrRegInp>: Sealed {
fn new(status: StatusInp, reg: RegInp, addr: AddrRegInp) -> Self;
}

impl<StatusInp, RegInp, AddrRegInp> MakeExclusiveStoreArgs<StatusInp, RegInp, AddrRegInp>
for ExclusiveStoreArgs<RegOrZero32>
where
StatusInp: IntoReg<RegOrZero32>,
RegInp: IntoReg<RegOrZero32>,
AddrRegInp: IntoReg<RegOrSp64>,
{
fn new(status: StatusInp, reg: RegInp, addr: AddrRegInp) -> Self {
Self {
status: status.into_reg(),
reg: reg.into_reg(),
addr: addr.into_reg(),
}
}
}

impl<StatusInp, RegInp, AddrRegInp> MakeExclusiveStoreArgs<StatusInp, RegInp, AddrRegInp>
for ExclusiveStoreArgs<RegOrZero64>
where
StatusInp: IntoReg<RegOrZero32>,
RegInp: IntoReg<RegOrZero64>,
AddrRegInp: IntoReg<RegOrSp64>,
{
fn new(status: StatusInp, reg: RegInp, addr: AddrRegInp) -> Self {
Self {
status: status.into_reg(),
reg: reg.into_reg(),
addr: addr.into_reg(),
}
}
}
pub struct ExclusiveStore32Args {
pub status: RegOrZero32,
pub reg: RegOrZero32,
pub addr: RegOrSp64,
}

impl Sealed for ExclusiveStore32Args {}

pub trait MakeExclusiveStore32Args<StatusInp, RegInp, AddrRegInp>: Sealed {
fn new(status: StatusInp, reg: RegInp, addr: AddrRegInp) -> Self;
}

impl<StatusInp, RegInp, AddrRegInp> MakeExclusiveStore32Args<StatusInp, RegInp, AddrRegInp>
for ExclusiveStore32Args
where
StatusInp: IntoReg<RegOrZero32>,
RegInp: IntoReg<RegOrZero32>,
AddrRegInp: IntoReg<RegOrSp64>,
{
fn new(status: StatusInp, reg: RegInp, addr: AddrRegInp) -> Self {
Self {
status: status.into_reg(),
reg: reg.into_reg(),
addr: addr.into_reg(),
}
}
}

pub struct ExclusivePairLoadArgs<Reg> {
pub reg1: Reg,
pub reg2: Reg,
pub addr: RegOrSp64,
}

impl Sealed for ExclusivePairLoadArgs<RegOrZero32> {}
impl Sealed for ExclusivePairLoadArgs<RegOrZero64> {}

pub trait MakeExclusivePairLoadArgs<Reg1Inp, Reg2Inp, AddrRegInp>: Sealed {
fn new(reg1: Reg1Inp, reg2: Reg2Inp, addr: AddrRegInp) -> Self;
}

impl<Reg1Inp, Reg2Inp, AddrRegInp> MakeExclusivePairLoadArgs<Reg1Inp, Reg2Inp, AddrRegInp>
for ExclusivePairLoadArgs<RegOrZero32>
where
Reg1Inp: IntoReg<RegOrZero32>,
Reg2Inp: IntoReg<RegOrZero32>,
AddrRegInp: IntoReg<RegOrSp64>,
{
fn new(reg1: Reg1Inp, reg2: Reg2Inp, addr: AddrRegInp) -> Self {
Self {
reg1: reg1.into_reg(),
reg2: reg2.into_reg(),
addr: addr.into_reg(),
}
}
}

impl<Reg1Inp, Reg2Inp, AddrRegInp> MakeExclusivePairLoadArgs<Reg1Inp, Reg2Inp, AddrRegInp>
for ExclusivePairLoadArgs<RegOrZero64>
where
Reg1Inp: IntoReg<RegOrZero64>,
Reg2Inp: IntoReg<RegOrZero64>,
AddrRegInp: IntoReg<RegOrSp64>,
{
fn new(reg1: Reg1Inp, reg2: Reg2Inp, addr: AddrRegInp) -> Self {
Self {
reg1: reg1.into_reg(),
reg2: reg2.into_reg(),
addr: addr.into_reg(),
}
}
}

pub struct ExclusivePairStoreArgs<Reg> {
pub status: RegOrZero32,
pub reg1: Reg,
pub reg2: Reg,
pub addr: RegOrSp64,
}

impl Sealed for ExclusivePairStoreArgs<RegOrZero32> {}
impl Sealed for ExclusivePairStoreArgs<RegOrZero64> {}

pub trait MakeExclusivePairStoreArgs<StatusInp, Reg1Inp, Reg2Inp, AddrRegInp>: Sealed {
fn new(status: StatusInp, reg1: Reg1Inp, reg2: Reg2Inp, addr: AddrRegInp) -> Self;
}

impl<StatusInp, Reg1Inp, Reg2Inp, AddrRegInp>
MakeExclusivePairStoreArgs<StatusInp, Reg1Inp, Reg2Inp, AddrRegInp>
for ExclusivePairStoreArgs<RegOrZero32>
where
StatusInp: IntoReg<RegOrZero32>,
Reg1Inp: IntoReg<RegOrZero32>,
Reg2Inp: IntoReg<RegOrZero32>,
AddrRegInp: IntoReg<RegOrSp64>,
{
fn new(status: StatusInp, reg1: Reg1Inp, reg2: Reg2Inp, addr: AddrRegInp) -> Self {
Self {
status: status.into_reg(),
reg1: reg1.into_reg(),
reg2: reg2.into_reg(),
addr: addr.into_reg(),
}
}
}

impl<StatusInp, Reg1Inp, Reg2Inp, AddrRegInp>
MakeExclusivePairStoreArgs<StatusInp, Reg1Inp, Reg2Inp, AddrRegInp>
for ExclusivePairStoreArgs<RegOrZero64>
where
StatusInp: IntoReg<RegOrZero32>,
Reg1Inp: IntoReg<RegOrZero64>,
Reg2Inp: IntoReg<RegOrZero64>,
AddrRegInp: IntoReg<RegOrSp64>,
{
fn new(status: StatusInp, reg1: Reg1Inp, reg2: Reg2Inp, addr: AddrRegInp) -> Self {
Self {
status: status.into_reg(),
reg1: reg1.into_reg(),
reg2: reg2.into_reg(),
addr: addr.into_reg(),
}
}
}
87 changes: 87 additions & 0 deletions harm/src/instructions/ldst/exclusive/ldxp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* Copyright (C) 2026 Ivan Boldyrev
*
* This document is licensed under the BSD 3-clause license.
*/

use crate::register::{RegOrSp64, RegOrZero32, RegOrZero64, Register};
use aarchmrs_instructions::A64::ldst::ldstexclp::{
LDXP_LP32_ldstexclp::LDXP_LP32_ldstexclp, LDXP_LP64_ldstexclp::LDXP_LP64_ldstexclp,
};

use crate::instructions::RawInstruction;

use super::exclusive_args::{ExclusivePairLoadArgs, MakeExclusivePairLoadArgs};

/// A `ldxp` instruction with a destination and an address.
pub struct Ldxp<Rt> {
args: ExclusivePairLoadArgs<Rt>,
}

impl<Rt: Copy> Ldxp<Rt> {
pub fn rt1(&self) -> Rt {
self.args.reg1
}

pub fn rt2(&self) -> Rt {
self.args.reg2
}

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

pub fn ldxp<TargetOut, Reg1Inp, Reg2Inp, AddrRegInp>(
r1: Reg1Inp,
r2: Reg2Inp,
addr: AddrRegInp,
) -> Ldxp<TargetOut>
where
ExclusivePairLoadArgs<TargetOut>: MakeExclusivePairLoadArgs<Reg1Inp, Reg2Inp, AddrRegInp>,
{
Ldxp {
args: <ExclusivePairLoadArgs<TargetOut> as MakeExclusivePairLoadArgs<
Reg1Inp,
Reg2Inp,
AddrRegInp,
>>::new(r1, r2, addr),
}
}

impl RawInstruction for Ldxp<RegOrZero32> {
fn to_code(&self) -> aarchmrs_types::InstructionCode {
LDXP_LP32_ldstexclp(self.rt2().index(), self.addr().index(), self.rt1().index())
}
}

impl RawInstruction for Ldxp<RegOrZero64> {
fn to_code(&self) -> aarchmrs_types::InstructionCode {
LDXP_LP64_ldstexclp(self.rt2().index(), self.addr().index(), self.rt1().index())
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::instructions::InstructionSeq;
use crate::register::Reg32::*;
use crate::register::Reg64::*;
use crate::register::RegOrSp64::SP;
use crate::register::RegOrZero32::WZR;
use crate::register::RegOrZero64::XZR;
use harm_test_utils::test_cases;

const LDXP_TEST_DB: &str = "
887f0903 ldxp w3, w2, [x8]
c87f0903 ldxp x3, x2, [x8]
887f13ff ldxp wzr, w4, [sp]
c87f13ff ldxp xzr, x4, [sp]
";
test_cases! {
LDXP_TEST_DB, untested_ldxp_test_db;
test_ldxp_w2_x8, ldxp(W3, W2, X8), "ldxp w3, w2, [x8]";
test_ldxp_x2_x8, ldxp(X3, X2, X8), "ldxp x3, x2, [x8]";
test_ldxp_wzr_sp, ldxp(WZR, W4, SP), "ldxp wzr, w4, [sp]";
test_ldxp_xzr_sp, ldxp(XZR, X4, SP), "ldxp xzr, x4, [sp]";
}
}
Loading