Hi!
Ich programmiere erst seit gestern mit WinAVR in neuster Version, vorher
habe ich so einige Projekte in Assembler realisiert, aber ich wollte mir
das Leben auch mal einfacher & übersichtlicher gestalten ;-) Deshalb
mache ich gerade ein Spaßprojekt, bei dem ein BlinkenLEDs Display von
einem Mega 8 angesteuert wird.
Nun ist mir aufgefallen, dass der Compiler bei Operationen, wo ich
diverse Bits in anderer Reihenfolge in andere Variablen bringe (kurz:
Bitshifting betreibe) keine sonderlich gute Arbeit leistet. Mit Inline
ASM hab ich einige Stellen innerhalb kürzester Zeit auf 35% Zyklenbedarf
bei ~20% Flash ersparnis reduziert... Nun eine Zeile, welche ich euch
einmal zeigen möchte:
Das steht in einer Schleife, i ist der Schleifenzähler. LCD_D8 ist ein
#define LCD_D8 0.
Merkt der Compiler an der Stelle nicht, dass ich lediglich 1 Bit von
einer variablen in ne andere bringen muss? Gibt es eine sinnvollere
Schreibweise, wie ich ihm das mitteilen kann? Ich würde in ASM einfach
folgendes machen:
ldd r24, z+2
bld r24, 6
brtc weiter
sbi 0x18, 0
weiter:
das sind grad mal 4 Instruktionen, welche exakt das gleiche machen.
Warum kann mein gcc nicht auch wenigstens Ansatzweise solchen Code
generieren?
Ich hoffe ja immernoch, dass der Fehler bei mir zu suchen ist... Denn
mir vergeht die Lust an C auf AVR, wenn mir jedes mal, wenn ich mir das
List file angucke, 1000 Verbesserungsmöglichkeiten auffallen.
Mir ist klar, dass der Compiler nicht perfekt arbeitet, aber ein
weeeeenig kann ich ja wohl von ihm erwarten? Teilweise klappts ganz gut
mit der Optimierung, aber eben an einigen Ecken und Kanten nicht.
Ich benutze übrigens -Os als Optimierungsstufe.
Vielen Dank,
Matthias
Ich glaube, das merkt er nicht. Das musst Du ihm schon vorkauen:
LCD_XTRA |= (lcd_framebuffer[3*(7-i)+2] & 64) >> (6 - LCD_D8);
-->
if (lcd_framebuffer[3*(7-i)+2] & 64){LCD_XTRA |= 1;}
Und ich wette, lcd_framebuffer[] ist 16 bit breit, also int.
Bei 8 Bit (char) würde der Code schon etwas kürzer sein.
Hi!
Danke erstmal, das mit dem if... oehm, irgendwie logisch, so könnts
gehen :-)
Und nein, ich vergaß zu schreiben, lcd_framebuffer ist ein uint8_t
Array. Werde morgen früh mal auf die If-Abfrage umstellen und mal
schauen, was bei raus kommt, jetzt gehts erstmal ins Bett.
Vielen Dank!
Matthias
>Gibt es eine sinnvollere>Schreibweise, wie ich ihm das mitteilen kann?
Ja, sicher. Erstmal schreibst du nicht alle Berechnungen
in eine Zeile. Und welchen Variablentyp hat i ? int i ?
Ohne etwas mehr Code kann man dazu kaum was sagen.
Wobei der move von R26:R25 in R28:R27 keinen Sinn ergibt, denn R28:R27
wird überhaupt nicht mehr verwendet, bevor es vor Ende der Funktion vom
Stack gepopt wird :-) Er macht hier die Bitübertragung explizit mit
rollen durchs carry. Warum nicht den kack sparen und:
1
LDD R24,Y+2
2
SBRS R24,7
3
rjmp nicht_setzen
4
sbi LCD_XTRA, LCD_D8
5
nicht_setzen:
eben genau wie an der anderen Stelle (der ASM Code der anderen Funktion
steht oben)
Also, wäre nett, wenn ihr mir schreiben könntet, wie ich das anstellen
soll :-) Ich probiere jetzt, wie gestern schon gesagt, erstmal die
If-Anweisung aus.
Matthias
Hm jetzt muss ich mir schon selbst antworten, kann man als registrierter
Benutzer seine Beiträge editieren?
Also: If ist die Lösung. Sogar noch schlauer als ich, bin wohl grade
nicht so ganz drin im ASM:
Wunderbar, so solls sein ^^
Schade nur, dass er das nicht automatisch aus der anderen Zeile erkennt,
denn durch das & ist ja klar, dass ich mich nur auf exakt 1 bit beziehe,
durch das oder ist klar, dass es nur gesetzt werden kann und der shift
zeigt an, um welches ziel-bit es sich handelt..
Immerhin zeigt das gut, dass man auch als C-Programmierer immer etwas
mitdenken sollte :-)
Vielen Dank & noch einen schönen Sonntag,
Matthias
Matthias Larisch wrote:
> Hm jetzt muss ich mir schon selbst antworten, kann man als registrierter> Benutzer seine Beiträge editieren?
Kann man.
> Immerhin zeigt das gut, dass man auch als C-Programmierer immer etwas> mitdenken sollte :-)
Allerdings. Aber mich wundert teilweise schon, wie intelligent der GCC
doch ist. Der ersetzt mir doch tatsächlich eine Subtraktionsschleife
durch einen Aufruf von _divmodqi4...
So, hab mich angemeldet.
Ja, ich war auch überrascht, wie er bei oben geschriebenen Code die
for-schleife implementiert hat:
X Pointer wird auf höchste "base-adresse" gesetzt, also auf
lcd_framebuffer[3*(7-i)] und dann für jeden loop um 3 verringert, dann
einfach gegen den niedrigsten wert getestet, falls drunter -> loop zu
ende... Also komplett ohne eigene Loopvariable sozusagen :-) Das gefällt
mir wirklich sehr gut!
Naja, all das zeigt auch, das man sich den entstehenden ASM Code doch
mal anschauen sollte. Wie eine kleine Veränderung so viel bewirken kann
(das ersetzen der hier diskutierten Zeile durch gleichwertiges mit dem
If verringert die Zyklenzahl für den kompletten Funktionsaufruf von 1126
auf 822 - also benötigt nur 73% der Zeit!
Matthias