From a14cbb581907cd05208705b51b953ac773abb0d5 Mon Sep 17 00:00:00 2001
From: Rudo <rudo2204@gmail.com>
Date: Sat, 29 May 2021 19:26:49 +0700
Subject: [PATCH] Hardware divide/modulo support (#40)

* Initial SIO div/mod implementation
* Implement signed/unsigned methods for HwDivider
---
 rp2040-hal/src/sio.rs | 68 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 61 insertions(+), 7 deletions(-)

diff --git a/rp2040-hal/src/sio.rs b/rp2040-hal/src/sio.rs
index 111376b..063df57 100644
--- a/rp2040-hal/src/sio.rs
+++ b/rp2040-hal/src/sio.rs
@@ -12,22 +12,34 @@
 //! let pins = pac.IO_BANK0.split(pac.PADS_BANK0, sio.gpio_bank0, &mut pac.RESETS);
 //! ```
 use super::*;
-use core::marker::PhantomData;
 
 /// Marker struct for ownership of SIO gpio bank0
 pub struct SioGpioBank0 {
-    _private: PhantomData<u32>,
+    _private: (),
+}
+
+/// Marker struct for ownership of divide/modulo module
+pub struct HwDivider {
+    _private: (),
+}
+
+/// Result of divide/modulo operation
+pub struct DivResult<T> {
+    /// The remainder of divide/modulo operation
+    pub remainder: T,
+    /// The quotient of divide/modulo operation
+    pub quotient: T,
 }
 
 /// Struct containing ownership markers for managing ownership of the SIO registers.
 pub struct Sio {
     _sio: pac::SIO,
-
     /// GPIO Bank 0 registers
     pub gpio_bank0: SioGpioBank0,
+    /// 8-cycle hardware divide/modulo module
+    pub hwdivider: HwDivider,
     // we can hand out other things here, for example:
     // gpio_qspi
-    // divider
     // interp0
     // interp1
 }
@@ -37,9 +49,51 @@ impl Sio {
         Self {
             _sio: sio,
 
-            gpio_bank0: SioGpioBank0 {
-                _private: PhantomData,
-            },
+            gpio_bank0: SioGpioBank0 { _private: () },
+
+            hwdivider: HwDivider { _private: () },
+        }
+    }
+}
+
+impl HwDivider {
+    /// Perform hardware unsigned divide/modulo operation
+    pub fn unsigned(&self, dividend: u32, divisor: u32) -> DivResult<u32> {
+        let sio = unsafe { &(*pac::SIO::ptr()) };
+        sio.div_sdividend.write(|w| unsafe { w.bits(dividend) });
+
+        sio.div_sdivisor.write(|w| unsafe { w.bits(divisor) });
+
+        cortex_m::asm::delay(8);
+
+        // Note: quotient must be read last
+        let remainder = sio.div_remainder.read().bits();
+        let quotient = sio.div_quotient.read().bits();
+
+        DivResult {
+            remainder,
+            quotient,
+        }
+    }
+
+    /// Perform hardware signed divide/modulo operation
+    pub fn signed(&self, dividend: i32, divisor: i32) -> DivResult<i32> {
+        let sio = unsafe { &(*pac::SIO::ptr()) };
+        sio.div_sdividend
+            .write(|w| unsafe { w.bits(dividend as u32) });
+
+        sio.div_sdivisor
+            .write(|w| unsafe { w.bits(divisor as u32) });
+
+        cortex_m::asm::delay(8);
+
+        // Note: quotient must be read last
+        let remainder = sio.div_remainder.read().bits() as i32;
+        let quotient = sio.div_quotient.read().bits() as i32;
+
+        DivResult {
+            remainder,
+            quotient,
         }
     }
 }