Forum: Mikrocontroller und Digitale Elektronik GCC (Atmel Studio7): Struct-Variable auf 128 Byte Grenze legen


von Alexxx (Gast)


Lesenswert?

Hallo,

im DB des SAMD21 steht, dass ein DMA-Descriptor-Block
128-bit aligned sein muss.

"Bits 31:0 – DESCADDR[31:0] Next Descriptor Address
This bit group holds the SRAM address of the next descriptor.
The value must be 128-bit aligned."

Da die Adresse des next descriptors aligned sein muss,
und diese Adresse auf das Ende des ganzen Blocks zeigt,
muss ich folglich die ganze Struktur 128-bit aligned
im RAM ablegen können.
Mit welcher Anweisung kann man das erreichen, ohne eine feste Adresse
angeben zu müssen?
Von selbst macht er das ja nicht?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Schreibste __attribute__((aligned(gewünschtes_alignment))) dahinter.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Du könntest
1
__attribute__((aligned(16)))

probieren.  Aber:

https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes

"If your linker is only able to align variables up to a maximum of 
8-byte alignment, then specifying aligned(16) in an _attribute_ still 
only provides you with 8-byte alignment. See your linker documentation 
for further information."

Du müsstest also rausfinden, was der Linker maximal unterstützt.

Alternativ: in eine eigene section packen, und im Linkerscript diese 
entsprechend ausrichten.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Alexxx schrieb:

> Da die Adresse des next descriptors aligned sein muss,
> und diese Adresse auf das Ende des ganzen Blocks zeigt,
> muss ich folglich die ganze Struktur 128-bit aligned
> im RAM ablegen können.
> Mit welcher Anweisung kann man das erreichen, ohne eine feste Adresse
> angeben zu müssen?

in C++:
1
// the array "cacheline" will be aligned to 128-byte boundary
2
alignas(128) char cacheline[128];

In C11 geht es mit dem entsprechenden header (welches alignas als Alias 
für _Alignas definiert):
1
#include <stdalign.h>
2
alignas(128) char cacheline[128];

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Torsten R. schrieb:
> In C11 geht es mit dem entsprechenden header (welches alignas als Alias
> für _Alignas definiert):

Auch der wird sich allerdings nicht über potenzielle Restriktionen des 
Linkers hinwegsetzen können; diese müsste der TE also zuerst eruieren.

Wenn er das hat, geht's auch ohne C11 mit dem genannten Attribut.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Jörg W. schrieb:

> Wenn er das hat, geht's auch ohne C11 mit dem genannten Attribut.

Oder eben ohne GCC :-) Welches C wird den in der Praxis so gesprochen? 
(Ich habe immer den Verdacht, viele embedded C-Entwickler wissen das 
überhaupt nicht).

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Torsten R. schrieb:
> Oder eben ohne GCC

Das war aber im ${subject} des Threads gefordert.

> Welches C wird den in der Praxis so gesprochen?

Was meinst du damit, welche Version des Standards?

Das dürfte stark von deiner Zielplattform abhängen. Wenn's Microsoft 
ist, dann C89, mit paar Ergänzungen, die sie für würdig befunden haben. 
:)

Embedded: wir benutzen C99/gnu99 derzeit, als Erweiterung gegenüber C89 
dabei vor allem benannte Initialisierung von structs, 
Variablendefinitionen so lokal wie möglich, ggf. variable Argumentliste 
in Makros (bspw. wenn man printf wrappen möchte). Mittlerweile dürfte 
allerdings die Verbreitung C11-tauglicher Compiler gut genug sein, dass 
man auch das nehmen könnte. Habe noch nicht getestet, inwiefern sich 
unsere aktuellen Projekte einfach „upgraden“ ließen.

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Jörg W. schrieb:

> Das war aber im ${subject} des Threads gefordert.

Ich würde das jetzt nicht so verstehen wollen, dass die Lösung nur mit 
dem GCC funktioniert, sondern eben auch mit dem GCC. :-) (Ich gehe 
jetzt mal davon aus, dass der GCC auch C11 unterstützt)

Ich würde im Prinzip immer versuchen, eine Lösung zu finden, die mit den 
Standards der Sprache auskommt. Aber klar, wenn die Verwendung neuer 
Sprachstandards wie C11 eine Einschränkung darstellt, dann muss halt 
eine Compiler spezifische Lösung her (wobei man die Portierbarkeit des 
Codes dann auf GCC und < C11 reduziert).

von Alexxx (Gast)


Angehängte Dateien:

Lesenswert?

OK, danke schonmal @alle.

Siehe angehängtes Bild (Family-DB Seite 307)

Der Linker ist der, der bei Atmel Studio 7.0 dabe ist ;-)

Weiteres Problem:
Die Struktur ist nur 12Byte lang. Das Ende der
Struktur muss aligned sein, so dass die Anfangsadresse NICHT
128Bit-aligned ist! Grrrr...
- Geht sowas nur mit einer (berechneten) festen Adresse?
- und was bedeutet dieses aligned dann eigentlich?
   Muss das letzte Byte der Struktur dann auf Adresse x0xxxF
   oder auf x0xxx0 liegen???

Die Brachialmethode wäre natürlich, eine Variable mit vielen Bytes
anzulegen und das Beschreiben der Böcke mit berechneten Zeigern
darin zu machen.
Aber das würde natürlich haufenweise kostbares RAM fressen ...

Es muss doch eine vernünftige Methode geben. Das ASF macht es ja auch 
irgend wie. Ich gebe zu, dass ich da zu faul bin, mich durch diesen
ganzen Wirrwar durchzubeißen.

Bei der align-Anweisung wird im INET gesagt, dass dann Lücken
im RAM erzeugt werden. Kann der Compiler nicht kleinere Variablen
zum Auffüllen verwenden?

von mh (Gast)


Lesenswert?

Jörg W. schrieb:
> Du könntest
> __attribute__((aligned(16)))
> probieren.  Aber:
>
> 
https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes
>
> "If your linker is only able to align variables up to a maximum of
> 8-byte alignment, then specifying aligned(16) in an attribute still
> only provides you with 8-byte alignment. See your linker documentation
> for further information."

Wäre ein derartiger Linker nicht inkompatibel zum C++ Standard (habe 
nicht in den C Standard geguckt)? Ich konnte im Standard keine 
Einschränkung finden. Kennst du einen solchen Linker und weißt ob er 
Fehler oder Warnungen ausgibt?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

mh schrieb:
> Wäre ein derartiger Linker nicht inkompatibel zum C++ Standard

Warum sollte er? Wo garantiert der C++-Standard, dass du alles beliebig 
kurios ausrichten lassen kannst? Ich habe da auch nicht reingeschaut, 
aber vermute ganz stark, dass man da so gut wie alle Details als 
"implementation-defined" standardisiert haben wird, damit alle 
existierenden Implementierungen damit benutzbar sind.

Alexxx schrieb:
> Die Struktur ist nur 12Byte lang.

Wie kommst du denn darauf? Die ist natürlich 128 Bits (= 16 Bytes lang).

Schau einfach mal in die Appnote:

https://www.microchip.com/wwwAppNotes/AppNotes.aspx?appnote=en591729

da gibt's ein Bild:
1
DMA Transfer Descriptor
2
3
The transfer descriptor resides in the SRAM and defines these channel properties.
4
5
Field name                Field width
6
Descriptor Next Address   32 bits
7
Destination Address       32 bits
8
Source Address            32 bits
9
Block Transfer Counter    16 bits
10
Block Transfer Control    16 bits

von mh (Gast)


Lesenswert?

Jörg W. schrieb:
> mh schrieb:
>> Wäre ein derartiger Linker nicht inkompatibel zum C++ Standard
>
> Warum sollte er? Wo garantiert der C++-Standard, dass du alles beliebig
> kurios ausrichten lassen kannst? Ich habe da auch nicht reingeschaut,
> aber vermute ganz stark, dass man da so gut wie alle Details als
> "implementation-defined" standardisiert haben wird, damit alle
> existierenden Implementierungen damit benutzbar sind.

Ok ich bin nur blind. Der C++ Standard sagt
1
if the constant expression does not evaluate to an alignment value ([basic.align]), or evaluates to an extended alignment and the implementation does not support that alignment in the context of the declaration, the program is ill-formed.
Es müsste also ne Meldung an irgend einer Stelle geben.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Der GNU-Linker für arm-none-eabi scheint zumindest nahezu beliebige 
Alignments zu unterstützen:
1
$ cat foo.c
2
int __attribute__((aligned(ALIGN))) foo;
3
4
void _exit(int i) { for (;;) {}}
5
6
int main(void)
7
{
8
  return foo;
9
}
10
$ for align in 32 64 128 256 512 1024 2048 4096 42
11
> do
12
> echo "Testing alignment $align"
13
> arm-none-eabi-gcc -Os -mcpu=cortex-m3 -DALIGN=$align foo.c; arm-none-eabi-nm a.out | fgrep foo
14
> done
15
Testing alignment 32
16
00018880 B foo
17
Testing alignment 64
18
000188c0 B foo
19
Testing alignment 128
20
00018900 B foo
21
Testing alignment 256
22
00018a00 B foo
23
Testing alignment 512
24
00018c00 B foo
25
Testing alignment 1024
26
00019000 B foo
27
Testing alignment 2048
28
00019800 B foo
29
Testing alignment 4096
30
0001a000 B foo
31
Testing alignment 42
32
foo.c:1:1: error: requested alignment is not a positive power of 2
33
 int __attribute__((aligned(ALIGN))) foo;
34
 ^~~

Die 42 ist nur in der Liste, um mal was Unrealistisches zu haben – aber 
da meckert schon der Compiler. :)

von Alexxx (Gast)


Lesenswert?

@Jörg W.
>> Schau einfach mal in die Appnote:

Vielen Dank für den Hinweis - die habe ich nicht gekannt. Werde die mal 
gewissenhaft durcharbeiten.

>>> Die Struktur ist nur 12Byte lang. -> Wie kommst du denn darauf?

Ich habe nur den Offset-Index bei 20.9 Register Summary - SRAM
angeschaut und der geht bis x0C.
Aber das Register hat ja selbst 4 Byte - ergo 16Byte.
"Asche auf mein Haupt"

>> Der GNU-Linker für arm-none-eabi...

Nochmals vielen Dank für deine Untersuchungen dazu.
Dann sollte es mit __attribute__((aligned(16))) funktionieren,
wenn die Anfangsadresse (Struct-Variable) aligned ist.
Dann ist die DB-Aussage zu DESCADDR missverständlich.
Das letzte Byte von DESCADDR ist dann vor der align-Grenze...

Dann ist meine Anfrage damit beantwortet.
Danke nochmal an Alle...

von Philipp Klaus K. (pkk)


Lesenswert?

Jörg W. schrieb:
> Torsten R. schrieb:
>> Oder eben ohne GCC
>
> Das war aber im ${subject} des Threads gefordert.
>
>> Welches C wird den in der Praxis so gesprochen?
>
> Was meinst du damit, welche Version des Standards?
>
> Das dürfte stark von deiner Zielplattform abhängen. Wenn's Microsoft
> ist, dann C89, mit paar Ergänzungen, die sie für würdig befunden haben.
> :)
>
> Embedded: wir benutzen C99/gnu99 derzeit, als Erweiterung gegenüber C89
> dabei vor allem benannte Initialisierung von structs,
> Variablendefinitionen so lokal wie möglich, ggf. variable Argumentliste
> in Makros (bspw. wenn man printf wrappen möchte). Mittlerweile dürfte
> allerdings die Verbreitung C11-tauglicher Compiler gut genug sein, dass
> man auch das nehmen könnte. Habe noch nicht getestet, inwiefern sich
> unsere aktuellen Projekte einfach „upgraden“ ließen.

Microsoft war lange Zeit weit zurück, hat aber inzwischen aufgeholt, und 
unterstützt nun wohl großteils C11.
GCC und LLVM können C17.
IAR kann wohl recht gut C99.
SDCC großteils C17, aber noch mit der ein oder anderen Lücke (und es 
gibt eine experimentellen C2X-Modus, der aber noch keine Attribute 
kann).
Und dann gibt es noch so Nachzügler wie Raisonance für STM8 oder Keil 
für MCS-51, wo es selbst bei C90 große Lücken gibt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.