/*
 * Copyright 2020-2022 Yuntu Microelectronics Co., Ltd.
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

/*!
 * @file divsqrt_driver.h
 * @version 1.4.0
 */

#ifndef DIVSQRT_DRIVER_H
#define DIVSQRT_DRIVER_H

#include <stddef.h>
#include "device_registers.h"
#include "status.h"

/*!
 * @defgroup divsqrt_driver DIVSQRT Driver
 * @ingroup dvsq
 * @details This section describes the programming interface of the DIVSQRT driver.
 * @{
 */
/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*! @brief DIVSQRT execution status */
typedef enum
{
    DIVSQRT_IdleSquareRoot = 0x01U,    /*!< DIVSQRT is idle; the last calculation was a square root */
    DIVSQRT_IdleDivide = 0x02U,    /*!< DIVSQRT is idle; the last calculation was division */
    DIVSQRT_BusySquareRoot = 0x05U,    /*!< DIVSQRT is busy processing a square root calculation */
    DIVSQRT_BusyDivide = 0x06U     /*!< DIVSQRT is busy processing a division calculation */
} dvsq_execution_status_t;

/*! @brief DIVSQRT divide fast start select */
typedef enum
{
    DIVSQRT_EnableFastStart = 0U,     /*!< Division operation is initiated by a write to the DSOR register */
    DIVSQRT_DisableFastStart = 1U      /*!< Division operation is initiated by a write to CSR[SRT] = 1; normal start instead fast start */
} dvsq_fast_start_select_t;

/*******************************************************************************
 * API
 ******************************************************************************/

#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */

/*!
 * @name DIVSQRT functional Operation
 * @{
 */

/*!
 * @brief Performs the DIVSQRT division operation and returns the remainder.
 *
 * @param   base        DIVSQRT peripheral address
 * @param   dividend    Dividend value
 * @param   divisor     Divisor value
 * @param   isUnsigned  Mode of unsigned divide
 *                      - true   unsigned divide
 *                      - false  signed divide
 *
 */
int32_t DIVSQRT_GetDivideRemainder(DIVSQRT_Type *base, int32_t dividend, int32_t divisor, bool isUnsigned);

/*!
 * @brief Performs the DIVSQRT division operation and returns the quotient.
 *
 * @param   base        DIVSQRT peripheral address
 * @param   dividend    Dividend value
 * @param   divisor     Divisor value
 * @param   isUnsigned  Mode of unsigned divide
 *                      - true   unsigned divide
 *                      - false  signed divide
 *
 */
int32_t DIVSQRT_GetDivideQuotient(DIVSQRT_Type *base, int32_t dividend, int32_t divisor, bool isUnsigned);

/*!
 * @brief Performs the DIVSQRT square root operation.
 *
 * This function performs the DIVSQRT square root operation and returns the square root
 * result of a given radicand value.
 *
 * @param   base        DIVSQRT peripheral address
 * @param   radicand    Radicand value
 *
 */
uint16_t DIVSQRT_Sqrt(DIVSQRT_Type *base, uint32_t radicand);

/* @} */

/*!
 * @name DIVSQRT status Operation
 * @{
 */

/*!
 * @brief Gets the DIVSQRT execution status.
 *
 * This function checks the current DIVSQRT execution status of the combined
 * CSR[BUSY, DIV, SQRT] indicators.
 *
 * @param   base       DIVSQRT peripheral address
 *
 * @return  Current DIVSQRT execution status
 */
static inline dvsq_execution_status_t DIVSQRT_GetExecutionStatus(const DIVSQRT_Type *const base)
{
    uint8_t status = (uint8_t)(base->CSR >> DIVSQRT_CSR_SQRT_SHIFT);
    return (status == 0x1U) ? DIVSQRT_IdleSquareRoot : 
           ((status == 0x2U) ? DIVSQRT_IdleDivide :
           ((status == 0x5U) ? DIVSQRT_BusySquareRoot : DIVSQRT_BusyDivide));
}

/*!
 * @brief Configures  DIVSQRT fast start mode.
 *
 * This function sets the DIVSQRT division fast start. The DIVSQRT supports two
 * mechanisms for initiating a division operation. The default mechanism is
 * a "fast start" where a write to the DSOR register begins the division.
 * Alternatively, the start mechanism can begin after a write to the CSR
 * register with CSR[SRT] set.
 *
 * @param   base        DIVSQRT peripheral address
 * @param   mode        Mode of Divide-Fast-Start
 *                      - kMmdvsqDivideFastStart   = 0
 *                      - kMmdvsqDivideNormalStart = 1
 */
static inline void DIVSQRT_SetFastStartConfig(DIVSQRT_Type *base, dvsq_fast_start_select_t mode)
{
    if (mode == DIVSQRT_DisableFastStart)
    {
        base->CSR |= DIVSQRT_CSR_DFS_MASK;
    } else
    {
        base->CSR &= ~DIVSQRT_CSR_DFS_MASK;
    }
}

/*!
 * @brief Configures the DIVSQRT divide-by-zero mode.
 *
 * This function configures the DIVSQRT response to divide-by-zero
 * calculations. If both CSR[DZ] and CSR[DZE] are set, then a subsequent read
 * of the RES register is error-terminated to signal the processor of the
 * attempted divide-by-zero. Otherwise, the register contents are returned.
 *
 * @param   base           DIVSQRT peripheral address
 * @param   isDivByZero    Mode of Divide-By-Zero
 *                          - kMmdvsqDivideByZeroDis = 0
 *                          - kMmdvsqDivideByZeroEn  = 1
 */
static inline void DIVSQRT_SetDivideByZeroConfig(DIVSQRT_Type *base, bool isDivByZero)
{
    if (isDivByZero)
    {
        base->CSR |= DIVSQRT_CSR_DZE_MASK;
    } else
    {
        base->CSR &= ~DIVSQRT_CSR_DZE_MASK;
    }
}

/* @} */

#if defined(__cplusplus)
}

#endif /* __cplusplus */

/*! @}*/

#endif /* DIVSQRT_DRIVER_H */
/*******************************************************************************
 * EOF
 ******************************************************************************/
