Please note as of Wednesday, August 15th, 2018 this wiki has been set to read only. If you are a TI Employee and require Edit ability please contact x0211426 from the company directory.

Linker Generated ECC

From Texas Instruments Wiki
Jump to: navigation, search

Linker Generated ECC

Beginning with release 5.1.0, the TI ARM C/C++ Compiler supports automatic generation of Error Correction Codes compatible with the Flash ECC on various TI microcontrollers (e.g. TMS570, RM4x, TMS470M).

ECC can be generated during the final link step of compilation. The ECC data is included in the resulting object file, alongside code and data, as a data section located at the appropriate address. Therefore, no extra ECC generation step is required after compilation, and the ECC can be uploaded to the device along with everything else.

The Linker is configured to generate ECC using a new syntax in the linker command file. The command file will specify a separate memory range for the ECC inside the device's memory map, and it will indicate which other memory range corresponds to the Flash data memory covered by the ECC. It will also specify the parameters by which the ECC will be calculated, which can vary somewhat between devices.

Please note, that CCS supports the automatic generation of the ECC code when downloading the binary to the target. This feature is enabled by default and could be configured in the Project Settings. It's not possible to use both the CCS integrated ECC generation and Linker Generated ECC at the same time. The main difference between the two methods is, that with Linker Generated ECC the ECC code will be embedded in the binary (or ELF) file, whereas it's generated on the fly by CCS. Let CCS handle the ECC is a grate usability improvement, however there are uses cases for Linker Generated ECC as, use of a gang programmer for production purpose, building a Firmware Update binary, or if you want to have the full control of all build steps.

Linker Command File Syntax

The memory map for a device supporting Flash ECC may look something like this:

  MEMORY {
      VECTORS  : origin=0x00000000 length=0x000020
      FLASH0   : origin=0x00000020 length=0x17FFE0
      FLASH1   : origin=0x00180000 length=0x180000
      STACKS   : origin=0x08000000 length=0x000500
      RAM      : origin=0x08000500 length=0x03FB00
      ECC_VEC  : origin=0xf0400000 length=0x000004 ECC={ input_range=VECTORS }
      ECC_FLA0 : origin=0xf0400004 length=0x02FFFC ECC={ input_range=FLASH0  }
      ECC_FLA1 : origin=0xf0430000 length=0x030000 ECC={ input_range=FLASH1  }
  }

The "ECC" specifier attached to the ECC memory ranges indicates the data memory range that the ECC range covers. The ECC specifier supports the following parameters:

   input_range=<memory range>   The data memory range covered by the ECC
                                range; required.
   input_page =<page number>    The page number of the input range; required
                                only if the input range's name is ambiguous.
   algorithm  =<ECC algo. name> The name of an ECC algorithm defined later in
                                the command file; optional if only one
                                algorithm is defined. (see below)
   fill       =<true/false>     Whether to generate ECC data for holes in the
                                initialized data of the input range; default
                                value is "true". Using fill=false will
                                produce behavior similar to the nowECC tool.

In addition to specifying the ECC memory ranges in the memory map, the command file must specify parameters for generating the ECC data. This is done with a new top level directive in the command file:

  ECC {
      algo_name : address_mask = 0x003ffff8
                  hamming_mask = FMC
                  parity_mask  = 0xfc
                  mirroring    = F021
  }

This ECC algorithms directive accepts any number of definitions, which consist of an identifier, a colon, and some number of algorithm attributes. The following attributes are supported:

   address_mask=<32-bit mask>  This mask determines what address bits are used
                               in the calculation of ECC.
   hamming_mask=<FMC/R4>       This determines which data bits each ECC bit
                               encodes the parity for.
   parity_mask =<8-bit mask>   This determines which ECC bits encode even
                               parity, and which bits encode odd parity.
   mirroring   =<F021/F035>    This determines what pattern of duplication of
                               parity information is used in the ECC memory
                               for redundancy.

Each TI device supporting Flash ECC will have exactly one valid set of values for these parameters.

The memory maps and ECC algorithm definitions for Flash ECC devices should be included in subsequent releases of Code Composer Studio. Users will not generally need to modify the preset values.

Error Injection

To enable users to test ECC error detection and handling, the compiler now supports two new command line options that inject bit errors into the linked executable. The compiler allows the user to specify an address where an error will appear and a bitmask that specifies which bits in the code/data at that address should be flipped. The address of the error can be specified absolutely, or as an offset from a symbol. When a data error is injected, the ECC for the data is calculated as if the error were not present. This is the syntax for the error injection options:

   --ecc:data_error=(symbol+offset|address)[,page],bitmask
   --ecc:ecc_error=(symbol+offset|address)[,page],bitmask

The data_error version will inject errors into the load image at the specified location. The ecc_error version will inject errors into the ECC that corresponds to the specified location. Note that the ecc_error version can therefore only specify locations inside ECC input ranges, whereas the data_error version can also specify errors in the ECC output memory ranges.

For example, the following invocation of the compiler will flip the least significant bit in the byte at the address 0x100, making it inconsistent with the ECC for that byte:

   armcl test.c --ecc:data_error=0x100,0x01 -z -o test.out

This invocation will flip two bits in the third byte of the code for main():

   armcl test.c --ecc:data_error=main+2,0x42 -z -o test.out

This invocation will flip every bit in the ECC byte that contains the parity information for the byte at 0x200:

   armcl test.c --ecc:ecc_error=0x200,0xff -z -o test.out

The compiler will disallow injecting errors into memory ranges that are neither an ECC range nor the input range for an ECC range. The compiler can only inject errors into initialized sections.

VFILL Specifier

A small extension has been made to the fill value specifier for memory ranges in the linker command file. Normally, specifying a fill value for a memory range will create initialized data sections to cover any previously uninitialized areas of memory. To generate ECC for an entire memory range, the linker either needs to have initialized data for the entire range, or needs to know what value uninitialized memory areas will have at run time. To accommodate the case where the user wants to generate ECC for the entire memory range, but does not want to initialize the entire range by specifying a fill value, the new "vfill" specifier may be used instead of a "fill" specifier:

  MEMORY {
      FLASH : origin=0x0000  length=0x4000  vfill=0xffffffff
  }

The vfill specifier is functionally equivalent to omitting a fill specifier, except that it allows ECC generation to occur for areas of the input memory range that remain uninitialized. This has the benefit of reducing the size of the resulting object file.

The "vfill" specifier has no effect other than in ECC generation. It cannot be specified along with a "fill" specifier, since that would introduce ambiguity.

Settings for Hercules MCU's

TMS570LS20x/10x

ECC algorithm

ECC {
    algoR4F035 : address_mask = 0x003ffff8 /* Address Bits 21:3 */
                 hamming_mask = R4         /* Use R4 build in Mask */
                 parity_mask  = 0x0c       /* Set which ECC bits are Even and Odd parity */
                 mirroring    = F035       /* TMS570LS20x/10x are build in F035 */
}

example Memory Map for TMS570LS20216

#define FLASH_ECC_ORIGIN  (0x00400000)

MEMORY
{
/* Flash Memory */
/* Bank 0 */
    VECTORS (X)  : origin=0x00000000 length=0x00000020  fill=0xFFFFFFFF
    FLASH0  (RX) : origin=0x00000020 length=0x0007FFE0 vfill=0xFFFFFFFF
/* Bank 1 */
    FLASH1  (RX) : origin=0x00080000 length=0x00080000 vfill=0xFFFFFFFF
/* Bank 2 */
    FLASH2  (RX) : origin=0x00100000 length=0x00080000 vfill=0xFFFFFFFF
/* Bank 3 */
    FLASH3  (RX) : origin=0x00180000 length=0x00080000 vfill=0xFFFFFFF
/* Bank 0 ECC */
    ECC_VEC      : origin = (FLASH_ECC_ORIGIN+(start(VECTORS)>>1))
                   length = (size(VECTORS)>>1)
                   ECC    = {algorithm=algoR4F035, input_range=VECTORS}
    ECC_FLA0     : origin = (FLASH_ECC_ORIGIN+(start(FLASH0)>>1))
                   length = (size(FLASH0)>>1)
                   ECC    = {algorithm=algoR4F035, input_range=FLASH0}
/* Bank 1 ECC */
    ECC_FLA1     : origin = (FLASH_ECC_ORIGIN+(start(FLASH1)>>1))
                   length = (size(FLASH1)>>1)
                   ECC    = {algorithm=algoR4F035, input_range=FLASH1}
/* Bank 2 ECC */
    ECC_FLA2     : origin = (FLASH_ECC_ORIGIN+(start(FLASH2)>>1))
                   length = (size(FLASH2)>>1)
                   ECC    = {algorithm=algoR4F035, input_range=FLASH2}
/* Bank 3 ECC */
    ECC_FLA3     : origin = (FLASH_ECC_ORIGIN+(start(FLASH3)>>1))
                   length = (size(FLASH3)>>1)
                   ECC    = {algorithm=algoR4F035, input_range=FLASH3}
/* embedded SRAM */
    STACKS  (RW) : origin=0x08000000 length=0x00001500
    RAM     (RW) : origin=0x08001500 length=0x00026B00
}

TMS570LS and RM4x

ECC algorithm

ECC {
    algoR4F021 : address_mask = 0x003ffff8 /* Address Bits 21:3 */
                 hamming_mask = R4         /* Use R4 build in Mask */
                 parity_mask  = 0x0c       /* Set which ECC bits are Even and Odd parity */
                 mirroring    = F021       /* RM4x and TMS570LSx are build in F021 */
}

example Memory Map for RM42L432 and TMS570LS0432

MEMORY
{
/* Bank 0 (384kB) */
    VECTORS (X)  : origin=0x00000000
                   length=0x00000020
                   fill=0xffffffff
    FLASH0  (RX) : origin=end(VECTORS)
                   length=(0x00060000 - size(VECTORS))
                   vfill=0xffffffff

/* Bank 7 (FEE) */
    FLASH7   (R) : origin=0xF0200000
                   length=0x00004000
                   vfill=0xffffffff

/* Bank 0 ECC */
    ECC_VEC  (R) : origin=(0xf0400000 + (start(VECTORS) >> 3))
                   length=(size(VECTORS) >> 3)
                   ECC={algorithm=algoR4F021, input_range=VECTORS}
    ECC_FLA0 (R) : origin=(0xf0400000 + (start(FLASH0)  >> 3))
                   length=(size(FLASH0)  >> 3)
                   ECC={algorithm=algoR4F021, input_range=FLASH0 }

/* Bank 7 ECC */
    ECC_FLA7 (R) : origin=0xF0100000
                   length=(size(FLASH7)  >> 3)
                   ECC={algorithm=algoR4F021, input_range=FLASH7 }

/* Embedded SRAM (32kB) */
    STACKS  (RW) : origin=0x08000000
                   length=0x00001500
    RAM     (RW) : origin=end(STACKS)
                   length=(0x00008000 - size(STACKS))
}

example Memory Map for RM44L920 and TMS570LS0714

MEMORY
{
/* Flash Memory */
/* Bank 0 (1.0MB) */
    VECTORS  (X)  : origin=0x00000000
                    length=0x00000020
                    fill=0xffffffff
    FLASH0   (RX) : origin=(end(VECTORS))
                    length=(0x00100000 - size(VECTORS))
                    vfill=0xffffffff

/* Bank 7 (64kB, FEE) */
    FLASH7   (R)  : origin=0xF0200000
                    length=0x00010000
                    vfill=0xffffffff

/* Bank 0 ECC */
    ECC_VEC  (R)  : origin=(0xf0400000 + (start(VECTORS) >> 3))
                    length=(size(VECTORS) >> 3)
                    ECC={algorithm=algoR4F021, input_range=VECTORS}
    ECC_FLA0 (R)  : origin=(0xf0400000 + (start(FLASH0)  >> 3))
                    length=(size(FLASH0)  >> 3)
                    ECC={algorithm=algoR4F021, input_range=FLASH0 }

/* Bank 7 ECC */
    ECC_FLA7 (R)  : origin=0xF0100000
                    length=(size(FLASH7)  >> 3)
                    ECC={algorithm=algoR4F021, input_range=FLASH7 }

/* embedded SRAM (128kB) */
    STACKS   (RW) : origin=0x08000000
                    length=0x00001500
    RAM      (RW) : origin=(end(STACKS))
                    length=(0x00020000 - size(STACKS))
}

example Memory Map for RM46L852 and TMS570LS1227

MEMORY
{
/* Flash Memory */
/* Bank 0 (1.25MB) */
    VECTORS  (X)  : origin=0x00000000
                    length=0x00000020
                    fill=0xffffffff
    FLASH0   (RX) : origin=(end(VECTORS))
                    length=(0x00140000 - size(VECTORS))
                    vfill=0xffffffff

/* Bank 7 (64kB, FEE) */
    FLASH7   (R)  : origin=0xF0200000
                    length=0x00010000
                    vfill=0xffffffff

/* Bank 0 ECC */
    ECC_VEC  (R)  : origin=(0xf0400000 + (start(VECTORS) >> 3))
                    length=(size(VECTORS) >> 3)
                    ECC={algorithm=algoR4F021, input_range=VECTORS}
    ECC_FLA0 (R)  : origin=(0xf0400000 + (start(FLASH0)  >> 3))
                    length=(size(FLASH0)  >> 3)
                    ECC={algorithm=algoR4F021, input_range=FLASH0 }

/* Bank 7 ECC */
    ECC_FLA7 (R)  : origin=0xF0100000
                    length=(size(FLASH7)  >> 3)
                    ECC={algorithm=algoR4F021, input_range=FLASH7 }

/* embedded SRAM (192kB) */
    STACKS   (RW) : origin=0x08000000
                    length=0x00001500
    RAM      (RW) : origin=(end(STACKS))
                    length=(0x00030000 - size(STACKS))
}

example Memory Map for RM48L952 and TMS570LS3137

MEMORY
{
/* Flash Memory */
/* Bank 0 (1.5MB) */
    VECTORS  (X)  : origin=0x00000000
                    length=0x00000020
                    fill=0xffffffff
    FLASH0   (RX) : origin=(end(VECTORS))
                    length=(0x00180000 - size(VECTORS))
                    vfill=0xffffffff

/* Bank 1 (1.5MB) */
    FLASH1   (RX) : origin=0x00180000
                    length=0x00180000
                    vfill=0xffffffff

/* Bank 7 (64kB, FEE) */
    FLASH7   (R)  : origin=0xF0200000
                    length=0x00010000
                    vfill=0xffffffff

/* Bank 0 ECC */
    ECC_VEC  (R)  : origin=(0xf0400000 + (start(VECTORS) >> 3))
                    length=(size(VECTORS) >> 3)
                    ECC={algorithm=algoR4F021, input_range=VECTORS}
    ECC_FLA0 (R)  : origin=(0xf0400000 + (start(FLASH0)  >> 3))
                    length=(size(FLASH0)  >> 3)
                    ECC={algorithm=algoR4F021, input_range=FLASH0 }

/* Bank 1 ECC */
    ECC_FLA1 (R)  : origin=(0xf0400000 + (start(FLASH1)  >> 3))
                    length=(size(FLASH1)  >> 3)
                    ECC={algorithm=algoR4F021, input_range=FLASH1 }

/* Bank 7 ECC */
    ECC_FLA7 (R)  : origin=0xF0100000
                    length=(size(FLASH7)  >> 3)
                    ECC={algorithm=algoR4F021, input_range=FLASH7 }

/* embedded SRAM (256kB) */
    STACKS   (RW) : origin=0x08000000
                    length=0x00001500
    RAM      (RW) : origin=(end(STACKS))
                    length=(0x00040000 - size(STACKS))
}

TMS570LC4357 and RM57L843

ECC algorithm

These devices uses a different connection of the CPU to the flash and different flash wrapper (L2FMC) than TMS570LS and RM4x devices, due to their cached CPU (R5). From an ECC algorithm standpoint the difference is that all Address Bits are participating in the ECC check bit generation.

ECC {
    algoL2R5F021 : address_mask = 0xfffffff8 /* Address Bits 31:3 */
                   hamming_mask = R4         /* Use R4/R5 build in Mask */
                   parity_mask  = 0x0c       /* Set which ECC bits are Even and Odd parity */
                   mirroring    = F021       /* RM57Lx and TMS570LCx are build in F021 */
}

example Memory Map for RM57L843 and TMS570LC4357

MEMORY
{
/* Bank 0 (2MB) */
    VECTORS (X)  : origin=0x00000000 length=0x00000020  fill=0xffffffff
    FLASH0  (RX) : origin=0x00000020 length=0x001FFFE0 vfill=0xffffffff

/* Bank 1 (2MB) */
    FLASH1  (RX) : origin=0x00200000 length=0x00200000 vfill=0xffffffff

/* Bank 7 (128kB, FEE) */
    FLASH7   (R) : origin=0xF0200000 length=0x00020000 vfill=0xffffffff


/* Bank 0 ECC */
    ECC_VEC  (R) : origin=(0xf0400000 + (start(VECTORS) >> 3))
                   length=(size(VECTORS) >> 3)
                   ECC={algorithm=algoL2R5F021, input_range=VECTORS}

    ECC_FLA0 (R) : origin=(0xf0400000 + (start(FLASH0)  >> 3))
                   length=(size(FLASH0)  >> 3)
                   ECC={algorithm=algoL2R5F021, input_range=FLASH0 }
/* Bank 1 ECC */
    ECC_FLA1 (R) : origin=(0xf0400000 + (start(FLASH1)  >> 3))
                   length=(size(FLASH1)  >> 3)
                   ECC={algorithm=algoL2R5F021, input_range=FLASH1 }

/* Bank 7 ECC */
    ECC_FLA7 (R) : origin=0xF0100000
                   length=(size(FLASH7)  >> 3)
                   ECC={algorithm=algoL2R5F021, input_range=FLASH7 }
				 
/* eSRAM (512kB) */
    STACKS  (RW) : origin=0x08000000
                   length=0x00001500
				   
    RAM     (RW) : origin=(end(STACKS))
                   length=(0x00080000 - size(STACKS))
}

TMS470M

ECC algorithm

ECC {
    algoFMCF035 : address_mask = 0x003ffff8 /* Address Bits 21:3 */
                  hamming_mask = FMC        /* Use Flash Wrapper Mask */
                  parity_mask  = 0xfc       /* Set which ECC bits are Even and Odd parity */
                  mirroring    = F035       /* TMS470M is build in F035 */
}

example Memory Map for TMS470M066

#define FLASH_ECC_ORIGIN  (0x00400000)
MEMORY
{
/* embedded Flash */
  /* Bank 0 */
    VECTORS  (RX) : origin=0x00000000         length=0x00000100                         fill=0xffffffff
    FLASH0   (RX) : origin=(end(VECTORS))     length=(0x00080000 - size(VECTORS))      vfill=0xffffffff
  /* Bank 1 */
    FLASH1   (RX) : origin=0x00080000         length=0x00020000                        vfill=0xffffffff
  /* Bank 0 ECC */
    ECC_VEC  (R)  : origin=(FLASH_ECC_ORIGIN + (start(VECTORS) >> 1)) length=(size(VECTORS) >> 1) ECC={algorithm=algoFMCF035, input_range=VECTORS}
    ECC_FLA0 (R)  : origin=(FLASH_ECC_ORIGIN + (start(FLASH0)  >> 1)) length=(size(FLASH0)  >> 1) ECC={algorithm=algoFMCF035, input_range=FLASH0 }
  /* Bank 1 ECC */
    ECC_FLA1 (R)  : origin=(FLASH_ECC_ORIGIN + (start(FLASH1)  >> 1)) length=(size(FLASH1)  >> 1) ECC={algorithm=algoFMCF035, input_range=FLASH1 }
/* embedded SRAM */
    STACKS   (RW) : origin=0x08000000         length=0x00000800
    RAM      (RW) : origin=0x08000800         length=0x0000F800
}




The SECTIONS Directive

since the ECC on all current Hercuels devices is calculated on a 64 bit or 8 byte boundary all data and code sections which are placed in the on-chip flash should also be aligned to a 64 bit boundary. They furthermore should also end at 64 bit boundaries to ensure that the complete section will have a length of a multiple of 64 bits and is entirely be initialized. The easiest way to achieve this to use palign(8) on all output sections ind the Linker Command File which will be placed in the on-chip flash. In an LCF this could look like the following:

SECTIONS
{
   .intvecs    : {} palign=8 > VECTORS
.text  : {} palign=8 > FLASH0 | FLASH1 /* Executable code and constants */ .const  : {} palign=8 > FLASH0 | FLASH1 /* Global and static const variables that are explicitly initialized */ .cinit  : {} palign=8 > FLASH0 | FLASH1 /* Tables for explicitly initialized global and static variables */ #ifdef __TI_EABI_SUPPORT__ .init_array : {} palign=8 > FLASH0 | FLASH1 /* C++ global constructor addresses */ #else /* TI_ARM9_ABI and TIABI */ .pinit  : {} palign=8 > FLASH0 | FLASH1 /* C++ global constructor addresses */ #endif
.stack  : {} > STACKS /* Stack */
.bss  : {} > RAM /* Uninitialized global and static variables */ .data  : {} > RAM /* Global and static non-const variables that are explicitly initialized. */ .sysmem  : {} > RAM /* Memory pool (heap) for dynamic memory allocation */ }

Description of palign() copied from SPNU118

8.5.4.2.5 Alignment With Padding
As with align, you can tell the linker to place an output section at an address that falls on an n-byte boundary, where n is a power of 2, by using the palign keyword. In addition, palign ensures that the size of the section is a multiple of its placement alignment restrictions, padding the section size up to such a boundary, as needed.