/*
 * Copyright 2020-2023 YTMicro
 * All rights reserved.
 *
 * YTMicro Confidential. This software is owned or controlled by YTMicro and may
 * only be used strictly in accordance with the applicable license terms. By expressly
 * accepting such terms or by downloading, installing, activating and/or otherwise
 * using the software, you are agreeing that you have read, and that you agree to
 * comply with and are bound by, such license terms. If you do not agree to be
 * bound by the applicable license terms, then you may not retain, install,
 * activate or otherwise use the software. The production use license in
 * Section 2.3 is expressly granted for this software.
 */

/**
 * @page misra_violations MISRA-C:2012 violations list
 *
 * PRQA S 3684 Rule-8.11: When an array with external linkage is declared, its Size should be explicitly specified
 * PRQA S 2983 Rule-2.2: There shall be no dead code
 * PRQA S 0306 Rule-11.4: A conversion should not be performed between a pointer to object and an integer type
 * PRQA S 2871 Dir-4.1: Run-time failures shall be minimized
 * PRQA S 2990 Rule 14.3: Controlling expressions shall not be invariant
 */

#include "startup.h"
#include "Std_Types.h"

#define PLATFORM_START_SEC_CODE
#include "Platform_MemMap.h"

/*******************************************************************************
 * Definitions
 *******************************************************************************/
#define DOUBLE_WORDS_ALIGN_MASK (7U)
#define DOUBLE_WORDS_SHIFT      (3U)

/*!
* @brief Defines the init table layout
*/
typedef struct
{
    uint32 *RamStart;   /*!< Start address of section in RAM */
    uint32 *RomStart;   /*!< Start address of section in ROM */
    uint32 *RomEnd;     /*!< End address of section in ROM */
} Sys_CopyLayoutType;

/*!
 * @brief Defines the zero table layout
 */
typedef struct
{
    uint32 *RamStart;   /*!< Start address of section in RAM */
    uint32 *RamEnd;     /*!< End address of section in RAM */
} Sys_ZeroLayoutType;

extern uint32 __INIT_TABLE[];
extern uint32 __ZERO_TABLE[];

/*******************************************************************************
 * Code
 ******************************************************************************/

/*FUNCTION**********************************************************************
 *
 * Function Name : init_data_bss
 * Description   : Make necessary initializations for RAM.
 * - Copy the vector table from ROM to RAM.
 * - Copy initialized data from ROM to RAM.
 * - Copy code that should reside in RAM from ROM
 * - Clear the zero-initialized data section.
 *
 * Tool Chains:
 *   __GNUC__           : GNU Compiler Collection
 *   __ICCARM__         : IAR ARM Compiler
 *   __ARMCC_VERSION    : ARMC Compiler
 *
 * Implements    : init_data_bss_Activity
 *END**************************************************************************/
PLATFORM_FUNC void init_data_bss(void)
{
    const Sys_CopyLayoutType *CopyLayout;
    const Sys_ZeroLayoutType *ZeroLayout;
    const uint64 *Rom64;
    const uint8 *Rom8;
    uint64 *Ram64;
    uint8 *Ram8;
    uint8 DataPad;
    uint32 Len = 0U;
    uint32 Size = 0U;
    uint32 MajorLoopCnt = 0U;
    uint32 MinorLoopCnt = 0U;

    const uint32 *InitTable = (uint32 *)__INIT_TABLE;
    const uint32 *ZeroTable = (uint32 *)__ZERO_TABLE;

    /* Copy initialized table */
    Len = *InitTable;
    ++InitTable;
    CopyLayout = (const Sys_CopyLayoutType *)InitTable;
    for (MajorLoopCnt = 0U; MajorLoopCnt < Len; ++MajorLoopCnt)
    {
        Rom64 = (const uint64 *)CopyLayout[MajorLoopCnt].RomStart;
        Ram64 = (uint64 *)CopyLayout[MajorLoopCnt].RamStart;
        Size = (uint32)CopyLayout[MajorLoopCnt].RomEnd - (uint32)CopyLayout[MajorLoopCnt].RomStart;
        /* Make sure the data area to be copied must be aligned with 8. Then, copy 8 bytes at per one read */
        DataPad = Size & DOUBLE_WORDS_ALIGN_MASK;
        Size = (Size - DataPad) >> DOUBLE_WORDS_SHIFT;
        for (MinorLoopCnt = 0U; MinorLoopCnt < Size; ++MinorLoopCnt)
        {
            Ram64[MinorLoopCnt] = Rom64[MinorLoopCnt];
        }
        /* For the rest of data, copy 1 bytes at per one read */
        Rom8 = (uint8 *) & (Rom64[MinorLoopCnt]);
        Ram8 = (uint8 *) & (Ram64[MinorLoopCnt]);
        for (MinorLoopCnt = 0U; MinorLoopCnt < DataPad; ++MinorLoopCnt)
        {
            Ram8[MinorLoopCnt] = Rom8[MinorLoopCnt];
        }
    }

    /* Clear zero table */
    Len = *ZeroTable;
    ++ZeroTable;
    ZeroLayout = (const Sys_ZeroLayoutType *)ZeroTable;
    for (MajorLoopCnt = 0U; MajorLoopCnt < Len; ++MajorLoopCnt)
    {
        Ram64 = (uint64 *)ZeroLayout[MajorLoopCnt].RamStart;
        Size = (uint32)ZeroLayout[MajorLoopCnt].RamEnd - (uint32)ZeroLayout[MajorLoopCnt].RamStart;
        /* Make sure the data area to be zeroed must be aligned with 8. Then, zero 8 bytes at per one read */
        DataPad = Size & DOUBLE_WORDS_ALIGN_MASK;
        Size = (Size - DataPad) >> DOUBLE_WORDS_SHIFT;        
        for (MinorLoopCnt = 0U; MinorLoopCnt < Size; ++MinorLoopCnt)
        {
            Ram64[MinorLoopCnt] = 0U;
        }
        /* For the rest of data, zero 1 bytes at per one read */
        Ram8 = (uint8 *) & (Ram64[MinorLoopCnt]);
        for (MinorLoopCnt = 0U; MinorLoopCnt < DataPad; ++MinorLoopCnt)
        {
            Ram8[MinorLoopCnt] = 0U;
        }
    }
}

#define PLATFORM_STOP_SEC_CODE
#include "Platform_MemMap.h"

/*******************************************************************************
 * EOF
 ******************************************************************************/
