avr: __udivmod(h|q)i4
This commit is contained in:
parent
377b08cc29
commit
7fb882c3fd
1 changed files with 86 additions and 0 deletions
|
|
@ -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! {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue