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


von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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:
1
:
2
unsigned long var = 0xFFFFFF00;
3
:
4
while (var&0x8000000) {      // solange, bis alle 0xFF durchgeschoben sind
5
  IrgendeineWartefunktion(); // warten, bis ein Bit eingelesen werden darf...
6
  var = var | !!(PINC&1);    // PinC 0 in '0' oder '1' wandeln über doppelte Negation 
7
  var << 1;                  // bereit für nächstes Bit
8
}
9
:

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   :-(

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


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.
1
extern unsigned long bar (unsigned long);
2
3
void foo(void)
4
{
5
  unsigned long var = 0xFFFFFF00;
6
7
  while (var & 0x8000000)
8
  {
9
    var = bar(var);
10
  }
11
}

Beantwortet für -Os
1
.global  foo
2
  .type  foo, @function
3
foo:
4
/* prologue: function */
5
/* frame size = 0 */
6
  ldi r22,lo8(-256)
7
  ldi r23,hi8(-256)
8
  ldi r24,hlo8(-256)
9
  ldi r25,hhi8(-256)
10
  rjmp .L2
11
.L3:
12
  rcall bar
13
.L2:
14
  sbrc r25,3
15
  rjmp .L3
16
/* epilogue start */
17
  ret

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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):
1
  JMPR  cc_UC,_101
2
_99:
3
  MOV   R8,P5
4
  JB    R8.0,_144  // Pin
5
  JMPR  cc_UC,_145
6
_144:
7
  MOV   R8,#01h    // '1'               <<<<<<<<<
8
  JMPR  cc_UC,_146
9
_145:
10
  MOV   R8,#00h    // '0'               <<<<<<<<<
11
_146:
12
  MOV   R9,#00h                         <<<<<<<<<
13
  OR    R6,R8      // verodern Low      <<<<<<<<<
14
  OR    R7,R9      // verodern Hi       <<<<<<<<<
15
  ADD   R6,R6      // shift per Addition
16
  ADDC  R7,R7      // shift per Carry-Addition
17
_101:
18
  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:
1
  JMPR  cc_UC,_101
2
_99:
3
  MOV   R8,P5
4
  JNB   R8.0,_144  // Pin
5
  SBR   R6.0       // '1'               <<<<<<<<<
6
_144:
7
  ADD   R6,R6      // shift per Addition
8
  ADDC  R7,R7      // shift per Carry-Addition
9
_101:
10
  JB    R7.15,_99  // schon fertig?   while()

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

von Stefan E. (sternst)


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....

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

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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

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

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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


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.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

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

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

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.