Hallo Leute,
ich hoffe es kann mir jemand helfen, ist eigendlich ein relativ
einfaches Problem...
Vorweg ich programmiere in ASM in AVR Studio, Processor ATmega32.
Ich habe zwei 16-Bit Register (r24,r25 und YL,YH).
Ich ziehe beide Register von einander ab:
sub r24, YL
sbc r25, YH
In r24, r25 ist nun mein Ergebnis.
Nun soll verzweigt werden und zwar entweder wenn Ergebnis '0' oder
negativ ist.
Habe es mit "brmi negatives_Ergebnis" probiert, klappt auch, allerdings
nur bei negativen Ergebnis und nicht beim Ergebnis '0'.
Ich hoffe jemand hatte schonmal ein ähnliches Problem und kann helfen.
Gruß Ralf
P.S.: Im Prinzip suche ich eine Funktion "branch if zero or minus" aber
die gibt es nicht... äääh, naja, zumindest hab ich sie nicht gefunden.
Wenn es keine Funktion <= gibt versuch mal eine Funktion > zu nutzen
(wenn es die gibt) und was dann übrig bleibt ist <=.
2. Möglichkeit: zieh einfach noch mal "1" ab.
...Nachtrag: Es würde auch reichen, wenn ich jemand wüßte wie ich eine
16-Bit Zahl auf '0' überprüfen kann ;-)
Ich meine, "tst" überprüft halt nur 8-Bit also im Prizip ein "Test with
carry" wäre toll.
du könntest beide register ver-ODER-n. wenn das ergebnis 0 ist, waren
auch beide ausgangsregister 0.
also:
1. brmi negativ
2. or r24, r25
3. tst r24
4. breq null
5. sonstiger code
gruß
fabian
Intressante Idee, Größer gibt es...
Aber das Problem bleibt das Gleiche, '0' ist halt weder positiv noch
negativ...
Es gibt halt noch ein >=, bringt mir aber auch nicht wirklich was, da er
ja den "negativ-Threat" ausführen soll, wenn die Zahl '0' ist.
Wird durch die Subtraktion nicht schon das Zeroflag gesetzt? Aber das
gilt vermutlich nur für die letzte Operation, also für das Highbyte.
Jörgs 2. Lösung gefällt mir am besten, eins abziehen geht mit einem
einzigen 16Bit-Befehl. Aus Null wird dann FFFF, das ist negativ.
Also die Idee mit dem Ver-Odern hab ich gerad mal Gedanklich
durchgespielt, grundsätzlich möglich, da ich das Ergebnis der
Subtraktion aber noch brauche, müßte ich das Ergebnis vorher
zwischenspeichern und bei "nicht-null" wieder zurückschreiben,...geht
aber umständlich...
kommen wir nun zur Idee mit dem "-1"...
@Rene: der zweite Link hat nunmal gar nichts mit meinem Problem einer
Branch Anweisung tun,...wie ich rudimentäre Rechenschritte in 16-Bit
Registern durchführe weiß ich,...dafür brauch ich auch keine Macros.
Und aus dem ersten Link werd ich nicht schlau, kannst Du bitte im
Zweifelsfall SCHREIBEN was Dein Vorschlag wäre für das Problem...
So, hab das mit "-1" mal versucht, scheint auch zu klappen. Ich find´s
aber immer noch irgendwie, naja,... Ästetisch nicht ansprechend ;-)
sub r24, YL
sbc r25, YH
brmi Negatives_Ergebnis
subi r24, LOW(1)
sbci r25, HIGH(1)
brmi Negatives_Ergebnis
adiw r25:r24, 1
@Christoph Kessler: Moment ich lese gerade Du kennst "einen" Befehl für
das Abziehen von '1' von einem 16Bit Register??
Das wäre sozusagen Kollosal, oder Kollusal,...prima halt, he he
Wie heißten der? (dec with carry?)
Oh nein,...
Danke Michael U., genau, oh man, also manchmal sieht man den Wald vor
lauter Bäumen nicht... unglaublich und so einleuchtend...
Danke trotzdem an alle anderen die sich dem Problem angenommen haben...
Vielleicht sollte ich auch langsam mal ins Bett, das Licht draußen ist
ja schon wieder an, nerv...
timebeast wrote:
> brmi Negatives_Ergebnis> subi r24, LOW(1)> sbci r25, HIGH(1)> brmi Negatives_Ergebnis
Nur der Vollständigkeit halber.
Das zeiht keine 1 ab, sondern $0101
Den SubW fuer die immediate-subtraktion von einer konstanten von einem
Word ist im Instruction manual ersichtlich.
compares as from p14-7
assumes the compare as cp, cpi, cp16, cpi16, the last two to be seen
on my macro page, or Appnote 202
cpXX(Rd,Rr)
BRXX as below
signed
compare mnemo cp - para
Rd > Rr BRLT Rr,Rd (swap)
Rd >= Rr BRGE Rd,Rr
Rd = Rr BREQ Rd,Rr
Rd <= Rr BRGE Rr,Rd (swap)
Rd < Rr BRLT Rd,Rr
unsigned
compare mnemo cp - para
Rd > Rr BRLO Rr,Rd (swap)
Rd >= Rr BRCC Rd,Rr
Rd = Rr BREQ Rd,Rr
Rd <= Rr BRSH Rr,Rd (swap)
Rd < Rr BRLO Rd,Rr
eg 'skip if (U1 >= 0x10)' becomes when unsigned byte
cpi U1,0x10
brcc _next
eg 'skip if (U1 <= 0x10)' becomes when unsigned byte
ldi U2,0x10 ; cannot be constant compare - use reg
cp U2,U1
brsh _next
fuer 16 bit
.MACRO Cpi16 ; CP16 UL,UH,immediate U-immediate
cp @0,low(@2)
ldi temp,high(@2)
cpc @1,temp
.ENDMACRO
cpi16 R16,R17,0x1234
brcc groessergleich
ist nicht so schwierig.
Karl heinz Buchegger wrote:
> Nur der Vollständigkeit halber.> Das zeiht keine 1 ab, sondern $0101
Sicher? HIGH(1) sollte doch eigentlich 0 sein.
@alle: Die besondere Handhabung vom Z-Flag bei Carry-Befehlen, um solche
Vergleiche schmerzfrei durchzuführen, ist nicht allen Prozessorfamilien
eigen. Es hat recht lang gebraucht, bis die Entwickler auf diese Idee
kamen.
> Wie heißten der? (dec with carry?)
adiw hast du doch schon gefunden. Wie hast du es denn geschafft, sbiw
dabei zu übersehen?
Zu deinem Code: Wozu brauchst du den ersten Vergleich? Wie wäre es
damit:
1
sub r24, YL
2
sbc r25, YH
3
sbiw r25:r24, 1
4
brmi Negatives_Ergebnis
5
adiw r25:r24, 1
Alternativ kannst du in der ersten Subtraktion gleich noch 1 mehr
abziehen durch geschickte Nutzung des Carry-Flags:
1
sec
2
sbc r24, YL
3
sbc r25, YH
4
brmi Negatives_Ergebnis
5
adiw r25:r24, 1
Das ist nochmal einen Taktzyklus schneller. ;-)
Natürlich darfst du in beiden Fällen nicht vergessen, am Sprungziel auch
das adiw einzufügen. Aber auf das umständliche Abziehen und wieder
Dazuzählen würde ich hier verzichten und es so machen, wie Michael U.
vorschlägt.
Rolf Magnus wrote:
> Das ist nochmal einen Taktzyklus schneller. ;-)
Ist gefährlich, weil bei dieser Sequenz das Z-Flag nicht korrekt ist.
Bei BMI kein Problem, bei manch anderen Abfragen schon.
@Karl heinz Buchegger:
> Nur der Vollständigkeit halber.> Das zeiht keine 1 ab, sondern $0101
Nö, zieht nur '1' ab
@Andreas Kaiser:
>Sicher? HIGH(1) sollte doch eigentlich 0 sein.
eben, so ist das, daher klappt das auch.
@Rolf Magnus:
>adiw hast du doch schon gefunden. Wie hast du es denn geschafft, sbiw>dabei zu übersehen?
So im nachhinein betrachtet frag ich mich das allerdings auch ;-)
irgendwie hat´s nicht "klick" gemacht,... keine Ahnung, danke aber...
und nochn Trick: die 8Bit-Immediate Addition gibts nicht, aber eine
Subtraktion des negativen Werts mit SBCI ergibt dasselbe, der Assembler
läßt das zu.
Spess53 wrote:
> sbc r24, YL> sbc r25, YH> brcs ... ; Sprung wenn Minus> or r24,r25> breq ... ; Sprung wenn Null
Ein Fehler ist drin, Du ziehst den zufälligen Wert des Carry mit ab.
Und statt "or r24,r25" kannst Du auch "nop" schreiben, es ist
überflüssig.
Und wenn man die Register nicht zerstören will, nimmt man cp/cpc statt
sub/sbc:
@ Spess53 (Gast)
>Ich würde es ähnlich wie Fabian machen
Ich nicht, denn das ist falsch.
> sbc r24, YL
Hier muss ein SUB! hin, ohne carry!
> sbc r25, YH> brcs ... ; Sprung wenn Minus> or r24,r25
Das Or ist vollkommen überflüssig
> breq ... ; Sprung wenn Null
Also eher so