Skip to content

avr: implement unsigned division intrinsics #816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 16, 2025
Merged
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
86 changes: 86 additions & 0 deletions compiler-builtins/src/int/udiv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! {
Expand Down