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
2 changes: 2 additions & 0 deletions harm/src/instructions/arith.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ use crate::{
#[macro_use]
pub(crate) mod macros;

pub mod adc;
pub mod add;
pub mod adds;
pub mod sbc;
pub mod sub;
pub mod subs;

Expand Down
94 changes: 94 additions & 0 deletions harm/src/instructions/arith/adc.rs
Original file line number Diff line number Diff line change
@@ -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::{
ADC_32_addsub_carry::ADC_32_addsub_carry, ADC_64_addsub_carry::ADC_64_addsub_carry,
};
use aarchmrs_types::InstructionCode;

use crate::{
instructions::RawInstruction,
register::{IntoReg, Reg32, Reg64, RegOrZero32, RegOrZero64, Register as _},
sealed::Sealed,
};

pub fn adc<T, RealT, S1, S2, RealS1, RealS2>(
dst: T,
src1: S1,
src2: S2,
) -> <Adc<RealT, RealS1, RealS2> as MakeAdc<T, S1, S2>>::Output
where
Adc<RealT, RealS1, RealS2>: MakeAdc<T, S1, S2>,
{
Adc::<RealT, RealS1, RealS2>::new(dst, src1, src2)
}

pub trait MakeAdc<T, S1, S2>: Sealed {
type Output;

fn new(dst: T, src1: S1, src2: S2) -> Self::Output;
}

pub struct Adc<T, S1, S2> {
pub dst: T,
pub src1: S1,
pub src2: S2,
}

impl<T, S1, S2> Sealed for Adc<T, S1, S2> {}

impl MakeAdc<Reg64, Reg64, Reg64> for Adc<Reg64, Reg64, Reg64> {
type Output = Self;

#[inline]
fn new(dst: Reg64, src1: Reg64, src2: Reg64) -> Self {
Self { dst, src1, src2 }
}
}

impl MakeAdc<Reg32, Reg32, Reg32> for Adc<Reg32, Reg32, Reg32> {
type Output = Self;

#[inline]
fn new(dst: Reg32, src1: Reg32, src2: Reg32) -> Self {
Self { dst, src1, src2 }
}
}

define_arith_carry!(Adc, 32, addsub, RegOrZero32, Reg32);
define_arith_carry!(Adc, 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 ADC_DB: &str = "
1a0c0041 adc w1, w2, w12
1a1f0041 adc w1, w2, wzr
1a0c03e1 adc w1, wzr, w12
9a0c0041 adc x1, x2, x12
9a1f0041 adc x1, x2, xzr
9a0c03e1 adc x1, xzr, x12
";

test_cases! {
ADC_DB, untested_adc_db;
test_adc_32, adc(W1, W2, W12), "adc w1, w2, w12";
test_adc_64, adc(X1, X2, X12), "adc x1, x2, x12";
test_adc_64_zero, adc(RegZ(X1), XZR, X12), "adc x1, xzr, x12";
test_adc_32_zero, adc(RegZ32(W1), WZR, W12), "adc w1, wzr, w12";
test_adc_zero_64, adc(RegZ(X1), X2, XZR), "adc x1, x2, xzr";
test_adc_zero_32, adc(RegZ32(W1), W2, WZR), "adc w1, w2, wzr";
}
}
46 changes: 46 additions & 0 deletions harm/src/instructions/arith/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,49 @@ macro_rules! define_arith_extend {
}
};
}

macro_rules! define_arith_carry {
($name:ident, $bits:expr, $cmd:ident, $ztype:ty, $reg:ty) => {
::paste::paste! {
impl RawInstruction for $name<$reg, $reg, $reg> {
#[inline]
fn to_code(&self) -> InstructionCode {
$name {
dst: $ztype::Reg(self.dst),
src1: $ztype::Reg(self.src1),
src2: $ztype::Reg(self.src2),
}
.to_code()
}
}

impl<Src1, Src2> [<Make $name>]<$ztype, Src1, Src2> for $name<$ztype, $ztype, $ztype>
where
Src1: IntoReg<$ztype>,
Src2: IntoReg<$ztype>,
{
type Output = Self;

#[inline]
fn new(dst: $ztype, src1: Src1, src2: Src2) -> Self {
Self { dst, src1: src1.into_reg(), src2: src2.into_reg() }
}
}

impl RawInstruction for $name<$ztype, $ztype, $ztype> {
#[inline]
fn to_code(&self) -> InstructionCode {
let rm = self.src2.index();
let rn = self.src1.index();
let rd = self.dst.index();

[<$name:upper _ $bits _ $cmd _carry>](
rm.into(),
rn.into(),
rd.into(),
)
}
}
}
};
}
94 changes: 94 additions & 0 deletions harm/src/instructions/arith/sbc.rs
Original file line number Diff line number Diff line change
@@ -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::{
SBC_32_addsub_carry::SBC_32_addsub_carry, SBC_64_addsub_carry::SBC_64_addsub_carry,
};
use aarchmrs_types::InstructionCode;

use crate::{
instructions::RawInstruction,
register::{IntoReg, Reg32, Reg64, RegOrZero32, RegOrZero64, Register as _},
sealed::Sealed,
};

pub fn sbc<T, RealT, S1, S2, RealS1, RealS2>(
dst: T,
src1: S1,
src2: S2,
) -> <Sbc<RealT, RealS1, RealS2> as MakeSbc<T, S1, S2>>::Output
where
Sbc<RealT, RealS1, RealS2>: MakeSbc<T, S1, S2>,
{
Sbc::<RealT, RealS1, RealS2>::new(dst, src1, src2)
}

pub trait MakeSbc<T, S1, S2>: Sealed {
type Output;

fn new(dst: T, src1: S1, src2: S2) -> Self::Output;
}

pub struct Sbc<T, S1, S2> {
pub dst: T,
pub src1: S1,
pub src2: S2,
}

impl<T, S1, S2> Sealed for Sbc<T, S1, S2> {}

impl MakeSbc<Reg64, Reg64, Reg64> for Sbc<Reg64, Reg64, Reg64> {
type Output = Self;

#[inline]
fn new(dst: Reg64, src1: Reg64, src2: Reg64) -> Self {
Self { dst, src1, src2 }
}
}

impl MakeSbc<Reg32, Reg32, Reg32> for Sbc<Reg32, Reg32, Reg32> {
type Output = Self;

#[inline]
fn new(dst: Reg32, src1: Reg32, src2: Reg32) -> Self {
Self { dst, src1, src2 }
}
}

define_arith_carry!(Sbc, 32, addsub, RegOrZero32, Reg32);
define_arith_carry!(Sbc, 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 SBC_DB: &str = "
5a0c0041 sbc w1, w2, w12
5a1f0041 sbc w1, w2, wzr
5a0c03e1 sbc w1, wzr, w12
da0c0041 sbc x1, x2, x12
da1f0041 sbc x1, x2, xzr
da0c03e1 sbc x1, xzr, x12
";

test_cases! {
SBC_DB, untested_sbc_db;
test_sbc_32, sbc(W1, W2, W12), "sbc w1, w2, w12";
test_sbc_64, sbc(X1, X2, X12), "sbc x1, x2, x12";
test_sbc_64_zero, sbc(RegZ(X1), XZR, X12), "sbc x1, xzr, x12";
test_sbc_32_zero, sbc(RegZ32(W1), WZR, W12), "sbc w1, wzr, w12";
test_sbc_zero_64, sbc(RegZ(X1), X2, XZR), "sbc x1, x2, xzr";
test_sbc_zero_32, sbc(RegZ32(W1), W2, WZR), "sbc w1, w2, wzr";
}
}