/*
 * Copyright (c) 2013 Freescale Semiconductor, Inc.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor 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.
 */

/* Implements intrinsics API for the MMDVSQ module */

#ifndef __MMDVSQ_H__
#define __MMDVSQ_H__

#include <stddef.h>
#include <stdint.h>

#if defined(__GNUC__)
	#define __INLINE __attribute__((always_inline,unused))
	#define __ALWAYS_INLINE __attribute__((always_inline))	

	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Wattributes"
	#pragma GCC diagnostic ignored "-Wpragmas"

#elif defined(__CWCC__)
	#define __INLINE	__inline
#endif


/* The header file for the device defines these memory map registers

#define MMDVSQ_DEND                              MMDVSQ_DEND_REG(MMDVSQ_BASE_PTR)
#define MMDVSQ_DSOR                              MMDVSQ_DSOR_REG(MMDVSQ_BASE_PTR)
#define MMDVSQ_CSR                               MMDVSQ_CSR_REG(MMDVSQ_BASE_PTR)
#define MMDVSQ_RES                               MMDVSQ_RES_REG(MMDVSQ_BASE_PTR)
#define MMDVSQ_RCND                              MMDVSQ_RCND_REG(MMDVSQ_BASE_PTR)
*/

/*
	If CSR[REM, USGN] = 0b00, perform a signed divide, returning the quotient
	If CSR[REM, USGN] = 0b01, perform an unsigned divide, returning the quotient
	If CSR[REM, USGN] = 0b10, perform a signed divide, returning the remainder
	If CSR[REM, USGN] = 0b11, perform an unsigned divide, returning the remainder
*/
#define MMDVSQ_USGN_MASK	(1<<1)
#define MMDVSQ_REM_MASK		(1<<2)
#define MMDVSQ_DFS_MASK		(1<<5)

static int32_t __mmdvsq_sdiv (register int32_t dend, register int32_t dsor);
static uint32_t __mmdvsq_udiv (register uint32_t dend, register uint32_t dsor);
static int32_t __mmdvsq_smod (register int32_t dend, register int32_t dsor);
static uint32_t __mmdvsq_umod (register uint32_t dend, register uint32_t dsor);
static uint32_t __mmdvsq_sqrt (register uint32_t rcnd);

__INLINE int32_t __mmdvsq_sdiv (register int32_t dend, register int32_t dsor)
{
	/* setup csr */
	{
		MMDVSQ_CSR &= ~(MMDVSQ_USGN_MASK | MMDVSQ_DFS_MASK | MMDVSQ_REM_MASK);
	}
	
	/*
		store dend
		store dsor; trigger start of operation
	 */
	{
		MMDVSQ_DEND = dend;
		MMDVSQ_DSOR = dsor;
	}
	
	/* return result */
 	return MMDVSQ_RES;
}

__INLINE uint32_t __mmdvsq_udiv (register uint32_t dend, register uint32_t dsor)
{
	/* setup csr */
	{
		MMDVSQ_CSR = (MMDVSQ_CSR & ~(MMDVSQ_REM_MASK | MMDVSQ_DFS_MASK)) 
								 | MMDVSQ_USGN_MASK;
	}
	
	/*
		store dend
		store dsor; trigger start of operation
	 */
	{
		MMDVSQ_DEND = dend;
		MMDVSQ_DSOR = dsor;
	}
	
	/* return result */
 	return MMDVSQ_RES;
}

__INLINE int32_t __mmdvsq_smod (register int32_t dend, register int32_t dsor)
{
	/* setup csr */
	{
		MMDVSQ_CSR = (MMDVSQ_CSR & ~(MMDVSQ_USGN_MASK | MMDVSQ_DFS_MASK)) 
								 | MMDVSQ_REM_MASK;
	}
	
	/*
		store dend
		store dsor; trigger start of operation
	 */
	{
		MMDVSQ_DEND = dend;
		MMDVSQ_DSOR = dsor;
	}
	
	/* return result */
 	return MMDVSQ_RES;
}

__INLINE uint32_t __mmdvsq_umod (register uint32_t dend, register uint32_t dsor)
{
	/* setup csr */
	{
		MMDVSQ_CSR = (MMDVSQ_CSR & ~MMDVSQ_DFS_MASK) 
								 | MMDVSQ_REM_MASK
								 | MMDVSQ_USGN_MASK;
	}
	
	/*
		store dend
		store dsor; trigger start of operation
	 */
	{
		MMDVSQ_DEND = dend;
		MMDVSQ_DSOR = dsor;
	}
	
	/* return result */
 	return MMDVSQ_RES;
}

__INLINE uint32_t __mmdvsq_sqrt (register uint32_t rcnd)
{
	/* store rcnd; trigger sqrt operation */
	MMDVSQ_RCND = rcnd;
	
	/* return result */
	return	MMDVSQ_RES;
}

#if defined(__GNUC__)
	#pragma GCC diagnostic pop
#endif
#endif /*__MMDVSQ_H__*/
