mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
2681 lines
79 KiB
C
2681 lines
79 KiB
C
/**
|
|
******************************************************************************
|
|
* @file ll_aton.c
|
|
* @author SRA Artificial Intelligence & Embedded Architectures
|
|
* @brief ATON LL module driver.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2024 STMicroelectronics.
|
|
* All rights reserved.
|
|
*
|
|
* This software is licensed under terms that can be found in the LICENSE file
|
|
* in the root directory of this software component.
|
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <inttypes.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "ll_aton.h"
|
|
#include "ll_aton_caches_interface.h"
|
|
#include "ll_aton_util.h"
|
|
|
|
#define ATONN_CONST_SRCPORT(S, J, U, I, P) ATON_##S##_##J##_LINK_##U##_##I##_##P
|
|
#define ATONN_CONST_DSTPORT(S, J, U, I, P) ATON_##S##_DST_OFFSET(J, ATON_##S##_##J##_DST##U##_##I##_##P##_IDX)
|
|
|
|
#ifdef ATON_CONVACC_NUM
|
|
static uint32_t Conv_ctrl_bits[ATON_CONVACC_NUM]; // this is an hack FIXME !!!
|
|
#endif
|
|
|
|
#if (ATON_POOL_VERSION_MAJOR_DT < 1) || ((ATON_POOL_VERSION_MAJOR_DT == 1) && (ATON_POOL_VERSION_MINOR_DT <= 0))
|
|
#define POOL_RC14 /* Pooling unit is not yet patched with respect to auto-clearing of `CLR` bit and consistent SW/HW \
|
|
reset values */
|
|
#endif
|
|
|
|
#define ASSERT_UNITS_VERS_W_MSG(unitname, rtl_unitver) \
|
|
do \
|
|
{ \
|
|
rtl_unitver = ATON_##unitname##_VERSION_GET(0); \
|
|
} while (rtl_unitver == 0); \
|
|
assertf(ATON_##unitname##_VERSION_GET_TYPE(rtl_unitver) == ATON_##unitname##_VERSION_TYPE_DT && \
|
|
ATON_##unitname##_VERSION_GET_MAJOR(rtl_unitver) == ATON_##unitname##_VERSION_MAJOR_DT && \
|
|
ATON_##unitname##_VERSION_GET_MINOR(rtl_unitver) == ATON_##unitname##_VERSION_MINOR_DT, \
|
|
0, \
|
|
"%s unit ver mismatch: RTL:t=%" PRIu32 ",ver=%" PRIu32 ".%" PRIu32 " ATON.h:t=%" PRIu32 ",ver=%" PRIu32 \
|
|
".%" PRIu32 "\n\r", \
|
|
#unitname, ATON_##unitname##_VERSION_GET_TYPE(rtl_unitver), \
|
|
ATON_##unitname##_VERSION_GET_MAJOR(rtl_unitver), ATON_##unitname##_VERSION_GET_MINOR(rtl_unitver), \
|
|
(uint32_t)ATON_##unitname##_VERSION_TYPE_DT, (uint32_t)ATON_##unitname##_VERSION_MAJOR_DT, \
|
|
(uint32_t)ATON_##unitname##_VERSION_MINOR_DT)
|
|
|
|
/** @defgroup Simple watchdog management functions.
|
|
* Used to exit from LL_Streng_Wait() in case epoch locks
|
|
* @{
|
|
*/
|
|
|
|
static inline void ll_aton_static_checks(void)
|
|
{
|
|
static char done = 0;
|
|
|
|
if (done != 0)
|
|
return;
|
|
done = 1;
|
|
|
|
#define ASSERT_ATONN_SRCPORT(S, J, U, I, P) \
|
|
LL_ATON_ASSERT(ATONN_CONST_SRCPORT(S, J, U, I, P) == __atonn_getSrcPortID(S, J, U, I, P))
|
|
#define ASSERT_ATONN_DSTPORT(S, J, U, I, P) \
|
|
LL_ATON_ASSERT(ATONN_CONST_DSTPORT(S, J, U, I, P) == __atonn_getDstPortID(S, J, U, I, P))
|
|
|
|
#if ATON_STRENG_NUM > 1
|
|
ASSERT_ATONN_SRCPORT(STRSWITCH, 0, STRENG, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, STRENG, 1, 0);
|
|
#endif
|
|
#if ATON_STRENG_NUM > 2
|
|
ASSERT_ATONN_SRCPORT(STRSWITCH, 0, STRENG, 2, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, STRENG, 2, 0);
|
|
#endif
|
|
|
|
#if (LL_ATON_PLATFORM == LL_ATON_PLAT_EC_TRACE)
|
|
|
|
#if ATON_CONVACC_NUM > 1
|
|
ASSERT_ATONN_SRCPORT(STRSWITCH, 0, CONVACC, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, CONVACC, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, CONVACC, 1, 1);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, CONVACC, 1, 2);
|
|
#endif
|
|
|
|
#if ATON_CONVACC_NUM > 2
|
|
ASSERT_ATONN_SRCPORT(STRSWITCH, 0, CONVACC, 2, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, CONVACC, 2, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, CONVACC, 2, 1);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, CONVACC, 2, 2);
|
|
#endif
|
|
|
|
#if ATON_POOL_NUM > 1
|
|
ASSERT_ATONN_SRCPORT(STRSWITCH, 0, POOL, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, POOL, 1, 0);
|
|
#endif
|
|
|
|
#if ATON_ARITH_NUM > 1
|
|
ASSERT_ATONN_SRCPORT(STRSWITCH, 0, ARITH, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, ARITH, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, ARITH, 1, 1);
|
|
#endif
|
|
|
|
#if ATON_ACTIV_NUM > 1
|
|
ASSERT_ATONN_SRCPORT(STRSWITCH, 0, ACTIV, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, ACTIV, 1, 0);
|
|
#endif
|
|
|
|
#if ATON_DECUN_NUM > 1
|
|
ASSERT_ATONN_SRCPORT(STRSWITCH, 0, DECUN, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, DECUN, 1, 0);
|
|
ASSERT_ATONN_DSTPORT(STRSWITCH, 0, DECUN, 1, 1);
|
|
#endif
|
|
|
|
#endif // (LL_ATON_PLATFORM == LL_ATON_PLAT_EC_TRACE)
|
|
|
|
#undef ASSERT_ATONN_SRCPORT
|
|
#undef ASSERT_ATONN_DSTPORT
|
|
}
|
|
|
|
unsigned char *LL_Address_Physical2Virtual(unsigned char *address)
|
|
{
|
|
return ATON_LIB_PHYSICAL_TO_VIRTUAL_ADDR(address);
|
|
}
|
|
|
|
unsigned char *LL_Address_Virtual2Physical(unsigned char *address)
|
|
{
|
|
return ATON_LIB_VIRTUAL_TO_PHYSICAL_ADDR(address);
|
|
}
|
|
|
|
/**
|
|
* @brief Starts watchdog
|
|
* @param timeout Watchdog timeout in cycles
|
|
* @retval ATON Error code
|
|
*/
|
|
LL_ATON_WEAK int startWatchdog(uint32_t timeout)
|
|
{
|
|
(void)timeout;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Checkes whether watchdog has expired or not
|
|
* @retval ATON Error code
|
|
*/
|
|
LL_ATON_WEAK int checkWatchdog(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @brief ATON global initialization. Initializes clocks and bus interfaces. Must be called before anything else
|
|
* @retval Always zero
|
|
*/
|
|
int LL_ATON_Init(void)
|
|
{
|
|
uint32_t t;
|
|
int i;
|
|
|
|
ll_aton_static_checks();
|
|
|
|
/* Clear pipeline */
|
|
t = ATON_CLKCTRL_CTRL_GET(0);
|
|
t = ATON_CLKCTRL_CTRL_SET_CLR(t, 1);
|
|
ATON_CLKCTRL_CTRL_SET(0, t);
|
|
|
|
/* Enable all ATON clocks */
|
|
ATON_CLKCTRL_CTRL_SET(0, 1);
|
|
ATON_CLKCTRL_AGATES0_SET(0, 0xffffffff);
|
|
ATON_CLKCTRL_AGATES1_SET(0, 0xffffffff);
|
|
|
|
#if (LL_ATON_ENABLE_CLOCK_GATING == 1)
|
|
#if (LL_ATON_PLATFORM == LL_ATON_PLAT_EC_TRACE)
|
|
ATON_CLKCTRL_BGATES_SET(0, (1 << ATON_EPOCHCTRL_CLKB_CLK(0)));
|
|
#else
|
|
ATON_CLKCTRL_BGATES_SET(0, 0x0);
|
|
#endif
|
|
#else
|
|
ATON_CLKCTRL_BGATES_SET(0, 0xffffffff);
|
|
#endif
|
|
|
|
#ifdef ATON_CLKCTRL_BGATES1_OFFSET
|
|
ATON_CLKCTRL_BGATES1_SET(0, 0xffffffff);
|
|
#endif
|
|
|
|
/* Check that RTL and ATON.h match. Only check first unit */
|
|
ASSERT_UNITS_VERS_W_MSG(STRENG, t);
|
|
|
|
#ifdef ATON_CONVACC_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(CONVACC, t);
|
|
#endif
|
|
|
|
#ifdef ATON_POOL_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(POOL, t);
|
|
#endif
|
|
|
|
#ifdef ATON_ARITH_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(ARITH, t);
|
|
#endif
|
|
|
|
#ifdef ATON_ACTIV_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(ACTIV, t);
|
|
#endif
|
|
|
|
#ifdef ATON_DECUN_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(DECUN, t);
|
|
#endif
|
|
|
|
#ifdef ATON_EPOCHCTRL_VERSION_TYPE_DT
|
|
ASSERT_UNITS_VERS_W_MSG(EPOCHCTRL, t);
|
|
#endif
|
|
|
|
#ifdef ATON_RECBUF_VERSION_TYPE_DT
|
|
ASSERT_UNITS_VERS_W_MSG(RECBUF, t);
|
|
#endif
|
|
|
|
#ifdef ATON_STRENG64_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(STRENG64, t);
|
|
#endif
|
|
|
|
#ifdef ATON_STRSWITCH64_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(STRSWITCH64, t);
|
|
#endif
|
|
|
|
#ifdef ATON_STRSWITCH_VC_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(STRSWITCH_VC, t);
|
|
#endif
|
|
|
|
#ifdef ATON_IMC_NUM
|
|
ASSERT_UNITS_VERS_W_MSG(IMC, t);
|
|
#endif
|
|
|
|
ASSERT_UNITS_VERS_W_MSG(CLKCTRL, t);
|
|
|
|
ASSERT_UNITS_VERS_W_MSG(INTCTRL, t);
|
|
|
|
ASSERT_UNITS_VERS_W_MSG(STRSWITCH, t);
|
|
|
|
ASSERT_UNITS_VERS_W_MSG(BUSIF, t);
|
|
|
|
/* Enable Bus Interfaces */
|
|
for (i = 0; i < ATON_BUSIF_NUM; i++)
|
|
{
|
|
ATON_BUSIF_CTRL_SET(i, 1);
|
|
}
|
|
|
|
/* Enable Interrupt Controller */
|
|
ATON_INTCTRL_CTRL_SET(0, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief ATON global de-initialization. Must be called at the very end
|
|
* @retval Always zero
|
|
*/
|
|
int LL_ATON_DeInit(void)
|
|
{
|
|
int i;
|
|
|
|
/* Disable Interrupt Controller */
|
|
ATON_INTCTRL_CTRL_SET(0, 0);
|
|
|
|
/* Disable Bus Interfaces */
|
|
for (i = 0; i < ATON_BUSIF_NUM; i++)
|
|
{
|
|
ATON_BUSIF_CTRL_SET(i, 0);
|
|
}
|
|
|
|
/* Disable all ATON clocks */
|
|
ATON_CLKCTRL_AGATES0_SET(0, 0);
|
|
ATON_CLKCTRL_AGATES1_SET(0, 0);
|
|
ATON_CLKCTRL_BGATES_SET(0, 0);
|
|
#ifdef ATON_CLKCTRL_BGATES1_OFFSET
|
|
ATON_CLKCTRL_BGATES1_SET(0, 0);
|
|
#endif
|
|
ATON_CLKCTRL_CTRL_SET(0, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Enables a set of ATON units
|
|
* @param LL_ATON_EnableUnits_InitStruct Array of units to enable
|
|
* @param n Lenght of the initialization array
|
|
* @retval Error code
|
|
* @todo Add boundary checks
|
|
*/
|
|
int LL_ATON_EnableUnits_Init(const LL_ATON_EnableUnits_InitTypeDef *LL_ATON_EnableUnits_InitStruct, int n)
|
|
{
|
|
int i;
|
|
enum AccelUnitsType unitType;
|
|
uint32_t unitId;
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
unitType = LL_ATON_EnableUnits_InitStruct[i].unit.unit_type;
|
|
unitId = LL_ATON_EnableUnits_InitStruct[i].unit.unit_num;
|
|
|
|
switch (unitType)
|
|
{
|
|
case STRENG:
|
|
ATON_ENABLE(STRENG, unitId);
|
|
break;
|
|
|
|
#ifdef ATON_STRENG64_NUM
|
|
case STRENG64:
|
|
ATON_ENABLE(STRENG64, unitId);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_CONVACC_NUM
|
|
case CONVACC:
|
|
#if 0
|
|
ATON_ENABLE(CONVACC, unitId);
|
|
#else
|
|
ATON_CONVACC_CTRL_SET(unitId, ATON_CONVACC_CTRL_SET_EN(Conv_ctrl_bits[unitId], 1));
|
|
#endif
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_DECUN_NUM
|
|
case DECUN:
|
|
ATON_ENABLE(DECUN, unitId);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_ACTIV_NUM
|
|
case ACTIV:
|
|
ATON_ENABLE(ACTIV, unitId);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_ARITH_NUM
|
|
case ARITH:
|
|
ATON_ENABLE(ARITH, unitId);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_POOL_NUM
|
|
case POOL:
|
|
#ifdef POOL_RC14
|
|
ATON_POOL_CTRL_SET(unitId, ATON_POOL_CTRL_SET_EN(ATON_POOL_CTRL_GET(unitId), 1));
|
|
#else // !POOL_RC14
|
|
ATON_ENABLE(POOL, unitId);
|
|
#endif // !POOL_RC14
|
|
break;
|
|
#endif
|
|
#ifdef ATON_RECBUF_NUM
|
|
case RECBUF:
|
|
ATON_ENABLE(RECBUF, unitId);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Disables a set of ATON units
|
|
* @param LL_ATON_DisableUnits_InitTypeDef Array of units to disable
|
|
* @param n Length of the initialization array
|
|
* @retval Error code
|
|
*/
|
|
int LL_ATON_DisableUnits_Init(const LL_ATON_DisableUnits_InitTypeDef *LL_ATON_DisableUnits_InitStruct, int n)
|
|
{
|
|
int i;
|
|
enum AccelUnitsType unitType;
|
|
uint32_t unitId;
|
|
uint32_t t;
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
unitType = LL_ATON_DisableUnits_InitStruct[i].unit.unit_type;
|
|
unitId = LL_ATON_DisableUnits_InitStruct[i].unit.unit_num;
|
|
|
|
switch (unitType)
|
|
{
|
|
#ifdef ATON_STRENG_NUM
|
|
case STRENG:
|
|
ATON_DISABLE_CLR_CONFCLR(STRENG, unitId);
|
|
LL_ATON_DisableClock(ATON_STRENG_CLKB_CLK(unitId));
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_CONVACC_NUM
|
|
case CONVACC:
|
|
ATON_DISABLE_CLR_CONFCLR(CONVACC, unitId);
|
|
LL_ATON_DisableClock(ATON_CONVACC_CLKB_CLK(unitId));
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_DECUN_NUM
|
|
case DECUN:
|
|
ATON_DISABLE_CLR_CONFCLR(DECUN, unitId);
|
|
LL_ATON_DisableClock(ATON_DECUN_CLKB_CLK(unitId));
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_ACTIV_NUM
|
|
case ACTIV:
|
|
ATON_DISABLE_CLR_CONFCLR(ACTIV, unitId);
|
|
LL_ATON_DisableClock(ATON_ACTIV_CLKB_CLK(unitId));
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_ARITH_NUM
|
|
case ARITH:
|
|
ATON_DISABLE_CLR_CONFCLR(ARITH, unitId);
|
|
LL_ATON_DisableClock(ATON_ARITH_CLKB_CLK(unitId));
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_POOL_NUM
|
|
case POOL:
|
|
#ifdef POOL_RC14
|
|
ATON_POOL_CTRL_SET(unitId, ATON_POOL_CTRL_SET_EN(ATON_POOL_CTRL_GET(unitId), 0));
|
|
#else // !POOL_RC14
|
|
ATON_DISABLE_CLR_CONFCLR(POOL, unitId);
|
|
#endif // !POOL_RC14
|
|
|
|
LL_ATON_DisableClock(ATON_POOL_CLKB_CLK(unitId));
|
|
break;
|
|
#endif
|
|
|
|
#ifdef ATON_RECBUF_NUM
|
|
case RECBUF:
|
|
ATON_DISABLE_CLR_CONFCLR(RECBUF, unitId);
|
|
LL_ATON_DisableClock(ATON_RECBUF_CLKB_CLK(unitId));
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
return LL_ATON_INVALID_PARAM;
|
|
}
|
|
}
|
|
|
|
return LL_ATON_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Waits for streaming engine(s) to become idle
|
|
* @param mask Bitmask of DMA identifiers
|
|
* @retval Error code
|
|
*/
|
|
int LL_Streng_Wait(uint32_t mask)
|
|
{
|
|
int i;
|
|
uint32_t enableFlags;
|
|
|
|
startWatchdog(ATON_EPOCH_TIMEOUT);
|
|
|
|
do
|
|
{
|
|
enableFlags = 0;
|
|
for (i = 0; i < ATON_STRENG_NUM; i++)
|
|
{
|
|
if (mask & (1 << i))
|
|
{
|
|
enableFlags |= (ATON_STRENG_CTRL_GET(i) & (1U << ATON_STRENG_CTRL_RUNNING_LSB));
|
|
}
|
|
}
|
|
|
|
LL_ATON_ASSERT(checkWatchdog() == 0);
|
|
|
|
} while (enableFlags);
|
|
|
|
return LL_ATON_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Configures streaming engine
|
|
* @param id Streaming engine identifier [0..ATON_STRENG_NUM-1]
|
|
* @param conf Pointer to structure(s) describing initialization parameters
|
|
* @param n Number of elements in initialization structure array
|
|
* @retval error code. E.g.: Invalid ID, invalid parameters, not idle,..
|
|
*/
|
|
int LL_Streng_TensorInit(int id, const LL_Streng_TensorInitTypeDef *conf, int n)
|
|
{
|
|
uint32_t t;
|
|
|
|
/* deferred register values */
|
|
uint32_t t_streng_strd = ATON_STRENG_STRD_DT;
|
|
uint32_t t_streng_cid_cache = ATON_STRENG_CID_CACHE_DT;
|
|
uint32_t t_streng_event = ATON_STRENG_EVENT_DT;
|
|
|
|
if (id >= ATON_STRENG_NUM)
|
|
return LL_ATON_INVALID_ID;
|
|
|
|
LL_ATON_EnableClock(ATON_STRENG_CLKB_CLK(id));
|
|
|
|
#define _LL_min(x, y) ((x) > (y) ? (y) : (x))
|
|
|
|
if (n != 1)
|
|
return -1;
|
|
// if (conf->dir == 0 && (conf->nbits_in > conf->nbits_out)) return -1;
|
|
#ifndef ATON_IMC_NUM
|
|
if (conf->nbits_in > 24 || conf->nbits_out > 24)
|
|
return -1;
|
|
#endif
|
|
|
|
t = ATON_STRENG_CTRL_DT;
|
|
t = ATON_STRENG_CTRL_SET_DIR(t, (conf->dir != 0));
|
|
t = ATON_STRENG_CTRL_SET_RAW(t, (conf->raw != 0));
|
|
#ifdef ATON_STRENG_CTRL_SET_RAW_OUT
|
|
t = ATON_STRENG_CTRL_SET_RAW_OUT(t, conf->raw_out);
|
|
#else
|
|
/* Hardware feature not supported */
|
|
LL_ATON_ASSERT(conf->raw_out == 0);
|
|
#endif
|
|
t = ATON_STRENG_CTRL_SET_NOBLK(t, (conf->noblk != 0));
|
|
t = ATON_STRENG_CTRL_SET_NOINC(t, (conf->noinc == 1));
|
|
t = ATON_STRENG_CTRL_SET_SINGLE(t, conf->frame_tot_cnt == 1);
|
|
t = ATON_STRENG_CTRL_SET_CONT(t, conf->continuous == 1);
|
|
t = ATON_STRENG_CTRL_SET_LSBMODE(t, conf->align_right == 1);
|
|
t = ATON_STRENG_CTRL_SET_SIGNEXT(t, conf->align_right == 1 && conf->nbits_unsigned == 0);
|
|
|
|
int ch_bits[3] = {0, 0, 0};
|
|
int in_bits[3];
|
|
int out_bits[3];
|
|
int nbits_out = conf->nbits_out;
|
|
int nbits_in = conf->nbits_in;
|
|
|
|
// case 0: bus -> stream --> in_bits > out_bits -> use FRONT_GAP
|
|
// |
|
|
// case 1: --> in_bits <= out_bits -> use lanes but valid for out_bits=8,16,24 for other bit length out
|
|
// is right shifted by (8,16,24) - out_bits
|
|
//
|
|
// case 2: stream->bus --> in_bits >= out_bits -> use lanes but valid for in_bits=8,16,24 for other bit length out is
|
|
// right shifted by (8,16,24) - out_bits
|
|
// |
|
|
// case 3: --> in_bits < out_bits -> use FRONT_GAP
|
|
|
|
int io_case = ((conf->dir != 0) << 1);
|
|
io_case += (conf->dir == 0 ? (conf->nbits_in <= conf->nbits_out) : (conf->nbits_in < conf->nbits_out));
|
|
|
|
switch (io_case)
|
|
{
|
|
case 0: // in_bits > out_bits && bus->stream
|
|
// must use FRONT_GAP
|
|
{
|
|
if (conf->mem_lsb)
|
|
t_streng_strd = ATON_STRENG_STRD_SET_FGAP(t_streng_strd, (nbits_in - nbits_out));
|
|
else
|
|
t_streng_strd = ATON_STRENG_STRD_SET_BGAP(t_streng_strd, (nbits_in - nbits_out));
|
|
nbits_in = nbits_out;
|
|
}
|
|
// intentional fall through
|
|
case 1: // in_bits <= out_bits && bus->stream
|
|
in_bits[0] = _LL_min(8, nbits_in);
|
|
in_bits[1] = nbits_in > 8 ? _LL_min(8, nbits_in - 8) : 0;
|
|
in_bits[2] = nbits_in > 16 ? _LL_min(8, nbits_in - 16) : 0;
|
|
if (conf->align_right)
|
|
{
|
|
ch_bits[0] = in_bits[0];
|
|
ch_bits[1] = in_bits[1];
|
|
ch_bits[2] = in_bits[2];
|
|
}
|
|
else
|
|
{
|
|
if (nbits_out > 16)
|
|
{
|
|
ch_bits[2] = in_bits[0];
|
|
ch_bits[1] = in_bits[1];
|
|
ch_bits[0] = in_bits[2];
|
|
}
|
|
else if (nbits_out > 8)
|
|
{
|
|
ch_bits[1] = in_bits[0];
|
|
ch_bits[0] = in_bits[1];
|
|
} // N.B. the DMA stuffs the bits to the left of the channel
|
|
else
|
|
ch_bits[0] = in_bits[0];
|
|
}
|
|
break;
|
|
case 3: // in_bits < out_bits && stream->bus
|
|
{
|
|
if (conf->mem_lsb)
|
|
t_streng_strd = ATON_STRENG_STRD_SET_FGAP(t_streng_strd, (nbits_out - nbits_in));
|
|
else
|
|
t_streng_strd = ATON_STRENG_STRD_SET_BGAP(t_streng_strd, (nbits_out - nbits_in));
|
|
nbits_out = nbits_in;
|
|
}
|
|
// intentional fall through
|
|
case 2: // in_bits >= out_bits && stream->bus
|
|
out_bits[0] = _LL_min(8, nbits_out);
|
|
out_bits[1] = nbits_out > 8 ? _LL_min(8, nbits_out - 8) : 0;
|
|
out_bits[2] = nbits_out > 16 ? _LL_min(8, nbits_out - 16) : 0;
|
|
if (conf->align_right)
|
|
{
|
|
ch_bits[0] = out_bits[0];
|
|
ch_bits[1] = out_bits[1];
|
|
ch_bits[2] = out_bits[2];
|
|
}
|
|
else
|
|
{
|
|
if (nbits_in > 16)
|
|
{
|
|
ch_bits[2] = out_bits[0];
|
|
ch_bits[1] = out_bits[1];
|
|
ch_bits[0] = out_bits[2];
|
|
}
|
|
else if (nbits_in > 8)
|
|
{
|
|
ch_bits[1] = out_bits[0];
|
|
ch_bits[0] = out_bits[1];
|
|
} // N.B. the DMA stuffs the bits to the left of the channel
|
|
else
|
|
ch_bits[0] = out_bits[0];
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* Take care of N64 single size register. TODO: double check this */
|
|
#ifdef ATON_STRENG_CTRL_SET_SIZE1
|
|
t = ATON_STRENG_CTRL_SET_SIZE0(t, ch_bits[0]);
|
|
t = ATON_STRENG_CTRL_SET_SIZE1(t, ch_bits[1]);
|
|
t = ATON_STRENG_CTRL_SET_SIZE2(t, ch_bits[2]);
|
|
#else
|
|
if (conf->dir)
|
|
t = ATON_STRENG_CTRL_SET_SIZE0(t, conf->nbits_out);
|
|
else
|
|
t = ATON_STRENG_CTRL_SET_SIZE0(t, conf->nbits_in);
|
|
#endif
|
|
|
|
ATON_STRENG_CTRL_SET(id, t);
|
|
|
|
// ATON_STRENG_ADDR_SET(id, conf->addr_start.i);
|
|
ATON_REG_WRITE_RELOC(((volatile uint32_t *)(uintptr_t)ATON_STRENG_ADDR_ADDR(id)), conf->addr_base.i,
|
|
conf->offset_start);
|
|
|
|
if (conf->raw)
|
|
{
|
|
if (conf->frame_count)
|
|
t = conf->frame_count;
|
|
else
|
|
{
|
|
// N.B. end - start must contain padding if nbits_in is not power of two
|
|
t = (LL_Streng_len(conf) * 8) / (conf->dir == 0 ? conf->nbits_in : conf->nbits_out);
|
|
}
|
|
ATON_STRENG_FSIZE_SET(id, t);
|
|
}
|
|
else
|
|
{
|
|
t = ATON_STRENG_FSIZE_DT;
|
|
t = ATON_STRENG_FSIZE_SET_WIDTH(t, conf->fwidth);
|
|
t = ATON_STRENG_FSIZE_SET_HEIGHT(t, conf->fheight);
|
|
ATON_STRENG_FSIZE_SET(id, t);
|
|
|
|
uint32_t line_offset = conf->line_offset == 0 ? conf->fwidth * conf->batch_offset : conf->line_offset;
|
|
// if line_offset is left=0 then it's computed from the standard geometry of lines and batch
|
|
t_streng_strd = ATON_STRENG_STRD_SET_LOFF(t_streng_strd, line_offset);
|
|
|
|
#if defined(ATON_STRENG_CID_CACHE_SET_LOFF_MSB)
|
|
t = t_streng_cid_cache;
|
|
t = ATON_STRENG_CID_CACHE_SET_LOFF_MSB(t, (line_offset >> ATON_STRENG_STRD_LOFF_W));
|
|
t_streng_cid_cache = t;
|
|
#endif
|
|
|
|
t = ATON_STRENG_DEPTH_DT;
|
|
t = ATON_STRENG_DEPTH_SET_SIZE(t, conf->batch_depth);
|
|
t = ATON_STRENG_DEPTH_SET_OFFSET(t, conf->batch_offset);
|
|
ATON_STRENG_DEPTH_SET(id, t);
|
|
}
|
|
|
|
ATON_STRENG_FRPTOFF_SET(id, conf->loop_offset);
|
|
ATON_STRENG_FRAME_RPT_SET(id, conf->frame_loop_cnt);
|
|
ATON_STRENG_FOFFSET_SET(id, conf->frame_offset);
|
|
|
|
t = ATON_STRENG_LIMITEN_DT; // all other fields set to zero
|
|
t = ATON_STRENG_LIMITEN_SET_FRAMELIMIT(t, 1);
|
|
#if defined(ATON_STRENG_LIMITEN_SET_DOFF_MSB)
|
|
t = ATON_STRENG_LIMITEN_SET_DOFF_MSB(t, conf->batch_offset >> ATON_STRENG_DEPTH_OFFSET_W);
|
|
#endif
|
|
ATON_STRENG_LIMITEN_SET(id, t);
|
|
|
|
if (/*(conf->dir == 0) && */ (conf->offset_limit != 0x0))
|
|
{
|
|
t = ATON_STRENG_LIMITEN_SET_ADDRLIMIT(t, 1);
|
|
t = ATON_STRENG_LIMITEN_SET_STOPPREFTC(t, 1);
|
|
ATON_STRENG_LIMITEN_SET(id, t);
|
|
// NOTE: limiter is to be set to last accessible byte address
|
|
// ATON_STRENG_LIMITADDR_SET(id, (conf->addr_limit.i - 1));
|
|
ATON_REG_WRITE_RELOC(((volatile uint32_t *)(uintptr_t)ATON_STRENG_LIMITADDR_ADDR(id)), conf->addr_base.i,
|
|
conf->offset_limit - 1);
|
|
}
|
|
|
|
ATON_STRENG_LIMIT_SET(id, conf->frame_tot_cnt);
|
|
// LL_ATON_PRINTF("frame_tot_cnt=%d\n", conf->frame_tot_cnt);
|
|
|
|
#if defined(ATON_STRENG_CID_CACHE_SET_CID)
|
|
t_streng_cid_cache = ATON_STRENG_CID_CACHE_SET_CID(t_streng_cid_cache, conf->bus_cid);
|
|
t_streng_cid_cache = ATON_STRENG_CID_CACHE_SET_CACHEABLE(t_streng_cid_cache, conf->cacheable);
|
|
t_streng_cid_cache = ATON_STRENG_CID_CACHE_SET_ALLOC(t_streng_cid_cache, conf->cache_allocate);
|
|
t_streng_cid_cache = ATON_STRENG_CID_CACHE_SET_PFETCH(t_streng_cid_cache, conf->bus_pfetch);
|
|
t_streng_cid_cache = ATON_STRENG_CID_CACHE_SET_LINESIZE(t_streng_cid_cache, conf->cache_linesize);
|
|
#endif
|
|
|
|
/* Enable event interrupts */
|
|
if (conf->dir == 1)
|
|
{
|
|
#if LL_ATON_EN_EVENT_IRQ
|
|
t_streng_event = 0;
|
|
t_streng_event = ATON_STRENG_EVENT_SET_EN_OFLOW_FRM(t_streng_event, 1); // enable frame overflow interrupt
|
|
#if 0
|
|
t_streng_event = ATON_STRENG_EVENT_SET_EN_OFLOW_ADD(t_streng_event, 1); // enable address limiter interrupt
|
|
#endif
|
|
#endif // LL_ATON_EN_EVENT_IRQ
|
|
}
|
|
|
|
/* Enable illegal configuration interrupts */
|
|
#if LL_ATON_EN_ERROR_IRQ
|
|
t = t_streng_event;
|
|
t = ATON_STRENG_EVENT_SET_EN_ILLCFG(t, 1); // Enable Illegal Configuration interrupt
|
|
// t = ATON_STRENG_EVENT_SET_EN_FMTMM(t, 1); // Enable Format Mismatch interrupt (intentionally not enabled)
|
|
t_streng_event = t;
|
|
#endif // LL_ATON_EN_ERROR_IRQ
|
|
|
|
if ((conf->dir == 0) && conf->sync_with_other)
|
|
{
|
|
t = t_streng_event;
|
|
t = ATON_STRENG_EVENT_SET_FRMTRG_EN(t, 1); // Enable synchronizations of frames with other dma
|
|
t = ATON_STRENG_EVENT_SET_FRMTRG_SRC(t, conf->sync_dma); // Enable synchronizations of frames with other dma
|
|
t_streng_event = t;
|
|
}
|
|
|
|
#if 1
|
|
t = ATON_STRENG_POS_DT;
|
|
t = ATON_STRENG_POS_SET_GAPCYCLES(t, 0); // set interline gap cycle to 0, as it should be safe to do so
|
|
ATON_STRENG_POS_SET(id, t);
|
|
#endif
|
|
|
|
/* deferred register setting */
|
|
ATON_STRENG_STRD_SET(id, t_streng_strd);
|
|
ATON_STRENG_CID_CACHE_SET(id, t_streng_cid_cache);
|
|
ATON_STRENG_EVENT_SET(id, t_streng_event);
|
|
|
|
/* Ciphering settings */
|
|
#if (ATON_STRENG_VERSION_ENCR_DT == 1)
|
|
t = ATON_STRENG_ENCR_MSB_DT;
|
|
t = ATON_STRENG_ENCR_MSB_SET_EN(t, conf->cipher_en);
|
|
t = ATON_STRENG_ENCR_MSB_SET_KEY_SEL(t, conf->key_sel);
|
|
ATON_STRENG_ENCR_MSB_SET(id, t);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Configures the Streaming Engine External trigger source
|
|
* To be used, for example, for configuring synchronization with DCMIPP
|
|
* @param id Streaming engine identifier [0..ATON_STRENG_NUM-1]
|
|
* @param conf Pointer to structure describing External Sync configuration
|
|
*/
|
|
int LL_Streng_ExtSyncInit(int id, LL_Streng_ExtSyncTypedef *conf)
|
|
{
|
|
#ifdef ATON_STRENG_EXTSYNC_SET
|
|
uint32_t t;
|
|
|
|
if (id >= ATON_STRENG_NUM)
|
|
return LL_ATON_INVALID_ID;
|
|
|
|
LL_ATON_EnableClock(ATON_STRENG_CLKB_CLK(id));
|
|
|
|
t = ATON_STRENG_EXTSYNC_DT;
|
|
t = ATON_STRENG_EXTSYNC_SET_EN(t, conf->enable);
|
|
t = ATON_STRENG_EXTSYNC_SET_SRC(t, conf->trig_source);
|
|
t = ATON_STRENG_EXTSYNC_SET_LINES(t, conf->lines);
|
|
ATON_STRENG_EXTSYNC_SET(id, t);
|
|
|
|
t = ATON_STRENG_EXTSYNC2_DT;
|
|
t = ATON_STRENG_EXTSYNC2_SET_LINES(t, conf->lines_offset);
|
|
t = ATON_STRENG_EXTSYNC2_SET_OFF(t, conf->offset);
|
|
ATON_STRENG_EXTSYNC2_SET(id, t);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
#if defined(ATON_EPOCHCTRL_NUM)
|
|
/**
|
|
* @brief Sets external trigger signal to hi. Used to synchronize with external units, e.g.: HSP
|
|
* @param irq Interrupt line used as trigger signal
|
|
* @note uses Epoch Controller noack interrupt as irq source
|
|
*/
|
|
int LL_TriggerHigh(int irq)
|
|
{
|
|
if (irq >= ATON_INTCTRL_INTS(0))
|
|
return LL_ATON_INVALID_PARAM;
|
|
|
|
ATON_INTCTRL_INTORMSK_SET(0, irq, ~(1 << ATON_INTCTRL_0_INTORMSK_EPOCHCTRL_0_1_IDX));
|
|
ATON_INTCTRL_INTSET_SET(0, (1 << ATON_INTCTRL_0_INTSET_EPOCHCTRL_0_1_IDX));
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Sets external trigger signal to low. Used to synchronize with external units, e.g.: HSP
|
|
* @param irq Interrupt line used as trigger signal
|
|
* @note uses Epoch Controller noack interrupt as irq source
|
|
*/
|
|
int LL_TriggerLow(int irq)
|
|
{
|
|
if (irq >= ATON_INTCTRL_INTS(0))
|
|
return LL_ATON_INVALID_PARAM;
|
|
|
|
ATON_INTCTRL_INTCLR_SET(0, (1 << ATON_INTCTRL_0_INTCLR_EPOCHCTRL_0_1_IDX));
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
unsigned __atonn_getSrcPortID(enum SwitchUnitsType sut, unsigned char su_num, enum AccelUnitsType aut,
|
|
unsigned char au_num, unsigned char port)
|
|
{
|
|
// FIXME
|
|
LL_ATON_ASSERT(su_num == 0);
|
|
switch (sut)
|
|
{
|
|
case STRSWITCH:
|
|
switch (aut)
|
|
{
|
|
#if defined(ATON_STRENG_NUM)
|
|
case STRENG:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_STRENG_NUM);
|
|
return ATONN_CONST_SRCPORT(STRSWITCH, 0, STRENG, 0, 0) + au_num;
|
|
break;
|
|
#endif
|
|
#if defined(ATON_CONVACC_NUM)
|
|
case CONVACC:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_CONVACC_NUM);
|
|
return ATONN_CONST_SRCPORT(STRSWITCH, 0, CONVACC, 0, 0) + au_num;
|
|
break;
|
|
#endif
|
|
#if defined(ATON_DECUN_NUM)
|
|
case DECUN:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_DECUN_NUM);
|
|
return ATONN_CONST_SRCPORT(STRSWITCH, 0, DECUN, 0, 0) + au_num;
|
|
break;
|
|
#endif
|
|
#if defined(ATON_ACTIV_NUM)
|
|
case ACTIV:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_ACTIV_NUM);
|
|
return ATONN_CONST_SRCPORT(STRSWITCH, 0, ACTIV, 0, 0) + au_num;
|
|
break;
|
|
#endif
|
|
#if defined(ATON_ARITH_NUM)
|
|
case ARITH:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_ARITH_NUM);
|
|
return ATONN_CONST_SRCPORT(STRSWITCH, 0, ARITH, 0, 0) + au_num;
|
|
break;
|
|
#endif
|
|
#if defined(ATON_POOL_NUM)
|
|
case POOL:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_POOL_NUM);
|
|
return ATONN_CONST_SRCPORT(STRSWITCH, 0, POOL, 0, 0) + au_num;
|
|
break;
|
|
#endif
|
|
default:
|
|
LL_ATON_ASSERT(0);
|
|
break;
|
|
}
|
|
break;
|
|
case STRSWITCH64:
|
|
// TODO
|
|
LL_ATON_ASSERT(0);
|
|
break;
|
|
case STRSWITCH_VC:
|
|
// TODO
|
|
LL_ATON_ASSERT(0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned __atonn_getDstPortID(enum SwitchUnitsType sut, unsigned char su_num, enum AccelUnitsType aut,
|
|
unsigned char au_num, unsigned char port)
|
|
{
|
|
// FIXME
|
|
LL_ATON_ASSERT(su_num == 0);
|
|
switch (sut)
|
|
{
|
|
case STRSWITCH:
|
|
switch (aut)
|
|
{
|
|
#if defined(ATON_STRENG_NUM)
|
|
case STRENG:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_STRENG_NUM);
|
|
return ATONN_CONST_DSTPORT(STRSWITCH, 0, STRENG, 0, 0) + (0x4 * au_num);
|
|
break;
|
|
#endif
|
|
#if defined(ATON_CONVACC_NUM)
|
|
case CONVACC:
|
|
LL_ATON_ASSERT(port < 3);
|
|
LL_ATON_ASSERT(au_num < ATON_CONVACC_NUM);
|
|
return ATONN_CONST_DSTPORT(STRSWITCH, 0, CONVACC, 0, 0) + (0x4 * (3 * au_num + port));
|
|
break;
|
|
#endif
|
|
#if defined(ATON_DECUN_NUM)
|
|
case DECUN:
|
|
LL_ATON_ASSERT(port < 2);
|
|
LL_ATON_ASSERT(au_num < ATON_DECUN_NUM);
|
|
return ATONN_CONST_DSTPORT(STRSWITCH, 0, DECUN, 0, 0) + (0x4 * (2 * au_num + port));
|
|
break;
|
|
#endif
|
|
#if defined(ATON_ACTIV_NUM)
|
|
case ACTIV:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_ACTIV_NUM);
|
|
return ATONN_CONST_DSTPORT(STRSWITCH, 0, ACTIV, 0, 0) + (0x4 * au_num);
|
|
break;
|
|
#endif
|
|
#if defined(ATON_ARITH_NUM)
|
|
case ARITH:
|
|
LL_ATON_ASSERT(port < 2);
|
|
LL_ATON_ASSERT(au_num < ATON_ARITH_NUM);
|
|
return ATONN_CONST_DSTPORT(STRSWITCH, 0, ARITH, 0, 0) + (0x4 * (2 * au_num + port));
|
|
break;
|
|
#endif
|
|
#if defined(ATON_POOL_NUM)
|
|
case POOL:
|
|
LL_ATON_ASSERT(port == 0);
|
|
LL_ATON_ASSERT(au_num < ATON_POOL_NUM);
|
|
return ATONN_CONST_DSTPORT(STRSWITCH, 0, POOL, 0, 0) + (0x4 * au_num);
|
|
break;
|
|
#endif
|
|
default:
|
|
LL_ATON_ASSERT(0);
|
|
break;
|
|
}
|
|
break;
|
|
case STRSWITCH64:
|
|
// TODO
|
|
LL_ATON_ASSERT(0);
|
|
break;
|
|
case STRSWITCH_VC:
|
|
// TODO
|
|
LL_ATON_ASSERT(0);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Connects input and output port(s) on the streaming switch (without clearing configuration)
|
|
* @param LL_Switch_InitStruct Pointer to structure(s) describing ports to be connected
|
|
* @param n Number of entries in configuration array
|
|
* @retval Error code
|
|
*/
|
|
int LL_Switch_Init_NoReset(const LL_Switch_InitTypeDef *LL_Switch_InitStruct, int n)
|
|
{
|
|
int i;
|
|
volatile uint32_t *reg;
|
|
uint32_t t;
|
|
unsigned int en_shift[ATON_SWITCH_CONTEXT_NUM] = {ATON_STRSWITCH_DST_EN0_LSB, ATON_STRSWITCH_DST_EN1_LSB};
|
|
unsigned int link_shift[ATON_SWITCH_CONTEXT_NUM] = {ATON_STRSWITCH_DST_LINK0_LSB, ATON_STRSWITCH_DST_LINK1_LSB};
|
|
unsigned int fnr_shift[ATON_SWITCH_CONTEXT_NUM] = {ATON_STRSWITCH_DST_FNR0_LSB, ATON_STRSWITCH_DST_FNR1_LSB};
|
|
unsigned int fnr_mask[ATON_SWITCH_CONTEXT_NUM] = {ATON_STRSWITCH_DST_FNR0_MASK, ATON_STRSWITCH_DST_FNR1_MASK};
|
|
|
|
/* Enable Switch */
|
|
t = ATON_STRSWITCH_CTRL_DT;
|
|
t = ATON_STRSWITCH_CTRL_SET_EN(t, 1);
|
|
ATON_STRSWITCH_CTRL_SET(0, t);
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
/* Compute target destination configuration register */
|
|
reg = (uint32_t *)(ATON_STRSWITCH_BASE(0) + ATONN_DSTPORT_ID(LL_Switch_InitStruct[i].dest));
|
|
t = 0;
|
|
/* Enable Context and create link */
|
|
#if ATON_SWITCH_CONTEXT_NUM == 2
|
|
t |= ((LL_Switch_InitStruct[i].context0 != 0) << en_shift[0]);
|
|
t |= (ATONN_SRCPORT_ID(LL_Switch_InitStruct[i].source0) << link_shift[0]);
|
|
t |= ((LL_Switch_InitStruct[i].frames0 << fnr_shift[0]) & fnr_mask[0]);
|
|
t |= ((LL_Switch_InitStruct[i].context1 != 0) << en_shift[1]);
|
|
t |= (ATONN_SRCPORT_ID(LL_Switch_InitStruct[i].source1) << link_shift[1]);
|
|
t |= ((LL_Switch_InitStruct[i].frames1 << fnr_shift[1]) & fnr_mask[1]);
|
|
#else
|
|
int c;
|
|
for (c = 0; c < ATON_SWITCH_CONTEXT_NUM; c++)
|
|
{
|
|
t |= ((LL_Switch_InitStruct[i].context[c] != 0) << en_shift[c]);
|
|
t |= (ATONN_SRCPORT_ID(LL_Switch_InitStruct[i].source[c]) << link_shift[c]);
|
|
t |= ((LL_Switch_InitStruct[i].frames[c] << fnr_shift[c]) & fnr_mask[c]);
|
|
}
|
|
#endif
|
|
|
|
ATON_REG_WRITE(reg, t);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Connects input and output port(s) on the streaming switch (clearing configuration at the beginning)
|
|
* @param LL_Switch_InitStruct Pointer to structure(s) describing ports to be connected
|
|
* @param n Number of entries in configuration array
|
|
* @retval Error code
|
|
*/
|
|
int LL_Switch_Init(const LL_Switch_InitTypeDef *LL_Switch_InitStruct, int n)
|
|
{
|
|
uint32_t t;
|
|
|
|
#if (LL_ATON_PLATFORM == LL_ATON_PLAT_EC_TRACE)
|
|
ll_aton_static_checks();
|
|
#endif
|
|
|
|
/* Clear Configuration */
|
|
ATON_DISABLE_CLR_CONFCLR(STRSWITCH, 0);
|
|
|
|
return LL_Switch_Init_NoReset(LL_Switch_InitStruct, n);
|
|
}
|
|
|
|
/**
|
|
* @brief Fully disconnect a destination port from source ports on the streaming switch
|
|
* @param LL_Switch_InitStruct Pointer to structure(s) describing ports to be disconnected
|
|
* @param n Number of entries in configuration array
|
|
* @retval Error code
|
|
*/
|
|
int LL_Switch_Deinit(const LL_Switch_InitTypeDef *LL_Switch_InitStruct, int n)
|
|
{
|
|
int i;
|
|
volatile uint32_t *reg;
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
/* Compute target destination configuration register */
|
|
reg = (uint32_t *)(ATON_STRSWITCH_BASE(0) + ATONN_DSTPORT_ID(LL_Switch_InitStruct[i].dest));
|
|
|
|
/* Disable contexts */
|
|
ATON_REG_WRITE(reg, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Disconnects destination and source port(s) on the streaming switch
|
|
* @param LL_Switch_InitStruct Pointer to structure(s) describing ports to be disconnected
|
|
* @param n Number of entries in configuration array
|
|
* @retval Error code
|
|
*/
|
|
int LL_Switch_Deinit_Fine_Grained(const LL_Switch_InitTypeDef *LL_Switch_InitStruct, int n)
|
|
{
|
|
int i;
|
|
volatile uint32_t *reg;
|
|
unsigned int en_shift[ATON_SWITCH_CONTEXT_NUM] = {ATON_STRSWITCH_DST_EN0_LSB, ATON_STRSWITCH_DST_EN1_LSB};
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
/* Compute target destination configuration register */
|
|
reg = (uint32_t *)(ATON_STRSWITCH_BASE(0) + ATONN_DSTPORT_ID(LL_Switch_InitStruct[i].dest));
|
|
|
|
/* Disable context */
|
|
uint32_t t = *reg;
|
|
#if ATON_SWITCH_CONTEXT_NUM == 2
|
|
t &= ~((LL_Switch_InitStruct[i].context0 != 0) << en_shift[0]);
|
|
t &= ~((LL_Switch_InitStruct[i].context1 != 0) << en_shift[1]);
|
|
#else
|
|
int c;
|
|
for (c = 0; c < ATON_SWITCH_CONTEXT_NUM; c++)
|
|
t &= ~((LL_Switch_InitStruct[i].context[c] != 0) << en_shift[c]);
|
|
#endif
|
|
ATON_REG_WRITE(reg, t);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef ATON_STRSWITCH_VC_NUM
|
|
|
|
/**
|
|
* @brief Connects input and output port(s) on the streaming switch with virtual channels (without clearing
|
|
* configuration)
|
|
* @param LL_SwitchVC_InitStruct Pointer to structure(s) describing ports to be connected
|
|
* @param n Number of entries in configuration array
|
|
* @retval Error code
|
|
*/
|
|
int LL_SwitchVC_Init_NoReset(const LL_SwitchVC_InitTypeDef *LL_SwitchVC_InitStruct, int n)
|
|
{
|
|
int i;
|
|
volatile uint32_t *reg;
|
|
uint32_t t;
|
|
unsigned int en_shift = ATON_STRSWITCH_VC_DST_EN_LSB;
|
|
unsigned int src_shift = ATON_STRSWITCH_VC_DST_SRC_LSB;
|
|
|
|
/* Enable Switch */
|
|
t = ATON_STRSWITCH_VC_CTRL_DT;
|
|
t = ATON_STRSWITCH_VC_CTRL_SET_EN(t, 1);
|
|
ATON_STRSWITCH_VC_CTRL_SET(0, t);
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
/* Compute target destination configuration register */
|
|
reg = (uint32_t *)(ATON_STRSWITCH_VC_BASE(0) + ATONN_DSTPORT_ID(LL_SwitchVC_InitStruct[i].dest));
|
|
t = 0;
|
|
/* Enable Context and create link */
|
|
t |= (1 << en_shift);
|
|
t |= (ATONN_SRCPORT_ID(LL_SwitchVC_InitStruct[i].source) << src_shift);
|
|
ATON_REG_WRITE(reg, t);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Connects input and output port(s) on the streaming switch with virtual channels (clearing configuration at
|
|
* the beginning)
|
|
* @param LL_SwitchVC_InitStruct Pointer to structure(s) describing ports to be connected
|
|
* @param n Number of entries in configuration array
|
|
* @retval Error code
|
|
*/
|
|
int LL_SwitchVC_Init(const LL_SwitchVC_InitTypeDef *LL_SwitchVC_InitStruct, int n)
|
|
{
|
|
uint32_t t;
|
|
|
|
/* Clear Configuration */
|
|
ATON_DISABLE_CLR_CONFCLR(STRSWITCH_VC, 0);
|
|
|
|
return LL_SwitchVC_Init_NoReset(LL_SwitchVC_InitStruct, n);
|
|
}
|
|
|
|
/**
|
|
* @brief Fully disconnect a destination port from source ports on the streaming switch with virtual channels
|
|
* @param LL_SwitchVC_InitStruct Pointer to structure(s) describing ports to be disconnected
|
|
* @param n Number of entries in configuration array
|
|
* @retval Error code
|
|
*/
|
|
int LL_SwitchVC_Deinit(const LL_SwitchVC_InitTypeDef *LL_SwitchVC_InitStruct, int n)
|
|
{
|
|
int i;
|
|
volatile uint32_t *reg;
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
/* Compute target destination configuration register */
|
|
reg = (uint32_t *)(ATON_STRSWITCH_VC_BASE(0) + ATONN_DSTPORT_ID(LL_SwitchVC_InitStruct[i].dest));
|
|
|
|
/* Disable contexts */
|
|
ATON_REG_WRITE(reg, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Disconnects destination and source port(s) on the streaming switch with virtual channels
|
|
* @param LL_SwitchVC_InitStruct Pointer to structure(s) describing ports to be disconnected
|
|
* @param n Number of entries in configuration array
|
|
* @retval Error code
|
|
*/
|
|
int LL_SwitchVC_Deinit_Fine_Grained(const LL_SwitchVC_InitTypeDef *LL_SwitchVC_InitStruct, int n)
|
|
{
|
|
int i;
|
|
volatile uint32_t *reg;
|
|
unsigned int en_shift = ATON_STRSWITCH_VC_DST_EN_LSB;
|
|
|
|
for (i = 0; i < n; i++)
|
|
{
|
|
/* Compute target destination configuration register */
|
|
reg = (uint32_t *)(ATON_STRSWITCH_VC_BASE(0) + ATONN_DSTPORT_ID(LL_SwitchVC_InitStruct[i].dest));
|
|
|
|
/* Disable context */
|
|
uint32_t t = *reg;
|
|
t &= ~(1 << en_shift);
|
|
ATON_REG_WRITE(reg, t);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif // ATON_STRSWITCH_VC_NUM
|
|
|
|
#ifdef ATON_DECUN_NUM
|
|
|
|
static inline uint32_t decun_inc_page_addr(int id, uint32_t ctrl_val)
|
|
{
|
|
uint32_t page_addr = ATON_DECUN_CTRL_GET_PAGEADDR(ctrl_val);
|
|
page_addr++;
|
|
ctrl_val = ATON_DECUN_CTRL_SET_PAGEADDR(ctrl_val, page_addr);
|
|
ATON_DECUN_CTRL_SET(id, ctrl_val);
|
|
return ctrl_val;
|
|
}
|
|
|
|
static void LL_Decun_CB_1byte(int id, const LL_Decun_InitTypeDef *conf, uint32_t ctrl_val)
|
|
{
|
|
unsigned CBsize = conf->CBs_size;
|
|
unsigned i, k;
|
|
unsigned mem_idx_num = ATON_DECUN_MEM_LOW_IDX_MAX - ATON_DECUN_MEM_LOW_IDX_MIN + 1;
|
|
|
|
if (conf->nCWperCV == 1)
|
|
{
|
|
uint8_t *CBp = (uint8_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i++)
|
|
{
|
|
uint32_t temp = CBp[i];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 2)
|
|
{
|
|
#if 0
|
|
uint8_t *CBp = (uint8_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 2)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 8);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num )
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
#else
|
|
uint16_t *CBp = (uint16_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize / 2; i++)
|
|
{
|
|
uint32_t temp = CBp[i];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (conf->nCWperCV == 3)
|
|
{
|
|
uint8_t *CBp = (uint8_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 3)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 8) | (CBp[i + 2] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 4 || conf->nCWperCV == 8)
|
|
{
|
|
uint32_t *CBp = (uint32_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize / 4; i++)
|
|
{
|
|
uint32_t temp = CBp[i];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 5)
|
|
{
|
|
uint8_t *CBp = (uint8_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 5)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 8) | (CBp[i + 2] << 16) | (CBp[i + 3] << 24);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
temp = CBp[i + 4];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 6)
|
|
{
|
|
#if 0
|
|
uint8_t *CBp = (uint8_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 6)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 8) | (CBp[i + 2] << 16) | (CBp[i + 3] << 24);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
temp = CBp[i + 4] | (CBp[i + 5] << 8);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num )
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
#else
|
|
uint16_t *CBp = (uint16_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize / 2; i += 3)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
temp = CBp[i + 2];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (conf->nCWperCV == 7)
|
|
{
|
|
uint8_t *CBp = (uint8_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 7)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 8) | (CBp[i + 2] << 16) | (CBp[i + 3] << 24);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
temp = CBp[i + 4] | (CBp[i + 5] << 8) | (CBp[i + 6] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void LL_Decun_CB_2byte(int id, const LL_Decun_InitTypeDef *conf, uint32_t ctrl_val)
|
|
{
|
|
unsigned CBsize = conf->CBs_size / 2;
|
|
unsigned i, k;
|
|
unsigned mem_idx_num = ATON_DECUN_MEM_LOW_IDX_MAX - ATON_DECUN_MEM_LOW_IDX_MIN + 1;
|
|
|
|
if (conf->nCWperCV == 1)
|
|
{
|
|
uint16_t *CBp = (uint16_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i++)
|
|
{
|
|
uint32_t temp = CBp[i];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 2)
|
|
{
|
|
#if 0
|
|
uint16_t *CBp = (uint16_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 2)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num )
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
#else
|
|
uint32_t *CBp = (uint32_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize / 2; i++)
|
|
{
|
|
uint32_t temp = CBp[i];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (conf->nCWperCV == 3)
|
|
{
|
|
uint16_t *CBp = (uint16_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 3)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
temp = CBp[i + 2];
|
|
ATON_DECUN_MEM_HIGH_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 4)
|
|
{
|
|
uint32_t *CBp = (uint32_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize / 2; i += 2)
|
|
{
|
|
uint32_t temp = CBp[i];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
temp = CBp[i + 1];
|
|
ATON_DECUN_MEM_HIGH_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 5)
|
|
{
|
|
uint16_t *CBp = (uint16_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 5)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
temp = CBp[i + 2] | (CBp[i + 3] << 16);
|
|
ATON_DECUN_MEM_HIGH_SET(id, k, temp);
|
|
k++;
|
|
temp = CBp[i + 4];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 6)
|
|
{
|
|
#if 0
|
|
uint16_t *CBp = (uint16_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 6)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
temp = CBp[i + 2] | (CBp[i + 3] << 16);
|
|
ATON_DECUN_MEM_HIGH_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num )
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
temp = CBp[i + 4] | (CBp[i + 5] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num )
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
#else
|
|
uint32_t *CBp = (uint32_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize / 2; i += 3)
|
|
{
|
|
uint32_t temp = CBp[i];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
temp = CBp[i + 1];
|
|
ATON_DECUN_MEM_HIGH_SET(id, k, temp);
|
|
k++;
|
|
temp = CBp[i + 2];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (conf->nCWperCV == 7)
|
|
{
|
|
uint16_t *CBp = (uint16_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize; i += 7)
|
|
{
|
|
uint32_t temp = CBp[i] | (CBp[i + 1] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
temp = CBp[i + 2] | (CBp[i + 3] << 16);
|
|
ATON_DECUN_MEM_HIGH_SET(id, k, temp);
|
|
k++;
|
|
temp = CBp[i + 4] | (CBp[i + 5] << 16);
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
temp = CBp[i + 6];
|
|
ATON_DECUN_MEM_HIGH_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
if (conf->nCWperCV == 8)
|
|
{
|
|
uint32_t *CBp = (uint32_t *)conf->CBs_vector.p;
|
|
for (i = 0, k = 0; i < CBsize / 2; i += 2)
|
|
{
|
|
uint32_t temp = CBp[i];
|
|
ATON_DECUN_MEM_LOW_SET(id, k, temp);
|
|
temp = CBp[i + 1];
|
|
ATON_DECUN_MEM_HIGH_SET(id, k, temp);
|
|
k++;
|
|
if (k == mem_idx_num)
|
|
{
|
|
ctrl_val = decun_inc_page_addr(id, ctrl_val);
|
|
k = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Configures Decompression Unit accelerator
|
|
* @param id Decompression Unit identifier (Always 0 fo Tiny Orlando)
|
|
* @param conf Pointer to structure describing decompression unit configuration
|
|
* @retval Error code
|
|
*/
|
|
int LL_Decun_Init(int id, const LL_Decun_InitTypeDef *conf)
|
|
{
|
|
uint32_t t;
|
|
|
|
if (id >= ATON_DECUN_NUM)
|
|
return LL_ATON_INVALID_ID;
|
|
|
|
LL_ATON_EnableClock(ATON_DECUN_CLKB_CLK(id));
|
|
|
|
t = ATON_DECUN_CTRL_DT;
|
|
t = ATON_DECUN_CTRL_SET_DUALIN(t, (conf->noDualInput != 0));
|
|
t = ATON_DECUN_CTRL_SET_OW(t, (conf->noOverWrite != 0));
|
|
ATON_DECUN_CTRL_SET(id, t);
|
|
|
|
if (conf->CBs_size != 0)
|
|
{
|
|
if (conf->nFormatBytes == 1)
|
|
{
|
|
LL_Decun_CB_1byte(id, conf, t);
|
|
}
|
|
else
|
|
{
|
|
// LL_ATON_ASSERT(conf->nFormatBytes == 2);
|
|
LL_Decun_CB_2byte(id, conf, t);
|
|
}
|
|
}
|
|
|
|
t = ATON_DECUN_BFORMAT_DT;
|
|
t = ATON_DECUN_BFORMAT_SET_CVS(t, conf->nCVperCB - 1);
|
|
t = ATON_DECUN_BFORMAT_SET_CWS(t, conf->nCWperCV - 1);
|
|
t = ATON_DECUN_BFORMAT_SET_OSAM(t, conf->nRCWlastCV);
|
|
ATON_DECUN_BFORMAT_SET(id, t);
|
|
|
|
LL_ATON_ASSERT((conf->nFormatBytes == 1) || (conf->nFormatBytes == 2));
|
|
|
|
t = ATON_DECUN_DFORMAT_DT;
|
|
t = ATON_DECUN_DFORMAT_SET_CV8(t, conf->nFormatBytes & 0x1);
|
|
ATON_DECUN_DFORMAT_SET(id, t);
|
|
|
|
t = ATON_DECUN_FFORMAT_DT;
|
|
t = ATON_DECUN_FFORMAT_SET_BN(t, conf->nBatches);
|
|
ATON_DECUN_FFORMAT_SET(id, t);
|
|
|
|
return LL_ATON_OK;
|
|
}
|
|
#endif // ATON_DECUN_NUM
|
|
|
|
#ifdef ATON_CONVACC_NUM
|
|
/**
|
|
* @brief Configures Convolution Accelerator
|
|
* @param id Convolutional Accelerator identifier [0, ATON_CONVACC_NUM-1]
|
|
* @param Convacc_InitStruct Structure describing initialization parameters
|
|
* @retval Error code E.g.: Invalid ID, invalid parameters, not idle,..
|
|
*/
|
|
int LL_Convacc_Init(int id, const LL_Convacc_InitTypeDef *conf)
|
|
{
|
|
uint32_t t;
|
|
|
|
if (id >= ATON_CONVACC_NUM)
|
|
return LL_ATON_INVALID_ID;
|
|
|
|
LL_ATON_EnableClock(ATON_CONVACC_CLKB_CLK(id));
|
|
|
|
t = ATON_CONVACC_CTRL_DT;
|
|
t = ATON_CONVACC_CTRL_SET_NOSUM(t, (conf->accumulate == 0));
|
|
t = ATON_CONVACC_CTRL_SET_NO1SUM(t, (conf->accumulate_first == 0));
|
|
t = ATON_CONVACC_CTRL_SET_GEN1SUM(t, (conf->accumulate_gen_first != 0));
|
|
t = ATON_CONVACC_CTRL_SET_AFILTMODE(t, conf->afilt_mode);
|
|
t = ATON_CONVACC_CTRL_SET_SIMD(t, (conf->simd));
|
|
t = ATON_CONVACC_CTRL_SET_KT1(t, (conf->kt1_mode != 0));
|
|
t = ATON_CONVACC_CTRL_SET_KSETEN(t, conf->kseten);
|
|
t = ATON_CONVACC_CTRL_SET_FUNSIGNED(t, conf->f_unsigned);
|
|
t = ATON_CONVACC_CTRL_SET_KUNSIGNED(t, conf->k_unsigned);
|
|
#if defined(ATON_CONVACC_CTRL_SET_FSTAT)
|
|
t = ATON_CONVACC_CTRL_SET_FSTAT(t, (conf->fstat != 0));
|
|
#endif
|
|
|
|
#if defined(ATON_CONVACC_CTRL_GET_DEEPMODE)
|
|
t = ATON_CONVACC_CTRL_SET_DEEPMODE(t, (conf->deepmode != 0));
|
|
#if defined(ATON_CONVACC_CTRL_SET_FSTAT)
|
|
// deepmode and feature stats are incompatible
|
|
if ((conf->fstat != 0) && (conf->deepmode != 0))
|
|
{
|
|
return LL_ATON_INVALID_PARAM;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(ATON_CONVACC_CTRL_GET_DSS2MODE)
|
|
t = ATON_CONVACC_CTRL_SET_DSS2MODE(t, (conf->dss2mode != 0));
|
|
#if defined(ATON_CONVACC_CTRL_SET_FSTAT)
|
|
// deepmode and feature stats are incompatible
|
|
if ((conf->fstat != 0) && (conf->dss2mode != 0))
|
|
{
|
|
return LL_ATON_INVALID_PARAM;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(ATON_CONVACC_CTRL_SET_DSS2MODE) && defined(ATON_CONVACC_CTRL_SET_DEEPMODE)
|
|
// deepmode and dss2mode stats are incompatible
|
|
if ((conf->dss2mode != 0) && (conf->deepmode != 0))
|
|
{
|
|
return LL_ATON_INVALID_PARAM;
|
|
}
|
|
#endif
|
|
|
|
ATON_CONVACC_CTRL_SET(id, t);
|
|
Conv_ctrl_bits[id] = t;
|
|
|
|
if (conf->afilt_mode != AFILT_MODE_NONE)
|
|
{
|
|
t = ATON_CONVACC_AFILT_DT;
|
|
t = ATON_CONVACC_AFILT_SET_TOT(t, conf->afilt_tot);
|
|
t = ATON_CONVACC_AFILT_SET_FIRST(t, conf->afilt_first);
|
|
t = ATON_CONVACC_AFILT_SET_LAST(t, conf->afilt_last);
|
|
ATON_CONVACC_AFILT_SET(id, t);
|
|
}
|
|
|
|
if (conf->kfilt_tot > 0)
|
|
{
|
|
t = ATON_CONVACC_KFILT_DT;
|
|
t = ATON_CONVACC_KFILT_SET_TOT(t, conf->kfilt_tot);
|
|
t = ATON_CONVACC_KFILT_SET_FIRST(t, conf->kfilt_first);
|
|
t = ATON_CONVACC_KFILT_SET_LAST(t, conf->kfilt_last);
|
|
ATON_CONVACC_KFILT_SET(id, t);
|
|
}
|
|
|
|
t = ATON_CONVACC_DFORMAT_DT;
|
|
t = ATON_CONVACC_DFORMAT_SET_FROUND(t, conf->rounding_f);
|
|
t = ATON_CONVACC_DFORMAT_SET_FSAT(t, conf->saturation_f);
|
|
t = ATON_CONVACC_DFORMAT_SET_FRNDMODE(t, conf->round_mode_f);
|
|
t = ATON_CONVACC_DFORMAT_SET_FBYTES(t, conf->inbytes_f);
|
|
t = ATON_CONVACC_DFORMAT_SET_FSHIFT(t, ATON_SHIFT(conf->shift_f));
|
|
|
|
t = ATON_CONVACC_DFORMAT_SET_ROUND(t, conf->rounding_o);
|
|
t = ATON_CONVACC_DFORMAT_SET_SAT(t, conf->saturation_o);
|
|
t = ATON_CONVACC_DFORMAT_SET_ORNDMODE(t, (conf->relu_mode_o << 1) | conf->round_mode_o);
|
|
t = ATON_CONVACC_DFORMAT_SET_OBYTES(t, conf->outbytes_o);
|
|
t = ATON_CONVACC_DFORMAT_SET_OUTSHIFT(t, conf->shift_o); // shift right only
|
|
t = ATON_CONVACC_DFORMAT_SET_RAW(t, conf->raw_o);
|
|
|
|
t = ATON_CONVACC_DFORMAT_SET_INSHIFT(t, conf->shift_a); // accumulator shift left really (macro name is misleading)
|
|
ATON_CONVACC_DFORMAT_SET(id, t);
|
|
|
|
t = ATON_CONVACC_FFORMAT_DT;
|
|
t = ATON_CONVACC_FFORMAT_SET_WIDTH(t, conf->fWidth * conf->batchDepth);
|
|
t = ATON_CONVACC_FFORMAT_SET_HEIGHT(t, conf->fHeight);
|
|
ATON_CONVACC_FFORMAT_SET(id, t);
|
|
|
|
t = ATON_CONVACC_KFORMAT_DT;
|
|
t = ATON_CONVACC_KFORMAT_SET_WIDTH(t, conf->kernelWidth);
|
|
t = ATON_CONVACC_KFORMAT_SET_HEIGHT(t, conf->kernelHeight);
|
|
t = ATON_CONVACC_KFORMAT_SET_BTCDEPTH(t, conf->batchDepth);
|
|
t = ATON_CONVACC_KFORMAT_SET_NR(t, conf->nKernels);
|
|
ATON_CONVACC_KFORMAT_SET(id, t);
|
|
|
|
// LL_ATON_PRINTF("depth=%d k_w=%d k_h=%d\n",conf->batchDepth,conf->kernelWidth,conf->kernelHeight);
|
|
// LL_ATON_PRINTF("pad_t=%d pad_b=%d pad_l=%d
|
|
// pad_r=%d\n",conf->top_padding,conf->bot_padding,conf->left_padding,conf->right_padding);
|
|
|
|
int p_top = (conf->top_padding < conf->kernelHeight ? conf->top_padding : conf->kernelHeight - 1);
|
|
int p_bot = (conf->bot_padding < conf->kernelHeight ? conf->bot_padding : conf->kernelHeight - 1);
|
|
int p_left = (conf->left_padding < conf->kernelWidth ? conf->left_padding : conf->kernelWidth - 1);
|
|
int p_right = (conf->right_padding < conf->kernelWidth ? conf->right_padding : conf->kernelWidth - 1);
|
|
|
|
p_top = (p_top <= 2 ? p_top : 2);
|
|
p_bot = (p_bot <= 2 ? p_bot : 2);
|
|
p_left = (p_left <= 2 ? p_left : 2);
|
|
p_right = (p_right <= 2 ? p_right : 2);
|
|
// LL_ATON_PRINTF("p_t=%d p_b=%d p_l=%d p_r=%d\n",p_top,p_bot,p_left,p_right);
|
|
|
|
#if defined(ATON_CONVACC_CTRL_GET_DEEPMODE)
|
|
// no pad mode available in 1x1 deepmode
|
|
// will accomodate padding only with zframe below
|
|
if (conf->deepmode != 0)
|
|
p_top = p_bot = p_left = p_right = 0;
|
|
#endif
|
|
#if defined(ATON_CONVACC_CTRL_GET_DSS2MODE)
|
|
// no pad mode available in dss2mode
|
|
// will accomodate padding only with zframe below
|
|
if (conf->dss2mode != 0)
|
|
p_top = p_bot = p_left = p_right = 0;
|
|
#endif
|
|
#if defined(ATON_CONVACC_ZFBIAS_SET)
|
|
// no pad mode available if zfbias is set
|
|
// will accomodate padding only with zframe below
|
|
if (conf->zfbias != 0)
|
|
p_top = p_bot = p_left = p_right = 0;
|
|
#endif
|
|
|
|
int z_top = (conf->top_padding - p_top);
|
|
int z_bot = (conf->bot_padding - p_bot);
|
|
int z_left = (conf->left_padding - p_left);
|
|
int z_right = (conf->right_padding - p_right);
|
|
// LL_ATON_PRINTF("z_t=%d z_b=%d z_l=%d z_r=%d\n",z_top,z_bot,z_left*conf->batchDepth,z_right*conf->batchDepth);
|
|
|
|
t = ATON_CONVACC_ZFRAME_DT;
|
|
t = ATON_CONVACC_ZFRAME_SET_TOP(t, z_top);
|
|
t = ATON_CONVACC_ZFRAME_SET_BOTTOM(t, z_bot);
|
|
t = ATON_CONVACC_ZFRAME_SET_LEFT(t, z_left * conf->batchDepth);
|
|
t = ATON_CONVACC_ZFRAME_SET_RIGHT(t, z_right * conf->batchDepth);
|
|
ATON_CONVACC_ZFRAME_SET(id, t);
|
|
|
|
t = ATON_CONVACC_SAMPLE_DT;
|
|
t = ATON_CONVACC_SAMPLE_SET_TPAD(t, p_top);
|
|
t = ATON_CONVACC_SAMPLE_SET_BPAD(t, p_bot);
|
|
t = ATON_CONVACC_SAMPLE_SET_LPAD(t, p_left);
|
|
t = ATON_CONVACC_SAMPLE_SET_RPAD(t, p_right);
|
|
t = ATON_CONVACC_SAMPLE_SET_HSTRD(t, conf->hstride);
|
|
t = ATON_CONVACC_SAMPLE_SET_VSTRD(t, conf->vstride);
|
|
#if defined(ATON_CONVACC_SAMPLE_SET_FSTATCNT)
|
|
if (conf->fstat != 0)
|
|
t = ATON_CONVACC_SAMPLE_SET_FSTATCNT(t, conf->fstatcnt);
|
|
#endif
|
|
ATON_CONVACC_SAMPLE_SET(id, t);
|
|
|
|
// LL_ATON_PRINTF("crop_t=%d crop_b=%d crop_l=%d crop_r=%d\n",z_top,z_bot,z_left,z_right);
|
|
t = ATON_CONVACC_FHCROP_DT;
|
|
if (conf->left_crop > 0)
|
|
t = ATON_CONVACC_FHCROP_SET_LEFT(t, conf->left_crop * conf->batchDepth);
|
|
if (conf->right_crop > 0)
|
|
t = ATON_CONVACC_FHCROP_SET_RIGHT(t, conf->right_crop * conf->batchDepth + (conf->batchDepth - 1));
|
|
ATON_CONVACC_FHCROP_SET(id, t);
|
|
|
|
t = ATON_CONVACC_FVCROP_DT;
|
|
if (conf->top_crop > 0)
|
|
t = ATON_CONVACC_FVCROP_SET_TOP(t, conf->top_crop);
|
|
if (conf->bot_crop > 0)
|
|
t = ATON_CONVACC_FVCROP_SET_BOTTOM(t, conf->bot_crop);
|
|
ATON_CONVACC_FVCROP_SET(id, t);
|
|
// LL_ATON_PRINTF("c_t=%d c_b=%d c_l=%d c_r=%d\n",conf->top_crop,conf->bot_crop,conf->left_crop *
|
|
// conf->batchDepth,conf->right_crop * conf->batchDepth + (conf->batchDepth - 1));
|
|
|
|
#if defined(ATON_CONVACC_FSUB_SET)
|
|
if (conf->fsub != 0)
|
|
{
|
|
t = ATON_CONVACC_FSUB_DT;
|
|
t = ATON_CONVACC_FSUB_SET_FSUB(t, conf->fsub);
|
|
ATON_CONVACC_FSUB_SET(id, t);
|
|
}
|
|
#endif
|
|
#if defined(ATON_CONVACC_ZFBIAS_SET)
|
|
t = ATON_CONVACC_ZFBIAS_DT;
|
|
if (conf->zfbias != 0)
|
|
{
|
|
t = ATON_CONVACC_ZFBIAS_SET_ZFBIAS(t, conf->zfbias);
|
|
}
|
|
|
|
/* If hardware supports it (e.g.: 4CA2P), manage Batch Depths not fitting 8 bits */
|
|
#if defined(ATON_CONVACC_ZFBIAS_SET_ZFLEFTMSB)
|
|
t = ATON_CONVACC_ZFBIAS_SET_ZFLEFTMSB(t, (z_left * conf->batchDepth) >> ATON_CONVACC_ZFRAME_LEFT_W);
|
|
t = ATON_CONVACC_ZFBIAS_SET_ZFRIGHTMSB(t, (z_right * conf->batchDepth) >> ATON_CONVACC_ZFRAME_RIGHT_W);
|
|
#endif
|
|
|
|
ATON_CONVACC_ZFBIAS_SET(id, t);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#endif // ATON_CONVACC_NUM
|
|
|
|
#ifdef ATON_ACTIV_NUM
|
|
|
|
static int32_t get_Activacc_type(LL_Activacc_Op op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case ACTIV_RELU:
|
|
return ATON_ACTIVTYPE_RELU;
|
|
case ACTIV_PRELU:
|
|
return ATON_ACTIVTYPE_PRELU;
|
|
case ACTIV_TRELU:
|
|
return ATON_ACTIVTYPE_TRELU;
|
|
case ACTIV_FUNC:
|
|
return ATON_ACTIVTYPE_FUNCTION;
|
|
#if defined ATON_ACTIVTYPE_LUT
|
|
case ACTIV_LUT:
|
|
return ATON_ACTIVTYPE_LUT;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
LL_ATON_ASSERT(0);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Configures Activation Accelerator
|
|
* @param id Activation Accelerator identifier [0..ATON_ACTIV_NUM-1]
|
|
* @param Activacc_InitStruct Structure describing initialization parameters
|
|
* @retval Error code E.g.: Invalid ID, invalid parameters, not idle,..
|
|
*/
|
|
int LL_Activacc_Init(int id, const LL_Activacc_InitTypeDef *conf)
|
|
{
|
|
uint32_t t;
|
|
|
|
if (id >= ATON_ACTIV_NUM)
|
|
return LL_ATON_INVALID_ID;
|
|
|
|
LL_ATON_EnableClock(ATON_ACTIV_CLKB_CLK(id));
|
|
|
|
t = ATON_ACTIV_CTRL_DT;
|
|
t = ATON_ACTIV_CTRL_SET_TYPE(t, get_Activacc_type(conf->operation));
|
|
t = ATON_ACTIV_CTRL_SET_FBYTES(t, conf->inbytes_f);
|
|
t = ATON_ACTIV_CTRL_SET_FSHIFT(t, ATON_SHIFT(conf->shift_f));
|
|
t = ATON_ACTIV_CTRL_SET_FROUND(t, conf->rounding_f);
|
|
t = ATON_ACTIV_CTRL_SET_FSAT(t, (conf->saturation_f != 0));
|
|
t = ATON_ACTIV_CTRL_SET_FRNDMODE(t, conf->round_mode_f);
|
|
t = ATON_ACTIV_CTRL_SET_FOBYTES(t, conf->outbytes_f);
|
|
|
|
t = ATON_ACTIV_CTRL_SET_ROUND(t, (conf->rounding_o != 0));
|
|
t = ATON_ACTIV_CTRL_SET_SAT(t, (conf->saturation_o != 0));
|
|
t = ATON_ACTIV_CTRL_SET_OBYTES(t, conf->outbytes_o);
|
|
t = ATON_ACTIV_CTRL_SET_ORNDMODE(t, (conf->relu_mode_o << 1) | conf->round_mode_o);
|
|
ATON_ACTIV_CTRL_SET(id, t);
|
|
|
|
#if defined(ATON_ACTIV_FSUB_SET)
|
|
if (conf->fsub != 0)
|
|
{
|
|
t = ATON_ACTIV_FSUB_DT;
|
|
t = ATON_ACTIV_FSUB_SET_FSUB(t, conf->fsub);
|
|
ATON_ACTIV_FSUB_SET(id, t);
|
|
}
|
|
#endif
|
|
|
|
switch (conf->operation)
|
|
{
|
|
case ACTIV_RELU:
|
|
case ACTIV_PRELU:
|
|
case ACTIV_TRELU:
|
|
t = ATON_ACTIV_ACTIVPARAM_DT;
|
|
t = ATON_ACTIV_ACTIVPARAM_SET_PARAM(t, conf->parameter);
|
|
ATON_ACTIV_ACTIVPARAM_SET(id, t);
|
|
|
|
t = ATON_ACTIV_ACTIVPARAM2_DT;
|
|
t = ATON_ACTIV_ACTIVPARAM2_SET_PARAM2(t, conf->parameter_2);
|
|
ATON_ACTIV_ACTIVPARAM2_SET(id, t);
|
|
|
|
t = ATON_ACTIV_FUNC_DT;
|
|
t = ATON_ACTIV_FUNC_SET_SIGNEDOP(t, (conf->signedop != 0));
|
|
t = ATON_ACTIV_FUNC_SET_OUTSHIFT(t, conf->shift_o);
|
|
ATON_ACTIV_FUNC_SET(id, t);
|
|
break;
|
|
case ACTIV_FUNC:
|
|
{
|
|
t = ATON_ACTIV_FUNC_DT;
|
|
t = ATON_ACTIV_FUNC_SET_SIGNEDOP(t, (conf->signedop != 0));
|
|
t = ATON_ACTIV_FUNC_SET_OUTSHIFT(t, conf->shift_o);
|
|
t = ATON_ACTIV_FUNC_SET_BSHIFT(t, conf->shift_b);
|
|
t = ATON_ACTIV_FUNC_SET_CSHIFT(t, conf->shift_c);
|
|
t = ATON_ACTIV_FUNC_SET_BWIDTH(t, conf->bwidth);
|
|
ATON_ACTIV_FUNC_SET(id, t);
|
|
|
|
t = ATON_ACTIV_ACTIVPARAM_DT;
|
|
t = ATON_ACTIV_ACTIVPARAM_SET_PARAM(t, conf->parameter);
|
|
t = ATON_ACTIV_ACTIVPARAM_SET_FUNC(t, conf->shift_norm);
|
|
ATON_ACTIV_ACTIVPARAM_SET(id, t);
|
|
|
|
{
|
|
uint8_t *R0p = (uint8_t *)conf->ROM0_vector.p;
|
|
unsigned ROM0_rows = conf->ROM0_nbytes / (1 * 1);
|
|
for (int i = 0; i < ROM0_rows; i++)
|
|
{
|
|
t = ATON_ACTIV_ROM0_DT;
|
|
t = ATON_ACTIV_ROM0_SET_ENTRY(t, R0p[i]);
|
|
ATON_ACTIV_ROM0_SET(id, i, t);
|
|
}
|
|
}
|
|
{
|
|
uint16_t *R1p = (uint16_t *)conf->ROM1_vector.p;
|
|
unsigned ROM1_rows = conf->ROM1_nbytes / (3 * 2);
|
|
for (int i = 0; i < ROM1_rows; i++)
|
|
{
|
|
t = ATON_ACTIV_ROM1_AB_DT;
|
|
t = ATON_ACTIV_ROM1_AB_SET_A(t, R1p[3 * i + 0]);
|
|
t = ATON_ACTIV_ROM1_AB_SET_B(t, R1p[3 * i + 1]);
|
|
ATON_ACTIV_ROM1_AB_SET(id, i, t);
|
|
t = ATON_ACTIV_ROM1_C_DT;
|
|
t = ATON_ACTIV_ROM1_C_SET_C(t, R1p[3 * i + 2]);
|
|
ATON_ACTIV_ROM1_C_SET(id, i, t);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ACTIV_LUT:
|
|
#if defined ATON_ACTIVTYPE_LUT
|
|
{
|
|
uint8_t *Lutp = (uint8_t *)conf->LUT_vector.p;
|
|
for (int i = 0; i < 64; i++)
|
|
{
|
|
uint32_t val = ATON_ACTIV_LUT_DT;
|
|
val = ATON_ACTIV_LUT_SET_MOD8_1(val, Lutp[4 * i]);
|
|
val = ATON_ACTIV_LUT_SET_MOD8_2(val, Lutp[4 * i + 1]);
|
|
val = ATON_ACTIV_LUT_SET_MOD8_3(val, Lutp[4 * i + 2]);
|
|
val = ATON_ACTIV_LUT_SET_MOD8_4(val, Lutp[4 * i + 3]);
|
|
ATON_ACTIV_LUT_SET(id, i, val);
|
|
}
|
|
}
|
|
#else
|
|
assert("Unsupported Activation LUT configuration");
|
|
#endif
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif // ATON_ACTIV_NUM
|
|
|
|
#ifdef ATON_ARITH_NUM
|
|
|
|
static int32_t get_Arithacc_type(LL_Arithacc_Op op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case ARITH_AFFINE:
|
|
return ATON_ARITHOP_AX_BY_C;
|
|
case ARITH_MIN:
|
|
return ATON_ARITHOP_MIN_X_Y;
|
|
case ARITH_MAX:
|
|
return ATON_ARITHOP_MAX_X_Y;
|
|
case ARITH_MUL:
|
|
return ATON_ARITHOP_XY;
|
|
case ARITH_X_AND_Y:
|
|
return ATON_ARITHOP_X_AND_Y;
|
|
case ARITH_X_OR_Y:
|
|
return ATON_ARITHOP_X_OR_Y;
|
|
case ARITH_NOT_X:
|
|
return ATON_ARITHOP_NOT_X;
|
|
case ARITH_X_XOR_Y:
|
|
return ATON_ARITHOP_X_XOR_Y;
|
|
case ARITH_X_EQ_Y:
|
|
return ATON_ARITHOP_X_EQ_Y;
|
|
case ARITH_X_LT_Y:
|
|
return ATON_ARITHOP_X_LT_Y;
|
|
case ARITH_X_LE_Y:
|
|
return ATON_ARITHOP_X_LE_Y;
|
|
case ARITH_X_GT_Y:
|
|
return ATON_ARITHOP_X_GT_Y;
|
|
case ARITH_X_GE_Y:
|
|
return ATON_ARITHOP_X_GE_Y;
|
|
case ARITH_ABS_X:
|
|
return ATON_ARITHOP_ABS_X;
|
|
case ARITH_SIGN_X:
|
|
return ATON_ARITHOP_SIGN_X;
|
|
case ARITH_CLIP:
|
|
return ATON_ARITHOP_CLIP;
|
|
default:
|
|
break;
|
|
}
|
|
LL_ATON_ASSERT(0);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Configures Arithmetic Accelerator
|
|
* @param id Arithmetic Accelerator identifier [0..ATON_ARITH_NUM-1]
|
|
* @param Arithacc_InitStruct Structure describing initialization parameters
|
|
* @retval Error code E.g.: Invalid ID, invalid parameters, not idle,..
|
|
*/
|
|
int LL_Arithacc_Init(int id, const LL_Arithacc_InitTypeDef *conf)
|
|
{
|
|
uint32_t t;
|
|
char sshift;
|
|
|
|
if (id >= ATON_ARITH_NUM)
|
|
return LL_ATON_INVALID_ID;
|
|
|
|
/* Deal with Arith Acc V3 shifts extensions */
|
|
if (ATON_ARITH_VERSION_MAJOR_DT >= 3)
|
|
sshift = 16;
|
|
else
|
|
sshift = 0;
|
|
|
|
LL_ATON_EnableClock(ATON_ARITH_CLKB_CLK(id));
|
|
|
|
t = ATON_ARITH_CTRL_DT;
|
|
ATON_ARITH_CTRL_SET(id, t);
|
|
|
|
t = ATON_ARITH_CTRL_DT;
|
|
t = ATON_ARITH_CTRL_SET_CNT1(t, (conf->scalar == 0)); // these must be handled yet FIXME !!!
|
|
t = ATON_ARITH_CTRL_SET_CNT2(t, (conf->scalar == 0) && (conf->bcast == ARITH_BCAST_CHAN));
|
|
t = ATON_ARITH_CTRL_SET_CNT3(t, (conf->scalar == 0) && (conf->bcast == ARITH_BCAST_CHAN));
|
|
t = ATON_ARITH_CTRL_SET_ROUND(t, (conf->rounding_o != 0));
|
|
t = ATON_ARITH_CTRL_SET_ORNDMODE(t, (conf->relu_mode_o << 1) | conf->round_mode_o);
|
|
// t = ATON_ARITH_CTRL_SET_OBYTES(t,((conf->dataw_o + 7) >> 3));
|
|
t = ATON_ARITH_CTRL_SET_OBYTES(t, conf->outbytes_o);
|
|
t = ATON_ARITH_CTRL_SET_SAT(t, (conf->saturation_o != 0));
|
|
t = ATON_ARITH_CTRL_SET_COEFFA(t, (conf->scalar == 0));
|
|
t = ATON_ARITH_CTRL_SET_COEFFB(t, (conf->scalar == 0));
|
|
t = ATON_ARITH_CTRL_SET_COEFFC(t, (conf->scalar == 0));
|
|
t = ATON_ARITH_CTRL_SET_DUALIN(t, (conf->dualinput != 0));
|
|
t = ATON_ARITH_CTRL_SET_COMBINEBC(t, (conf->combinebc != 0));
|
|
#ifdef ATON_ARITH_CTRL_SET_CLIPOUT
|
|
t = ATON_ARITH_CTRL_SET_CLIPOUT(t, (conf->clipout != 0));
|
|
#endif
|
|
t = ATON_ARITH_CTRL_SET_OP(t, get_Arithacc_type(conf->operation));
|
|
if (conf->operation == ARITH_NOT_X)
|
|
{ // WORKAROUND
|
|
t = ATON_ARITH_CTRL_SET_LOGICALOP(t, 1);
|
|
}
|
|
ATON_ARITH_CTRL_SET(id, t);
|
|
|
|
t = ATON_ARITH_INSHIFTER_DT;
|
|
t = ATON_ARITH_INSHIFTER_SET_FBYTESX(t, conf->inbytes_x);
|
|
t = ATON_ARITH_INSHIFTER_SET_FSHIFTX(t, ATON_SHIFT(conf->shift_x));
|
|
t = ATON_ARITH_INSHIFTER_SET_FROUNDX(t, (conf->rounding_x != 0));
|
|
t = ATON_ARITH_INSHIFTER_SET_FSATX(t, (conf->saturation_x != 0));
|
|
t = ATON_ARITH_INSHIFTER_SET_FRNDMODEX(t, conf->round_mode_x);
|
|
t = ATON_ARITH_INSHIFTER_SET_FOBYTESX(t, conf->outbytes_x);
|
|
|
|
t = ATON_ARITH_INSHIFTER_SET_FBYTESY(t, conf->inbytes_y);
|
|
t = ATON_ARITH_INSHIFTER_SET_FSHIFTY(t, ATON_SHIFT(conf->shift_y));
|
|
t = ATON_ARITH_INSHIFTER_SET_FROUNDY(t, (conf->rounding_y != 0));
|
|
t = ATON_ARITH_INSHIFTER_SET_FSATY(t, (conf->saturation_y != 0));
|
|
t = ATON_ARITH_INSHIFTER_SET_FRNDMODEY(t, conf->round_mode_y);
|
|
t = ATON_ARITH_INSHIFTER_SET_FOBYTESY(t, conf->outbytes_y);
|
|
ATON_ARITH_INSHIFTER_SET(id, t);
|
|
|
|
t = ATON_ARITH_SHIFT_DT;
|
|
t = ATON_ARITH_SHIFT_SET_AX(t, conf->Ax_shift + sshift);
|
|
t = ATON_ARITH_SHIFT_SET_BY(t, conf->By_shift + sshift);
|
|
t = ATON_ARITH_SHIFT_SET_C(t, conf->C_shift + sshift);
|
|
t = ATON_ARITH_SHIFT_SET_RES(t, conf->shift_o); // right shift only
|
|
ATON_ARITH_SHIFT_SET(id, t);
|
|
|
|
t = ATON_ARITH_COEFFAC_DT;
|
|
t = ATON_ARITH_COEFFAC_SET_A(t, conf->A_scalar);
|
|
t = ATON_ARITH_COEFFAC_SET_C(t, conf->C_scalar);
|
|
ATON_ARITH_COEFFAC_SET(id, t);
|
|
|
|
t = ATON_ARITH_COEFFB_DT;
|
|
t = ATON_ARITH_COEFFB_SET_B(t, conf->B_scalar);
|
|
ATON_ARITH_COEFFB_SET(id, t);
|
|
|
|
#ifdef ATON_ARITH_CLIPRANGE_SET
|
|
if (conf->clipout)
|
|
{
|
|
t = ATON_ARITH_CLIPRANGE_DT;
|
|
t = ATON_ARITH_CLIPRANGE_SET_CLIPMAX(t, (conf->clipmax & 0xFFFFU));
|
|
t = ATON_ARITH_CLIPRANGE_SET_CLIPMIN(t, (conf->clipmin & 0xFFFFU));
|
|
ATON_ARITH_CLIPRANGE_SET(id, t);
|
|
|
|
#ifdef ATON_ARITH_CLIPRANGE_MSB_SET
|
|
t = ATON_ARITH_CLIPRANGE_MSB_DT;
|
|
t = ATON_ARITH_CLIPRANGE_MSB_SET_CLIPMAX(t, (conf->clipmax >> 16));
|
|
t = ATON_ARITH_CLIPRANGE_MSB_SET_CLIPMIN(t, (conf->clipmin >> 16));
|
|
ATON_ARITH_CLIPRANGE_MSB_SET(id, t);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
ATON_ARITH_COEFFADDR_SET(id, 0);
|
|
|
|
int maxc = 0;
|
|
if (conf->scalar == 0)
|
|
{ // vector mode
|
|
switch (conf->bcast)
|
|
{
|
|
case ARITH_BCAST_CHAN:
|
|
t = ATON_ARITH_INCCNT_SET_INCVAL(0, 0);
|
|
ATON_ARITH_INCCNT_SET(id, t);
|
|
|
|
t = ATON_ARITH_RSTCNT1_SET_RSTCNT(0, (conf->batchDepth - 1));
|
|
ATON_ARITH_RSTCNT1_SET(id, t);
|
|
|
|
t = ATON_ARITH_RSTCNT2_SET_RSTCNT(
|
|
0, (conf->fWidth * conf->fHeight * conf->batchDepth - 1)); // must check this fits into 27 bits FIXME !!!
|
|
ATON_ARITH_RSTCNT2_SET(id, t);
|
|
|
|
t = ATON_ARITH_RSTCNT3_SET_RSTCNT(
|
|
0, (conf->fWidth * conf->fHeight * conf->fChannels - 1)); // must check this fits into 27 bits FIXME !!!
|
|
ATON_ARITH_RSTCNT3_SET(id, t);
|
|
|
|
t = ATON_ARITH_INCOFFSET_SET_VAL(0, 1);
|
|
ATON_ARITH_INCOFFSET_SET(id, t);
|
|
|
|
t = ATON_ARITH_ADDROFFSET_SET_OFFSET1(0, -(conf->batchDepth - 1));
|
|
t = ATON_ARITH_ADDROFFSET_SET_OFFSET2(t, 1);
|
|
t = ATON_ARITH_ADDROFFSET_SET_OFFSET3(t, -(conf->fChannels - 1));
|
|
ATON_ARITH_ADDROFFSET_SET(id, t);
|
|
maxc = conf->fChannels;
|
|
break;
|
|
case ARITH_BCAST_HEIGHT:
|
|
t = ATON_ARITH_INCCNT_SET_INCVAL(0, (conf->fWidth * conf->batchDepth - 1));
|
|
ATON_ARITH_INCCNT_SET(id, t);
|
|
|
|
t = ATON_ARITH_RSTCNT1_SET_RSTCNT(0, (conf->fWidth * conf->fHeight * conf->batchDepth - 1));
|
|
ATON_ARITH_RSTCNT1_SET(id, t);
|
|
|
|
t = ATON_ARITH_INCOFFSET_SET_VAL(0, 1);
|
|
ATON_ARITH_INCOFFSET_SET(id, t);
|
|
|
|
t = ATON_ARITH_ADDROFFSET_SET_OFFSET1(0, -(conf->fHeight - 1));
|
|
ATON_ARITH_ADDROFFSET_SET(id, t);
|
|
maxc = conf->fHeight;
|
|
break;
|
|
case ARITH_BCAST_WIDTH:
|
|
t = ATON_ARITH_INCCNT_SET_INCVAL(0, (conf->batchDepth - 1));
|
|
ATON_ARITH_INCCNT_SET(id, t);
|
|
|
|
t = ATON_ARITH_RSTCNT1_SET_RSTCNT(0, (conf->fWidth * conf->batchDepth - 1));
|
|
ATON_ARITH_RSTCNT1_SET(id, t);
|
|
|
|
t = ATON_ARITH_INCOFFSET_SET_VAL(0, 1);
|
|
ATON_ARITH_INCOFFSET_SET(id, t);
|
|
|
|
t = ATON_ARITH_ADDROFFSET_SET_OFFSET1(0, -(conf->fWidth - 1));
|
|
ATON_ARITH_ADDROFFSET_SET(id, t);
|
|
maxc = conf->fWidth;
|
|
break;
|
|
case ARITH_BCAST_HEIGHT_WIDTH:
|
|
t = ATON_ARITH_INCCNT_SET_INCVAL(0, (conf->batchDepth - 1));
|
|
ATON_ARITH_INCCNT_SET(id, t);
|
|
|
|
t = ATON_ARITH_RSTCNT1_SET_RSTCNT(0, (conf->fHeight * conf->fWidth * conf->batchDepth - 1));
|
|
ATON_ARITH_RSTCNT1_SET(id, t);
|
|
|
|
t = ATON_ARITH_INCOFFSET_SET_VAL(0, 1);
|
|
ATON_ARITH_INCOFFSET_SET(id, t);
|
|
|
|
t = ATON_ARITH_ADDROFFSET_SET_OFFSET1(0, -(conf->fHeight * conf->fWidth - 1));
|
|
ATON_ARITH_ADDROFFSET_SET(id, t);
|
|
maxc = conf->fHeight * conf->fWidth;
|
|
break;
|
|
case ARITH_BCAST_SCALAR:
|
|
t = ATON_ARITH_INCCNT_SET_INCVAL(0, 0);
|
|
ATON_ARITH_INCCNT_SET(id, t);
|
|
|
|
t = ATON_ARITH_INCOFFSET_SET_VAL(0, 0);
|
|
ATON_ARITH_INCOFFSET_SET(id, t);
|
|
|
|
maxc = 1;
|
|
break;
|
|
default:
|
|
return LL_ATON_INVALID_PARAM;
|
|
}
|
|
|
|
maxc = (maxc > 512 ? 512 : maxc);
|
|
int i, k;
|
|
uint32_t *Ap = (uint32_t *)conf->A_vector.p;
|
|
uint32_t *Bp = (uint32_t *)conf->B_vector.p;
|
|
uint32_t *Cp = (uint32_t *)conf->C_vector.p;
|
|
int nbits_A = conf->vec_precision[0];
|
|
int nbits_B = conf->vec_precision[1];
|
|
int nbits_C = conf->vec_precision[2];
|
|
int bitcnt_A = 0;
|
|
int bitcnt_B = 0;
|
|
int bitcnt_C = 0;
|
|
int mem_idx_num = ATON_ARITH_COEFF_AB_IDX_MAX - ATON_ARITH_COEFF_AB_IDX_MIN + 1;
|
|
|
|
int32_t c_sign = (conf->C_scalar == -1 ? -1 : 1);
|
|
#if (LL_ATON_PLATFORM == LL_ATON_PLAT_EC_TRACE)
|
|
ec_trace_comment("Block ECASM optimizations to move reg writes pass this point");
|
|
#endif
|
|
ATON_ARITH_TRANSLATEADDR_SET(id, 1); // map 0x400 onto 0x0 offset for coefficients
|
|
for (i = 0, k = 0; i < maxc; i++, k++)
|
|
{
|
|
uint32_t t;
|
|
uint32_t A = Ap != NULL ? LL_ATON_getbits(Ap, bitcnt_A, nbits_A) : (uint32_t)conf->A_scalar;
|
|
uint32_t B = Bp != NULL ? LL_ATON_getbits(Bp, bitcnt_B, nbits_B) : (uint32_t)conf->B_scalar;
|
|
uint32_t C = Cp != NULL ? (c_sign * LL_ATON_getbits(Cp, bitcnt_C, nbits_C)) : (uint32_t)conf->C_scalar;
|
|
if (conf->combinebc)
|
|
{
|
|
B = (C >> 16);
|
|
C = (C & 0xFFFF);
|
|
}
|
|
if (k == mem_idx_num)
|
|
{
|
|
#if (LL_ATON_PLATFORM == LL_ATON_PLAT_EC_TRACE)
|
|
ec_trace_comment("Block ECASM optimizations to move reg writes pass this point");
|
|
#endif
|
|
ATON_ARITH_TRANSLATEADDR_SET(id, 0); // map 0xC00 onto 0xC00 offset for coefficients
|
|
k -= (256 / 2);
|
|
}
|
|
t = ATON_ARITH_COEFF_AB_DT;
|
|
t = ATON_ARITH_COEFF_AB_SET_A(t, A);
|
|
t = ATON_ARITH_COEFF_AB_SET_B(t, B);
|
|
ATON_ARITH_COEFF_AB_SET(id, k, t);
|
|
t = ATON_ARITH_COEFF_C_DT;
|
|
t = ATON_ARITH_COEFF_C_SET_C(t, C);
|
|
ATON_ARITH_COEFF_C_SET(id, k, t);
|
|
|
|
bitcnt_A += nbits_A;
|
|
bitcnt_B += nbits_B;
|
|
bitcnt_C += nbits_C;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
#endif // ATON_ARITH_NUM
|
|
|
|
#ifdef ATON_POOL_NUM
|
|
|
|
static int32_t get_Poolacc_type(LL_Poolacc_Op op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case POOL_MAX:
|
|
return ATON_POOLTYPE_MAX_POOLING;
|
|
case POOL_MIN:
|
|
return ATON_POOLTYPE_MIN_POOLING;
|
|
case POOL_AVG:
|
|
return ATON_POOLTYPE_AVG_POOLING;
|
|
case POOL_GMAX:
|
|
return ATON_POOLTYPE_GMAX_POOLING;
|
|
case POOL_GMIN:
|
|
return ATON_POOLTYPE_GMIN_POOLING;
|
|
case POOL_GAVG:
|
|
return ATON_POOLTYPE_GAVG_POOLING;
|
|
default:
|
|
break;
|
|
}
|
|
LL_ATON_ASSERT(0);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Configure Pooling Accelerator
|
|
* @param id Pooling Accelerator identifier [0..ATON_POOL_NUM-1]
|
|
* @param Poolacc_InitStruct Structure describing initialization parameters
|
|
* @retval Error code E.g.: Invalid ID, invalid parameters, not idle,..
|
|
*/
|
|
int LL_Poolacc_Init(int id, const LL_Poolacc_InitTypeDef *conf)
|
|
{
|
|
uint32_t t;
|
|
|
|
if (id >= ATON_POOL_NUM)
|
|
return LL_ATON_INVALID_ID;
|
|
|
|
LL_ATON_EnableClock(ATON_POOL_CLKB_CLK(id));
|
|
|
|
#ifdef POOL_RC14
|
|
/* Clear pipeline */
|
|
t = ATON_POOL_CTRL_GET(id);
|
|
t = ATON_POOL_CTRL_SET_EN(t, 0);
|
|
t = ATON_POOL_CTRL_SET_CLR(t, 1);
|
|
t = ATON_POOL_CTRL_SET_CONFCLR(t, 1);
|
|
ATON_POOL_CTRL_SET(id, t);
|
|
#endif // POOL_RC14
|
|
|
|
/* Initialize CTRL register parameters */
|
|
t = ATON_POOL_CTRL_DT;
|
|
t = ATON_POOL_CTRL_SET_TYPE(t, get_Poolacc_type(conf->operation));
|
|
t = ATON_POOL_CTRL_SET_ROUND(t, (conf->rounding_o != 0));
|
|
t = ATON_POOL_CTRL_SET_SAT(t, (conf->saturation_o != 0));
|
|
t = ATON_POOL_CTRL_SET_OUTSHIFT(t, conf->shift_o);
|
|
t = ATON_POOL_CTRL_SET_FBYTES(t, conf->inbytes_f);
|
|
t = ATON_POOL_CTRL_SET_FSHIFT(t, ATON_SHIFT(conf->shift_f));
|
|
t = ATON_POOL_CTRL_SET_FROUND(t, (conf->rounding_f != 0));
|
|
t = ATON_POOL_CTRL_SET_FSAT(t, (conf->saturation_f != 0));
|
|
#ifdef ATON_POOL_CTRL_SET_AVGNOPAD
|
|
t = ATON_POOL_CTRL_SET_AVGNOPAD(t, (conf->avgnopad != 0));
|
|
#endif
|
|
t = ATON_POOL_CTRL_SET_DUALLINE(t, conf->dualLine);
|
|
#if 0
|
|
int crop_en = ((conf->leftCrop > 0) || (conf->rightCrop > 0) || (conf->topCrop > 0) || (conf->bottomCrop > 0));
|
|
#else
|
|
int crop_en = 1;
|
|
#endif
|
|
t = ATON_POOL_CTRL_SET_CROPEN(t, crop_en);
|
|
ATON_POOL_CTRL_SET(id, t);
|
|
|
|
/* configure remaining in/out shifters */
|
|
t = ATON_POOL_RNDCTRL_DT;
|
|
t = ATON_POOL_RNDCTRL_SET_FOBYTES(t, conf->outbytes_f);
|
|
t = ATON_POOL_RNDCTRL_SET_FRNDMODE(t, conf->round_mode_f);
|
|
t = ATON_POOL_RNDCTRL_SET_OBYTES(t, conf->outbytes_o);
|
|
t = ATON_POOL_RNDCTRL_SET_ORNDMODE(t, (conf->relu_mode_o << 1) | conf->round_mode_o);
|
|
ATON_POOL_RNDCTRL_SET(id, t);
|
|
|
|
/* Configure Pooling unit dimensions register */
|
|
t = ATON_POOL_PDIMS_DT;
|
|
t = ATON_POOL_PDIMS_SET_WINX(t, conf->poolWinX);
|
|
t = ATON_POOL_PDIMS_SET_WINY(t, conf->poolWinY);
|
|
t = ATON_POOL_PDIMS_SET_STRDX(t, conf->strideX);
|
|
t = ATON_POOL_PDIMS_SET_STRDY(t, conf->strideY);
|
|
t = ATON_POOL_PDIMS_SET_TPAD(t, conf->topPad);
|
|
t = ATON_POOL_PDIMS_SET_BPAD(t, conf->bottomPad);
|
|
t = ATON_POOL_PDIMS_SET_LPAD(t, conf->leftPad);
|
|
t = ATON_POOL_PDIMS_SET_RPAD(t, conf->rightPad);
|
|
t = ATON_POOL_PDIMS_SET_BSIZE(t, conf->batchSize);
|
|
ATON_POOL_PDIMS_SET(id, t);
|
|
|
|
/* Configure Pooling unit FDIMS register */
|
|
t = ATON_POOL_FDIMS_DT;
|
|
t = ATON_POOL_FDIMS_SET_FEATX(t, conf->inputX * conf->batchSize);
|
|
t = ATON_POOL_FDIMS_SET_FEATY(t, conf->inputY);
|
|
ATON_POOL_FDIMS_SET(id, t);
|
|
|
|
/* Configure Pooling unit OUTDIMS register */
|
|
t = ATON_POOL_OUTDIMS_DT;
|
|
t = ATON_POOL_OUTDIMS_SET_FEATX(t, conf->outputX);
|
|
t = ATON_POOL_OUTDIMS_SET_FEATY(t, conf->outputY);
|
|
ATON_POOL_OUTDIMS_SET(id, t);
|
|
|
|
/* Configure mulval */
|
|
t = ATON_POOL_MULVAL_DT;
|
|
t = ATON_POOL_MULVAL_SET_MULVAL(t, conf->mulval);
|
|
ATON_POOL_MULVAL_SET(id, t);
|
|
|
|
/* Mulval is scattered across different registers from V3 onwards. TODO: use ATON.h macros */
|
|
#if (ATON_POOL_VERSION_MAJOR_DT >= 3)
|
|
unsigned int wsize = conf->poolWinX * conf->poolWinY;
|
|
if (wsize > 0 && wsize < 9)
|
|
{
|
|
uint32_t *mulval_addr = (uint32_t *)ATON_POOL_MULVAL_1_2_ADDR(id);
|
|
wsize--;
|
|
mulval_addr += (wsize / 2);
|
|
if (wsize & 1)
|
|
*mulval_addr |= ((conf->mulval) << 16);
|
|
else
|
|
*mulval_addr |= conf->mulval;
|
|
}
|
|
#endif
|
|
|
|
/* Configure cropping if needed */
|
|
t = ATON_POOL_XCROP_DT;
|
|
if (conf->leftCrop > 0)
|
|
t = ATON_POOL_XCROP_SET_LCROP(t, conf->leftCrop * conf->batchSize);
|
|
int r_crop = conf->rightCrop * conf->batchSize + (conf->batchSize - 1);
|
|
if (r_crop > 0)
|
|
t = ATON_POOL_XCROP_SET_RCROP(t, conf->rightCrop * conf->batchSize + (conf->batchSize - 1));
|
|
ATON_POOL_XCROP_SET(id, t);
|
|
|
|
t = ATON_POOL_YCROP_DT;
|
|
if (conf->topCrop > 0)
|
|
t = ATON_POOL_YCROP_SET_TCROP(t, conf->topCrop);
|
|
if (conf->bottomCrop > 0)
|
|
t = ATON_POOL_YCROP_SET_BCROP(t, conf->bottomCrop);
|
|
ATON_POOL_YCROP_SET(id, t);
|
|
|
|
#ifdef ATON_POOL_USER_PAD_VALUE_SET
|
|
if (conf->pad_val_en)
|
|
{
|
|
t = ATON_POOL_USER_PAD_VALUE_DT;
|
|
t = ATON_POOL_USER_PAD_VALUE_SET_PADVAL(t, conf->pad_val);
|
|
t = ATON_POOL_USER_PAD_VALUE_SET_PADVALEN(t, 1);
|
|
ATON_POOL_USER_PAD_VALUE_SET(id, t);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
#endif // ATON_POOL_NUM
|
|
|
|
#if defined(ATON_EPOCHCTRL_NUM)
|
|
/**
|
|
* @brief Configure Epoch Controller
|
|
* @param id Epoch Controller identifier [0..ATON_EPOCHCTRL_NUM-1]
|
|
* @param conf Structure describing Epoch Controller initialization parameters
|
|
* @retval Error code
|
|
*/
|
|
int LL_EpochCtrl_Init(int id, const LL_EpochCtrl_InitTypeDef *conf)
|
|
{
|
|
uint32_t t;
|
|
|
|
if (id >= ATON_EPOCHCTRL_NUM)
|
|
return LL_ATON_INVALID_ID;
|
|
|
|
LL_ATON_EnableClock(ATON_EPOCHCTRL_CLKB_CLK(id));
|
|
|
|
/* Configure CTRL register */
|
|
t = ATON_EPOCHCTRL_CTRL_DT;
|
|
t = ATON_EPOCHCTRL_CTRL_SET_SM(t, conf->stepmode);
|
|
ATON_EPOCHCTRL_CTRL_SET(id, t);
|
|
|
|
/* Check address is 8 byte aligned */
|
|
if (conf->blobaddr & 0x7)
|
|
return LL_ATON_INVALID_PARAM;
|
|
|
|
ATON_EPOCHCTRL_ADDR_SET(id, conf->blobaddr);
|
|
|
|
return LL_ATON_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Trigger Epoch Controller Single Step execution
|
|
* @param id Epoch Controller identifier [0..ATON_EPOCHCTRL_NUM-1]
|
|
* @retval Error code
|
|
*/
|
|
int LL_EpochCtrl_Step(int id)
|
|
{
|
|
uint32_t t;
|
|
|
|
t = ATON_EPOCHCTRL_IRQ_GET(id);
|
|
t = ATON_EPOCHCTRL_IRQ_SET_SM(t, 1);
|
|
ATON_EPOCHCTRL_IRQ_SET(id, t);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Waits for epoch controller to become idle
|
|
* @param id Bitmask of EC identifiers
|
|
* @retval Error code
|
|
*/
|
|
int LL_EpochCtrl_Wait(uint32_t mask)
|
|
{
|
|
int i;
|
|
uint32_t enableFlags;
|
|
|
|
startWatchdog(ATON_EPOCH_TIMEOUT);
|
|
|
|
do
|
|
{
|
|
enableFlags = 0;
|
|
for (i = 0; i < ATON_EPOCHCTRL_NUM; i++)
|
|
{
|
|
if (mask & (1 << i))
|
|
{
|
|
enableFlags |= (ATON_EPOCHCTRL_CTRL_GET(i) & (1U << ATON_EPOCHCTRL_CTRL_RUNNING_LSB));
|
|
}
|
|
}
|
|
|
|
LL_ATON_ASSERT(checkWatchdog() == 0);
|
|
|
|
} while (enableFlags);
|
|
|
|
return LL_ATON_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief Returns the size of a blob
|
|
* @param eb_addr Pointer to blob
|
|
* @retval Size in bytes of the blob
|
|
*/
|
|
unsigned int LL_EpochCtrl_GetBlobSize(uint32_t *eb_addr)
|
|
{
|
|
unsigned bloblines = eb_addr[1] + 2;
|
|
return bloblines * 4;
|
|
}
|
|
#endif // ATON_EPOCHCTRL_NUM
|
|
|
|
void LL_ATON_EnableClock(unsigned int clock)
|
|
{
|
|
#if (LL_ATON_ENABLE_CLOCK_GATING == 1)
|
|
ATON_REG_WRITE_FIELD_RANGE(CLKCTRL, 0, BGATES, clock, 1, 1);
|
|
#endif
|
|
}
|
|
|
|
void LL_ATON_DisableClock(unsigned int clock)
|
|
{
|
|
#if (LL_ATON_ENABLE_CLOCK_GATING == 1)
|
|
ATON_REG_WRITE_FIELD_RANGE(CLKCTRL, 0, BGATES, clock, 1, 0);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @brief DMA version of a memcpy functionality, this function could be overloaded if a system DMA could be used
|
|
* @param dst destination memory address
|
|
* @param src source memory address
|
|
* @param src_limit memory pool end address of `src`
|
|
* @param n number of bytes to be transferred
|
|
* @param dst_cached Destination under cache flag
|
|
* @param dst_cached Source under cache flag
|
|
* @retval Error code E.g.: Invalid ID, invalid parameters, not idle,..
|
|
*
|
|
* @note: This function completely undermines any possibility for integrating correctly
|
|
* SW operators (or any other functionality which calls this function) in any of the three ATON runtime
|
|
* scheduling modes. In other words, function `LL_ATON_Dma_memcpy()` and its usage are incompatible with the ATON
|
|
* runtime. Therefore either `memcpy()` should be used in its place or calls to `LL_ATON_Dma_memcpy()` need to be
|
|
* transformed in a sequence of "epoch blocks" which can be integrated with the ATON runtime (as an example see the
|
|
* ATON-accelerated implementation of operator `Concat`)!
|
|
*/
|
|
/* N.B. assumes DMA0 and 1 are free to use */
|
|
#define MIN_BUFF_LEN 40
|
|
LL_ATON_WEAK void *LL_ATON_Dma_memcpy(void *dst, void *src, void *src_limit, size_t n, int dst_cached, int src_cached)
|
|
{
|
|
uint8_t *_dst_orig = dst;
|
|
|
|
int prolog_len = (n % 3);
|
|
int i;
|
|
uint8_t *_dst = (uint8_t *)dst;
|
|
uint8_t *_src = (uint8_t *)src;
|
|
|
|
if (n < MIN_BUFF_LEN)
|
|
prolog_len = n; // not worth it ...
|
|
// LL_ATON_PRINTF("n=%d prolog=%d\n",n,prolog_len);
|
|
|
|
for (i = 0; i < prolog_len; i++)
|
|
*_dst++ = *_src++;
|
|
n -= prolog_len;
|
|
|
|
if (prolog_len > 0)
|
|
{
|
|
/* *** MCU cache clean & invalidate operation (SW) *** */
|
|
LL_ATON_Cache_MCU_Clean_Invalidate_Range(ATON_LIB_PHYSICAL_TO_VIRTUAL_ADDR((uintptr_t)_dst_orig), prolog_len);
|
|
}
|
|
|
|
if (n > 0)
|
|
{
|
|
LL_Streng_TensorInitTypeDef dma_in = {
|
|
.dir = 0,
|
|
.addr_base = {_src},
|
|
.offset_start = 0,
|
|
.offset_end = n,
|
|
.offset_limit = ((uintptr_t)src_limit - (uintptr_t)src), // awful FIXME Francesco
|
|
.raw = 1,
|
|
.frame_count = 0,
|
|
.fwidth = 0,
|
|
.fheight = 0,
|
|
.batch_depth = 0,
|
|
.batch_offset = 0,
|
|
.frame_offset = n,
|
|
.line_offset = 0,
|
|
.loop_offset = 0,
|
|
.frame_loop_cnt = 0,
|
|
.frame_tot_cnt = 1,
|
|
.nbits_in = 24,
|
|
.nbits_out = 24,
|
|
.nbits_unsigned = 0,
|
|
.align_right = 0,
|
|
.noblk = 0,
|
|
};
|
|
|
|
LL_Streng_TensorInitTypeDef dma_out = {
|
|
.dir = 1,
|
|
.addr_base = {_dst},
|
|
.offset_start = 0,
|
|
.offset_end = n,
|
|
.raw = 1,
|
|
.frame_count = 0,
|
|
.fwidth = 0,
|
|
.fheight = 0,
|
|
.batch_depth = 0,
|
|
.batch_offset = 0,
|
|
.frame_offset = n,
|
|
.line_offset = 0,
|
|
.loop_offset = 0,
|
|
.frame_loop_cnt = 0,
|
|
.frame_tot_cnt = 1,
|
|
.nbits_in = 24,
|
|
.nbits_out = 24,
|
|
.nbits_unsigned = 0,
|
|
.align_right = 0,
|
|
.noblk = 0,
|
|
};
|
|
|
|
if (src_cached)
|
|
{
|
|
dma_in.cacheable = 1;
|
|
dma_in.cache_allocate = 1;
|
|
}
|
|
|
|
if (dst_cached)
|
|
{
|
|
dma_out.cacheable = 1;
|
|
dma_out.cache_allocate = 1;
|
|
}
|
|
|
|
const LL_Switch_InitTypeDef switch_init = {LL_Switch_Init_Dest() = ATONN_DSTPORT(STRSWITCH, 0, STRENG, 1, 0),
|
|
LL_Switch_Init_Source(0) = ATONN_SRCPORT(STRSWITCH, 0, STRENG, 0, 0),
|
|
LL_Switch_Init_Context(0) = 1, LL_Switch_Init_Frames(0) = 0};
|
|
const LL_ATON_EnableUnits_InitTypeDef dma_units[] = {{{STRENG, 1}}, {{STRENG, 0}}};
|
|
const uint32_t dma_wait_mask = 0x2;
|
|
|
|
LL_Streng_TensorInit(0, &dma_in, 1);
|
|
LL_Streng_TensorInit(1, &dma_out, 1);
|
|
LL_Switch_Init(&switch_init, 1);
|
|
LL_ATON_EnableUnits_Init(dma_units, 2);
|
|
LL_Streng_Wait(dma_wait_mask);
|
|
LL_ATON_DisableUnits_Init(dma_units, 1);
|
|
LL_Switch_Deinit(&switch_init, 1);
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
#if (LL_ATON_PLATFORM == LL_ATON_PLAT_EC_TRACE)
|
|
static void *ec_aton_base;
|
|
|
|
uintptr_t get_ec_aton_base(void)
|
|
{
|
|
return (uintptr_t)ec_aton_base;
|
|
}
|
|
|
|
void initialize_ec_aton_base(void)
|
|
{
|
|
ec_aton_base = malloc(ATON_SIZE);
|
|
}
|
|
|
|
/* Called by patched ATON.h to trace ATON register stores */
|
|
void ec_trace_write(uintptr_t dstreg, unsigned int val)
|
|
{
|
|
uint32_t IP_id = ec_trace_get_IP_id(dstreg);
|
|
uint32_t regaddr_offset = dstreg - (uintptr_t)ATON_BASE;
|
|
uint32_t REG_id = ec_trace_get_REG_id(regaddr_offset);
|
|
ec_trace_reg_write(IP_id, REG_id, val);
|
|
}
|
|
|
|
void ec_trace_write_reloc(uintptr_t dstreg, unsigned int base, unsigned int offset)
|
|
{
|
|
uint32_t IP_id = ec_trace_get_IP_id(dstreg);
|
|
uint32_t regaddr_offset = dstreg - (uintptr_t)ATON_BASE;
|
|
uint32_t REG_id = ec_trace_get_REG_id(regaddr_offset);
|
|
ec_trace_reg_write_reloc(IP_id, REG_id, base, offset);
|
|
}
|
|
|
|
unsigned int ec_trace_get_IP_id(uintptr_t dstreg)
|
|
{
|
|
uint32_t regaddr_offset = dstreg - (uintptr_t)ATON_BASE;
|
|
uint32_t IP_id = (uint32_t)((regaddr_offset & 0x0ffff000) >> 12);
|
|
return IP_id;
|
|
}
|
|
unsigned int ec_trace_get_REG_id(unsigned int regoffset)
|
|
{
|
|
return (regoffset & 0xfff) >> 2;
|
|
}
|
|
|
|
void ec_trace_wait_epoch_end(uint32_t wait_mask)
|
|
{
|
|
// TODO: Only polling mode supported at the moment
|
|
for (unsigned i = 0; i < 32; i++)
|
|
{
|
|
if (wait_mask & (1 << i))
|
|
{
|
|
ATON_REG_POLL(STRENG, i, CTRL, RUNNING, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|