Blame | Last modification | View Log | Download | RSS feed
; FLOAT.INC;******************************************************************************;* Gleitkommabibliothek fuer TLCS 900 *;* *;* Originale fuer den 68000 aus mc, bis auf die Quadratwurzel aus c't *;* Portierung auf TLCS 900 von Alfred Arnold, Oktober 1993 *;* *;* Routine Funktion Eingabe Ausgabe Stack Laenge Zeit/14MHz *;* *;* fadd Addition XWA+XHL XWA 12 Byte 194 Byte 60 us *;* fsub Subtraktion XWA-XHL XWA 12 Byte 7 Byte 65 us *;* fmul Multiplikation XWA*XHL XWA 20 Byte 218 Byte 70 us *;* fdiv Division XWA/XHL XWA 20 Byte 147 Byte 300 us *;* fmul2 Mult. mit 2er-Potenz XWA*(2^BC) XWA 6 Byte 99 Byte 20 us *;* fitof Int-->Float XWA XWA 4 Byte 41 Byte 90 us *;* fftoi Float-->Int XWA XWA 2 Byte 72 Byte 20 us *;* fsqrt Quadratwurzel XWA XWA 16 Byte 192 Byte 220 us *;* fftoa Float-->ASCII XWA (XHL),BC ~38 Byte 228 Byte ~4500 us *;* fatof ASCII-->Float (XHL),BC XWA,[BC] ~40 Byte 260 Byte ~2300 us *;* *;* - Wollen Sie einzelne Routinen entfernen, so beachten Sie, dass fsub Teile *;* aus fadd und fdiv Teile aus fmul verwendet ! *;* - Gleitkommaformat ist IEEE Single (32 Bit) *;* - Integerwerte bei fmul2, fitof und fftoi sind vorzeichenbehaftet *;* - Der Prozessor muss sich im Maximum-Modus befinden *;* - Da die Routinen lokale Labels verwenden, ist mindestens AS 1.39 erfor- *;* derlich *;* - Die Ausfuehrungszeiten koennen je nach Operand streuen, insbesondere bei *;* den Konvertierungsfunktionen *;* - MACROS.INC muss vorher eingebunden werden *;******************************************************************************;------------------------------------------------------------------------------; gemeinsamer Anfang, Makrosshifta macro op,dest ; Schieben, falls evtl. A>=16push a ; A wird zerschossenbit 4,a ; Akku im Bereich 16..31 ?jr z,smallerop 16,dest ; dann einmal gross schiebensmaller: push f ; Carry erhaltenand a,15 ; obere Bits plaettenjr z,fertigpop f ; evtl. Rest verarbeitenop a,destjr ende ; Carry schon gutfertig: pop fende: pop a ; A zurueckendmsection FloatLib;------------------------------------------------------------------------------; KonstantenLd10: dd ld(10) ; KonversionskonstantenOne: dd 1.0Half: dd 0.5Ten: dd 10.0Tenth: dd 3dcccccdh ; =0.1, aber die Rundung auf manchen; Systemen variiert (damit Test nicht; scheitert)Bias equ 127MaxExpo equ 255Comma equ '.';------------------------------------------------------------------------------; Addition: XWA=XWA+XHLproc faddpush xbc ; andere Register rettenpush xdepush xhlld xde,xwa ; Operand 1 nach XDE verschiebenrlc 1,xde ; Vorzeichen der Operanden nach Bit 0rlc 1,xhlld xbc,xde ; Differenz bildensub xbc,xhljr nc,NoSwap ; evtl. vertauschen, so dassld xwa,xhl ; groessere in XDEld xhl,xdeld xde,xwaNoSwap: ld qa,e ; Vorzeichen 1 ausmaskierenand qa,1 ; (=Ergebnis Vorzeichen)bit 0,c ; gleiches Vorzeichen ?jr z,NoSubset 1,qa ; dann Subtraktion vormerkenNoSub: sub xbc,xbc ; XBC initialisierenrlc 8,xde ; Exponent 1 rausholenld c,eor e,e ; falls <>0, implizite 1 einbauenscc nz,errc 1,xdeld e,0 ; Bit 0..7 wieder plaettenrlc 8,xhl ; dito Exponent 2 extrahierenld qc,lor l,lscc nz,lrrc 1,xhlld l,0; Zwischenstand:; - Mantissen linksbuendig inkl. impliziter Eins in XDE und XHL; - Exponent 1 in BC, Exponent 2 in QBC; - Ergebnisvorzeichen in QA, Bit 0; - Subtraktionsflag in QA, Bit 1ld wa,bc ; Exponentendifferenz berechnensub wa,qbccp wa,24 ; >24, d.h. Zahl 2 vernachlaessigbar gegen Zahl 1jr gt,Round ; ja, Ergebnis ist groessere Zahlshifta srl,xhl ; ansonsten Mantisse 2 entspr. anpassenAdd: bit 1,qa ; subtrahieren ?jr nz,Subtract ; ja-->add xde,xhl ; nein, Mantissen addierenjr nc,Round ; kein Ueberlauf, rundenrr 1,xde ; ansonsten Ueberlauf einschieben...inc bc ; ...und Exponent korrigierenjr Round ; normal weiter rundenSubtract: sub xde,xhl ; Mantissen subtrahierenjr z,Zero ; falls Null, Gesamtergebnis 0jr m,Round ; fuehrende 1 noch da: zum RundenNormalize: or bc,bc ; Exponent bereits Null ?jr z,Round ; dann denormales Ergebnisdec bc ; ansonsten Mantisse eins rauf, Exponentsll 1,xde ; eins runterjr p,Normalize ; solange, bis Eins auftauchtRound: add xde,80h ; Rundung auf Bit hinter Mantissejr nc,NoOverrr 1,xde ; Bei Ueberlauf korrigiereninc bcNoOver: ld e,0 ; Mantissenrest plaettenor xde,xde ; insgesamt 0 ?jr z,Zero ; dann Ergebnis 0cp bc,MaxExpo ; Exponentenueberlauf ?jr lt,NoEOverld bc,MaxExpo ; ja: Unendlich: Exponent=Maximumsub xde,xde ; Mantisse=0jr DenormalNoEOver: or bc,bc ; Exponent 0 ?jr z,Denormal ; ja, denormalsll 1,xde ; fuehrende Eins nicht speichernDenormal: ld e,c ; Exponenten einbauenrrc 8,xde ; nach oben schiebenrr 1,qa ; Vorzeichen einbauenrr 1,xdeZero: ld xwa,xde ; Ergebnis in Akkupop xhl ; Register zurueckpop xdepop xbcretendp;------------------------------------------------------------------------------; Subtraktion: XWA=XWA-XHLproc fsubxor qh,80h ; Vorzeichen 2 drehenjp fadd ; ansonsten wie Additionendp;------------------------------------------------------------------------------; Multiplikation: XWA=XWA*XHLproc fmulpublic MulRound:Parent,MulZero:Parent,MulResult:Parentpublic DivError:Parentpush xbc ; Register rettenpush xdepush xhlpush xixpush xiyld xiy,xwa ; Op1 kopierenxor xiy,xhl ; Ergebnisvorzeichen bestimmenex wa,qwa ; Registerhaelften Op1 vertauschenld xde,xwa ; Op1 ab sofort in XDEand de,7fh ; Exponent und Vz. behandelnand wa,7f80h ; Exponent maskierenjr z,Denorm1 ; gleich Null-->Op1 denormalset 7,de ; ansonsten implizite Eins einbauensub wa,80h ; Bias kompensierenDenorm1:ex hl,qhl ; Op2 genauso behandelnld xbc,xhland hl,7fhand bc,7f80hjr z,Denorm2set 7,hlsub bc,80hDenorm2:add bc,wa ; Exponenten addierensrl 7,bc ; richtig positionierensub bc,Bias-3 ; Bias-3 abziehencp bc,-24 ; totaler Unterlauf ?jr lt,MulZero ; dann Ergebnis 0ld wa,de ; beide oberen Haelften multiplizierenmul xwa,hlex wa,qwa ; Ergebnis in oberer Haelfte lagernld wa,de ; obere Haelfte Op1 rettenex de,qde ; untere Haelfte Op1 holenld ix,hl ; untere Haelfte Op1 * obere Op2mul xix,deex hl,qhl ; untere Op1 * untere Op2mul xde,hlex de,qde ; obere Op1 * untere Op2mul xhl,wald wa,de ; Teile aufaddierenadd xwa,xixadd xwa,xhljr z,MulResult ; Mantisse Null, Ergebnis Nulljr m,MulRoundor bc,bc ; Exponent negativ ?jr m,Unterlauf ; ggfs. Unterlauf behandelnNor: or bc,bc ; Exponent Null ?jr z,MulRound ; ja-->zum Rundenrl 1,xde ; nein, Mantisse eins nachschiebenrl 1,xwadec bc ; und Exponent runteror xwa,xwa ; fuehrende Eins da ?jr p,Nor ; nein, weiterschiebenMulRound: add xwa,80h ; Rundungjr nc,NoROver ; dabei Ueberlauf ?rr 1,xwa ; ja: Mantisse & Exponent korrigiereninc bcNoROver: cp bc,MaxExpo ; Exponentenueberlauf ?jr lt,NoEOverDivError: ld bc,MaxExpo ; dann unendlich einstellensub xwa,xwajr DenormalNoEOver: or bc,bc ; Exponent 0 ?jr z,Denormalsll 1,xwa ; fuehrende 1 loeschenDenormal: ld a,c ; Exponent einbauenrrc 8,xwa ; hochschiebenrl 1,xiy ; Vorzeichen einbauenrr 1,xwaMulResult: pop xiypop xixpop xhlpop xdepop xbcretMulZero: sub xwa,xwa ; Null erzeugenjr MulResultUnterlauf: cp bc,-24 ; totaler Unterlauf ?jr le,MulZero ; dann Nullneg bc ; sonst umbauenld xde,xwa ; dazu Akku freimachensub wa,wa ; Endexponentex wa,bc ; ist 0shifta srl,xde ; Mantisse herunterschiebenld xwa,xde ; Ergebnis zurueck nach XWAjr MulRound ; zurueck mit Exponent 0endp;------------------------------------------------------------------------------; Division: XWA=XWA/XHLproc fdivpush xbc ; Register retten (muss gleich zu fmul sein)push xdepush xhlpush xixpush xiyld xiy,xwa ; Op1 kopierenxor xiy,xhl ; Ergebnisvorzeichen bestimmenex wa,qwa ; Vorbehandlung wie bei fmulld xde,xwaand de,7fhand wa,7f80hjr z,Denorm1set 7,desub wa,80hDenorm1:ex hl,qhlld xbc,xhland hl,7fhand bc,7f80hjr z,Denorm2set 7,hlsub bc,80hDenorm2:sub wa,bc ; Exponentendifferenz bildenld bc,wa ; muс in BC liegensra 7,bc ; richtig positionierenadd bc,Bias ; Bias addierencp bc,-24 ; totaler Unterlauf ?jr lt,MulZero ; ja, Ergebnis Nullex hl,qhl ; Format 0fff ... ffff 0000 0000or xhl,xhl ; Ergebnis unendlich ?jrl z,DivErrorsll 7,xhlex de,qde ; dito Dividentor xde,xde ; falls Null, Ergebnis Nulljrl z,MulZerosll 7,xdeNormLoop: bit 14,qhl ; Divisor normalisiert ?jr nz,Normalinc bc ; nein, Exponent RAUF (ist Ergebnisexponent)sll 1,xhljr NormLoopNormal: sub xwa,xwa ; Ergebnisquotient vorbesetzenadd bc,25 ; Exponent nicht groesser als 0Loop: ld xix,xde ; Divident zwischenspeichernsub xde,xhl ; probeweise abziehenccf ; Carry drehenjr c,IsOne ; ungedrehter Carry=1: Divisor paсtld xde,xix ; ansonsten zurueckkopierenIsOne: rl 1,xwa ; Ergebnisbit einschiebensll 1,xde ; Divident verschiebendec bc ; Exponent runteror bc,bcjr z,Denorm ; falls Null, denormalisierenbit 8,qwa ; fuehrende Eins da ?jr z,Loop ; nein, weiterrechnenDenorm: sll 7,xwa ; Mantisse positionierenjrl z,MulResult ; Ergebnis 0 ?jrl MulRound ; ansonsten zum Rundenendp;-----------------------------------------------------------------------------; Multiplikation mit Zweierpotenz: XWA=XWA*2^BCproc fmul2push bc ; Register rettenpush xdeld xde,xwa ; Vorzeichen merkensll 1,xwa ; Vorzeichen rausschiebenjr z,Zero ; falls Null, Ergebnis Nullrlc 8,xwa ; Exponent nach unten...sub de,de ; und in DE packenadd e,ajr z,Denorm ; falls denormalisiert..or bc,bc ; Multiplikation oder Division ?jr m,Divide ; (neg. Exponent=Division)add de,bc ; Exponent addierencp de,MaxExpo ; Ueberlauf ?jr ge,Over ; ja, Ergebnis unendlichResult: ld a,e ; Ergebnisexponent einbauenrrc 8,xwa ; Exponent nach obenrl 1,xde ; Vorzeichen einschiebenrr 1,xwaZero: pop xde ; Register zurueckpop bcretOver: ld de,MaxExpo ; Ergebnis unendlichsub xwa,xwajr ResultDivide: add de,bc ; Exponentensumme bildenjr gt,Result ; >0, keine Sonderbehandlungscf ; ansonsten 1 explizit fБrrr 1,xwa ; denormale Zahl machenDDenorm: or de,de ; Exponent=0 ?jr z,Result ; ja, Ergebnis einfach denormalsrl 1,xwa ; ansonsten weiter denormalisierenjr z,Zero ; dabei totaler Unterlauf->Nullinc de ; Exponent korrigierenjr DDenormDDDenorm: add de,bc ; Exponentensumme bildenjr DDenormDenorm: or bc,bc ; Multiplikation oder Division ?jr m,DDDenormsub a,a ; alten Exponenten loeschenNorm: sll 1,xwa ; normalisieren...jr c,Stop ; bis fuehrende Eins dadec bc ; oder 2. Exponent 0or bc,bcjr nz,Normjr Result ; Multiplikator kompl. fuer Normalisierung draufgegangenStop: add de,bc ; Rest addierenjr Result ; alles andere schon o.k.endp;------------------------------------------------------------------------------; LongInt-->Float : XWA-->XWAproc fitofpush xbc ; Register rettenor xwa,xwa ; Null ?jr z,Result ; dann Ergebnis Nullscc m,qc ; Vorzeichen nach QC, Bit 0jr p,Positivecpl wa ; falls negativ,drehencpl qwainc xwaPositive: ld bc,Bias+32 ; Exponent vorbesetzenShift: dec bc ; Mantisse verschiebensll 1,xwajr nc,Shiftld a,c ; Exponent einbauenrrc 8,xwa ; Exponent nach obenrr 1,qc ; Vorzeichen einbauenrr 1,xwaResult: pop xbc ; Register zurueckretendp;------------------------------------------------------------------------------; Float-->LongInt : XWA-->XWAproc fftoipush bc ; Register rettenrl 1,xwa ; Vorzeichen in Carryscc c,b ; in B merkenrlc 8,xwa ; Exponent nach untenld c,a ; in C legensub c,Bias ; Bias abziehenjr m,Zero ; neg. Exponent -> Zahl<0 -> Ergebnis 0cp c,31 ; Ueberlauf ?jr ge,Overscf ; fuehrende Eins einschiebenrr 1,xwasub a,a ; Exponent loeschenShift: srl 1,xwa ; jetzt schieben, bis Ergebnis stimmtinc ccp c,31jr ne,Shiftsrl 1,b ; negieren ?jr nc,Positivecpl wa ; ggfs. negierencpl qwainc xwaPositive: pop bc ; Register zurueckretZero: sub xwa,xwa ; Ergebnis 0jr PositiveOver: ld xwa,7fffffffh ; Ueberlauf: Maxint zurueckgebensrl 1,b ; negativ ?jr nc,Positivecpl wa ; ja, neg. Maximum zurueckgebencpl qwajr Positiveendp;------------------------------------------------------------------------------; Quadratwurzel: XWA=SQRT(XWA)proc fsqrtpush xbc ; Register rettenpush xdepush xhlpush xixld xix,xwa ; Argument rettenor xix,xix ; Zahl negativ ?jrl m,DomainError ; dann geht es nichtex ix,qix ; MSW holenand xix,7f80h ; Exponent isolierenjrl z,Zero ; keine Behandlung denormaler Zahlenand xwa,7fffffh ; Mantisse isolierensub ix,7fh*80h ; Bias vom Exponenten entfernenbit 7,ix ; Exponent ungerade ?res 7,ixjr z,EvenExpadd xwa,xwa ; ja: Mantisse verdoppelnadd xwa,1000000h-800000h ; impl. Eins dazuEvenExp: ; erste Iteration ohne impl. Einssra 1,ix ; Exponent/2 mit Vorzeichenadd ix,7fh*80h ; Bias wieder dazuex ix,qix ; neuen Exponenten in QIX aufhebensll 7,xwa ; x ausrichtenld xde,40000000h ; xroot nach erster Iterationld xhl,10000000h ; m2=2 << (MaxBit-1)Loop10: ld xbc,xwa ; xx2 = xLoop11: sub xbc,xde ; xx2 -= xrootsrl 1,xde ; xroot = xroot/2sub xbc,xhl ; x2 -= m2jr m,DontSet1ld xwa,xbc ; x = xx2or xde,xhl ; xroot += m2srl 2,xhl ; m2 = m2/4jr nz,Loop11jr WABCSameDontSet1: srl 2,xhl ; m2 = m2/4jr nz,Loop10 ; 15* abarbeiten; Bit 22..8ld xbc,xwa ; 17. Iteration separatWABCSame: sub xbc,xderrc 1,xde ; mitsamt Carry...ex de,qde ; auf neues Alignment umstellensub xbc,1 ; Carry von 0-$4000: x2 -= m2jr m,DontSet7or xbc,-40000000h ; 0-$4000: x2 -= m2, Teil 2ld xwa,xbcor de,4000h ; xroot += m2DontSet7: ex wa,qwa ; x auf neues Alignment umstellenld hl,1000h ; m2 - obere Haelfte schon 0Loop20: ld xbc,xwa ; xx2 = xLoop21: sub xbc,xde ; xx2 -= xrootsrl 1,xde ; xroot = xroot/2sub xbc,xhl ; x2 -= m2jr m,DontSet2ld xwa,xbc ; x = xx2or xde,xhl ; xroot += m2srl 2,xhl ; m2 = m2/4jr nz,Loop21jr FinishDontSet2: srl 2,xhl ; m2 = m2/4jr nz,Loop20 ; 7* abarbeitenFinish: sub xwa,xde ; Aufrunden notwendig ?jr ule,NoIncinc xde ; wenn ja, durchfuehrenNoInc: res 7,qde ; impl. Eins loeschenor xde,xixld xwa,xde ; Ergebnis in XWAjr EndDomainError: ld xwa,0ffc00000h ; -NAN zurueckgebenjr EndZero: sub xwa,xwa ; Ergebnis 0End: pop xix ; Register zurueckpop xhlpop xdepop xbcretendp;------------------------------------------------------------------------------; Unterroutine Zehnerpotenz bilden: XWA=10.0^BCsection fPot10 ; nicht mit proc, da private Funktionpublic fPot10:ParentfPot10:push xbc ; Register rettenpush xhlld xwa,(One) ; Ausgangspunkt fuers Multiplizierenld xhl,(Ten) ; zu benutzende Potenzor bc,bc ; negative Potenz ?jr p,IsPosld xhl,(Tenth) ; dann eben Zehntel multiplizierenneg bc ; fuer Schleife immer positivIsPos:or bc,bc ; Noch weiter multiplizieren ?jr z,Endbit 0,bc ; Restpotenz ungerade ?jr z,IsEvencall fmul ; ja: einzeln multiplizierenIsEven: srl 1,bc ; naechste Stellepush xwa ; neue Potenz berechnenld xwa,xhlcall fmul ; durch quadrierenld xhl,xwapop xwajr IsPos ; weiter nach Einsen suchenEnd: pop xhl ; Register zurueckpop xbcretendsection;------------------------------------------------------------------------------; Unterroutine Zahl dezimal wandelnsection fOutDecpublic fOutDec:ParentfOutDec:push xwa ; Register rettenpush xbcpush depush xhlbit 15,qwa ; negativ ?jr z,IsPosld (xix+),'-' ; ja: vermerken...cpl wa ; ...und Zweierkomplementcpl qwainc xwajr GoOnIsPos: bit 7,c ; Pluszeichen ausgeben ?jr nz,GoOnld (xix+),'+'GoOn: res 7,c ; Plusflag loeschenld qbc,0 ; Nullflag und Zaehler loeschenInLoop: ld xhl,0 ; Division vorbereitenld e,32 ; 32 Bit-DivisionDivLoop: sll 1,xwa ; eins weiterschiebenrl 1,xhlsrl 1,xwa ; fuer nachhersub xhl,10 ; passt Divisor hinein ?jr nc,DivOKadd xhl,10 ; nein, zuruecknehmen...scf ; im Ergebnis 0 einschiebenDivOK: ccf ; neues Ergebnisbitrl 1,xwa ; Ergebnis in XWA einschieben...djnz e,DivLoopadd l,'0' ; ASCII-Offset addierenbit 1,qb ; schon im Nullbereich ?jr z,NormValld l,b ; ja, dann gewuenschtes LeerzeichenNormVal: push l ; auf LIFO legeninc qc ; ein Zeichen mehror xwa,xwa ; Quotient Null ?scc z,qbjr nz,InLoop ; wenn nicht Null, auf jeden Fall weitercp c,qc ; ansonsten nur, falls min. Stellenzahljr ugt,InLoop ; noch nicht erreichtOutLoop: pop a ; jetzt Zeichen umgekehrt ablegenld (xix+),adjnz qc,OutLooppop xhl ; Register zurueckpop depop xbcpop xwaretendsection;------------------------------------------------------------------------------; Gleitkomma nach ASCII wandeln:; In: Zahl in XWA; Zeiger auf Speicher in XHL; max. Anzahl Nachkommastellen in C; B/Bit 0 setzen, falls Mantissen-Pluszeichen unerwuenscht; B/Bit 1 setzen, falls Exponenten-Pluszeichen unerwuenscht; B/Bit 2..4 = Stellenzahl Exponent; B/Bit 5 setzen, falls Nullen am Ende der Mantisse unerwuenscht; Out: Zahl abgelegter Zeichen (exkl. NUL am Ende) in BC; (XHL) = gebildeter Stringproc fftoapush xix ; Register rettenpush xhlpush depush xbcpush xwald xix,xhl ; Zeiger auf Speicher kopierenld de,bc ; Parameter sichernld xhl,xwa ; Zahl auf die Zerlegebank bringenres 15,qwa ; Vorzeichen hier nicht mehr gebrauchtld c,'+' ; Annahme positivsll 1,xhl ; Vorzeichen in Carry bringenjr c,IsNeg ; Minuszeichen immer erforderlich...bit 0,d ; ...Pluszeichen optionaljr nz,NoMantSgnjr WrMantSgnIsNeg: ld c,'-' ; jaWrMantSgn: ld (xix+),c ; Mantissenvorzeichen ablegenNoMantSgn:ld c,qh ; Exponenten herausholen...extz bc ; ...auf 16 Bit erweitern...sll 8,xhl ; ...und in Quelle loeschencp bc,MaxExpo ; Sonderwert (INF/NAN) ?jrl z,SpecialVals ; ja-->or bc,bc ; Zahl denormal ?jr nz,IsNormal ; nein, normal weiteror xhl,xhl ; bei kompl. Null auch ueberspringenjr z,IsNullNormalize: sll 1,xhl ; ja: solange zaehlen, bis 1 erscheintjr c,IsNormaldec bcjr NormalizeIsNormal: sub bc,Bias ; Bias abziehenIsNull:push xwa ; fuer folgendes Zahl rettenld wa,bc ; Zweierexponenten in Float wandelnexts xwacall fitofld xhl,(Ld10) ; in Dezimalexponenten wandelncall fdivor xwa,xwa ; Zahl negativ ?jr p,NoCorrld xhl,(One) ; dann nocheinmal korrigieren wg.call fsub ; unterer GaussklammerNoCorr: call fftoi ; Den Ausflug in Float beendenld qbc,wa ; den Zehnerexponenten rettenld bc,wacall fPot10 ; von diesem Exponenten Zehnerpotenzld xhl,xwa ; bildenpop xwa ; alte Zahl zurueckcall fdiv ; Teilen: Ergebnis ist Zahl zwischenAgain: ld xhl,xwa ; 1.0 und 9.9999..., diese rettencall fftoi ; Vorkommastelle berechnencp a,10 ; doch etwas drueber ?jr ult,NoRoundErrld xwa,xhl ; ja, dann noch einmal zehntelnld xhl,(Tenth)call fmulinc qbcjr AgainNoRoundErr: add a,'0' ; diese nach ASCII wandeln...ld (xix+),a ; ...und ablegensub a,'0' ; wieder rueckgaengig machencp e,0 ; gar keine Nachkommastellen ?jr eq,NoCommald (xix+),Comma ; Dezimalpunkt ausgebencall fitof ; in ganze Gleitkommazahl wandelncall fsub ; Differenz bildenchg 15,qwa ; war verkehrtherum...ld xhl,xwa ; nach XHL verschieben, weil XWA gebrauchtld c,e ; Zehnerpotenz fuer Skalierung ausrechnenextz bc ; auf 16 Bit aufblasencall fPot10 ; Skalierungswert berechnencall fmul ; hochmultiplizierenld xhl,(Half) ; Rundungcall faddcall fftoi ; diese herausziehenld b,'0' ; n-stellig mit Vornullen ausgebenld c,eset 7,c ; kein Pluszeichen!call fOutDecbit 5,d ; Nullen am Ende abraeumen ?jr nz,CleanZerosNoComma:ld a,d ; falls Minimalstellenzahl Exponent=0and a,00011100b ; und Exponent=0, vergessenor a,qbor a,qcjr z,Endld (xix+),'E' ; Exponenten ausgebenld wa,qbcexts xwald b,'0' ; evtl. vornullen...ld c,d ; Bit 1-->Bit 7rrc 2,cand c,87h ; Bits ausmaskierencall fOutDecEnd: pop xwa ; Register zurueckpop xbcpop depop xhlld (xix),0 ; NUL-Zeichen im String nicht vergessensub xix,xhl ; Stringlaenge berechnenld bc,ixpop xixretSpecialVals: or xde,xde ; Ist die Mantisse Null ?jr nz,IsNANldw (xix+),'NI' ; ja: INF einschreibenld (xix+),'F'jr EndIsNAN: ldw (xix+),'AN' ; nein: NAN einschreibenld (xix+),'N'jr EndCleanZeros: cp (xix-1),'0' ; steht da eine Null am Ende ?jr nz,CleanNoZero ; nein, Endedec xix ; ja: Zaehler runter, so dass Ueber-jr CleanZeros ; schrieben wird und neuer VersuchCleanNoZero: cp (xix-1),Comma ; evtl. Komma entfernbar ?jr nz,NoComma ; nein-->dec xix ; ja: noch ein Zeichen wenigerjr NoCommaendp;------------------------------------------------------------------------------; ASCII nach Gleitkomma wandeln:; In: Zeiger auf String (ASCIIZ) in XHL; Out: XWA = Ergebnis bzw. fehlerhafte Stelle; CY = 0, falls fehlerfreiproc fatofpush xbc ; Register rettenpush xdepush xhlpush xixld xix,xhl ; Zeiger nach XIXld qbc,01 ; Phase 1 (Mantisse), noch kein Vorzeichenld xde,(Ten) ; in der Mantisse mit 10 hochmultiplizierenld xhl,0 ; Mantisse vorbelegenld bc,0 ; Exponent vorbelegenReadLoop: ld a,(xix+) ; ein neues Zeichen holenextz wa ; auf 32 Bit aufblasenextz xwacp a,0 ; Endezeichen ?jrl eq,Combine ; ja, alles zusammencp a,' ' ; Leerzeichen ignorierenjr eq,ReadLoopcp a,'+' ; Pluszeichen gnadenhalber zugelassenjr ne,NoPlus ; ist aber nur ein Dummybit 0,qb ; schon ein Vorzeichen dagewesen ?jrl nz,Error ; dann Fehlerset 0,qb ; ansonsten einfach setzenjr ReadLoopNoPlus:cp a,'-' ; Minuszeichen bewirkt schon eher etwasjr ne,NoMinusbit 0,qb ; darf auch nur einmal auftretenjrl nz,Errorset 0,qbcp qc,1 ; je nach Phase anderes Flag setzenjr ne,MinPhase3set 1,qb ; bei Mantisse Bit 1...jr ReadLoopMinPhase3: set 2,qb ; bei Exponent Bit 2jr ReadLoopNoMinus:cp a,'.' ; Umschaltung zu Phase 2 (Nachkomma) ?jr ne,NoPointcp qc,1 ; bish. Phase muss eins seinjrl ne,Errorld qc,2 ; neue Phase eintragenset 0,qb ; Nachkomma darf kein Vorzeichen habenld xde,(Tenth) ; im Nachkomma durch 10 teilenjr ReadLoopNoPoint:cp a,'e' ; kleines und grosses E zulassenjr eq,IsEcp a,'E'jr ne,NoEIsE: cp qc,3 ; vorherige Phase muss 1 oder 2 seinjr eq,Errorld qc,3 ; vermerkenres 0,qb ; Vorzeichen wieder zugelassenjr ReadLoopNoE:sub a,'0' ; jetzt nur noch 0..9 zugelassenjr c,Errorcp a,9jr ugt,Errorset 0,qb ; nach Ziffern kein Vorzeichen mehr zulassencp qc,1 ; Phase 1 (Mantisse) :jr ne,NoPhase1push xwa ; Zeichen rettenld xwa,xde ; bish. Mantisse * 10call fmulld xhl,xwapop xwa ; Zahl nach Float wandelncall fitofcall fadd ; dazuaddierenld xhl,xwa ; Mantisse zuruecklegenjrl ReadLoopNoPhase1:cp qc,2 ; Phase 2 (Nachkomma) :jr ne,NoPhase2call fitof ; Stelle nach Float wandelnpush xhl ; Mantisse rettenld xhl,xde ; Stelle mit Zehnerpotenz skalierencall fmulpop xhl ; zur Mantisse addierencall faddpush xwa ; Zwischenergebnis rettenld xwa,xde ; nДchste Skalierungspotenz ausrechnenld xhl,(Tenth)call fmulld xde,xwa ; alles wieder zurueckpop xhljrl ReadLoopNoPhase2:mul bc,10 ; Exponent heraufmultiplizierenadd bc,wacp bc,45 ; Minimum ist 1e-45jr ugt,Errorjrl ReadLoopCombine: bit 2,qb ; Exponent negativ ?jr z,ExpPosneg bcExpPos: call fPot10 ; Zehnerpotenz des Exponenten bildencall fmul ; mit Mantisse kombinierenbit 1,qb ; Mantisse negativ ?jr z,ManPosset 15,qwaManPos: rcf ; Ende ohne Fehlerpop xix ; Register zurueckpop xhlpop xdepop xbcretError: ld xwa,xix ; Endzeiger ladenpop xixpop xhlsub xwa,xhl ; rel. Position des fehlerhaften Zeichens berechnenpop xdepop xbcscf ; Ende mit Fehlerretendp;------------------------------------------------------------------------------; gemeinsames Endeendsection