home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / emulator / unix / z80pack / z80src / float.asm < prev    next >
Encoding:
Assembly Source File  |  1992-07-09  |  19.7 KB  |  832 lines

  1. ; *******************************
  2. ; * Fliesskomma-Arithmetik fuer    *
  3. ; * den Z80-Mikroprozessor    *
  4. ; * (mc 12/88, Seite 100    *
  5. ; *******************************
  6.  
  7. ; ********************************************************
  8. ; * Die folgende Testroutine liefert die Ausgabe:
  9. ; *    40400000
  10. ; *    00700000
  11. ; *    7F800000
  12. ; *    35BFFFFF
  13. ; *    00400000
  14. ; *    7F7FFFFF
  15. ; *    7F800000
  16. ; *    406DB6DB
  17. ; *    15400001
  18.  
  19. START:
  20.     LD      SP,STACK
  21.     LD    BC,3F80H    ; Aufruf der Additionsroutine
  22.     LD    DE,0000H    ; mit verschiedenen Parametern
  23.     PUSH    BC        ; entspricht 1 + 2
  24.     PUSH    DE
  25.     LD    BC,4000H
  26.     LD    DE,0000H
  27.     PUSH    BC
  28.     PUSH    DE
  29.     CALL    F_ADD
  30.     CALL    HEXOUT        ; anschliessend Ausgabe
  31.  
  32.     LD    BC,00F0H    ; eine kleine, gerade noch normalisierte
  33.     LD    DE,0000H    ; Zahl, dazu die kleinste normalisierte
  34.     PUSH    BC        ; Zahl mit negativem Vorzeichen addieren
  35.     PUSH    DE
  36.     LD    BC,8080H
  37.     LD    DE,0000H
  38.     PUSH    BC
  39.     PUSH    DE
  40.     CALL    F_ADD
  41.     CALL    HEXOUT
  42.  
  43.     LD    BC,7F00H    ; die Summe dieser beiden Zahlen
  44.     LD    DE,0000H    ; ergibt unendlich. Setzt man
  45.     PUSH    BC        ; fuer die zweite Zahl den Wert
  46.     PUSH    DE        ; 7EFFFFFE, so ist das Ergebnis
  47.     LD    BC,7EFFH    ; gerade MAXFLOAT
  48.     LD    DE,0FFFFH
  49.     PUSH    BC
  50.     PUSH    DE
  51.     CALL    F_ADD
  52.     CALL    HEXOUT
  53.  
  54.     LD    BC,0000H    ; Multiplikation testen
  55.     LD    DE,0003H    ; MAXFLOAT * <denormalisierte Zahl>
  56.     PUSH    BC
  57.     PUSH    DE
  58.     LD    BC,7F7FH
  59.     LD    DE,0FFFFH
  60.     PUSH    BC
  61.     PUSH    DE
  62.     CALL    F_MUL
  63.     CALL    HEXOUT
  64.  
  65.     LD    BC,0080H    ; die kleinste normalisierte Zahl
  66.     LD    DE,0000H    ; mit 0.5 multiplizieren
  67.     PUSH    BC        ; (ergibt eine denormalisierte Zahl)
  68.     PUSH    DE
  69.     LD    BC,3F00H
  70.     LD    DE,0000H
  71.     PUSH    BC
  72.     PUSH    DE
  73.     CALL    F_MUL
  74.     CALL    HEXOUT
  75.  
  76.     LD    BC,4000H    ; eine sehr grosse Zahl mit zwei
  77.     LD    DE,0000H    ; multiplizieren. Das Ergebnis
  78.     PUSH    BC        ; ist genau MAXFLOAT
  79.     PUSH    DE
  80.     LD    BC,7EFFH
  81.     LD    DE,0FFFFH
  82.     PUSH    BC
  83.     PUSH    DE
  84.     CALL    F_MUL
  85.     CALL    HEXOUT
  86.  
  87.     LD    BC,0000H    ; Test der Divisionsroutine
  88.     LD    DE,0000H    ; hier 1 / 0 (ergibt unendlich)
  89.     PUSH    BC
  90.     PUSH    DE
  91.     LD    BC,3F80H
  92.     LD    DE,0000H
  93.     PUSH    BC
  94.     PUSH    DE
  95.     CALL    F_DIV
  96.     CALL    HEXOUT
  97.  
  98.     LD    BC,40E0H    ; jetzt 26 / 7 berechnen
  99.     LD    DE,0000H
  100.     PUSH    BC
  101.     PUSH    DE
  102.     LD    BC,41D0H
  103.     LD    DE,0000H
  104.     PUSH    BC
  105.     PUSH    DE
  106.     CALL    F_DIV
  107.     CALL    HEXOUT
  108.  
  109.     LD    BC,1FFFH    ; jetzt eine sehr kleine
  110.     LD    DE,0FFFFH    ; denormalisierte Zahl durch
  111.     PUSH    BC        ; eine kleine normalisierte
  112.     PUSH    DE        ; Zahl dividieren
  113.     LD    BC,0000H
  114.     LD    DE,0003H
  115.     PUSH    BC
  116.     PUSH    DE
  117.     CALL    F_DIV
  118.     CALL    HEXOUT
  119.  
  120.     HALT                    ; Ende des Tests
  121.  
  122.     DEFS    100
  123. STACK:
  124.  
  125. ; ************************************************
  126. ; * Zahl in BC-DE in 8 Hexadezimalziffern drucken.
  127. ; * Dazu werden nacheinander die Nibble-Paare in
  128. ; * B, C, D und E ausgedruckt.
  129. ; *
  130.  
  131. HEXOUT:
  132.     LD    A,B        ; Nacheinander die einzelnen
  133.     CALL    DIG2        ; Nibble-Paare in A laden
  134.     LD    A,C        ; und ausdrucken
  135.     CALL    DIG2
  136.     LD    A,D
  137.     CALL    DIG2
  138.     LD    A,E
  139.     CALL    DIG2
  140.     LD    A,10
  141.     CALL    OUTCHAR
  142.     LD    A,13
  143.     CALL    OUTCHAR
  144.     RET
  145.  
  146. DIG2:
  147.     PUSH    AF        ; Nibble-Paar ausdrucken
  148.     RRCA                    ; unterstes Nibble retten
  149.     RRCA                    ; oberes Nibble rechtsbuendig
  150.     RRCA                    ; positionieren
  151.     RRCA
  152.     AND     00001111B
  153.     ADD     A,90H           ; binaer in ASCII (hex)
  154.     DAA
  155.     ADC     A,40H
  156.     DAA
  157.     CALL    OUTCHAR        ; Zeichen ausgeben
  158.     POP    AF        ; jetzt unteres Nibble verarbeiten
  159.     AND    00001111B    ; Nibble maskieren
  160.     ADD     A,90H           ; binaer in ASCII (hex)
  161.     DAA
  162.     ADC     A,40H
  163.     DAA
  164.     CALL    OUTCHAR
  165.     RET
  166.  
  167. OUTCHAR:                        ; Zeichen auf Console ausgeben
  168.     OUT     (0),A
  169.     RET
  170.  
  171. ; **********************************
  172. ; * Globale Konstanten-Definitionen
  173. ; * fuer das Fliesskommapaket
  174. ; *
  175.  
  176. MAXEXPO    EQU    255        ; Maximal zulaessiger Exponent
  177. BIAS    EQU    127        ; Bias des Exponenten
  178.  
  179. ; *************************************************
  180. ; * Fliesskomma-Addition in Single-Precision
  181. ; * Parameter: Operand 1 und Operand 2 ueber Stack
  182. ; * Ergebnis:  in BC-DE: MSB in B, LSB in E
  183. ; *
  184.  
  185. ; * Es folgen Offset-Definitionen fuer Stack-relativen Zugriff
  186.  
  187. FHL_ALT    EQU    0        ; Top of Stack liegt HL
  188. FADR    EQU    2        ; dann die Ruecksprungadresse
  189. OP1    EQU    4        ; jetzt Offset-Definitionen fuer
  190. OP2    EQU    8        ; Parameter-Uebergabe
  191.  
  192. OPSIZE    EQU    4        ; Groesse eines Operanden
  193.  
  194. F_ADD:
  195.     PUSH    HL        ; alten Basepointer retten
  196.     LD    (F_STACK),SP    ; aktuellen Stackpointer abspeichern
  197.     LD    HL,(F_STACK)    ; und in HL laden (= Basepointer)
  198.     PUSH    AF        ; benoetigte Register retten
  199.     PUSH    IX
  200.     PUSH    IY
  201.     LD    BC,OP1        ; jeztz die Zeiger auf die
  202.     ADD    HL,BC        ; Operanden initialisieren
  203.     PUSH    HL
  204.     POP    IX        ; IX zeigt auf Operand 1
  205.     LD    BC,OPSIZE
  206.     ADD    HL,BC
  207.     PUSH    HL
  208.     POP    IY        ; IY zeigt auf Operand 2
  209. F_ADSUB:
  210.     ADD    HL,BC        ; HL zeigt jetzt hinter die Operanden!
  211.     LD    (F_STACK),HL    ; diese Adresse fuer's Ende merken
  212.     LD    A,(IX+3)    ; Vorzeichen von Operand 1 laden
  213.     LD    E,A        ; Ergebnisvorzeichen in E, Bit 7
  214.     XOR    (IY+3)        ; mit Vorzeichen von OP2 verknuepfen
  215.     LD    D,A        ; Subtraktionsflag in D, Bit 7
  216.     RES    7,(IX+3)    ; Vorzeichen in Mantisse 1 loeschen
  217.     RES     7,(IY+3)        ; Vorzeichen in Mantisse 2 loeschen
  218.  
  219. ; Die Operanden sind jetzt in der Form: 0EEE EEEE EFFF ... FFFF
  220.  
  221.     LD    A,(IX+0)    ; Differenz OP1 - OP2 bilden
  222.     SUB    (IY+0)
  223.     LD    A,(IX+1)
  224.     SBC    A,(IY+1)
  225.     LD    A,(IX+2)
  226.     SBC    A,(IY+2)
  227.     LD    A,(IX+3)
  228.     SBC    A,(IY+3)
  229.     JR    NC,FAD_1    ; Sprung falls OP1 groesser als OP2
  230.     PUSH    IX        ; ansonsten Operanden vertauschen
  231.     EX    (SP),IY        ; (eigentlich nur die Pointer), so
  232.     POP    IX        ; dass IY den Kleineren adressiert
  233.     LD    A,E        ; Ergebnisvorzeichen neu berechnen
  234.     XOR    D
  235.     LD    E,A
  236. FAD_1:
  237.     LD    A,(IX+2)
  238.     LD    C,(IX+3)    ; Exponent der groesseren Zahl laden
  239.     SLA    A
  240.     RL    C
  241.     JR    Z,AD_DN1
  242.     SET    7,(IX+2)    ; implizite Eins erzeugen
  243. AD_DN1:
  244.     LD    A,(IY+2)
  245.     LD    B,(IY+3)    ; Exponent der kleineren Zahl laden
  246.     SLA    A
  247.     RL    B
  248.     JR    Z,AD_DN2
  249.     SET     7,(IY+2)        ; implizite Eins erzeugen
  250. AD_DN2:
  251.     PUSH    BC        ; Jetzt die Register fuer den
  252.     PUSH    DE        ; Blocktransferbefehl retten
  253.     LD      BC,(OPSIZE*2)-1 ; beide Operanden verschieben
  254.     DEC    HL        ; HL zeigt auf letztes Byte
  255.     PUSH    HL        ; HL nach DE kopieren
  256.     POP    DE
  257.     DEC    HL        ; HL zeigt auf vorletztes Byte
  258.     LDDR            ; Verschiebung beider Mantissen
  259.     POP    DE        ; um 8 Bit nach links
  260.     POP    BC
  261.     XOR    A
  262.     LD    (IX+0),A    ; Form: FFFF ... FFFF 0000 0000
  263.     LD    (IY+0),A
  264.     LD    A,C        ; Differenz der Exponenten berechnen
  265.     SUB    B
  266.     LD    B,A        ; Differenz nach B fuer Loop-Befehl
  267.     JR    Z,AD_NAP    ; falls Null, dann keine Anpassung
  268.     CP    25        ; mehr als 24? (Abfrage mit Carry
  269.     JP    NC,AD_RND    ; erfordert Vergleich mit 25)
  270. AD_ANP:
  271.     SRL    (IY+3)        ; Anpassung der zweiten Mantisse
  272.     RR    (IY+2)        ; durch Verschiebung nach rechts
  273.     RR    (IY+1)
  274.     RR    (IY+0)
  275.     DJNZ    AD_ANP        ; Loop-Befehl bis B = 0
  276. AD_NAP:
  277.     BIT    7,D        ; Subtraktion oder Addition?
  278.     JR    NZ,SUBTR    ; ggf. zur Subtraktion springen
  279.     LD    A,(IX+0)    ; jetzt werden die beiden Mantissen
  280.     ADD    A,(IY+0)    ; zueinander addiert
  281.     LD    (IX+0),A
  282.     LD    A,(IX+1)
  283.     ADC    A,(IY+1)
  284.     LD    (IX+1),A
  285.     LD    A,(IX+2)
  286.     ADC    A,(IY+2)
  287.     LD    (IX+2),A
  288.     LD    A,(IX+3)
  289.     ADC    A,(IY+3)
  290.     LD    (IX+3),A
  291.     JR    NC,AD_RND    ; kein Ueberlauf --> zum Runden
  292.     RR    (IX+3)        ; Ueberlauf einschieben
  293.     RR    (IX+2)        ; und Exponent erhoehen
  294.     RR    (IX+1)        ; durch die Vorgeschichte ist
  295.     RR    (IX+0)        ; gesichert, dass B Null ist; BC
  296.     INC    BC        ; enthaelt den 16-Bit-Exponent
  297.     JR    AD_RND        ; und zum Runden
  298. SUBTR:
  299.     LD    A,(IX+0)    ; Die beiden Mantissen werden
  300.     SUB    (IY+0)        ; voneinander subtrahiert
  301.     LD    (IX+0),A
  302.     LD    A,(IX+1)
  303.     SBC    A,(IY+1)
  304.     LD    (IX+1),A
  305.     LD    A,(IX+2)
  306.     SBC    A,(IY+2)
  307.     LD    (IX+2),A
  308.     LD    A,(IX+3)
  309.     SBC    A,(IY+3)
  310.     LD    (IX+3),A
  311.     JP    M,AD_RND    ; bei fuehrender Eins zum Runden
  312.     JR    NZ,AD_NRM    ; ungleich Null: Normalisieren
  313.     CP    (IX+2)        ; Rest der Mantisse auch Null?
  314.     JR    NZ,AD_NRM
  315.     CP    (IX+1)
  316.     JR    NZ,AD_NRM
  317.     CP    (IX+0)
  318.     JR    Z,AD_ZERO    ; alles Null --> Ergebnis ist Null
  319. AD_NRM:
  320.     XOR    A        ; A = 0
  321. AD_NR1:
  322.     CP    C        ; Exponent ist Null?
  323.     JR    NZ,AD_NR2    ; nein, Normierung moeglich
  324.     CP    B        ; oberes Byte auch Null?
  325.     JR    Z,AD_RND    ; dann ist Ergebnis denormalisiert
  326. AD_NR2:
  327.     DEC    BC        ; Exponent erniedrigen
  328.     SLA    (IX+0)        ; Mantisse normalisieren bis
  329.     RL    (IX+1)        ; fuehrende Eins auftaucht
  330.     RL    (IX+2)
  331.     RL    (IX+3)
  332.     JP    P,AD_NR1    ; weiter bis fuehrende Eins auftaucht
  333. AD_RND:
  334.     LD    A,(IX+0)    ; jetzt Runden auf Bit hinter
  335.     ADD    A,80H        ; Mantisse
  336.     JR    NC,AD_NOV    ; kein Uebertrag?
  337.     INC    (IX+1)        ; doch, naechstes Mantissenbyte
  338.     JR    NZ,AD_NOV    ; behandeln, jetzt auf Null pruefen,
  339.     INC    (IX+2)        ; da der INC-Befehl kein Carry liefert
  340.     JR    NZ,AD_NOV
  341.     INC    (IX+3)
  342.     JR    NZ,AD_NOV
  343.     SCF            ; Eins erzeugen
  344.     RR    (IX+3)        ; bei Ueberlauf Mantisse durch
  345.     RR    (IX+2)        ; Rechtsschieben wieder normalisieren
  346.     RR    (IX+1)        ; (nur noch 24 Bit noetig)
  347.     INC    BC        ; und Exponent korrigieren
  348. AD_NOV:
  349.     XOR    A        ; A = 0
  350.     CP    (IX+3)        ; Mantisse auf Null pruefen
  351.     JR    NZ,AD_NOZ
  352.     CP    (IX+2)
  353.     JR    NZ,AD_NOZ
  354.     CP    (IX+1)        ; alle Mantissenbytes Null?
  355.     JR    NZ,AD_NOZ    ; dann ist auch das Ergebnis Null
  356. AD_ZERO:            ; Null Ergebnis aufbauen
  357.     LD    B,A
  358.     LD    C,A
  359.     LD    D,A
  360.     LD    E,A
  361.     JR    AD_EXIT        ; dann Routine verlassen
  362. AD_NOZ:
  363.     CP    B        ; A ist 0
  364.     LD    A,MAXEXPO    ; Exponent oberstes Byte ungleich Null?
  365.     JR    NZ,AD_OVR    ; dann ist Ueberlauf eingetreten
  366.     CP    C        ; oder genau maxexpo erreicht?
  367.     JR    NZ,AD_NUE    ; nein, --> kein Ueberlauf
  368. AD_OVR:
  369.     LD    C,A        ; Exponent auf maxexpo setzen
  370.     XOR    A        ; und Mantisse auf Null
  371.     LD    (IX+3),A    ; fuer unendlich
  372.     LD    (IX+2),A
  373.     LD    (IX+1),A
  374.     JR    AD_DEN
  375. AD_NUE:
  376.     XOR    A        ; A = 0
  377.     CP    C        ; Exponent Null (Zahl denormalisiert)?
  378.     JR    Z,AD_DEN    ; ja, -->
  379.     SLA    (IX+1)        ; fuehrendes Bit wird nicht gespeichert
  380.     RL    (IX+2)        ; daher Mantisse um 1 Bit nach links
  381.     RL    (IX+3)
  382. AD_DEN:
  383.     LD    B,C        ; Ergebnis aufbauen: Exponent in B
  384.     LD    C,(IX+3)    ; Mantisse oberstes Byte
  385.     LD    D,(IX+2)
  386.     SLA    E        ; Vorzeichen aus E in Carry schieben
  387.     LD    E,(IX+1)
  388.     RR    B        ; Vorzeichen in Ergebnis einschieben
  389.     RR    C
  390.     RR    D
  391.     RR    E
  392. AD_EXIT:
  393.     POP    IY        ; Register restaurieren
  394.     POP    IX
  395.     POP    AF
  396.     POP    HL
  397.     LD    (F_HL),HL    ; HL zwischenspeichern
  398.     EX    (SP),HL        ; alte Ruecksprungadresse in HL
  399.     LD      SP,(F_STACK)    ; Stack zuruecksetzen
  400.     PUSH    HL        ; Ruecksprungadresse ablegen
  401.     LD    HL,(F_HL)    ; HL wieder laden
  402.     RET            ; Ende des Unterprogramms
  403.  
  404. ; *************************************************
  405. ; * Fliesskomma-Subtraktion in Single-Precision
  406. ; * Parameter: Operand 1 und Operand 2 ueber Stack
  407. ; * Ergebnis: in BC-DE: MSB in B, LSB in E
  408. ; *
  409.  
  410. F_SUB:
  411.     PUSH    HL        ; alten Basepointer retten
  412.     LD    (F_STACK),SP    ; aktuellen Stackpointer abspeichern
  413.     LD    HL,(F_STACK)    ; und in HL laden (= Basepointer)
  414.     PUSH    AF        ; benoetigte Register retten
  415.     PUSH    IX
  416.     PUSH    IY
  417.     LD    BC,OP1
  418.     ADD    HL,BC
  419.     PUSH    HL
  420.     POP    IX        ; IX zeigt auf Operand 1
  421.     LD    BC,OPSIZE
  422.     ADD    HL,BC
  423.     PUSH    HL
  424.     POP    IY        ; IY zeigt auf Operand 2
  425.     LD    A,80H
  426.     XOR    (IY+3)        ; Vorzeichenbit von Operand 2 umdrehen
  427.     LD    (IY+3),A    ; wieder abspeichern
  428.     JP    F_ADSUB        ; jetzt weiter bei Additionsroutine
  429.  
  430. ; *************************************************
  431. ; * Fliesskomma-Multiplikation in Single-Precision
  432. ; * Parameter: Operand 1 und Operand 2 ueber Stack
  433. ; * Ergebnis: in BC-DE: MSB in B, LSB in E
  434. ; *
  435.  
  436. TEMP    EQU    -10        ; Offset lokale Variable (6 Byte)
  437.  
  438. F_MUL:
  439.     PUSH    HL        ; alten Basepointer retten
  440.     LD    (F_STACK),SP    ; aktuellen Stackpointer abspeichern
  441.     LD    HL,(F_STACK)    ; und in HL laden (= Basepointer)
  442.     PUSH    AF        ; benoetigte Register retten
  443.     PUSH    IX
  444.     PUSH    IY
  445.     LD    BC,OP1
  446.     ADD    HL,BC
  447.     PUSH    HL
  448.     EX    (SP),IX        ; IX zeigt auf Operand 1
  449.                 ; 2 Dummy-Byte auf Stack fuer lokale
  450.     LD    BC,OPSIZE    ; Variable bleiben stehen
  451.     ADD    HL,BC
  452.     PUSH    HL
  453.     EX    (SP),IY        ; IY zeigt auf Operand 2
  454.     PUSH    HL        ; insgesamt 6 Byte fuer lokale Variable
  455.     ADD    HL,BC        ; HL zeigt jetzt hinter die Operanden!
  456.     LD    (F_STACK),HL
  457.     LD    A,(IX+3)    ; Ergebnisvorzeichen bestimmen
  458.     XOR    (IY+3)
  459.     LD    C,A        ; Vorzeichen in C Bit 7 merken
  460.     LD    D,0        ; Exponent 1 laden
  461.     LD    E,(IX+3)
  462.     LD    A,(IX+2)    ; Operand um 8 Bit nach links schieben
  463.     LD    (IX+3),A
  464.     RES    7,(IX+3)    ; implizite Null vorbesetzen
  465.     SLA    A        ; Exponent unterstes Bit in Carry
  466.     RL    E        ; und in E einschieben
  467.     JR    Z,MU_DN1    ; falls Null, dann OP1 denormalisieren
  468.     SET    7,(IX+3)    ; implizite Eins erzeugen
  469.     DEC    DE        ; Bias kompensieren
  470. MU_DN1:
  471.     LD    A,(IX+1)    ; jetzt restliche Bytes verschieben
  472.     LD    (IX+2),A
  473.     LD    A,(IX+0)
  474.     LD    (IX+1),A
  475.     XOR    A        ; unterste Mantissenbits loeschen
  476.     LD    (IX+0),A    ; Form: FFFF ... FFFF 0000 0000
  477.     LD    (IX+TEMP+5),A    ; lokale Variable mit Null vorbesetzen
  478.     LD    (IX+TEMP+4),A
  479.     LD    (IX+TEMP+3),A
  480.     LD    (IX+TEMP+2),A
  481.     LD    (IX+TEMP+1),A
  482.     LD    (IX+TEMP+0),A
  483.     LD    H,A        ; Exponent 2 in HL aufbauen
  484.     LD    L,(IY+3)
  485.     LD    A,(IY+2)
  486.     RES    7,(IY+2)    ; implizite Null vorbesetzen
  487.     SLA    A
  488.     RL    L
  489.     JR    Z,MU_DN2    ; gleich Null, dann Op2 denormalisieren
  490.     SET    7,(IY+2)    ; implizite Eins erzeugen
  491.     DEC    HL        ; Bias kompensieren
  492. MU_DN2:
  493.     ADD    HL,DE        ; Exponenten aufaddieren
  494.     LD    DE,3-BIAS    ; Bias-3 subtrahieren
  495.     ADD    HL,DE        ; bzw. 3-Bias addieren
  496.     JP    P,MU_NOZ
  497.     LD    A,L        ; Exponent kleiner als -24?
  498.     CP    -24
  499.     JR    NC,MU_NOZ
  500.     JP    MU_ZERO        ; ja, dann ist das Ergebnis Null
  501. MU_NOZ:
  502.     LD    B,24        ; Multiplikationsschleifenzaehler
  503.     LD    DE,0        ; Hilfsregister fuer Multiplikand
  504. MU_MUL:
  505.     SRL    (IX+3)        ; Multiplikand nach rechts schieben
  506.     RR    (IX+2)
  507.     RR    (IX+1)
  508.     RR    (IX+0)
  509.     RR    D        ; DE als Verlaengerung von Operand 1
  510.     RR    E
  511.     SLA    (IY+0)        ; Multiplikator nach links schieben
  512.     RL    (IY+1)
  513.     RL    (IY+2)        ; falls fuehrendes Bit Null ist, dann
  514.     JR    NC,MU_NAD    ; muss nicht addiert werden
  515.     LD    A,(IX+TEMP+0)    ; sonst Multiplikand aufaddieren
  516.     ADD    A,E
  517.     LD    (IX+TEMP+0),A
  518.     LD    A,(IX+TEMP+1)
  519.     ADC    A,D
  520.     LD    (IX+TEMP+1),A
  521.     LD    A,(IX+TEMP+2)
  522.     ADC    A,(IX+0)
  523.     LD    (IX+TEMP+2),A
  524.     LD    A,(IX+TEMP+3)
  525.     ADC    A,(IX+1)
  526.     LD    (IX+TEMP+3),A
  527.     LD    A,(IX+TEMP+4)
  528.     ADC    A,(IX+2)
  529.     LD    (IX+TEMP+4),A
  530.     LD    A,(IX+TEMP+5)
  531.     ADC    A,(IX+3)
  532.     LD    (IX+TEMP+5),A
  533. MU_NAD:
  534.     DJNZ    MU_MUL        ; Schleife durchlaufen
  535.     LD    A,(IX+TEMP+5)
  536.     OR    A        ; Flags setzen
  537.     JP    M,MU_RND    ; bei fuerender Eins zum Runden
  538.     JR    NZ,MU_NOR    ; ungleich Null --> normalisieren
  539.     CP    (IX+TEMP+4)
  540.     JR    NZ,MU_NOR
  541.     CP    (IX+TEMP+3)
  542.     JR    NZ,MU_NOR
  543.     CP    (IX+TEMP+2)
  544.     JR    NZ,MU_NOR
  545.     JP    MU_ZERO        ; Mantisse komplett Null --> Null
  546. MU_NOR:
  547.     XOR    A        ; A = 0
  548.     OR    H        ; Exponent ist negativ?
  549.     JP    M,MU_UNT    ; ggf. Unterlauf behandeln
  550. MU_NR1:
  551.     XOR    A        ; A = 0
  552.     CP    L        ; Exponent = Null?
  553.     JR    NZ,MU_NR2
  554.     CP    H        ; bei Null zum Runden
  555.     JR    Z,MU_RND
  556. MU_NR2:
  557.     DEC    HL        ; Exponent erniedrigen
  558.     SLA    (IX+TEMP+0)
  559.     RL    (IX+TEMP+1)
  560.     RL    (IX+TEMP+2)    ; Mantisse solange nach links
  561.     RL    (IX+TEMP+3)    ; verschieben bis fuerende Eins
  562.     RL    (IX+TEMP+4)    ; auftaucht
  563.     RL    (IX+TEMP+5)
  564.     JP    P,MU_NR1
  565. MU_RND:
  566.     LD    A,(IX+TEMP+2)    ; jetzt Runden auf Bit hinter
  567.     ADD    A,80H        ; Mantisse
  568.     JR    NC,MU_NOV    ; kein Uebertrag?
  569.     INC    (IX+TEMP+3)    ; doch, naechstes Mantissenbyte
  570.     JR    NZ,MU_NOV    ; behandeln, jetzt auf Null pruefen
  571.     INC    (IX+TEMP+4)    ; da der INC-Befehl kein Carry liefert
  572.     JR    NZ,MU_NOV
  573.     INC    (IX+TEMP+5)
  574.     JR    NZ,MU_NOV
  575.     SCF            ; Eins erzeugen
  576.     RR    (IX+TEMP+5)    ; bei Ueberlauf Mantisse durch
  577.     RR    (IX+TEMP+4)    ; Rechtsschieben wieder normalisieren
  578.     RR    (IX+TEMP+3)
  579.     INC    HL        ; und Eponent korrigieren
  580. MU_NOV:
  581.     XOR    A        ; A = 0
  582.     CP    H        ; Exponent pruefen
  583.     LD    A,MAXEXPO    ; A vorbesetzen
  584.     JR    NZ,MU_OVR    ; groesser Null: Ueberlauf behandeln
  585.     CP    L        ; oder genau maxexpo erreicht?
  586.     JR    NZ,MU_NUE    ; nein, kein Ueberlauf
  587. MU_OVR:
  588.     LD    L,MAXEXPO    ; Ueberlauf: Exponent = maxexpo
  589.     XOR    A        ;          Mantisse = Null
  590.     LD    (IX+TEMP+5),A
  591.     LD    (IX+TEMP+4),A
  592.     LD    (IX+TEMP+3),A
  593.     JR    MU_DEN
  594. MU_NUE:
  595.     XOR    A        ; A = 0
  596.     CP    L        ; Exponent ist Null?
  597.     JR    Z,MU_DEN    ; ja, Ergebnis ist denormalisiert
  598.     SLA    (IX+TEMP+3)    ; nein, fuehrendes Mantissenbit
  599.     RL    (IX+TEMP+4)    ; rausschieben
  600.     RL    (IX+TEMP+5)
  601. MU_DEN:
  602.     SLA    C        ; Vorzeichen in Carry schieben
  603.     LD    B,L        ; Exponent einsetzen
  604.     LD    C,(IX+TEMP+5)
  605.     LD    D,(IX+TEMP+4)
  606.     LD    E,(IX+TEMP+3)
  607.     RR    B        ; und Vorzeichen einschieben
  608.     RR    C
  609.     RR    D        ; Form: SEEE EEEE EFFF FFFF ... FFFF
  610.     RR    E
  611. MU_RES:
  612.     POP    HL        ; lokale Variable deallozieren
  613.     POP    HL
  614.     POP    HL
  615.     POP    IY        ; Register restaurieren
  616.     POP    IX
  617.     POP    AF
  618.     POP    HL
  619.     LD    (F_HL),HL    ; Parameter vom Stack deallozieren
  620.     EX    (SP),HL
  621.     LD    SP,(F_STACK)
  622.     PUSH    HL
  623.     LD    HL,(F_HL)
  624.     RET            ; und return
  625. MU_ZERO:
  626.     XOR    A        ; Ergebnis ist Null
  627.     LD    B,A
  628.     LD    C,A
  629.     LD    D,A
  630.     LD    E,A
  631.     JR    MU_RES
  632. MU_UNT:
  633.     LD    A,L        ; Exponent in A
  634.     NEG            ; negieren fuer Schleifenzaehler
  635.     CP    24        ; totaler Ueberlauf?
  636.     JR    NC,MU_ZERO    ; ja, dann ist Ergebnis Null
  637.     LD    B,A        ; in B fuer Loop
  638. MU_SHR:
  639.     SRL    (IX+TEMP+5)    ; Mantisse denormalisieren
  640.     RR    (IX+TEMP+4)    ; bis Exponent Null ist
  641.     RR    (IX+TEMP+3)
  642.     DJNZ    MU_SHR
  643.     LD    L,B        ; Exponent in Register L = B = 0
  644.     JP    MU_DEN        ; denormalisiertes Ergebnis erzeugen
  645.  
  646. ; *************************************************
  647. ; * Fliesskomma-Division in Single-Precision
  648. ; * Parameter: Operand 1 und Operand 2 ueber Stack
  649. ; * Ergebnis: in BC-DE: MSB in B, LSB in E
  650. ; *
  651.  
  652. F_DIV:
  653.     PUSH    HL        ; alten Basepointer retten
  654.     LD    (F_STACK),SP    ; aktuellen Stackpointer abspeichern
  655.     LD    HL,(F_STACK)    ; und in HL laden (= Basepointer)
  656.     PUSH    AF        ; benoetigte Register retten
  657.     PUSH    IX
  658.     PUSH    IY
  659.     LD    BC,OP1
  660.     ADD    HL,BC
  661.     PUSH    HL
  662.     EX    (SP),IX        ; IX zeigt auf Operand 1
  663.                 ; 2 Dummy-Byte auf Stack fuer lokale
  664.     LD    BC,OPSIZE    ; Variable bleiben stehen
  665.     ADD    HL,BC
  666.     PUSH    HL
  667.     EX    (SP),IY        ; IY zeigt auf Operand 2
  668.     PUSH    HL        ; insgesamt 6 Byte fuer lokale Variable
  669.     ADD    HL,BC        ; HL zeigt jetzt hinter die Operanden!
  670.     LD    (F_STACK),HL
  671.     LD    A,(IX+3)    ; Ergebnisvorzeichen bestimmen
  672.     XOR    (IY+3)
  673.     LD    C,A        ; Vorzeichen in C Bit 7 merken
  674.     LD    H,0        ; Exponent 1 laden
  675.     LD    L,(IX+3)
  676.     LD    A,(IX+2)
  677.     RES    7,(IX+2)    ; implizite Null vorbesetzen
  678.     SLA    A        ; Exponent unterstes Bit in Carry
  679.     RL    L        ; und in E einschieben
  680.     JR    Z,DV_DN1    ; falls Null, dann Op1 denormalisieren
  681.     SET    7,(IX+2)    ; implizite Eins erzeugen
  682.     DEC    HL        ; Bias kompensieren
  683. DV_DN1:
  684.     LD    D,0        ; Exponent 2 in DE aufbauen
  685.     LD    E,(IY+3)
  686.     LD    A,(IY+2)
  687.     LD    (IY+3),A    ; Mantisse um 8 Bit verschieben
  688.     RES    7,(IY+3)    ; implizite Null vorbesetzen
  689.     SLA    A
  690.     RL    E
  691.     JR    Z,DV_DN2    ; gleich Null, dann Op2 denormalisieren
  692.     SET    7,(IY+3)    ; implizite Eins erzeugen
  693.     DEC    DE        ; Bias kompensieren
  694. DV_DN2:
  695.     LD    A,(IY+1)    ; jetzt restliche Bytes verschieben
  696.     LD    (IY+2),A
  697.     LD    A,(IY+0)
  698.     LD    (IY+1),A
  699.     XOR    A        ; A = 0
  700.     LD    (IY+0),A    ; Form: FFFF ... FFFF 0000 0000
  701.     SRL    (IY+3)
  702.     RR    (IY+2)
  703.     RR    (IY+1)
  704.     RR    (IY+0)        ; Form: 0FFF ... FFFF F000 0000
  705.     JR    NZ,DV_NZ1    ; Mantisse 2 auf Null pruefen
  706.     CP    (IY+1)
  707.     JR    NZ,DV_NZ1
  708.     CP    (IY+2)
  709.     JR    NZ,DV_NZ1
  710.     CP    (IY+3)
  711.     JR    NZ,DV_NZ1
  712.     JP    MU_OVR        ; Bei Division durch Null: unendlich
  713. DV_NZ1:
  714.     XOR    A        ; Carry-Flag loeschen
  715.     SBC    HL,DE        ; Exponenten subtrahieren
  716.     LD    DE,BIAS        ; Bias addieren
  717.     ADD    HL,DE
  718.     BIT    7,H        ; Exponent positiv?
  719.     JR    Z,DV_NOZ
  720.     LD    A,L        ; Exponent kleiner als -24?
  721.     JR    NC,DV_NOZ
  722.     JP    MU_ZERO        ; ja, dann ist das Ergebnis Null
  723. DV_NOZ:
  724.     PUSH    BC        ; Vorzeichen retten
  725.     LD    DE,25        ; Exponent um 25 erhoehen
  726.     ADD    HL,DE        ; jetzt ist er sicher groesser als Null
  727.     XOR    A        ; A = 0
  728.     LD    B,(IX+2)    ; Divident in Register kopieren
  729.     LD    C,(IX+1)
  730.     LD    D,(IX+0)
  731.     LD    E,A        ; die untersten Bits sind Null
  732.     CP    D        ; ist Dividend Null?
  733.     JR    NZ,DV_NZ2
  734.     CP    C
  735.     JR    NZ,DV_NZ2
  736.     CP    B
  737.     JR    NZ,DV_NZ2
  738.     POP    BC        ; Stack bereinigen (Vorzeichen laden)
  739.     JP    MU_ZERO        ; und Null als Ergebnis ausgeben
  740. DV_NZ2:
  741.     LD    (IX+TEMP+5),A    ; Ergebnis vorbesetzen
  742.     LD    (IX+TEMP+4),A
  743.     LD    (IX+TEMP+3),A
  744.     LD    (IX+TEMP+2),A
  745. DV_NLP:
  746.     BIT    6,(IY+3)    ; ist der Divisor normalisiert
  747.     JR    NZ,DV_NOR    ; ja, -->
  748.     INC    HL        ; nein, Exponent erhoehen
  749.     SLA    (IY+0)        ; Divisor verschieben bis in
  750.     RL    (IY+1)        ; Form 01FF ...
  751.     RL    (IY+2)
  752.     RL    (IY+3)
  753.     JR    DV_NLP
  754. DV_NOR:
  755.     SRL    B
  756.     RR    C
  757.     RR    D
  758.     RR    E        ; Form: 0FFF ... FFFF F000 0000
  759. DV_LOP:
  760.     LD    (IX+3),B    ; Dividend zwischenspeichern
  761.     LD    (IX+2),C    ; die Speicherplaetze von Op1
  762.     LD    (IX+1),D    ; stehen zur Verfuegung, da wir OP1
  763.     LD    (IX+0),E    ; in die Register BC-DE kopiert haben
  764.     LD    A,E        ; jetzt Divisor abziehen
  765.     SUB    (IY+0)
  766.     LD    E,A
  767.     LD    A,D
  768.     SBC    A,(IY+1)
  769.     LD    D,A
  770.     LD    A,C
  771.     SBC    A,(IY+2)
  772.     LD    C,A
  773.     LD    A,B
  774.     SBC    A,(IY+3)
  775.     LD    B,A
  776.     JR    NC,DV_ONE    ; kein Carry: Divisor passt
  777.     LD    E,(IX+0)    ; zurueckkopieren
  778.     LD    D,(IX+1)    ; Carry bleibt dabei erhalten
  779.     LD    C,(IX+2)
  780.     LD    B,(IX+3)
  781. DV_ONE:
  782.     CCF            ; Carry-Flag umkehren
  783.     RL    (IX+TEMP+2)    ; Ergebnis aufbauen
  784.     RL    (IX+TEMP+3)
  785.     RL    (IX+TEMP+4)
  786.     RL    (IX+TEMP+5)
  787.     SLA    E        ; Dividend verschieben
  788.     RL    D
  789.     RL    C
  790.     RL    B
  791.     DEC    HL        ; Exponent erniedrigen
  792.     XOR    A        ; A = 0
  793.     CP    L        ; Exponent = Null ?
  794.     JR    NZ,DV_DIV
  795.     CP    H
  796.     JR    Z,DV_DEN    ; falls Null, dann denormalisiert
  797. DV_DIV:
  798.     BIT    0,(IX+TEMP+5)    ; fuerende Eins in Ergebnis-Mantisse?
  799.     JR    Z,DV_LOP    ; nein, weiter rechnen
  800. DV_DEN:
  801.     LD    B,(IX+TEMP+5)    ; hoechstes Bit merken
  802.     LD    A,(IX+TEMP+4)
  803.     LD    (IX+TEMP+5),A    ; Mantisse in Form
  804.     LD    A,(IX+TEMP+3)    ; FFFF ... FFFF 0000 0000
  805.     LD    (IX+TEMP+4),A
  806.     LD    A,(IX+TEMP+2)
  807.     LD    (IX+TEMP+3),A
  808.     RR    B        ; hoechstes Bit einschieben
  809.     RR    (IX+TEMP+5)
  810.     RR    (IX+TEMP+4)
  811.     RR    (IX+TEMP+3)    ; Form: FFFF ... FFFF F000 0000
  812.     RR    (IX+TEMP+2)
  813.     POP    BC        ; Vorzeichen wieder laden
  814.     XOR    A        ; A = 0
  815.     CP    (IX+TEMP+5)    ; Mantisse ist Null?
  816.     JR    NZ,DV_NZ3
  817.     CP    (IX+TEMP+4)
  818.     JR    NZ,DV_NZ3
  819.     CP    (IX+TEMP+3)
  820.     JR    NZ,DV_NZ3
  821.     CP    (IX+TEMP+2)
  822.     JP    Z,MU_ZERO    ; dann ist Ergebnis auch Null
  823. DV_NZ3:
  824.     JP    MU_RND        ; sonst weiter wie bei Multiplikation
  825.  
  826. F_STACK:    
  827.     DEFS    2               ; Hilfsspeicher fuer Stackpointer
  828. F_HL:
  829.     DEFS    2               ; Hilfsspeicher fuer Basepointer HL
  830.  
  831.     END
  832.