avr: __udivmod(h|q)i4

This commit is contained in:
Paul Sbarra 2025-04-12 16:14:24 -05:00 committed by Trevor Gross
parent 377b08cc29
commit 7fb882c3fd

View file

@ -43,6 +43,92 @@ intrinsics! {
((rem as u64) << 32) | (div as u64)
}
#[unsafe(naked)]
pub unsafe extern "C" fn __udivmodqi4() {
// compute unsigned 8-bit `n / d` and `n % d`.
//
// Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
// Inputs:
// R24: dividend
// R22: divisor
// Outputs:
// R24: quotient (dividend / divisor)
// R25: remainder (dividend % divisor)
// Clobbers:
// R23: loop counter
core::arch::naked_asm!(
// This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm.
// Bits shift out of the dividend and into the quotient, so R24 is used for both.
"clr R25", // remainder = 0
"ldi R23, 8", // for each bit
"1:",
"lsl R24", // shift the dividend MSb
"rol R25", // into the remainder LSb
"cp R25, R22", // if remainder >= divisor
"brlo 2f",
"sub R25, R22", // remainder -= divisor
"sbr R24, 1", // quotient |= 1
"2:",
"dec R23", // end loop
"brne 1b",
"ret",
);
}
#[unsafe(naked)]
pub unsafe extern "C" fn __udivmodhi4() {
// compute unsigned 16-bit `n / d` and `n % d`.
//
// Note: GCC implements a [non-standard calling convention](https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention) for this function.
// Inputs:
// R24: dividend [low]
// R25: dividend [high]
// R22: divisor [low]
// R23: divisor [high]
// Outputs:
// R22: quotient [low] (dividend / divisor)
// R23: quotient [high]
// R24: remainder [low] (dividend % divisor)
// R25: remainder [high]
// Clobbers:
// R21: loop counter
// R26: divisor [low]
// R27: divisor [high]
core::arch::naked_asm!(
// This assembly routine implements the [long division](https://en.wikipedia.org/wiki/Division_algorithm#Long_division) algorithm.
// Bits shift out of the dividend and into the quotient, so R24+R25 are used for both.
"mov R26, R22", // move divisor to make room for quotient
"mov R27, R23",
"mov R22, R24", // move dividend to output location (becomes quotient)
"mov R23, R25",
"clr R24", // remainder = 0
"clr R25",
"ldi R21, 16", // for each bit
"1:",
"lsl R22", // shift the dividend MSb
"rol R23",
"rol R24", // into the remainder LSb
"rol R25",
"cp R24, R26", // if remainder >= divisor
"cpc R25, R27",
"brlo 2f",
"sub R24, R26", // remainder -= divisor
"sbc R25, R27",
"sbr R22, 1", // quotient |= 1
"2:",
"dec R21", // end loop
"brne 1b",
"ret",
);
}
}
intrinsics! {