#include "ptypes_tms570.h"

/***************************************************************************
 *
 * C O M P I L E R   S E T T I N G S
 *
 **************************************************************************/
/* main function -> has NOT the format "int main(int argc, char* argv[])" */
#pragma diag_suppress = 2085
#pragma diag_suppress = 2086

/* linking interrupt vector reset to entry point */
#pragma INTERRUPT(_c_int00, RESET)

/**************************************************************************
 *
 * D E F I N I T I O N S
 *
 **************************************************************************/
/* fill pattern for stacks and heap */
#define SYS_HEAP_PATTERN        (0xAAAAAAAAU)
#define SYS_STACK_PATTERN       (0xAAAAAAAAU)

/* gap in stacks, which will be not filled */
#define SYS_STACK_GAP_SUPER     (0x40)
#define SYS_STACK_GAP_UND       (0x10)
#define SYS_STACK_GAP_ABORT     (0x10)
#define SYS_STACK_GAP_IRQ       (0x10)
#define SYS_STACK_GAP_FIQ       (0x10)
#define SYS_STACK_GAP_USER      (0x10)

/* definitions for RAM size and location */
#define SYS_RAM_START           ((volatile ubyte4 *)(0x08000000))
#define SYS_RAM_SIZE            ((0x40000)/sizeof(ubyte4))

/**************************************************************************
 *
 * E X T E R N A L S
 *
 **************************************************************************/

/* external symbols (coming from the linker) */
extern ubyte4 _StackSUPER_;     /* start of supervisor stack */
extern ubyte4 _StackSUPER_END_; /* end of supervisor stack   */
extern ubyte4 _StackUND_;       /* start of undefined stack  */
extern ubyte4 _StackUND_END_;   /* end of undefined stack    */
extern ubyte4 _StackABORT_;     /* start of abort stack      */
extern ubyte4 _StackABORT_END_; /* end of abort stack        */
extern ubyte4 _StackIRQ_;       /* start of IRQ stack        */
extern ubyte4 _StackIRQ_END_;   /* end of IRQ stack          */
extern ubyte4 _StackFIQ_;       /* start of FIQ stack        */
extern ubyte4 _StackFIQ_END_;   /* end of FIQ stack          */
extern ubyte4 _StackUSER_;      /* start of user stack       */
extern ubyte4 _StackUSER_END_;  /* end of user stack         */
extern ubyte4 _sys_memory;      /* start of heap             */
extern ubyte4 __SYSMEM_SIZE;    /* end of heap               */

/* compiler integrated function for variable initialization */
extern void __TI_auto_init(void);

/* main function */
extern void main(void);

/**************************************************************************
 *
 * I N T E R N A L   F U N C T I O N S
 *
 **************************************************************************/

static void stack_init(void);
static void heap_init(void);
static void mem_init(void);

/**************************************************************************
 *
 * !!! E N T R Y   P O I N T !!!
 *
 **************************************************************************/
/* [QAC]: Msg(2:1503) The function '_c_int00' is defined but is not used within this project.
 *        Msg(7:0602) [U] The identifier '_c_int00' is reserved for use by the library.
 *                    REFERENCE - ISO:C90-7.1.3 Reserved Identifiers
 *        Msg(2:3408) '_c_int00' has external linkage and is being defined without any previous
 *        declaration.
 *
 * Justification:
 *   From ARM Optimizing C/C++ Compiler v5.1 (SPNU151I):
 *   | You must link all C/C++ programs with code to initialize and execute the
 *   | program called a bootstrap routine. The symbol _c_int00 is defined as the
 *   | program entry point; it identifies the beginning of the C/C++ boot routine
 *   | in boot.obj.
 */
void _c_int00 (void) /* PRQA S 1503 */ /* PRQA S 0602 */ /* PRQA S 3408 */
{
    /* fill stack with 0xAA pattern */
    stack_init();

    /* fill heap with 0xAA pattern */
    heap_init();

    /* automatic c variables initialization with shared memory save/restore */
    mem_init();

    /* call the application (should never return) */
    main();

    /* stop here */
    /* [QAC]: Msg(5:2870) Infinite loop construct with constant control expression.
     *        Msg(5:2740) This loop controlling expression is a constant expression and its value
     *        is 'true'.
     *
     * Justification:
     * The intent here is to create an infinite loop from which the microcontroller will not
     * escape. This is because the main() function of the application finished (which it usually
     * should not in an embedded application). As we don't have any other program code to run, it
     * is safest to do nothing by staying in an infinite loop. The TPS65381 safety companion will
     * ensure turning off all high-power outputs when its watchdog is not kicked anymore by the
     * microcontroller.
     */
    while(1) /* PRQA S 2870 */ /* PRQA S 2740 */
    {
        ;
    }
}

/**************************************************************************
 *
 * F U N C T I O N S
 *
 **************************************************************************/
static void stack_init(void)
{
    volatile ubyte4 * addr_start;
    volatile ubyte4 * addr_end;

    /* get supervisor stack area */
    addr_start = (volatile ubyte4 *)(_symval(&_StackSUPER_) - SYS_STACK_GAP_SUPER);
    addr_start--;
    addr_end = (volatile ubyte4 *)_symval(&_StackSUPER_END_);

    /* fill stack area with pattern */
    while (addr_start >= addr_end)
    {
        *addr_start-- = SYS_STACK_PATTERN;
    }

    /* get undefined stack area */
    addr_start = (volatile ubyte4 *)(_symval(&_StackUND_) - SYS_STACK_GAP_UND);
    addr_start--;
    addr_end = (volatile ubyte4 *)_symval(&_StackUND_END_);

    /* fill stack area with pattern */
    while (addr_start >= addr_end)
    {
        *addr_start-- = SYS_STACK_PATTERN;
    }

    /* get abort stack area */
    addr_start = (volatile ubyte4 *)(_symval(&_StackABORT_) - SYS_STACK_GAP_ABORT);
    addr_start--;
    addr_end = (volatile ubyte4 *)_symval(&_StackABORT_END_);

    /* fill stack area with pattern */
    while (addr_start >= addr_end)
    {
        *addr_start-- = SYS_STACK_PATTERN;
    }

    /* get IRQ stack area */
    addr_start = (volatile ubyte4 *)(_symval(&_StackIRQ_) - SYS_STACK_GAP_IRQ);
    addr_start--;
    addr_end = (volatile ubyte4 *)_symval(&_StackIRQ_END_);

    /* fill stack area with pattern */
    while (addr_start >= addr_end)
    {
        *addr_start-- = SYS_STACK_PATTERN;
    }

    /* get FIQ stack area */
    addr_start = (volatile ubyte4 *)(_symval(&_StackFIQ_) - SYS_STACK_GAP_FIQ);
    addr_start--;
    addr_end = (volatile ubyte4 *)_symval(&_StackFIQ_END_);

    /* fill stack area with pattern */
    while (addr_start >= addr_end)
    {
        *addr_start-- = SYS_STACK_PATTERN;
    }

    /* get user stack area */
    addr_start = (volatile ubyte4 *)(_symval(&_StackUSER_) - SYS_STACK_GAP_USER);
    addr_start--;
    addr_end = (volatile ubyte4 *)_symval(&_StackUSER_END_);

    /* fill stack area with pattern */
    while (addr_start >= addr_end)
    {
        *addr_start-- = SYS_STACK_PATTERN;
    }
}

static void heap_init(void)
{
    volatile ubyte4 * addr_start;
    volatile ubyte4 * addr_end;

    /* get heap area */
    addr_start = (volatile ubyte4 *)(_symval(&_sys_memory) + _symval(&__SYSMEM_SIZE));
    addr_start--;
    addr_end = (volatile ubyte4 *)_symval(&_sys_memory);

    /* fill heap area with pattern */
    while (addr_start >= addr_end)
    {
        *addr_start-- = SYS_HEAP_PATTERN;
    }
}

static void mem_init(void)
{
    /* initialize C variables */
    __TI_auto_init();
}

void custom_dabort(ubyte4 fault_address)
{
    (void)fault_address;
    
    while (1)
    {
        ;
    }
}

void custom_pabort(ubyte4 fault_address)
{
    (void)fault_address;
    
    while (1)
    {
        ;
    }
}

void custom_undef(void)
{
    while (1)
    {
        ;
    }
}

void vim_parity_error(void)
{
    while (1)
    {
        ;
    }
}
