Vergleichen von x und y in Assembler

Gast #5776558
Lesenswert?

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?
#5776571
Lesenswert?

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?
Gast #5776576
Lesenswert?

Entschuldigung habe vergessen meinen Lösungsansatz für die zweite 
Bedingung mitzugeben.
1
   mov   r15,yl
2
   mov   r16,yh
3
   sub   r15,xl
4
   sbc   r16,xh
5

6
   mov   r17,r15  ; In r17 und r18 das Ergebnis sichern für später
7
   mov   r18 r16
8
   brmi  negativ
9
   
10
   subi  r15,low(Konstante2)
11
   sbci  r16,high(Konstante2)
12
   brcc  ende_v2
13
negativ:
14
   mov   r15,yl
15
   mov   r16,yh
16
   subi  r15,low(Konstante2)
17
   sbci  r16,high(Konstante2)
18
   mov   xl,r15
19
   mov   xh,r16
20
   ldi   r17,low(Konstante2)
21
   ldi   r18,high(Konstante2)
22

23
ende_v2:
#5776587
Lesenswert?

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.
Moderator #5776641
Lesenswert?

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.
Gast #5776647
Lesenswert?

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.
Gast #5776667
Lesenswert?

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.
Gast #5776677
Lesenswert?

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
7
   mov   r19 r17
8
   brmi  negativ

Das N-Flag im SREG auch gesetzt.
Gast #5776731
Lesenswert?

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.
(Firma: Vescomp) #5776737
Lesenswert?

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
27
  cp  add_lo, cmp_lo
28
  cpc  add_hi, cmp_hi
29
  brcs  SumLow      ;* Summe kleiner als Konstante1
30
SumGrt:  
31
  sub  cmp_lo, y_lo
32
  sbc  cmp_hi, y_hi
33
  movw  x_lo, cmp_lo
34
  ret
35
SumLow:
36
  ;* Fehler - do etwas mit x_Reg (oder auch nicht)
37
  ret
38
err_ovrflw:
39
  ;* Fehler - do etwas mit x_Reg (oder auch nicht)
40
  ret
41

42
;***** 
43
cpBdng2:
44
  cp  y_lo, x_lo
45
  cpc  y_hi, x_hi
46
  brcs  Bdng2_YLow      ;* Y kleiner als X
47

48
  ldi  cmp_lo, low(Konstante2)
49
  ldi  cmp_hi, high(Konstante2)
50
  movw  add_lo, y_lo
51
  sub  add_lo, x_lo
52
  sbc  add_hi, x_hi    ;* Y-X
53
  cp  add_lo, cmp_lo    ;* (Y-X) < Konstante2 ?
54
  cpc  add_hi, cmp_hi
55
  brcs  Bdng2_OK
56
Bdng2_Err:
57
  ;* Fehler - do etwas mit x_Reg (oder auch nicht)
58
  ret
59
Bdng2_OK:
60
  cp  y_lo, cmp_lo
61
  cpc  y_hi, cmp_hi
62
  brcs  Bdng2_ovrflw    ;* Y < Konstante2 == Error
63
  movw  add_lo, y_lo
64
  sub  add_lo, cmp_lo
65
  sbc  add_hi, cmp_hi
66
  movw  x_lo, add_lo
67
  ret
68
Bdng2_YLow:
69
  ;* Fehler - do etwas mit x_Reg (oder auch nicht)
70
  ret
71
Bdng2_ovrflw:
72
  ;* Fehler - do etwas mit x_Reg (oder auch nicht)
73
  ret
Gast #5776740
Lesenswert?

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.
(Firma: Vescomp) #5776893
Lesenswert?

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.
#5776926
Lesenswert?

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:
1
;  t = Konstante1 - y
2
  ldi   tl, low(K1)
3
  ldi   th, high(K1)
4
  sub   tl, yl
5
  sbc   th, vh
6
;  brcs error           ; handle overflow
7
;  Ist x > t dann x = t
8
  cp    tl, xl
9
  cpc   th, xh
10
  brcc  m1
11
  movw  xl, tl
12
m1:
13
;  t = y - Konstante2
14
  movw  tl, yl
15
  subi  tl, low(K2)
16
  sbci  th, high(K2)
17
;  brcs error           ; handle overflow
18
;  Ist x > t dann x = t
19
  cp    tl, xl
20
  cpc   th, xh
21
  brcc  m2
22
  movw  xl, tl
23
m2:

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren