The pragma defines how a data structure is packed during the allocation. The attribute has to be inserted above the data structure and affects the packing of the entire structure.
Syntax:
{attribute 'pack_mode' := ' <pack mode value>' }
Insert location: above the declaration of the data structure
<pack mode value> |
Associated packing method |
Description |
---|---|---|
0 |
Aligned |
All variables are allocated to byte addresses. There are no memory gaps. |
1 |
1-byte-aligned |
|
2 |
2-byte-aligned |
There are
|
4 |
4-byte-aligned |
There are
|
8 |
8-byte-aligned |
There are
|
Depending on the structure, there may be no difference in the memory mapping of the
individual modes. Therefore, the memory allocation of a structure with <pack mode value> = 4
can correspond to that of <pack mode value> = 8
.
Arrays of structures: If the structures are combined in arrays, then bytes are added at the end of the structure so that the next structure is aligned.




NOTICE

If the “Compatibility layout” option is selected in the symbol configuration and at the same time the attribute 'pack_mode' is used in the code, then problems can occur due to unintentional memory misalignment.
See also
Example 1
Example
{attribute 'pack_mode' := '1'} TYPE myStruct: STRUCT Enable: BOOL; Counter: INT; MaxSize: BOOL; MaxSizeReached: BOOL; END_STRUCT END_TYPE
The memory range for a variable of the data type myStruct
is allocated 'aligned'. If the storage address of its component Enable
is 0x0100
, for example, then the component Counter
follows at the address 0x0101
, MaxSize
at address 0x0103
and MaxSizeReached
at address 0x0104
. In the case of 'pack_mode':=2
, Counter
would be at 0x0102
, MaxSize
at 0x0104
and MaxSizeReached
at 0x0106
.
Example 2
Example
STRUCT Var1 : BOOL := 16#01; Var2 : BYTE := 16#11; Var3 : WORD := 16#22; Var4 : BYTE := 16#44; Var5 : DWORD := 16#88776655; Var6 : BYTE := 16#99; Var7 : BYTE := 16#AA; Var8 : DWORD := 16#AA; END_TYPE
pack_mode = 0 |
pack_mode = 1 |
pack_mode = 2 |
pack_mode = 4 |
pack_mode = 8 |
||||||
---|---|---|---|---|---|---|---|---|---|---|
Variable |
Value |
Variable |
Value |
Variable |
Value |
Variable |
Value |
Variable |
Value |
|
0 |
Var1 |
01 |
Var1 |
01 |
Var1 |
01 |
Var1 |
01 |
Var1 |
01 |
1 |
Var2 |
11 |
Var2 |
11 |
Var2 |
11 |
Var2 |
11 |
Var2 |
11 |
2 |
Var3 |
22 |
Var3 |
22 |
Var3 |
22 |
Var3 |
22 |
Var3 |
22 |
3 |
... |
00 |
... |
00 |
... |
00 |
... |
00 |
... |
00 |
4 |
Var4 |
44 |
Var4 |
44 |
Var4 |
44 |
Var4 |
44 |
Var4 |
44 |
5 |
Var5 |
55 |
Var5 |
55 |
||||||
6 |
... |
66 |
... |
66 |
Var5 |
55 |
||||
7 |
... |
77 |
... |
77 |
... |
66 |
||||
8 |
... |
88 |
... |
88 |
... |
77 |
Var5 |
55 |
Var5 |
55 |
9 |
Var6 |
99 |
Var6 |
99 |
... |
88 |
... |
66 |
... |
66 |
10 |
Var7 |
AA |
Var7 |
AA |
Var6 |
99 |
... |
77 |
... |
77 |
11 |
Var8 |
AA |
Var8 |
AA |
Var7 |
AA |
... |
88 |
... |
88 |
12 |
... |
00 |
... |
00 |
Var8 |
AA |
Var6 |
99 |
Var6 |
99 |
13 |
... |
00 |
... |
00 |
... |
00 |
Var7 |
AA |
Var7 |
AA |
14 |
... |
00 |
... |
00 |
... |
00 |
||||
15 |
... |
00 |
||||||||
16 |
Var8 |
AA |
Var8 |
AA |
||||||
17 |
... |
00 |
... |
00 |
||||||
18 |
... |
00 |
... |
00 |
||||||
19 |
... |
00 |
... |
00 |
||||||
20 |
||||||||||
21 |
||||||||||
22 |
||||||||||
23 |
||||||||||
24 |
||||||||||
25 |
||||||||||
26 |
||||||||||
27 |
||||||||||
28 |
||||||||||
29 |
||||||||||
30 |
||||||||||
31 |
Example 3
Example
STRUCT Var1 : BYTE := 16#01; Var2 : LWORD := 16#11; Var3 : BYTE := 16#22; Var4 : BYTE := 16#44; Var5 : DWORD := 16#88776655; Var6 : BYTE := 16#99; Var7 : BYTE := 16#AA; Var8 : WORD := 16#AA; END_TYPE
pack_mode = 0 |
pack_mode = 1 |
pack_mode = 2 |
pack_mode = 4 |
pack_mode = 8 |
||||||
---|---|---|---|---|---|---|---|---|---|---|
Variable |
Value |
Variable |
Value |
Variable |
Value |
Variable |
Value |
Variable |
Value |
|
0 |
Var1 |
01 |
Var1 |
01 |
Var1 |
01 |
Var1 |
01 |
Var1 |
01 |
1 |
Var2 |
11 |
Var2 |
11 |
||||||
2 |
... |
00 |
... |
00 |
Var2 |
11 |
||||
3 |
... |
00 |
... |
00 |
... |
00 |
||||
4 |
... |
00 |
... |
00 |
... |
00 |
Var2 |
11 |
||
5 |
... |
00 |
... |
00 |
... |
00 |
... |
00 |
||
6 |
... |
00 |
... |
00 |
... |
00 |
... |
00 |
||
7 |
... |
00 |
... |
00 |
... |
00 |
... |
00 |
||
8 |
... |
00 |
... |
00 |
... |
00 |
... |
00 |
Var2 |
11 |
9 |
Var3 |
22 |
Var3 |
22 |
... |
00 |
... |
00 |
... |
00 |
10 |
Var4 |
44 |
Var4 |
44 |
Var3 |
22 |
... |
00 |
... |
00 |
11 |
Var5 |
55 |
Var5 |
55 |
Var4 |
44 |
... |
00 |
... |
00 |
12 |
... |
66 |
... |
66 |
Var5 |
55 |
Var3 |
22 |
... |
00 |
13 |
... |
77 |
... |
77 |
... |
66 |
Var4 |
44 |
... |
00 |
14 |
... |
88 |
... |
88 |
... |
77 |
... |
00 |
||
15 |
Var6 |
99 |
Var6 |
99 |
... |
88 |
... |
00 |
||
16 |
Var7 |
AA |
Var7 |
AA |
Var6 |
99 |
Var5 |
55 |
Var3 |
22 |
17 |
Var8 |
AA |
Var8 |
AA |
Var7 |
AA |
... |
66 |
Var4 |
44 |
18 |
... |
00 |
... |
00 |
Var8 |
AA |
... |
77 |
||
19 |
... |
00 |
... |
88 |
||||||
20 |
Var6 |
99 |
Var5 |
55 |
||||||
21 |
Var7 |
AA |
... |
66 |
||||||
22 |
Var8 |
AA |
... |
77 |
||||||
23 |
... |
00 |
... |
88 |
||||||
24 |
Var6 |
99 |
||||||||
25 |
Var7 |
AA |
||||||||
26 |
Var8 |
AA |
||||||||
27 |
... |
00 |
||||||||
28 |
||||||||||
29 |
||||||||||
30 |
||||||||||
31 |
Behavior without pack mode
If pack mode is not used, then the compiler typically uses pack mode 4 or 8, depending on the device description. In each case, a pack mode which is particularly beneficial for the processor is used so that memory access can be performed. This is also called natural alignment or a natural alignment of data.
Negative effects when using pack mode
Unaligned memory access can be the result of using the attribute 'pack_mode'
. This means, for example, that a data type with a size of 4 bytes is then located
at an address which is not divisible by 4. Normally, on a 32-bit system a 32-bit data
type can be read and written with a single memory access. On some platforms, for example
on ARM platforms, this is possible only when this value is aligned in the memory.
On other platforms, it can be that the access is possible but it is performed much
more slowly.
Example
{attribute 'pack_mode':=1} TYPE DUT STRUCT by1 : BYTE; dw1 : DWORD; END_STRUCT END_TYPE
On an ARM platform, the value dw1
cannot be read with a single access. When an attempt is made to access this element
directly, the ARM processor will throw an exception.
Assumption: The following read access is performed: dwTest := dut1.dw1;
For this access to the DWORD dw1
, four memory accesses are required because each byte is read, shifted, and disjuncted
individually. The flow is somewhat the same as in the following example in which a
DWORD
is generated from an array of four bytes:
dwHelp := bytes[0]; dwResult := dwHelp; dwHelp := bytes[1]; dwHelp := SHL(dwHelp, 8); dwResult := dwResult OR dwHelp; dwHelp := bytes[2]; dwHelp := SHL(dwHelp, 16); dwResult := dwResult OR dwHelp; dwHelp := bytes[3]; dwHelp := SHL(dwHelp, 24); dwResult := dwResult OR dwHelp;
Obviously, this kind of access is much slower than access to a DWORD
, which is aligned appropriately in the memory.
pdw := ADR(dut1.dw1); dwTest := pdw^;
However, the compiler will not generate the access of the example when this kind of member is accessed by means of a pointer. This means that the following code results in an exception on an ARM platform.
pdw := ADR(dut1.dw1); dwTest := pdw^;
For performance reasons, you should therefore avoid working with structures which are not naturally aligned.
A packed structure must not contain an unpacked structure.