Hallo liebe Forenmitglieder.
Ich stehe vor der Aufgabe folgendes in Assembler zu realisieren:
Jeweils nur eine der Bedingungen sollen geprüft werden
Eine Bedingung ist:
Ist y+x>Konstante1 dann x=Konstante1-y
Die andere Bedienung ist:
Ist y-x<Konstante2 dann x=y-Konstante2
Die erste Bedingung habe ich so umgesetzt:
1
.equ Konstante1=39230
2
.equ Konstante2=93
3
4
mov r15,xl
5
mov r16,xh
6
add r15,yl
7
adc r16,yh
8
9
mov r17,r15 ; In r17 und r18 das Ergebnis sichern für später
10
mov r18,r16
11
12
subi r15,low(Konstante1)
13
sbci r16,high(Konstante1)
14
brcs ende_v1
15
16
sub xl,r15
17
sbc xh,r16
18
ldi r17,low(Konstante1)
19
ldi r18,high(Konstante1)
20
21
ende_v1:
Damit dachte ich die erste Bedingung gelöst zu haben.
Doch bei der Zweiten bin ich am verzweifeln.
Könnte mir jemand auf die Sprünge helfen?
R. Brettschneider schrieb:> Hallo liebe Forenmitglieder.> Ich stehe vor der Aufgabe folgendes in Assembler zu realisieren:>> Jeweils nur eine der Bedingungen sollen geprüft werden>> Eine Bedingung ist:> Ist y+x>Konstante1 dann x=Konstante1-y
Ist doch einfach. Addieren, vergleichen, springen, zuweisen.
> Die andere Bedienung ist:> Ist y-x<Konstante2 dann x=y-Konstante2
Dito.
> Die erste Bedingung habe ich so umgesetzt: .equ Konstante1=39230> .equ Konstante2=93>> mov r15,xl> mov r16,xh> add r15,yl> adc r16,yh>> mov r17,r15 ; In r17 und r18 das Ergebnis sichern für später> mov r18,r16>> subi r15,low(Konstante1)> sbci r16,high(Konstante1)
Vergleichen tut man mit cp bzw. cpc. Das ist mathematisch identisch zum
Subtrahieren, allerdings wird das Ergebnis nicht ins Register
geschrieben, nur die Flags werden gesetzt.
> brcs ende_v1>> sub xl,r15> sbc xh,r16> ldi r17,low(Konstante1)> ldi r18,high(Konstante1)
Na das überlegen wir uns noch einmal.
> ende_v1:>> Damit dachte ich die erste Bedingung gelöst zu haben.
Nö.
> Doch bei der Zweiten bin ich am verzweifeln.
Warum? Die ist doch nahezu identisch? Oder hast du die "Lösung" nur
abgeschrieben?
> Könnte mir jemand auf die Sprünge helfen?
Wo liegt das Problem? Wenn du x+y rechnen kannst, kannst du doch wohl
auch y-x rechnen, oder?
R. Brettschneider schrieb:> mov r15,yl> mov r16,yh> sub r15,xl> sbc r16,xh>> mov r17,r15 ; In r17 und r18 das Ergebnis sichern für später> mov r18 r16> brmi negativ
Was soll das hier?
> subi r15,low(Konstante2)> sbci r16,high(Konstante2)> brcc ende_v2> negativ:> mov r15,yl> mov r16,yh> subi r15,low(Konstante2)> sbci r16,high(Konstante2)> mov xl,r15> mov xh,r16
Das kann man gleich in xl, xh rechnen, spart 2 Befehle und Takte.
Dieser Vergleich incl. der Zuweisung stimmt.
R. Brettschneider schrieb:> Doch bei der Zweiten bin ich am verzweifeln.
Als ich mal asm programmieren musste und nicht weiter kam, habe ich es
in C programmiert und angeschaut, was der Compiler draus macht im
asm-listing. Das kann helfen.
Ingo Less schrieb:> Als ich mal asm programmieren musste und nicht weiter kam, habe ich es> in C programmiert und angeschaut, was der Compiler draus macht im> asm-listing. Das kann helfen.
Danke für die Antwort doch dazu müsste ich C können.
R. Brettschneider schrieb:> Ich dachte, geht die Rechnung schon ins negative bin ich ja schon unter> der Konstante2
Das ist nicht gefordert. Vergiss bei solchen Sachen erstmal irgendwelche
Optimierung und Tricks sondern schreib das ganz formal auf.
Ein paar Tipps:
- Die Bedingungen lassen sich folgendermaßen umschreiben:
Erste Bedingung:
t = Konstante1 - y
Ist x > t dann x = t
Zweite Bedingung:
t = y - Konstante2
Ist x > t dann x = t
- Die Befehle mit Immediate-Operanden (LDI, SUBI usw.) funktionieren nur
für die Register R16..R31. Insbesondere
1
subi r15,low(Konstante2)
geht also nicht.
- Lädt man 16-Bit-Werte so in die Register, dass das Low-Byte in einem
geradzahligen und das High-Byte im nächsthöheren (ungeradzahligen)
Register steht, kann man MOVW für schnelle 16-Bit-Registertransfers
nutzen.
Falk B. schrieb:> Das ist nicht gefordert. Vergiss bei solchen Sachen erstmal irgendwelche> Optimierung und Tricks sondern schreib das ganz formal auf.
Nun: Ist y-x<Konstante2 dann x=y-Konstante2
Y-X könnte ja bei:
.equ Konstante2=0x5D (93)
Y=0x5E (94)
X=0x9C (156)
Y-X=0xFFC2 (65474) werden. Da nachher ein Vergleich ob 0xFFC2<0x5D ist,
nicht erfolgreich wäre dachte ich mir ich prüfe es mit dem N-Flag im
SREG.
Möchte mit der Erklärung nur meine Denkweise aufzeigen.
R. Brettschneider schrieb:> Y-X=0xFFC2 (65474) werden. Da nachher ein Vergleich ob 0xFFC2<0x5D ist,> nicht erfolgreich wäre dachte ich mir ich prüfe es mit dem N-Flag im> SREG.
OK, hast recht.
> Möchte mit der Erklärung nur meine Denkweise aufzeigen.
Vollkommen OK.
Yalu X. schrieb:> - Die Befehle mit Immediate-Operanden (LDI, SUBI usw.) funktionieren nur> für die Register R16..R31. Insbesondere>> subi r15,low(Konstante2)> geht also nicht.
Richtig und danke. Ich habe hier meine .def für die Register entfernt
und bei umschreiben in rxx fälschlicherweise bei r15 angefangen. Also
nur ein reiner hier rein geschriebener Fehler.
Danke für den Tipp mit MOVW bin noch ganz am Anfang im Assembler.
Falk B. schrieb:> R. Brettschneider schrieb:>>> Y-X=0xFFC2 (65474) werden. Da nachher ein Vergleich ob 0xFFC2<0x5D ist,>> nicht erfolgreich wäre dachte ich mir ich prüfe es mit dem N-Flag im>> SREG.>> OK, hast recht.>>> Möchte mit der Erklärung nur meine Denkweise aufzeigen.>> Vollkommen OK.
Doch leider wird bei:
Y=0x80F2 (33010)
X=0xA0 (160)
1
mov r16,yl
2
mov r17,yh
3
sub r16,xl
4
sbc r17,xh
5
6
mov r18,r16 ; In r18 und r19 das Ergebnis sichern für später
Müssen Unter- und Überläufe tatsächlich in der Aufgabe berücksichtigt
werden? Wenn ja, dann musst du auch den Fall x+y>65535 in der ersten
Bedingung behandeln.
Und was soll bei
x=Konstante1-y
und
x=y-Konstante2
geschehen, wenn y>Konstante1 bzw. y<Konstante2 ist und damit das
Ergebnis negatiov wird?
Die Bedingung:
Ist y+x>Konstante1 dann x=Konstante1-y
Habe ich nun so umgesetzt:
1
mov r16 Dummy2,xl
2
mov r17 Dummy3,xh
3
add r16,yl
4
adc r17,yh
5
6
mov r18,r16
7
mov r19,r17
8
subi r16,low(Konstante1)
9
sbci r17,high(Konstante1)
10
BRCS ende_v1
11
sub xl,r16
12
sbc xh,r17
13
ldi r18,low(Konstante1)
14
ldi r19,high(Konstante1)
15
16
ende_v1:
X wird nun nie höher als das Y+X den Wert von Konstante1 überschreiten
und in R18 und R19 habe ich das Ergebnis von Y+X. Y bleibt davon
unverändert. Das war mein Ziel.
Die Bedingung:
Ist y-x<Konstante2 dann x=y-Konstante2
Habe ich nun auch zum laufen gebracht:
1
mov r16,yl
2
mov r17,yh
3
sub r16,xl
4
sbc r17,xh
5
6
mov r18,r16
7
mov r19,r17
8
cpi r17,0xC0
9
brsh Negativ
10
11
subi r16,low(Konstante2)
12
sbci r17,high(Konstante2)
13
brcc ende_v2
14
Negativ:
15
mov r16,yl
16
mov r17,yh
17
subi r16,low(Konstante2)
18
sbci r17,high(Konstante2)
19
mov xl,r16
20
mov xh,r17
21
ldi r18,low(Konstante2)
22
ldi r19,high(Konstante2)
23
24
ende_v2:
X wird nun nie kleiner als das Y-X den Wert von Konstante2
unterschreitet und in R18 und R19 habe ich das Ergebnis von Y-X. Y
bleibt davon unverändert. Auch das war mein Ziel.
Läuft also soweit. Doch habe ich gemerkt das ich wohl einiges falsch
mache, bzw umständlich. Aller Anfang ist schwer.
Was könnte ich noch mal überdenken? MOVW werde ich nun mal angehen.
Yalu X. schrieb:> Müssen Unter- und Überläufe tatsächlich in der Aufgabe berücksichtigt> werden? Wenn ja, dann musst du auch den Fall x+y>65535 in der ersten> Bedingung behandeln.>> Und was soll bei>> x=Konstante1-y>> und>> x=y-Konstante2>> geschehen, wenn y>Konstante1 bzw. y<Konstante2 ist und damit das> Ergebnis negatiov wird?
Ja, das sollte man tun.
Hier etwas zum ausprobieren (Aus dem Kopf, All Wrongs reserved)
1
;***** Register Variables
2
.def cmp_lo = r16
3
.def cmp_hi = r17
4
5
.def x_lo = r18
6
.def x_hi = r19
7
.def y_lo = r20
8
.def y_hi = r21
9
10
.def add_lo = r24
11
.def add_hi = r25
12
13
.equ Konstante1 = 39230
14
.equ Konstante2 = 93
15
16
;*****
17
cpBdng1:
18
ldi cmp_lo, low(Konstante1)
19
ldi cmp_hi, high(Konstante1)
20
movw add_lo, x_lo
21
22
add add_lo, y_lo
23
adc add_hi, y_hi
24
brcs err_ovrflw ;* (x+y) > 0xFFFF
25
26
sbiw add_lo, 1 ;* Damit nicht auf >= geprueft wird
Yalu X. schrieb:> Müssen Unter- und Überläufe tatsächlich in der Aufgabe berücksichtigt> werden? Wenn ja, dann musst du auch den Fall x+y>65535 in der ersten> Bedingung behandeln.
Das kann in diesem Fall nicht passieren, weil Konstante1 bei 39230 oder
kleiner liegt und Y bei Konstante2 erst anfängt, in dem Fall bei 93 oder
größer. X wird nie mehr als 255 auf ein Schlag größer und bei jeder
Zunahme getestet.
Peter D. schrieb:> Daß Konstante1 >= y >= Konstante2 gilt, dafür muß Du natürlich sorgen.
Und auch dafür, daß Y > X ist.
Und auch dafür, daß (Y + X) <= #FFFF.
Nachdem das alles geprüft wird, bleibt einmal addieren oder
subtrahieren, danach einmal vergleichen und ev. das Resultat
in X-Reg. umladen auf jeden Fall.
> Ich würde daher die Vereinfachung von Yalu nehmen:> Beitrag "Re: Vergleichen von x und y in Assembler"
Deswegen ist die Vereinfachung (und es ist nicht gesagt, daß dies
überhaupt eine Vereinfachung ist) nicht immer der bessere Weg.
Vor allem in Assembler sind übersichtliches codieren und reichlich
Komentare sehr, sehr wichtig.
Ansonsten überlegt man was der Zweck dieser Vereinfachung ist,
vor allem wenn man sich das Ganze nach ein paar Monaten anschaut.
Marc V. schrieb:> Vor allem in Assembler sind übersichtliches codieren und reichlich> Komentare sehr, sehr wichtig.
Das sehe ich auch so.
Die original Aufgabe ist für mich völlig unverständlich.
Erst die Vereinfachung macht die Funktion klar erkennbar, X soll auf
einen Bereich begrenzt werden.
Gerade in Assembler sollte man daher zu verschwurbelte Konstrukte
meiden.
Hier mal die einfache Variante: