This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/PROCESSOR-SDK-AM335X: Have BIOS heap use the maximum amount of memory available

Part Number: PROCESSOR-SDK-AM335X

Tool/software: Code Composer Studio

Hello

It seems that the recommended way of specifying the BIOS system heap requires us to hard-code the location and size:

var textAndBss = 25 * 1024 * 1024;
var totalRam = 0x20000000;
BIOS.heapSize = totalRam - textAndBss;

var heapSection = new Program.SectionSpec();
heapSection.loadAddress = 0x80000000 + totalRam - BIOS.heapSize;
heapSection.runAddress = heapSection.loadAddress;
heapSection.type = "NOLOAD";
Program.sectMap[".system.heap"] = heapSection;
BIOS.heapSection = ".system.heap"

Obviously this is not good because we would either have to waste a lot of memory by assuming an overly large value for size of text+bss, or we are forced to manually update the hard-coded values every time we compile.  Is there a way to let the linker figure out the best placement of the heap for maximum memory utilization?

  • Hi,

    I don't think the sectionSpec loadAddress needs to be used.

    Please see <XDCTools>/docs/docs/cdoc/xdc/cfg/Program.html, config Program.sectMap // module-wide:

    Suppose for example that the platform defines a memory segment named "DDR2". The following configuration statement places everything from the ".text" section into the "DDR2" segment.
    Program.sectMap[".text"] = new Program.SectionSpec();
    Program.sectMap[".text"].loadSegment = "DDR2";

    In this case the linker determines the location.

    I've looped in a colleague to comment more if required.

    Regards,
    Frank

  • I have tried this already but this has 2 problems.

    1) You still have to specify the heap size.

    2) The bin file becomes huge (512MB, or the entire size of RAM) due to the lack of control that we have over the ordering of the sections from the cfg file.  

  • HI,

    You're saying the size of the bin file depends on the size & location of the heap? If that's the case, then I suspect an issue with 0's being included in the image as initializes for the heap memory.

    Regards,
    Frank

  • Absolutely.  If the heap is placed in between two sections with code or data then objcopy will grow the bin file to accommodate it.

  • I don't think the bin file should increase because the heap increases since the heap is RAM. A bin file should only include initialized data.

    I assume you're using the GCC compiler. Have you tried using Program.sectionsExclude? For example:

    // Remove section to exclude 0's for heap initialization from ARM image.
    // Must have corresponding NOLOAD specifier for this section in linker command file.
    Program.sectionsExclude = "^\.myHeap";

    Regards,
    Frank

  • I tried removing the runAddress/loadAddress and adding the ".system.heap" section the Program.sectionsExclude but objcopy still creates a huge bin file (491MB).  

    Here is the resulting linker.cmd file:

    /*
     * This file was generated by linkcmd_bm_v7a.xdt from the gnu.target.arm  package.
     */
    
    ENTRY(_c_int00)
    
    __TI_STACK_SIZE = 0x1000;
    __STACK_SIZE = __TI_STACK_SIZE;
    
    __HEAP_SIZE = 0x0;
    
    INPUT(
        "/home/clarkson/projects/er-301/bin/firmware/sysbios/package/cfg/release_pa8fg.oa8fg"
        "/home/clarkson/projects/er-301/bin/firmware/sysbios/package/cfg/release_pa8fg.src/sysbios/sysbios.aa8fg"
        "/home/clarkson/ti-old/bios_6_46_05_55/packages/gnu/targets/arm/rtsv7A/lib/gnu.targets.arm.rtsv7A.aa8fg"
        "/home/clarkson/ti-old/bios_6_46_05_55/packages/gnu/targets/arm/rtsv7A/lib/boot.aa8fg"
        "/home/clarkson/ti-old/bios_6_46_05_55/packages/gnu/targets/arm/rtsv7A/lib/syscalls.aa8fg"
    )
    
    MEMORY
    {
        SRAM (RWX) : org = 0x402f0400, len = 0x1fbff
        DDR3 (RWX) : org = 0x80000000, len = 0x20000000
    }
    
    /*
     * In order to put the .bass, .text, .data, .heap or .stack into a
     * different memory section, change the corresponding REGION_ALIAS.
     */
    REGION_ALIAS("REGION_BSS", DDR3);
    REGION_ALIAS("REGION_TEXT", DDR3);
    REGION_ALIAS("REGION_DATA", DDR3);
    REGION_ALIAS("REGION_STACK", DDR3);
    REGION_ALIAS("REGION_HEAP", DDR3);
    REGION_ALIAS("REGION_ARM_EXTAB", DDR3);
    REGION_ALIAS("REGION_ARM_EXIDX", DDR3);
    
    /*
     * symbolic aliases for static instance objects
     */
    xdc_runtime_Startup__EXECFXN__C = 1;
    xdc_runtime_Startup__RESETFXN__C = 1;
    
    /*
     * Linker command file contributions from all loaded packages:
     */
    
    /* Content from ti.sysbios.family.arm (ti/sysbios/family/arm/linkcmd.xdt): */
    
    /* Content from ti.sysbios.rts (ti/sysbios/rts/linkcmd.xdt): */
    
    /* Content from ti.sysbios.family.arm.a8.intcps (ti/sysbios/family/arm/a8/intcps/linkcmd.xdt): */
    ti_sysbios_family_arm_a8_intcps_Hwi_intc = 0x48200000;
    
    
    SECTIONS {
    
            .c_int00 0x80000000 : {*(.c_int00)} 
        .vecs : {*(.vecs)}  AT> DDR3
        ti.sysbios.family.arm.a8.mmuTableSection (NOLOAD) : {*(ti.sysbios.family.arm.a8.mmuTableSection)}  AT> DDR3
        xdc.meta (COPY) : {KEEP(*(xdc.meta))}  AT> DDR3
    
    
        .c_int00 : {
            KEEP (*(.c_int00))
        } > REGION_TEXT
    
        .text : {
            CREATE_OBJECT_SYMBOLS
            KEEP (*(.resetVecs))
            KEEP (*(.text))
            *(.text.*)
            *(.gnu.linkonce.t*)
            *(.gnu.warning)
            *(.glue*)
            . = ALIGN(0x4);
            KEEP (*(.ctors))
            *(.gnu.linkonce.r.*)
            . = ALIGN(0x4);
            __init_array_start = .;
            KEEP(*(SORT(.init_array.*)))
            KEEP(*(.init_array))
            __init_array_end = .;
            *(.init)
            *(.fini*)
        } > REGION_TEXT
    
        .rodata : {
            *(.rodata)
            *(.rodata.*)
        } > REGION_TEXT
    
        .ARM.extab : {
            *(.ARM.extab*)
            *(.gnu.linkonce.armextab.*)
        } > REGION_ARM_EXTAB
    
        .ARM.exidx : {
            __exidx_start = .;
            *(.ARM.exidx*)
            *(.gnu.linkonce.armexidx.*)
            __exidx_end = .;
        } > REGION_ARM_EXIDX
    
        etext   = .;
        _etext  = .;
        __etext = .;
    
        .data : {
            __data_load__ = LOADADDR (.data);
            __data_start__ = .;
            *(.got.plt)
            *(.got)
            *(.shdata)
            KEEP (*(.data))
            KEEP (*(.data*))
            *(.gnu.linkonce.d.*)
            . = ALIGN (4);
            __data_end__ = .;
        } > REGION_DATA AT> REGION_TEXT
    
        /*
         * Place .heap section before .bss and .stack as the _sbrk
         * implementation in librdimon.a compares the (heap_end + incr)
         * to the current SP value to check if the heap has overlapped
         * with the stack. 
         *
         * If .heap is placed between .bss and .stack in a SYS/BIOS app,
         * when the task stack (allocated in .bss) is the current stack,
         * the heap check in _sbrk will fail and trigger an error even
         * though the heap might not have actually overlapped with the
         * system stack.
         */
        .heap : ALIGN(0x100) {
            __heap_start__ = .;
            end = __heap_start__;
            _end = end;
            __end = end;
            . += __HEAP_SIZE;
            __heap_end__ = .;
            __HeapLimit = __heap_end__;
        } > REGION_HEAP
    
        .bss : {
            __bss_start__ = .;
            *(.shbss)
            KEEP (*(.bss))
            *(.bss.*)
            *(.gnu.linkonce.b.*)
            *(COMMON)
            . = ALIGN (4);
            __bss_end__ = .;
        } > REGION_BSS
    
        .stack : ALIGN(0x0008) {
            __TI_STACK_BASE = .;
            __stack = .;
            . += __TI_STACK_SIZE;
        } > REGION_STACK
    
        .stab           0 : { *(.stab) }
        .stabstr        0 : { *(.stabstr) }
        .stab.excl      0 : { *(.stab.excl) }
        .stab.exclstr   0 : { *(.stab.exclstr) }
        .stab.index     0 : { *(.stab.index) }
        .stab.indexstr  0 : { *(.stab.indexstr) }
        .comment        0 : { *(.comment) }
    
        .debug          0 : { *(.debug) }
        .line           0 : { *(.line)  }
        .debug_srcinfo  0 : { *(.debug_srcinfo) }
        .debug_sfnames  0 : { *(.debug_sfnames) }
        .debug_aranges  0 : { *(.debug_aranges) }
        .debug_pubnames 0 : { *(.debug_pubnames) }
        .debug_info     0 : { *(.debug_info) }
        .debug_abbrev   0 : { *(.debug_abbrev) }
        .debug_line     0 : { *(.debug_line) }
        .debug_frame    0 : { *(.debug_frame) }
        .debug_str      0 : { *(.debug_str) }
        .debug_loc      0 : { *(.debug_loc) }
        .debug_macinfo  0 : { *(.debug_macinfo) }
        .debug_weaknames    0 : { *(.debug_weaknames) }
        .debug_funcnames    0 : { *(.debug_funcnames) }
        .debug_typenames    0 : { *(.debug_typenames) }
        .debug_varnames     0 : { *(.debug_varnames) }
        .debug_pubtypes     0 : { *(.debug_pubtypes) }
        .debug_ranges       0 : { *(.debug_ranges) }
    
    }
    
    /* function aliases */
    xdc_runtime_System_asprintf_va__E = xdc_runtime_System_asprintf_va__F;
    xdc_runtime_System_snprintf_va__E = xdc_runtime_System_snprintf_va__F;
    xdc_runtime_System_printf_va__E = xdc_runtime_System_printf_va__F;
    xdc_runtime_System_aprintf_va__E = xdc_runtime_System_aprintf_va__F;
    xdc_runtime_System_sprintf_va__E = xdc_runtime_System_sprintf_va__F;
    

    and here is the cfg file:

    // Configuration shared by all builds of SYS/BIOS.
    
    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    var Diags = xdc.useModule('xdc.runtime.Diags');
    var Assert = xdc.useModule('xdc.runtime.Assert');
    var Error = xdc.useModule('xdc.runtime.Error');
    var Log = xdc.useModule('xdc.runtime.Log');
    
    var Main = xdc.useModule('xdc.runtime.Main');
    var Memory = xdc.useModule('xdc.runtime.Memory')
    var SysMin = xdc.useModule('xdc.runtime.SysMin');
    var System = xdc.useModule('xdc.runtime.System');
    var Text = xdc.useModule('xdc.runtime.Text');
    
    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    var Hwi = xdc.useModule('ti.sysbios.family.arm.a8.intcps.Hwi');
    var Hwi2 = xdc.useModule('ti.sysbios.hal.Hwi');
    
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var Event = xdc.useModule('ti.sysbios.knl.Event');
    var Idle = xdc.useModule('ti.sysbios.knl.Idle');
    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
    var Cache = xdc.useModule('ti.sysbios.family.arm.a8.Cache');
    
    // var TimerProvider = xdc.useModule('ti.sysbios.timers.dmtimer.TimestampProvider');
    var TimerProvider = xdc.useModule('ti.sysbios.family.arm.a8.TimestampProvider');
    
    var HeapBuf = xdc.useModule('ti.sysbios.heaps.HeapBuf');
    var HeapMultiBuf = xdc.useModule('ti.sysbios.heaps.HeapMultiBuf');
    var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
    
    
    Task.addHookSet({
            switchFxn: "&onTaskSwitch",
    });
    
    System.extendedFormats += "%f";
    
    /*
     * Minimize exit handler array in System.  The System module includes
     * an array of functions that are registered with System_atexit() to be
     * called by System_exit().
     */
    System.maxAtexitHandlers = 4;
    
    /* 
     * Uncomment this line to disable the Error print function.
     * We lose error information when this is disabled since the errors are
     * not printed.  Disabling the raiseHook will save some code space if
     * your app is not using System_printf() since the Error_print() function
     * calls System_printf().
    Error.raiseHook = null;
     */
    
    /*
     * Uncomment this line to keep Error, Assert, and Log strings from being
     * loaded on the target.  These strings are placed in the .const section.
     * Setting this parameter to false will save space in the .const section.
     * Error, Assert and Log message will print raw ids and args instead of
     * a formatted message.
    Text.isLoaded = false;
     */
    
    /*
     * Uncomment this line to disable the output of characters by SysMin
     * when the program exits.  SysMin writes characters to a circular buffer.
     * This buffer can be viewed using the SysMin Output view in ROV.
    SysMin.flushAtExit = false;
     */
    SysMin.flushAtExit = true;
    
    // place the entry point at the beginning (buggy)
    Program.sectMap[".c_int00"] = new Program.SectionSpec();
    Program.sectMap[".c_int00"].runAddress = 0x80000000;
    
    /*
     * The BIOS module will create the default heap for the system.
     * Specify the size of this default heap.
     */
    // text + bss < 4700kB
    //var textAndBss = 5 * 1024 * 1024;
    var textAndBss = 25 * 1024 * 1024;
    var totalRam = 0x20000000;
    BIOS.heapSize = totalRam - textAndBss;
    
    var heapSection = new Program.SectionSpec();
    //heapSection.runAddress = 0x80000000 + totalRam - BIOS.heapSize;
    heapSection.type = "NOLOAD";
    Program.sectMap["system.heap"] = heapSection;
    BIOS.heapSection = "system.heap"
    // Remove section to exclude 0's for heap initialization from ARM image.
    // Must have corresponding NOLOAD specifier for this section in linker command file.
    Program.sectionsExclude = "system.heap";
    
    // use HeapTrack for the default heap
    BIOS.heapTrackEnabled = false;
    
    /* System stack size (used by ISRs and Swis) */
    Program.stack = 4 * 1024;
    
    /* Circular buffer size for System_printf() */
    SysMin.bufSize = 8 * 1024;
    
    System.SupportProxy = SysMin;
    SysMin.outputFxn = "&Uart_write";
    Error.raiseHook = "&onSystemError";
    
    BIOS.swiEnabled = true;
    BIOS.taskEnabled = true;
    
    /* Set up MMU for peripheral addresses */
    Mmu.enableMMU = true;
    
    // Force peripheral section to be NON cacheable strongly-ordered memory
    var attrs = {
            type: Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
            tex: 0,
            bufferable: false,                // bufferable
            cacheable: false,                // cacheable
            shareable: false,                // shareable
            noexecute: true,                 // not executable
    };
    
    for (var addr = 0x44000000; addr < 0x57000000; addr += 0x00100000) {
            Mmu.setFirstLevelDescMeta(addr, addr, attrs);
    }
    
    Task.checkStackFlag = false;
    Hwi2.checkStackFlag = false;
    
    Task.deleteTerminatedTasks = false;
    
    Clock.swiPriority = 10;
    // Dynamic mode seems to have more accurate timing
    // BUT! it seriously reduces the amount of CPU available before clicks/pops and completely breaks ADC at low buffer sizes.
    // Clock.tickMode = Clock.TickMode_DYNAMIC;
    
    var Load = xdc.useModule('ti.sysbios.utils.Load');
    Load.windowInMs = 1000;
    Load.taskEnabled = true;
    //Clock.timerId = 5;
    Clock.tickPeriod = 1000;
    

  • And for completeness, here is the linker file and cfg file that I normally use but has the problem where I need to hardcode the size/location of the heap but at least the generated bin file matches the size of text+bss (3.9MB in my case):

    /*
     * This file was generated by linkcmd_bm_v7a.xdt from the gnu.target.arm  package.
     */
    
    ENTRY(_c_int00)
    
    __TI_STACK_SIZE = 0x1000;
    __STACK_SIZE = __TI_STACK_SIZE;
    
    __HEAP_SIZE = 0x0;
    
    INPUT(
        "/home/clarkson/projects/er-301/bin/firmware/sysbios/package/cfg/release_pa8fg.oa8fg"
        "/home/clarkson/projects/er-301/bin/firmware/sysbios/package/cfg/release_pa8fg.src/sysbios/sysbios.aa8fg"
        "/home/clarkson/ti-old/bios_6_46_05_55/packages/gnu/targets/arm/rtsv7A/lib/gnu.targets.arm.rtsv7A.aa8fg"
        "/home/clarkson/ti-old/bios_6_46_05_55/packages/gnu/targets/arm/rtsv7A/lib/boot.aa8fg"
        "/home/clarkson/ti-old/bios_6_46_05_55/packages/gnu/targets/arm/rtsv7A/lib/syscalls.aa8fg"
    )
    
    MEMORY
    {
        SRAM (RWX) : org = 0x402f0400, len = 0x1fbff
        DDR3 (RWX) : org = 0x80000000, len = 0x20000000
    }
    
    /*
     * In order to put the .bass, .text, .data, .heap or .stack into a
     * different memory section, change the corresponding REGION_ALIAS.
     */
    REGION_ALIAS("REGION_BSS", DDR3);
    REGION_ALIAS("REGION_TEXT", DDR3);
    REGION_ALIAS("REGION_DATA", DDR3);
    REGION_ALIAS("REGION_STACK", DDR3);
    REGION_ALIAS("REGION_HEAP", DDR3);
    REGION_ALIAS("REGION_ARM_EXTAB", DDR3);
    REGION_ALIAS("REGION_ARM_EXIDX", DDR3);
    
    /*
     * symbolic aliases for static instance objects
     */
    xdc_runtime_Startup__EXECFXN__C = 1;
    xdc_runtime_Startup__RESETFXN__C = 1;
    
    /*
     * Linker command file contributions from all loaded packages:
     */
    
    /* Content from ti.sysbios.family.arm (ti/sysbios/family/arm/linkcmd.xdt): */
    
    /* Content from ti.sysbios.rts (ti/sysbios/rts/linkcmd.xdt): */
    
    /* Content from ti.sysbios.family.arm.a8.intcps (ti/sysbios/family/arm/a8/intcps/linkcmd.xdt): */
    ti_sysbios_family_arm_a8_intcps_Hwi_intc = 0x48200000;
    
    
    SECTIONS {
    
            .c_int00 0x80000000 : {*(.c_int00)} 
        system.heap 0x81900000 (NOLOAD) : {*(system.heap)} 
        .vecs : {*(.vecs)}  AT> DDR3
        ti.sysbios.family.arm.a8.mmuTableSection (NOLOAD) : {*(ti.sysbios.family.arm.a8.mmuTableSection)}  AT> DDR3
        xdc.meta (COPY) : {KEEP(*(xdc.meta))}  AT> DDR3
    
    
        .c_int00 : {
            KEEP (*(.c_int00))
        } > REGION_TEXT
    
        .text : {
            CREATE_OBJECT_SYMBOLS
            KEEP (*(.resetVecs))
            KEEP (*(.text))
            *(.text.*)
            *(.gnu.linkonce.t*)
            *(.gnu.warning)
            *(.glue*)
            . = ALIGN(0x4);
            KEEP (*(.ctors))
            *(.gnu.linkonce.r.*)
            . = ALIGN(0x4);
            __init_array_start = .;
            KEEP(*(SORT(.init_array.*)))
            KEEP(*(.init_array))
            __init_array_end = .;
            *(.init)
            *(.fini*)
        } > REGION_TEXT
    
        .rodata : {
            *(.rodata)
            *(.rodata.*)
        } > REGION_TEXT
    
        .ARM.extab : {
            *(.ARM.extab*)
            *(.gnu.linkonce.armextab.*)
        } > REGION_ARM_EXTAB
    
        .ARM.exidx : {
            __exidx_start = .;
            *(.ARM.exidx*)
            *(.gnu.linkonce.armexidx.*)
            __exidx_end = .;
        } > REGION_ARM_EXIDX
    
        etext   = .;
        _etext  = .;
        __etext = .;
    
        .data : {
            __data_load__ = LOADADDR (.data);
            __data_start__ = .;
            *(.got.plt)
            *(.got)
            *(.shdata)
            KEEP (*(.data))
            KEEP (*(.data*))
            *(.gnu.linkonce.d.*)
            . = ALIGN (4);
            __data_end__ = .;
        } > REGION_DATA AT> REGION_TEXT
    
        /*
         * Place .heap section before .bss and .stack as the _sbrk
         * implementation in librdimon.a compares the (heap_end + incr)
         * to the current SP value to check if the heap has overlapped
         * with the stack. 
         *
         * If .heap is placed between .bss and .stack in a SYS/BIOS app,
         * when the task stack (allocated in .bss) is the current stack,
         * the heap check in _sbrk will fail and trigger an error even
         * though the heap might not have actually overlapped with the
         * system stack.
         */
        .heap : ALIGN(0x100) {
            __heap_start__ = .;
            end = __heap_start__;
            _end = end;
            __end = end;
            . += __HEAP_SIZE;
            __heap_end__ = .;
            __HeapLimit = __heap_end__;
        } > REGION_HEAP
    
        .bss : {
            __bss_start__ = .;
            *(.shbss)
            KEEP (*(.bss))
            *(.bss.*)
            *(.gnu.linkonce.b.*)
            *(COMMON)
            . = ALIGN (4);
            __bss_end__ = .;
        } > REGION_BSS
    
        .stack : ALIGN(0x0008) {
            __TI_STACK_BASE = .;
            __stack = .;
            . += __TI_STACK_SIZE;
        } > REGION_STACK
    
        .stab           0 : { *(.stab) }
        .stabstr        0 : { *(.stabstr) }
        .stab.excl      0 : { *(.stab.excl) }
        .stab.exclstr   0 : { *(.stab.exclstr) }
        .stab.index     0 : { *(.stab.index) }
        .stab.indexstr  0 : { *(.stab.indexstr) }
        .comment        0 : { *(.comment) }
    
        .debug          0 : { *(.debug) }
        .line           0 : { *(.line)  }
        .debug_srcinfo  0 : { *(.debug_srcinfo) }
        .debug_sfnames  0 : { *(.debug_sfnames) }
        .debug_aranges  0 : { *(.debug_aranges) }
        .debug_pubnames 0 : { *(.debug_pubnames) }
        .debug_info     0 : { *(.debug_info) }
        .debug_abbrev   0 : { *(.debug_abbrev) }
        .debug_line     0 : { *(.debug_line) }
        .debug_frame    0 : { *(.debug_frame) }
        .debug_str      0 : { *(.debug_str) }
        .debug_loc      0 : { *(.debug_loc) }
        .debug_macinfo  0 : { *(.debug_macinfo) }
        .debug_weaknames    0 : { *(.debug_weaknames) }
        .debug_funcnames    0 : { *(.debug_funcnames) }
        .debug_typenames    0 : { *(.debug_typenames) }
        .debug_varnames     0 : { *(.debug_varnames) }
        .debug_pubtypes     0 : { *(.debug_pubtypes) }
        .debug_ranges       0 : { *(.debug_ranges) }
    
    }
    
    /* function aliases */
    xdc_runtime_System_asprintf_va__E = xdc_runtime_System_asprintf_va__F;
    xdc_runtime_System_snprintf_va__E = xdc_runtime_System_snprintf_va__F;
    xdc_runtime_System_printf_va__E = xdc_runtime_System_printf_va__F;
    xdc_runtime_System_aprintf_va__E = xdc_runtime_System_aprintf_va__F;
    xdc_runtime_System_sprintf_va__E = xdc_runtime_System_sprintf_va__F;
    

    and the cfg file:

    // Configuration shared by all builds of SYS/BIOS.
    
    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    var Diags = xdc.useModule('xdc.runtime.Diags');
    var Assert = xdc.useModule('xdc.runtime.Assert');
    var Error = xdc.useModule('xdc.runtime.Error');
    var Log = xdc.useModule('xdc.runtime.Log');
    
    var Main = xdc.useModule('xdc.runtime.Main');
    var Memory = xdc.useModule('xdc.runtime.Memory')
    var SysMin = xdc.useModule('xdc.runtime.SysMin');
    var System = xdc.useModule('xdc.runtime.System');
    var Text = xdc.useModule('xdc.runtime.Text');
    
    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    var Hwi = xdc.useModule('ti.sysbios.family.arm.a8.intcps.Hwi');
    var Hwi2 = xdc.useModule('ti.sysbios.hal.Hwi');
    
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var Event = xdc.useModule('ti.sysbios.knl.Event');
    var Idle = xdc.useModule('ti.sysbios.knl.Idle');
    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
    var Cache = xdc.useModule('ti.sysbios.family.arm.a8.Cache');
    
    // var TimerProvider = xdc.useModule('ti.sysbios.timers.dmtimer.TimestampProvider');
    var TimerProvider = xdc.useModule('ti.sysbios.family.arm.a8.TimestampProvider');
    
    var HeapBuf = xdc.useModule('ti.sysbios.heaps.HeapBuf');
    var HeapMultiBuf = xdc.useModule('ti.sysbios.heaps.HeapMultiBuf');
    var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
    
    
    Task.addHookSet({
            switchFxn: "&onTaskSwitch",
    });
    
    System.extendedFormats += "%f";
    
    /*
     * Minimize exit handler array in System.  The System module includes
     * an array of functions that are registered with System_atexit() to be
     * called by System_exit().
     */
    System.maxAtexitHandlers = 4;
    
    /* 
     * Uncomment this line to disable the Error print function.
     * We lose error information when this is disabled since the errors are
     * not printed.  Disabling the raiseHook will save some code space if
     * your app is not using System_printf() since the Error_print() function
     * calls System_printf().
    Error.raiseHook = null;
     */
    
    /*
     * Uncomment this line to keep Error, Assert, and Log strings from being
     * loaded on the target.  These strings are placed in the .const section.
     * Setting this parameter to false will save space in the .const section.
     * Error, Assert and Log message will print raw ids and args instead of
     * a formatted message.
    Text.isLoaded = false;
     */
    
    /*
     * Uncomment this line to disable the output of characters by SysMin
     * when the program exits.  SysMin writes characters to a circular buffer.
     * This buffer can be viewed using the SysMin Output view in ROV.
    SysMin.flushAtExit = false;
     */
    SysMin.flushAtExit = true;
    
    // place the entry point at the beginning (buggy)
    Program.sectMap[".c_int00"] = new Program.SectionSpec();
    Program.sectMap[".c_int00"].runAddress = 0x80000000;
    
    /*
     * The BIOS module will create the default heap for the system.
     * Specify the size of this default heap.
     */
    // text + bss < 4700kB
    //var textAndBss = 5 * 1024 * 1024;
    var textAndBss = 25 * 1024 * 1024;
    var totalRam = 0x20000000;
    BIOS.heapSize = totalRam - textAndBss;
    
    var heapSection = new Program.SectionSpec();
    heapSection.runAddress = 0x80000000 + totalRam - BIOS.heapSize;
    heapSection.type = "NOLOAD";
    Program.sectMap["system.heap"] = heapSection;
    BIOS.heapSection = "system.heap"
    
    // use HeapTrack for the default heap
    BIOS.heapTrackEnabled = false;
    
    /* System stack size (used by ISRs and Swis) */
    Program.stack = 4 * 1024;
    
    /* Circular buffer size for System_printf() */
    SysMin.bufSize = 8 * 1024;
    
    System.SupportProxy = SysMin;
    SysMin.outputFxn = "&Uart_write";
    Error.raiseHook = "&onSystemError";
    
    BIOS.swiEnabled = true;
    BIOS.taskEnabled = true;
    
    /* Set up MMU for peripheral addresses */
    Mmu.enableMMU = true;
    
    // Force peripheral section to be NON cacheable strongly-ordered memory
    var attrs = {
            type: Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
            tex: 0,
            bufferable: false,                // bufferable
            cacheable: false,                // cacheable
            shareable: false,                // shareable
            noexecute: true,                 // not executable
    };
    
    for (var addr = 0x44000000; addr < 0x57000000; addr += 0x00100000) {
            Mmu.setFirstLevelDescMeta(addr, addr, attrs);
    }
    
    Task.checkStackFlag = false;
    Hwi2.checkStackFlag = false;
    
    Task.deleteTerminatedTasks = false;
    
    Clock.swiPriority = 10;
    // Dynamic mode seems to have more accurate timing
    // BUT! it seriously reduces the amount of CPU available before clicks/pops and completely breaks ADC at low buffer sizes.
    // Clock.tickMode = Clock.TickMode_DYNAMIC;
    
    var Load = xdc.useModule('ti.sysbios.utils.Load');
    Load.windowInMs = 1000;
    Load.taskEnabled = true;
    //Clock.timerId = 5;
    Clock.tickPeriod = 1000;
    

  • Hi, 

    I think you need to add a custom linker command file to the build, e.g.

    SECTIONS
    {
    
        /*
        Remove section to exclude0's for heap initialization from ARM image.
        Must have corresponding "Program.sectionsExclude" in SYSBIOS configuration file.
        */
        .ddrHeap (NOLOAD):
        {
            *(.myHeap) 
        } > DDR2
    }

  • It looks like you are changing the order of the sections by excluding the heap section from the cfg-generated part of the linker script and forcing it to be placed in another (relative) location that is specified in a custom linker script?  I can see that working and I will try it.  I just have to figure out how to do add a custom linker command file to my non-CCS/gnu-make build system.

    However, even if the above works it still leaves the bigger problem of how to specify the heap size without hard-coding it, right?

  • Probably I'm not understanding the problem.

    The heap size needs to be set somewhere. How would it not be "hard-coded"? If it weren't hard-coded, where would it be set? Note this is the total (maximum) space allocated for the run-time heap, and more or less of the heap will be consumed depending on how the application uses it. The maximum size can be adjusted according to application requirements.

    Using the above method, the linker can determine the best location for the heap in in the desired memory area.

    Ideally the bin file shouldn't not be impacted by the size or location of the heap.

    As I said before, I've looped in a colleague who may be able to provide more ideas.

    Regards,
    Frank 

  • You would use symbols defined in the linker script.  For example, you would define 2 symbols in the linker script, one for the beginning of the heap and one for the end of the heap.  Then the heap management code would use the distance between these symbols as the heap size.  Another example, if all fixed-size sections were placed contiguously in memory starting at the beginning then you can a define a symbol that points to the location right after the last section.  Then the heap just extends to the end of the memory and then only the total size of RAM is hard-coded.

  • Please look at http://software-dl.ti.com/dsps/dsps_public_sw/sdo_sb/targetcontent/sysbios/6_53_02_00/exports/bios_6_53_02_00/docs/cdoc/ti/sysbios/heaps/HeapMem.html#primary.Heap.Base.Addr

    You can create a heap in the .cfg using symbols from the linker file. You can assign this to the Memory.defaultHeap then. For example (where __primary_heap_start__ and __primary_heap_end__ are defined in the linker file).

    var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
    HeapMem.primaryHeapBaseAddr = "&__primary_heap_start__";
    HeapMem.primaryHeapEndAddr = "&__primary_heap_end__";
    
    var heapMemParams = new HeapMem.Params();
    heapMemParams.usePrimaryHeap = true;
    Program.global.heap0 = HeapMem.create(heapMemParams);
    
    Memory.defaultHeapInstance = Program.global.heap0;

    You can also use HeapCallback and provide whatever implementation you want for the heap.

    Todd

  • Oh!  This looks like exactly what I want!  Thank you, Todd.

    I'll try this out today and get back to you.  By the way, just so I understand what is going on. 

    Q1) In the last 2 lines, did you create a *new* global variable, called heap0, and then point the defaultHeapInstance to it?  Or does the global variable, heap0, already exist and thus has a special meaning to BIOS?

    Q2) Memory.defaultHeapInstance is used by the RTS for calls to malloc/free?

    Q3) Declaring linker symbols requires using a custom linker script and is not possible in the cfg script?

  • BrianBrianBrian said:
    Q1) In the last 2 lines, did you create a *new* global variable, called heap0, and then point the defaultHeapInstance to it?  Or does the global variable, heap0, already exist and thus has a special meaning to BIOS?

    It has no special meaning. Using "Program.global.heap0" also creates a global variable (called "heap0") that the C code can reference. You need to do have a #include <xdc/cfg/global.h>

    BrianBrianBrian said:

    Q2) Memory.defaultHeapInstance is used by the RTS for calls to malloc/free?

    You get the default heap with malloc and when you do Memory_alloc(NULL, blah, blah, blah);

    BrianBrianBrian said:

    Q3) Declaring linker symbols requires using a custom linker script and is not possible in the cfg script?

    You need to specify the symbols in the linker script and reserve the space
    HEAPSIZE = 0x1000;  /* Size of heap buffer used by HeapMem */
    
    SECTIONS
    {
        ...
    
        /* Heap buffer used by HeapMem */
        .priheap   : {
            __primary_heap_start__ = .;
            . += HEAPSIZE;
            __primary_heap_end__ = .;
        } > SRAM_DATA align 8
    
        ...

    Todd

  • I just want to report back and let you know that your suggestion worked like a charm.  Thank you.  Here is what I ended up doing:

    First, I made my own custom linker template script (XDT) file and added to the compile process via

    Program.linkTemplate = "linkcmd_custom.xdt"

    The contents of this custom linker template script was copied from the original template that was being used by default.  In my case it was a copy of ~/ti/bios_6_46_05_55/packages/gnu/targets/arm/linkcmd_bm_v7a.xdt.  Then I edited it so that the .heap section was defined at the end and that the size of the section extended to the end of RAM using a dot expression (see the .heap section).

    [linkcmd_custom.xdt]

    %%{
    /* 
     *  Copyright (c) 2008-2015 Texas Instruments and others.
     *  All rights reserved. This program and the accompanying materials
     *  are made available under the terms of the Eclipse Public License v1.0
     *  which accompanies this distribution, and is available at
     *  www.eclipse.org/.../epl-v10.html
     *
     *  Contributors:
     *      Texas Instruments - initial implementation
     *
     * */
    
    /* Linker templates are passed the following arguments:
     *      $out        - an open file stream for the generated linker
     *                    command file
     *      $args[]     - array of zero or more libraries that should be linked
     *                    with (in the order they appear in the argument list)
     *
     *  We can't add "'s around names; otherwise the GNU linker looks for names
     *  with "'s.
     */
    
    /*
     * Bare Metal ARM v7a and v7m link template
     *
     * Customized for the ER-301 by Brian Clarkson
     * Original: ./bios_6_46_05_55/packages/gnu/targets/arm/linkcmd_bm_v7a.xdt
     * 
     */
    %%}
    /*
     * This file was generated by er-301/libs/sysbios/linkcmd_er301.xdt.
     */
    
    ENTRY(_c_int00)
    
    __TI_STACK_SIZE = `utils.toHex(prog.stack)`;
    __STACK_SIZE = __TI_STACK_SIZE;
    __HEAP_SIZE = `utils.toHex(0x20000000 - 25 * 1024 * 1024)`;
    
    %if ($args.length > 0) {
    INPUT(
        %for (var i = 0; i < $args.length; i++) {
        "`$args[i]`"
        %}
    )
    %}
    
    MEMORY
    {
    %for (var i = 0; i < prog.cpu.memoryMap.length; i++) {
        %var mem = prog.cpu.memoryMap[i];
        %var page = (mem.page != null) ? ("PAGE " + mem.page + ": ") : "";
        %var org = utils.toHex(mem.base);
        %var len = utils.toHex(mem.len);
        %var access = (mem.access != null) ? (" (" + mem.access + ")") : "";
        `page``mem.name``access` : org = `org`, len = `len`
    %}
    }
    
    /*
     * In order to put the .bass, .text, .data, .heap or .stack into a
     * different memory section, change the corresponding REGION_ALIAS.
     */
    REGION_ALIAS("REGION_BSS", `Program.platform.dataMemory`);
    REGION_ALIAS("REGION_TEXT", `Program.platform.codeMemory`);
    REGION_ALIAS("REGION_DATA", `Program.platform.dataMemory`);
    REGION_ALIAS("REGION_STACK", `Program.platform.stackMemory`);
    REGION_ALIAS("REGION_HEAP", `Program.platform.dataMemory`);
    REGION_ALIAS("REGION_ARM_EXTAB", `Program.platform.dataMemory`);
    REGION_ALIAS("REGION_ARM_EXIDX", `Program.platform.dataMemory`);
    
    /*
     * symbolic aliases for static instance objects
     */
    %for (var sym in Program.symbol) {
        %var inst = Program.symbol[sym];
        %if (typeof(inst) == 'number') {
    `this.build.target.asmName(sym)` = `inst`;
        %}
        %else {
            %var objTab = inst.$module.$name.replace(/\./g, '_') + '_Object__table__V';
            %var off = Program.$capsule.instSize(inst) * inst.$index;
    `this.build.target.asmName(sym)` = `this.build.target.asmName(objTab)` + `off`;
        %}
    %}
    
    /*
     * Linker command file contributions from all loaded packages:
     */
    %var _utils = xdc.loadCapsule("gnu/targets/linkUtils.xs");
    `_utils.genContributions($args)`
    
    SECTIONS {
    
        .c_int00 0x80000000 : {
            KEEP (*(.c_int00))
        } > REGION_TEXT
    
    `_utils.genSections(prog)`
    
        .text : {
            CREATE_OBJECT_SYMBOLS
            KEEP (*(.resetVecs))
            KEEP (*(.text))
            *(.text.*)
            *(.gnu.linkonce.t*)
            *(.gnu.warning)
            *(.glue*)
            . = ALIGN(0x4);
            KEEP (*(.ctors))
            *(.gnu.linkonce.r.*)
            . = ALIGN(0x4);
            __init_array_start = .;
            KEEP(*(SORT(.init_array.*)))
            KEEP(*(.init_array))
            __init_array_end = .;
            *(.init)
            *(.fini*)
        } > REGION_TEXT
    
        .rodata : {
            *(.rodata)
            *(.rodata.*)
        } > REGION_TEXT
    
        .ARM.extab : {
            *(.ARM.extab*)
            *(.gnu.linkonce.armextab.*)
        } > REGION_ARM_EXTAB
    
        .ARM.exidx : {
            __exidx_start = .;
            *(.ARM.exidx*)
            *(.gnu.linkonce.armexidx.*)
            __exidx_end = .;
        } > REGION_ARM_EXIDX
    
        etext   = .;
        _etext  = .;
        __etext = .;
    
        .data : {
            __data_load__ = LOADADDR (.data);
            __data_start__ = .;
            *(.got.plt)
            *(.got)
            *(.shdata)
            KEEP (*(.data))
            KEEP (*(.data*))
            *(.gnu.linkonce.d.*)
            . = ALIGN (4);
            __data_end__ = .;
        } > REGION_DATA AT> REGION_TEXT
    
        .bss : {
            __bss_start__ = .;
            *(.shbss)
            KEEP (*(.bss))
            *(.bss.*)
            *(.gnu.linkonce.b.*)
            *(COMMON)
            . = ALIGN (4);
            __bss_end__ = .;
        } > REGION_BSS
    
        .stack : ALIGN(0x0008) {
            __TI_STACK_BASE = .;
            __stack = .;
            . += __TI_STACK_SIZE;
        } > REGION_STACK
    
        .stab           0 : { *(.stab) }
        .stabstr        0 : { *(.stabstr) }
        .stab.excl      0 : { *(.stab.excl) }
        .stab.exclstr   0 : { *(.stab.exclstr) }
        .stab.index     0 : { *(.stab.index) }
        .stab.indexstr  0 : { *(.stab.indexstr) }
        .comment        0 : { *(.comment) }
    
        .debug          0 : { *(.debug) }
        .line           0 : { *(.line)  }
        .debug_srcinfo  0 : { *(.debug_srcinfo) }
        .debug_sfnames  0 : { *(.debug_sfnames) }
        .debug_aranges  0 : { *(.debug_aranges) }
        .debug_pubnames 0 : { *(.debug_pubnames) }
        .debug_info     0 : { *(.debug_info) }
        .debug_abbrev   0 : { *(.debug_abbrev) }
        .debug_line     0 : { *(.debug_line) }
        .debug_frame    0 : { *(.debug_frame) }
        .debug_str      0 : { *(.debug_str) }
        .debug_loc      0 : { *(.debug_loc) }
        .debug_macinfo  0 : { *(.debug_macinfo) }
        .debug_weaknames    0 : { *(.debug_weaknames) }
        .debug_funcnames    0 : { *(.debug_funcnames) }
        .debug_typenames    0 : { *(.debug_typenames) }
        .debug_varnames     0 : { *(.debug_varnames) }
        .debug_pubtypes     0 : { *(.debug_pubtypes) }
        .debug_ranges       0 : { *(.debug_ranges) }
    
        /* WARNING: I've placed the heap after .bss and .stack which is
         * a problem for librdimon.a.  See below:
         *
         * Place .heap section before .bss and .stack as the _sbrk
         * implementation in librdimon.a compares the (heap_end + incr)
         * to the current SP value to check if the heap has overlapped
         * with the stack. 
         *
         * If .heap is placed between .bss and .stack in a SYS/BIOS app,
         * when the task stack (allocated in .bss) is the current stack,
         * the heap check in _sbrk will fail and trigger an error even
         * though the heap might not have actually overlapped with the
         * system stack.
         */
        .heap : ALIGN(0x100) {
            __heap_start__ = .;
            /*. += __HEAP_SIZE;*/
            /* Heap extends to the end of DDR3 */
            . = ORIGIN(DDR3) + LENGTH(DDR3); 
            __heap_end__ = .;
        } > REGION_HEAP
    
    }
    
    /* function aliases */
    %if (prog.build.profile.match(/blas/) == null) {
    %    for (var keys = this.$$aliases.keys(); keys.hasMoreElements(); ) {
    %        var key = keys.nextElement();
    `key` = `this.$$aliases.get(key)`;
    %    }
    %}
    %%{
    /*
     * @(#) gnu.targets.arm; 1, 0, 0,0; 10-21-2016 18:16:49; /db/ztree/library/trees/xdctargets/xdctargets-l07/src/ xlibrary
    
     */
    
    %%}
    

    Finally, I removed the BIOS.heapSize and BIOS.heapSection code from the cfg file and created my own default instance as described in this thread:

    // Configuration shared by all builds of SYS/BIOS.
    
    var Defaults = xdc.useModule('xdc.runtime.Defaults');
    var Diags = xdc.useModule('xdc.runtime.Diags');
    var Assert = xdc.useModule('xdc.runtime.Assert');
    var Error = xdc.useModule('xdc.runtime.Error');
    var Log = xdc.useModule('xdc.runtime.Log');
    
    var Main = xdc.useModule('xdc.runtime.Main');
    var Memory = xdc.useModule('xdc.runtime.Memory')
    var SysMin = xdc.useModule('xdc.runtime.SysMin');
    var System = xdc.useModule('xdc.runtime.System');
    var Text = xdc.useModule('xdc.runtime.Text');
    
    var BIOS = xdc.useModule('ti.sysbios.BIOS');
    var Hwi = xdc.useModule('ti.sysbios.family.arm.a8.intcps.Hwi');
    var Hwi2 = xdc.useModule('ti.sysbios.hal.Hwi');
    
    var Task = xdc.useModule('ti.sysbios.knl.Task');
    var Event = xdc.useModule('ti.sysbios.knl.Event');
    var Idle = xdc.useModule('ti.sysbios.knl.Idle');
    var Clock = xdc.useModule('ti.sysbios.knl.Clock');
    var Mmu = xdc.useModule('ti.sysbios.family.arm.a8.Mmu');
    var Cache = xdc.useModule('ti.sysbios.family.arm.a8.Cache');
    
    // var TimerProvider = xdc.useModule('ti.sysbios.timers.dmtimer.TimestampProvider');
    var TimerProvider = xdc.useModule('ti.sysbios.family.arm.a8.TimestampProvider');
    
    var HeapBuf = xdc.useModule('ti.sysbios.heaps.HeapBuf');
    var HeapMultiBuf = xdc.useModule('ti.sysbios.heaps.HeapMultiBuf');
    var HeapMem = xdc.useModule('ti.sysbios.heaps.HeapMem');
    
    
    Task.addHookSet({
            switchFxn: "&onTaskSwitch",
    });
    
    System.extendedFormats += "%f";
    
    /*
     * Minimize exit handler array in System.  The System module includes
     * an array of functions that are registered with System_atexit() to be
     * called by System_exit().
     */
    System.maxAtexitHandlers = 4;
    
    /* 
     * Uncomment this line to disable the Error print function.
     * We lose error information when this is disabled since the errors are
     * not printed.  Disabling the raiseHook will save some code space if
     * your app is not using System_printf() since the Error_print() function
     * calls System_printf().
    Error.raiseHook = null;
     */
    
    /*
     * Uncomment this line to keep Error, Assert, and Log strings from being
     * loaded on the target.  These strings are placed in the .const section.
     * Setting this parameter to false will save space in the .const section.
     * Error, Assert and Log message will print raw ids and args instead of
     * a formatted message.
    Text.isLoaded = false;
     */
    
    /*
     * Uncomment this line to disable the output of characters by SysMin
     * when the program exits.  SysMin writes characters to a circular buffer.
     * This buffer can be viewed using the SysMin Output view in ROV.
    SysMin.flushAtExit = false;
     */
    SysMin.flushAtExit = true;
    
    Program.linkTemplate = "linkcmd_custom.xdt"
    
    HeapMem.primaryHeapBaseAddr = "&__heap_start__";
    HeapMem.primaryHeapEndAddr = "&__heap_end__";
    var heapMemParams = new HeapMem.Params();
    heapMemParams.usePrimaryHeap = true;
    Program.global.heap0 = HeapMem.create(heapMemParams);
    Memory.defaultHeapInstance = Program.global.heap0;
    
    // use HeapTrack for the default heap
    BIOS.heapTrackEnabled = false;
    
    /* System stack size (used by ISRs and Swis) */
    Program.stack = 4 * 1024;
    
    /* Circular buffer size for System_printf() */
    SysMin.bufSize = 8 * 1024;
    
    System.SupportProxy = SysMin;
    SysMin.outputFxn = "&Uart_write";
    Error.raiseHook = "&onSystemError";
    
    BIOS.swiEnabled = true;
    BIOS.taskEnabled = true;
    
    /* Set up MMU for peripheral addresses */
    Mmu.enableMMU = true;
    
    // Force peripheral section to be NON cacheable strongly-ordered memory
    var attrs = {
            type: Mmu.FirstLevelDesc_SECTION, // SECTION descriptor
            tex: 0,
            bufferable: false,                // bufferable
            cacheable: false,                // cacheable
            shareable: false,                // shareable
            noexecute: true,                 // not executable
    };
    
    for (var addr = 0x44000000; addr < 0x57000000; addr += 0x00100000) {
            Mmu.setFirstLevelDescMeta(addr, addr, attrs);
    }
    
    Task.checkStackFlag = false;
    Hwi2.checkStackFlag = false;
    
    Task.deleteTerminatedTasks = false;
    
    Clock.swiPriority = 10;
    // Dynamic mode seems to have more accurate timing
    // BUT! it seriously reduces the amount of CPU available before clicks/pops and completely breaks ADC at low buffer sizes.
    // Clock.tickMode = Clock.TickMode_DYNAMIC;
    
    var Load = xdc.useModule('ti.sysbios.utils.Load');
    Load.windowInMs = 1000;
    Load.taskEnabled = true;
    //Clock.timerId = 5;
    Clock.tickPeriod = 1000;
    

    Thanks again!