%%{
    let options = args.options;

    let stackSize = 16*1024;
    let heapSize =  32*1024;
    /* with nested interrupts logic added, IRQ stack is only used minimally, instead
     * SVC stack is used, hence IRQ stack size is less as compared to SVC stack
     */
    let irqStackSize = 256;
    let svcStackSize = 4*1024;
    let fiqStackSize = 256;
    let abortStackSize = 256;
    let undefinedStackSize = 256;
    let codeDataAddr = 0;
    let codeDataSize = 0;
    let nocacheDataSize = 0;
    let codeDataAddrDdr = 0;
    let codeDataSizeDdr = 0;
    let codeDataAddrFlash = 0;
    let codeDataSizeFlash = 0;
    let nocacheDataAddr = 0;
    let useDdr = false;
    let useFlash = false;
    let addrBase = 0;
    let addrBaseDdr = 0;
    let addrBaseFlash = 0;
    let nocacheAddrBase = 0;
    let isSingleCore = false;
    /* Temp change till we support DDR - alloc all memory to single core
     * as we don't plan to run code coverage for system project */
    if(args.isInstrumentation)
    {
        isSingleCore = true;
    }
    let isIcssPktBufEnable = false;

    if(options && options.isXip)
    {
        useFlash = true;
    }

    /* if no options given use defaults */
    if(options && options.stackSize)
        stackSize = options.stackSize;
    if(options && options.heapSize)
        heapSize = options.heapSize;
    if(options && options.irqStackSize)
        irqStackSize = options.irqStackSize;
    if(options && options.fiqStackSize)
        fiqStackSize = options.fiqStackSize;
    if(options && options.svcStackSize)
        svcStackSize = options.svcStackSize;
    if(options && options.abortStackSize)
        abortStackSize = options.abortStackSize;
    if(options && options.undefinedStackSize)
        undefinedStackSize = options.undefinedStackSize;
    if(options && options.isSingleCore)
        isSingleCore = options.isSingleCore;
    if(options && options.isIcssPktBufEnable)
        isIcssPktBufEnable = options.isIcssPktBufEnable;

    if(isSingleCore === true) {
        codeDataSize = 0x40000 * 4;
        codeDataSizeFlash = 0x80000;
        codeDataSizeDdr = 0x1000000 * 4;
        nocacheDataSize = 0x8000;
    }
    else {
        codeDataSize = 0x40000;
        codeDataSizeFlash = 0x80000;
        codeDataSizeDdr = 0x1000000;
        nocacheDataSize = 0x8000;
    }

    /* offset from  top of codeDataAddrDdr where the code/data is actually placed,
       the first codeDataOffsetDdr bytes are used for IPC in linux
     */
    codeDataOffsetDdr = 0x100000;

    if(args.project.isLinuxInSystem === true) {
        addrBase = 0x70080000;
        addrBaseDdr = 0xA0000000;
        addrBaseFlash = 0x60100000;
        useDdr = true;
    } else {
        addrBase = 0x70080000;
        addrBaseFlash = 0x60100000;
        nocacheAddrBase = 0x70060000;
    }
    if(isSingleCore === true) {
        codeDataAddr    = addrBase;
        codeDataAddrDdr = addrBaseDdr;
        codeDataAddrFlash = addrBaseFlash;
        nocacheDataAddr = nocacheAddrBase;
    }
    else {
        if(args.project.cpu == "r5fss0-0") {
            codeDataAddr    = addrBase + codeDataSize*0;
            codeDataAddrDdr = addrBaseDdr + codeDataSizeDdr*0;
            codeDataAddrFlash = addrBaseFlash + codeDataSizeFlash*0;
            nocacheDataAddr = nocacheAddrBase + nocacheDataSize*0;
        }
        if(args.project.cpu == "r5fss0-1") {
            codeDataAddr    = addrBase + codeDataSize*1;
            codeDataAddrDdr = addrBaseDdr + codeDataSizeDdr*1;
            codeDataAddrFlash = addrBaseFlash + codeDataSizeFlash*1;
            nocacheDataAddr = nocacheAddrBase + nocacheDataSize*1;
        }
        if(args.project.cpu == "r5fss1-0") {
            codeDataAddr    = addrBase + codeDataSize*2;
            codeDataAddrDdr = addrBaseDdr + codeDataSizeDdr*2;
            codeDataAddrFlash = addrBaseFlash + codeDataSizeFlash*2;
            nocacheDataAddr = nocacheAddrBase + nocacheDataSize*2;
        }
        if(args.project.cpu == "r5fss1-1") {
            codeDataAddr    = addrBase + codeDataSize*3;
            codeDataAddrDdr = addrBaseDdr + codeDataSizeDdr*3;
            codeDataAddrFlash = addrBaseFlash + codeDataSizeFlash*3;
            nocacheDataAddr = nocacheAddrBase + nocacheDataSize*3;
        }
    }
    if(options && options.codeDataAddr)
        codeDataAddr = options.codeDataAddr;
    if(options && options.codeDataSize)
        codeDataSize = options.codeDataSize;
    if(options && options.codeDataAddrFlash)
        codeDataAddrFlash = options.codeDataAddrFlash;
    if(options && options.codeDataSizeFlash)
        codeDataSizeFlash = options.codeDataSizeFlash;
%%}

/* This is the stack that is used by code running within main()
 * In case of NORTOS,
 * - This means all the code outside of ISR uses this stack
 * In case of FreeRTOS
 * - This means all the code until vTaskStartScheduler() is called in main()
 *   uses this stack.
 * - After vTaskStartScheduler() each task created in FreeRTOS has its own stack
 */
__TI_STACK_SIZE = 16384;
/* This is the heap size for malloc() API in NORTOS and FreeRTOS
 * This is also the heap used by pvPortMalloc in FreeRTOS
 */
__TI_HEAP_SIZE = 32768;
ENTRY(_vectors)  /* This is the entry of the application, _vector MUST be plabed starting address 0x0 */

/* This is the size of stack when R5 is in IRQ mode
 * In NORTOS,
 * - Here interrupt nesting is disabled as of now
 * - This is the stack used by ISRs registered as type IRQ
 * In FreeRTOS,
 * - Here interrupt nesting is enabled
 * - This is stack that is used initally when a IRQ is received
 * - But then the mode is switched to SVC mode and SVC stack is used for all user ISR callbacks
 * - Hence in FreeRTOS, IRQ stack size is less and SVC stack size is more
 */
__IRQ_STACK_SIZE = `irqStackSize`;
/* This is the size of stack when R5 is in IRQ mode
 * - In both NORTOS and FreeRTOS nesting is disabled for FIQ
 */
__FIQ_STACK_SIZE = `fiqStackSize`;
__SVC_STACK_SIZE = `svcStackSize`; /* This is the size of stack when R5 is in SVC mode */
__ABORT_STACK_SIZE = `abortStackSize`;  /* This is the size of stack when R5 is in ABORT mode */
__UNDEFINED_STACK_SIZE = `undefinedStackSize`;  /* This is the size of stack when R5 is in UNDEF mode */

/*
NOTE: Below memory is reserved for DMSC usage
 - During Boot till security handoff is complete
   0x701E0000 - 0x701FFFFF (128KB)
 - After "Security Handoff" is complete (i.e at run time)
   0x701F4000 - 0x701FFFFF (48KB)

 Security handoff is complete when this message is sent to the DMSC,
   TISCI_MSG_SEC_HANDOVER

 This should be sent once all cores are loaded and all application
 specific firewall calls are setup.
*/
MEMORY
{
    R5F_VECS  : ORIGIN = 0x00000000 , LENGTH = 0x00000040
    R5F_TCMA  : ORIGIN = 0x00000040 , LENGTH = 0x00007FC0
    R5F_TCMB0 : ORIGIN = 0x41010000 , LENGTH = 0x00008000

    % if (isIcssPktBufEnable) {
    /* shared memories that is used between ICCS and this core. MARK as non-cache or cache+sharable */
    ICSS_PKT_BUF_MEM        : ORIGIN = 0x70000000, LENGTH = 0x00010000

    % }
    % if ( ! args.project.isLinuxInSystem) { /* This is not used when Linux is there */
    /* memory segment used to hold CPU specific non-cached data, MAKE to add a MPU entry to mark this as non-cached */
    NON_CACHE_MEM : ORIGIN = 0x`nocacheDataAddr.toString(16).toUpperCase()` , LENGTH = 0x`nocacheDataSize.toString(16).toUpperCase()`

    % }
    /* when using multi-core application's i.e more than one R5F/M4F active, make sure
     * this memory does not overlap with other R5F's
     */
    MSRAM     : ORIGIN = 0x`codeDataAddr.toString(16).toUpperCase()` , LENGTH = 0x`codeDataSize.toString(16).toUpperCase()`

    /* This section can be used to put XIP section of the application in flash, make sure this does not overlap with
     * other CPUs. Also make sure to add a MPU entry for this section and mark it as cached and code executable
     */
    FLASH     : ORIGIN = 0x`codeDataAddrFlash.toString(16).toUpperCase()` , LENGTH = 0x`codeDataSizeFlash.toString(16).toUpperCase()`

    % if(useDdr) {
    /* when using multi-core application's i.e more than one R5F/M4F active, make sure
     * this memory does not overlap with other R5F's
     */
    DDR       : ORIGIN = 0x`(codeDataAddrDdr+codeDataOffsetDdr).toString(16).toUpperCase()` , LENGTH = 0x`(codeDataSizeDdr - codeDataOffsetDdr).toString(16).toUpperCase()`

    % }
    /* shared memory segments */
    /* On R5F,
     * - make sure there is a MPU entry which maps below regions as non-cache
     */
    USER_SHM_MEM            : ORIGIN = 0x701D0000, LENGTH = 0x80
    LOG_SHM_MEM             : ORIGIN = 0x701D0000 + 0x80, LENGTH = 0x00004000 - 0x80
    RTOS_NORTOS_IPC_SHM_MEM : ORIGIN = 0x701D4000, LENGTH = 0x0000C000
    % if(args.project.isLinuxInSystem) {
    LINUX_IPC_SHM_MEM       : ORIGIN = 0x`codeDataAddrDdr.toString(16).toUpperCase()` , LENGTH = 0x`codeDataOffsetDdr.toString(16).toUpperCase()`
    % }
}

SECTIONS
{
    /* This has the R5F entry point and vector table, this MUST be at 0x0 */
    .vectors : ALIGN (8) {}  > R5F_VECS

    /* This has the R5F boot code until MPU is enabled,  this MUST be at a address < 0x80000000
     * i.e this cannot be placed in DDR
     */
    .text.hwi   : ALIGN (8) {} > MSRAM
    .text.cache : ALIGN (8) {} > MSRAM
    .text.mpu   : ALIGN (8) {} > MSRAM
    .text.boot  : ALIGN (8) {} > MSRAM
    .text:abort : ALIGN (8) {} > MSRAM  /* this helps in loading symbols when using XIP mode */

    /* This is rest of code. This can be placed in DDR if DDR is available and needed */
    % if(useDdr) {
    .text       : ALIGN (8) {} > DDR    /* This is where code resides */
    .rodata     : ALIGN (8) {} > DDR    /* This is where const's go */
    % } else if(useFlash) {
    .text       : ALIGN (8) {} > FLASH  /* This is where code resides */
    .rodata     : ALIGN (8) {} > FLASH  /* This is where const's go */
    % } else {
    .text       : ALIGN (8) {} > MSRAM  /* This is where code resides */
    .rodata     : ALIGN (8) {} > MSRAM  /* This is where const's go */
    % }

    /* This is rest of initialized data. This can be placed in DDR if DDR is available and needed */
    % if(useDdr) {
    /* This is the resource table used by linux to know where the IPC "VRINGs" are located */
    .resource_table : ALIGN (4096) {} > DDR
    .data           : ALIGN (8)    {} > DDR     /* This is where initialized globals and static go */
    % } else {
    .data           : ALIGN (8)    {} > MSRAM   /* This is where initialized globals and static go */
    % }

    /* This is rest of uninitialized data. This can be placed in DDR if DDR is available and needed */
    % if(useDdr) {
    .bss : {
        __bss_start__ = .;
        __BSS_START = .;
        *(.bss)
        *(.bss.*)
        . = ALIGN (8);
        __BSS_END = .;
        __bss_end__ = .;
        . = ALIGN (8);
    } > DDR
    % } else {
    .bss : {
        __bss_start__ = .;
        __BSS_START = .;
        *(.bss)
        *(.bss.*)
        . = ALIGN (8);
        __BSS_END = .;
        __bss_end__ = .;
        . = ALIGN (8);
    } > MSRAM
    % }

    /* This is where the stacks for different R5F modes go */
    % if(useDdr) {
    .irqstack : ALIGN(16) {
        __IRQ_STACK_START = .;
        . = . + __IRQ_STACK_SIZE;
        __IRQ_STACK_END = .;
        . = ALIGN (8);
    } > DDR
    .fiqstack : ALIGN(16) {
        __FIQ_STACK_START = .;
        . = . + __FIQ_STACK_SIZE;
        __FIQ_STACK_END = .;
    } > DDR
    .svcstack : ALIGN(16) {
        __SVC_STACK_START = .;
        . = . + __SVC_STACK_SIZE;
        __SVC_STACK_END = .;
    } > DDR
    .abortstack : ALIGN(16) {
        __ABORT_STACK_START = .;
        . = . + __ABORT_STACK_SIZE;
        __ABORT_STACK_END = .;
    } > DDR
    .undefinedstack : ALIGN(16) {
        __UNDEFINED_STACK_START = .;
        . = . + __UNDEFINED_STACK_SIZE;
        __UNDEFINED_STACK_END = .;
    } > DDR

    .heap (NOLOAD) : {
        end = .;
        KEEP(*(.heap))
        . = . + __TI_HEAP_SIZE;
    } > DDR

    .stack (NOLOAD) : ALIGN(16) {
        __TI_STACK_BASE = .;
        KEEP(*(.stack))
        . = . + __TI_STACK_SIZE;
        __STACK_END = .;
    } > DDR
    % } else {
    .irqstack : ALIGN(16) {
        __IRQ_STACK_START = .;
        . = . + __IRQ_STACK_SIZE;
        __IRQ_STACK_END = .;
        . = ALIGN (8);
    } > MSRAM
    .fiqstack : ALIGN(16) {
        __FIQ_STACK_START = .;
        . = . + __FIQ_STACK_SIZE;
        __FIQ_STACK_END = .;
    } > MSRAM
    .svcstack : ALIGN(16) {
        __SVC_STACK_START = .;
        . = . + __SVC_STACK_SIZE;
        __SVC_STACK_END = .;
    } > MSRAM
    .abortstack : ALIGN(16) {
        __ABORT_STACK_START = .;
        . = . + __ABORT_STACK_SIZE;
        __ABORT_STACK_END = .;
    } > MSRAM
    .undefinedstack : ALIGN(16) {
        __UNDEFINED_STACK_START = .;
        . = . + __UNDEFINED_STACK_SIZE;
        __UNDEFINED_STACK_END = .;
    } > MSRAM

    .heap (NOLOAD) : {
        end = .;
        KEEP(*(.heap))
        . = . + __TI_HEAP_SIZE;
    } > MSRAM

    .stack (NOLOAD) : ALIGN(16) {
        __TI_STACK_BASE = .;
        KEEP(*(.stack))
        . = . + __TI_STACK_SIZE;
        __STACK_END = .;
    } > MSRAM
    % }

    /* Sections needed for C++ projects */
    % if(useDdr) {
    .ARM.exidx  : ALIGN (8) {} > DDR    /* Needed for C++ exception handling */
    .init_array : ALIGN (8) {} > DDR    /* Contains function pointers called before main */
    .fini_array : ALIGN (8) {} > DDR    /* Contains function pointers called after main */
    % } else if(useFlash) {
    .ARM.exidx  : ALIGN (8) {} > FLASH  /* Needed for C++ exception handling */
    .init_array : ALIGN (8) {} > FLASH  /* Contains function pointers called before main */
    .fini_array : ALIGN (8) {} > FLASH  /* Contains function pointers called after main */
    % } else {
    .ARM.exidx  : ALIGN (8) {} > MSRAM  /* Needed for C++ exception handling */
    .init_array : ALIGN (8) {} > MSRAM  /* Contains function pointers called before main */
    .fini_array : ALIGN (8) {} > MSRAM  /* Contains function pointers called after main */
    % }

    % if (isIcssPktBufEnable) {
    /* Packet buffer memory used by ICCS */
    .bss.icss_emac_pktbuf_mem (NOLOAD) : { KEEP(*(.bss.icss_emac_pktbuf_mem)) } > ICSS_PKT_BUF_MEM
    % }
    /* General purpose user shared memory, used in some examples */
    .bss.user_shared_mem (NOLOAD) : { KEEP(*(.bss.user_shared_mem)) } > USER_SHM_MEM
    /* this is used when Debug log's to shared memory are enabled, else this is not used */
    .bss.log_shared_mem  (NOLOAD) : { KEEP(*(.bss.log_shared_mem)) } > LOG_SHM_MEM
    /* this is used only when IPC RPMessage is enabled, else this is not used */
    .bss.ipc_vring_mem   (NOLOAD) : { KEEP(*(.bss.ipc_vring_mem)) } > RTOS_NORTOS_IPC_SHM_MEM
    % if ( ! args.project.isLinuxInSystem) { /* This is not used when Linux is there */
    /* General purpose non cacheable memory, used in some examples */
    .bss.nocache   (NOLOAD) : { KEEP(*(.bss.nocache)) } > NON_CACHE_MEM
    % }
}
