32 Bit-Wert mit 16 Bit-Register als dezimale ASCIIs ausgeben?

20/09/2011 - 21:55 von Dirk Wolfgang Glomp | Report spam
Hallo Leute,
ich möchte auf einem 80286 mit 16 Bit-Integer-Registern/Befehlen einen 32
Bit-Wert als ASCIIs am Bildschirm ausgeben.

Auf einem 80386 mit 32 Bit-Registern kann man beispielsweise den Wert von
4.294.967.295 mit einem 32 Bit-Divisor von 1.000.000.000 teilen, um die
höchste Ziffer (in diesem Fall eine 4) daraus zu bekommen.

Wie stelle ich es aber mit 16 Bit-Register an, denn wenn ich den 32 Bit
Wert von 4.294.967.295 in DX:AX durch einen 16 Bit-Divisor von 10.0000
zu teilen versuchen würde, dann dürfte das Ergebnis davon ja nicht in das
Zielregister passen.

Kann jemand einen einfachen Lösungsweg mit der Verwendung von 16
Bit-Registern aufzeigen?

(Momentan habe ich hierbei ein Brett vor dem Kopf. Für jeden Hinweis
bedanke ich mich im voraus.)

Ich selber habe dafür bisher immer nur 32 Bit-Register verwendet
und so brauchte ich mir darüber bisher nie Gedanken machen, wie es denn
eigentlich nur mit 16 Bit-Register/Befehle funktionieren könnte.

(Für die Wandlung eines dezimalen Wertes von 0-9 nach ASCII und die Ausgabe
am Bildschirm und/oder für eine Berechnung über die FPU und/oder die
Berechnung über 32 Bit-Register/Befehle brauche ich keine Hilfe.)

Dirk
 

Lesen sie die antworten

#1 Heiko Nocon
20/09/2011 - 23:34 | Warnen spam
Dirk Wolfgang Glomp wrote:

ich möchte auf einem 80286 mit 16 Bit-Integer-Registern/Befehlen einen 32
Bit-Wert als ASCIIs am Bildschirm ausgeben.

Auf einem 80386 mit 32 Bit-Registern kann man beispielsweise den Wert von
4.294.967.295 mit einem 32 Bit-Divisor von 1.000.000.000 teilen, um die
höchste Ziffer (in diesem Fall eine 4) daraus zu bekommen.

Wie stelle ich es aber mit 16 Bit-Register an, denn wenn ich den 32 Bit
Wert von 4.294.967.295 in DX:AX durch einen 16 Bit-Divisor von 10.0000
zu teilen versuchen würde, dann dürfte das Ergebnis davon ja nicht in das
Zielregister passen.

Kann jemand einen einfachen Lösungsweg mit der Verwendung von 16
Bit-Registern aufzeigen?



Schriftliche Division kannst du doch sicherlich? Also aus der Schule und
im Dezimalsystem.

Nun, genau dasselbe Prinzip verwendet man auch zum dividieren im
Binàrsystem. Da ergeben sich sogar einige Vereinfachungen, denn im
Dezimalsystem muß man überlegen, wie oft der Divisor in der aktuellen
Verschiebungsposition in den Dividenden paßt. Das ist im Binàrsystem
nicht nötig, denn da gibt nur zwei Möglichkeiten: Entweder er paßt ein
mal oder null mal.

Ich selber habe dafür bisher immer nur 32 Bit-Register verwendet
und so brauchte ich mir darüber bisher nie Gedanken machen, wie es denn
eigentlich nur mit 16 Bit-Register/Befehle funktionieren könnte.



Das Prinzip funktioniert sogar noch, wenn man nur eine Maschine mit nur
einem Bit Wortbreite hat. Nur die Zahl der nötigen Instruktionen ist
dann natürlich entsprechend höher.

Das Prinzip in Pseudocode für 32 Bit breite Register/Werte geht so:

Startwert Endwert

R0: Dividend Rest
R1: Divisor (unwichtig)
R2: 1 1
R3: 0 Quotient

linksausrichten:
Oberstes Bit von R1 gesetzt oder R1>=R0?
Ja:
goto dividieren
Nein:
schiebe R1 und R2 je ein Bit nach links
goto linksausrichten

dividieren:
R0=R0-R1
Unterlauf dabei passiert?
Ja:
R0=R0+R1
goto testfertig
Nein:
R3=R3+R2
goto testfertig

testfertig:
R2=1?
Ja:
goto fertig
Nein:
Schiebe R1 und R2 je ein Bit nach rechts
goto dividieren

fertig:
...

Soweit das Prinzip. Wenn man nur 16Bit-Register hat, muß man halt je
zwei verwenden (insgesamt braucht man dann also 8) und die
entsprechenden Additionen, Subtraktionen und Verschiebungen aus je zwei
Teilbefehlen zusammensetzen, wobei üblicherweise der Übertrag via
Carry-Flag passiert. Schieben nach links für Register R1, bestehend aus
den 16-Bit-Registern R1a (hiword) und R1b (loword), würde also z.B. so
umgesetzt werden: SchiebeLinks R1b (rausgeschobenes Bit landet im
Carryflag), Rotierelinks"through carry" R1a (Bit aus carry landet im
untersten Bit von R1a).
Schieben nach rechts funktioniert analog, man muß bloß mit dem hiword
beginnen. Also: SchiebeRechts R1a, dann RotiereRechts"through carry"
R1b.
Auch Addition und Subtraktion setzen jeweils bei Über/Unterlauf das
Carryflag und es gibt jeweils Varianten der Befehle, die den Zustand des
Carryflags in das Ergebnis einbeziehen. Im Unterschied zu den
Verschiebungen fàngt man bei Addition/Subtraktion aber immer mit dem
loword an zu rechnen. Also z.B.: Addiere R0 (R0a:R0b) und R1 (R1a:R1b)
geht so: Addiere R0b=R0b+R1b (eventueller Überlauf landet im Carryflag),
dann AdddiereMitCarry R0a=R0a+R1a (wird dann hier in Rechenergebnis mit
einbezogen, es werden also eigentlich drei Zahlen addiert)

Bei noch schmaleren Registern muß man dann die Sache analog weiter
untersetzen, bei 8Bit-Registern besteht also so eine Verschiebung oder
Addition bereits aus vier Instruktionen.

Der Punkt ist: Das Prinzip ist immer das Gleiche. Genau dasselbe wie
beim aus der Schule bekannten "schriftlichen Dividieren", was eigentlich
nichts anderes ist als wiederholtes Subtrahieren. Sieht man im
Pseudocode auch sehr schön, direkt die erste Instruktion nach dem
"dividieren:"-Label ist die Subtraktionsoperation, die den Kern der
Sache darstellt.

Ähnliche fragen