PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Optimierter Programmcode



helmut_w
17.08.2007, 20:39
Hi,

ich habe eine Frage an die Programmierer:

Was macht der (Pre-) / Compiler mit
" #define BATTERIE (1 << MUX0) | (1 << MUX2) ",
wenn es irgendwo eingesetzt wird?

Kommen da (viele) _Shift-left_- und _Or_-
Maschinenbefehle raus, oder macht er bereits
OPTIMIERTEN Code draus; ... und verwendet hier
z.Bsp. "0x03", also gleich das Resultat?

Danke fürs Aufklären!:)

cu Helmut

Superhirn
17.08.2007, 22:46
(1 << MUX0) | (1 << MUX2) und 0x03 ist nicht dasselbe!

die shft befehle setzen nur den bit 0 und bit 2 und ander bist bleiben wie sie sind, 0x03 setzt jedoch den ganzen port auf 0x03 ohne rücksichtnahme ob er davor bereits eine stellung hatte.

außerdem schreibt man das so im programmcode:
port |= BATTERIE;
port |= (1 << MUX0) | (1 << MUX2); //->Entsteht

port = 0x03; //das | vorm = fehlt. du seihtst hier wird alles

harry3
17.08.2007, 23:19
MUX0 setzt das rechteste Bit auf 1, MUX2 das 3. von rechts.
Die beiden kann man zumindest zusammenfassen, dabei kommt raus:
0100 | 0001 = 0101 = 5
Aber auch diese '5' muss mit dem PORT mittels OR verknüpft werden, um eben ein Überschreiben anderer Werte zu vermeiden. Also wird der Compiler wohl nicht viel mehr machen können als wie die rechte Seite, sprich die Konstanten, zusammenzufassen(das hat Superhirn eh schon sehr gut beschrieben).

izaseba
18.08.2007, 00:35
Hallo,


Was macht der (Pre-) / Compiler mit
" #define BATTERIE (1 << MUX0) | (1 << MUX2) ",
wenn es irgendwo eingesetzt wird?

Meinst Du Präprozessor ? Oder das Endprodukt?
der gcc hat einen schönen Schalter -E , der das Kompilieren abbricht, nachdem der Präprozessor fertig ist, ich habe es ausprobiert:


#define BATTERIE (1<<0)|(1<<2)
usigned char high;
high = BATTERIE;

ein gcc blabla.c -E | grep high ergibt


unsigned char high;
high = (1<<0)|(1<<2);
also reinen Textersatz (war auch klar)
Richtig optimieren tut der Kompiler, ich weiß aber nicht, ob auch bei -O0, da mußt Du selber gucken, dazu habe ich im Moment keine Lust

Gruß Sebastian

radbruch
18.08.2007, 01:03
Hallo

Ein kleiner Testcode

#define BATTERIE (1 << MUX0) | (1 << MUX2)

int main(void)
{
setLEDs(0);
ADMUX |= BATTERIE;
setLEDs(255);
ADMUX |= 5;

wird wie folgt übersetzt

29 .LM2:
30 0008 80E0 ldi r24,lo8(0)
31 000a 0E94 0000 call setLEDs
32 .LM3:
33 000e 87B1 in r24,39-0x20
34 0010 8560 ori r24,lo8(5)
35 0012 87B9 out 39-0x20,r24
36 .LM4:
37 0014 8FEF ldi r24,lo8(-1)
38 0016 0E94 0000 call setLEDs
39 .LM5:
40 001a 87B1 in r24,39-0x20
41 001c 8560 ori r24,lo8(5)
42 001e 87B9 out 39-0x20,r24
43 .L2:

Die setLEDs(); dienen der Orientierung im Assemblerlisting. Schön zu sehen ab LM3/5: Lesen des Ports, Wert verodern, schreiben. Wie man sieht, ist es egal, wie man es formuliert, es ist immer 5.

Wenn man wirklich nicht weiß, welche Spannungsreferenz und welche Bündigkeit das Ergebniss haben soll, dann weiß man sicher auch nicht, welcher ADC-Kanal zuvor ausgewählt war. Deshalb sollte man die MUX0-4 wenigstens löschen bevor man sie mit |= setzt. Oder man definiert BATTERIE etwas um:

#define BATTERIE2 (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1 << MUX0) | (1 << MUX2)

und mit

ADMUX = BATTERIE2;

ergibt das dann diesen Code:

ldi r24,lo8(69)
out 39-0x20,r24

Gruß

mic

helmut_w
18.08.2007, 12:03
Hallo an alle!

Zuerst 'mal ein !_ganz_großes_Dankeschön_! für Eure _Spitzen-Abhandlung_!!!!

Harri hat natürlich recht: 1 + 4 = 5 (nicht 3)
Sorry war mein Flüchtigkeitsfehler!:( (... den aber auch Superhirn übersah!:))

Was _ich_ daraus gelernt habe:
1. der Präprozessor ersetzt einfach nur! (Danke an Sebastian!)
2. der Compiler ist intelligent*) und macht gleich den richtigen Wert aus einem an sich in Maschinensprache komplexen Ausdruck! (Danke an mic!)
(Wobei "Maschinensprache" hier im Bsp. nicht so _ganz_ passt; es scheint eher ein Objekt-Code, also die Vorstufe dazu, zu sein.)

Toll, wie Ihr das erklärt habt: Ich denke, da haben noch jede Menge anderer Leser dazulernen können!

@mic!

Die setLEDs(); dienen der Orientierung im Assemblerlisting. ...
Ist sehr tricki!!!

Was heißt eigentlich das "lo8(5)" bei einem _Byte_-Register? (Evtl. 'was für den Linker!?)

Nochmals Danke!
cu Helmut

*) denn bei a >>= 4 muss er ja wirklich schieben!
(Das Gelernte gilt offensichtlich nur bei _Konstanten_!)

Übrigens meine Idee war, Platz zu sparen; aber da hätte die Lesbarkeit gelitten!

izaseba
18.08.2007, 12:19
*) denn bei a >>= 4 muss er ja wirklich schieben!
(Das Gelernte gilt offensichtlich nur bei _Konstanten_!)

Nein gcc ist schlauer als Du denkst ;-)
Er schiebt nicht 4 mal sondern dreht beide nibbles um (swap) und verundet das Ergenbnis mit 0x0F, braucht also nur 2 Takte und keine 4 ...

Gruß Sebastian

radbruch
18.08.2007, 12:36
Hallo


Was heißt eigentlich das "lo8(5)" bei einem _Byte_-Register?
Ich vermute, es bedeutet "das 8bit-low-byte" einer 16bit-Konstanten beim Schreiben in ein 8bit-Register? Hängt vielleicht mit der Trennung von Code und Daten bei den AVR zusammen - keine Ahnung, was das alles im Detail bedeutet. Das ist die .lst-Ausgabe meines Kompilers. Ich ging bisher davon aus, dies ist der Programmcode in Maschinensprache, so wie er dann vom Assembler in ein .hex gewandelt wird.

Gruß

mic

izaseba
18.08.2007, 12:48
mit lo8 oder hi8 wird erst richtig klar, wenn man Unsinn programmiert.
Ich habe so ein Beispiel gerade verwendet:


uint16_t i;
uint16_t a = 0x0AED;

while(1) {
i = (PINB<<8)|PIND;
i +=a;
PORTB = (uint8_t)i;
PORTC = (uint8_t)(i>>8);
}
Ergebnis:

15:bubu.c **** i +=a;
95 .LM3:
96 001c 8351 subi r24,lo8(-(2797))
97 001e 954F sbci r25,hi8(-(2797))
16:bubu.c **** PORTB = (uint8_t)i;
99 .LM4:
100 0020 88BB out 56-0x20,r24
17:bubu.c **** PORTC = (uint8_t)(i>>8);
102 .LM5:
103 0022 892F mov r24,r25
104 0024 9927 clr r25
105 0026 85BB out 53-0x20,r24

Interessant ist hier vielleicht, daß hier subtrahiert und nicht addiert wird...

radbruch
18.08.2007, 12:59
Interessant ist hier vielleicht, daß hier subtrahiert und nicht addiert wird...
Weil der Wert negativ dargestellt ist: -(2797) Das sind noch die höheren Weihen des C-Kompilers.

Ein Blick ins ATMega-Datenblatt zeigt erstaunliches: Es gibt subi-abziehen einer Konstanten und sbci-abziehen einer Konstanten mit carry, aber scheinbar nichts entsprechendes mit add und Konstante!

mic

izaseba
18.08.2007, 13:09
Weil der Wert negativ dargestellt ist: -(2797)

:-$ Genau, ich weiß im Moment aber nicht mehr warum :-k
O Weh, das wußt ich mal, weißt Du es ?
Ich muß mir das durch den Kopf gehen lassen...
Gruß Sebastian

P.S. Ich bin echt blöd,
Die Lösung :
subi
sbci
gehen beide mit Konstanten ](*,)
Addition geht so nicht
es gibt zwar
adi
aber kein Befehl wo man Konstante und Carry addieren kann ](*,)

helmut_w
18.08.2007, 18:28
Hi,

[glow=red:b6642de26a]nochmals DAAAANKE!:)[/glow:b6642de26a]

cu Helmut

PS: Das mit dem "Swap"en der Nybbles geht aber nur bei "unsigned char"!:)

izaseba
18.08.2007, 18:51
Komische Wurst hier :-k
Wo ich oben mein P.S. geschrieben hatte war das

Ein Blick ins ATMega-Datenblatt zeigt erstaunliches: Es gibt subi-abziehen einer Konstanten und sbci-abziehen einer Konstanten mit carry, aber scheinbar nichts entsprechendes mit add und Konstante!
Noch nicht da :-k :-k :-k

radbruch
18.08.2007, 20:12
Als ich oben mein P.S. geschrieben hatte war das ... noch nicht da.
Weil ich nach dem Absenden des ersten Teils des Postings nochmal drüber nachgedacht hatte und dann meine Datenblatt-Erweiterung dazu kam, während du dein p.s. formuliert hast. Sorry.

Gruß

mic

izaseba
18.08.2007, 20:25
Sorry.
Ach wat!
ich hab ja auch zwischendurch Atmelbefehlsatz geguckt
Und dann hab ich mein Edit gemacht, wo Du schon Fertig warst O:)
Sieht jetzt auf jedem Fall lustig aus, aber doppelt hält besser \:D/


Gruß Sebastian

radbruch
18.08.2007, 20:32
O Weh, das wußt ich mal, weißt Du es?
Diesmal hälts ein Leben lang, wie Flags mit = löschen. *grins*

damaltor
26.08.2007, 15:09
hrhr.. ist es nicht egal ob mal eine positive zahl addiert oder eine negative abzieht? da wurde ganz einfach platz auf dem silizium gespart... =)