Forum: Mikrocontroller und Digitale Elektronik assembler division mit rest


von M. S. (sadmarvin)


Lesenswert?

Für ein Programm brauche ich eine Routine die durch 10 teilt.
Ich brauche das Ergebnis und den Rest.

Ich habe mir dies hier überlegt
1
.def ergebnis = r1
2
.def rest =  r2
3
.def divident = r16
4
5
division10:        ; division durch 10 mit Rest
6
  clr    ergebnis
7
  clr    rest
8
div10:
9
  mov   rest, divident
10
  subi  divident, 10
11
  inc   ergebnis
12
  brmi  div10_ende    ; Sprung wenn divident < 0
13
  rjmp  div10
14
div10_ende:
15
  dec    ergebnis    
16
  ret

nach aufruf der Routine sollte jetzt ja das Ergebins in "ergebnis" und 
der Rest in "rest" stehen.

Ist das so richtig?

von Ansgar K. (paulderbademeister)


Lesenswert?

Zwei Dinge solltest du überprüfen:

1. Welche Flags können durch INC verändert werden und welche werden 
durch BRMI geprüft?

2. Was steht in deinem Rest? Der wird kein einziges mal verändert.

von Spess53 (Gast)


Lesenswert?

Hi

>Ich habe mir dies hier überlegt

Ich dies:
1
.def ergebnis = r1
2
.def rest =  r2
3
.def divident = r16
4
5
division10:        ; division durch 10 mit Rest
6
  ldi ergebnis,-1
7
  mov   rest, divident
8
div10:
9
  inc   ergebnis
10
  subi  rest, 10
11
  brcc  div10    ; Sprung wenn divident > 0
12
  add rest,10
13
  ret

MfG Spess

von Spess53 (Gast)


Lesenswert?

Hi

Korrektur:

  add rest,10 -> subi rest, -10

MfG Spess

von M. S. (sadmarvin)


Lesenswert?

Ansgar K. schrieb:
> Zwei Dinge solltest du überprüfen:
>
> 1. Welche Flags können durch INC verändert werden und welche werden
> durch BRMI geprüft?

Ah, ja das INC das N Flag verändert hatte ich nicht berücksichtigt.

>
> 2. Was steht in deinem Rest? Der wird kein einziges mal verändert.

Hm, eigentlich doch jedesmal am Anfang von div10:

mov  rest, divident

EDIT:
so müsste es doch dann klappen, oder?
1
.def ergebnis = r1
2
.def rest =  r2
3
.def divident = r16
4
5
division10:        ; division durch 10 mit Rest
6
  clr    ergebnis
7
  clr    rest
8
div10:
9
  mov   rest, divident
10
  subi  divident, 10
11
  brmi  div10_ende    ; Sprung wenn divident < 0
12
  inc   ergebnis
13
  rjmp  div10
14
div10_ende:
15
  ret

von Ansgar K. (paulderbademeister)


Lesenswert?

Stimmt, da hatte ich einen kleinen Denkfehler was den Rest angeht - das 
funktioniert tatsächlich so, ist aber umständlich.

Dein neuer Code sollte so gut funktionieren, falls es dir nicht um 
maximale Geschwindigkeit geht. Falls doch, solltest du dir einmal den 
Vorschlag von Spess angucken, er braucht in seiner Schleife nur 4 statt 
deiner 7 Zyklen.

Noch schneller wäre eine Multiplikation mit 0.1, falls ein 
Hardwaremultiplizierer zur Verfügung steht. In 99% der Fälle dürfte 
deine Lösung aber gute Dienste leisten.

von M. S. (sadmarvin)


Lesenswert?

ok,

werde mir die version von Spess angucken.

von M. S. (sadmarvin)


Lesenswert?

Spess53 schrieb:
> Hi
>
> Korrektur:
>
>   add rest,10 -> subi rest, -10
>
> MfG Spess

Ich habe mir den Spess Code mal angeguckt und auch verstanden.
Aber warum kein add ?

Weil man das nur auf zwei Register anwenden kann?

wenn ich jetzt noch ein Register als divident definieren und mit 10 
laden würde, könnte ich doch auch add nehmen, oder?

und dann halt SUB statt SUBI

von M. S. (sadmarvin)


Lesenswert?

Korrektur

divident -> divisor

von Spess53 (Gast)


Lesenswert?

Hi

>Weil man das nur auf zwei Register anwenden kann?

Richtig.

>wenn ich jetzt noch ein Register als divident definieren und mit 10
>laden würde, könnte ich doch auch add nehmen, oder?

Wozu? Das 'subi' erfüllt seinen Zweck.

>wenn ich jetzt noch ein Register als divident definieren und mit 10
>laden würde, könnte ich doch auch add nehmen, oder?

>und dann halt SUB statt SUBI

Was hast du davon?

MfG Spess

von M. S. (sadmarvin)


Lesenswert?

nochmal ich ;)

bin grad doch etwas verwirrt

In der Beschreibung von SUBI und SUB steht ja

"Das C-Flag wird gesetzt, wenn der absolute Wert der Konstante größer 
als der absolute Wert von Rd ist, andernfalls wird es gelöscht."

müsste man dann bei verwendung von BRCC nicht die Addition nach der 
Schleife weglassen? (ergbnis am Anfang = 0)

EDIT:
oder bezieht sich die Beschreibung auf die Registerinhalte vor der 
Subtraktion?

von Spess53 (Gast)


Lesenswert?

Hi

>(ergbnis am Anfang = 0)

Ergebnis am Anfang ist -1  ->  ldi ergebnis,-1

Dann folgt ein inc ergebnis -> ergebnis=0

Danach die Subtraktion. Wenn Rest<10 ist wird das Carry-Flag gesetzt und 
nicht wieder nach 'div10' gesprungen. Ergebnis hat damit den richtigen 
Wert und mit 'subi rest, -10' wird die letzte Subtraktion rückgängig 
gemacht.

MfG Spess

von M. S. (sadmarvin)


Lesenswert?

ich glaube mein Denkfehler war, dass ich dachte der Vergleich zwichen 
rest und 10 zum setzen des Carry Flags wird mit dem Inhalt den reset 
NACH der Subtraktion hat gemacht, kann das sein?

also:

z.B. rest = 12

12 - 10 = 2 --> 2 < 10 --> C-Flag = 1

aber es ist

12 > 10 -- > C-Flag = 0

von Spess53 (Gast)


Lesenswert?

Hi

>aber es ist

>12 > 10 -- > C-Flag = 0

Bingo.

von M. S. (sadmarvin)


Lesenswert?

ok, hab ich wohl zu kompliziert gedacht ;)

von Spess53 (Gast)


Lesenswert?

Hi

>ok, hab ich wohl zu kompliziert gedacht ;)

Kommt vor. Wenn du breq/ne/cc/cs richtig verstanden hast, kannst du 
damit 99,... aller Fälle erschlagen.

MfG Spess

von M. S. (sadmarvin)


Lesenswert?

Ja, danke Dir. :)

Ich bin ja grad erst am Assembler lernen, wird schon noch mit der Zeit. 
;)

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.