Das Pragma legt fest, wie eine Datenstruktur während der Allozierung gepackt wird. Das Attribut muss oberhalb der Datenstruktur eingefügt werden und wirkt sich auf das Packen der gesamten Struktur aus.
Syntax:
{attribute 'pack_mode' := ' <pack mode value>' }
Einfügeort: oberhalb der Deklaration der Datenstruktur
<pack mode value> |
Assoziierte Packungsart |
Beschreibung |
---|---|---|
0 |
aligned |
Es liegen alle Variablen auf Byte-Adressen; es treten keine Speicherlücken auf. |
1 |
1-byte-aligned |
|
2 |
2-byte-aligned |
Es liegen
|
4 |
4-byte-aligned |
Es liegen
|
8 |
8-byte-aligned |
Es liegen
|
Abhängig vom Aufbau der Struktur kann es somit vorkommen, dass es keinen Unterschied
in der Speicheraufteilung zwischen den einzelnen Modi gibt.
Somit kann die Speicherverteilung einer Struktur mit <pack mode value> = 4
der von <pack mode value> = 8
entsprechen.
Arrays von Strukturen: Werden die Strukturen in Arrays zusammengefasst, so werden am Ende der Struktur Bytes eingefügt, damit die nächste Struktur wieder aligned ist.




HINWEIS

Wenn in der Symbolkonfiguration die Option „Kompatibilitätslayout“ aktiviert wird und gleichzeitig das Attribut 'pack_mode' im Code verwendet wird, können Probleme wegen unabsichtlich falscher Speicherausrichtung auftreten.
Siehe auch
Beispiel 1
Beispiel
{attribute 'pack_mode' := '1'} TYPE myStruct: STRUCT Enable: BOOL; Counter: INT; MaxSize: BOOL; MaxSizeReached: BOOL; END_STRUCT END_TYPE
Der Speicherbereich für eine Variable vom Datentyp myStruct
wird "aligned" alloziert: Ist die Speicheradresse ihrer Komponente Enable
beispielsweise 0x0100
, dann folgt die Komponente Counter
an der Adresse 0x0101
, MaxSize
an Adresse 0x0103
und MaxSizeReached
an Adresse 0x0104
. Mit 'pack_mode':=2
läge Counter
bei 0x0102
, MaxSize
bei 0x0104
und MaxSizeReached
bei 0x0106
.
Beispiel 2
Beispiel
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 |
Wert |
Variable |
Wert |
Variable |
Wert |
Variable |
Wert |
Variable |
Wert |
|
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 |
Beispiel 3
Beispiel
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 |
Wert |
Variable |
Wert |
Variable |
Wert |
Variable |
Wert |
Variable |
Wert |
|
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 |
Verhalten ohne pack-mode
Wenn kein pack-mode verwendet wird, dann verwendet der Compiler typischerweise pack-mode 4 oder 8, abhängig von der Gerätebeschreibung. In jedem Fall wird ein für den Prozessor besonders vorteilhafter pack-mode verwendet, so dass Speicherzugriffe besonders effizient durchgeführt werden können. Dies wird auch natürliches Alignment genannt, oder eine natürliche Ausrichtung der Daten.
Negative Auswirkungen bei Anwendung von eines pack-mode
Durch die Verwendung des Attributs 'pack_mode'
kann es zu nicht ausgerichteten Speicherzugriffen kommen. Das bedeutet beispielsweise,
dass ein Datentyp der Größe 4 Byte dann auf einer Adresse liegt, die nicht durch
4 teilbar ist. Normalerweise kann auf einem 32-Bit-System ein 32 Bit großer Datentyp
mit einem einzigen Speicherzugriff gelesen und geschrieben werden. Auf manchen Plattformen,
wie beispielsweise auf ARM-Plattformen, ist das jedoch nur möglich, wenn dieser Wert
im Speicher ausgerichtet ist. Auf anderen Plattformen kann es sein, dass der Zugriff
zwar möglich ist, aber deutlich langsamer ausgeführt wird.
Beispiel
{attribute 'pack_mode':=1} TYPE DUT STRUCT by1 : BYTE; dw1 : DWORD; END_STRUCT END_TYPE
Auf einer ARM-Plattform kann der Wert dw1
nicht mit einem einzigen Zugriff gelesen werden. Bei dem Versuch auf dieses Element
direkt zuzugreifen, wird der ARM-Prozessor eine Exception auslösen.
Annahme: Folgender lesender Zugriff wird durchgeführt: dwTest := dut1.dw1;
Für diesen Zugriff auf das DWORD dw1
werden 4 Speicherzugriffe benötigt, da jedes Byte einzeln eingelesen, geshiftet und
verodert wird. Der Ablauf ist in etwa der Gleiche, wie wenn in dem folgenden Beispiel
aus einem Array von 4 Bytes ein DWORD
generiert wird:
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;
Es ist offensichtlich, dass ein solcher Zugriff deutlich langsamer ist als ein Zugriff
auf ein DWORD
, das passend im Speicher ausgerichtet ist.
pdw := ADR(dut1.dw1); dwTest := pdw^;
Den Zugriff des Beispiels wird der Compiler jedoch nicht generieren, wenn über einen Pointer auf eine solche Komponente zugegriffen wird. Das bedeutet, dass der folgende Code auf einer ARM-Plattform zu einer Exception führt.
pdw := ADR(dut1.dw1); dwTest := pdw^;
Aus Performance-Gründen sollte es daher vermieden werden, mit Strukturen zu arbeiten, die nicht natürlich ausgerichtet sind.
Eine gepackte Struktur darf keine ungepackte Struktur enthalten.