Magic Disk 64

home to index to html: MD9009-KURSE-ASSEMBLER-KURS_1_TEIL_9.html
         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-  (nieder-
wertiges Byte)  und  Y-Register  (höher-
wertiges Byte).                         
Dummerweise existiert  keine  entsprech-
ende  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.5E3  ent-
spricht (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.5E-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
Links-   bzw.   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  Vorkomma-
   stellen  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  be-
   stimmtes 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är-
   punkt um 6 Stellen  nach  links  ver-
   schoben werden, was durch eine Multi-
   plikation   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  bi-
   nä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  Exponen-
   ten, die bei der  Normalisierung  der
   Mantisse   entstehen  können,  darzu-
   stellen.   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  abge-
   speichert werden soll.               
5. Floatingpoint-Zahlen des C64         
   Dieser Computer kennt zwei  verschie-
   dene   Fließkommaformate,   die  sich
   hauptsächlich durch die Art der Spei-
   cherung des  Vorzeichens  unterschei-
   den. Die eine wird nur innerhalb  der
   beiden Fließkommakkumulatoren verwen-
   det, 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 $6E. Welche Auf-
   gabe   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 C8 80 00 00 00                      
Sicher halten Sie  die  benutzung  eines
ganzen Bytes für nur  ein  Vorzeichenbit
für  Verschwendung.  In  den  Flißkomma-
akkumulatoren    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  Ver-
fü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  abge-
legt 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är-
punkt 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: 86 48 80 00 00  
ROM-Routinen zur Handhabung  der  Fließ-
kommazahlen                             
Innerhalb  dises  Kursteiles  kann   ich
Ihnen leider  nur  eine  kleine  Auswahl
dieser ROM-Routinen vorstellen.         
$B3A2|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ück-
weise 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)  ausge-
fü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.                             
Mich interessiert sehr Ihre Meinung, wie
Ihnen  der  Kurs  gefallen  hat.  Welche
Themen  wurden  zu  kurz  behandelt,  wo
sehen Sie noch Probleme, was fanden  Sie
besonders gut?                          
Schreiben  Sie  mir  doch   bitte   Ihre
positive oder negative Kritik:          
Ralf Trabhardt                          
Philippsbergstraße 45                   
6200 Wiesbaden                          
Also, bis zum nächsten Kursteil...      
Valid HTML 4.0 Transitional Valid CSS!