Was genau bewirkt eigentlich der "-mmcu=xxxx"-Parameter bei
AVR-GCC-Aufrufen? Setzt er lediglich das benötigte Makro (z.B.
"__AVR_ATmega128__"), oder tut er noch mehr?
Hintergrund dieser Betrachtung ist: wenn man eigene Bibliotheken
entwickeln möchte, die nur hardware-unabhängige Funktionen enthalten, so
will man diese Bibliotheken ja für alle AVR-Typen verwenden, die man
einsetzt, bei mir also z.B. ATmega48/88/168, ATmega32/644/644P,
ATmega128, ATmega1280, aber z.B. keine Tiny's.
Ist es dann ratsam, den "-mmcu="-Parameter wegzulassen?
Günter R. wrote:
> Was genau bewirkt eigentlich der "-mmcu=xxxx"-Parameter bei> AVR-GCC-Aufrufen? Setzt er lediglich das benötigte Makro (z.B.> "__AVR_ATmega128__"), oder tut er noch mehr?
Er tut mehr. Er sagt dem Compiler, welcher Befehlssatz zur Verfügung
steht, und sagt dem Linker, welches Linker-Script er verwenden sollte.
> Ist es dann ratsam, den "-mmcu="-Parameter wegzulassen?
Es gibt ein paar Maschinenklassen für die Befehlssatzauswahl, die man
dann in -mmcu=xxx verwenden kann. Bischen im Compiler nachforschen kann
dabei helfen.
Günter R. wrote:
> Du meinst sicher die Sache mit "avr1" ... "avr5"?
Ja. Du kannst dann auch kein #include <avr/io.h> machen (weil die
Bitdefinitionen natürlich nur für einen konkreten AVR zutreffen
können), aber allgemeine Bibliotheken sollte man auf diese Weise
entwickeln können.
Günter R. wrote:
> Was genau bewirkt eigentlich der "-mmcu=xxxx"-Parameter bei> AVR-GCC-Aufrufen? Setzt er lediglich das benötigte Makro (z.B.> "__AVR_ATmega128__"), oder tut er noch mehr?>> Hintergrund dieser Betrachtung ist: wenn man eigene Bibliotheken> entwickeln möchte, die nur hardware-unabhängige Funktionen enthalten, so> will man diese Bibliotheken ja für alle AVR-Typen verwenden, die man> einsetzt, bei mir also z.B. ATmega48/88/168, ATmega32/644/644P,> ATmega128, ATmega1280, aber z.B. keine Tiny's.>> Ist es dann ratsam, den "-mmcu="-Parameter wegzulassen?
Nein, es sollte schon angegeben werden, für welche Familie von Derivaten
übersetzt wird. Ansonsten wird für avr2 übersetzt, also für die Familie
von AVRs, zu der auch AT90S2313 gehört.
Das Setzen von Builtin-Makros wie _AVR_ATmega128_ ist Resultat von
-mmcu. Damit kann in Anwendungen (dazu gehört aus gcc-Sicht in gewisser
Weise auch die avr-libc etc) erkannt werden, um welches Derivat es genau
handelt -- wichtig, um SFR-Adressen definieren zu können und passende
Inline-Assembler Makros zu definieren, etwa für EEPROM-Zugriff,
Sleep-Modes, ...
Darüber hinaus werden noch andere Builtin-Makros gesetzt (oder eben
nicht gesetzt) wie
1
__AVR_HAVE_RAMPZ__
2
__AVR_HAVE_ELPM__
3
__AVR_HAVE_ELPMX__
4
__AVR_HAVE_MOVW__
5
__AVR_HAVE_LPMX__
6
__AVR_ASM_ONLY__
7
__AVR_ENHANCED__
8
__AVR_HAVE_MUL__
9
__AVR_MEGA__
10
__AVR_HAVE_JMP_CALL__
11
__AVR_2_BYTE_PC__
12
__AVR_ARCH__
Intern richtet avr-gcc die Codeerzeugung nach den Fähigkeiten des
Targets aus, die sich zB an den oben beschriebenen Eigenschaften
orientieren.
Diese Eigenschaften unterteilen die AVRs in Familien, die grobkörniger
sind als einzelne AVRs. Diese Familien können auch per -mmcu angegeben
werden:
avr1, avr25, avr2 avr35, avr3, avr31, avr3, avr51, avr5, ...
welche im Makro _AVR_ARCH_ ersichtlich ist:
Die Erstelluung von Bibliotheken aus Sicht von avr-gcc braucht nur diese
Klassen zur Unterscheidung, da dort keine SFRs angesprochen werden. Dies
dient also zur Erstellung der Multilibs, wie sie zB bei WinAVR unter
./avr/lib zu finden sind. avr-gcc selbst hat kein Wissen über
SFR-Adressen, diese stehen in Headern der avr-libc. Das einzige, was er
weiß, ist ob er ein IN/OUT nehmen kann oder ein LDS/STS.
Zur Erzeugung einer HAL-Bibliothek, die zB einen generischen UART
implementiert, reicht die Granulierung per AVR_ARCH nicht aus.
Die angegebene -mmcu Option wird per Specs, also per Kommandozeile, an
die Tools wie as und ld weitergereicht, damit auch die nachgeschalteten
Tools darüber Bescheid wissen, was das Derivat an Befehlen kann und was
nicht, etc.
Zudem wird der Linker darüber informiert, welchen Startup-Code er
hinzulinken soll (crt*.o), und teilweise wird der Linker auch über
-Tdata über die Startadresse einzelner Sections angewiesen. Das crt
selbst wird jedoch erst im Rahmen der avr-libc zur Verfügung gestellt
(./crt1/gcrt1.S) aus dem die unterschiedlichen crt erzeugt werden.
In deinem Falle wird sich der Code zB darin unterscheiden, ob eine
Funktion per CALL oder per RCALL aufgerufen wird, ob es ELP- und RAMPZ
gibt, etc.
Johann
Innerhalb von WinAVR gibt es (u.a.) die Directories "avr3", "avr4" und
"avr5" mit jeweils Bibliotheken "libgcc.a"; man darf dann doch wohl
davon ausgehen, daß es sich hier jeweils um Compilate für die diversen
Prozessor-Architekturen handelt, und daß beim Linken anhand des
mcu-Parameters das richtige Directory ausgewählt wird?
Im Makefile gibt es die Zeilen
MCU = atmega1280 (beispielsweise)
COMMON = -mmcu=$(MCU)
LDFLAGS = $(COMMON)
Genau hier wird wohl dem Linker die Info zugespielt, um welchen
Prozessor es sich handelt, sodaß er sich dann aber selbst das richtige
Directory auswählt? Irgendwo muß es also eine Tabelle geben, wo die
Prozessoren den Architektur-Klassen zugeordnet werden. Ist das die Datei
"specs" und dort die Zeilen "*multilib_matches:"? Dort finde ich Zeilen
wie "mmcu=atmega103 mmcu=avr3".
Ist das die Mechanik, die hier angewandt wird? Wie könnte man das für
eigene Bibliotheken nutzen?
Würde es funktionieren, wenn man seine eigenen Bibliotheken auch in die
Directories "avr3", "avr4", "avr5" schreiben würde?
Günter R. wrote:
> Irgendwo muß es also eine Tabelle geben, wo die> Prozessoren den Architektur-Klassen zugeordnet werden. Ist das die Datei> "specs" und dort die Zeilen "*multilib_matches:"?
Ja, wenn du eine externe specs-Datei hast, dann wird die genommen,
ansonsten gibt es eine entsprechend voreingestellte Tabelle noch
intern eincompiliert.
Ich meinte schon die voreingestellte Tabelle, die auch vom gcc-Linker
verwendet wird; ich würde dann einfach meine eigenen Bibliotheken per
Batch in die entsprechenden Directories ("avr3", "avr4" etc.)
reinkopieren, sonst nichts.
Günter R. wrote:
> Ich meinte schon die voreingestellte Tabelle, die auch vom gcc-Linker> verwendet wird; [...]
Ich auch. Die Aussage oben bezieht sich darauf.
Das Kommando "gcc" ist nur der Compiler-Treiber: er nimmt die
Kommandozeilenargumente entgegen und ruft die einzelnen Backend-
Kommandos auf (cc1, cc1plus, as, ld). Denen gibt er dann die
entsprechenden Argumente mit. Der Linker selbst weiß also nicht,
wo er das suchen sollte; er bekommt das alles haarklein vom
Compiler-Treiber gesagt, und dieser wiederum benutzt dafür die
specs (entweder extern als Datei, oder einen eincompilierten
internen String).
Das kann man alles mit der Option -v verfolgen.
Günter R. wrote:
> Innerhalb von WinAVR gibt es (u.a.) die Directories "avr3", "avr4" und> "avr5" mit jeweils Bibliotheken "libgcc.a"; man darf dann doch wohl> davon ausgehen, daß es sich hier jeweils um Compilate für die diversen> Prozessor-Architekturen handelt, und daß beim Linken anhand des> mcu-Parameters das richtige Directory ausgewählt wird?
Ja, das sind die ober erwähnten Multilibs von avr-gcc. Die libgcc (nicht
zu verwechseln mit der libc) wird für jede Derivatfamilie erzeugt.
> Im Makefile gibt es die Zeilen>> MCU = atmega1280 (beispielsweise)> COMMON = -mmcu=$(MCU)> LDFLAGS = $(COMMON)>> Genau hier wird wohl dem Linker die Info zugespielt, um welchen> Prozessor es sich handelt, sodaß er sich dann aber selbst das richtige> Directory auswählt? Irgendwo muß es also eine Tabelle geben, wo die> Prozessoren den Architektur-Klassen zugeordnet werden. Ist das die Datei> "specs" und dort die Zeilen "*multilib_matches:"? Dort finde ich Zeilen> wie "mmcu=atmega103 mmcu=avr3".
Ja, das geschieht über specs-File bzw. über die Builtin-Specs von
avr-gcc.
Allerding wird man üblicherweise den Linker avr-ld nicht direkt
aufrufen, sondern das Treiberprogramm avr-gcc den Aufruf erzeugen
lassen.
Im Makefile etwa:
1
MCU_TARGET =atmega8
2
CC = avr-gcc -mmcu=$(MCU_TARGET)
3
LD = $(CC)
oder über ähnliche Konstrukte. Damit stimmen dann die Lib-Pfade und auch
das Startup-File crt*.o, das hinzuzulinken ist sowie sonstige Angaben.
Ein nackter ld hat kaum Infos, und die müsste man erst mühsam
zusammentragen.
> Ist das die Mechanik, die hier angewandt wird? Wie könnte man das für> eigene Bibliotheken nutzen?
Was du suchst ist wohl eine Möglichkeit, gegen selbst erstellte
Multilibs zu linken oder sie zu erzeugen?
Ersteres könnte so aussehen (ungetestet):
MY_MULTILIB enthält dann Unterverzeichnisse wie avr2, avr3, etc., welche
die möglichen Multilibs abdecken, d.h. für jedes Derivat, für das gegen
deine Lib zu linken ist, muss für die Derivat-Familie, der es angehört,
eine Ausprägung der Lib existieren.
Zur Erzeugung von Multilibs kann die Info per -print-multi-lib hilfreich
sein.
> Würde es funktionieren, wenn man seine eigenen Bibliotheken auch in die> Directories "avr3", "avr4", "avr5" schreiben würde?
Ja, aber davon würde ich abraten. Ebenso davon, Header in die
Systemverzeichnisse zu mischen, damit sie gefunden werden.
Was du brauchst sollte mit -L, -l nebst -print-multi-directory ohne
eigene specs zu bewerkstelligen sein.
Falls deine Libs feiner granuliert sind als die avr-Multilibs, reicht
das aber nicht mehr aus. Dann musst du explizit im Makefile angeben,
wogegen gelinkt werden muss oder mit specs arbeiten.
Johann
Johann L. wrote:
> Falls deine Libs feiner granuliert sind als die avr-Multilibs, reicht> das aber nicht mehr aus. Dann musst du explizit im Makefile angeben,> wogegen gelinkt werden muss oder mit specs arbeiten.
Dann würde es allerdings wohl Sinn haben, dass man gleich eine Lib
per Device baut und