; FLOAT.INC
;******************************************************************************
;* Gleitkommabibliothek fuer TLCS 90                                          *
;*                                                                            *
;* Originale fuer den Z80 aus mc 12/88,1/89                                   *
;* Portierung auf TLCS 90 von Alfred Arnold, Dezember 1993                    *
;*                                                                            *
;*  Routine  Funktion             Eingabe Ausgabe  Stack    Laenge  Zeit/10MHz *
;*                                                                            *
;*  fadd     Addition             2*Stack  BC-DE  14 Byte 347 Byte   248 us   *
;*  fsub     Subtraktion          2*Stack  BC-DE  14 Byte  12 Byte   255 us   *
;*  fmul     Multiplikation       2*Stack  BC-DE  20 Byte 356 Byte   936 us   *
;*  fdiv     Division             2*Stack  BC-DE  22 Byte 303 Byte  1081 us   *
;*  fmul2    Mult. mit 2er-Potenz Stack,A  BC-DE  10 Byte 162 Byte    28 us   *
;*  fsqrt    Quadratwurzel        Stack    BC-DE  22 Byte 621 Byte  1900 us   *
;*  fitof    Int-->Float          Stack    BC-DE  10 Byte  84 Byte  160 us *) *
;*  fftoi    Float-->Int          Stack    BC-DE  10 Byte 104 Byte  170 us *) *
;*  fftoa    Float-->ASCII        3*Stack  -----  40 Byte 451 Byte     *)     *
;*  fatof    ASCII-->Float        Stack  C,BC-DE  42 Byte 396 Byte     *)     *
;*                                                                            *
;*  *) Die Ausfuehrungszeiten streuen je nach Operand sehr stark und koennen  *
;*     bei den ASCII-Funktionen bei vielen Millisekunden liegen.              *
;*                                                                            *
;*  - Parametereingabe ueber den Stack bedeutet, dass die Parameter mittels   *
;*    PUSH vor dem Aufruf auf den Stack gelegt werden muessen.  Diese Werte   *
;*    werden von den Unterroutinen am Ende automatisch vom Stack entfernt.    *
;*    Der zur bergabe benoetigte Platz ist bei den Angaben zur Stackbelastung *
;*    eingerechnet!                                                           *
;*  - Wollen Sie einzelne Routinen entfernen, so beachten Sie, dass fsub Teile *
;*    aus fadd, fdiv Teile aus fmul sowie fftoi Teile aus fitof verwendet !   *
;*  - Gleitkommaformat ist IEEE Single (32 Bit)                               *
;*  - Integerwerte bei fmul2, fitof und fftoi sind vorzeichenbehaftet         *
;*  - Da die Routinen lokale Labels verwenden, ist mindestens AS 1.39 erfor-  *
;*    derlich                                                                 *
;*  - MACROS.INC muss vorher eingebunden werden                               *
;******************************************************************************

                section float

;------------------------------------------------------------------------------
; modulglobale Konstanten

MaxExpo         equ     255
Bias            equ     127

OpSize          equ     4               ; Groesse eines Operanden

fIX_alt         equ     0               ; Top of Stack liegt IX
FAdr            equ     2               ; Ruecksprungadresse
Op2             equ     4               ; Adresse Operand 2
Op1             equ     Op2+OpSize      ; Adresse Operand 1

Ld10:           dd      ld(10)
One:            dd      1.0
Ten:            dd      10.0
Tenth:          dd      3dcccccdh       ; =0.1, aber die Rundung auf manchen
					; Systemen variiert (damit Test nicht
					; scheitert)
Half:           dd      0.5

cpsh            macro   reg,op,{NoExpand}
                ld      reg,(op+2)
                push    reg
                ld      reg,(op)
                push    reg
                endm

;------------------------------------------------------------------------------
; Addition

                proc    fadd
                link    ix,0            ; Eintritt

                push    af              ; Register retten
                push    hl

                public  AddSub:Parent   ; Einsprung fuer fsub

AddSub:         ld      a,(ix+Op1+3)    ; Vorzeichen Operand 1 laden
                ld      e,a             ; Ergebnisvorzeichen in E, Bit 7
                xor     a,(ix+Op2+3)    ; mit Vorzeichen von Op2 verknuepfen
                ld      d,a             ; Subtraktionsflag in D, Bit 7
                res     7,(ix+Op1+3)    ; Vorzeichen in Mantisse 1 loeschen
                res     7,(ix+Op2+3)    ; Vorzeichen in Mantisse 2 loeschen

; Die Operanden sind jetzt in der Form 0eee eeee efff ... ffff

                ld      hl,(ix+Op1)     ; Differenz Op1-Op2 bilden
                sub     hl,(ix+Op2)
                ld      hl,(ix+Op1+2)
                sbc     hl,(ix+Op2+2)
                jr      nc,Ad_1         ; Sprung falls Op1>Op2
                ld      bc,(ix+Op1)     ; ansonsten Operanden vertauschen
                ex      bc,(ix+Op2)
                ld      (ix+Op1),bc
                ld      bc,(ix+Op1+2)
                ex      bc,(ix+Op2+2)
                ld      (ix+Op1+2),bc
                ld      a,e             ; Ergebnisvorzeichen neu berechnen
                xor     a,d
                ld      e,a

Ad_1:           ld      a,(ix+Op1+2)    ; Exponent der groesseren Zahl laden
                ld      c,(ix+Op1+3)
                slaa
                rl      c
                jr      z,Den1
                set     7,(ix+Op1+2)    ; implizite Eins erzeugen
Den1:           ld      a,(ix+Op2+2)    ; dito Zahl 2
                ld      b,(ix+Op2+3)
                slaa
                rl      b
                jr      z,Den2
                set     7,(ix+Op2+2)

Den2:           push    bc              ; jetzt die Register fuer den
                push    de              ; Blocktransferbefehl retten
                ld      bc,2*OpSize-1   ; beide Operanden verschieben
                ld      hl,ix           ; HL zeigt auf letztes Byte
                add     hl,Op2+2*OpSize-1
                ld      de,hl           ; HL nach DE kopieren
                dec     hl              ; HL zeigt auf vorletztes Byte
                lddr                    ; Verschiebung beider Mantissen
                pop     de              ; um 8 Bit nach links
                pop     bc

                xor     a,a
                ld      (ix+Op1),a      ; Form: ffff ... ffff 0000 0000
                ld      (ix+Op2),a
                ld      a,c             ; Differenz der Exponenten berechnen
                sub     a,b
                ld      b,a             ; Differenz nach B fuer LOOP-Befehl
                jr      z,N_Anp         ; falls Null, keine Anpassung
                cp      a,25            ; mehr als 24? (Abfrage mit Carry
                jp      c,Anp           ; erfordert Vergleich mit 25)
                ld      b,0             ; !!!!
                jp      Round

Anp:            srl     (ix+Op2+3)      ; Anpassung der zweiten Mantisse
                rr      (ix+Op2+2)      ; durch Verschiebung nach rechts
                rr      (ix+Op2+1)
                rr      (ix+Op2)
                djnz    Anp             ; bis B=0

N_Anp:          bit     7,d             ; Addition oder Subtraktion ?
                jr      nz,Subtract     ; ggfs. zur Subtraktion springen
                ld      hl,(ix+Op1)     ; jetzt werden die beiden Mantissen
                add     hl,(ix+Op2)     ; zueinander addiert
                ld      (ix+Op1),hl
                ld      hl,(ix+Op1+2)
                adc     hl,(ix+Op2+2)
                ld      (ix+Op1+2),hl
                jr      nc,Round        ; kein Ueberlauf-->zum Runden
                rr      (ix+Op1+3)      ; Ueberlauf einschieben
                rr      (ix+Op1+2)
                rr      (ix+Op1+1)
                rr      (ix+Op1)
                inc     bc              ; Exponent erhoehen (B ist 0 durch
                jr      Round           ; Schleife), zum Runden

Subtract:       ld      hl,(ix+Op1)     ; beide Mantissen werden voneinander
                sub     hl,(ix+Op2)     ; subtrahiert
                ld      (ix+Op1),hl
                ld      hl,(ix+Op1+2)
                sbc     hl,(ix+Op2+2)
                ld      (ix+Op1+2),hl
                jr      m,Round         ; bei fuehrender Eins zum Runden
                jr      nz,Norm         ; ungleich 0 ?  Dann zum Normalisieren
                cp      hl,(ix+Op1)     ; Rest der Mantisse auch Null ?
                jr      eq,Zero         ; alles Null --> Ergebnis ist Null

Norm:           ld      a,b             ; Exponent noch nicht Null ?
                or      a,c
                jr      z,Round
                dec     bc              ; Exponent erniedrigen
                sla     (ix+Op1)        ; Mantisse normalisieren, bis
                rl      (ix+Op1+1)      ; fuehrende Eins auftaucht
                rl      (ix+Op1+2)
                rl      (ix+Op1+3)
                jr      p,Norm          ; noch keine Eins-->weitermachen

Round:          add     (ix+Op1),80h    ; jetzt Runden auf Bit hinter Mantisse
                jr      nc,NoOver       ; kein Uebertrag ?
                inc     (ix+Op1+1)      ; doch, naechstes Mantissenbyte
                jr      nz,NoOver       ; behandeln, jetzt auf Null pruefen,
                inc     (ix+Op1+2)      ; da der INC-Befehl kein Carry liefert
                jr      nz,NoOver
                inc     (ix+Op1+3)
                jr      nz,NoOver
                scf                     ; fuehrende Eins erzeugen
                rr      (ix+Op1+3)      ; bei Ueberlauf Mantisse durch
                rr      (ix+Op1+2)      ; Rechtsschieben wieder normalisieren
                rr      (ix+Op1+1)      ; (nur fuer 24 Bit notwendig)
                inc     bc              ; und Exponent korrigieren

NoOver:         xor     a,a             ; A = 0
                cp      a,(ix+Op1+3)    ; Mantisse auf Null pruefen
                jr      nz,NoZero
                cp      a,(ix+Op1+2)
                jr      nz,NoZero
                cp      a,(ix+Op1+1)    ; alle Mantissenbytes Null ?
                jr      nz,NoZero       ; dann ist auch das Ergebnis Null

Zero:           ld      b,a             ; Null-Ergebnis aufbauen
                ld      c,a
                ld      de,bc
                jr      Exit            ; dann Routine verlassen

NoZero:         cp      a,b             ; A ist Null
                ld      a,MaxExpo       ; Exponent oberes Byte ungleich Null ?
                jr      nz,Over         ; dann ist Ueberlauf eingetreten
                cp      a,c             ; oder genau MaxExpo erreicht ?
                jr      nz,NoUe
Over:           ld      c,a             ; Exponent auf MaxExpo setzen
                xor     a,a             ; und Mantisse auf Null
                ld      (ix+Op1+3),a
                ld      (ix+Op1+2),a
                ld      (ix+Op1+1),a
                jr      DeNorm

NoUe:           xor     a,a             ; A = 0
                cp      a,c             ; Exponent Null (Zahl denormalisiert ?
                jr      z,DeNorm        ; ja -->
                sla     (ix+Op1+1)      ; fuehrendes Bit wird nicht gespeichert
                rl      (ix+Op1+2)      ; daher Mantisse um 1 Bit nach links
                rl      (ix+Op1+3)

DeNorm:         ld      b,c             ; Ergebnis aufbauen: Exponent in B
                ld      c,(ix+Op1+3)    ; Mantisse oberstes Byte
                ld      d,(ix+Op1+2)
                sla     e               ; Vorzeichen aus E in Carry schieben
                ld      e,(ix+Op1+1)
                rr      b               ; Vorzeichen in Ergebnis einschieben
                rr      c
                rr      d
                rr      e

Exit:           pop     hl              ; Register restaurieren
                pop     af

                unlk    ix              ; Austritt
                retd    2*OpSize        ; Parameter abraeumen
                endp

;------------------------------------------------------------------------------
; Subtraktion

                proc    fsub

                link    ix,0            ; Eintritt

                push    af              ; Register retten
                push    hl

                xor     (ix+Op2+3),80h  ; Vorzeichen Operand 2 kippen

                jrl     AddSub          ; weiter wie Addition

                endp

;------------------------------------------------------------------------------
; Multiplikation

                proc    fmul

                DefLocal temp,6         ; Platz Temporaervariable

                link    ix,LocalSize    ; Platz auf Stack reservieren

                push    af              ; Register retten
                push    hl

                ld      a,(ix+Op1+3)    ; Ergebnisvorzeichen bestimmen
                xor     a,(ix+Op2+3)
                ld      c,a             ; in C merken

                ld      d,0             ; Exponent 1 laden
                ld      e,(ix+Op1+3)
                ld      a,(ix+Op1+2)
                slaa                    ; Exponent unterstes Bit in Carry
                rl      e               ; und in E einschieben
                srla                    ; ergibt Bit 7=0
                ld      (ix+Op1+3),a    ; impl. Null vorbesetzen+um 8 Bit schieben
                cp      e,0
                jr      z,Den1          ; falls Null, dann denormalisiert
                set     7,(ix+Op1+3)    ; ansonsten impl. Eins erzeugen
                dec     de              ; Bias kompensieren
Den1:           ld      hl,(ix+Op1)     ; jetzt restliche Bytes verschieben
                ld      (ix+Op1+1),hl
                xor     hl,hl           ; unterste Mantissenbits loeschen
                ld      (ix+Op1),h      ; Form: ffff ... ffff 0000 0000

                ld      (ix+temp+4),hl  ; lokale Variable mit Null vorbesetzen
                ld      (ix+temp+2),hl
                ld      (ix+temp),hl

                ld      l,(ix+Op2+3)    ; Exponent 2 in HL aufbauen
                ld      a,(ix+Op2+2)
                res     7,(ix+Op2+2)    ; gleiches Verfahren wie Op1
                slaa
                rl      l
                jr      z,Den2
                set     7,(ix+Op2+2)
                dec     hl
Den2:
                add     hl,de           ; Exponenten aufaddieren
                sub     hl,Bias-3       ; Bias-3 subtrahieren
                jp      p,NoZero        ; positiv-->kein Unterlauf
                ld      a,l             ; Exponent <-24 ?
                cp      a,-24
                jr      nc,NoZero
                jp      MulZero         ; ja, dann ist Ergebnis Null

NoZero:         ld      b,24            ; Schleifenzaehler Multiplikation
                ld      de,0            ; Hilfsregister Multiplikand
                push    hl              ; HL zum Addieren benutzen
Multiply:       srl     (ix+Op1+3)      ; Multiplikand nach rechts schieben
                rr      (ix+Op1+2)
                rr      (ix+Op1+1)
                rr      (ix+Op1)
                rr      d               ; DE als Verlaengerung von Operand 1
                rr      e
                sla     (ix+Op2)        ; Multiplikator nach links schieben
                rl      (ix+Op2+1)
                rl      (ix+Op2+2)      ; falls fuehrendes Bit 0, nicht addieren
                jr      nc,NoAdd
                ld      hl,(ix+temp)    ; sonst aufaddieren
                add     hl,de
                ld      (ix+temp),hl
                ld      hl,(ix+temp+2)
                adc     hl,(ix+Op1)
                ld      (ix+temp+2),hl
                ld      hl,(ix+temp+4)
                adc     hl,(ix+Op1+2)
                ld      (ix+temp+4),hl
NoAdd:          djnz    Multiply        ; Schleife durchlaufen
                pop     hl
                ld      a,(ix+temp+5)
                or      a,a             ; Flags setzen
                jp      m,MulRound      ; bei fuehrender Eins zum Runden
                jr      nz,Normalize    ; ansonsten normalisieren
                cp      a,(ix+temp+4)
                jr      nz,Normalize
                cp      a,(ix+temp+3)
                jr      nz,Normalize
                cp      a,(ix+temp+2)
                jr      Normalize
                jp      MulZero         ; komplett Null-->Ergebnis Null

Normalize:      bit     7,h             ; Exponent negativ ?
                jp      nz,Underrun     ; ggf. Unterlauf behandlen

Norm1:          cp      hl,0            ; Exponent=0 ?
                jr      z,MulRound
                dec     hl              ; Exponent erniedrigen,
                sla     (ix+temp)       ; Mantisse verschieben...
                rl      (ix+temp+1)
                rl      (ix+temp+2)
                rl      (ix+temp+3)
                rl      (ix+temp+4)
                rl      (ix+temp+5)
                jp      p,Norm1         ; ...bis fuehrende Eins auftaucht

                public  MulRound:Parent ; Einsprung fuer Division
MulRound:       ld      a,(ix+temp+2)   ; jetzt Runden auf Bit hinter Mantisse
                add     a,80h
                jr      nc,NoOver       ; kein Uebertrag
                inc     (ix+temp+3)     ; doch, naechstes Mantissenbyte
                jr      nz,NoOver       ; behandeln, jetzt auf Null pruefen
                inc     (ix+temp+4)     ; da INC kein Carry liefert
                jr      nz,NoOver
                inc     (ix+temp+5)
                jr      nz,NoOver
                scf                     ; Eins erzeugen
                rr      (ix+temp+5)     ; bei Ueberlauf Mantisse durch
                rr      (ix+temp+4)     ; Rechtsschieben wieder normalisieren
                rr      (ix+temp+3)
                inc     hl              ; und Exponent korrigieren

NoOver:         cp      hl,MaxExpo      ; Exponent pruefen
                jr      ult,NoUeber     ; kein Ueberlauf

                public  MulOver:Parent  ; Einsprung fuer fdiv
MulOver:        ld      hl,MaxExpo      ; Ueberlauf: Exponent=MaxExpo
                ld      (ix+temp+5),h
                ld      (ix+temp+4),h
                ld      (ix+temp+3),h
                jr      DeNorm

NoUeber:        xor     a,a             ; A=0
                cp      a,l             ; Exponent ist Null ?
                jr      z,DeNorm        ; ja, Ergebnis ist denormalisiert
                sla     (ix+temp+3)     ; nein, fuehrende=implizite Eins
                rl      (ix+temp+4)     ; rausschieben
                rl      (ix+temp+5)

DeNorm:         sla     c               ; Vorzeichen in Carry schieben
                ld      b,l             ; Exponent einsetzen
                ld      c,(ix+temp+5)
                ld      d,(ix+temp+4)
                ld      e,(ix+temp+3)
                rr      b               ; und Vorzeichen einschieben
                rr      c
                rr      d
                rr      e               ; Form: seee eeee efff ffff ... ffff

Result:         pop     hl              ; Register zurueck
                pop     af

                unlk    ix              ; Stackrahmen abbauen
                retd    2*OpSize        ; Operanden abraeumen

                public  MulZero:Parent  ; Einsprung fuer fdiv
MulZero:        xor     a,a             ; Ergebnis ist Null
                ld      b,a
                ld      c,a
                ld      d,a
                ld      e,a
                jr      Result

Underrun:       ld      a,l             ; Exponent in A
                neg     a               ; negieren fuer Schleifenzaehler
                cp      a,24            ; totaler Unterlauf ?
                jr      nc,MulZero      ; ja, dann ist Ergebnis Null
                ld      b,a             ; Mantisse denormalisieren
Shr:            srl     (ix+temp+5)     ; bis Exponent Null ist
                rr      (ix+temp+4)
                rr      (ix+temp+3)
                djnz    Shr
                ld      l,b             ; Exponent in Register L=B=0
                jp      Denorm          ; denormalisiertes Ergebnis erzeugen

                endp

;------------------------------------------------------------------------------
; Division

                proc    fdiv

                DefLocal temp,6         ; Platz Temporaervariable

                link    ix,LocalSize    ; 6 Byte Platz auf Stack reservieren

                push    af              ; Register retten
                push    hl

                ld      a,(ix+Op1+3)    ; Ergebnisvorzeichen bestimmen
                xor     a,(ix+Op2+3)
                ld      c,a             ; Vorzeichen in C Bit 7 merken
                push    bc              ; Vorzeichen retten

                ld      h,0             ; Exponent 1 laden
                ld      l,(ix+Op1+3)
                ld      a,(ix+Op1+2)
                res     7,(ix+Op1+2)    ; impl. Null vorbesetzen
                slaa                    ; Exponent unterstes Bit in Carry
                rl      l               ; und in L einschieben
                jr      z,Den1          ; falls Null, dann Op1 denormalisiert
                set     7,(ix+Op1+2)    ; implizite Eins erzeugen
                dec     hl              ; Bias kompensieren
Den1:
                ld      d,0             ; Exponent 2 in DE aufbauen
                ld      e,(ix+Op2+3)
                ld      a,(ix+Op2+2)
                ld      (ix+Op2+3),a    ; Verfahren wie oben
                res     7,(ix+Op2+3)
                slaa
                rl      e
                jr      z,Den2
                set     7,(ix+Op2+3)
                dec     de
Den2:
                ld      bc,(ix+Op2)     ; jetzt restliche Bytes kopieren
                ld      (ix+Op2+1),bc
                xor     a,a             ; A=0
                ld      (ix+Op2),a      ; Form: ffff ... ffff 0000 0000
                srl     (ix+Op2+3)
                rr      (ix+Op2+2)
                rr      (ix+Op2+1)
                rr      (ix+Op2)        ; Form: 0fff ... ffff f000 0000
                jr      nz,NoZero1      ; Mantisse 2 auf Null pruefen
                cp      a,(ix+Op2+1)
                jr      nz,NoZero1
                cp      a,(ix+Op2+2)
                jr      nz,NoZero1
                cp      a,(ix+Op2+3)
                jr      nz,NoZero1
                jp      MulOver

NoZero1:        xor     a,a             ; Carry-Flag loeschen
                sbc     hl,de           ; Exponenten subtrahieren
                add     hl,Bias         ; Bias addieren
                jr      p,NoZero        ; Exponent negativ ?
                cp      l,-24           ; Exponent kleiner als -24 ?
                jr      nc,NoZero
                jp      MulZero         ; ja, dann ist das Ergebnis Null
NoZero:
                add     hl,25           ; Exponent um 25 erhoehen; jetzt ist er sicher groesser als Null
                xor     a,a             ; A=0
                ld      bc,(ix+Op1+1)   ; Divident in Register kopieren
                ld      d,(ix+Op1)
                ld      e,a             ; die untersten Bits sind Null
                cp      a,d             ; ist Divident Null ?
                jr      nz,NoZero2
                cp      a,c
                jr      nz,NoZero2
                cp      a,b
                jr      nz,NoZero2
                pop     bc              ; Stack bereinigen (Vorzeichen laden)
                jp      MulZero         ; und Null als Ergebnis ausgeben
NoZero2:
                ld      (ix+temp+5),a   ; Ergebnis vorbesetzen
                ld      (ix+temp+4),a
                ld      (ix+temp+3),a
                ld      (ix+temp+2),a

NormLoop:       bit     6,(ix+Op2+3)    ; ist der Divisor normalisiert ?
                jr      nz,Norm         ; ja-->
                inc     hl              ; nein, Exponent erhoehen
                sla     (ix+Op2)        ; Divisor verschieben bis in
                rl      (ix+Op2+1)      ; Form 01ff ...
                rl      (ix+Op2+2)
                rl      (ix+Op2+3)
                jr      NormLoop
Norm:           srl     b
                rr      c
                rr      d
                rr      e               ; Form: 0fff ... ffff f000 0000

                push    iy              ; Exponent nach IY
                ld      iy,hl
Loop:           ld      (ix+Op1+2),bc   ; Divident zwischenspeichern
                                        ; die Speicherplaetze von Op1
                ld      (ix+Op1),de     ; stehen zur Verfuegung, da wir Op1
                                        ; in die Register BC-DE kopiert haben
                ld      hl,de           ; jetzt Divisor abziehen
                sub     hl,(ix+Op2)
                ld      de,hl
                ld      hl,bc
                sbc     hl,(ix+Op2+2)
                ld      bc,hl
                jr      nc,IsOne        ; kein Carry: Divisor passt
                ld      de,(ix+Op1)     ; ansonsten zurueckkopieren
                ld      bc,(ix+Op1+2)   ; Carry bleibt erhalten!
IsOne:          ccf                     ; Carry-Flag umdrehen
                rl      (ix+temp+2)     ; Ergebnis aufbauen
                rl      (ix+temp+3)
                rl      (ix+temp+4)
                rl      (ix+temp+5)
                sla     e               ; Divident verschieben
                rl      d
                rl      c
                rl      b

                add     iy,-1           ; Exponent erniedrigen
                jr      z,DeNorm        ; falls Null, dann denormalisiert
                bit     0,(ix+temp+5)   ; fuehrende Eins in Ergebnis-Mantisse ?
                jr      z,Loop          ; nein, weiter rechnen

DeNorm:         ld      hl,iy           ; Exponent zurueck
                ld      b,(ix+temp+5)   ; hoechstes Bit merken
                ld      a,(ix+temp+4)
                ld      (ix+temp+5),a   ; Mantisse in Form
                ld      iy,(ix+temp+2)  ; ffff ... ffff 0000 0000
                ld      (ix+temp+3),iy
                pop     iy              ; IY erst jetzt freigeben
                rr      b               ; hoechstes Bit einschieben
                rr      (ix+temp+5)
                rr      (ix+temp+4)
                rr      (ix+temp+3)
                rr      (ix+temp+2)

                pop     bc              ; Vorzeichen wieder laden
                xor     a,a             ; A=0
                cp      a,(ix+temp+5)   ; Mantisse ist Null ?
                jr      nz,NoZero3
                cp      a,(ix+temp+4)
                jr      nz,NoZero3
                cp      a,(ix+temp+3)
                jr      nz,NoZero3
                cp      a,(ix+temp+2)
                jp      z,MulZero
NoZero3:
                jp      MulRound

                endp

;------------------------------------------------------------------------------
; Wandlung Integer-->Gleitkomma

                proc    fitof

                link    ix,0            ; Stackrahmen aufbauen
                push    af              ; Register retten
                push    hl

                ld      bc,(ix+Op2+2)   ; Operanden hereinholen
                ld      de,(ix+Op2)     ; Reihenfolge: BCDE

                ld      hl,bc           ; Operand = 0 ?
                or      hl,de
                jr      z,ItofResult    ; dann Ergebnis Null

                bit     7,b             ; Zahl positiv ?
                jr      z,Positive
                ld      hl,bc           ; dann Zahl negieren
                xor     hl,-1
                ld      bc,hl
                ld      hl,de
                xor     hl,-1
                inc     hl
                or      hl,hl
                ld      de,hl
                jr      nz,Positive
                inc     bc

Positive:       ld      l,Bias+32       ; Exponent vorbesetzen
Shift:          dec     l
                sla     e               ; Mantisse verschieben, bis fuehrende
                rl      d               ; Eins auftaucht
                rl      c
                rl      b
                jr      nc,Shift
                ld      e,d             ; Exponent einsetzen
                ld      d,c
                ld      c,b
                ld      b,l
                sla     (ix+Op2+3)      ; Vorzeichen in Carry
                rr      b               ; ins Ergebnis einschieben
                rr      c
                rr      d
                rr      e

                public  ItofResult:Parent
ItofResult:     pop     hl              ; Register zurueck
                pop     af
                unlk    ix              ; abbauen
                retd    4               ; Ende

                endp

;------------------------------------------------------------------------------
; Wandlung Gleitkomma-->Integer

                proc    fftoi

                link    ix,0            ; Stackrahmen aufbauen

                push    af              ; Register retten
                push    hl

                ld      d,(ix+Op2)      ; Operand in Register laden
                ld      bc,(ix+Op2+1)   ; Reihenfolge: EBCD
                ld      e,(ix+Op2+3)    ; erspart spaeter Vertauschungen

                ld      h,e             ; Vorzeichen in H, Bit 7
                ld      a,e             ; Exponent in A aufbauen
                sla     b               ; LSB aus B holen
                rla
                scf                     ; impl. Eins einschieben
                rr      b
                sub     a,Bias
                ld      l,a             ; Exponent nach L kopieren
                jp      m,Zero          ; falls keiner Null, Ergebnis Null
                ld      a,30
                cp      a,l             ; groesser 30 ?
                jr      c,Over          ; dann Ueberlauf
                ld      e,0             ; Zahl jetzt in BCDE in der Form
                inc     a               ; 1fff ... ffff 0000 0000

Shift:          srl     b               ; jetzt Mantisse verschieben
                rr      c
                rr      d
                rr      e
                inc     l
                cp      a,l             ; bis Exponent stimmt
                jr      nz,Shift
                bit     7,h             ; Zahl negativ ?
                jr      z,ItofResult    ; nein, fertig

                ld      hl,de           ; Zahl negieren
                xor     hl,-1
                ld      de,hl
                ld      hl,bc
                xor     hl,-1
                ld      bc,hl
                inc     de
                jr      nz,ItofResult
                inc     bc
                jr      nz,ItofResult

Zero:           ld      bc,0
                ld      de,bc
                jp      ItofResult      ; Ergebnis Null

Over:           bit     7,h             ; Ergebnis positiv ?
                jr      z,OpPos
                ld      b,80h           ; MININT laden
                xor     a,a             ; A=0
                ld      c,a
                ld      d,a
                ld      e,a
                jp      ItofResult
OpPos:          ld      b,7fh           ; MAXINT laden
                ld      a,0ffh
                ld      c,a
                ld      d,a
                ld      e,a
                jp      ItofResult

                endp

;------------------------------------------------------------------------------
; Multiplikation mit Zweierpotenz (in A)

                proc    fmul2

                link    ix,0            ; Stackrahmen aufbauen

                push    af              ; Register retten
                push    hl

                ld      de,(ix+Op2)     ; Operand 1 in Register laden
                ld      bc,(ix+Op2+2)

                ld      h,a             ; Operand 2 nach H kopieren
                ld      l,b             ; Vorzeichen nach L, Bit 7
                xor     a,a             ; A=0
                cp      a,b             ; Operand 1 = Null ?
                jr      nz,NoZero
                cp      a,c
                jr      nz,NoZero
                cp      a,d
                jr      nz,NoZero
                cp      a,e
                jr      z,Zero

NoZero:         sla     e               ; Operand 1 verschieben
                rl      d
                rl      c
                rl      b               ; Form: eeee eeee ffff ... fff0
                jr      z,Den           ; Falls Exponent Null -->denormal

                add     a,h             ; A=0+H
                jr      m,Div           ; Falls Op2<0-->Division
                add     a,b             ; A=Summe der Exponenten
                ld      b,a             ; zurueck nach B
                jr      c,Over          ; bei Ueberlauf-->
                cp      a,MaxExpo       ; oder genau MaxExpo
                jr      z,Over

Result:         sla     l               ; Vorzeichen in Carry schieben
                rr      b
                rr      c
                rr      d
                rr      e               ; Ergebnis zusammensetzen

Zero:           pop     hl              ; Register zurueck
                pop     af

                unlk    ix              ; Stackrahmen abbauen
                retd    4               ; Ende

Over:           ld      b,MaxExpo       ; Ueberlauf: Exponent=MaxExpo
                xor     a,a             ;           Mantisse=0
                ld      c,a
                ld      d,a
                ld      e,a
                jr      Result

Div:            add     a,b             ; A = Summe der Exponenten
                ld      b,a             ; zurueck nach B
                jr      z,Div2
                jr      p,Result        ; falls >0, Ergebnis abliefern
Div2:           scf                     ; implizite Eins real machen
                rr      c
                rr      d
                rr      e               ; Form: eeee eeee 1fff ... ffff

Denorm:         xor     a,a             ; A = 0
                cp      a,b             ; Exponent Null ?
                jr      z,Result        ; ja, ergebnis abliefern
                srl     c
                rr      d
                rr      e               ; Mantisse denormalisieren
                jr      nz,NoZero2
                cp      a,d
                jr      nz,NoZero2
                cp      a,c
                jr      nz,NoZero2
                ld      b,a             ; totaler Unterlauf, Ergebnis = Null
                jr      Zero

NoZero2:        inc     b               ; Exponent erhoehen
                jr      Denorm          ; weiter denormalisieren

DDD:            add     a,b             ; Summe der Exponenten bilden
                ld      b,a             ; zurueck nach B
                jr      Denorm

Den:            add     a,h             ; A=0+H
                jr      m,DDD           ; bei Division verzweigen
NoOver:         sla     e               ; Multiplikation: Eine
                rl      d               ; denormalisierte Mantisse
                rl      c               ; wird wieder normalisiert
                jr      c,Stop          ; bis fuehrende Eins rausfliegt
                dec     h               ; oder Operand 2 = Null
                jr      nz,NoOver
                jr      Result

Stop:           ld      a,h             ; Summe der Exponenten bilden
                add     a,b
                ld      b,a             ; zurueck nach B
                jr      Result

                endp

;------------------------------------------------------------------------------
; Quadratwurzel ziehen

                proc    fsqrt

Op              equ     4               ; Lage Parameter
                DefLocal XRoot,4        ; Iterationsvariablen
                DefLocal m2,4
                DefLocal xx2,4

                link    ix,LocalSize    ; Stackrahmen aufbauen

                push    af              ; Register retten
                push    hl
                push    iy

                bit     7,(ix+Op+3)     ; negatives Argument ?
                jp      nz,DomainError  ; dann Fehler

                ld      hl,(ix+Op+2)    ; Exponent isolieren
                and     hl,07f80h
                jp      z,Zero          ; keine Behandlung denormaler Zahlen

                ld      (ix+Op+3),0     ; Mantisse isolieren
                and     (ix+Op+2),7fh
                sub     hl,7fh*80h      ; Bias vom Exponenten entfernen
                ld      bc,hl
                bit     7,c             ; Exponent ungerade ?
                res     7,c
                jr      z,EvenExp
                ld      hl,(ix+Op)      ; ja: Mantisse verdoppeln
                add     hl,hl
                ld      (ix+Op),hl
                ld      hl,(ix+Op+2)
                adc     hl,hl
                add     hl,100h-80h     ; impl. Eins dazu
                ld      (ix+Op+2),hl
EvenExp:
                sra     b               ; Exponent/2 mit Vorzeichen
                rr      c
                ld      hl,7fh*80h      ; Bias wieder dazu
                add     hl,bc
                ld      iy,hl           ; Exponent in IY aufheben
                ld      de,(ix+Op+1)    ; x ausrichten (um 7 nach links)
                ld      a,(ix+Op+3)     ; oberstes Byte merken
                ld      (ix+Op+2),de    ; da wir hier eins zuviel schieben
                ld      d,(ix+Op)
                ld      e,0
                ld      (ix+Op),de
                srla                    ; dieses Bit einschieben
                rr      (ix+Op+3)
                rr      (ix+Op+2)
                rr      (ix+Op+1)
                rr      (ix+Op)
                ld      de,0            ; vorbelegen
                ld      (ix+XRoot),de
                ld      (ix+m2),de
                ld      d,40h
                ld      (ix+XRoot+2),de
                ld      d,10h
                ld      (ix+m2+2),de
Loop10:         ld      de,(ix+Op)      ; xx2 = x
                ld      (ix+xx2),de
                ld      de,(ix+Op+2)
                ld      (ix+xx2+2),de
Loop11:         ld      hl,(ix+xx2)     ; xx2 -= xroot
                sub     hl,(ix+XRoot)
                ld      (ix+xx2),hl
                ld      hl,(ix+xx2+2)
                sbc     hl,(ix+XRoot+2)
                ld      (ix+xx2+2),hl
                srl     (ix+XRoot+3)    ; xroot /= 2
                rr      (ix+XRoot+2)
                rr      (ix+XRoot+1)
                rr      (ix+XRoot)
                ld      hl,(ix+xx2)     ; xx2 -= m2
                sub     hl,(ix+m2)
                ld      (ix+xx2),hl
                ld      hl,(ix+xx2+2)
                sbc     hl,(ix+m2+2)
                ld      (ix+xx2+2),hl
                jr      m,DontSet1
                ld      hl,(ix+xx2)     ; x = xx2
                ld      (ix+Op),hl
                ld      hl,(ix+xx2+2)
                ld      (ix+Op+2),hl
                ld      hl,(ix+XRoot)   ; xroot += m2
                or      hl,(ix+m2)
                ld      (ix+XRoot),hl
                ld      hl,(ix+XRoot+2)
                or      hl,(ix+m2+2)
                ld      (ix+XRoot+2),hl
                ld      hl,(ix+m2)      ; m2 /= 4
                ld      de,(ix+m2+2)
                rept    2
                 srl    d
                 rr     e
                 rr     h
                 rr     l
                endm
                ld      (ix+m2),hl
                ld      (ix+m2+2),de
                or      hl,de
                jr      nz,Loop11
                jr      IsSame
DontSet1:       ld      hl,(ix+m2)      ; m2 /= 4
                ld      de,(ix+m2+2)
                rept    2
                 srl    d
                 rr     e
                 rr     h
                 rr     l
                endm
                ld      (ix+m2),hl
                ld      (ix+m2+2),de
                or      hl,de
                jp      nz,Loop10       ; 15* abarbeiten
                                        ; Bit 22..8
                ld      hl,(ix+Op)      ; 17. Iteration separat
                ld      (ix+xx2),hl
                ld      hl,(ix+Op+2)
                ld      (ix+xx2+2),hl
IsSame:         ld      hl,(ix+xx2)
                sub     hl,(ix+XRoot)
                ld      (ix+xx2),hl
                ld      hl,(ix+xx2+2)
                sbc     hl,(ix+XRoot+2)
                ld      (ix+xx2+2),hl
                ld      de,(ix+XRoot+2) ; mitsamt Carry...
                ld      hl,(ix+XRoot)
                srl     d
                rr      e
                rr      h
                rr      l
                jr      nc,NoC1
                set     7,d
NoC1:           ld      (ix+XRoot+2),hl ; auf neues Alignment umstellen
                ld      (ix+XRoot),de
                decw    (ix+xx2)        ; Carry von 0-$4000: xx2 -= m2
                jr      nz,NoC2
                decw    (ix+xx2+2)
NoC2:           bit     7,(ix+xx2+3)
                jr      nz,DontSet7
                or      (ix+xx2+3),0c0h ; 0-$4000: x2 -= m2, Teil 2
                ld      hl,(ix+xx2)
                ld      (ix+Op),hl
                ld      hl,(ix+xx2+2)
                ld      (ix+Op+2),hl
                or      (ix+XRoot+1),40h; xroot += m2
DontSet7:       ld      hl,(ix+Op)      ; x auf neues Alignment umstellen
                ld      de,(ix+Op+2)
                ld      (ix+Op),de
                ld      (ix+Op+2),hl
                ld      hl,1000h        ; m2 - obere Haelfte schon 0
                ld      (ix+m2),hl
Loop20:         ld      hl,(ix+Op)      ; xx2 = x
                ld      (ix+xx2),hl
                ld      hl,(ix+Op+2)
                ld      (ix+xx2+2),hl
Loop21:         ld      hl,(ix+xx2)     ; xx2 -= xroot
                sub     hl,(ix+XRoot)
                ld      (ix+xx2),hl
                ld      hl,(ix+xx2+2)
                sbc     hl,(ix+XRoot+2)
                ld      (ix+xx2+2),hl
                srl     (ix+XRoot+3)    ; XRoot = XRoot/2
                rr      (ix+XRoot+2)
                rr      (ix+XRoot+1)
                rr      (ix+XRoot)
                ld      hl,(ix+xx2)     ; x2 -= m2
                sub     hl,(ix+m2)
                ld      (ix+xx2),hl
                ld      hl,(ix+xx2+2)
                sbc     hl,(ix+m2+2)
                ld      (ix+xx2+2),hl
                jr      m,DontSet2
                ld      hl,(ix+xx2)     ; x = xx2
                ld      (ix+Op),hl
                ld      hl,(ix+xx2+2)
                ld      (ix+Op+2),hl
                ld      hl,(ix+XRoot)   ; xroot += m2
                or      hl,(ix+m2)
                ld      (ix+XRoot),hl
                ld      hl,(ix+XRoot+2)
                or      hl,(ix+m2+2)
                ld      (ix+XRoot+2),hl
                ld      hl,(ix+m2)      ; m2 /= 4
                ld      de,(ix+m2+2)
                rept    2
                 srl    d
                 rr     e
                 rr     h
                 rr     l
                endm
                ld      (ix+m2),hl
                ld      (ix+m2+2),de
                or      hl,de
                jr      nz,Loop21
                jr      Finish
DontSet2:       ld      hl,(ix+m2)      ; m2 /= 4
                ld      de,(ix+m2+2)
                rept    2
                 srl    d
                 rr     e
                 rr     h
                 rr     l
                endm
                ld      (ix+m2),hl
                ld      (ix+m2+2),de
                or      hl,de
                jp      nz,Loop20       ; 7* abarbeiten

Finish:         ld      hl,(ix+Op)      ; Aufrunden notwendig ?
                sub     hl,(ix+XRoot)
                ld      (ix+Op),hl
                ld      hl,(ix+Op+2)
                sub     hl,(ix+XRoot+2)
                ld      (ix+Op+2),hl
                jr      ule,NoInc
                incw    (ix+XRoot)      ; wenn ja, durchfuehren
                jr      nz,NoInc
                incw    (ix+XRoot)
NoInc:          res     7,(ix+XRoot+2)  ; impl. Eins loeschen
                ld      hl,(ix+XRoot+2) ; Exponent einbauen
                or      hl,iy
                ld      bc,hl           ; Ergebnis in BC-DE
                ld      de,(ix+XRoot)
                jr      End

DomainError:    ld      bc,0ffc0h       ; - NAN zuueckgeben
                ld      de,0
                jr      End

Zero:           ld      bc,0            ; Ergebnis 0
                ld      de,bc

End:            pop     iy              ; Register zurueck
                pop     hl
                pop     af

                unlk    ix              ; Stackrahmen abbauen
                retd    4               ; Ende

                endp

;------------------------------------------------------------------------------
; Zehnerpotenz bilden

                subproc fPot10

                push    ix              ; Register retten
                push    iy
                push    hl

                ld      bc,(One+2)      ; Ausgangspunkt fuers Multiplizieren
                ld      de,(One)
                ld      ix,(Ten+2)      ; zu benutzende Potenz
                ld      iy,(Ten)
                or      hl,hl           ; negative Potenz?
                jr      p,IsPos
                ld      ix,(Tenth+2)    ; dann eben mit Zehntel
                ld      iy,(Tenth)
                xor     hl,-1           ; Zweierkomplement
                inc     hl
IsPos:
                or      hl,hl           ; weiter multiplizieren ?
                jr      z,End           ; nein, Ende
                bit     0,l             ; Restpotenz ungerade ?
                jr      z,IsEven
                push    bc              ; ja: einzeln multiplizieren
                push    de
                push    ix
                push    iy
                call    fmul
IsEven:         srl     h
                rr      l
                push    bc              ; naechste Potenz berechnen
                push    de
                push    ix              ; durch quadrieren
                push    iy
                push    ix
                push    iy
                call    fmul
                ld      ix,bc
                ld      iy,de
                pop     de
                pop     bc
                jr      IsPos           ; weitersuchen
End:
                pop     hl              ; Register zurueck
                pop     iy
                pop     ix

                ret                     ; Ende

                endp

;------------------------------------------------------------------------------

                subproc fOutDec

Op              equ     6               ; Adresse Operand
Format          equ     4               ; Formatdeskriptor
                DefLocal Temp,4         ; 64-Bit-Erweiterung Divident

                link    ix,LocalSize

                push    af              ; Register retten
                push    bc
                push    de
                push    hl

                bit     7,(ix+Op+3)     ; negativ ?
                jr      z,IsPos
                ld      (iy),'-'        ; ja: vermerken...
                inc     iy
                ld      hl,(ix+Op)      ; ...und Zweierkomplement
                xor     hl,-1
                ld      (ix+Op),hl
                ld      hl,(ix+Op+2)
                xor     hl,-1
                ld      (ix+Op+2),hl
                incw    (ix+Op)
                jr      nz,GoOn
                incw    (ix+Op+2)
                jr      GoOn
IsPos:          bit     7,(ix+Format+1) ; Pluszeichen ausgeben ?
                jr      nz,GoOn
                ld      (iy),'+'
                inc     iy
GoOn:           res     7,(ix+Format+1) ; Plusflag loeschen
                ld      de,0            ; Nullflag & Zaehler loeschen

InLoop:         ld      hl,0            ; Division vorbereiten
                ld      (ix+Temp),hl    ; dazu auf 64 Bit erweitern
                ld      (ix+Temp+2),hl
                ld      b,32            ; 32-Bit-Division
DivLoop:        sll     (ix+Op)         ; eins weiterschieben
                rl      (ix+Op+1)
                rl      (ix+Op+2)
                rl      (ix+Op+3)
                rl      (ix+Temp)
                rl      (ix+Temp+1)
                rl      (ix+Temp+2)
                rl      (ix+Temp+3)
                srl     (ix+Op)         ; fuer nachher
                ld      hl,(ix+Temp)    ; probeweise abziehen
                sub     hl,10
                ld      (ix+Temp),hl
                ld      hl,(ix+Temp+2)
                sbc     hl,0
                ld      (ix+Temp+2),hl
                jr      nc,DivOK        ; passt es ?
                ld      hl,(ix+Temp)    ; nein, zuruecknehmen
                add     hl,10
                ld      (ix+Temp),hl
                ld      hl,(ix+Temp+2)
                adc     hl,0
                ld      (ix+Temp+2),hl
                scf                     ; ins Ergebnis 0 einschieben
DivOK:          ccf                     ; neues Ergebnisbit
                rl      (ix+Op)         ; von unten einschieben
                djnz    DivLoop

                ld      a,(ix+Temp)     ; ASCII-Offset addieren
                add     a,'0'
                bit     0,d             ; schon im Nullbereich ?
                jr      z,NormVal
                ld      a,(ix+Format)   ; ja, dann gewuenschtes Leerzeichen
NormVal:        push    af              ; auf LIFO legen
                inc     e               ; ein Zeichen mehr
                ld      a,(ix+Op)       ; Quotient Null ?
                or      a,(ix+Op+1)
                or      a,(ix+Op+2)
                or      a,(ix+Op+3)
                ld      d,0             ; Annahme: nicht Null
                jr      nz,InLoop       ; falls <>0, auf jeden Fall weiter
                ld      d,0ffh          ; Flag auf True setzen
                ld      a,e             ; ansonsten nur weiter, falls minimale
                cp      a,(ix+Format+1) ; Zahl noch nicht erreicht
                jr      ult,InLoop

                ld      b,e             ; jetzt Zeichen ausgeben
OutLoop:        pop     af
                ld      (iy),a
                inc     iy
                djnz    OutLoop

                pop     hl              ; Register zurueck
                pop     de
                pop     bc
                pop     af

                unlk    ix
                retd    6

                endp

;------------------------------------------------------------------------------
; Wandlung Float-->ASCII

                proc    fftoa

Op              equ     8               ; Lage Eingabe auf Stack
Format          equ     6               ; Lage Formatdeskriptor auf Stack
Buffer          equ     4               ; Pufferadresse
                DefLocal Copy,4         ; Temporaerkopie der Zahl
                DefLocal ExpSave,2      ; berechneter Exponent

                link    ix,LocalSize    ; Platz fuer Exponenten/Kopie der Zahl

                push    af              ; Register retten
                push    de
                push    iy
                push    hl

                ld      iy,(ix+Buffer)  ; Pufferadresse holen

                ld      hl,(ix+Op)      ; Zahl kopieren
                ld      (ix+Copy),hl
                ld      hl,(ix+Op+2)
                res     7,h             ; dabei Vorzeichen loeschen
                ld      (ix+Copy+2),hl

                ld      a,'+'           ; Annahme positiv
                sll     (ix+Op)         ; Vorzeichen herausschieben
                rl      (ix+Op+1)       ; und in Carry bringen
                rl      (ix+Op+2)
                rl      (ix+Op+3)
                jr      c,IsNeg         ; Minuszeichen immer erforderlich
                bit     0,(ix+Format+1) ; Pluszeichen dagegen optional
                jr      nz,NoMantSgn
                jr      WrMantSgn
IsNeg:          ld      a,'-'           ; negative Zahl
WrMantSgn:      ld      (iy),a          ; Vorzeichen ablegen
                inc     iy
NoMantSgn:
                ld      l,(ix+Op+3)     ; Exponent herausholen...
                ld      h,0             ; ...auf 16 Bit erweitern...
                ld      bc,(ix+Op+1)    ; ...und in Quelle loeschen
                ld      (ix+Op+2),bc
                ld      b,(ix+Op)
                ld      c,0
                ld      (ix+Op),bc

                cp      hl,MaxExpo      ; Sonderwerte ?
                jp      z,SpecialVals   ; ja-->

                or      hl,hl           ; Zahl denormal ?
                jr      nz,IsNormal     ; nein, normal weiter
                ld      a,(ix+Op+3)     ; falls Mantisse Null,
                or      a,(ix+Op+2)     ; nicht normalisieren
                or      a,(ix+Op+1)
                jr      z,IsNull
Normalize:      sll     (ix+Op+1)       ; ansonsten schieben, bis fuehrende
                rl      (ix+Op+2)       ; Eins da
                rl      (ix+Op+3)
                jr      c,IsNormal
                dec     hl
                jr      Normalize
IsNormal:       sub     hl,Bias         ; Bias abziehen
IsNull:
                ld      b,h             ; Zweierexponenten in Float wandeln
                ld      c,h
                push    bc
                push    hl
                call    fitof
                push    bc              ; in Dezimalexponenten wandeln
                push    de
                cpsh    bc,Ld10
                call    fdiv
                bit     7,b             ; Zahl negativ ?
                jr      z,NoCorr
                push    bc              ; dann noch eins abziehen wegen
                push    de              ; unterer Gaussklammer
                cpsh    bc,One
                call    fsub
NoCorr:         push    bc              ; den Ausflug in Float beenden
                push    de
                call    fftoi
                ld      (ix+ExpSave),de ; Exponenten retten

                ld      bc,(ix+Copy+2)  ; Originalzahl
                push    bc
                ld      bc,(ix+Copy)
                push    bc
                ld      hl,de           ; durch die Zehnerpotenz
                call    fPot10          ; des Exponenten
                push    bc
                push    de
                call    fdiv            ; teilen
Again:          ld      (ix+Copy),de    ; Ergebnis zwischen 1...9,999 retten
                ld      (ix+Copy+2),bc
                push    bc              ; Vorkommastelle berechnen
                push    de
                call    fftoi
                cp      e,10            ; doch etwas drueber ?
                jr      ult,NoRoundErr
                ld      bc,(ix+Copy+2)  ; dann nocheinmal zehnteln
                push    bc
                ld      bc,(ix+Copy)
                push    bc
                cpsh    bc,Tenth
                call    fmul
                incw    (ix+ExpSave)
                jr      Again
NoRoundErr:     add     e,'0'           ; Vorkommastelle nach ASCII
                ld      (iy),e          ; ablegen
                inc     iy
                sub     e,'0'           ; wieder rueckgaengig machen
                cp      (ix+Format),0   ; gar keine Nachkommastellen ?
                jr      eq,NoComma
                ld      (iy),'.'        ; Dezimalpunkt ausgeben
                inc     iy
                push    bc              ; Vorkomma nach Float wandeln
                push    de
                call    fitof
                push    bc
                push    de
                cpsh    bc,ix+Copy      ; von alter Zahl abziehen
                call    fsub
                xor     b,80h           ; war verkehrtherum
                push    bc              ; zum Skalieren auf Stack
                push    de
                ld      l,(ix+Format)   ; passende Skalierungskonstante ausrechnen
                ld      h,0
                call    fPot10
                push    bc
                push    de
                call    fmul            ; hochskalieren
                push    bc              ; Rundung
                push    de
                cpsh    bc,Half
                call    fadd
                push    bc              ; Stellen nach Integer
                push    de
                call    fftoi
                push    bc              ; entspr. ausgeben
                push    de
                ld      b,(ix+Format)   ; Format fuer fOutDec aufbauen
                set     7,b             ; kein Pluszeichen
                ld      c,'0'           ; Fuellzeichen Nullen
                push    bc
                call    fOutDec
                bit     5,(ix+Format+1) ; Nullen am Ende abraeumen ?
                jr      nz,CleanZeros
NoComma:
                ld      a,(ix+Format+1) ; falls Minimalstellenzahl Exponent=0
                and     a,00011100b     ; und Exponent=0, vergessen
                or      a,(ix+ExpSave)
                or      a,(ix+ExpSave+1)
                jr      z,End

                ld      (iy),'E'        ; Exponenten ausgeben
                inc     iy
                ld      hl,(ix+ExpSave)
                ld      b,h
                ld      c,h
                push    bc
                push    hl
                ld      c,'0'           ; evtl. vornullen
                ld      b,(ix+Format+1)
                rrc     b               ; Bit 1-->Bit 7
                rrc     b
                and     b,87h
                push    bc
                call    fOutDec

End:            ld      (iy),0          ; NUL-Zeichen als Terminierer
                ld      de,iy           ; Endezeiger nach DE
                pop     hl              ; Register zurueck
                pop     iy
                ex      de,hl           ; zur Subtraktion tauschen
                sub     hl,de           ; = Zahl geschriebener Zeichen
                ex      de,hl           ; HL wieder original
                ld      bc,de           ; Ergebnis nach BC
                pop     de
                pop     af

                unlk    ix              ; Stackrahmen abbauen
                retd    8               ; Ende

SpecialVals:    ld      a,(ix+Op+3)     ; Mantisse Null ?
                or      a,(ix+Op+2)
                or      a,(ix+Op+1)
                jr      nz,IsNAN
                ld      (iy),'I'        ; ja: Unendlichkeit
                ld      (iy+1),'N'
                ld      (iy+2),'F'
                add     iy,3
                jr      End
IsNAN:          ld      (iy),'N'        ; nein: NAN
                ld      (iy+1),'A'
                ld      (iy+2),'N'
                add     iy,3
                jr      End

CleanZeros:     cp      (iy-1),'0'      ; Null am Ende ?
                jr      nz,CleanNoZero  ; nein, Ende
                dec     iy              ; ja: Zaehler runter, so dass ueber-
                jr      CleanZeros      ; schrieben wird und neuer Versuch
CleanNoZero:    cp      (iy-1),'.'      ; evtl. Komma entfernbar ?
                jr      nz,Ready        ; nein-->
                dec     iy              ; ja: noch ein Zeichen weniger
Ready:          jrl     NoComma

                endp

;------------------------------------------------------------------------------
; Wandlung ASCII-->Float

                proc    fatof

SrcAddr         equ     4               ; Lage Parameter auf Stack
                DefLocal Flags,2        ; Steuerflags
                DefLocal Exp,2          ; Speicher Exponent
                DefLocal Mant,4         ; Speicher fuer Mantissenzwischenwert
                DefLocal Factor,4       ; Speicher fuer Zehnerpotenz

                link    ix,LocalSize    ; Stackrahmen aufbauen

                push    af              ; Register retten
                push    hl
                push    iy

                ld      iy,(ix+SrcAddr) ; Zeigeradresse laden
                ld      (ix+Flags),01h  ; Phase 1 (Mantisse), noch kein Vorzeichen
                ld      (ix+Flags+1),0
                ld      bc,(Ten)        ; in der Mantisse mit 10 hochmultiplizieren
                ld      (ix+Factor),bc
                ld      bc,(Ten+2)
                ld      (ix+Factor+2),bc
                ld      bc,0            ; Exponent mit 0 vorbelegen
                ld      (ix+Exp),bc
                ld      (ix+Mant),bc    ; Mantisse auch
                ld      (ix+Mant+2),bc

ReadLoop:       ld      a,(iy)          ; ein neues Zeichen holen
                inc     iy

                cp      a,0             ; Endezeichen ?
                jp      eq,Combine      ; ja, zusammenbauen

                cp      a,' '           ; Leerzeichen ignorieren
                jr      eq,ReadLoop

                cp      a,'+'           ; Pluszeichen gnadenhalber zulassen
                jr      ne,NoPlus       ; ist aber nur ein Dummy
                bit     0,(ix+Flags+1)  ; schon ein Vorzeichen dagewesen ?
                jp      nz,Error        ; dann Fehler
                set     0,(ix+Flags+1)  ; ansonsten einfach setzen
                jr      ReadLoop
NoPlus:
                cp      a,'-'           ; Minuszeichen bewirkt schon eher etwas
                jr      ne,NoMinus
                bit     0,(ix+Flags+1)  ; darf auch nur einmal auftreten
                jp      nz,Error
                set     0,(ix+Flags+1)
                cp      (ix+Flags),1    ; je nach Phase anderes Flag setzen
                jr      ne,MinPhase3
                set     1,(ix+Flags+1)  ; bei Mantisse Bit 1...
                jr      ReadLoop
MinPhase3:      set     2,(ix+Flags+1)  ; ...bei Exponent Bit 2
                jr      ReadLoop
NoMinus:
                cp      a,'.'           ; Umschaltung Phase 2 (Nachkomma) ?
                jr      ne,NoPoint
                cp      (ix+Flags),1    ; bish. Phase muss Eins sein
                jp      ne,Error
                ld      (ix+Flags),2    ; neue Phase eintragen
                set     0,(ix+Flags+1)  ; Nachkomma darf kein Vorzeichen haben
                ld      bc,(Tenth)      ; im Nachkomma durch 10 teilen
                ld      (ix+Factor),bc
                ld      bc,(Tenth+2)
                ld      (ix+Factor+2),bc
                jr      ReadLoop
NoPoint:
                cp      a,'e'           ; kleines & grosses E zulassen
                jr      eq,IsE
                cp      a,'E'
                jr      ne,NoE
IsE:            cp      (ix+Flags),3    ; vorh. Phase muss 1 oder 2 sein
                jp      eq,Error
                ld      (ix+Flags),3    ; vermerken
                res     0,(ix+Flags+1)  ; Vorzeichen wieder zulassen
                jr      ReadLoop
NoE:
                sub     a,'0'           ; jetzt nur noch 0..9 zugelassen
                jp      c,Error
                cp      a,9
                jp      ugt,Error
                set     0,(ix+Flags+1)  ; nach Ziffern keine Vorzeichen mehr zulassen

                cp      (ix+Flags),1    ; Phase 1 (Mantisse) :
                jr      ne,NoPhase1
                cpsh    bc,ix+Mant      ; bish. Mantisse * 10
                cpsh    bc,ix+Factor
                call    fmul
                push    bc              ; Ziffer dazuaddieren
                push    de
                ld      e,a
                ld      d,0
                ld      bc,0
                push    bc
                push    de
                call    fitof
                push    bc
                push    de
                call    fadd
                ld      (ix+Mant),de    ; Mantisse zuruecklegen
                ld      (ix+Mant+2),bc
                jrl     ReadLoop
NoPhase1:
                cp      (ix+Flags),2    ; Phase 2 (Nachkomma) :
                jr      nz,NoPhase2
                ld      e,a             ; Stelle nach Float
                ld      d,0
                ld      bc,0
                push    bc
                push    de
                call    fitof
                push    bc              ; mit Zehnerpotenz skalieren
                push    de
                cpsh    bc,ix+Factor
                call    fmul
                push    bc              ; zur Mantisse addieren
                push    de
                cpsh    bc,ix+Mant
                call    fadd
                ld      (ix+Mant),de    ; Mantisse zuruecklegen
                ld      (ix+Mant+2),bc
                cpsh    bc,ix+Factor    ; Faktor * 1/10
                cpsh    bc,Tenth
                call    fmul
                ld      (ix+Factor),de
                ld      (ix+Factor+2),bc
                jrl     ReadLoop
NoPhase2:
                ld      hl,(ix+Exp)
                mul     hl,10           ; Exponent heraufmultiplizieren
                add     a,l
                ld      l,a
                ld      a,0
                adc     h,0
                cp      hl,45           ; Minimum ist 1E-45
                jr      ugt,Error
                ld      (ix+Exp),hl
                jrl     ReadLoop

Combine:        ld      hl,(ix+Exp)
                bit     2,(ix+Flags+1)  ; Exponent negativ ?
                jr      z,ExpPos
                xor     hl,-1
                inc     hl
ExpPos:         call    fPot10          ; Zehnerpotenz des Exponenten bilden
                push    bc
                push    de
                cpsh    bc,ix+Mant      ; mit Mantisse kombinieren
                call    fmul
                bit     1,(ix+Flags+1)  ; Mantisse negativ ?
                jr      z,ManPos
                set     7,b
ManPos:         rcf                     ; Ende ohne Fehler

End:            pop     iy              ; Register zurueck
                pop     hl
                pop     af

                unlk    ix              ; Rahmen abbauen
                retd    2               ; Ende

Error:          ld      hl,iy           ; rel. Zeichenposition ermitteln
                sub     hl,(ix+SrcAddr)
                ld      bc,hl
                scf                     ; Ende mit Fehler
                jr      End

                endp

;------------------------------------------------------------------------------
; gemeinsames Ende

                endsection

