Magic Disk 64

home to index to text: MD9407-KURSE-ASSEMBLER_KURS_2_(TEIL_9).txt

Assembler-Kurs Teil 9

Multipilkation und Division             

Die Addition und Subtraktion von ganzen Zahlen mit ADC und SBC war noch recht einfach. Leider gibt es aber keine Assmblerbefehle wie MULT oder DIV, die unsere Berechnungen übernehmen könnten.
Wenn wir eine Multiplikation durchführen wollen, dann müßten wir eigentlich ein Programm dafür schreiben, was allerdings eine ziemliche Quälerei wäre, da wir das Problem über Additionen lösen müßten.
Glücklicherweise gibt es auch für dieses Problem eine geeignete ROM-Routine ($ B357) . Der Faktor muß dafür in den Speicherstellen $28 und $29, der zweite Faktor in $71/$72 bereitgestellt werden.
Das Ergebnis dieser 16- Bit-Multi- plikation erhalten wir im X-( niederwertiges Byte) und Y-Register ( höherwertiges Byte) .
Dummerweise existiert keine entsprechende Routine für die Division. Hier tritt außerdem noch das Problem auf, daß beim Dividieren zweier ganzer Zahlen in den seltensten Fällen das Ergebnis eine ganze Zahl sein dürfte. Jetzt kommen wir um die gebrochenen Zahlen nicht mehr herum.

Die Flißkommazahlen (Floating Point,FLP)

Gebrochene Zahlen werden im allgemeinenn als Fließkommazahlen bezeichnet. Fließkommazahlen bestehen immer aus drei Teilen: der Mantisse, der Basis und dem Exponenten.
Betrachten wir zunächst eine dezimale FLP-Zahl:4500 ist darstellbar als 4 .5*10↑3, was der Darstellung 4 .5 E3 entspricht (4 .5 ist die Mantisse,3 der Exponent und 10 die Basis) . Die Zahl 0 .045 ließe sich auch als 4 .5*10↑-2(4 .5 E-2) schreiben. beachten Sie bitte, daß beide Zahlen auf dieselbe Matissenform gebracht wurden und sich lediglich noch im Exponenten unterscheiden. Das haben wir durch ein Linksbzw. Rechtsverschieben des Dezimalpunktes erreicht.
Bei dezimalen FLP-Zahlen ist das alles noch recht einfach, aber wie kann man binäre FLP-Zahlen in ein einheitliches Format bringen, so daß alle Zahlen dieselbe Anzahl von Bytes haben ?
Betrachten wir das Problem anhand eines Beispiels:
Die Dezimalzahl 50 .125 soll in eine binäre FLP-Zahl umgewandelt werden. Die Umwandlung erfolgt in 5 Schritten:
1 . Vorkommateil umwandeln Der Vorkommateil wird als Integerzahl behandelt und wie gewohnt umgerechnet

   50 : 2 = 25  Rest: 0    niederw. Bit 
   25 : 2 = 12  Rest: 1                 
   12 : 2 =  6  Rest: 0                 
    6 : 2 =  3  Rest: 0                 
    3 : 2 =  1  Rest: 1                 
    1 : 2 =  0  Rest: 1                 

Das Ergebnis :110010 2 . Nachkommateil umwandeln Die Stellen nach dem Binärpunkt haben die Wertigkeiten 2↑-1,2↑-2 usw.
Bei der Berechnung muß daher die Dezimalzahl immer mit 2 multipliziert werden, bei auftretenden Vorkommastellen wird das jeweilige Bit gesetzt.

   0.125 * 2 = 0.25 Vorkommast.: 0      
   0.25  * 2 = 0.5  Vorkommast.: 0      
   0.5   * 2 = 1    Vorkommast.: 1 n.Bit

Das Ergebnis : .001 3 . Normalisierung der Mantisse Unter Normalisierung versteht man das Anpassen der Mantisse an ein bestimmtes Format. Der Binärpunkt muß soweit verschoben werden, bis er links genau neben der höchstwertigen binären 1 steht.

   Vorherige Mantisse: 110010.001       
   Normalisierte Man.: 0.110010001 * 2↑6

In unserem Bespiel mußte der Binärpunkt um 6 Stellen nach links verschoben werden, was durch eine Multiplikation mit 2↑6 ausgegelichen werden muß, damit das Ergebnis nicht verfälscht wird.
Die Mantisse ist nun in der richtigen Form und wir haben auch unseren binären Exponenten (69 gefunden. Die binäre Basis ist logischerweise 2 .
4 . Umwandlung des Exponenten Zu unserem Exponenten 6 wird nun noch die Zahl 128 hinzuaddiert, damit es möglich ist, auch negative Exponenten, die bei der Normalisierung der Mantisse entstehen können, darzustellen. Bei der Rückumrechnung ( Binär -> Dezimal) ist daher daruaf zu achten, daß vom binären Exponenten 128 abzuziehen ist.

         6                              
     + 128                              
    -------                             
       134  (binär : 10000110)          

Ergebnis : Mantisse:0 .110010001 Exponent:10000110 Nun muß nur noch festgelegt werden, in wievielen Bytes diese Zahl abgespeichert werden soll.
5 . Floatingpoint-Zahlen des C64 Dieser Computer kennt zwei verschiedene Fließkommaformate, die sich hauptsächlich durch die Art der Speicherung des Vorzeichens unterscheiden. Die eine wird nur innerhalb der beiden Fließkommakkumulatoren verwendet, die andere beim Abspeichern der Ergebnisse im Arbeitsspeicher.
a) In den beiden Fließkommaakkumulatoren ( abgekürzt: FAC und ARG) werden alle Berechnungen von Fließkommazahlen mit Hilfe von ROM-Routinen durchgeführt.
Der FAC belegt in der Zeropage den bereich von Speicherstelle $61 bis $66, ARG von $69 bis $6 E. Welche Aufgabe die einzelnen Bytes havben, können Sie der nachfolgenden Tabelle entnehmen.

               FAC  ARG                 
   --------------------                 
   Exponent    $61  $69                 
   Mantisse 1  $62  $6A                 
   Mantisse 2  $63  $6B                 
   Mantisse 3  $64  $6C                 
   Mantisse 4  $65  $6D                 
   Vorzeichen  $66  $6E                 

Schauen wir nun, wie die FLP-Zahl aus unserem Beispiel im FAC oder ARG abgelegt wird. Der Exponent erhält 8 Bits, während sich die Mantisse auf 32 Bits ausbreiten darf. Die normalisierte Mantisse wird aber ab dem Binärpunkt linksbündig in die zur Verfügung stehenden Bytes eingetragen. Ist die Mantisse länger als 4 Bytes, so wird der überschüssige Teil einfach weggelassen.
So entstehen u. a. die heißgeliebten Rechenfehler in einem Computer.
Zusätzlich gibt es noch ein Byte, das das Vorzeichen enthält. Von diesem Byte ist jedoch nur das Bit 7 von Bedeutung(0-> positiv ;1-> negativ), die anderen Bits sind uninteressant.
Format der Fließkommaakkumulatoren:

              /--------\                
              |10000110|                
              \--------/                
               Exponent                 
 /--------+--------+--------+--------\  
 |11001000|10000000|00000000|00000000|  
 \--------+--------+--------+--------/  
      1        2        3        4      
            M A N T I S S E             
              /--------\                
              |0xxxxxxx|                
              \--------/                
              Vorzeichen                

In hexadezimaler Form ergibt das:
86 C880000000 Sicher halten Sie die benutzung eines ganzen Bytes für nur ein Vorzeichenbit für Verschwendung. In den Flißkommaakkumulatoren stört das jedoch niemanden, da es ohnehin nur zwei davon gibt. Außerdem erleichtert das getrennte Vorzeichen die Berechung bei der Fließkommaarithmetik.
Hier nun eine kleine Auswahl der möglichen Rechenoperationen:

 /----------------------------+-------\ 
 |Rechenoperation             |Routine| 
 +--------------+-------------+-------+ 
 |Addition      |FAC :=ARG+FAC| $B86A | 
 |Subtraktion   |FAC :=ARG-FAC| $B853 | 
 |Multiplikation|FAC :=ARG*FAC| $BA2B | 
 |Division      |FAC :=ARG/FAC| $BB12 | 
 |Potenzierung  |FAC :=ARG↑FAC| $BF7B | 
 \--------------+-------------+-------/ 

Vor dem Aufruf der Routinen müssen FAC und ARG natürlich die gewünschten Zahlen enthalten.
Wie Sie sehen, enthält der FAC immer das Ergebnis der Berechnungn. Spontan fallen uns zwei Probleme auf: Wie bekomme ich die Zahlen in den FAC oder ARG und wie kann ich das Ergebnis abspeichern, damit es erhalten bleibt? Auch dafür stehen uns wieder einige ROM-Routinen zur Verfügung, die Sie gleich noch kennenlernen werden. Zunächst jedoch zurück zu dem zweiten Fließkomme-Format von demm die Rede war.
b) Es handelt sich um das Format, in dem die Fließkommazahlen im Speicher abgelegt werden, entweder als Ergebnis einer Berechung, oder als Operanden für die Rechenoperationen in FAC und ARG. Ein Format, das sich auf den Arbeitsspeicher bezieht, sollte möglichst kurz und speicherplatzsparend sein. Ein eigenes Byte für ein Vorzeichen ist jetzt völlig ausgeschlossen. Die ganze Fließkommazehl wird nun durch einen kleinen Trick auf 5 Bytes beschränkt.
Wir wissen, daß rechts neben dem Binärpunkt der normalisierten Mantisse eine 1 steht ( deshalb haben wir den Punkt ja dorthin gesetzt) . Wenn uns sowieso bekannt ist, daß es sich um eine 1 handelt, dann brauchen wir sie doch nicht mehr mit abzuspeichern. Diese 1 muß lediglich bei allen Berechnungen berücksichtigt werden. Diese Bits nennt man Hidden Bits ( versteckte Bits) . Da das äußerst links stehende Bit der Mantisse nun frei geworden ist, können wir dort unser Vorzeichen unterbringen.
Tatsächlich benötigen wir jetzt nur noch 5 Bytes für die Zahlendarstellung.
Format im Arbeitsspeicher:

              /--------\                
              |10000110|                
              \--------/                

Exponent

   /Vorzeichen-Bit                      
  /+-------+--------+--------+--------\ 
  |01001000|10000000|00000000|00000000| 
  \--------+--------+--------+--------/ 
       1        2        3        4     
             M A N T I S S E            

Hexadezimal erhält man:8648800000 ROM-Routinen zur Handhabung der Fließkommazahlen Innerhalb dises Kursteiles kann ich Ihnen leider nur eine kleine Auswahl dieser ROM-Routinen vorstellen.
$ B3 A2| Wandelt eine vorzeichenlose ganze | Zahl (0 . . .255), die im Y-Register | steht, in eine FLP-Zahl im FAC um.

     |                                  
$BBA2|Lädt FAC mit  einer  FLP-Zahl  aus
     |dem Arbeitsspeicher, auf  die  der
     |Zeiger Akku/Y-Register  weist  und
     |wandelt sie in  das  benötigte  6-
     |Byte-Format um.                   
     |                                  
$BA8C|Lädt ARG mit  einer  FLP-Zahl  aus
     |dem Arbeitsspeicher, auf  die  der
     |Zeiger Akku/Y-Register  weist  und
     |wandelt sie  in  das  benötigt  6-
     |Byte-Format um.                   
     |                                  
$BC0C|Kopiert den Inhalt des FAC in  den
     |ARG.                              
     |                                  
$BBFC|Kopiert den Inhalt des ARG in  den
     |FAC.                              
-----+----------------------------------
$B7F7|Wandelt den Inhalt des FAC in eine
     |vorzeichenlose  Integerzahl  (0...
     |65535) in den Speicherzellen  $14/
     |$15 und Y-Register/Akkumulator um.
     |                                  

$ BDDD| Wandelt den Inhalt von FAC in eine | ASCII-Zeichenkette und legt sie im | Puffer am $0100 ab.
|$ BBD4| Wandelt den FAC ( Rechenergebnis)| in eine 5- Byte-FLP- Zahl und legt | sie im Speicher under der Adresse | ab, die der Zeiger X-Register/ Y-| Register bildet.
Die USR-Funktion ( User callable machine language SubRoutine) Bisher waren wir es gewohnt, unsere ASSEMBLER-Programme von BASIC aus mit SYS-Befehlen aufzurufen. Die Parameterübergabe konnte nur durhc das POKEn der Werte an die jeweilige Adresse erfolgen.
Wenn der zu übergebende Wert jedoch eine FLP-Zahl ist, dann müßte die Zahl in BASIC zerlegt werden, um sie dann stückweise in den FAC zu POKEn. Das wäre doch sehr umständlich. Speziell für das Bearbeiten von Fließkommazahlen gibt es daher die USR-Funktion. Der Vorteil dieser Funktion ist, daß der Inhalt der angegebenen Variablen automatisch in den FAC übertragen wird. Aber woher weiß der Computer , wo unsere ASSEMBLER-Routine beginnt? Bei der Ausführung von USR wird der indirekte Sprung JMP ($0311) ausgeführt. Die Einsprungadresse des ASSEMBLER-Programms muß als Zeiger in den Adressen $0311( niederwertiges Byte) und $0312( höherwertiges Byte) vor dem Aufruf bereitgestellt werden.
Unter anderem enthält das Programm " ASSEMBLER-KURS 9" auch ein Beispiel für die Benutzung von USR.
Im nächsten ( und letzten) Kursteil geht es dann um den Umgang mit den Interrupts.

Also, bis zum nächsten Kursteil...      
                                 (rt/wk)

Valid HTML 4.0 Transitional Valid CSS!