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.

MSP430 GCC automatic code splitting between low and far rom?

Other Parts Discussed in Thread: MSP430F5438A

Hi,

I am very interested in the gcc port for MSP430 and its integration in CCSv6. I am very glad about the effort done by TI (and RedHat) to offer this opensource and free development option.

However, I have some issues with the code placement in ROM

Release notes of the 4.9 (fist production) version states:

  • Support for intelligently splitting code and data between low and high memory

But linker scripts provided with CCSv6 (and the ones downloadables at the TI GCC MSP page) are configured only to use the lowest ROM memory region. I have been able to manually place code in the far region by modifying these files, for example like this (and of course using the -mlarge flag when compiling and linking):

/* This is just for crt0.S and interrupt handlers. */

.lowtext :
{
PROVIDE (_start = .);
. = ALIGN(2);
KEEP (*(SORT(.crt_*)))
KEEP (*(.lowtext))
} > ROM

.lower.text :
{
. = ALIGN(2);
*(.lower.text.* .lower.text)
} > ROM

.text :
{
. = ALIGN(2);
*(.text .stub .text.* .gnu.linkonce.t.* .text:*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.interp .hash .dynsym .dynstr .gnu.version*)
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(2);
KEEP (*(.init))
KEEP (*(.fini))
KEEP (*(.tm_clone_table))
} > FAR_ROM

However this places almost all code in far ROM region, except for the interrupt subroutines and some other (few) functions. This is not optimal, since a significant amount of Flash is in the low address space and would be wasted.

Of course, I can manually place code in the low rom by using the section attribute, but I would prefer the linker  to automatically split the code bewteen the two region, as hinted in the release notes, so I do not have to manually state where each function is placed. 

Is this possible? If so, How? I have not been able to figure it out so far.

 Regards, and Thank you,

Jose

  • Automatic code splitting requires a completely different strategy that what the existing linkers used before.
    For optimum linking, this would require a multi-pass linking process, while the current algorithms are one-pass straight.
    What happens if low flash is full and there comes an ISR? And if low flash is reserved for ISRs, then what if there comes none? (your “wasted space”)
    Best strategy without a complete rewrite of the linking algorithms would be placing all code into far flash except for ISRs and constant data (if small data model is active).
    An improved version could place normal code in low flash when far flash is full. However, this again can lead to situations where the could would fit but due to the order in which it appears to the linker, it doesn’t fit, leaving two holes that would together be large enough, but aren’t one alone.

     It’s easy to forget that things that seem so simple for a human, are really difficult to explain to a linear-working machine.

  • Thank you for your reply.

    I am not talking about fully optimizing the code split between two region, I am just talking about using both flash regions to store the generated program code without having to do so manually (of course some gap could be still wasted at the end of the low rom region, but not almos all the low rom region).  Both IAR and CCS's TI compiler for MSP430 perform this, when the code is big enough, some subroutines are automatically placed in low rom whereas others are placed in the high rom, thus using (almost) all the available program memory. This is what I meant in my previous post, sorry if I did not explain myself clearly.

    Of course GCC is an opensource and license free tool andI appreciate all the effort TI and RedHat (and other contributors) have been doing to provide us with such a tool, for free. For me, free use of the tool is a very important feature, and I perfectily  understand that we must accept  it will probably lack some features that alternative commercial tools have.

    However, the Release notes of the 4.9 version of MSP GCC specifically mention  "Support for intelligently splitting code and data between low and high memory" as one of the added features. I am just wondering if this feature has been actualy  added (As I said, I would understand it is still not supported, but I just  would like to know),  and if it is indeed supported, how can it be activated, since apparently it does not work.

    The patch for the linker script I provided above, exactly implements your first suggestion, place all code into far flash except for ISRs and constant data (and variable data initialization). This is the best result I have achieved so far, but If your project does not include much constant data or ISR code, a significant amount of the low rom/flash is still wasted. What I was asking for is what you define as an "improved version" that  could place normal code in low flash when far flash is full. This I think is which CCS and IAR are capable of  doing, but I have not managed to configure GCC to do it, and I am not even sure if it can.

    Regards, and thank you again for your great effort.

     

    Jose

  • I am curious as to the answer for this as well.  I understand the linker script challenges, just ... wonder what TI means by "intelligently splitting code" as a new feature :)  If it's just something we need to light up with a few linker script "hints", that would be awesome!

  • I didn’t know that this “intelligently splitting code” support has been announced as added. In this case, one would expect it to be working (even if still buggy) and there should be hints on how to enable/use it.

    However, your existing and apparently working solution doesn’t “waste” more flash than the ‘improved’ version, as long as all code fits into upper memory: it makes no difference whether the remaining unused flash is in upper or lower memory.
    The only problem is when code is larger than upper memory. Then the ‘improved’ version would be necessary for automatic placement. Well, in this case, one can easily put some selected functions into lower memory by hand. Not too much effort, I’d say. Just less convenient. But should do until it is finally solved in the linker.

    Many years ago, at times of DOS, there was the problem of conventional and upper memory too. Drivers could be loaded low or high (and low memory was needed for applications). The challenge was to pack as many drivers into upper memory. Worse, the drivers often needed more memory when being launched than they needed after initialization.
    There was a commercial product called QEMM386 (an EMS virtual memory driver) that came with an analyzer tool. It did boot the PC several times while measuring the space each driver needed for launching and after initialization, then reordered driver loading, to get the drivers optimally packed into upper memory. Quite a time-consuming process, but worth the effort.
    Well, if the increased link time for multiple passes is not an issue, it should be not a big problem to implement this. Especially as the size of each code block is static. It’s not a new problem and has been solved before.

  • Apparently Redhat has already committed patches to gcc, newlib and so on, to get it working.

    See this thread: https://sourceware.org/ml/newlib/2015/msg00466.html

    @TI, when will this be available in Code Composer Studio?

  • I don’t know if the question still is how to split code over two or more Sections, then this can be done by;
    Chance “} > FAR_ROM” to “} > ROM | FAR_ROM” and the compiler will first fill ‘ROM’ and the remainder to ‘FAR_ROM’ with ‘.text’. Does this not work with GCC?

    Optional use ‘>>’ to create a contiguous Section, if possible.

  • GCC, newlib and other tools apparently needed some patches, which seems to be in the official trees of the respective tools now, but not in the GCC supplied for CCS by TI.

    Hopefully someone from TI can give a release date when they will release the updated tools for MSP430 for CCS v6.x.
  • Redhat msp gcc 4.9.1 does support splitting, however, the linker scripts in CCS do not yet support it. We should have an August release with bug updates that will additionally include updated linker scripts for splitting (explicit .lower/.upper sections).

    In the mean time please see below options as well as the user:
    gcc.gnu.org/.../gcc.pdf

    -mcode-region=
    -mdata-region=
    These options tell the compiler where to place functions and data that do not have one of the lower, upper, either or section attributes. Possible values are lower, upper, either or any. The first three behave like the corresponding attribute. The fourth possible value - any - is the default. It leaves placement entirely up to the linker script and how it assigns the standard sections (.text, .data etc) to the memory regions.

    Page 411 additionally describes lower/upper/either attributes and
    lower
    upper
    either On the MSP430 target these attributes can be used to specify whether the
    function or variable should be placed into low memory, high memory, or the
    placement should be left to the linker to decide. The attributes are only significant
    if compiling for the MSP430X architecture.
    The attributes work in conjunction with a linker script that has been augmented
    to specify where to place sections with a .lower and a .upper prefix. So for
    example as well as placing the .data section the script would also specify the
    placement of a .lower.data and a .upper.data section. The intention being
    that lower sections are placed into a small but easier to access memory region
    and the upper sections are placed into a larger, but slower to access region.
    The either attribute is special. It tells the linker to place the object into the
    corresponding lower section if there is room for it. If there is insufficient room
    then the object is placed into the corresponding upper section instead. Note
    - the placement algorithm is not very sophisticated. It will not attempt to
    find an optimal packing of the lower sections. It just makes one pass over the
    objects and does the best that it can. Using the ‘-ffunction-sections’ and
    ‘-fdata-sections’ command line options can help the packing however, since
    they produce smaller, easier to pack regions.
  • I'm trying to compile code for a msp430f5438a, and i found this thread helpfull.
    Solving most of my problems with some forum questions here and there, i'm still not "happy" with my compiler, and it dosen't finish compilation due to a " undefined reference to `__read_status_register'".
    I tried installing both the complete package already compiled, and compiling myself the mspgcc (from here: software-dl.ti.com/.../index_FDS.html) but it gives me exactly the same problem.

    As i am using linux and compiling in console (not using CCS) this problem rises, probably because i have no path to where that func. is defined?
    Also, i had to force the path to the .h and .ld specific Microcontroler files into the compiler because it wasent recognisable. I know that prob this is not the best thread to ask this question, but i don't seem to find solution to this.
    I followed this site: www.instructables.com/.../Getting-started-with-TIs-MSP430-gcc-and-the-MSP430
    but either solution (for my compilation, or for the installed package from TI compiled options is ok).

    I must enforce that i'm NOT using CCS, but compiling in command line @ linux.

    Here are my flags

    MSPVERSION = "5438a"
    if buildEnv['toolchain']=='mspgcc':
    flags = []
    flags += ['-mmcu=msp430f{0}'.format(MSPVERSION)]
    flags += ['-Wall']
    flags += ['-Wno-main']
    flags += ['-mlarge']
    flags += ['-mcode-region=upper']
    #flags += ['-mdata-region=upper']
    flags += ['-mcpu=msp430xv2']
    flags +=['-L/home/mote/ti/gcc/include/']
    flags +=['-I/home/mote/ti/gcc/include/']
    #flags +=['-L/opt/msp430-toolchain/msp430-none-elf/include/']
    #flags +=['-I/opt/msp430-toolchain/msp430-none-elf/include/']
    ##DID NOTHING
    # flags += ['-ffunction-sections']
    # flags += ['-fdata-sections']
    # flags += ['-gstrict-dwarf']
    # flags += ['-fno-toplevel-reorder']
    if buildEnv['debug']==0:
    flags += ['-Os']
    else:
    flags += ['-O0']
    flags += ['-g']
    #flags += ['-ggdb']
    buildEnv.Append(CCFLAGS = ' '.join(flags))
    buildEnv.Append(LINKFLAGS = ' '.join(flags))

    and compiler settings

    # compiler
    env.Replace(CC = 'msp430-elf-gcc')
    env.Append(CCFLAGS = '-Wstrict-prototypes')
    env.Append(CCFLAGS = '')
    # archiver
    env.Replace(AR = 'msp430-elf-ar')
    env.Append(ARFLAGS = '')
    env.Replace(RANLIB = 'msp430-elf-ranlib')
    env.Append(RANLIBFLAGS = '')
    # linker
    env.Replace(LINK = 'msp430-elf-gcc')
    env.Append(LINKFLAGS = '')

    the compiler is Scons, thats why it is partitioned
    Thanx, DG.

**Attention** This is a public forum