PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Rechnen mit 3 Registern



Philipp83
02.03.2006, 18:42
Einen schönen guten Abend erstmal !

Also ich habe eine Zahl in 3 Registern ( 5000000 )
möchte diese nun durch die in 2 Registern stehende ( 36500)
teilen. Es sollte 136 rauskommen.

Aber wie kann ich Binär eine Zahl die in 3 Registern steht,
durch eine andere die in 2 Registern steht teilen?

Es wäre wirklich super !!! wenn mir einer die vorgehensweise erläutern kann


mfg, Philipp

SprinterSB
02.03.2006, 18:47
Eigentlich nimmt man da "Schuldivision" (wie man sie in der Grundschule lernt).

Kommt darauf an, in welcher Sprache du das formulieren willst... oder willst du eine algerbraisch formale Beschreibung???

Philipp83
02.03.2006, 19:47
Naja, mir ist der ganze logische Ablauf nicht so ganz klar :-(

Was muss ich mit welchem register in welcher Reihenfolge machen und was gibt es im uC vielleicht für fertige befehle dafür?

AlexAtRobo
02.03.2006, 22:06
Hallo Philipp,

das ist beim AVR nur mit guter Handarbeit zu erledigen. Hab mal eben ein Muster zusammengeschusselt, ich denke es sollte funktioneren - aber vorher unbedingt testen - ich will nicht schuld sein, wenn deine Bombe zufrüh hochgeht weil die Rechnung nicht stimmt :-D

.def rd1hh=r16
.def rd1h=r17
.def rd1l=r18
.def rd2h=r19
.def rd2l=r20
.def rd1ul=r21
.def rd1uh=r22
.def rehh=r23
.def reh=r24
.def rel=r25

div:
ldi rd1hh, 0x4c
ldi rd1h, 0x4b
ldi rd1l, 0x40

ldi rd2h, 0x8e
ldi rd2l, 0x94

clr rd1ul ;Hilfsregister
clr rd1uh

clr rehh ; Ergebnis rehh:reh:rel
clr reh ;
clr rel ; (Ergebnisregister dient auch als
inc rel ; Zähler bis 24! Bit 1 auf 1 setzen) diese 1 wird immer weiter nach links geschoben, wenn sie
; rauskommt sind wir fertig
;
; Hier beginnt die Divisionsschleife
;
div1:
clc ; Carry-Bit leeren
rol rd1l ; nächsthöheres Bit des Dividenten
rol rd1h ; in das Hilfsregister rotieren
rol rd1hh ;
rol rd1ul ;
rol rd1uh ;
brcs div2 ; Eine 1 ist herausgerollt, ziehe ab

cp rd1uh, rd2h
brcs div3
cp rd1ul,rd2l ; Divisionsergebnis 1 oder 0?
brcs div3 ; Überspringe Subtraktion, wenn kleiner
div2:
sub rd1ul,rd2l ; Subtrahiere Divisor
sbc rd1uh,rd2h
sec ; Setze carry-bit, Ergebnis ist eine 1
rjmp div4 ; zum Schieben des Ergebnisses
div3:
clc ; Lösche carry-bit, Ergebnis ist eine 0
div4:
rol rel ; Rotiere carry-bit in das Ergebnis
rol reh
rol rehh
brcc div1 ; solange Nullen aus dem Ergebnis
; rotieren: weitermachen


Zum erklären: am besten AVR Studio runterladen (vielleicht hast dus ja schon) und simulieren und beobachten - dann verstehen versuchen.
Im Prinzip schiebt man die 5000000 nach links raus in 2 Hilfsregister und schaut, ob man davon schon die 36500 abziehen kann. Wenn ja, ins Ergebnis eine 1 schieben sonst eine 0. Ein Sonderfall kann eintreten, nämlich das beim Hilfsregister auch eine 1 rauskommt. Die kannst du dann gleich ins Ergebnis schieben.
Wie gesagt, simulieren und studieren, dann klappts auch mit dem Assembler ;-).
Das ganze oben ist natürlich jetzt ziemlich roh, in eine Unterroutine verpackt kannst du da noch einige Register einsparen (push / pop) werte aus dem Ram holen etc. Mußt dir halt eine gute Schnittstelle überlegen je nach Anwendung.

Was wirds wenns fertig ist?

lg

Alex

SprinterSB
03.03.2006, 10:23
Vom Prinzip her ist die Vorgehensweise so, wenn man quot = a / b und mod = a modulo b berechnen will:
Erweitere b zu einem 24-Bit-Wert, indem man es expandiert. Wie expandiert wird, ist abhängig davon, ob die Werte Vorzeichen haben oder nicht. Ist b ohne Vorzeichen (also >= 0) wird es mit Nullen aufgefüllt. Ist b vorzeichenbehaftet, wird das obere Bit von b zum Füllen verwendet
Merke die Vorzeichen ersetzte a, b durch ihre Beträge
Falls b=0 dann FEHLER
Falls b > a oder a=0 dann quot:=0, mod=:a, Gehe zu 12.
mask:=1, quot := 0
Schiebe mask und b so lange nach links, bis das obere Bit von b mit dem oberen Bit von a übereinstimmt
Falls b<=a dann a := a-b, quot := quot OR mask
Schiebe b und mask um 1 nach rechts
Falls b ungleich 0 dann gehe zu 7.
mod := a
Rechne die gemerkten Vorzeichen von a und b in das Ergebnis ein
Fertig


Von a werden also 2er-Potenzen von b abgezogen, falls dieser Wert <= a ist. Wie hoch die Potenz ist merkt mask. Im Falle einer Subtraktion wird zum Ergebnis mask addiert (in diesem speziellen Fall geht ein OR (bitweise ODER), gleichbedeutend und gleicheffizient für AVR ist eine Addition).

Linksschieben geht mit
add R0, R0
addc R1, R1
addc R2, R2
...
Für addc x, x ist auch die Abkürzung rol x gebräuchlich, für add x, x auch lsl x oder asl x

Zum Vergleichen nimmt man
cp A0, B0
cpc A1, B1
cpc A2, B2
...
cp und cpc funktionieren genauso wie Subtraktion, nur das A nicht verändert wird, sondern nur die Flags, Mit dem Carry-Flag kann man auf größer/kleiner testen, mit dem Zero-Flag auf Gleichheit, etc

Philipp83
09.05.2006, 20:43
habe grad ein problem mit dem obigen programm:

und zwar müsste doch beim dividieren von EA60 / 1388 also:
rd1hh: 0x00
rd1h: 0xEA
rd1l: 0x60

rd2h: 0x13
rd2l: 0x88

das Ergebnis C rauskommen oder?

es kommt aber nur 4 raus.

Ist das obige programm falsch?????

BITTE UM SCHNELLE HILFE !!!

SprinterSB
09.05.2006, 23:06
Jaja, offenbar. Das Ergebnis ist wie gesagt 0xc.

Philipp83
10.05.2006, 06:46
UPS, ich meinte auch nicht 1888 sondern 1388.

dabei kommt ein falsches ergenbnis raus

AlexAtRobo
10.05.2006, 08:27
Ja, da war ein Fehler drinnen.


cp rd1uh, rd2h
brcs div3
cp rd1ul,rd2l ; Divisionsergebnis 1 oder 0?
brcs div3 ; Überspringe Subtraktion, wenn kleiner
div2:
ist natürlich topfen....

cp rd1ul,rd2l ; Divisionsergebnis 1 oder 0?
cpc rd1uh, rd2h
brcs div3 ; Überspringe Subtraktion, wenn kleiner

So ist es gleich viel besser.. ;-) Sorry.

lg

Alex

10.05.2006, 11:46
Klasse!!

Ich danke dir vielmals!!!!!