about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Sbarra <Sbarra.Paul@gmail.com>2025-04-12 16:14:24 -0500
committerTrevor Gross <t.gross35@gmail.com>2025-04-16 17:35:44 -0500
commit7fb882c3fdf78bc1e3fe06c869e2d62ca64f3810 (patch)
tree6c318ce8c6d2102a2f6da8afda79d5017821890d
parent377b08cc297cd9ae82bfa3e2604eaf64e426b7e6 (diff)
downloadrust-7fb882c3fdf78bc1e3fe06c869e2d62ca64f3810.tar.gz
rust-7fb882c3fdf78bc1e3fe06c869e2d62ca64f3810.zip
avr: __udivmod(h|q)i4
-rw-r--r--library/compiler-builtins/compiler-builtins/src/int/udiv.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs
index a5c16040a52..f18537b006b 100644
--- a/library/compiler-builtins/compiler-builtins/src/int/udiv.rs
+++ b/library/compiler-builtins/compiler-builtins/src/int/udiv.rs
@@ -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! {