diff --git a/harm/src/instructions/arith.rs b/harm/src/instructions/arith.rs index c1b9ed5..bf3d71c 100644 --- a/harm/src/instructions/arith.rs +++ b/harm/src/instructions/arith.rs @@ -14,9 +14,11 @@ use crate::{ pub(crate) mod macros; pub mod adc; +pub mod adcs; pub mod add; pub mod adds; pub mod sbc; +pub mod sbcs; pub mod sub; pub mod subs; diff --git a/harm/src/instructions/arith/adcs.rs b/harm/src/instructions/arith/adcs.rs new file mode 100644 index 0000000..68aae25 --- /dev/null +++ b/harm/src/instructions/arith/adcs.rs @@ -0,0 +1,94 @@ +/* Copyright (C) 2026 Ivan Boldyrev + * + * This document is licensed under the BSD 3-clause license. + */ + +use aarchmrs_instructions::A64::dpreg::addsub_carry::{ + ADCS_32_addsub_carry::ADCS_32_addsub_carry, ADCS_64_addsub_carry::ADCS_64_addsub_carry, +}; +use aarchmrs_types::InstructionCode; + +use crate::{ + instructions::RawInstruction, + register::{IntoReg, Reg32, Reg64, RegOrZero32, RegOrZero64, Register as _}, + sealed::Sealed, +}; + +pub fn adcs( + dst: T, + src1: S1, + src2: S2, +) -> as MakeAdcs>::Output +where + Adcs: MakeAdcs, +{ + Adcs::::new(dst, src1, src2) +} + +pub trait MakeAdcs: Sealed { + type Output; + + fn new(dst: T, src1: S1, src2: S2) -> Self::Output; +} + +pub struct Adcs { + pub dst: T, + pub src1: S1, + pub src2: S2, +} + +impl Sealed for Adcs {} + +impl MakeAdcs for Adcs { + type Output = Self; + + #[inline] + fn new(dst: Reg64, src1: Reg64, src2: Reg64) -> Self { + Self { dst, src1, src2 } + } +} + +impl MakeAdcs for Adcs { + type Output = Self; + + #[inline] + fn new(dst: Reg32, src1: Reg32, src2: Reg32) -> Self { + Self { dst, src1, src2 } + } +} + +define_arith_carry!(Adcs, 32, addsub, RegOrZero32, Reg32); +define_arith_carry!(Adcs, 64, addsub, RegOrZero64, Reg64); + +#[cfg(test)] +mod tests { + use harm_test_utils::test_cases; + + use super::*; + use crate::instructions::InstructionSeq; + use Reg32::*; + use Reg64::*; + use RegOrZero32::Reg as RegZ32; + use RegOrZero32::WZR; + use RegOrZero64::Reg as RegZ; + use RegOrZero64::XZR; + + const ADCS_DB: &str = " +3a0c0041 adcs w1, w2, w12 +3a1f0041 adcs w1, w2, wzr +3a0c03e1 adcs w1, wzr, w12 +ba0c0041 adcs x1, x2, x12 +ba1f0041 adcs x1, x2, xzr +ba0c03e1 adcs x1, xzr, x12 +"; + + test_cases! { + ADCS_DB, untested_adcs_db; + test_adcs_32, adcs(W1, W2, W12), "adcs w1, w2, w12"; + test_adcs_64, adcs(X1, X2, X12), "adcs x1, x2, x12"; + test_adcs_64_zero, adcs(RegZ(X1), XZR, X12), "adcs x1, xzr, x12"; + test_adcs_32_zero, adcs(RegZ32(W1), WZR, W12), "adcs w1, wzr, w12"; + test_adcs_zero_64, adcs(RegZ(X1), X2, XZR), "adcs x1, x2, xzr"; + test_adcs_zero_32, adcs(RegZ32(W1), W2, WZR), "adcs w1, w2, wzr"; + } +} diff --git a/harm/src/instructions/arith/sbcs.rs b/harm/src/instructions/arith/sbcs.rs new file mode 100644 index 0000000..278433b --- /dev/null +++ b/harm/src/instructions/arith/sbcs.rs @@ -0,0 +1,94 @@ +/* Copyright (C) 2026 Ivan Boldyrev + * + * This document is licensed under the BSD 3-clause license. + */ + +use aarchmrs_instructions::A64::dpreg::addsub_carry::{ + SBCS_32_addsub_carry::SBCS_32_addsub_carry, SBCS_64_addsub_carry::SBCS_64_addsub_carry, +}; +use aarchmrs_types::InstructionCode; + +use crate::{ + instructions::RawInstruction, + register::{IntoReg, Reg32, Reg64, RegOrZero32, RegOrZero64, Register as _}, + sealed::Sealed, +}; + +pub fn sbcs( + dst: T, + src1: S1, + src2: S2, +) -> as MakeSbcs>::Output +where + Sbcs: MakeSbcs, +{ + Sbcs::::new(dst, src1, src2) +} + +pub trait MakeSbcs: Sealed { + type Output; + + fn new(dst: T, src1: S1, src2: S2) -> Self::Output; +} + +pub struct Sbcs { + pub dst: T, + pub src1: S1, + pub src2: S2, +} + +impl Sealed for Sbcs {} + +impl MakeSbcs for Sbcs { + type Output = Self; + + #[inline] + fn new(dst: Reg64, src1: Reg64, src2: Reg64) -> Self { + Self { dst, src1, src2 } + } +} + +impl MakeSbcs for Sbcs { + type Output = Self; + + #[inline] + fn new(dst: Reg32, src1: Reg32, src2: Reg32) -> Self { + Self { dst, src1, src2 } + } +} + +define_arith_carry!(Sbcs, 32, addsub, RegOrZero32, Reg32); +define_arith_carry!(Sbcs, 64, addsub, RegOrZero64, Reg64); + +#[cfg(test)] +mod tests { + use harm_test_utils::test_cases; + + use super::*; + use crate::instructions::InstructionSeq; + use Reg32::*; + use Reg64::*; + use RegOrZero32::Reg as RegZ32; + use RegOrZero32::WZR; + use RegOrZero64::Reg as RegZ; + use RegOrZero64::XZR; + + const SBCS_DB: &str = " +7a0c0041 sbcs w1, w2, w12 +7a1f0041 sbcs w1, w2, wzr +7a0c03e1 sbcs w1, wzr, w12 +fa0c0041 sbcs x1, x2, x12 +fa1f0041 sbcs x1, x2, xzr +fa0c03e1 sbcs x1, xzr, x12 +"; + + test_cases! { + SBCS_DB, untested_sbcs_db; + test_sbcs_32, sbcs(W1, W2, W12), "sbcs w1, w2, w12"; + test_sbcs_64, sbcs(X1, X2, X12), "sbcs x1, x2, x12"; + test_sbcs_64_zero, sbcs(RegZ(X1), XZR, X12), "sbcs x1, xzr, x12"; + test_sbcs_32_zero, sbcs(RegZ32(W1), WZR, W12), "sbcs w1, wzr, w12"; + test_sbcs_zero_64, sbcs(RegZ(X1), X2, XZR), "sbcs x1, x2, xzr"; + test_sbcs_zero_32, sbcs(RegZ32(W1), W2, WZR), "sbcs w1, w2, wzr"; + } +}