Hallo! Ich habe ein ziemlich banales "Problem" ich habe eine Schleife die x mal durchlaufen werden soll, x ist ein zwei Registern, aber maximal 512 gross. Wie mache ich das am Besten mit möglichst wenig Branches. Es gibt da eine unzahl an Branches, welche geschickte kombination aus denen aber eine kompakte Abzähl/Überprüf-Fuktion hat ist mir schleierhaft. Kann man das überhaupt elegant lösen? Danke für eure Tipps, achja, verwende einen ATmega Gruss
Klaus schrieb: > x ist ein zwei Registern, aber maximal 512 gross. Was soll das heißen?
Dass eine so grosse Zahl nicht in einem Register Platz hat und deshalb auf 2 aufgeteilt ist zum Beispiel: ldi r20, high(x) ldi r21, low(x)
Kleines Beispiel für 'ne Pause: PAUSE: ldi PZEIT1,255 ldi PZEIT2,1 P_WAIT: dec PZEIT1 brne P_WAIT ldi PZEIT1,255 dec PZEIT2 brne P_WAIT ret Sollte von 512 'runterzählen.
Hmm.. sehr unübersichtlich.
Schleife: ldi X_low,255
ldi X_high,1
>hier Code einfügen<
WAIT: dec X_low
brne WAIT
ldi X_low,255
dec X_high
brne WAIT
ret
müsste besser sein.
>Sollte von 512 'runterzählen.
Zählt aber von 511 runter...
Das 2. ldi PZEIT1,255 müsste man sich aufgrund des begrenzten
Zahlenraums sparen können.
(Bin aber niocht ganz so asmbewandert...)
OK, das ist ziemlich kompakt, aber wenn ich zur initialisierung ldi X_high, 0 habe, dann funktionierts nicht? Oder täusche ich mich? Dann zieht er eins ab, obwohl er schon null ist??
>Zählt aber von 511 runter...
Die komplette Schleife zählt von 512 'runter. Evtl. 'ne kleine
Zeitüberschneidung beim Posten ?!
111111111b ist für mich 511 dezimal, oder? Sie wird 512 Mal durchlaufen...
Hat wohl keiner bemerkt:
Schleife: ldi X_low,255
ldi X_high,1
WAIT:
>hier Code einfügen<
dec X_low
brne WAIT
ldi X_low,255
dec X_high
brne WAIT
ret
So muss es aussehen.
Kannst auch von 0 abwärtszählen, dann wird das 'N'-Flag gesetzt. Wenn
das nicht stört zählt er halt von 256 'runter.
Wenn ich obigen code simuliere, dann erhalte ich wie bereits vermutet komische ergebnisse, die schleife wird nicht mit jedem wert <512 korrekt oft mal durchlaufen, anscheinend geht es doch nicht so einfach... zum Beipiel mit 256 also x_low=0 und x_high=1, dann wird die Schleife 511 mal durchlaufen. Man muss (wie ich bereits befürchtet habe) auch auf null testen bevor man abzählen kann :(
Hmm.. X_high sollte 2 sein, dann sollte die X_low-Schleife 2x 'runtergezählt werden, sprich: 2x256=512. Hatte vergessen die X_high auf 2 zu ändern, sorry!
wenn ich 255 wie folgt initialisiere: x_low = 255 und x_high = 1 dann gehts wenn ich für 256 folgendes eingebe: x_low = 0 x_high = 2 dann machts die schleife eben 511 mal deshalb wäre es irgendwie von Vorteil, wenn es eine Möglichkeit gibt die auch geht... An so einem einfachen Ding verzweifle ich noch
>wenn ich 255 wie folgt initialisiere:
x_low = 255 und x_high = 1
dann gehts
Na, ist doch auch richtig. In Assembler und C wird ab 0 gezählt, also
0..255 sind 256 Schritte. Sobald beim Abwärtszählen von 255 die 0
erreicht wird (und das Zero-Flag gesetzt wird) sind 256 Schritte
durchlaufen. Bau' die Schleife so auf und es funktioniert!
Notfalls durch "NOP" ein Feinabgleich vornehmen Schleife: ldi X_low,255 ldi X_high,1 WAIT: dec X_low brne WAIT ldi X_low,255 dec X_high brne WAIT nop ; 1 x nix tun ret
@Sonic Nicht ganz. Das Problem ist, dass zuerst dekrementiert und erst dann auf 0 geprüft wird. Du musst das umdrehen. Geh ins extrem: low gleich 0, high gleich 0. Wie oft werden die Schleifen durchlaufen? Exakt: 65536 mal
Sorry nochmal, X_high muss 2 sein, sonst geht's nicht. Ansonsten ist die Schleife so korrekt, läuft 512 Schritte durch.
ich glaub ich bin zu blöd, bei x_low = 0 und x_high = 2 bekomme ich 511 durchläufe
Danke Karl, so kam ich der Sache auf die Spur, man musste aber noch überprüfen ob denn von high nicht abgezogen wird obwohl schon null, folgendes ist entstanden: ldi X_low,255 ldi X_high,0 WAIT: //>hier Code einfügen< dec X_low brne WAIT tst X_high breq finito dec X_high rjmp WAIT finito: wer was einfachere kennt, bei dem man die Zahlen einsetzen kann und es läuft dann auch so viel mal, der möge sich melden....
Wozu die Umstände, der AVR kann doch 16Bit rechnen und höher:
1 | ldi r16, low(512) |
2 | ldi r17, high(512) |
3 | loop: |
4 | |
5 | ; tue was 512 mal |
6 | |
7 | subi r16, low(1) |
8 | sbci r17, high(1) |
9 | brne loop |
Peter
So implementierts der Compiler for( Counter = i; Counter != 0; --Counter ) 72: c0 91 60 00 lds r28, 0x0060 76: d0 91 61 00 lds r29, 0x0061 7a: 20 97 sbiw r28, 0x00 ; 0 7c: 19 f0 breq .+6 ; 0x84 <main+0x1a> foo(); 7e: ee df rcall .-36 ; 0x5c <foo> 80: 21 97 sbiw r28, 0x01 ; 1 82: fb cf rjmp .-10 ; 0x7a <main+0x10> 84: 00 c0 rjmp .+0 ; 0x86 <_exit>
@Peter diese Schleife gefällt mir, aber müsste es nicht so sein? ... subi r16, low(1) brne loop sbci r17, high(1) brne loop Bernhard
Bernhard Schulz wrote: > diese Schleife gefällt mir, aber müsste es nicht so sein? Nein, der AVR hat ne sogenannte "Zero-Propagation": Ein Folge von SUBI, SBCI, ... SBCI setzt nur dann das Zero-Flag, wenn sämtliche Ergebnisbytes Null sind. Gilt analog für CP, CPC, ... CPC. Peter
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.