Hallo
Das "quick&dirty" bezog sich auf die Annahme, dass der Kompiler intern false als 0 speichert und deshalb jeder Wert größer 0 als true interpretiert wird. Ich wollte das nur mal wieder bewußt machen, denn "im Alltag" beachtet das eh niemand: while(1) sollte eigentlich while(true) lauten.
#define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT)) > 0) // Fragt Bit = 1?
So würde das Ergebniss true oder false sein.
Das wollte ich mal genauer untersuchen, weil ich ja was lernen will. Mit C komme ich inwischen recht gut zurecht, aber mit Assembler kenne ich mich noch gar nicht aus. Dieses kleine Testprogramm wurde (ohne Optimierung!) mit 136 Bytes übersetzt:
Code:
#define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT))?1:0) // Fragt Bit = 1?
#define IsBitSet2(ADDR,BIT) (((ADDR) & (1<<BIT)) > 0)
int main(void)
{
int x, tmp;
if(IsBitSet(x,0)) tmp=0x11; else tmp=0x22;
if(IsBitSet2(x,0)) tmp=0x33; else tmp=0x44;
while(1);
return(0);
}
IsBitSet() wird in zwei Varianten definiert, Variante eins prüft 1 oder 0, Variante zwei prüft true/false.
Aus dem erzeugten Assemblerlisting habe ich die entscheidende Stelle rauskopiert und kommentiert (soweit mir das möglich ist):
Code:
.LM2: // if((
ldd r24,Y+3 // x
ldd r25,Y+4 // x ist in Y+3 und Y+4 gespeichert
andi r24,lo8(1) // & (1<<0))
andi r25,hi8(1)
tst r24 // prüft ob ein Bit in R24 gesetzt ist (Lowbyte von x!)
breq .L2 // springt nach L2 wenn R24 null ist
ldi r24,lo8(17) // tmp=0x1111
ldi r25,hi8(17)
std Y+2,r25 // tmp ist in Y+1 und Y*2 gespeichert
std Y+1,r24
rjmp .L3
.L2:
ldi r24,lo8(34) // tmp=0x2222
ldi r25,hi8(34)
std Y+2,r25
std Y+1,r24
.L3:
.LM3:
ldd r24,Y+3
ldd r25,Y+4
andi r24,lo8(1)
andi r25,hi8(1)
cp __zero_reg__,r24 // Vergleicht Lowbyte von x mit null
cpc __zero_reg__,r25 // dito Highbyte mit Carry! (beide Bytes werden ausgewertet)
brge .L4 // Sprung wenn beide Vergleiche null sind
ldi r24,lo8(51)
ldi r25,hi8(51)
std Y+2,r25
std Y+1,r24
rjmp .L5
.L4:
ldi r24,lo8(68)
ldi r25,hi8(68)
std Y+2,r25
std Y+1,r24
.L5: // while(1)
rjmp .L5
Erstaunlicherweise ist die erste Variante kürzer, allerdings habe ich das Gefühl, mit tst r24 wird nur das Lowbyte geprüft. Beschreibung von breq:
"Conditional relative branch. Tests the Zero Flag (Z) and branches relatively to PC if Z is set." Bedingter relativer Sprung, springt relativ zum Progammcounter, wenn ZeroFlag gesetzt ist. Das Z-Flag wird von tst gesetzt:
Z: R7• R6 •R5• R4• R3 •R2• R1• R0
Set if the result is $00; cleared otherwise.
Das ist aber das Ergebniss vom Test mit R24, wo wird geprüft, ob R25 auch null ist? Sehr seltsam.
btw. wird sowohl while(1) wie auch while(1==1) gleich übersetzt:
.L5:
rjmp .L5
Gruß
mic
[Edit]
tst scheint doch richtig zu funktionieren. Bei if(IsBitSet(x,0)) ergibt (1<<0) genau 1, das passt in das Lowbyte. Bei if(IsBitSet(x,15)) übersetzt der Kompiler so:
Code:
29 .LM2:
30 000c 8B81 ldd r24,Y+3
31 000e 9C81 ldd r25,Y+4
32 0010 9923 tst r25
33 0012 04F4 brge .L2
34 0014 81E1 ldi r24,lo8(17)
35 0016 90E0 ldi r25,hi8(17)
36 0018 9A83 std Y+2,r25
37 001a 8983 std Y+1,r24
38 001c 00C0 rjmp .L3
39 .L2:
40 001e 82E2 ldi r24,lo8(34)
41 0020 90E0 ldi r25,hi8(34)
42 0022 9A83 std Y+2,r25
43 0024 8983 std Y+1,r24
44 .L3:
45 .LM3:
46 0026 8B81 ldd r24,Y+3
47 0028 9C81 ldd r25,Y+4
48 002a 8070 andi r24,lo8(-32768)
49 002c 9078 andi r25,hi8(-32768)
50 002e 1816 cp __zero_reg__,r24
51 0030 1906 cpc __zero_reg__,r25
52 0032 04F4 brge .L4
53 0034 83E3 ldi r24,lo8(51)
54 0036 90E0 ldi r25,hi8(51)
55 0038 9A83 std Y+2,r25
56 003a 8983 std Y+1,r24
57 003c 00C0 rjmp .L5
58 .L4:
59 003e 84E4 ldi r24,lo8(68)
60 0040 90E0 ldi r25,hi8(68)
61 0042 9A83 std Y+2,r25
62 0044 8983 std Y+1,r24
63 .L5:
64 0046 00C0 rjmp .L5
Genial ;)
[EDIT2]
Erstaunlich was der Kompiler alles beachtet:
Code:
#define IsBitSet(ADDR,BIT) (((ADDR) & (1<<BIT))?1:0) // Fragt Bit = 1?
int main(void)
{
int x, tmp;
if(IsBitSet(x,0)) tmp=11; else tmp=22;
if(IsBitSet(x,15)) tmp=33; else tmp=44;
while(1);
return(0);
}
Code:
.LM2:
ldd r24,Y+3
ldd r25,Y+4
andi r24,lo8(1)
andi r25,hi8(1)
tst r24
breq .L2
ldi r24,lo8(11)
ldi r25,hi8(11)
std Y+2,r25
std Y+1,r24
rjmp .L3
.L2:
ldi r24,lo8(22)
ldi r25,hi8(22)
std Y+2,r25
std Y+1,r24
.L3:
.LM3:
ldd r24,Y+3
ldd r25,Y+4
tst r25
brge .L4
ldi r24,lo8(33)
ldi r25,hi8(33)
std Y+2,r25
std Y+1,r24
rjmp .L5
.L4:
ldi r24,lo8(44)
ldi r25,hi8(44)
std Y+2,r25
std Y+1,r24
.L5:
rjmp .L5
Lesezeichen