www.mikrocontroller.net

Forum: Compiler & IDEs while ( var&0x8000000 ) --> was macht WinAVR


Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich war gerade dort: Beitrag "Bit folge einlesen"
Und jetzt sind mir da zwei Fragen in den Sinn gekommen.

Angenommen, ich hätte diesen Code:
:
unsigned long var = 0xFFFFFF00;
:
while (var&0x8000000) {      // solange, bis alle 0xFF durchgeschoben sind
  IrgendeineWartefunktion(); // warten, bis ein Bit eingelesen werden darf...
  var = var | !!(PINC&1);    // PinC 0 in '0' oder '1' wandeln über doppelte Negation 
  var << 1;                  // bereit für nächstes Bit
}
:

Da stellt sich mir gleich die Frage:
> while (var&0x8000000);
Was macht der AVR-GCC-Compiler daraus? Der muss m.E. ja nur das MSB des 
longs vergleichen, bei den anderen 3 kommt sowieso 0 heraus. Ist der 
Compiler so klug?

Und dasselbe nur in grün:
>   var = var | !!(PINC&1);
Hier würde das Verodern des LSB ausreichen...

Bin schon mal gespannt auf eure Antworten...

BTW:
Ich probier das gerade an einem Tasking C167-Compiler (16 Bit),
an den WinAVR komme ich leider erst am Wochenende wieder ran   :-(

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, kleiner Typo   :(
falsch:    var << 1;       // bereit für nächstes Bit
richtig:   var <<=1;       // bereit für nächstes Bit

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller wrote:

> Da stellt sich mir gleich die Frage:
>> while (var&0x8000000);
> Was macht der AVR-GCC-Compiler daraus? Der muss m.E. ja nur das MSB des
> longs vergleichen, bei den anderen 3 kommt sowieso 0 heraus. Ist der
> Compiler so klug?

Das ist keine Frage an ein Forum, sondern eine Frage an den Compiler.
extern unsigned long bar (unsigned long);

void foo(void)
{
  unsigned long var = 0xFFFFFF00;

  while (var & 0x8000000)
  {
    var = bar(var);
  }
}

Beantwortet für -Os
.global  foo
  .type  foo, @function
foo:
/* prologue: function */
/* frame size = 0 */
  ldi r22,lo8(-256)
  ldi r23,hi8(-256)
  ldi r24,hlo8(-256)
  ldi r25,hhi8(-256)
  rjmp .L2
.L3:
  rcall bar
.L2:
  sbrc r25,3
  rjmp .L3
/* epilogue start */
  ret

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> eine Frage an den Compiler...
Ja, ich habe den wie gesagt gerade nicht zur Hand,
und bis zum Wochenende hab ichs vergessen.

Danke, das wars:
> sbrc r25,3

Die ,3 kommt vom 2. Typo:
falsch:  while (var&0x8000000) {
richtig: while (var&0x80000000) {

Dann wäre auch wie gewünscht  *sbrc r25,7*  herausgekommen.


Dann bleibt nur noch die zweite Frage:
> var = var | !!(PINC&1);
Wie kommt das Bit in die Variable?
Ich werde die Frage dann dem Compiler am Wochenende stellen,
aber wenn jemand gerade einen zur Hand hat....




Der Tasking-C167 macht das übrigens so (obiger Code, P5.0 ist 
Eingangspin, ohne Warteschleife, mit Optimierung -Os):
  JMPR  cc_UC,_101
_99:
  MOV   R8,P5
  JB    R8.0,_144  // Pin
  JMPR  cc_UC,_145
_144:
  MOV   R8,#01h    // '1'               <<<<<<<<<
  JMPR  cc_UC,_146
_145:
  MOV   R8,#00h    // '0'               <<<<<<<<<
_146:
  MOV   R9,#00h                         <<<<<<<<<
  OR    R6,R8      // verodern Low      <<<<<<<<<
  OR    R7,R9      // verodern Hi       <<<<<<<<<
  ADD   R6,R6      // shift per Addition
  ADDC  R7,R7      // shift per Carry-Addition
_101:
  JB    R7.15,_99  // schon fertig?  while()


Die while-Abfrage ist also gleich schnell erledigt (Bit-Abfrage),
das Einlesen des Portpins macht aber recht viel Aufwand.


<<<<<<<<< Statt dieser Befehle (oben)
          würde eigentlich ein sbr reichen, 0 ist das Bit ja bereits.
So, quasi:
  JMPR  cc_UC,_101
_99:
  MOV   R8,P5
  JNB   R8.0,_144  // Pin
  SBR   R6.0       // '1'               <<<<<<<<<
_144:
  ADD   R6,R6      // shift per Addition
  ADDC  R7,R7      // shift per Carry-Addition
_101:
  JB    R7.15,_99  // schon fertig?   while()

Aber immer noch besser ein suboptimaler Compiler, als alles von Hand 
hinzuassemblieren    ;-)

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wie kommt das Bit in die Variable?
> Ich werde die Frage dann dem Compiler am Wochenende stellen,
> aber wenn jemand gerade einen zur Hand hat....

  var = var | !!(PINC&1);    // PinC 0 in '0' oder '1' wandeln über doppelte Negation 
  70:  83 b3         in  r24, 0x13  ; 19
  72:  90 e0         ldi  r25, 0x00  ; 0
  74:  a0 e0         ldi  r26, 0x00  ; 0
  76:  b0 e0         ldi  r27, 0x00  ; 0
  78:  81 70         andi  r24, 0x01  ; 1
  7a:  90 70         andi  r25, 0x00  ; 0
  7c:  a0 70         andi  r26, 0x00  ; 0
  7e:  b0 70         andi  r27, 0x00  ; 0
  80:  28 2b         or  r18, r24
  82:  39 2b         or  r19, r25
  84:  4a 2b         or  r20, r26
  86:  5b 2b         or  r21, r27

Besseren (bzw. den besten) Code bekommst du mit:
if (PINC & 1) var |= 1;
  70:  98 99         sbic  0x13, 0  ; 19
  72:  81 60         ori  r24, 0x01  ; 1

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst wrote:
> Besseren (bzw. den besten) Code bekommst du mit:
> if (PINC & 1) var |= 1;
>
>   70:  98 99         sbic  0x13, 0  ; 19
>   72:  81 60         ori  r24, 0x01  ; 1
> 

>> Wie kommt das Bit in die Variable?
>>
>>   var = var | !!(PINC&1);    // PinC 0 in '0' oder '1' wandeln über
>> 

Zwar hübbsch hinzuschreiben, aber ungeschickt, weil das auf 32-Bit-Ebene 
ausgewertet wird. Das ist gut auf Maschinen, wo Sprünge teuer sind und 
32-Bit-Operationen nix kosten.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>wo Sprünge teuer sind und 32-Bit-Operationen nix kosten.
Richtig, ich hatte das ursprünglich für den ColdFire (32Bit) gemacht,
da sah das recht elegant aus. Aber schon beim C167 (16) ist diese 
Kurzschreibweise fraglich und beim AVR (8) tödlich...   :(

Na gut, dann werde ich mir wieder ein paar neue Programmierregeln für 
den AVR anlegen müssen.

Danke für eure Zeit.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag:
Ich habe das im Tasking C167 auch noch gemacht:
   if(P5&0x01) var |= 1;

Und siehe da, wunderhübscher Code:
  JMPR  cc_UC,_101
_99:
  MOV  R8,P5
  JNB  R8.0,_100   // if(P5&0x01)
  BSET  R6.0       //     var |= 1
_100:
  ADD  R6,R6       // shift per Addition
  ADDC  R7,R7      // shift per Carry-Addition
_101:
  JB  R7.15,_99    // schon fertig?   while()

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.