474 lines
12 KiB
C
474 lines
12 KiB
C
/**
|
|
* \file
|
|
*
|
|
* \brief SAM Divide and Square Root Accelerator (DIVAS) Driver
|
|
*
|
|
* Copyright (c) 2015 Atmel Corporation. All rights reserved.
|
|
*
|
|
* \asf_license_start
|
|
*
|
|
* \page License
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. The name of Atmel may not be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* 4. This software may only be redistributed and used in connection with an
|
|
* Atmel microcontroller product.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
|
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* \asf_license_stop
|
|
*
|
|
*/
|
|
/*
|
|
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
|
*/
|
|
|
|
#include "divas.h"
|
|
|
|
/**
|
|
* \internal
|
|
* \brief Initializes and enables the Divide and Square Root Accelerator (DIVAS) Driver.
|
|
*
|
|
* Enable the clocks used by Divide and Square Root Accelerator (DIVAS) Driver.
|
|
* Enable leading zero optimization.
|
|
*
|
|
* \note When SYSTEM module is used, this function will be invoked by
|
|
* \ref system_init() automatically if the module is included.
|
|
*/
|
|
void _system_divas_init(void);
|
|
void _system_divas_init(void)
|
|
{
|
|
/* Turn on the digital interface clock. */
|
|
system_ahb_clock_set_mask(MCLK_AHBMASK_DIVAS);
|
|
|
|
DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_DLZ;
|
|
}
|
|
|
|
/**
|
|
* \brief Signed division operation
|
|
*
|
|
* Run the signed division operation and return the quotient.
|
|
*
|
|
* \param[in] numerator The dividend of the signed division operation
|
|
* \param[in] denominator The divisor of the signed division operation
|
|
*
|
|
* \return The quotient of the DIVAS signed division operation.
|
|
*/
|
|
int32_t divas_idiv(int32_t numerator, int32_t denominator)
|
|
{
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Signed division. */
|
|
DIVAS->CTRLA.reg |= DIVAS_CTRLA_SIGNED;
|
|
|
|
/* Write the dividend to DIVIDEND register. */
|
|
DIVAS->DIVIDEND.reg = numerator;
|
|
/* Write the divisor to DIVISOR register. */
|
|
DIVAS->DIVISOR.reg = denominator;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the division is complete. */
|
|
}
|
|
|
|
int32_t quotient = DIVAS->RESULT.reg;
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return quotient;
|
|
}
|
|
|
|
/**
|
|
* \brief Unsigned division operation
|
|
*
|
|
* Run the unsigned division operation and return the results.
|
|
*
|
|
* \param[in] numerator The dividend of the unsigned division operation
|
|
* \param[in] denominator The divisor of the unsigned division operation
|
|
*
|
|
* \return The quotient of the DIVAS unsigned division operation.
|
|
*/
|
|
uint32_t divas_uidiv(uint32_t numerator, uint32_t denominator)
|
|
{
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Unsigned division. */
|
|
DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_SIGNED;
|
|
|
|
/* Write the dividend to DIVIDEND register. */
|
|
DIVAS->DIVIDEND.reg = numerator;
|
|
/* Write the divisor to DIVISOR register. */
|
|
DIVAS->DIVISOR.reg = denominator;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the division is complete. */
|
|
}
|
|
|
|
uint32_t quotient = DIVAS->RESULT.reg;
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return quotient;
|
|
}
|
|
|
|
/**
|
|
* \brief Signed division remainder operation
|
|
*
|
|
* Run the signed division operation and return the remainder.
|
|
*
|
|
* \param[in] numerator The dividend of the signed division operation
|
|
* \param[in] denominator The divisor of the signed division operation
|
|
*
|
|
* \return The remainder of the DIVAS signed division operation.
|
|
*/
|
|
int32_t divas_idivmod(int32_t numerator, int32_t denominator)
|
|
{
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Signed division. */
|
|
DIVAS->CTRLA.reg |= DIVAS_CTRLA_SIGNED;
|
|
|
|
/* Write the dividend to DIVIDEND register. */
|
|
DIVAS->DIVIDEND.reg = numerator;
|
|
/* Write the divisor to DIVISOR register. */
|
|
DIVAS->DIVISOR.reg = denominator;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the division is complete. */
|
|
}
|
|
|
|
int32_t remainder = DIVAS->REM.reg;
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return remainder;
|
|
}
|
|
|
|
/**
|
|
* \brief Unsigned division remainder operation
|
|
*
|
|
* Run the unsigned division operation and return the remainder.
|
|
*
|
|
* \param[in] numerator The dividend of the unsigned division operation
|
|
* \param[in] denominator The divisor of the unsigned division operation
|
|
*
|
|
* \return The remainder of the DIVAS unsigned division operation.
|
|
*/
|
|
uint32_t divas_uidivmod(uint32_t numerator, uint32_t denominator)
|
|
{
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Unsigned division. */
|
|
DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_SIGNED;
|
|
|
|
/* Write the dividend to DIVIDEND register. */
|
|
DIVAS->DIVIDEND.reg = numerator;
|
|
/* Write the divisor to DIVISOR register. */
|
|
DIVAS->DIVISOR.reg = denominator;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the division is complete. */
|
|
}
|
|
|
|
uint32_t remainder = DIVAS->REM.reg;
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return remainder;
|
|
}
|
|
|
|
/**
|
|
* \brief Square root operation
|
|
*
|
|
* Run the square root operation and return the results.
|
|
*
|
|
* \param[in] radicand The radicand of the square root operation
|
|
*
|
|
* \return The result of the DIVAS square root operation.
|
|
*/
|
|
uint32_t divas_sqrt(uint32_t radicand)
|
|
{
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Write the radicand to DIVIDEND register. */
|
|
DIVAS->SQRNUM.reg = radicand;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the square root is complete. */
|
|
}
|
|
|
|
uint32_t result_sqrt = DIVAS->RESULT.reg;
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return result_sqrt;
|
|
}
|
|
|
|
/**
|
|
* \name DIVAS Operation Overloading
|
|
* @{
|
|
*/
|
|
|
|
#if DIVAS_OVERLOAD_MODE == true
|
|
# if defined ( __GNUC__ )
|
|
|
|
/**
|
|
* \brief Signed division operation overload
|
|
*
|
|
* Run the signed division operation and return the results.
|
|
*
|
|
* \param[in] numerator The dividend of the signed division operation
|
|
* \param[in] denominator The divisor of the signed division operation
|
|
*
|
|
* \return The quotient of the DIVAS signed division operation.
|
|
*/
|
|
int32_t __aeabi_idiv(int32_t numerator, int32_t denominator)
|
|
{
|
|
return divas_idiv(numerator, denominator);
|
|
}
|
|
|
|
/**
|
|
* \brief Unsigned division operation overload
|
|
*
|
|
* Run the unsigned division operation and return the results.
|
|
*
|
|
* \param[in] numerator The dividend of the unsigned division operation
|
|
* \param[in] denominator The divisor of the unsigned division operation
|
|
*
|
|
* \return The quotient of the DIVAS unsigned division operation.
|
|
*/
|
|
uint32_t __aeabi_uidiv(uint32_t numerator, uint32_t denominator)
|
|
{
|
|
return divas_uidiv(numerator, denominator);
|
|
}
|
|
|
|
/**
|
|
* \brief Signed division remainder operation overload
|
|
*
|
|
* Run the signed division operation and return the remainder.
|
|
*
|
|
* \param[in] numerator The dividend of the signed division operation
|
|
* \param[in] denominator The divisor of the signed division operation
|
|
*
|
|
* \return The remainder of the DIVAS signed division operation.
|
|
*/
|
|
uint64_t __aeabi_idivmod(int32_t numerator, int32_t denominator)
|
|
{
|
|
uint64_t uret;
|
|
int32_t quotient, remainder;
|
|
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Signed division. */
|
|
DIVAS->CTRLA.reg |= DIVAS_CTRLA_SIGNED;
|
|
|
|
/* Write the dividend to DIVIDEND register. */
|
|
DIVAS->DIVIDEND.reg = numerator;
|
|
/* Write the divisor to DIVISOR register. */
|
|
DIVAS->DIVISOR.reg = denominator;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the division is complete. */
|
|
}
|
|
|
|
/* Read out the result. */
|
|
quotient = DIVAS->RESULT.reg;
|
|
remainder = DIVAS->REM.reg;
|
|
|
|
/* quotient in r0, remainder in r1 */
|
|
uret = ((uint64_t)quotient & 0x00000000FFFFFFFF ) |
|
|
(((uint64_t)remainder ) << 32);
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return uret;
|
|
}
|
|
|
|
/**
|
|
* \brief Unsigned division remainder operation overload
|
|
*
|
|
* Run the unsigned division operation and return the remainder.
|
|
*
|
|
* \param[in] numerator The dividend of the unsigned division operation
|
|
* \param[in] denominator The divisor of the unsigned division operation
|
|
*
|
|
* \return The remainder of the DIVAS unsigned division operation.
|
|
*/
|
|
uint64_t __aeabi_uidivmod(uint32_t numerator, uint32_t denominator)
|
|
{
|
|
uint64_t uret;
|
|
uint32_t quotient, remainder;
|
|
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Unsigned division. */
|
|
DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_SIGNED;
|
|
|
|
/* Write the dividend to DIVIDEND register. */
|
|
DIVAS->DIVIDEND.reg = numerator;
|
|
/* Write the divisor to DIVISOR register. */
|
|
DIVAS->DIVISOR.reg = denominator;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the division is complete. */
|
|
}
|
|
|
|
/* Read out the result. */
|
|
quotient = DIVAS->RESULT.reg;
|
|
remainder = DIVAS->REM.reg;
|
|
|
|
/* quotient in r0, remainder in r1 */
|
|
uret = quotient | (((uint64_t)remainder) << 32);
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return uret;
|
|
}
|
|
|
|
# elif defined ( __ICCARM__ )
|
|
/**
|
|
* \brief Signed division operation overload
|
|
*
|
|
* Run the signed division operation and return the results.
|
|
*
|
|
* \param[in] numerator The dividend of the signed division operation
|
|
* \param[in] denominator The divisor of the signed division operation
|
|
*
|
|
* \return The quotient of the DIVAS signed division operation.
|
|
*/
|
|
int32_t __aeabi_idiv(int32_t numerator, int32_t denominator)
|
|
{
|
|
return divas_idiv(numerator, denominator);
|
|
}
|
|
|
|
/**
|
|
* \brief Unsigned division operation overload
|
|
*
|
|
* Run the unsigned division operation and return the results.
|
|
*
|
|
* \param[in] numerator The dividend of the unsigned division operation
|
|
* \param[in] denominator The divisor of the unsigned division operation
|
|
*
|
|
* \return The quotient of the DIVAS unsigned division operation.
|
|
*/
|
|
uint32_t __aeabi_uidiv(uint32_t numerator, uint32_t denominator)
|
|
{
|
|
return divas_uidiv(numerator, denominator);
|
|
}
|
|
|
|
/**
|
|
* \brief Signed division remainder operation overload
|
|
*
|
|
* Run the signed division operation and return the remainder.
|
|
* \param[in] numerator The dividend of the signed division operation
|
|
* \param[in] denominator The divisor of the signed division operation
|
|
*
|
|
* \return The remainder of the DIVAS signed division operation.
|
|
*/
|
|
__value_in_regs idiv_return __aeabi_idivmod(int numerator, int denominator)
|
|
{
|
|
idiv_return result;
|
|
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Signed division. */
|
|
DIVAS->CTRLA.reg |= DIVAS_CTRLA_SIGNED;
|
|
|
|
/* Write the dividend to DIVIDEND register. */
|
|
DIVAS->DIVIDEND.reg = numerator;
|
|
/* Write the divisor to DIVISOR register. */
|
|
DIVAS->DIVISOR.reg = denominator;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the division is complete. */
|
|
}
|
|
|
|
/* Read out the result. */
|
|
result.quotient = DIVAS->RESULT.reg;
|
|
result.remainder = DIVAS->REM.reg;
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* \brief Unsigned division remainder operation overload
|
|
*
|
|
* Run the unsigned division operation and return the remainder.
|
|
* \param[in] numerator The dividend of the unsigned division operation
|
|
* \param[in] denominator The divisor of the unsigned division operation
|
|
*
|
|
* \return The remainder of the DIVAS unsigned division operation.
|
|
*/
|
|
__value_in_regs uidiv_return __aeabi_uidivmod(unsigned numerator, unsigned denominator)
|
|
{
|
|
uidiv_return result;
|
|
|
|
/* Disable interrupt. */
|
|
cpu_irq_enter_critical();
|
|
|
|
/* Unsigned division. */
|
|
DIVAS->CTRLA.reg &= ~DIVAS_CTRLA_SIGNED;
|
|
|
|
/* Write the dividend to DIVIDEND register. */
|
|
DIVAS->DIVIDEND.reg = numerator;
|
|
/* Write the divisor to DIVISOR register. */
|
|
DIVAS->DIVISOR.reg = denominator;
|
|
|
|
while(DIVAS->STATUS.bit.BUSY){
|
|
/* Wait the division is complete. */
|
|
}
|
|
|
|
/* Read out the result. */
|
|
result.quotient = DIVAS->RESULT.reg;
|
|
result.remainder = DIVAS->REM.reg;
|
|
|
|
/* Enable interrupt. */
|
|
cpu_irq_leave_critical();
|
|
|
|
return result;
|
|
}
|
|
|
|
# endif
|
|
#endif
|
|
|
|
/** @} */
|
|
|