Forum: Mikrocontroller und Digitale Elektronik Banale Assembler-Schleifenfrage


von Klaus (Gast)


Lesenswert?

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

von jack (Gast)


Lesenswert?

Klaus schrieb:
   > x ist ein zwei Registern, aber maximal 512 gross.

Was soll das heißen?

von Klaus (Gast)


Lesenswert?

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)

von Sonic (Gast)


Lesenswert?

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.

von Sonic (Gast)


Lesenswert?

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.

von Sonic (Gast)


Lesenswert?

Ups.. X_high muss natürlich mit 2 initialisiert werden!

von unscheinbarer WM-Rahul (Gast)


Lesenswert?

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

von Klaus (Gast)


Lesenswert?

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

von Sonic (Gast)


Lesenswert?

>Zählt aber von 511 runter...

Die komplette Schleife zählt von 512 'runter. Evtl. 'ne kleine 
Zeitüberschneidung beim Posten ?!

von unscheinbarer WM-Rahul (Gast)


Lesenswert?

111111111b ist für mich 511 dezimal, oder?

Sie wird 512 Mal durchlaufen...

von Sonic (Gast)


Lesenswert?

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.

von Klaus (Gast)


Lesenswert?

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

von Sonic (Gast)


Lesenswert?

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!

von Ste (Gast)


Lesenswert?

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

von Sonic (Gast)


Lesenswert?

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

von Bernhard S. (bernhard)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

@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

von Sonic (Gast)


Lesenswert?

Sorry nochmal, X_high muss 2 sein, sonst geht's nicht. Ansonsten ist die 
Schleife so korrekt, läuft 512 Schritte durch.

von Karl (Gast)


Lesenswert?

ich glaub ich bin zu blöd,
bei x_low = 0
und x_high = 2
bekomme ich 511 durchläufe

von Karl H. (kbuchegg)


Lesenswert?

lass den reload von low mit 255 weg.

von Karl (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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>

von Karl (Gast)


Lesenswert?

Wieso einfach wenns auch kompliziert geht?
Danke vielmals

von Bernhard S. (bernhard)


Lesenswert?

@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

von Peter D. (peda)


Lesenswert?

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

von Bernhard S. (bernhard)


Lesenswert?

Danke Peter,

wieder was für's Leben gelernt :)


Bernhard

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.