Reduce code size with the right choice of initialize

Download Report

Transcript Reduce code size with the right choice of initialize

By Hiroki Akaboshi, IAR Systems
Reduce code size with the right choice of initialize
algorithm in ILINK
Embedded systems have limited memory space for code and data and therefore you might need a way
to reduce the code that initializes your variables.
In Standard C, all static variables, which are variables that are allocated at a fixed memory address,
must be initialized by the runtime system to a known value at application startup. This value is either an
explicit value assigned to the variable, or if no value is given, it is cleared to zero. In the compiler in IAR
Embedded Workbench, there are exceptions to this rule, for example variables declared __no_init,
which are not initialized at all.
Initialization of data is handled by the IAR ILINK Linker and the system startup code in conjunction.
The IAR ILINK Linker, included in IAR Embedded Workbench, is a powerful, flexible software tool for
use in the development of embedded applications. It is equally well suited for linking small, single-file,
absolute assembler programs as it is for linking large, relocatable, multi-module, C/C++, or mixed C/C++
and assembler programs. The linker combines one or more relocatable object files—produced by the
compiler or assembler in IAR Embedded Workbench—with selected parts of one or more object libraries
to produce an executable image in the industry-standard format Executable and Linking Format (ELF).
In this article, we will show different ways to reduce the initialization code and discuss some of the data
compression algorithms that can be used by ILINK.
Global variable initialization
In the following text, we assume that the code and constant data are stored in ROM (Flash) and the
non-constant data are stored in RAM.
const int cvalue = 100;
int zvalue;
int dvalue = 100;
int main()
…
The global constant variable cvalue with the value 100 is placed in ROM. The global variable zvalue
is placed in RAM and is initialized to zero. The variable dvalue is an initialized variable and is placed in
RAM.
Page 2
How do we store the initialized value 100 in the program and set dvalue? In the application, data for
initialization are stored in ROM and the function which initializes variables is executed before the main
function is called.
If the number of initialized variables increases the ROM usage will increase and the initialization time will
be longer.
How to decrease the use of ROM
There are several ways to decrease the ROM usage. Two of them are:
1.
2.
Decrease the number of initialized variables if possible.
Compress the initialization data. ILINK supports several algorithms for that: zeros, packbits,
lz77, bwt, and lzw (See the IAR C/C++ Development Guide for further information).
Linker configuration for compression
The linker configuration file in IAR Embedded Workbench for ARM has the file extension “.ICF”.
Normally, this file has a directive for initialize as follows:
initialize by copy {readwrite };
To specify a compression algorithm, this description must be appended with with packing=XXX
(XXX should be selected from zeros, packbits, lz77, bwt, lzw). If XXX is set to “none”, ILINK will
generate code without compression.
initialize by copy with packing=XXX{ readwrite };
Page 3
Let’s try with a sample project!
You can download a sample project which is tested with IAR Embedded Workbench for ARM 7.20.2
from IAR Systems. Unzip the download file and open the Workspace.eww file in the folder
TN_INITIALIZE from IAR Embedded Workbench (File>Open>Workspace).
1
The application has sixteen arrays with 512 initialized elements each, and sixteen non-initialize arrays.
The application requires 32+32 KBytes in RAM and 32Kbytes in ROM space to initialize and store the
arrays.
In the linker configuration file Proj.icf used in this project you can find the initialize description on the
24th line:
initialize by copy with packing=none{ readwrite };
After you have built the project open the map file c.map. There are several points to check here
1. INIT TABLE
In the map file, there is a section, “INIT TABLE”. Zero (__iar_zero_init3) shows the zeroinitialization area information, and Copy (__iar_copy_init3) shows the initialization area with
source and destination range.
Address
Size
---------Zero (__iar_zero_init3)
1 destination range, total size 0x8000:
0x20008000 0x8000
Copy (__iar_copy_init3)
1 source range, total size 0x8000:
0x00000130 0x8000
1 destination range, total size 0x8000:
0x20000000 0x8000
2. ENTRY LIST
The map file also contains an “ENTRY LIST”. The Entry list has information about all functions and
variables with its size information (code size, read-only data size or readwrite data size).
At the end of the map file you have a summary of the size for the whole application.
268 bytes of readonly code memory
32 804 bytes of readonly data memory
66 560 bytes of readwrite data memory
Try option packing=zeros
Modify the linker configuration file “Proj.icf” and change the initialize statement from packing=none to
packing=zeros. The zeros algorithm compresses consecutive bytes with the value zero. The size of
initialized data is reduced to 36 % from non-compress data in INIT TABLE of the map file.
1
If different version is applied, the result may be different.
Page 4
Address
Size
---------Zero (__iar_zero_init3)
1 destination range, total size 0x8000:
0x20008000 0x8000
Copy/zeros (__iar_rle_init3)
1 source range, total size 0x2e2b (36% of destination):
0x000001ea 0x2e2b
1 destination range, total size 0x8000:
0x20000000 0x8000
Thanks to the data compression, the size of the read-only data is decreased. One important point is that
the code size is increased due to the compress algorithm code that is added. When the size of
initialization is small or the effect of compression is small, the total memory area may be increased.
438 bytes of read-only code memory
11 863 bytes of read-only data memory
66 560 bytes of readwrite data memory
Try other algorithms
The following chart shows the size of code and read-only data using the different algorithms.
The smallest is made by the option lz77. The size of uncompressed read-only data and code is about 33
Kbytes. The size of lz77 compress read-only data and code is about 1.3Kbytes, which is one-thirtieth of
non-compress size! How much you can gain with the different algorithms depends on your data and
code.
35000
30000
25000
20000
readonly
15000
code
10000
5000
0
none
zeros
packbits
bwt
lz77
lzw
How to select algorithm
You may wonder how to select these algorithms. If you read the document IAR C/C++ Development
Guide, you can find other algorithms auto and smallest. The smallest option is automatic selection
for choosing the smallest size including code size. The auto option is the smallest between none,
packbits, and lz77 and is default option for the initialize directive.
Page 5
Conclusion
ILINK in IAR Embedded Workbench has several options to compress the initialized data and some
options automatically choose the smallest size. As we have seen in this article, the code decrease can
be significant depending on your data. When you select an algorithm, you must be aware of not only the
data size but also the code size since the compression algorithm requires some code.