diff --git a/harm/src/instructions/arith/add.rs b/harm/src/instructions/arith/add.rs index 71d633c..8d4cf1f 100644 --- a/harm/src/instructions/arith/add.rs +++ b/harm/src/instructions/arith/add.rs @@ -68,7 +68,7 @@ impl MakeAdd for Add { } } -define_arith_faillible!(Add); +define_arith_fallible!(Add); define_arith_shift!(Add, 32, addsub, RegOrZero32, Reg32); define_arith_shift!(Add, 64, addsub, RegOrZero64, Reg64); diff --git a/harm/src/instructions/arith/adds.rs b/harm/src/instructions/arith/adds.rs index 45834bc..06d970b 100644 --- a/harm/src/instructions/arith/adds.rs +++ b/harm/src/instructions/arith/adds.rs @@ -71,7 +71,7 @@ impl MakeAdds for Adds { } } -define_arith_faillible!(Adds); +define_arith_fallible!(Adds); define_arith_shift!(Adds, 32, addsub, RegOrZero32, Reg32); define_arith_shift!(Adds, 64, addsub, RegOrZero64, Reg64); diff --git a/harm/src/instructions/arith/macros.rs b/harm/src/instructions/arith/macros.rs index 3fe6001..e54beff 100644 --- a/harm/src/instructions/arith/macros.rs +++ b/harm/src/instructions/arith/macros.rs @@ -1,4 +1,4 @@ -macro_rules! define_arith_faillible { +macro_rules! define_arith_fallible { ($name:ident) => { ::paste::paste! { impl []> diff --git a/harm/src/instructions/arith/sub.rs b/harm/src/instructions/arith/sub.rs index b2e5270..a4cca47 100644 --- a/harm/src/instructions/arith/sub.rs +++ b/harm/src/instructions/arith/sub.rs @@ -64,7 +64,7 @@ impl MakeSub for Sub { } } -define_arith_faillible!(Sub); +define_arith_fallible!(Sub); define_arith_shift!(Sub, 32, addsub, RegOrZero32, Reg32); define_arith_shift!(Sub, 64, addsub, RegOrZero64, Reg64); diff --git a/harm/src/instructions/arith/subs.rs b/harm/src/instructions/arith/subs.rs index 8da0188..8ab76e5 100644 --- a/harm/src/instructions/arith/subs.rs +++ b/harm/src/instructions/arith/subs.rs @@ -71,7 +71,7 @@ impl MakeSubs for Subs { } } -define_arith_faillible!(Subs); +define_arith_fallible!(Subs); define_arith_shift!(Subs, 32, addsub, RegOrZero32, Reg32); define_arith_shift!(Subs, 64, addsub, RegOrZero64, Reg64); diff --git a/harm/src/instructions/dpimm/pcreladdr.rs b/harm/src/instructions/dpimm/pcreladdr.rs index 41cb39b..dcc7ac4 100644 --- a/harm/src/instructions/dpimm/pcreladdr.rs +++ b/harm/src/instructions/dpimm/pcreladdr.rs @@ -172,7 +172,7 @@ b0800007 adrp x7, .-0xfffff000 test_adrp_plus_max, adrp(X8, SBitValue::new_i64(MAX_ADRP_OFFSET).unwrap()), "adrp x8, .+0xfffff000"; test_adrp_minus_max, adrp(X7, SBitValue::new_i64(-MAX_ADRP_OFFSET).unwrap()), "adrp x7, .-0xfffff000"; - test_adr_0x12345_faillible, adr(X28, 0x12345).unwrap(), "adr x28, .+0x12345"; + test_adr_0x12345_fallible, adr(X28, 0x12345).unwrap(), "adr x28, .+0x12345"; test_adrp_0x12345_fallible, adrp(X9, 0x12345 << 12).unwrap(), "adrp x9, .+0x12345000"; } } diff --git a/harm/src/instructions/ldst.rs b/harm/src/instructions/ldst.rs index 3a1e2c1..698aff4 100644 --- a/harm/src/instructions/ldst.rs +++ b/harm/src/instructions/ldst.rs @@ -9,6 +9,7 @@ pub(crate) mod macros; mod increment; mod shift_extend; +mod ldnp; mod ldp; mod ldpsw; mod ldr; @@ -23,6 +24,7 @@ mod ldurh; mod ldursb; mod ldursh; mod ldursw; +mod stnp; mod stp; mod str; mod strb; @@ -32,6 +34,7 @@ mod sturb; mod sturh; pub use self::increment::*; +pub use self::ldnp::*; pub use self::ldp::*; pub use self::ldpsw::*; pub use self::ldr::*; @@ -47,6 +50,7 @@ pub use self::ldursb::*; pub use self::ldursh::*; pub use self::ldursw::*; pub use self::shift_extend::*; +pub use self::stnp::*; pub use self::stp::*; pub use self::str::*; pub use self::strb::*; diff --git a/harm/src/instructions/ldst/ldnp.rs b/harm/src/instructions/ldst/ldnp.rs new file mode 100644 index 0000000..11bd868 --- /dev/null +++ b/harm/src/instructions/ldst/ldnp.rs @@ -0,0 +1,206 @@ +/* Copyright (C) 2026 Ivan Boldyrev + * + * This document is licensed under the BSD 3-clause license. + */ + +use aarchmrs_instructions::A64::ldst::ldstnapair_offs::{ + LDNP_32_ldstnapair_offs::LDNP_32_ldstnapair_offs, + LDNP_64_ldstnapair_offs::LDNP_64_ldstnapair_offs, +}; + +use crate::bits::BitError; +use crate::register::{IntoReg, RegOrSp64, RegOrZero32, RegOrZero64, Register}; +use crate::sealed::Sealed; + +use super::{LdpStpOffset32, LdpStpOffset64}; + +/// A `ldnp` instruction with a destination and an address. +pub struct Ldnp { + rt: (Rt, Rt), + addr: Addr, +} + +impl Ldnp { + pub fn rt(&self) -> &(Rt, Rt) { + &self.rt + } + + pub fn addr(&self) -> &Addr { + &self.addr + } +} + +impl Sealed for Ldnp {} + +/// Defines possible ways to construct a `ldnp` instruction. +pub trait MakeLdnp: Sealed { + /// Allows defining both fallible and infallible constructors. + type Output; + + fn new(rt: (Rt1, Rt2), addr: Addr) -> Self::Output; +} + +pub fn ldnp( + d1: DestInp1, + d2: DestInp2, + addr: AddrInp, +) -> as MakeLdnp>::Output +where + Ldnp: MakeLdnp, +{ + Ldnp::new((d1, d2), addr) +} + +define_simple_pair_imm_offset_rules!( + Ldnp, + MakeLdnp, + LDNP, + RegOrZero32, + "32", + LdpStpOffset32, + "ldstnapair_offs" +); +define_simple_pair_imm_offset_rules!( + Ldnp, + MakeLdnp, + LDNP, + RegOrZero64, + "64", + LdpStpOffset64, + "ldstnapair_offs" +); +define_pair_fallible_rules!(LDNP, Ldnp, MakeLdnp); + +#[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; + + const LDNP_DB: &str = " +a87f8c41 ldnp x1, x3, [x2, -8] +a8408c41 ldnp x1, x3, [x2, 8] +a85f8c41 ldnp x1, x3, [x2, 504] +a8700c41 ldnp x1, x3, [x2, -256] +a8400c41 ldnp x1, x3, [x2, 0] +a8400c41 ldnp x1, x3, [x2] +a87f8fe1 ldnp x1, x3, [sp, -8] +a8408fe1 ldnp x1, x3, [sp, 8] +a85f8fe1 ldnp x1, x3, [sp, 504] +a8700fe1 ldnp x1, x3, [sp, -256] +a8400fe1 ldnp x1, x3, [sp, 0] +287f8c41 ldnp w1, w3, [x2, -4] +28408c41 ldnp w1, w3, [x2, 4] +285f8c41 ldnp w1, w3, [x2, 252] +28600c41 ldnp w1, w3, [x2, -256] +28400c41 ldnp w1, w3, [x2, 0] +287f8fe1 ldnp w1, w3, [sp, -4] +28408fe1 ldnp w1, w3, [sp, 4] +285f8fe1 ldnp w1, w3, [sp, 252] +28600fe1 ldnp w1, w3, [sp, -256] +28400fe1 ldnp w1, w3, [sp, 0] +a87f8c5f ldnp xzr, x3, [x2, -8] +a8408c5f ldnp xzr, x3, [x2, 8] +a85f8c5f ldnp xzr, x3, [x2, 504] +a8700c5f ldnp xzr, x3, [x2, -256] +a8400c5f ldnp xzr, x3, [x2, 0] +a87f8fff ldnp xzr, x3, [sp, -8] +a8408fff ldnp xzr, x3, [sp, 8] +a85f8fff ldnp xzr, x3, [sp, 504] +a8700fff ldnp xzr, x3, [sp, -256] +a8400fff ldnp xzr, x3, [sp, 0] +287f8c5f ldnp wzr, w3, [x2, -4] +28408c5f ldnp wzr, w3, [x2, 4] +285f8c5f ldnp wzr, w3, [x2, 252] +28600c5f ldnp wzr, w3, [x2, -256] +28400c5f ldnp wzr, w3, [x2, 0] +287f8fff ldnp wzr, w3, [sp, -4] +28408fff ldnp wzr, w3, [sp, 4] +285f8fff ldnp wzr, w3, [sp, 252] +28600fff ldnp wzr, w3, [sp, -256] +28400fff ldnp wzr, w3, [sp, 0] +"; + + test_cases! { + LDNP_DB, untested_ldnp_cases; + test_ldnp_x1_x2_m8, ldnp(X1, X3, (X2, -8i32)).unwrap(), "ldnp x1, x3, [x2, -8]"; + test_ldnp_x1_x2_8, ldnp(X1, X3, (X2, 8i32)).unwrap(), "ldnp x1, x3, [x2, 8]"; + test_ldnp_x1_x2_504, ldnp(X1, X3, (X2, 504i32)).unwrap(), "ldnp x1, x3, [x2, 504]"; + test_ldnp_x1_x2_m256, ldnp(X1, X3, (X2, -256i32)).unwrap(), "ldnp x1, x3, [x2, -256]"; + test_ldnp_x1_x2_0, ldnp(X1, X3, (X2, 0i32)).unwrap(), "ldnp x1, x3, [x2, 0]"; + test_ldnp_x1_x2_simple, ldnp(X1, X3, (X2,)), "ldnp x1, x3, [x2]"; + test_ldnp_x1_sp_m8, ldnp(X1, X3, (SP, -8i32)).unwrap(), "ldnp x1, x3, [sp, -8]"; + test_ldnp_x1_sp_8, ldnp(X1, X3, (SP, 8i32)).unwrap(), "ldnp x1, x3, [sp, 8]"; + test_ldnp_x1_sp_504, ldnp(X1, X3, (SP, 504i32)).unwrap(), "ldnp x1, x3, [sp, 504]"; + test_ldnp_x1_sp_m256, ldnp(X1, X3, (SP, -256i32)).unwrap(), "ldnp x1, x3, [sp, -256]"; + test_ldnp_x1_sp_0, ldnp(X1, X3, (SP, 0i32)).unwrap(), "ldnp x1, x3, [sp, 0]"; + test_ldnp_w1_x2_m4, ldnp(W1, W3, (X2, -4i32)).unwrap(), "ldnp w1, w3, [x2, -4]"; + test_ldnp_w1_x2_4, ldnp(W1, W3, (X2, 4i32)).unwrap(), "ldnp w1, w3, [x2, 4]"; + test_ldnp_w1_x2_252, ldnp(W1, W3, (X2, 252i32)).unwrap(), "ldnp w1, w3, [x2, 252]"; + test_ldnp_w1_x2_m256, ldnp(W1, W3, (X2, -256i32)).unwrap(), "ldnp w1, w3, [x2, -256]"; + test_ldnp_w1_x2_0, ldnp(W1, W3, (X2, 0i32)).unwrap(), "ldnp w1, w3, [x2, 0]"; + test_ldnp_w1_sp_m4, ldnp(W1, W3, (SP, -4i32)).unwrap(), "ldnp w1, w3, [sp, -4]"; + test_ldnp_w1_sp_4, ldnp(W1, W3, (SP, 4i32)).unwrap(), "ldnp w1, w3, [sp, 4]"; + test_ldnp_w1_sp_252, ldnp(W1, W3, (SP, 252i32)).unwrap(), "ldnp w1, w3, [sp, 252]"; + test_ldnp_w1_sp_m256, ldnp(W1, W3, (SP, -256i32)).unwrap(), "ldnp w1, w3, [sp, -256]"; + test_ldnp_w1_sp_0, ldnp(W1, W3, (SP, 0i32)).unwrap(), "ldnp w1, w3, [sp, 0]"; + test_ldnp_xzr_x2_m8, ldnp(XZR, X3, (X2, -8i32)).unwrap(), "ldnp xzr, x3, [x2, -8]"; + test_ldnp_xzr_x2_8, ldnp(XZR, X3, (X2, 8i32)).unwrap(), "ldnp xzr, x3, [x2, 8]"; + test_ldnp_xzr_x2_504, ldnp(XZR, X3, (X2, 504i32)).unwrap(), "ldnp xzr, x3, [x2, 504]"; + test_ldnp_xzr_x2_m256, ldnp(XZR, X3, (X2, -256i32)).unwrap(), "ldnp xzr, x3, [x2, -256]"; + test_ldnp_xzr_x2_0, ldnp(XZR, X3, (X2, 0i32)).unwrap(), "ldnp xzr, x3, [x2, 0]"; + test_ldnp_xzr_sp_m8, ldnp(XZR, X3, (SP, -8i32)).unwrap(), "ldnp xzr, x3, [sp, -8]"; + test_ldnp_xzr_sp_8, ldnp(XZR, X3, (SP, 8i32)).unwrap(), "ldnp xzr, x3, [sp, 8]"; + test_ldnp_xzr_sp_504, ldnp(XZR, X3, (SP, 504i32)).unwrap(), "ldnp xzr, x3, [sp, 504]"; + test_ldnp_xzr_sp_m256, ldnp(XZR, X3, (SP, -256i32)).unwrap(), "ldnp xzr, x3, [sp, -256]"; + test_ldnp_xzr_sp_0, ldnp(XZR, X3, (SP, 0i32)).unwrap(), "ldnp xzr, x3, [sp, 0]"; + test_ldnp_wzr_x2_m4, ldnp(WZR, W3, (X2, -4i32)).unwrap(), "ldnp wzr, w3, [x2, -4]"; + test_ldnp_wzr_x2_4, ldnp(WZR, W3, (X2, 4i32)).unwrap(), "ldnp wzr, w3, [x2, 4]"; + test_ldnp_wzr_x2_252, ldnp(WZR, W3, (X2, 252i32)).unwrap(), "ldnp wzr, w3, [x2, 252]"; + test_ldnp_wzr_x2_m256, ldnp(WZR, W3, (X2, -256i32)).unwrap(), "ldnp wzr, w3, [x2, -256]"; + test_ldnp_wzr_x2_0, ldnp(WZR, W3, (X2, 0i32)).unwrap(), "ldnp wzr, w3, [x2, 0]"; + test_ldnp_wzr_sp_m4, ldnp(WZR, W3, (SP, -4i32)).unwrap(), "ldnp wzr, w3, [sp, -4]"; + test_ldnp_wzr_sp_4, ldnp(WZR, W3, (SP, 4i32)).unwrap(), "ldnp wzr, w3, [sp, 4]"; + test_ldnp_wzr_sp_252, ldnp(WZR, W3, (SP, 252i32)).unwrap(), "ldnp wzr, w3, [sp, 252]"; + test_ldnp_wzr_sp_m256, ldnp(WZR, W3, (SP, -256i32)).unwrap(), "ldnp wzr, w3, [sp, -256]"; + test_ldnp_wzr_sp_0, ldnp(WZR, W3, (SP, 0i32)).unwrap(), "ldnp wzr, w3, [sp, 0]"; + } + + #[test] + fn test_ldnp_r64_offset_underflow() { + assert!(ldnp(X1, X2, (X3, -0x1fci32)).is_err()); + assert!(ldnp(X1, X2, (X3, -0x200i32)).is_ok()); + assert!(ldnp(X1, X2, (X3, -0x204i32)).is_err()); + assert!(ldnp(X1, X2, (X3, -0x208i32)).is_err()); + } + + #[test] + fn test_ldnp_r32_offset_underflow() { + assert!(ldnp(W1, W2, (X3, -0xfei32)).is_err()); + assert!(ldnp(W1, W2, (X3, -0x100i32)).is_ok()); + assert!(ldnp(W1, W2, (X3, -0x102i32)).is_err()); + assert!(ldnp(W1, W2, (X3, -0x104i32)).is_err()); + } + + #[test] + fn test_ldnp_r64_offset_overflow() { + assert!(ldnp(X1, X2, (X3, 0x1f4i32)).is_err()); + assert!(ldnp(X1, X2, (X3, 0x1f8i32)).is_ok()); + assert!(ldnp(X1, X2, (X3, 0x1fci32)).is_err()); + assert!(ldnp(X1, X2, (X3, 0x200i32)).is_err()); + } + + #[test] + fn test_ldnp_r32_offset_overflow() { + assert!(ldnp(W1, W2, (X3, 0xfai32)).is_err()); + assert!(ldnp(W1, W2, (X3, 0xfci32)).is_ok()); + assert!(ldnp(W1, W2, (X3, 0xfei32)).is_err()); + assert!(ldnp(W1, W2, (X3, 0x100i32)).is_err()); + } +} diff --git a/harm/src/instructions/ldst/ldp.rs b/harm/src/instructions/ldst/ldp.rs index 25ee663..6e488e9 100644 --- a/harm/src/instructions/ldst/ldp.rs +++ b/harm/src/instructions/ldst/ldp.rs @@ -38,9 +38,9 @@ impl Ldp { impl Sealed for Ldp {} -/// Defines possible was to construct a `ldp` instruction. +/// Defines possible ways to construct a `ldp` instruction. pub trait MakeLdp: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: (Rt1, Rt2), addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/ldpsw.rs b/harm/src/instructions/ldst/ldpsw.rs index b58ad91..04ed60f 100644 --- a/harm/src/instructions/ldst/ldpsw.rs +++ b/harm/src/instructions/ldst/ldpsw.rs @@ -32,9 +32,9 @@ impl Ldpsw { impl Sealed for Ldpsw {} -/// Defines possible was to construct a `ldpsw` instruction. +/// Defines possible ways to construct a `ldpsw` instruction. pub trait MakeLdpsw: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: (Rt1, Rt2), addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/ldr.rs b/harm/src/instructions/ldst/ldr.rs index a93d39a..99ac002 100644 --- a/harm/src/instructions/ldst/ldr.rs +++ b/harm/src/instructions/ldst/ldr.rs @@ -144,9 +144,9 @@ impl Ldr { impl Sealed for Ldr {} -/// Defines possible was to construct a `ldr` instruction. +/// Defines possible ways to construct a `ldr` instruction. pub trait MakeLdr: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -183,7 +183,7 @@ define_pc_offset_rules!( ); // -// ## Faillible +// ## Fallible // define_fallible_rules!(LDR, Ldr, MakeLdr); diff --git a/harm/src/instructions/ldst/ldrb.rs b/harm/src/instructions/ldst/ldrb.rs index 81f4226..160f259 100644 --- a/harm/src/instructions/ldst/ldrb.rs +++ b/harm/src/instructions/ldst/ldrb.rs @@ -100,9 +100,9 @@ impl Ldrb { impl Sealed for Ldrb {} -/// Defines possible was to construct a `ldrb` instruction. +/// Defines possible ways to construct a `ldrb` instruction. pub trait MakeLdrb: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -118,7 +118,7 @@ define_reg_offset_rules!(Ldrb, MakeLdrb, LDRB, RegOrZero32, "32B", ByteShift); define_imm_offset_rules!(Ldrb, MakeLdrb, LDRB, RegOrZero32, "32", ScaledOffset8); // -// ## Faillible +// ## Fallible // define_fallible_rules!(LDRB, Ldrb, MakeLdrb); diff --git a/harm/src/instructions/ldst/ldrh.rs b/harm/src/instructions/ldst/ldrh.rs index 70e28cc..4900529 100644 --- a/harm/src/instructions/ldst/ldrh.rs +++ b/harm/src/instructions/ldst/ldrh.rs @@ -102,9 +102,9 @@ impl Ldrh { impl Sealed for Ldrh {} -/// Defines possible was to construct a `LDRH` instruction. +/// Defines possible ways to construct a `LDRH` instruction. pub trait MakeLdrh: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -120,7 +120,7 @@ define_reg_offset_rules!(Ldrh, MakeLdrh, LDRH, RegOrZero32, "32", HalfShift); define_imm_offset_rules!(Ldrh, MakeLdrh, LDRH, RegOrZero32, "32", ScaledOffset16); // -// ## Faillible +// ## Fallible // define_fallible_rules!(LDRH, Ldrh, MakeLdrh); diff --git a/harm/src/instructions/ldst/ldrsb.rs b/harm/src/instructions/ldst/ldrsb.rs index 39ea384..d7d0d1a 100644 --- a/harm/src/instructions/ldst/ldrsb.rs +++ b/harm/src/instructions/ldst/ldrsb.rs @@ -112,9 +112,9 @@ impl Ldrsb { impl Sealed for Ldrsb {} -/// Defines possible was to construct a `Ldrsb` instruction. +/// Defines possible ways to construct a `Ldrsb` instruction. pub trait MakeLdrsb: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -131,7 +131,7 @@ define_imm_offset_rules!(Ldrsb, MakeLdrsb, LDRSB, RegOrZero64, 64, ScaledOffset8 define_imm_offset_rules!(Ldrsb, MakeLdrsb, LDRSB, RegOrZero32, 32, ScaledOffset8); // -// ## Faillible +// ## Fallible // define_fallible_rules!(LDRSB, Ldrsb, MakeLdrsb); diff --git a/harm/src/instructions/ldst/ldrsh.rs b/harm/src/instructions/ldst/ldrsh.rs index 0f04ab2..a44df6a 100644 --- a/harm/src/instructions/ldst/ldrsh.rs +++ b/harm/src/instructions/ldst/ldrsh.rs @@ -114,9 +114,9 @@ impl Ldrsh { impl Sealed for Ldrsh {} -/// Defines possible was to construct a `Ldrsh` instruction. +/// Defines possible ways to construct a `Ldrsh` instruction. pub trait MakeLdrsh: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -133,7 +133,7 @@ define_imm_offset_rules!(Ldrsh, MakeLdrsh, LDRSH, RegOrZero64, 64, ScaledOffset1 define_imm_offset_rules!(Ldrsh, MakeLdrsh, LDRSH, RegOrZero32, 32, ScaledOffset16); // -// ## Faillible +// ## Fallible // define_fallible_rules!(LDRSH, Ldrsh, MakeLdrsh); diff --git a/harm/src/instructions/ldst/ldrsw.rs b/harm/src/instructions/ldst/ldrsw.rs index dbef6d5..0a90969 100644 --- a/harm/src/instructions/ldst/ldrsw.rs +++ b/harm/src/instructions/ldst/ldrsw.rs @@ -138,9 +138,9 @@ impl Ldrsw { impl Sealed for Ldrsw {} -/// Defines possible was to construct a `ldsrw` instruction. +/// Defines possible ways to construct a `ldsrw` instruction. pub trait MakeLdrsw: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -167,7 +167,7 @@ define_pc_offset_rules!( ); // -// ## Faillible +// ## Fallible // define_fallible_rules!(LDRSW, Ldrsw, MakeLdrsw); diff --git a/harm/src/instructions/ldst/ldur.rs b/harm/src/instructions/ldst/ldur.rs index 1f4f9e5..45fd7e0 100644 --- a/harm/src/instructions/ldst/ldur.rs +++ b/harm/src/instructions/ldst/ldur.rs @@ -32,9 +32,9 @@ impl Ldur { impl Sealed for Ldur {} -/// Defines possible was to construct a `ldur` instruction. +/// Defines possible ways to construct a `ldur` instruction. pub trait MakeLdur: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/ldurb.rs b/harm/src/instructions/ldst/ldurb.rs index b470786..c8ed475 100644 --- a/harm/src/instructions/ldst/ldurb.rs +++ b/harm/src/instructions/ldst/ldurb.rs @@ -30,9 +30,9 @@ impl Ldurb { impl Sealed for Ldurb {} -/// Defines possible was to construct a `ldurb` instruction. +/// Defines possible ways to construct a `ldurb` instruction. pub trait MakeLdurb: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/ldurh.rs b/harm/src/instructions/ldst/ldurh.rs index 463542a..99d2a1b 100644 --- a/harm/src/instructions/ldst/ldurh.rs +++ b/harm/src/instructions/ldst/ldurh.rs @@ -30,9 +30,9 @@ impl Ldurh { impl Sealed for Ldurh {} -/// Defines possible was to construct a `ldurh` instruction. +/// Defines possible ways to construct a `ldurh` instruction. pub trait MakeLdurh: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/ldursb.rs b/harm/src/instructions/ldst/ldursb.rs index 52f213a..4d5b5d2 100644 --- a/harm/src/instructions/ldst/ldursb.rs +++ b/harm/src/instructions/ldst/ldursb.rs @@ -33,9 +33,9 @@ impl Ldursb { impl Sealed for Ldursb {} -/// Defines possible was to construct a `ldursb` instruction. +/// Defines possible ways to construct a `ldursb` instruction. pub trait MakeLdursb: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/ldursh.rs b/harm/src/instructions/ldst/ldursh.rs index cc7e56b..b93bafa 100644 --- a/harm/src/instructions/ldst/ldursh.rs +++ b/harm/src/instructions/ldst/ldursh.rs @@ -33,9 +33,9 @@ impl Ldursh { impl Sealed for Ldursh {} -/// Defines possible was to construct a `ldursh` instruction. +/// Defines possible ways to construct a `ldursh` instruction. pub trait MakeLdursh: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/ldursw.rs b/harm/src/instructions/ldst/ldursw.rs index d5e0a5e..c8a8324 100644 --- a/harm/src/instructions/ldst/ldursw.rs +++ b/harm/src/instructions/ldst/ldursw.rs @@ -30,9 +30,9 @@ impl Ldursw { impl Sealed for Ldursw {} -/// Defines possible was to construct a `ldursw` instruction. +/// Defines possible ways to construct a `ldursw` instruction. pub trait MakeLdursw: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/macros.rs b/harm/src/instructions/ldst/macros.rs index dd9545b..df92cb3 100644 --- a/harm/src/instructions/ldst/macros.rs +++ b/harm/src/instructions/ldst/macros.rs @@ -8,7 +8,9 @@ macro_rules! define_reg_offset_rules { define_reg_offset_rules!($name, $trait_name, $mnem, $rt, $bitness, $rt); }; ($name:ident, $trait_name:ident, $mnem:ident, $rt:ty, $bitness:expr, $shift:ty) => { - /// `LDR` with 64-bit destination, base register with extended 64-bit register offset with scale. + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, base register with extended 64-bit register offset with scale."] impl $trait_name for $name<$rt, (RegOrSp64, Extended<$shift, RegOrZero64>)> where @@ -27,7 +29,9 @@ macro_rules! define_reg_offset_rules { } } - /// `LDR` with 64-bit destination, base register with extended 32-bit register offset with scale. + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, base register with extended 32-bit register offset with scale."] impl $trait_name for $name<$rt, (RegOrSp64, Extended<$shift, RegOrZero32>)> where @@ -46,7 +50,9 @@ macro_rules! define_reg_offset_rules { } } - /// `LDR` with 64-bit destination, base register with 64-bit offset without scaling. + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, base register with 64-bit offset without scaling."] impl $trait_name for $name<$rt, (RegOrSp64, RegOrZero64)> where @@ -113,7 +119,9 @@ macro_rules! define_reg_offset_rules { macro_rules! define_imm_offset_rules { ($name:ident, $trait_name:ident, $mnem:ident, $rt:ty, $bitness:expr, $offset_type:ty) => { - /// `LDR` with 64-bit destination, bare base register. + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, bare base register."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where Rt: IntoReg<$rt>, @@ -130,7 +138,9 @@ macro_rules! define_imm_offset_rules { } } - /// `LDR` with 64-bit destination, bare base register as a tuple. + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, bare base register as a tuple."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where Rt: IntoReg<$rt>, @@ -147,7 +157,9 @@ macro_rules! define_imm_offset_rules { } } - /// `LDR` with 64-bit destination, base register with aligned immediate offset. + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, base register with aligned immediate offset."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where @@ -165,8 +177,10 @@ macro_rules! define_imm_offset_rules { } } - /// `LDR` with 64-bit destination, base register with immediate offset. It is fallible, as the offset has to have - /// specific range and alignment. + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, base register with immediate offset. It is fallible, as the offset has to have +specific range and alignment."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where Rt: IntoReg<$rt>, @@ -184,8 +198,10 @@ macro_rules! define_imm_offset_rules { } } - /// `LDR` with 64-bit destination, base register with immediate offset. It is fallible, as the offset has to have - /// specific range and alignment. + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, base register with immediate offset. It is fallible, as the offset has to have +specific range and alignment."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where Rt: IntoReg<$rt>, @@ -428,7 +444,7 @@ macro_rules! define_fallible_rules { ($mnem: ident, $name:ident, $trait_name:ident) => { #[doc = "`"] #[doc = stringify!($mnem)] - #[doc = "` with fallible offset that delegates to non-faillible variants."] + #[doc = "` with fallible offset that delegates to non-fallible variants."] impl $trait_name)> for $name where @@ -449,7 +465,7 @@ macro_rules! define_fallible_rules { #[doc = "`"] #[doc = stringify!($mnem)] - #[doc = "` with fallible offset that delegates to non-faillible variants."] + #[doc = "` with fallible offset that delegates to non-fallible variants."] impl $trait_name, BaseInp)> for $name @@ -471,7 +487,7 @@ macro_rules! define_fallible_rules { #[doc = "`"] #[doc = stringify!($mnem)] - #[doc = "` with fallible address that delegates to non-faillible variants."] + #[doc = "` with fallible address that delegates to non-fallible variants."] impl $trait_name> for $name where @@ -488,9 +504,11 @@ macro_rules! define_fallible_rules { } #[macro_export] -macro_rules! define_pair_imm_offset_rules { - ($name:ident, $trait_name:ident, $mnem:ident, $rt:ty, $bitness:expr, $offset_type:ty) => { - #[doc = r" `LDP` with 64-bit destination, base register with aligned immediate offset."] +macro_rules! define_simple_pair_imm_offset_rules { + ($name:ident, $trait_name:ident, $mnem:ident, $rt:ty, $bitness:expr, $offset_type:ty, $suffix:expr) => { + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = r"` with 64-bit destination, base register with aligned immediate offset."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where @@ -508,7 +526,9 @@ macro_rules! define_pair_imm_offset_rules { } } - #[doc = r" `LDP` with 64-bit destination and base register."] + #[doc = r" `"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination and base register."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where @@ -526,7 +546,9 @@ macro_rules! define_pair_imm_offset_rules { } } - #[doc = r" `LDP` with 64-bit destination and base register."] + #[doc = r" `"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination and base register."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where @@ -544,7 +566,9 @@ macro_rules! define_pair_imm_offset_rules { } } - #[doc = r" `LDP` with 64-bit destination, base register with immediate offset. It is fallible, as the offset has to have"] + #[doc = r"`"] + #[doc = stringify!($mnem)] + #[doc = "` with 64-bit destination, base register with immediate offset. It is fallible, as the offset has to have"] #[doc = r" specific range and alignment."] impl $trait_name for $name<$rt, (RegOrSp64, $offset_type)> where @@ -562,6 +586,37 @@ macro_rules! define_pair_imm_offset_rules { }) } } + + ::paste::paste! { + impl $crate::instructions::RawInstruction for $name<$rt, (RegOrSp64, $offset_type)> { + #[inline] + fn to_code(&self) -> $crate::InstructionCode { + let (base, offset) = self.addr; + let code = [<$mnem _ $bitness _ $suffix>]( + offset.into(), + self.rt.1.index(), + base.index(), + self.rt.0.index(), + ); + code + } + } + } + }; +} + +#[macro_export] +macro_rules! define_pair_imm_offset_rules { + ($name:ident, $trait_name:ident, $mnem:ident, $rt:ty, $bitness:expr, $offset_type:ty) => { + define_simple_pair_imm_offset_rules!( + $name, + $trait_name, + $mnem, + $rt, + $bitness, + $offset_type, + ldstpair_off + ); impl, Rt2: IntoReg<$rt>, Base: IntoReg> $trait_name, Base)> for $name<$rt, (Inc<$offset_type>, RegOrSp64)> @@ -588,19 +643,6 @@ macro_rules! define_pair_imm_offset_rules { } ::paste::paste! { - impl $crate::instructions::RawInstruction for $name<$rt, (RegOrSp64, $offset_type)> { - #[inline] - fn to_code(&self) -> $crate::InstructionCode { - let (base, offset) = self.addr; - let code = [<$mnem _ $bitness _ldstpair_off>]( - offset.into(), - self.rt.1.index(), - base.index(), - self.rt.0.index(), - ); - code - } - } impl $crate::instructions::RawInstruction for $name<$rt, (Inc<$offset_type>, RegOrSp64)> { #[inline] fn to_code(&self) -> $crate::InstructionCode { @@ -636,7 +678,7 @@ macro_rules! define_pair_fallible_rules { ($mnem: ident, $name:ident, $trait_name:ident) => { #[doc = "`"] #[doc = stringify!($mnem)] - #[doc = "` with fallible offset that delegates to non-faillible variants."] + #[doc = "` with fallible offset that delegates to non-fallible variants."] impl $trait_name)> for $name @@ -661,7 +703,7 @@ macro_rules! define_pair_fallible_rules { #[doc = "`"] #[doc = stringify!($mnem)] - #[doc = "` with fallible offset that delegates to non-faillible variants."] + #[doc = "` with fallible offset that delegates to non-fallible variants."] impl $trait_name, BaseInp)> for $name @@ -686,7 +728,7 @@ macro_rules! define_pair_fallible_rules { #[doc = "`"] #[doc = stringify!($mnem)] - #[doc = "` with fallible address that delegates to non-faillible variants."] + #[doc = "` with fallible address that delegates to non-fallible variants."] impl $trait_name> for $name where diff --git a/harm/src/instructions/ldst/stnp.rs b/harm/src/instructions/ldst/stnp.rs new file mode 100644 index 0000000..cae66e3 --- /dev/null +++ b/harm/src/instructions/ldst/stnp.rs @@ -0,0 +1,206 @@ +/* Copyright (C) 2026 Ivan Boldyrev + * + * This document is licensed under the BSD 3-clause license. + */ + +use aarchmrs_instructions::A64::ldst::ldstnapair_offs::{ + STNP_32_ldstnapair_offs::STNP_32_ldstnapair_offs, + STNP_64_ldstnapair_offs::STNP_64_ldstnapair_offs, +}; + +use crate::bits::BitError; +use crate::register::{IntoReg, RegOrSp64, RegOrZero32, RegOrZero64, Register}; +use crate::sealed::Sealed; + +use super::{LdpStpOffset32, LdpStpOffset64}; + +/// A `stnp` instruction with a destination and an address. +pub struct Stnp { + rt: (Rt, Rt), + addr: Addr, +} + +impl Stnp { + pub fn rt(&self) -> &(Rt, Rt) { + &self.rt + } + + pub fn addr(&self) -> &Addr { + &self.addr + } +} + +impl Sealed for Stnp {} + +/// Defines possible ways to construct a `stnp` instruction. +pub trait MakeStnp: Sealed { + /// Allows defining both fallible and infallible constructors. + type Output; + + fn new(rt: (Rt1, Rt2), addr: Addr) -> Self::Output; +} + +pub fn stnp( + d1: DestInp1, + d2: DestInp2, + addr: AddrInp, +) -> as MakeStnp>::Output +where + Stnp: MakeStnp, +{ + Stnp::new((d1, d2), addr) +} + +define_simple_pair_imm_offset_rules!( + Stnp, + MakeStnp, + STNP, + RegOrZero32, + "32", + LdpStpOffset32, + "ldstnapair_offs" +); +define_simple_pair_imm_offset_rules!( + Stnp, + MakeStnp, + STNP, + RegOrZero64, + "64", + LdpStpOffset64, + "ldstnapair_offs" +); +define_pair_fallible_rules!(STNP, Stnp, MakeStnp); + +#[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; + + const STNP_DB: &str = " +a83f8c41 stnp x1, x3, [x2, -8] +a8008c41 stnp x1, x3, [x2, 8] +a81f8c41 stnp x1, x3, [x2, 504] +a8300c41 stnp x1, x3, [x2, -256] +a8000c41 stnp x1, x3, [x2, 0] +a8000c41 stnp x1, x3, [x2] +a83f8fe1 stnp x1, x3, [sp, -8] +a8008fe1 stnp x1, x3, [sp, 8] +a81f8fe1 stnp x1, x3, [sp, 504] +a8300fe1 stnp x1, x3, [sp, -256] +a8000fe1 stnp x1, x3, [sp, 0] +283f8c41 stnp w1, w3, [x2, -4] +28008c41 stnp w1, w3, [x2, 4] +281f8c41 stnp w1, w3, [x2, 252] +28200c41 stnp w1, w3, [x2, -256] +28000c41 stnp w1, w3, [x2, 0] +283f8fe1 stnp w1, w3, [sp, -4] +28008fe1 stnp w1, w3, [sp, 4] +281f8fe1 stnp w1, w3, [sp, 252] +28200fe1 stnp w1, w3, [sp, -256] +28000fe1 stnp w1, w3, [sp, 0] +a83f8c5f stnp xzr, x3, [x2, -8] +a8008c5f stnp xzr, x3, [x2, 8] +a81f8c5f stnp xzr, x3, [x2, 504] +a8300c5f stnp xzr, x3, [x2, -256] +a8000c5f stnp xzr, x3, [x2, 0] +a83f8fff stnp xzr, x3, [sp, -8] +a8008fff stnp xzr, x3, [sp, 8] +a81f8fff stnp xzr, x3, [sp, 504] +a8300fff stnp xzr, x3, [sp, -256] +a8000fff stnp xzr, x3, [sp, 0] +283f8c5f stnp wzr, w3, [x2, -4] +28008c5f stnp wzr, w3, [x2, 4] +281f8c5f stnp wzr, w3, [x2, 252] +28200c5f stnp wzr, w3, [x2, -256] +28000c5f stnp wzr, w3, [x2, 0] +283f8fff stnp wzr, w3, [sp, -4] +28008fff stnp wzr, w3, [sp, 4] +281f8fff stnp wzr, w3, [sp, 252] +28200fff stnp wzr, w3, [sp, -256] +28000fff stnp wzr, w3, [sp, 0] +"; + + test_cases! { + STNP_DB, untested_stnp_cases; + test_stnp_x1_x2_m8, stnp(X1, X3, (X2, -8i32)).unwrap(), "stnp x1, x3, [x2, -8]"; + test_stnp_x1_x2_8, stnp(X1, X3, (X2, 8i32)).unwrap(), "stnp x1, x3, [x2, 8]"; + test_stnp_x1_x2_504, stnp(X1, X3, (X2, 504i32)).unwrap(), "stnp x1, x3, [x2, 504]"; + test_stnp_x1_x2_m256, stnp(X1, X3, (X2, -256i32)).unwrap(), "stnp x1, x3, [x2, -256]"; + test_stnp_x1_x2_0, stnp(X1, X3, (X2, 0i32)).unwrap(), "stnp x1, x3, [x2, 0]"; + test_stnp_x1_x2_simple, stnp(X1, X3, (X2,)), "stnp x1, x3, [x2]"; + test_stnp_x1_sp_m8, stnp(X1, X3, (SP, -8i32)).unwrap(), "stnp x1, x3, [sp, -8]"; + test_stnp_x1_sp_8, stnp(X1, X3, (SP, 8i32)).unwrap(), "stnp x1, x3, [sp, 8]"; + test_stnp_x1_sp_504, stnp(X1, X3, (SP, 504i32)).unwrap(), "stnp x1, x3, [sp, 504]"; + test_stnp_x1_sp_m256, stnp(X1, X3, (SP, -256i32)).unwrap(), "stnp x1, x3, [sp, -256]"; + test_stnp_x1_sp_0, stnp(X1, X3, (SP, 0i32)).unwrap(), "stnp x1, x3, [sp, 0]"; + test_stnp_w1_x2_m4, stnp(W1, W3, (X2, -4i32)).unwrap(), "stnp w1, w3, [x2, -4]"; + test_stnp_w1_x2_4, stnp(W1, W3, (X2, 4i32)).unwrap(), "stnp w1, w3, [x2, 4]"; + test_stnp_w1_x2_252, stnp(W1, W3, (X2, 252i32)).unwrap(), "stnp w1, w3, [x2, 252]"; + test_stnp_w1_x2_m256, stnp(W1, W3, (X2, -256i32)).unwrap(), "stnp w1, w3, [x2, -256]"; + test_stnp_w1_x2_0, stnp(W1, W3, (X2, 0i32)).unwrap(), "stnp w1, w3, [x2, 0]"; + test_stnp_w1_sp_m4, stnp(W1, W3, (SP, -4i32)).unwrap(), "stnp w1, w3, [sp, -4]"; + test_stnp_w1_sp_4, stnp(W1, W3, (SP, 4i32)).unwrap(), "stnp w1, w3, [sp, 4]"; + test_stnp_w1_sp_252, stnp(W1, W3, (SP, 252i32)).unwrap(), "stnp w1, w3, [sp, 252]"; + test_stnp_w1_sp_m256, stnp(W1, W3, (SP, -256i32)).unwrap(), "stnp w1, w3, [sp, -256]"; + test_stnp_w1_sp_0, stnp(W1, W3, (SP, 0i32)).unwrap(), "stnp w1, w3, [sp, 0]"; + test_stnp_xzr_x2_m8, stnp(XZR, X3, (X2, -8i32)).unwrap(), "stnp xzr, x3, [x2, -8]"; + test_stnp_xzr_x2_8, stnp(XZR, X3, (X2, 8i32)).unwrap(), "stnp xzr, x3, [x2, 8]"; + test_stnp_xzr_x2_504, stnp(XZR, X3, (X2, 504i32)).unwrap(), "stnp xzr, x3, [x2, 504]"; + test_stnp_xzr_x2_m256, stnp(XZR, X3, (X2, -256i32)).unwrap(), "stnp xzr, x3, [x2, -256]"; + test_stnp_xzr_x2_0, stnp(XZR, X3, (X2, 0i32)).unwrap(), "stnp xzr, x3, [x2, 0]"; + test_stnp_xzr_sp_m8, stnp(XZR, X3, (SP, -8i32)).unwrap(), "stnp xzr, x3, [sp, -8]"; + test_stnp_xzr_sp_8, stnp(XZR, X3, (SP, 8i32)).unwrap(), "stnp xzr, x3, [sp, 8]"; + test_stnp_xzr_sp_504, stnp(XZR, X3, (SP, 504i32)).unwrap(), "stnp xzr, x3, [sp, 504]"; + test_stnp_xzr_sp_m256, stnp(XZR, X3, (SP, -256i32)).unwrap(), "stnp xzr, x3, [sp, -256]"; + test_stnp_xzr_sp_0, stnp(XZR, X3, (SP, 0i32)).unwrap(), "stnp xzr, x3, [sp, 0]"; + test_stnp_wzr_x2_m4, stnp(WZR, W3, (X2, -4i32)).unwrap(), "stnp wzr, w3, [x2, -4]"; + test_stnp_wzr_x2_4, stnp(WZR, W3, (X2, 4i32)).unwrap(), "stnp wzr, w3, [x2, 4]"; + test_stnp_wzr_x2_252, stnp(WZR, W3, (X2, 252i32)).unwrap(), "stnp wzr, w3, [x2, 252]"; + test_stnp_wzr_x2_m256, stnp(WZR, W3, (X2, -256i32)).unwrap(), "stnp wzr, w3, [x2, -256]"; + test_stnp_wzr_x2_0, stnp(WZR, W3, (X2, 0i32)).unwrap(), "stnp wzr, w3, [x2, 0]"; + test_stnp_wzr_sp_m4, stnp(WZR, W3, (SP, -4i32)).unwrap(), "stnp wzr, w3, [sp, -4]"; + test_stnp_wzr_sp_4, stnp(WZR, W3, (SP, 4i32)).unwrap(), "stnp wzr, w3, [sp, 4]"; + test_stnp_wzr_sp_252, stnp(WZR, W3, (SP, 252i32)).unwrap(), "stnp wzr, w3, [sp, 252]"; + test_stnp_wzr_sp_m256, stnp(WZR, W3, (SP, -256i32)).unwrap(), "stnp wzr, w3, [sp, -256]"; + test_stnp_wzr_sp_0, stnp(WZR, W3, (SP, 0i32)).unwrap(), "stnp wzr, w3, [sp, 0]"; + } + + #[test] + fn test_stnp_r64_offset_underflow() { + assert!(stnp(X1, X2, (X3, -0x1fci32)).is_err()); + assert!(stnp(X1, X2, (X3, -0x200i32)).is_ok()); + assert!(stnp(X1, X2, (X3, -0x204i32)).is_err()); + assert!(stnp(X1, X2, (X3, -0x208i32)).is_err()); + } + + #[test] + fn test_stnp_r32_offset_underflow() { + assert!(stnp(W1, W2, (X3, -0xfei32)).is_err()); + assert!(stnp(W1, W2, (X3, -0x100i32)).is_ok()); + assert!(stnp(W1, W2, (X3, -0x102i32)).is_err()); + assert!(stnp(W1, W2, (X3, -0x104i32)).is_err()); + } + + #[test] + fn test_stnp_r64_offset_overflow() { + assert!(stnp(X1, X2, (X3, 0x1f4i32)).is_err()); + assert!(stnp(X1, X2, (X3, 0x1f8i32)).is_ok()); + assert!(stnp(X1, X2, (X3, 0x1fci32)).is_err()); + assert!(stnp(X1, X2, (X3, 0x200i32)).is_err()); + } + + #[test] + fn test_stnp_r32_offset_overflow() { + assert!(stnp(W1, W2, (X3, 0xfai32)).is_err()); + assert!(stnp(W1, W2, (X3, 0xfci32)).is_ok()); + assert!(stnp(W1, W2, (X3, 0xfei32)).is_err()); + assert!(stnp(W1, W2, (X3, 0x100i32)).is_err()); + } +} diff --git a/harm/src/instructions/ldst/stp.rs b/harm/src/instructions/ldst/stp.rs index 602583a..c8eb32a 100644 --- a/harm/src/instructions/ldst/stp.rs +++ b/harm/src/instructions/ldst/stp.rs @@ -40,9 +40,9 @@ impl Stp { impl Sealed for Stp {} -/// Defines possible was to construct a `STP` instruction. +/// Defines possible ways to construct a `STP` instruction. pub trait MakeStp: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: (Rt1, Rt2), addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/str.rs b/harm/src/instructions/ldst/str.rs index 6cfc6e7..b2422fa 100644 --- a/harm/src/instructions/ldst/str.rs +++ b/harm/src/instructions/ldst/str.rs @@ -145,9 +145,9 @@ impl Str { impl Sealed for Str {} -/// Defines possible was to construct a `STR` instruction. +/// Defines possible ways to construct a `STR` instruction. pub trait MakeStr: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -164,7 +164,7 @@ define_imm_offset_rules!(Str, MakeStr, Str, RegOrZero64, 64, ScaledOffset64); define_imm_offset_rules!(Str, MakeStr, Str, RegOrZero32, 32, ScaledOffset32); // -// ## Faillible +// ## Fallible // define_fallible_rules!(STR, Str, MakeStr); diff --git a/harm/src/instructions/ldst/strb.rs b/harm/src/instructions/ldst/strb.rs index ac17177..bef6423 100644 --- a/harm/src/instructions/ldst/strb.rs +++ b/harm/src/instructions/ldst/strb.rs @@ -100,9 +100,9 @@ impl Strb { impl Sealed for Strb {} -/// Defines possible was to construct a `STRB` instruction. +/// Defines possible ways to construct a `STRB` instruction. pub trait MakeStrb: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -118,7 +118,7 @@ define_reg_offset_rules!(Strb, MakeStrb, STRB, RegOrZero32, "32B", ByteShift); define_imm_offset_rules!(Strb, MakeStrb, STRB, RegOrZero32, "32", ScaledOffset8); // -// ## Faillible +// ## Fallible // define_fallible_rules!(STRB, Strb, MakeStrb); diff --git a/harm/src/instructions/ldst/strh.rs b/harm/src/instructions/ldst/strh.rs index 68bf30d..43b5c34 100644 --- a/harm/src/instructions/ldst/strh.rs +++ b/harm/src/instructions/ldst/strh.rs @@ -102,9 +102,9 @@ impl Strh { impl Sealed for Strh {} -/// Defines possible was to construct a `STRH` instruction. +/// Defines possible ways to construct a `STRH` instruction. pub trait MakeStrh: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; } @@ -120,7 +120,7 @@ define_reg_offset_rules!(Strh, MakeStrh, STRH, RegOrZero32, "32", HalfShift); define_imm_offset_rules!(Strh, MakeStrh, STRH, RegOrZero32, "32", ScaledOffset16); // -// ## Faillible +// ## Fallible // define_fallible_rules!(STRH, Strh, MakeStrh); diff --git a/harm/src/instructions/ldst/stur.rs b/harm/src/instructions/ldst/stur.rs index 83373a6..eeeb9ba 100644 --- a/harm/src/instructions/ldst/stur.rs +++ b/harm/src/instructions/ldst/stur.rs @@ -32,9 +32,9 @@ impl Stur { impl Sealed for Stur {} -/// Defines possible was to construct a `stur` instruction. +/// Defines possible ways to construct a `stur` instruction. pub trait MakeStur: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/sturb.rs b/harm/src/instructions/ldst/sturb.rs index fc1c56c..4e3caba 100644 --- a/harm/src/instructions/ldst/sturb.rs +++ b/harm/src/instructions/ldst/sturb.rs @@ -30,9 +30,9 @@ impl Sturb { impl Sealed for Sturb {} -/// Defines possible was to construct a `sturb` instruction. +/// Defines possible ways to construct a `sturb` instruction. pub trait MakeSturb: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/ldst/sturh.rs b/harm/src/instructions/ldst/sturh.rs index ff15418..c0febcb 100644 --- a/harm/src/instructions/ldst/sturh.rs +++ b/harm/src/instructions/ldst/sturh.rs @@ -30,9 +30,9 @@ impl Sturh { impl Sealed for Sturh {} -/// Defines possible was to construct a `sturh` instruction. +/// Defines possible ways to construct a `sturh` instruction. pub trait MakeSturh: Sealed { - /// Allows defining both faillible and infallible constructors. + /// Allows defining both fallible and infallible constructors. type Output; fn new(rt: Rt, addr: Addr) -> Self::Output; diff --git a/harm/src/instructions/mov.rs b/harm/src/instructions/mov.rs index 99f91fe..83f9871 100644 --- a/harm/src/instructions/mov.rs +++ b/harm/src/instructions/mov.rs @@ -29,7 +29,7 @@ * or representable as logical immediate of particular register size (`orr` immedate argument). For `SP`/`WSP` only * logical immediate variant is available. * - * This is always a faillible variant, and it is defined for both `u32` and `i32` for 32-bit registers, and both `u64` + * This is always a fallible variant, and it is defined for both `u32` and `i32` for 32-bit registers, and both `u64` * and `i64` for 64-bit registers. For this reason, the compiler cannot deduce type for immediate untyped argument, * you have to explicitely provide the type. Signed integer variants simply cast the value to unsigned. *