hallo,
ich möchte aus speichergründen und geschwindigkeitsgründen einige meiner
variablen in registern ablegen. Zusaetzlich bringt das ja noch mehr
Geschwindigkeit.
das habe ich in einem projekt entdeckt.
1
registeruint8_tvolatileposasm("r3");//8Bit Variable pos in Register r3
2
registeruint16_tvolatilewartezeitasm("r4");//16Bit Varibale in Register r4:r5
3
registeruint8_tvolatiledelta_pos1asm("r6");//delta_pos zur Verschiebung in Register r6
4
registeruint8_tvolatiledelta_posasm("r7");//delta_pos1 bei Neustart der LAufschrift in r7
5
registeruint16_tvolatile_sizeasm("r8");//16Bit Variable _size in Register r8:r9
6
registeruint8_tvolatile_laufschriftasm("r12");//_laufschrift in Register r12
das ganze habe ich für meinen fall angepasst
z.B. mit diesen registen
in dieser Variante
1
registervolatileuint8_tnextasm("r3");
2
registervolatileuint8_tiasm("r4");
3
registervolatileuint16_tsecondsasm("r5");//soll r5:r6 sein
und in diese Schreibweise
1
registeruint8_tvolatilenextasm("r3");
2
registeruint8_tvolatileiasm("r4");
3
registeruint16_tvolatilesecondsasm("r5");//soll r5:r6 sein
allerdings funktioniert das bei mir nicht so ganz.
ich erhalte eine compiler fehlermeldung:
GenericHID.c:95: error: expected '=', ',', ';', 'asm' or '__attribute__'
before 'asm'
GenericHID.c:96: error: expected '=', ',', ';', 'asm' or '__attribute__'
before 'asm'
GenericHID.c:97: error: expected '=', ',', ';', 'asm' or '__attribute__'
before 'asm'
was muss ich aendern, damit es wie im anderen Projekt funktioniert?
fehlt mir evtl. ne header Datei die ich inkludieren muss?
danke im voraus für jede Antwort
delicious_cake
delicious_cake schrieb:> ich möchte aus speichergründen und geschwindigkeitsgründen einige meiner> variablen in registern ablegen.
Bei solchen Vorhaben gibt es eine Standard-Gegenfrage:
Warum?
delicious_cake schrieb:> was muss ich aendern, damit es wie im anderen Projekt funktioniert?
Du solltest den Compiler benutzen, der das "andere Projekt" fehlerfrei
kompilieren kann.
Oliver
Oliver schrieb:> Warum?
der verfügbare sram ist aus. bzw. muss was für den heap übrig bleiben.
sonst kommts zu fehlern.
Oliver schrieb:> Du solltest den Compiler benutzen, der das "andere Projekt" fehlerfrei> kompilieren kann.
ne sinnlosere antwort hab ich noch nie bekommen. ich habe beide auf
meinem rechner kompiliert.
delicious_cake schrieb:> ich möchte aus speichergründen und geschwindigkeitsgründen einige meiner> variablen in registern ablegen. Zusaetzlich bringt das ja noch mehr> Geschwindigkeit.
Wenn es optimal läuft vielleicht.
Im schlechten Fall behindert deine "Optimierung" den Compiler. Es fehlen
dem dann die Arbeitsregister und der Restcode wird durch zusätzliche
Push/Pops speichermäßig (Stack) aufgebläht und verlangsamt.
> der verfügbare sram ist aus. bzw. muss was für den heap übrig bleiben.> sonst kommts zu fehlern.
Wurde der Code bereits kritisch angesehen? Konstante Daten auslagern
(Flash), Datentypen kritisch hinterfragen und globale Variablen
reduzieren?
Stefan B. schrieb:> Wurde der Code bereits kritisch angesehen?
ich habe den lufa usb stack eingebunden. der bindet mir ziehmlich die
haende. fast 50% des srams gehen dabei für den stack und den heap drauf.
jetzt will ich halt in die nicht verwendeten register, vor allen die
general purpose register auslagern. im vergleich zur unoptimierten
variante meines programms habe ich bereits 25% sram frei bekommen.
kann mir endlich jemand sagen wie ich den fehler beim compilieren
beheben kann?
delicious_cake schrieb:> kann mir endlich jemand sagen wie ich den fehler beim compilieren> beheben kann?
vergiss es einfach.
Dem Compiler bei der Registerbelegung ins Handwerk zu pfuschen ist eine
extrem schlechte Idee, die schief geht sobald dein Code mehr als sagen
wir mal 10 Zeilen C Code umfasst.
Du tust dir damit nichts gutes.
Löse deine Probleme richtig und spekuliere nicht damit, dass du schlauer
bist als dein Compilerbauer. Du bist es nicht (und ich auch nicht)
> Zusaetzlich bringt das ja noch mehr Geschwindigkeit.
Der Schuss geht mit an Sicherheit grenzender Wahrscheinlichkeit sowieso
nach hinten los.
Und ob du weniger Speicher verbrauchst ist auch fraglich.
Jedes Register, das du fix belegst, kann dazu führen, dass der Compiler
bei Berechnungen Zwischenergebnisse anstelle von in Registern, auf dem
Stack zwischenparken muss.
Mal ganz davon abgesehen, dass du dann auch die komplette
Runtime-Library neu übersetzen musst. Diese Funktionen müssen ja
schliesslich auch wissen, dass diese Register nicht mehr zur Verfügung
stehen.
Das Schlüsselwort 'register' hatte mal seie Berechtigung. Die Zeiten
sind aber lange vorbei. Und das fixe Binden von Variablen an Register
macht bis auf Micky Maus Programme, die keine Standard-Library benutzen,
keinen oder kaum Sinn.
delicious_cake schrieb:>> Du solltest den Compiler benutzen, der das "andere Projekt" fehlerfrei>> kompilieren kann.>> ne sinnlosere antwort hab ich noch nie bekommen. ich habe beide auf> meinem rechner kompiliert.
Kompiliert hast du dein Projekt nicht, das lässt sich ja nicht
kompilieren. Wenn das "andere Projekt" sich kompilieren lässt, musst du
da halt richtig abschreiben.
Eigentlich hat Karl Heinz ja schon alles dazu gesagt. Ergänzend kann man
noch, daß der gcc "register volatile" sowieso nicht versteht, insofern
ist selbst bei fehlerfreier Kompilierbarkeit deines "anderen Projekts"
dessen Funktion mehr als fraglich.
Beitrag "Variable an Register binden - ich kanns nicht oder compilerbug :)"
Oliver
erst mal danke für die antworten. mittlerweile hab ich mich in die
problematik der optimierung eingelesen und verstehe auch warum dass mit
den registern nicht in allen faellen besonders ratsam ist.
jedenfalls geht mir der ram aus und ich brauche ne möglichkeit etwas
davon frei zu kriegen. in diesem anderen Projekt ist dadurch ein
erheblicher Geschwindigkeitsschub gelungen. Mein Projekt und das andere
sind sehr aehnlich, deshalb dachte ich es waere einen versuch wert die
gp register zu benutzen. wenn ich mein programm im simulator lange
laufen lasse und dabei verschiede aktionen durchführe bleiben 11
register unveraendert. diese könnten denke ich also verwendet werden.
und wenn nich gut hinhaut, dann halt nicht. dann muss ich mir was
anderes suchen.
ich habs jetzt hinbekommen. ich habe dazu ein paar compiler optionen
setzen müssen.
## Compile options common for all C compilation units.
CFLAGS = $(COMMON)
CFLAGS += -D AVRGCC -Wall -gdwarf-2 -Os -fsigned-char
CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d
CFLAGS +=-std=gnu99
delicious_cake schrieb:> ich habs jetzt hinbekommen.
Hast du denn auch mal im generierten Assembler-Listing überprüft, ob der
Compiler auch das macht, was du gerne hättest?
Oliver
ja, es funktioniert alles wie es sollte. ich hab zum testen mal schnell
die variablen in register gelegt die am öftesten verwendet werden.
bisher nur insgesamt 4 Byte, aber die ausführungszeit hat sich erheblich
verbessert.
Das erstaunt mich. Waren die vielleicht auch schon davor volatile, aber
es wurde sehr oft darauf zugegriffen? Das sollte man nicht nur aus
Performancegründen vermeiden.
Rolf Magnus schrieb:> Waren die vielleicht auch schon davor volatile, aber> es wurde sehr oft darauf zugegriffen?
ja die waren vorher schon volatile, und ja es wird sehr oft darauf
zugegriffen. deshalb wollte ich die ja stetig im register halten.
An vielen Stellen reicht es für gewöhnlich, die Variable in eine lokale
variable zu kopieren und damit zu arbeiten. Das hat auch den Vorteil,
daß dann zusammengehörende Zugriffe mit dem selben Wert arbeiten und
nicht evtl. mit verschiedenen, weil sich der Wert zwischendrin geändert
hat.
Auch bei deinen 16-Bit-Werten wirst du dich nochmal speziell darum
kümmern müssen, weil da schon ein einzelner Zugriff nicht atomar ist,
egal ob auf Speicher oder Register.
(1)
Es ist sinnlos, Register volatile zu machen (zumindest für GCC). GCC hat
intern überhaupt nicht die Möglichleit, ein Register (GPR) als volatile
zu markieren. Wer's nicht glaubt lese gcc/rtl.def :-)
(2)
16-Bit-Variablen müssen in geraden GPR-Nummern liegen bzw. anfangen
(3)
Es wird mindestend stdint.h benötigt
(4)
Die Fehler treten in Zeile 95-97 auf. Oben sind 3 Zeilen gepostet. U.U
fehlt einfach in Zeile 42 irgendwo ne Klammer o.ä.
(5)
Wer sich mit sochen Features nicht auskennt (siehe (2)) dem fliegt der
Code über kurz oder Lang um die Ohren. Dann suchst die nen Wolf. Oder
zwei oder drei. Etwa bei Verwendung von STandard-Bibliotheken,
Interrupts, etc. GCC kann globale Register wegoptimieren . So gesehen
in GCC 4.x, wo es als tot analysiert wurde (was es im Sinne von C auch
war, da es asynchron verwendet werden sollte. Da solche Regs jedoch
nicht volatile sind bzw. das wirkungslos ist, muss man Hacks einfügen,
die der Code weder hübscher noch besser wartbar, verständlicher oder
portierbarer machen.
(6)
Die "Optimierung" wird nicht viel bringen. Diese Register sind
eingeschränkt, was ihren Funktionsumfang angeht. Wenn du zB 42 in ein
solches Register laden willst, wird die 42 in ein oberes GPR geladen und
von dort verschoben.
(7)
Wenn der Speicher voll ist, bringt es nix, blindlinks Hacks einzufügen.
Als erstes muss untersucht werden, wo die Speicherfresser sind. Es ist
zwecklos eine Variable wie i, die wohl nur eine Laufvariable ist, die eh
in einem GPR lebt.