Forum: Compiler & IDEs Tricks, wie ich mein Compilat kleiner kriege


von Jörg (Gast)


Lesenswert?

Hallo,

mein aktuelles Hobbyprojekt für einen Mega8 drohte über die 
Flash-Kapazität hinauszuwachsen, 6 KB in meinem Fall, denn 2 KB gehen 
für meinen Bootloader drauf. Nach ein paar Maßnamen paßt es nun aber 
wieder komfortabel hinein, ich will hier mal meine Erfahrungen teilen.

Ausganspunkt war "normaler" Embedded-Code, schon ziemlich dicht codiert, 
das ist nichts Neues für mich, damit verdiene ich auch mein Geld. Nichts 
speziell auf Größenoptimierung "verunstaltet" (jeden gemeinsamen Fitzel 
Code in eine Unterfunktion o.Ä.). Das habe ich auch in Folge nicht 
getan. Keine üblichen "Anfängerfehler" drin, keine floats, printf's, 
unnötige Libs, malloc, Strings, etc. Immer schön ins map-File gucken, ob 
man die aufgeführten Library-Funktionen auch wirklich haben wollte.

- gcc v4.1.1 versus v3.4.6: meistens ist der alte Compiler besser, in 
meinem Fall momentan um 40 Byte. Den Bootloader hingegen macht gcc 4.1.1 
kleiner. Hilft mir in dem Fall aber nicht, unter die nächste Grenze von 
1KB kriege ich den nie.

- Nullinitialisierung von statischen Variablen: Bisher hatte ich in 
meinen Init-Funktionen nicht auf den Startup-Code verlassen, sondern die 
nötigen Variablen genullt. So kann ich auch eine Re-Initialisierung 
machen, habe aber keinen Gebrauch davon gemacht. Stattdessen starte ich 
komplett neu. Entfernung Null-Inits brachte einiges. (OK, kann man doch 
als Anfängerfehler bezeichnen, ich mußte erst im C-Standard nachlesen 
daß das BSS-Nullen keine Eigenart von gcc ist.)

- statische (globale) Variablen in ein struct sammeln: Das erleichtert 
dem Compiler die Adressierung, da er den Basiszeiger wiederverwenden 
kann. Finde ich aber schwach, daß der Compiler sich das nicht selbst 
passend hinlegt. Die Codegröße kann dann noch von der Reihenfolge der 
struct-Member abhängen Die häufigst benutzte Variable sollte am Anfang 
stehen, dann kann sie ohne Offset direkt mit dem Basiszeiger adressiert 
werden. Ansonsten in Gruppen, wie die Variablen auch gebraucht werden. 
Hier kann man viel rumprobieren...

- Multiplikationen mit Konstanten: der Compiler instanziiert sofort eine 
teure allgemeine Bibliotheksfunktion, auch wenn es anders ginge. Ich 
hatte eine einzige 32-bit Multiplikation mit 10 drin, die mir ein mulsi3 
beschert hat. Mit a = b<<3 + b<<1 geht es in dem Fall kürzer. Wie 
gesagt, map-File beobachten.

- alle Variablen nur so breit wie nötig: Hatte ich eigentlich schon, nur 
an einigen wenigen Stellen war ich da etwas nachlässig. Mitunter reicht 
ein kleinerer Typ doch, wenn man z.B. vorher geeignet skaliert. Am 
besten nur die skalaren Typen aus <stdint.h> verwenden, das erleichtert 
auch das Folgende.

- logische Operatoren werden auf int-Größe erweitert: Trotz 8-bit Target 
ist der AVR-gcc 16-bittig drauf. Für a = ~b wird die eigentliche 
Negationsoperation 16-bittig ausgeführt, obwohl beide als uint8_t 
definiert sind! Ziemlich blöd, mit einem cast dazwische wird's kleiner: 
a = (uint8_t)~b. Dasselbe gilt für & und |, habe ich aber nicht mehr mit 
casts ausprobiert.

- Compileroption -mint8 für 8-Bit Arithmetik als Default: Mit obigen 
casts überall sähe der Code ziemlich schlimm aus. Blöd auch, wenn man 
mal einen Type ändert, dann muß man sorgsam nach den zugehörigen casts 
suchen. Mit dem Compilerschalter -mint8 wird das zum Standard. Bei mir 
hat das etwa 200 Byte gespart! Man sollte dafür aber keine ints mehr im 
Code haben, nur noch Typen definierter Größe aus <stdint.h>. 
Literal-Werte muß man ggf. anpassen (z.B. mit postfix L long machen) 
damit sie nicht überlaufen, Compiler-Warnings beachten.  Ist anscheinend 
noch etwas experimentell(?), mit dem aktuellen gcc 4.1.1 geht es nicht, 
der kriegt ein Problem mit den 64-bit Typen. Ist aber wohl in Arbeit, 
ich habe einen Patch gesehen.

- ein paar Schlagworte habe ich noch, die aber nicht zur Anwendung 
kamen: -ffreestanding, soll noch ein pragma für main() geben welches 
Prolog/Epilog kappt, vielleicht kann man die Vektortabelle beschneiden.

Wenn ich noch was vergessen habe schreib' ich ein Follow-Up. Fühlt Euch 
frei, selbst Tricks und Kommentare anzumerken.  ;-)

von Wolfgang Horn (Gast)


Lesenswert?

Hi, Jörg,

Danke.

Wolfgang Horn

von D. H. (slyd)


Lesenswert?

> statische (globale) Variablen in ein struct sammeln

wusste ich schon - aber das es auf die Reihenfolge ankommt war mir neu!
Danke! :)



Die Unterschiede vom GCC 3.4.6 zum 4.1.1 kommen oft von inline 
Funktionen die eigentlich gar nicht geinlined werden sollen ;)

Mit nem prototyp wie:
void xyz(uint16_t param) __attribute__((noinline));

kann man das manuell verhindern.
Spart oft ein paar Bytes - war bei einem Bootloader von mir extrem 
ausgeprägt im Vergleich zur alten GCC Version...

Dann noch der Prolog in der Main Funktion - da kommen seit neuestem ja 
ne ganze Menge pushs und anderes dazu... mit einem 
__attribute__((noreturn)) kann man zumindest ein wenig davon abschalten.

MfG,
Dominik

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


Lesenswert?

Dominik s. Herwald wrote:

> Mit nem prototyp wie:
> void xyz(uint16_t param) __attribute__((noinline));
>
> kann man das manuell verhindern.
> Spart oft ein paar Bytes ...

Erstmal als "static" deklarieren, vielleicht spart ja dann das Inlining
sogar noch mehr Bytes?

Der rechnet sich nämlich eigentlich aus, wie viel es spart.  Sofern er
sich dabei bei nicht-inline-asm-Code verrechnet, darf man dafür auch
gern Bugreports schreiben.  Nur bei inline asm ist es sinnlos, da gibt
es keine Methode, dem Compiler mitzuteilen, dass sich darin mehr als
ein Prozessorbefehl versteckt.

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


Lesenswert?

Jörg wrote:

> - statische (globale) Variablen in ein struct sammeln: Das
> erleichtert dem Compiler die Adressierung, da er den Basiszeiger
> wiederverwenden kann. Finde ich aber schwach, daß der Compiler sich
> das nicht selbst passend hinlegt.

Wenn du drüber nachdenkst wüsstest du, warum er das nicht kann.

Globale Variablen bekommen erst vom Linker eine Zuweisung der Adresse
verpasst.  Damit ist es erst der, der das sortiert.  Folglich kann
sich der Compiler nicht einfach die Adresse von irgendeiner Variablen
benutzen und dann einen Offset dazu errechnen, um andere Variablen zu
erreichen.

von Trog (Gast)


Lesenswert?

Toent vielleicht trivial, aber irgendwan kann man bei gleicher Groesse 
die Funktionalitaet nicht mehr verdoppeln, wird einen groesseren Chip 
benoetigen. Meist gibt es ja Baugleiche. Der Mega8 ist ja eher von der 
kleinen Sorte.

von Giradeli (Gast)


Lesenswert?

@Trog
Was willst du uns damit sagen? :D

von Thomas (Gast)


Lesenswert?

Ich habe die Texte mal in einem neuen Wiki-Artikel eingefügt:

http://www.mikrocontroller.net/articles/AVR-GCC-Codeoptimierung

Ich finde das schon interessant, und ein Thread verschwindet ja schnell 
wieder im Archiv.

von Jörg (Gast)


Angehängte Dateien:

Lesenswert?

Zwischendurch mal danke für die Anmerkungen und den Wiki-Artikel, sowas 
schwebte mir auch vor, habe ich hier nur noch nie gemacht, bin recht neu 
hier.  ;-)
Vielleicht sollte ich mich mal anmelden.

Mittlerweile habe ich noch das Compileflag -mtiny-stack entdeckt, das 
hat nochmal ca. 100 Byte gebracht. (Meine Güte, was fange ich nur an mit 
all dem freigewordenen Platz... ;-)
Mit 256 Bytes Stack sollte ich auskommen, denke ich. Die meisten meiner 
Variablen sind static und modul-global, statische Zustandsvariablen, nur 
wenig automatische. Verschachtelungstiefe ist auch nicht so wild, selbst 
mit Interrupts. Gibt es eine Möglichkeit, das zu testen?

Ich habe den Header <stdint.h> für -mint8 und gcc 4.1.1 "repariert", 
siehe Anhang, damit klappts. Das Flag wird in dem Header zwar schon 
korrekt berücksichtigt, aber die 64bit-Typen müssen in dem Fall wohl 
raus, die kann der Compiler dann nicht mehr.

__attribute__((noreturn)) für main() habe ich irgendwie nicht 
hinbekommen. Der Compiler motzt am Funktionsende, ich hätte ein return, 
habe ich aber auskommentiert. Ein for(;;) am Ende von main() scheint als 
Hinweis an den Compiler den gleichen Zweck erfüllen, damit wird es 
jedenfalls 4 Byte kürzer.

@dl8dtl:
>Wenn du drüber nachdenkst wüsstest du, warum er das nicht kann.
>Globale Variablen bekommen erst vom Linker eine Zuweisung
>der Adresse verpasst.
Schon, aber das waren keine übergreifend globalen Variablen, sondern 
statics, nur für dieses Modul. Da könnte der Compile vielleicht doch 
selbst... Naja, ich will mich nicht zu sehr als ahnungslos outen.

@Trog:
Das Design steht fest, es gibt einige Stück davon. Der Code ist auch 
praktisch fertig, es kommen keine Features mehr hinzu, nur noch Bugfixes 
und sonstige Pflege. Es paßt ja auch gut rein, wie man sieht, wenn man 
sich etwas Mühe gibt. Der Mega8 ist für meine Anwendung prima, alles 
andere wäre Verschwendung.

vorläufige Zusammenfassung:
Die bisher genanntem Maßnamen haben meinen Code von 6482 auf 5696 Byte 
verkleinert, das sind ca. 12%! Ich konnte ein paar Luxusfeatures wieder 
einschalten, die ich zuvor rausnehmen mußte um unter 6 KB zu kommen. Den 
Code selbst habe ich kaum verändert, nur die Inits und ein ganz paar zu 
große Typen. Ist immer noch alles sauber und lesbar, imho. Ich bin 
zufrieden und habe was gelernt.  :-)

Noch eine Frage zum Schluß: kann man die .lst Files "schöner" bekommen, 
möglichst mit eingestreutem C-Code? Mit der neuen global-struct taucht 
nur noch diese auf, vorher gaben zumindest die Variablennamen einen 
Hinweis, wo man gerade ist. Ich hätte gern mehr Feedback, was der 
Compiler im Einzelnen so aus meinen Statements macht.


von Thomas (Gast)


Lesenswert?

> logische Operatoren werden auf int-Größe erweitert: Trotz 8-bit Target
> ist der AVR-gcc 16-bittig drauf. Für a = ~b wird die eigentliche
> Negationsoperation 16-bittig ausgeführt, obwohl beide als uint8_t
> definiert sind! Ziemlich blöd, mit einem cast dazwische wird's kleiner:
> a = (uint8_t)~b. Dasselbe gilt für & und |, habe ich aber nicht mehr mit
> casts ausprobiert.

Habe gerade mal versucht das nachzuvollziehen, konnte jedoch keine 
Unterschiede feststellen.
Der GCC 3.4.6 macht in beiden fällen ein:
1
****   a =  ~b;
2
mov r25,r24
3
com r25

In welchem Fall ist das bei dir aufgetreten?

von Jörg (Gast)


Lesenswert?

>In welchem Fall ist das bei dir aufgetreten?

Hab's grad noch mal ausprobiert, bei fast allen Negationen in meinem 
Code ist es tatsächlich egal. Bis auf eine, und da kostet es auf einmal 
12 Bytes(?):
1
static void set_output(unsigned char new_lines)
2
{
3
    if (new_lines == global_lines)
4
    {
5
        return; // nothing to do
6
    }
7
8
    if (new_lines & (unsigned char)~global_lines) // new set bit(s)?
9
    {
10
       // do something
11
    }
12
13
   // do more stuff
14
}
Allgemein liegt der Hase wohl schon in derartigem Pfeffer, sonst wäre 
-mint8 ja nicht so der Bringer bei mir, wo ich alle Typen in der Größe 
festgenagelt habe.

von Thomas (Gast)


Lesenswert?

Das scheint der Compiler auch nur zu machen, wenn die Verknüpfung in 
einer if-Abfrage stattfindet. Aber warum?
Wenn ich das mit einer zusätzlichen Variable mache wird es auch nicht 
auf 16-Bit aufgebläht:
1
void foo(uint8_t a, uint8_t b)
2
{
3
  uint8_t x;
4
  if (a == b)
5
    PORTC = 1;
6
  x = ~b;
7
  if (a == x)
8
    PORTC = 0;
9
}

von Uhu U. (uhu)


Lesenswert?

Sieht stark danach aus, daß da eine Artanpassungsregel greift: if 
erwartet einen Ausdruck vom Typ int, also werden die Operanden, aus 
denen der Ausdruck berechnet werden soll, auf int erweitert.

von Jörg (Gast)


Lesenswert?

Vielleicht, weil die Bedingung in einem if() als int bewertet wird.

von D. H. (slyd)


Lesenswert?

@Jörg Wunsch:

Die Funktionen static zu machen hat nur bei der hier:
1
void putch(char ch)
2
{
3
    while (!(UCSRA & (1<<UDRE)));
4
    UDR = ch;
5
}

8 Bytes gebracht. Bei den delays brachte das nix.

noinline brachte aber bei der Funktion oben ganze 46 Bytes für den 
Bootloader bei -Os.
Ähnlich verhält es sich bei einer einfachen delay Funktion - da ist 
sogar genau ein inline assembler Befehl drin - ein nop weil sonst die 
ganze delay Schleife wegoptimiert werden würde ;)

Die anderen Funktionen die ein bisschen größer sind, werden für -Os 
richtig behandelt und NICHT geinlined. Passiert eigentlich bei mir 
bisher nur bei sehr kleinen Funktionen mit zwei drei Zeilen wie die 
oben.

Beim alten GCC 3.4.6 brauchte ich das nicht als noinline zu deklarieren 
der hat es gleich so gemacht wie vorgesehen.

Eine ähnliche Diskussion war ja schonmal vor kurzem hier:
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=46152

Naja zumindest bevor der der Thread auf Seite 2 etwas Offtopic wurde ;)

MfG,
Dominik

von A.K. (Gast)


Lesenswert?

Manchmal ist ein vermeintliches Optimierungsproblem einfach nur ein 
Programmierfehler. Denn (~b) ist nicht etwa (b ^ 0xFF) sondern ((b & 
0x00FF) ^ 0xFFFF) und hat folglich den Wertebereich 0xFF00-0xFFFF. Der 
Vergleich mit (a) wird also stets falsch sein.

von Jörg (Gast)


Lesenswert?

> Denn (~b) ist nicht etwa (b ^ 0xFF) sondern
> ((b & 0x00FF) ^ 0xFFFF) und hat folglich den Wertebereich
> 0xFF00-0xFFFF. Der Vergleich mit (a) wird also stets falsch sein.

Na, das wäre aber böse, dann würde bei mir wohl etliches nicht 
funktionieren.
Ich hantiere hier viel mit 8bit-Werten und entsprechenden Masken.
Werd' aber noch in den Assemblercode gucken, das war bisher noch nicht 
so mein Ding.

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


Lesenswert?

Dominik s. Herwald wrote:

> Ähnlich verhält es sich bei einer einfachen delay Funktion - da ist
> sogar genau ein inline assembler Befehl drin - ein nop weil sonst
> die ganze delay Schleife wegoptimiert werden würde ;)

Nimm <util/delay.h> dafür.

> Passiert eigentlich bei mir bisher nur bei sehr kleinen Funktionen
> mit zwei drei Zeilen wie die oben.

Wie geschrieben, wenn du Fälle hast, wo sich GCC ernsthaft verrechnet
und garantiert kein inline-asm drin ist (auch nicht aus der avr-libc),
dann schreib einen Bugreport für GCC.

Das AVR-Target kann von den GCC-Entwicklern mangels einer geeigneten
Testumgebung nicht getestet werden.  Damit kann dort keiner merken,
wenn auf dem AVR eine bestimmte Optimierung sich in das Gegenteil
verkehrt: für die Architekturen, die sie prüfen können, wird nämlich
sehr wohl (automatisiert) geprüft, ob eine bestimmte Optimierung
Nachteile bringt.

Ob da inline-asm-Code drin ist, kannst du im vom Compiler generierten
Assemblercode (das ist nicht der Disassembler-Code!) schnell
feststellen, indem du nach den Kommentaren /* APP */ ... /* NOAPP */
guckst.  Den Assemblercode für eine Datei foo.c erhälst du (bei
passend gestaltetem Makefile, z. B. dem von WinAVR) durch »make foo.s«.

> Beim alten GCC 3.4.6 brauchte ich das nicht als noinline zu
> deklarieren der hat es gleich so gemacht wie vorgesehen.

Der konnte automatisches Inlining nur bei Optimierung auf
Geschwindigkeit (-O3), nicht bei Optimierung auf Platz -- obwohl es
eben auch durchaus Platzeinsparungen bringen kann.

von A.K. (Gast)


Lesenswert?

Hinsichtlich unerwünschter Inlines hat sich bei mir auch schon mal
-finline-limit=1 als nützlich erwiesen.

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


Lesenswert?

Jörg wrote:

> Mittlerweile habe ich noch das Compileflag -mtiny-stack entdeckt, ...

> Mit 256 Bytes Stack sollte ich auskommen, denke ich. ...

Du hast weniger Stack.

Der Stackpointer wird beim ATmega8 auf 0x45F initialisiert.  Da
-mtiny-stack nur SPL manipuliert, ist die niedrigstmögliche Adresse,
die du auf dem Stack nutzen kannst, 0x400.  Du hast also nur 96 Bytes
Stack.

Eine ziemlich gefährliche Option, wie ich finde.  Du könntest dich
noch rausretten, indem du den Stack woanders hin verlagerst, aber dann
verplemperst du unweigerlich RAM stattdessen.

Ich stimme mit denjenigen hier überein, die bei derartig knapper
Reserve lieber zum nächstgrößeren Controller raten würden, vor allem,
falls spätere Bugfixes ,,im Feld'' notwendig sein könnten.  Dann
lieber gleich das ganze Design auf einen ATmega168 hochziehen.  Aber
das ist natürlich deine Entscheidung.

> Ich habe den Header <stdint.h> für -mint8 und gcc 4.1.1 "repariert",
> siehe Anhang, damit klappts.

Das kannst du gern mal als Bugreport für avr-libc einreichen und dann
dort einen Patch mit reinlegen.  Bitte nicht das ganze File, sondern
die Ausgabe von "diff -u" zwischen altem und neuem File.  Allerdings
hast du noch einen Fehler drin: Typen wie intmax_t und uintmax_t
sollte es auch bei -mint8 auf jeden Fall geben.  Die müssen dann nur
Aliase auf die entsprechenden 32-bit-Typen sein.

-mint8 ist aber ansonsten eine mindestens genauso gefährliche Option
with -mtiny-stack.  Alle Funktionen der Standardbibliothek gehen von
16-bit-int aus, und praktisch können sie auch gar nicht anders.  Diese
Option hat also nur dann wirklich Sinn, wenn man keinerlei Dinge aus
der Bibliothek benutzt.

von D. H. (slyd)


Lesenswert?

> Nimm <util/delay.h> dafür.

ja das wäre eine Idee - werde ich wohl auch mal tun.



Zu dem Verrechnen - da müsste ich mal nen kleinen Beispielcode 
zusammenstellen. Aber ob sich das dann noch genauso verhält wie im 
großen Programm weiss ich nicht.

Den Code der betreffenden Applikation darf ich leider so nicht 
rausgeben...

Aber in der kleinen Funktion da oben:
Beitrag "Re: Tricks, wie ich mein Compilat kleiner kriege"

ist wohl kein inline ASM drin - auch nichts aus der avr-libc - 
jedenfalls seh ich da nichts ;)

MfG,
Dominik

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


Lesenswert?

Dominik s. Herwald wrote:

> Den Code der betreffenden Applikation darf ich leider so nicht
> rausgeben...

Dann kürze ihn soweit ein und anonymisiere das entsprechend, dass
du ihn rausgeben kannst.  Wenn du nachweisen kannst, dass das
Inlining überhaupt in einer Konstellation Platz verschwendet trotz
-Os, dann ist es den Bugreport wert.

von D. H. (slyd)


Angehängte Dateien:

Lesenswert?

Hallo Jörg,

hmm das habe ich gerade mal mit einem Minimalbeispiel ausprobiert - 
hätte ich zwar nicht gedacht, aber da passierts auch:
1
#include <avr/io.h>
2
3
// void putch(char ch) __attribute__((noinline));
4
5
void putch(char ch)
6
{
7
  while (!(UCSRA & (1<<UDRE)));
8
  UDR = ch;
9
}
10
11
int main(void)
12
{
13
  putch(0); 
14
  putch(1); 
15
  putch(2); 
16
  putch(3);
17
  putch(4); 
18
  putch(5); 
19
  putch(6);
20
  putch(7);
21
  putch(8);
22
  putch(9);
23
  
24
  return 0;
25
}

Mit -Os (makefile von WinAVR... ) sind das 234 Bytes.

Wenn man in der Zeile
// void putch(char ch) __attribute__((noinline));
die Kommentarzeichen entfernt, sinds nur 216 Bytes!

s. Anhang.

Oder ist das nur bei mir so?

MfG,
Dominik

von Jörg (Gast)


Lesenswert?

@Jörg Wunsch:
Vielen Dank für die Anmerkungen zu -mint8 und -mtiny-stack.

-mtiny-stack
Hielt ich bisher für die ungefährlichere Option... Ich wollte auch noch 
danach fragen, ob der Stack an einer passenden Grenze steht, bzw. stehen 
muß, nun ist die Antwort schon vorher da. ;-)
Wo kommt die 0x45F her, warum so "krumm"? Ich habe in das 
ldscripts-Verzeichnis mal oberflächlich reingeschaut und nicht viel 
verstanden. RAM habe ich mehr als genug, von daher wäre es kein Nachteil 
den Stack umzusetzen. Wie ginge das?

-mint8
Ich sehe da 2 "Issues".
1) Die Standardbibliothek ist bereits kompiliert, in den Funktionen 
sollte es intern also keine Probleme geben, sondern "nur" an den 
Interfaces; immer dann wenn Typen wie int oder long übergeben werden, 
die dann in der Größe anders sind. Daran müßte man es doch erkennen 
können? Ich verwende aus den Libs nur EEPROM- und Watchdogfunktionen, 
die scheinen in Ordnung zu sein.
2) Das andere Problem ist, daß der Compiler bei Konstanten nur noch 
16bittig rechnet, auch wenn sie mit UL Postfix versehen sind. Man müßte 
sie auf uint32_t casten. F_CPU ist so ein Beispiel, daraus errechnete 
Werte für Baudraten- oder Timerregister gehen schief.
Ich traue mich noch nicht, -mint8 wirklich zu verwenden, müßte zu viel 
neu testen.

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


Lesenswert?

(Dominiks Beispiel)

Ja, das sieht stichhaltig aus.  Funktioniert auch noch, wenn man die
Funktion static macht.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31528

Kannst dich ja als Cc drauf setzen, wenn du möchtest (oder mir deine
email-Adresse mailen, dann setze ich dich drauf).

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


Lesenswert?

Jörg wrote:

> Wo kommt die 0x45F her, warum so "krumm"?

Es ist das Ende des RAMs auf deinem ATmega8.

Andere AVRs haben andere RAM-Aufteilung, da könntest du mehr Glück
haben.

> RAM habe ich mehr als genug, von daher wäre es kein Nachteil
> den Stack umzusetzen. Wie ginge das?

Es müsste genügen, auf der Linker-Kommandozeile den Wert des Symbols
__stack zu setzen.  Das kann man mit der Option --defsym, der man bei
der Übergabe durch den Compilertreiber noch ein -Wl, voranstellen
muss.  Dabei den Offset 0x800000 für den RAM nicht vergessen, also
zum Beispiel
1
-Wl,--defsym=__stack=0x8003ff

Der RAM oberhalb 0x400 (bis 0x45f) ist damit praktisch erst einmal
nicht mehr benutzbar.

> 2) Das andere Problem ist, daß der Compiler bei Konstanten nur noch
> 16bittig rechnet, auch wenn sie mit UL Postfix versehen sind. Man
> müßte sie auf uint32_t casten.

ULL benutzen.

von Jörg (Gast)


Lesenswert?

Super Tipps, probiere ich aus, danke!

von D. H. (slyd)


Lesenswert?

@Jörg Wunsch

Du hast Post!
Extra anmelden wollte ich mich wegen der "Kleinigkeit" eigentlich nicht.

MfG,
Dominik

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


Lesenswert?

Dominik s. Herwald wrote:

> Extra anmelden wollte ich mich wegen der "Kleinigkeit" eigentlich nicht.

Hmpf.  Man kann da nur die email-Adressen von Leuten eintragen, die
angemeldet sind.

Aber anmelden kost nüscht, und du erwirbst damit das Recht, eigene
Kommentare zu anderen Bugreports hinzuzufügen. ;-)

von D. H. (slyd)


Lesenswert?

OK hast mich überzeugt ;)
Habe mich mal angemeldet.

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


Lesenswert?

Dominik s. Herwald wrote:

> Habe mich mal angemeldet.

Ja, hat mir der Bugzilla schon gepetzt. ;-)

Da sich das sogar auf i386 nachweisen lässt, haben wir vielleicht
gar nicht so schlechte Karten, dass sich da einer drum kümmert.

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.