S12Z constant, variable, code allocation in CodeWarrior

Document created by Radek Sestak Employee on May 30, 2017Last modified by Radek Sestak Employee on May 30, 2017
Version 2Show Document
  • View in full screen mode

The S12Z MCU has linear address space therefore constant, variable, code placement is easier in compare with older S12 or S12X MCUs. But still, there are several ways and potential issues.


The object placement is made by Smart Linker. The linker configuration is defined by settings in project *.prm file and also by linker command line options (menu - Project – Properties – C/C++ Build – Settings – S12Z Linker).

The detail information about linker options may be found in MCU_Build_Tools_Utilities.pdf with default path:

"c:\Freescale\CW MCU v10.7\MCU\Help\PDF\MCU_Build_Tools_Utilities.pdf"


We may define memory segments in *.prm linker file. The default prm file contains segments for RAM, EEPROM, and ROM (Flash). The sizes of these segments typically reflect our MCU derivative physical memory map, but we may redefine that and use more virtual segments per our needs.

The physical/virtual segments definition in prm linker file is located at:

// segments definition



The general data placement may be divided into two main approaches:

  • Manual – the programmer will specify fix address for some of the data
  • Automatic – the placement will be driven automatically by Smart Linker


Manual placement

The first option is an exact specification of specific content at a specific address. This may be managed for a small amount of data by FILL linker command in *.prm linker parameter file. For example:

ROM_CONST       = READ_ONLY   0xFE0000 TO 0xFE0000 FILL 0x5A;  //insert 0x5A value at address 0xFE0000


Such placement isn’t very comfortable, but it might be simply used for some configuration data out of project code.

Note: you may use more than one bytes (e.g. FILL 0x0A 0x34). If segment size is bigger than a number of specified bytes, the bytes will be used as a pattern for filling whole target segment.

Note: The potential linker placement will overlap such defined data.


The next option is using address specification by an @ qualifier directly in C code. For example:

unsigned const int rom_const @0xFE0100 = 0x5AA5;

This may be used also for more complex types than simple byte – typically arrays,...


Since such type of placement is still manual, the linker parameters must be configured for avoiding possible overlapping.

Be aware! The default CW project has disabled memory overlapping warnings.

So, we must exclude target memory area from linker using. For example, in the *.prm file:

ROM_1           = READ_ONLY   0xFE0000 TO 0xFE00FF
//ROM_CONST  = READ_ONLY   0xFE0100 TO 0xFE0101;            //we use the 0xFE0100 byte for rom_const
ROM_2           = READ_ONLY   0xFE0102 TO 0xFFFDFF


Note: We use qualifiers for define memory access type. READ_ONLY is used for Flash, READ_WRITE for RAM and NO_INIT for RAM where we do not want to initialize data after reset. Sections placed in an NO_INIT segment should not contain any initialized variables (variable defined as int c = 8).


Note: The manual placement may be also implemented by assembler code. For example:

XDEF MyVariable
MyVariable: equ $1100

However, also in this case, we must exclude target memory area from linker use like in the case of @ qualifier for avoiding memory overlapping.


Automatic placement by linker

The PLACEMENT block allows us to physically place each section from the application in a specific memory area (segment). The sections specified in a PLACEMENT block may be linker-predefined sections (like DEFAULT_ROM, DEFAULT_RAM, COPY, SSTACK,…) or user sections specified in one of the source file building the application (like MY_RAM,…).

// section(s) INTO segment(s);


Note: Since the linker is case sensitive, the name of the section names specified in the PLACEMENT block must be valid predefined or user-defined section names.


Note: There is quite mess in ELF/Freescale section/segment terminology. Please take this information as simplified as possible. Please look at MCU_Build_Tools_Utilities.pdf for more details about predefined segments/sections.


Note: We may place a various number of sections into a various number of segments. The “,” is used as section/segment delimiter.


Note: In general, the placement order is given by simple list order (first specified section will be allocated from first specified segment, after that next section …). But, there are still few limitations for sections list order. The error is generated in the case of wrong list order – for example: ERROR L1122: only checksum section may be behind .copy in the section list.


The default variable/constant/code placement may be changed by #pragma commands.

Note: Most of these pragma commands are not limited to the single file. Therefore, we should keep it in complementary pairs. An example of placing code into specific section:

void f(void)


The #pragma DATA_SEG modifies variable placement. For example:

unsigned int counter;


The #pragma CONT_SEG modifies variable placement. For example:

const unsigned int my_parameter;


Note: The shorter option for directly allocating variables in a named segment, rather than using a #pragma may be used. For example:

unsigned int counter@"MY_RAM";

However, even in such case, the #pragma command like #pragma DATA_SEG MY_RAM must be used at least once prior that variable declaration.


Note: The S12Z compiler/linker allows to use also already predefined sections like DEFAULT_ROM, DEFAULT_RAM or ROM_VAR as target sections in #pragma commands (not possible in the case of older S12(X) compiler/linker).  


More details about #pragma commands may be found in MCU_S12Z_Compiler.pdf with default path:

"c:\Freescale\CW MCU v10.7\MCU\Help\PDF\MCU_S12Z_Compiler.pdf"



Data alignment

Sometimes we need to keep allocated data aligned. This is for example typical requirement for ADC command and result list where DMA is used for transfer data between ADC module and memory.

The simplest method is using alignment attribute. For example:

volatile unsigned long adc0_cmdlist[NR_A_CH] __attribute__ ((aligned (4))); //max 256 bytes = 64 commands per 4-byte entries
volatile unsigned int adc0_results[NR_A_CH] __attribute__ ((aligned (4)));  //max 128 bytes = 64 results per 2-byte entries



I hope it helps you.


Best regards


1 person found this helpful