/**********************************************************************************************************************
 *  COPYRIGHT
 *  -------------------------------------------------------------------------------------------------------------------
 *  \verbatim
 *  Copyright (c) 2025 by Vector Informatik GmbH.                                                  All rights reserved.
 *
 *                This software is copyright protected and proprietary to Vector Informatik GmbH.
 *                Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
 *                All other rights remain with Vector Informatik GmbH.
 *  \endverbatim
 *  -------------------------------------------------------------------------------------------------------------------
 *  FILE DESCRIPTION
 *  -----------------------------------------------------------------------------------------------------------------*/
/** \file  File:  ARMStartup_CortexR.c
 *      Project:  Vector Basic Runtime System
 *       Module:  BrsHw for all platforms with ARM core Cortex-R
 *     Template:  This file is reviewed according to Brs_Template@Implementation[1.03.12]
 *
 *  \brief Description:  This file contains the assembler part of the BRS StartUpCode.
 *
 *  \attention Please note:
 *    The demo and example programs only show special aspects of the software. With regard to the fact
 *    that these programs are meant for demonstration purposes only, Vector Informatik liability shall be
 *    expressly excluded in cases of ordinary negligence, to the extent admissible by law or statute.
 *********************************************************************************************************************/

/**********************************************************************************************************************
 *  REVISION HISTORY
 *  -------------------------------------------------------------------------------------------------------------------
 *  Refer to ARMBrsHw_CortexR.h.
 *********************************************************************************************************************/

/**********************************************************************************************************************
 *  EXAMPLE CODE ONLY
 *  -------------------------------------------------------------------------------------------------------------------
 *  This Example Code is only intended for illustrating an example of a possible BSW integration and BSW configuration.
 *  The Example Code has not passed any quality control measures and may be incomplete. The Example Code is neither
 *  intended nor qualified for use in series production. The Example Code as well as any of its modifications and/or
 *  implementations must be tested with diligent care and must comply with all quality requirements which are necessary
 *  according to the state of the art before their use.
 *********************************************************************************************************************/

#define ARMSTARTUP_CORTEXR_SOURCE

/**********************************************************************************************************************
 *  INCLUDES
 *********************************************************************************************************************/
#include "BrsHw.h"

#if defined (BRS_FIRST_EXECUTION_INSTANCE)
/* This code is only needed for the first instance/executable in the system */

#include "vBrs_Lcfg.h"
#include "vLinkGen_Lcfg.h"

/**********************************************************************************************************************
 *  CONFIGURATION CHECK
 *********************************************************************************************************************/
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)

#else
  #error "Unknown compiler specified!"
#endif

#if (VLINKGEN_CFG_MAJOR_VERSION != 2u)
  #error "This StartUpCode is dependent to the vLinkGen version! vLinkGen major version does not fit!"
#else
# if (VLINKGEN_CFG_MINOR_VERSION < 5u)
  #error "This StartUpCode is dependent to the vLinkGen version! Your vLinkGen minor version is too old!"
# endif
#endif

/**********************************************************************************************************************
 *  DEFINITION + MACROS
 *********************************************************************************************************************/
#if defined (BRS_FIRST_EXECUTION_INSTANCE)
extern void intvect_CoreExceptions(void);
#endif

#if defined (BRS_ENABLE_OS_MULTICORESUPPORT)
extern ARMBrsHw_PhysicalCoreId_CoreExceptions_MappingType BrsHw_intvect_CoreExceptions_list[BRS_CPU_CORE_AMOUNT-1];
#endif

/**********************************************************************************************************************
 *  GLOBAL VARIABLES
 *********************************************************************************************************************/
#if defined (BRS_ENABLE_OS_MULTICORESUPPORT)
/* used 32bit values for less assembler differences in accessing code */
const uint32 BrsHw_InitCoreID = (uint32) BRSHW_INIT_CORE_ID;
const uint32 BrsHw_CpuCoreAmountMinus1 = (uint32) (BRS_CPU_CORE_AMOUNT-1);
#endif

/**********************************************************************************************************************
 *  PROTOTYPES OF LOCAL FUNCTIONS
 *********************************************************************************************************************/
BRS_LOCAL_PROTOTYPE(_start)
BRS_LOCAL_PROTOTYPE(brsStartupEntry)
BRS_LOCAL_PROTOTYPE(brsStartupInvalidateCache)
BRS_LOCAL_PROTOTYPE(brsStartupZeroInitLoop)
BRS_LOCAL_PROTOTYPE(brsStartupStackSearch)
BRS_LOCAL_PROTOTYPE(coreRegisterInit)
BRS_LOCAL_PROTOTYPE(coreRegisterInit2)
BRS_LOCAL_PROTOTYPE(coreRegisterInit3)
BRS_LOCAL_PROTOTYPE(stackPointerInit)
BRS_LOCAL_PROTOTYPE(brsPreAsmStartupHook)


/* =========================================================================== */
/*                                                                             */
/* Description: Entry point for all cores                                      */
/*                                                                             */
/* =========================================================================== */

BRS_SECTION_CODE(brsStartup)

/* Alternativ entry point from OS default config */
 BRS_GLOBAL(_start)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(_start)
BRS_MULTILINE_ASM_END()
BRS_GLOBAL_END()

 BRS_GLOBAL(brsStartupEntry)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(brsStartupEntry)
#if defined (BRSHW_PRE_ASM_STARTUP_HOOK_AVAILABLE)
#endif

 BRS_BRANCH(brsPreAsmStartupHook)
BRS_MULTILINE_ASM_END()
BRS_GLOBAL_END()

/* =========================================================================== */
/*                                                                             */
/* Description: Optional hook for platform specific tasks                      */
/*                                                                             */
/* =========================================================================== */
#if !defined (BRSHW_PRE_ASM_STARTUP_HOOK_AVAILABLE)
 BRS_GLOBAL(brsPreAsmStartupHook)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(brsPreAsmStartupHook)
/* Nothing to do here */

 BRS_BRANCH(coreRegisterInit)
BRS_MULTILINE_ASM_END()
BRS_GLOBAL_END()
#endif /*!BRSHW_PRE_ASM_STARTUP_HOOK_AVAILABLE*/

/* =========================================================================== */
/*                                                                             */
/* Description: Initialize core ID independent core registers                  */
/*                                                                             */
/* =========================================================================== */
 BRS_GLOBAL(coreRegisterInit)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(coreRegisterInit)

/* Note: ARMStartup_CortexR.c must be compiled in ARM mode, since
 *       the exception table is implemented in ARM mode only
 */
 __as1(LDR  r0, =BrsStartupInstSetInit)

#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ORR  r0 ,r0, 0)
#else
 __as2(ORR  r0 ,r0, #0)
#endif
 ___asm(BX  r0)


BRS_LABEL(BrsStartupInstSetInit)

#if defined (BRS_FPU_USED)
 /* Allow full access to coprocessors 10,11 */
 /* r0 gets the content of the Coprocessor Access Control Register */
# if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as5(MRC  p15, 0, r0, c1, c0, 2)
# else
 __as5(MRC  p15, #0x00, r0, c1, c0, #0x02)
# endif

 __as2(ORR  r0, r0, #0x00F00000)
 /* Write Coprocessor Access Control Register to set access rights for coprocessor cp10, cp11 to full access
    Note: Coprocessors cp10 and cp11 support floating-point and vector operations, and the control and configuration of
          the Floating-point and Advanced SIMD architecture extensions. */
# if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as5(MCR  p15, 0, r0, c1, c0, 2)
# else
 __as5(MCR  p15, #0x00, r0, c1, c0, #0x02)
# endif

/* Enable Advanced SIMD and Floating-point Extensions */
 __as1(VMRS r0, FPEXC)
 __as1(MOV  r1, #0x40000000)
 __as2(ORR  r0, r0, r1)
 __as1(VMSR FPEXC, r0)
#endif /*BRS_FPU_USED*/

/* Switch to System Mode */
 __as1(MRS  r0, CPSR)
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ORR  r0, r0, 0x1f)
 __as1(MSR  CPSR, r0)
#else
 __as2(ORR  r0, r0, #0x1f)
 __as1(MSR  cpsr_cxsf, r0)
#endif

 BRS_BRANCH(coreRegisterInit2)
BRS_MULTILINE_ASM_END()
BRS_GLOBAL_END()

/* =========================================================================== */
/*                                                                             */
/* Description: Initialize all core ID dependent core registers                */
/*              Setup exception table                                          */
/*                                                                             */
/* =========================================================================== */
 BRS_GLOBAL(coreRegisterInit2)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(coreRegisterInit2)

#if defined (BRSHW_ARMCOMMON_COREEXCEPTIONS_AT_ADDRESS_0)
# if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R2, 0)
# else
 __as1(MOV  R2, #0)
# endif

#else /*(BRSHW_ARMCOMMON_COREEXCEPTIONS_AT_ADDRESS_0)*/
# if defined (BRS_ENABLE_OS_MULTICORESUPPORT)
 __as1(LDR  R1, =BrsHw_InitCoreID)
 __as1(LDR  R3, [R1])
  /* ==> R3 = BrsHw_InitCoreID */

 BRS_READ_COREID(R0)
  /* ==> R0 = BRS_READ_COREID */

  /* If actual running core is init core, directly jump to implemantation for init core.
     (ExceptionTable of init core is not part of BrsHw_intvect_CoreExceptions_list[]) */
 BRS_BRANCH_EQUAL(R0, R3, set_exception_table_location_on_init_core)

 __as1(LDR  R1, =BrsHw_CpuCoreAmountMinus1)
 __as1(LDR  R5, [R1])
  /* ==> R5 = BrsHw_CpuCoreAmountMinus1 */

 __as1(LDR  R4, =BrsHw_intvect_CoreExceptions_list)
  /* ==> R4 = BrsHw_intvect_CoreExceptions_list */

/* Use R6 as count register in the loop. Initialize with zero. */
#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R6, 0)
#  else
 __as1(MOV  R6, #0)
#  endif

BRS_LABEL(get_exception_table_location_for_this_core_loop)

 __as1(LDR  R7, [R4])
  /* ==> R7 = BrsHw_intvect_CoreExceptions_list[R6].PhysicalCoreId */
  
 BRS_READ_COREID(R0)
  /* ==> R0 = BRS_READ_COREID */

  /* Check, if BrsHw_intvect_CoreExceptions_list entry of actual running core is reached */
 BRS_BRANCH_EQUAL(R0, R7, get_exception_table_location_for_this_core)

/* Increase count register by one. */
#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R6, R6, 1)
#  else
 __as2(ADD  R6, R6, #1)
#  endif

/* Set R4 to point to next entry of BrsHw_intvect_CoreExceptions_list. */
#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R4, R4, 8)
#  else
 __as2(ADD  R4, R4, #8)
#  endif

/* Check if end of BrsHw_intvect_CoreExceptions_list has been reached. */
 BRS_BRANCH_NOT_EQUAL(R6, R5, get_exception_table_location_for_this_core_loop)
/* If no Exception Table address for running core has been found -> BrsMainExceptionStartup. */
 BRS_BRANCH(get_exception_table_location_error)

BRS_LABEL(get_exception_table_location_for_this_core)

/* Set R4 to point to next attribute of the current (R6)
   struct ARMBrsHw_PhysicalCoreId_CoreExceptions_MappingType: CoreExceptions
 */
#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R4, R4, 4)
#  else
 __as2(ADD  R4, R4, #4)
#  endif

 __as1(LDR  R2, [R4])
  /* ==> R2 = BrsHw_intvect_CoreExceptions_list[R6].CoreExceptions */

 BRS_BRANCH(get_exception_table_location_end)

BRS_LABEL(set_exception_table_location_on_init_core)
# endif /*BRS_ENABLE_OS_MULTICORESUPPORT*/

# if defined (BRS_FIRST_EXECUTION_INSTANCE)
 __as1(LDR  R2, =intvect_CoreExceptions)

# else
/* init core should be configured, but no 1st execution instance! -> BrsMainExceptionStartup. */
 BRS_BRANCH(get_exception_table_location_error)
# endif /*BRS_FIRST_EXECUTION_INSTANCE*/

BRS_LABEL(get_exception_table_location_end)
#endif /*else BRSHW_ARMCOMMON_COREEXCEPTIONS_AT_ADDRESS_0*/

/* Copy backup exception vectors over exception vectors at address "intvect_CoreExceptions"
   See ARMv7_Cortex-R_BRS_Exception_Handling.pdf for details of the mechanism!
   R2 = destination address / R3 = source address / R6 = index / R4,R5 = data buffer
*/
 __as1(MOV  R3, R2)
 __as1(MOV  R7, R2) /* save Exception Table address in R7 */

/* Use R6 as count register in the loop. Initialize with zero. */
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R6, 0)
 __as2(ADD  R2, R2, 32)
 __as2(ADD  R3, R3, 64)
#else
 __as1(MOV  R6, #0)
 __as2(ADD  R2, R2, #32)
 __as2(ADD  R3, R3, #64)
#endif

BRS_LABEL(copy_exception_vectors_backup_to_active_start)

 __as3(LDRD  R4, R5, [R3], #+8)
 __as3(STRD  R4, R5, [R2], #+8)

/* Increase count register by one. */
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R6, R6, 1)
#else
 __as2(ADD  R6, R6, #1)
#endif

#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 BRS_BRANCH_EQUAL(R6, 4, copy_exception_vectors_backup_to_active_end)
#else
 BRS_BRANCH_EQUAL(R6, #4, copy_exception_vectors_backup_to_active_end)
#endif

 BRS_BRANCH(copy_exception_vectors_backup_to_active_start)

BRS_LABEL(copy_exception_vectors_backup_to_active_end)

/* Set Exception Table code for all 8 Exceptions to the default "LDR PC, [PC,0x18]" 
   using R7 = Exception Table address.
   Use R6 as count register in the loop. Initialize with zero. 
*/
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R6, 0)
 __as1(MOVW R2, 0xF018)
 __as1(MOVT R2, 0xE59F)
#else
 __as1(MOV  R6, #0)
 __as1(MOVW R2, #0xF018)
 __as1(MOVT R2, #0xE59F)
#endif

BRS_LABEL(restore_exception_table_start)

 __as2(STR  R2, [R7], #+4)
 
/* Increase count register by one. */
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R6, R6, 1)
#else
 __as2(ADD  R6, R6, #1)
#endif

#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 BRS_BRANCH_EQUAL(R6, 8, restore_exception_table_end)
#else
 BRS_BRANCH_EQUAL(R6, #8, restore_exception_table_end)
#endif

 BRS_BRANCH(restore_exception_table_start)

BRS_LABEL(restore_exception_table_end)

/* The exception table is implemented for ARM instrcutions -> The exception must be entered in ARM state
 * -> Set SCTLR.TE bit for ARM state
 */
 __as5(MRC p15, #0, r0, c1, c0, #0) /* read SCTLR register */
 __as2(BIC r0, r0, #(1 << 30))      /* clear the TE bit to enter Exc in ARM mode */
 __as5(MCR p15, #0, r0, c1, c0, #0) /* write SCTLR register */
 
 /* Assure V-Bit is cleard and low exception vectors at 0x00000000 were set
  * -> Set SCTLR.V bit for low exception base
  */
 __as5(MRC  p15, #0x00, r0, c1, c0, #0x0)  /* Read SCTLR (System Control Register)*/
 __as2(BIC r0, r0, #(1 << 13))             /* clear the V-bit */
 __as5(MCR  p15, #0x00, r0, c1, c0, #0x0)  /* Write SCTLR (System Control Register) */

 BRS_BRANCH(brsStartupInvalidateCache)

BRS_LABEL(get_exception_table_location_error)

BRS_MULTILINE_ASM_END()

/* Branch to BrsMainExceptionStartup if no Exception Table address can be found. */
 BRS_EXTERN_BRANCH(BrsMainExceptionStartup)
BRS_GLOBAL_END()

/* =========================================================================== */
/*                                                                             */
/* Description: Invalidate cache memory                                        */
/*                                                                             */
/* =========================================================================== */
 BRS_GLOBAL(brsStartupInvalidateCache)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(brsStartupInvalidateCache)

#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as5(MRC p15, 1, r0, c0, c0, 0) /* read cache size id */
 __as1(MOVW r3, 0x01ff)
 __as1(MOVT r3, 0x0000)
 __as3(AND r0, r3, r0, lsr #13)
 __as1(MOV r1, 0)
BRS_LABEL(way_loop)
 __as1(MOV r3, 0)
BRS_LABEL(set_loop)
 __as2(MOV r2, r1, lsl #30)
 __as3(ORR r2, r2, r3, lsl #5)
BRS_LABEL(format)
 __as5(MCR p15, 0, r2, c7, c6, 2) /* invalidate */
 ___asm(DSB)
 ___asm(ISB)
 __as2(ADD r3, r3, 1)
 BRS_BRANCH_GREATER_THAN(r0, r3, set_loop)
 __as2(ADD r1, r1, 1)
 BRS_BRANCH_NOT_EQUAL(r1, 4, way_loop)

#else
 __as5(MRC p15, #1, r0, c0, c0, #0) /* read cache size id */
 __as1(MOVW r3, #0x01ff)
 __as1(MOVT r3, #0x0000)
 __as3(AND r0, r3, r0, lsr #13)
 __as1(MOV r1, #0)
BRS_LABEL(way_loop)
 __as1(MOV r3, #0)
BRS_LABEL(set_loop)
 __as2(MOV r2, r1, lsl #30)
 __as3(ORR r2, r2, r3, lsl #5)
BRS_LABEL(format)
 __as5(MCR p15, #0, r2, c7, c6, #2) /* invalidate */
 ___asm(DSB)
 ___asm(ISB)
 __as2(ADD r3, r3, #1)
 BRS_BRANCH_GREATER_THAN(r0, r3, set_loop)
 __as2(ADD r1, r1, #1)
 BRS_BRANCH_NOT_EQUAL(r1, #4, way_loop)
#endif /*BRS_COMP_x*/

 BRS_BRANCH(brsStartupZeroInitLoop)

BRS_MULTILINE_ASM_END()
BRS_GLOBAL_END()

/* =========================================================================== */
/*                                                                             */
/* Description: Initialize memory blocks and groups with zero                  */
/*                                                                             */
/* =========================================================================== */
 BRS_GLOBAL(brsStartupZeroInitLoop)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(brsStartupZeroInitLoop)

/* Initialize memory sections blocks with zeros */
#if defined (VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_BLOCKS)
# if (VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_BLOCKS>1uL)
 __as1(LDR  R1, =vLinkGen_ZeroInit_Early_Blocks)

 BRS_READ_COREID(R0)

BRS_LABEL(startup_block_zero_init_start)
 __as1(MOV  R2, R1)

#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R1, R1, 16)
#  else
 __as2(ADD  R1, R1, #16)
#  endif

 __as1(LDR  R3, [R2])      /* vLinkGen_ZeroInit_Early_Blocks->start */
 __as2(LDR  R4, [R2, #4])  /* vLinkGen_ZeroInit_Early_Blocks->end */
 __as2(LDR  R5, [R2, #8])  /* vLinkGen_ZeroInit_Early_Blocks->core */
 __as2(LDR  R6, [R2, #12]) /* vLinkGen_ZeroInit_Early_Blocks->alignment */

/* Verify if the end of struct vLinkGen_ZeroInit_Early_Blocks is reached, by checking if start == 0, end == 0 and core == 0 */
#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R7, 0)
#  else
 __as1(MOV  R7, #0)
#  endif

 __as2(ORR  R7, R7, R3) /* Or with vLinkGen_ZeroInit_Early_Blocks->start */
 __as2(ORR  R7, R7, R4) /* Or with vLinkGen_ZeroInit_Early_Blocks->end */
 __as2(ORR  R7, R7, R5) /* Or with vLinkGen_ZeroInit_Early_Blocks->core */

#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 BRS_BRANCH_EQUAL(R7, 0, startup_block_zero_init_end) /* If start address, end address and core are equal to zero -> Finished */
#  else
 BRS_BRANCH_EQUAL(R7, #0, startup_block_zero_init_end) /* If start address, end address and core are equal to zero -> Finished */
#  endif

 BRS_BRANCH_NOT_EQUAL(R0, R5, startup_block_zero_init_start) /* If InitCore is not running -> go to the next array entry */

#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R7, 0) /* set R7 to '0', as value to write in memory later */
 __as1(MOV  R8, 0) /* set R8 to '0', as value to write in memory later */
#  else
 __as1(MOV  R7, #0) /* set R7 to '0', as value to write in memory later */
 __as1(MOV  R8, #0) /* set R8 to '0', as value to write in memory later */
#  endif

 BRS_BRANCH_EQUAL(R6, #8, startup_block_zero_init_8byte_loop_start) /* if block is 8-Byte aligned, use specific init loop */

BRS_LABEL(startup_block_zero_init_loop_start)
 BRS_BRANCH_GREATER_THAN_OR_EQUAL(R3, R4, startup_block_zero_init_start) /* if start address is same with or higher than end address-> Finished. */

 __as1(STR  R7, [R3]) /* write value of R7 ('0') to address of R3 (4-byte access); must be an aligned memory access! */

#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R3, R3, 4) /* increase address value of R3 by '4' */
#  else
 __as2(ADD  R3, R3, #4) /* increase address value of R3 by '4' */
#  endif

/* End address of this block was not yet reached. Run through the loop again */
 BRS_BRANCH(startup_block_zero_init_loop_start)

/* ================================================================ */
/* 8-Byte aligned initialization, to support 8-Byte aligned ECC RAM */
/* ================================================================ */
BRS_LABEL(startup_block_zero_init_8byte_loop_start)
 BRS_BRANCH_GREATER_THAN_OR_EQUAL(R3, R4, startup_block_zero_init_start) /* if start address is same with or higher than end address-> Finished. */

/* Address stored in R3 must be 8 Byte aligned at this point! */
 __as2(STMIA R3!, {R7, R8}) /* 8 Byte alignment store for ECC, R3 would be automatically updated after the write */

/* End address of this block was not yet reached. Run through the loop again */
 BRS_BRANCH(startup_block_zero_init_8byte_loop_start)

/* Zero-Init loop of blocks end label */
BRS_LABEL(startup_block_zero_init_end)
# endif /*VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_BLOCKS>1uL*/

#else
  #error "Mandatory define VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_BLOCKS missing within vLinkGen configuration!"
#endif /*VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_BLOCKS*/

/* Initialize memory sections groups with zeros */
#if defined (VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS)
# if (VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS>1uL)
 __as1(LDR  R1, =vLinkGen_ZeroInit_Early_Groups)

BRS_LABEL(startup_group_zero_init_start)
 __as1(MOV  R2, R1)

#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R1, R1, 16)
#  else
 __as2(ADD  R1, R1, #16)
#  endif

 __as1(LDR  R3, [R2])      /* vLinkGen_ZeroInit_Early_Groups->start */
 __as2(LDR  R4, [R2, #4])  /* vLinkGen_ZeroInit_Early_Groups->end */
 __as2(LDR  R5, [R2, #8])  /* vLinkGen_ZeroInit_Early_Groups->core */
 __as2(LDR  R6, [R2, #12]) /* vLinkGen_ZeroInit_Early_Groups->alignment */

/* Verify if the end of struct vLinkGen_ZeroInit_Early_Groups is reached, by checking if start == 0, end == 0 and core == 0 */
#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R7, 0)
#  else
 __as1(MOV  R7, #0)
#  endif

 __as2(ORR  R7, R7, R3) /* Or with vLinkGen_ZeroInit_Early_Groups->start */
 __as2(ORR  R7, R7, R4) /* Or with vLinkGen_ZeroInit_Early_Groups->end */
 __as2(ORR  R7, R7, R5) /* Or with vLinkGen_ZeroInit_Early_Groups->core */

#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 BRS_BRANCH_EQUAL(R7, 0,  startup_group_zero_init_end) /* If start address, end address and core are equal to zero -> Finished */
#  else
 BRS_BRANCH_EQUAL(R7, #0,  startup_group_zero_init_end) /* If start address, end address and core are equal to zero -> Finished */
#  endif

 BRS_BRANCH_NOT_EQUAL(R0, R5, startup_group_zero_init_start) /* If InitCore is not running -> go to the next array entry */

#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R7, 0) /* set R7 to '0', as value to write in memory later */
 __as1(MOV  R8, 0) /* set R8 to '0', as value to write in memory later */
#  else
 __as1(MOV  R7, #0) /* set R7 to '0', as value to write in memory later */
 __as1(MOV  R8, #0) /* set R8 to '0', as value to write in memory later */
#  endif

 BRS_BRANCH_EQUAL(R6, #8, startup_group_zero_init_8byte_loop_start) /* if group is 8-Byte aligned, use specific init loop */

BRS_LABEL(startup_group_zero_init_loop_start)
 BRS_BRANCH_GREATER_THAN_OR_EQUAL(R3, R4, startup_group_zero_init_start) /* if start address is same with or higher than end address-> Finished. */

 __as1(STR  R7, [R3]) /* write value of R7 ('0') to address of R3 (4-byte access); must be an aligned memory access! */

#  if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R3, R3, 4) /* increase address value of R3 by '4' */
#  else
 __as2(ADD  R3, R3, #4) /* increase address value of R3 by '4' */
#  endif

/* End address of this group was not yet reached. Run through the loop again */
 BRS_BRANCH(startup_group_zero_init_loop_start)

/* ================================================================ */
/* 8-Byte aligned initialization, to support 8-Byte aligned ECC RAM */
/* ================================================================ */
BRS_LABEL(startup_group_zero_init_8byte_loop_start)
 BRS_BRANCH_GREATER_THAN_OR_EQUAL(R3, R4, startup_group_zero_init_start) /* if start address is same with or higher than end address-> Finished. */

/* Address stored in R3 must be 8 Byte aligned at this point! */
 __as2(STMIA R3!, {R7, R8}) /* 8 Byte alignment store for ECC, R3 would be automatically updated after the write */

/* End address of this group was not yet reached. Run through the loop again */
 BRS_BRANCH(startup_group_zero_init_8byte_loop_start)

/* Zero-Init loop of groups end label */
BRS_LABEL(startup_group_zero_init_end)
# endif /*VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS>1uL*/

#else
  #error "Mandatory define VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS missing within vLinkGen configuration!"
#endif /*VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS*/

/* Jump to routine to search for valid startup stack pointer of actual running core */
 BRS_BRANCH(brsStartupStackSearch)
BRS_MULTILINE_ASM_END()
BRS_GLOBAL_END()

/* =========================================================================== */
/*                                                                             */
/* Description: Search for valid startup stack pointer of actual running core  */
/*              (vBRS is genearing the core specific configuration into the    */
/*               struct BrsMain_CoreConfig in vBrs_Lcfg.c)                     */
/*                                                                             */
/* =========================================================================== */
 BRS_GLOBAL(brsStartupStackSearch)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(brsStartupStackSearch)

 __as1(LDR  R1, =BrsMain_CoreConfig_Size)

BRS_LABEL(core_config_size_init)
 __as1(LDR  R5, [R1])   /* R5 = BrsMain_CoreConfig_Size */

 __as1(LDR  R1, =BrsMain_CoreConfig)

 BRS_READ_COREID(R0)

BRS_LABEL(core_config_init_start)

/* Use R2 as count register in the loop. Initialize with zero. */
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as1(MOV  R2, 0)
#else
 __as1(MOV  R2, #0)
#endif

BRS_LABEL(brs_coreconfig_loop)

 __as2(LDR  R4, [R1,#4])  /* BrsMain_CoreConfig->PhysicalCoreId */
/* Check if core id (R0) matches to physical core id of BrsMain_CoreConfig entry (R4). */
 BRS_BRANCH_EQUAL(R0, R4, stackPointerInit)

/* Increase count register by one. */
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R2, R2, 1)
#else
 __as2(ADD  R2, R2, #1)
#endif

/* Set R1 to point to next entry of BrsMain_CoreConfig. */
#if defined (BRS_COMP_LLVMTEXASINSTRUMENTS)
 __as2(ADD  R1, R1, 28)
#else
 __as2(ADD  R1, R1, #28)
#endif

/* Check if end of BrsMain_CoreConfig has been reached. */
 BRS_BRANCH_NOT_EQUAL(R2, R5, brs_coreconfig_loop)

BRS_MULTILINE_ASM_END()

/* Branch to BrsMainExceptionStartup if there are no more entries in the array. */
 BRS_EXTERN_BRANCH(BrsMainExceptionStartup)
BRS_GLOBAL_END()

/* =========================================================================== */
/*                                                                             */
/* Description: Initialize all core registers of actual running core with      */
/*              specific init values                                           */
/*                                                                             */
/* =========================================================================== */
 BRS_GLOBAL(stackPointerInit)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(stackPointerInit)
 __as2(LDR  R4, [R1,#8]) /* BrsMain_CoreConfig->StartupStackEndLabel */
 __as1(MOV  SP, R4)

 BRS_BRANCH(coreRegisterInit3)

BRS_MULTILINE_ASM_END()
BRS_GLOBAL_END()

/* =========================================================================== */
/*                                                                             */
/* Description: Initialize additional core registers                           */
/*                                                                             */
/* =========================================================================== */
 BRS_GLOBAL(coreRegisterInit3)
BRS_MULTILINE_ASM_BEGIN()
BRS_LABEL(coreRegisterInit3)
BRS_MULTILINE_ASM_END()

/* =========================================================================== */
/*                                                                             */
/* Description: Jump to Brs_PreMainStartup() (BrsMainStartup.c)                */
/*                                                                             */
/* =========================================================================== */
 BRS_EXTERN_BRANCH(Brs_PreMainStartup)

/* =========================================================================== */
/*                                                                             */
/* Description: Jump to BrsMainExceptionStartup() in case of an unexpected     */
/*              return from PreMain/main                                       */
/*                                                                             */
/* =========================================================================== */
 BRS_EXTERN_BRANCH(BrsMainExceptionStartup)

BRS_GLOBAL_END()


#endif /*BRS_FIRST_EXECUTION_INSTANCE*/
