Blame | Last modification | View Log | Download | RSS feed
; 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 KonstantenMaxExpo equ 255Bias equ 127OpSize equ 4 ; Groesse eines OperandenfIX_alt equ 0 ; Top of Stack liegt IXFAdr equ 2 ; RuecksprungadresseOp2 equ 4 ; Adresse Operand 2Op1 equ Op2+OpSize ; Adresse Operand 1Ld10: dd ld(10)One: dd 1.0Ten: dd 10.0Tenth: dd 3dcccccdh ; =0.1, aber die Rundung auf manchen; Systemen variiert (damit Test nicht; scheitert)Half: dd 0.5cpsh macro reg,op,{NoExpand}ld reg,(op+2)push regld reg,(op)push regendm;------------------------------------------------------------------------------; Additionproc faddlink ix,0 ; Eintrittpush af ; Register rettenpush hlpublic AddSub:Parent ; Einsprung fuer fsubAddSub: ld a,(ix+Op1+3) ; Vorzeichen Operand 1 ladenld e,a ; Ergebnisvorzeichen in E, Bit 7xor a,(ix+Op2+3) ; mit Vorzeichen von Op2 verknuepfenld d,a ; Subtraktionsflag in D, Bit 7res 7,(ix+Op1+3) ; Vorzeichen in Mantisse 1 loeschenres 7,(ix+Op2+3) ; Vorzeichen in Mantisse 2 loeschen; Die Operanden sind jetzt in der Form 0eee eeee efff ... ffffld hl,(ix+Op1) ; Differenz Op1-Op2 bildensub hl,(ix+Op2)ld hl,(ix+Op1+2)sbc hl,(ix+Op2+2)jr nc,Ad_1 ; Sprung falls Op1>Op2ld bc,(ix+Op1) ; ansonsten Operanden vertauschenex bc,(ix+Op2)ld (ix+Op1),bcld bc,(ix+Op1+2)ex bc,(ix+Op2+2)ld (ix+Op1+2),bcld a,e ; Ergebnisvorzeichen neu berechnenxor a,dld e,aAd_1: ld a,(ix+Op1+2) ; Exponent der groesseren Zahl ladenld c,(ix+Op1+3)slaarl cjr z,Den1set 7,(ix+Op1+2) ; implizite Eins erzeugenDen1: ld a,(ix+Op2+2) ; dito Zahl 2ld b,(ix+Op2+3)slaarl bjr z,Den2set 7,(ix+Op2+2)Den2: push bc ; jetzt die Register fuer denpush de ; Blocktransferbefehl rettenld bc,2*OpSize-1 ; beide Operanden verschiebenld hl,ix ; HL zeigt auf letztes Byteadd hl,Op2+2*OpSize-1ld de,hl ; HL nach DE kopierendec hl ; HL zeigt auf vorletztes Bytelddr ; Verschiebung beider Mantissenpop de ; um 8 Bit nach linkspop bcxor a,ald (ix+Op1),a ; Form: ffff ... ffff 0000 0000ld (ix+Op2),ald a,c ; Differenz der Exponenten berechnensub a,bld b,a ; Differenz nach B fuer LOOP-Befehljr z,N_Anp ; falls Null, keine Anpassungcp a,25 ; mehr als 24? (Abfrage mit Carryjp c,Anp ; erfordert Vergleich mit 25)ld b,0 ; !!!!jp RoundAnp: srl (ix+Op2+3) ; Anpassung der zweiten Mantisserr (ix+Op2+2) ; durch Verschiebung nach rechtsrr (ix+Op2+1)rr (ix+Op2)djnz Anp ; bis B=0N_Anp: bit 7,d ; Addition oder Subtraktion ?jr nz,Subtract ; ggfs. zur Subtraktion springenld hl,(ix+Op1) ; jetzt werden die beiden Mantissenadd hl,(ix+Op2) ; zueinander addiertld (ix+Op1),hlld hl,(ix+Op1+2)adc hl,(ix+Op2+2)ld (ix+Op1+2),hljr nc,Round ; kein Ueberlauf-->zum Rundenrr (ix+Op1+3) ; Ueberlauf einschiebenrr (ix+Op1+2)rr (ix+Op1+1)rr (ix+Op1)inc bc ; Exponent erhoehen (B ist 0 durchjr Round ; Schleife), zum RundenSubtract: ld hl,(ix+Op1) ; beide Mantissen werden voneinandersub hl,(ix+Op2) ; subtrahiertld (ix+Op1),hlld hl,(ix+Op1+2)sbc hl,(ix+Op2+2)ld (ix+Op1+2),hljr m,Round ; bei fuehrender Eins zum Rundenjr nz,Norm ; ungleich 0 ? Dann zum Normalisierencp hl,(ix+Op1) ; Rest der Mantisse auch Null ?jr eq,Zero ; alles Null --> Ergebnis ist NullNorm: ld a,b ; Exponent noch nicht Null ?or a,cjr z,Rounddec bc ; Exponent erniedrigensla (ix+Op1) ; Mantisse normalisieren, bisrl (ix+Op1+1) ; fuehrende Eins auftauchtrl (ix+Op1+2)rl (ix+Op1+3)jr p,Norm ; noch keine Eins-->weitermachenRound: add (ix+Op1),80h ; jetzt Runden auf Bit hinter Mantissejr nc,NoOver ; kein Uebertrag ?inc (ix+Op1+1) ; doch, naechstes Mantissenbytejr nz,NoOver ; behandeln, jetzt auf Null pruefen,inc (ix+Op1+2) ; da der INC-Befehl kein Carry liefertjr nz,NoOverinc (ix+Op1+3)jr nz,NoOverscf ; fuehrende Eins erzeugenrr (ix+Op1+3) ; bei Ueberlauf Mantisse durchrr (ix+Op1+2) ; Rechtsschieben wieder normalisierenrr (ix+Op1+1) ; (nur fuer 24 Bit notwendig)inc bc ; und Exponent korrigierenNoOver: xor a,a ; A = 0cp a,(ix+Op1+3) ; Mantisse auf Null pruefenjr nz,NoZerocp a,(ix+Op1+2)jr nz,NoZerocp a,(ix+Op1+1) ; alle Mantissenbytes Null ?jr nz,NoZero ; dann ist auch das Ergebnis NullZero: ld b,a ; Null-Ergebnis aufbauenld c,ald de,bcjr Exit ; dann Routine verlassenNoZero: cp a,b ; A ist Nullld a,MaxExpo ; Exponent oberes Byte ungleich Null ?jr nz,Over ; dann ist Ueberlauf eingetretencp a,c ; oder genau MaxExpo erreicht ?jr nz,NoUeOver: ld c,a ; Exponent auf MaxExpo setzenxor a,a ; und Mantisse auf Nullld (ix+Op1+3),ald (ix+Op1+2),ald (ix+Op1+1),ajr DeNormNoUe: xor a,a ; A = 0cp a,c ; Exponent Null (Zahl denormalisiert ?jr z,DeNorm ; ja -->sla (ix+Op1+1) ; fuehrendes Bit wird nicht gespeichertrl (ix+Op1+2) ; daher Mantisse um 1 Bit nach linksrl (ix+Op1+3)DeNorm: ld b,c ; Ergebnis aufbauen: Exponent in Bld c,(ix+Op1+3) ; Mantisse oberstes Byteld d,(ix+Op1+2)sla e ; Vorzeichen aus E in Carry schiebenld e,(ix+Op1+1)rr b ; Vorzeichen in Ergebnis einschiebenrr crr drr eExit: pop hl ; Register restaurierenpop afunlk ix ; Austrittretd 2*OpSize ; Parameter abraeumenendp;------------------------------------------------------------------------------; Subtraktionproc fsublink ix,0 ; Eintrittpush af ; Register rettenpush hlxor (ix+Op2+3),80h ; Vorzeichen Operand 2 kippenjrl AddSub ; weiter wie Additionendp;------------------------------------------------------------------------------; Multiplikationproc fmulDefLocal temp,6 ; Platz Temporaervariablelink ix,LocalSize ; Platz auf Stack reservierenpush af ; Register rettenpush hlld a,(ix+Op1+3) ; Ergebnisvorzeichen bestimmenxor a,(ix+Op2+3)ld c,a ; in C merkenld d,0 ; Exponent 1 ladenld e,(ix+Op1+3)ld a,(ix+Op1+2)slaa ; Exponent unterstes Bit in Carryrl e ; und in E einschiebensrla ; ergibt Bit 7=0ld (ix+Op1+3),a ; impl. Null vorbesetzen+um 8 Bit schiebencp e,0jr z,Den1 ; falls Null, dann denormalisiertset 7,(ix+Op1+3) ; ansonsten impl. Eins erzeugendec de ; Bias kompensierenDen1: ld hl,(ix+Op1) ; jetzt restliche Bytes verschiebenld (ix+Op1+1),hlxor hl,hl ; unterste Mantissenbits loeschenld (ix+Op1),h ; Form: ffff ... ffff 0000 0000ld (ix+temp+4),hl ; lokale Variable mit Null vorbesetzenld (ix+temp+2),hlld (ix+temp),hlld l,(ix+Op2+3) ; Exponent 2 in HL aufbauenld a,(ix+Op2+2)res 7,(ix+Op2+2) ; gleiches Verfahren wie Op1slaarl ljr z,Den2set 7,(ix+Op2+2)dec hlDen2:add hl,de ; Exponenten aufaddierensub hl,Bias-3 ; Bias-3 subtrahierenjp p,NoZero ; positiv-->kein Unterlaufld a,l ; Exponent <-24 ?cp a,-24jr nc,NoZerojp MulZero ; ja, dann ist Ergebnis NullNoZero: ld b,24 ; Schleifenzaehler Multiplikationld de,0 ; Hilfsregister Multiplikandpush hl ; HL zum Addieren benutzenMultiply: srl (ix+Op1+3) ; Multiplikand nach rechts schiebenrr (ix+Op1+2)rr (ix+Op1+1)rr (ix+Op1)rr d ; DE als Verlaengerung von Operand 1rr esla (ix+Op2) ; Multiplikator nach links schiebenrl (ix+Op2+1)rl (ix+Op2+2) ; falls fuehrendes Bit 0, nicht addierenjr nc,NoAddld hl,(ix+temp) ; sonst aufaddierenadd hl,deld (ix+temp),hlld hl,(ix+temp+2)adc hl,(ix+Op1)ld (ix+temp+2),hlld hl,(ix+temp+4)adc hl,(ix+Op1+2)ld (ix+temp+4),hlNoAdd: djnz Multiply ; Schleife durchlaufenpop hlld a,(ix+temp+5)or a,a ; Flags setzenjp m,MulRound ; bei fuehrender Eins zum Rundenjr nz,Normalize ; ansonsten normalisierencp a,(ix+temp+4)jr nz,Normalizecp a,(ix+temp+3)jr nz,Normalizecp a,(ix+temp+2)jr Normalizejp MulZero ; komplett Null-->Ergebnis NullNormalize: bit 7,h ; Exponent negativ ?jp nz,Underrun ; ggf. Unterlauf behandlenNorm1: cp hl,0 ; Exponent=0 ?jr z,MulRounddec 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 auftauchtpublic MulRound:Parent ; Einsprung fuer DivisionMulRound: ld a,(ix+temp+2) ; jetzt Runden auf Bit hinter Mantisseadd a,80hjr nc,NoOver ; kein Uebertraginc (ix+temp+3) ; doch, naechstes Mantissenbytejr nz,NoOver ; behandeln, jetzt auf Null pruefeninc (ix+temp+4) ; da INC kein Carry liefertjr nz,NoOverinc (ix+temp+5)jr nz,NoOverscf ; Eins erzeugenrr (ix+temp+5) ; bei Ueberlauf Mantisse durchrr (ix+temp+4) ; Rechtsschieben wieder normalisierenrr (ix+temp+3)inc hl ; und Exponent korrigierenNoOver: cp hl,MaxExpo ; Exponent pruefenjr ult,NoUeber ; kein Ueberlaufpublic MulOver:Parent ; Einsprung fuer fdivMulOver: ld hl,MaxExpo ; Ueberlauf: Exponent=MaxExpold (ix+temp+5),hld (ix+temp+4),hld (ix+temp+3),hjr DeNormNoUeber: xor a,a ; A=0cp a,l ; Exponent ist Null ?jr z,DeNorm ; ja, Ergebnis ist denormalisiertsla (ix+temp+3) ; nein, fuehrende=implizite Einsrl (ix+temp+4) ; rausschiebenrl (ix+temp+5)DeNorm: sla c ; Vorzeichen in Carry schiebenld b,l ; Exponent einsetzenld c,(ix+temp+5)ld d,(ix+temp+4)ld e,(ix+temp+3)rr b ; und Vorzeichen einschiebenrr crr drr e ; Form: seee eeee efff ffff ... ffffResult: pop hl ; Register zurueckpop afunlk ix ; Stackrahmen abbauenretd 2*OpSize ; Operanden abraeumenpublic MulZero:Parent ; Einsprung fuer fdivMulZero: xor a,a ; Ergebnis ist Nullld b,ald c,ald d,ald e,ajr ResultUnderrun: ld a,l ; Exponent in Aneg a ; negieren fuer Schleifenzaehlercp a,24 ; totaler Unterlauf ?jr nc,MulZero ; ja, dann ist Ergebnis Nullld b,a ; Mantisse denormalisierenShr: srl (ix+temp+5) ; bis Exponent Null istrr (ix+temp+4)rr (ix+temp+3)djnz Shrld l,b ; Exponent in Register L=B=0jp Denorm ; denormalisiertes Ergebnis erzeugenendp;------------------------------------------------------------------------------; Divisionproc fdivDefLocal temp,6 ; Platz Temporaervariablelink ix,LocalSize ; 6 Byte Platz auf Stack reservierenpush af ; Register rettenpush hlld a,(ix+Op1+3) ; Ergebnisvorzeichen bestimmenxor a,(ix+Op2+3)ld c,a ; Vorzeichen in C Bit 7 merkenpush bc ; Vorzeichen rettenld h,0 ; Exponent 1 ladenld l,(ix+Op1+3)ld a,(ix+Op1+2)res 7,(ix+Op1+2) ; impl. Null vorbesetzenslaa ; Exponent unterstes Bit in Carryrl l ; und in L einschiebenjr z,Den1 ; falls Null, dann Op1 denormalisiertset 7,(ix+Op1+2) ; implizite Eins erzeugendec hl ; Bias kompensierenDen1:ld d,0 ; Exponent 2 in DE aufbauenld e,(ix+Op2+3)ld a,(ix+Op2+2)ld (ix+Op2+3),a ; Verfahren wie obenres 7,(ix+Op2+3)slaarl ejr z,Den2set 7,(ix+Op2+3)dec deDen2:ld bc,(ix+Op2) ; jetzt restliche Bytes kopierenld (ix+Op2+1),bcxor a,a ; A=0ld (ix+Op2),a ; Form: ffff ... ffff 0000 0000srl (ix+Op2+3)rr (ix+Op2+2)rr (ix+Op2+1)rr (ix+Op2) ; Form: 0fff ... ffff f000 0000jr nz,NoZero1 ; Mantisse 2 auf Null pruefencp a,(ix+Op2+1)jr nz,NoZero1cp a,(ix+Op2+2)jr nz,NoZero1cp a,(ix+Op2+3)jr nz,NoZero1jp MulOverNoZero1: xor a,a ; Carry-Flag loeschensbc hl,de ; Exponenten subtrahierenadd hl,Bias ; Bias addierenjr p,NoZero ; Exponent negativ ?cp l,-24 ; Exponent kleiner als -24 ?jr nc,NoZerojp MulZero ; ja, dann ist das Ergebnis NullNoZero:add hl,25 ; Exponent um 25 erhoehen; jetzt ist er sicher groesser als Nullxor a,a ; A=0ld bc,(ix+Op1+1) ; Divident in Register kopierenld d,(ix+Op1)ld e,a ; die untersten Bits sind Nullcp a,d ; ist Divident Null ?jr nz,NoZero2cp a,cjr nz,NoZero2cp a,bjr nz,NoZero2pop bc ; Stack bereinigen (Vorzeichen laden)jp MulZero ; und Null als Ergebnis ausgebenNoZero2:ld (ix+temp+5),a ; Ergebnis vorbesetzenld (ix+temp+4),ald (ix+temp+3),ald (ix+temp+2),aNormLoop: bit 6,(ix+Op2+3) ; ist der Divisor normalisiert ?jr nz,Norm ; ja-->inc hl ; nein, Exponent erhoehensla (ix+Op2) ; Divisor verschieben bis inrl (ix+Op2+1) ; Form 01ff ...rl (ix+Op2+2)rl (ix+Op2+3)jr NormLoopNorm: srl brr crr drr e ; Form: 0fff ... ffff f000 0000push iy ; Exponent nach IYld iy,hlLoop: ld (ix+Op1+2),bc ; Divident zwischenspeichern; die Speicherplaetze von Op1ld (ix+Op1),de ; stehen zur Verfuegung, da wir Op1; in die Register BC-DE kopiert habenld hl,de ; jetzt Divisor abziehensub hl,(ix+Op2)ld de,hlld hl,bcsbc hl,(ix+Op2+2)ld bc,hljr nc,IsOne ; kein Carry: Divisor passtld de,(ix+Op1) ; ansonsten zurueckkopierenld bc,(ix+Op1+2) ; Carry bleibt erhalten!IsOne: ccf ; Carry-Flag umdrehenrl (ix+temp+2) ; Ergebnis aufbauenrl (ix+temp+3)rl (ix+temp+4)rl (ix+temp+5)sla e ; Divident verschiebenrl drl crl badd iy,-1 ; Exponent erniedrigenjr z,DeNorm ; falls Null, dann denormalisiertbit 0,(ix+temp+5) ; fuehrende Eins in Ergebnis-Mantisse ?jr z,Loop ; nein, weiter rechnenDeNorm: ld hl,iy ; Exponent zurueckld b,(ix+temp+5) ; hoechstes Bit merkenld a,(ix+temp+4)ld (ix+temp+5),a ; Mantisse in Formld iy,(ix+temp+2) ; ffff ... ffff 0000 0000ld (ix+temp+3),iypop iy ; IY erst jetzt freigebenrr b ; hoechstes Bit einschiebenrr (ix+temp+5)rr (ix+temp+4)rr (ix+temp+3)rr (ix+temp+2)pop bc ; Vorzeichen wieder ladenxor a,a ; A=0cp a,(ix+temp+5) ; Mantisse ist Null ?jr nz,NoZero3cp a,(ix+temp+4)jr nz,NoZero3cp a,(ix+temp+3)jr nz,NoZero3cp a,(ix+temp+2)jp z,MulZeroNoZero3:jp MulRoundendp;------------------------------------------------------------------------------; Wandlung Integer-->Gleitkommaproc fitoflink ix,0 ; Stackrahmen aufbauenpush af ; Register rettenpush hlld bc,(ix+Op2+2) ; Operanden hereinholenld de,(ix+Op2) ; Reihenfolge: BCDEld hl,bc ; Operand = 0 ?or hl,dejr z,ItofResult ; dann Ergebnis Nullbit 7,b ; Zahl positiv ?jr z,Positiveld hl,bc ; dann Zahl negierenxor hl,-1ld bc,hlld hl,dexor hl,-1inc hlor hl,hlld de,hljr nz,Positiveinc bcPositive: ld l,Bias+32 ; Exponent vorbesetzenShift: dec lsla e ; Mantisse verschieben, bis fuehrenderl d ; Eins auftauchtrl crl bjr nc,Shiftld e,d ; Exponent einsetzenld d,cld c,bld b,lsla (ix+Op2+3) ; Vorzeichen in Carryrr b ; ins Ergebnis einschiebenrr crr drr epublic ItofResult:ParentItofResult: pop hl ; Register zurueckpop afunlk ix ; abbauenretd 4 ; Endeendp;------------------------------------------------------------------------------; Wandlung Gleitkomma-->Integerproc fftoilink ix,0 ; Stackrahmen aufbauenpush af ; Register rettenpush hlld d,(ix+Op2) ; Operand in Register ladenld bc,(ix+Op2+1) ; Reihenfolge: EBCDld e,(ix+Op2+3) ; erspart spaeter Vertauschungenld h,e ; Vorzeichen in H, Bit 7ld a,e ; Exponent in A aufbauensla b ; LSB aus B holenrlascf ; impl. Eins einschiebenrr bsub a,Biasld l,a ; Exponent nach L kopierenjp m,Zero ; falls keiner Null, Ergebnis Nullld a,30cp a,l ; groesser 30 ?jr c,Over ; dann Ueberlaufld e,0 ; Zahl jetzt in BCDE in der Forminc a ; 1fff ... ffff 0000 0000Shift: srl b ; jetzt Mantisse verschiebenrr crr drr einc lcp a,l ; bis Exponent stimmtjr nz,Shiftbit 7,h ; Zahl negativ ?jr z,ItofResult ; nein, fertigld hl,de ; Zahl negierenxor hl,-1ld de,hlld hl,bcxor hl,-1ld bc,hlinc dejr nz,ItofResultinc bcjr nz,ItofResultZero: ld bc,0ld de,bcjp ItofResult ; Ergebnis NullOver: bit 7,h ; Ergebnis positiv ?jr z,OpPosld b,80h ; MININT ladenxor a,a ; A=0ld c,ald d,ald e,ajp ItofResultOpPos: ld b,7fh ; MAXINT ladenld a,0ffhld c,ald d,ald e,ajp ItofResultendp;------------------------------------------------------------------------------; Multiplikation mit Zweierpotenz (in A)proc fmul2link ix,0 ; Stackrahmen aufbauenpush af ; Register rettenpush hlld de,(ix+Op2) ; Operand 1 in Register ladenld bc,(ix+Op2+2)ld h,a ; Operand 2 nach H kopierenld l,b ; Vorzeichen nach L, Bit 7xor a,a ; A=0cp a,b ; Operand 1 = Null ?jr nz,NoZerocp a,cjr nz,NoZerocp a,djr nz,NoZerocp a,ejr z,ZeroNoZero: sla e ; Operand 1 verschiebenrl drl crl b ; Form: eeee eeee ffff ... fff0jr z,Den ; Falls Exponent Null -->denormaladd a,h ; A=0+Hjr m,Div ; Falls Op2<0-->Divisionadd a,b ; A=Summe der Exponentenld b,a ; zurueck nach Bjr c,Over ; bei Ueberlauf-->cp a,MaxExpo ; oder genau MaxExpojr z,OverResult: sla l ; Vorzeichen in Carry schiebenrr brr crr drr e ; Ergebnis zusammensetzenZero: pop hl ; Register zurueckpop afunlk ix ; Stackrahmen abbauenretd 4 ; EndeOver: ld b,MaxExpo ; Ueberlauf: Exponent=MaxExpoxor a,a ; Mantisse=0ld c,ald d,ald e,ajr ResultDiv: add a,b ; A = Summe der Exponentenld b,a ; zurueck nach Bjr z,Div2jr p,Result ; falls >0, Ergebnis abliefernDiv2: scf ; implizite Eins real machenrr crr drr e ; Form: eeee eeee 1fff ... ffffDenorm: xor a,a ; A = 0cp a,b ; Exponent Null ?jr z,Result ; ja, ergebnis abliefernsrl crr drr e ; Mantisse denormalisierenjr nz,NoZero2cp a,djr nz,NoZero2cp a,cjr nz,NoZero2ld b,a ; totaler Unterlauf, Ergebnis = Nulljr ZeroNoZero2: inc b ; Exponent erhoehenjr Denorm ; weiter denormalisierenDDD: add a,b ; Summe der Exponenten bildenld b,a ; zurueck nach Bjr DenormDen: add a,h ; A=0+Hjr m,DDD ; bei Division verzweigenNoOver: sla e ; Multiplikation: Einerl d ; denormalisierte Mantisserl c ; wird wieder normalisiertjr c,Stop ; bis fuehrende Eins rausfliegtdec h ; oder Operand 2 = Nulljr nz,NoOverjr ResultStop: ld a,h ; Summe der Exponenten bildenadd a,bld b,a ; zurueck nach Bjr Resultendp;------------------------------------------------------------------------------; Quadratwurzel ziehenproc fsqrtOp equ 4 ; Lage ParameterDefLocal XRoot,4 ; IterationsvariablenDefLocal m2,4DefLocal xx2,4link ix,LocalSize ; Stackrahmen aufbauenpush af ; Register rettenpush hlpush iybit 7,(ix+Op+3) ; negatives Argument ?jp nz,DomainError ; dann Fehlerld hl,(ix+Op+2) ; Exponent isolierenand hl,07f80hjp z,Zero ; keine Behandlung denormaler Zahlenld (ix+Op+3),0 ; Mantisse isolierenand (ix+Op+2),7fhsub hl,7fh*80h ; Bias vom Exponenten entfernenld bc,hlbit 7,c ; Exponent ungerade ?res 7,cjr z,EvenExpld hl,(ix+Op) ; ja: Mantisse verdoppelnadd hl,hlld (ix+Op),hlld hl,(ix+Op+2)adc hl,hladd hl,100h-80h ; impl. Eins dazuld (ix+Op+2),hlEvenExp:sra b ; Exponent/2 mit Vorzeichenrr cld hl,7fh*80h ; Bias wieder dazuadd hl,bcld iy,hl ; Exponent in IY aufhebenld de,(ix+Op+1) ; x ausrichten (um 7 nach links)ld a,(ix+Op+3) ; oberstes Byte merkenld (ix+Op+2),de ; da wir hier eins zuviel schiebenld d,(ix+Op)ld e,0ld (ix+Op),desrla ; dieses Bit einschiebenrr (ix+Op+3)rr (ix+Op+2)rr (ix+Op+1)rr (ix+Op)ld de,0 ; vorbelegenld (ix+XRoot),deld (ix+m2),deld d,40hld (ix+XRoot+2),deld d,10hld (ix+m2+2),deLoop10: ld de,(ix+Op) ; xx2 = xld (ix+xx2),deld de,(ix+Op+2)ld (ix+xx2+2),deLoop11: ld hl,(ix+xx2) ; xx2 -= xrootsub hl,(ix+XRoot)ld (ix+xx2),hlld hl,(ix+xx2+2)sbc hl,(ix+XRoot+2)ld (ix+xx2+2),hlsrl (ix+XRoot+3) ; xroot /= 2rr (ix+XRoot+2)rr (ix+XRoot+1)rr (ix+XRoot)ld hl,(ix+xx2) ; xx2 -= m2sub hl,(ix+m2)ld (ix+xx2),hlld hl,(ix+xx2+2)sbc hl,(ix+m2+2)ld (ix+xx2+2),hljr m,DontSet1ld hl,(ix+xx2) ; x = xx2ld (ix+Op),hlld hl,(ix+xx2+2)ld (ix+Op+2),hlld hl,(ix+XRoot) ; xroot += m2or hl,(ix+m2)ld (ix+XRoot),hlld hl,(ix+XRoot+2)or hl,(ix+m2+2)ld (ix+XRoot+2),hlld hl,(ix+m2) ; m2 /= 4ld de,(ix+m2+2)rept 2srl drr err hrr lendmld (ix+m2),hlld (ix+m2+2),deor hl,dejr nz,Loop11jr IsSameDontSet1: ld hl,(ix+m2) ; m2 /= 4ld de,(ix+m2+2)rept 2srl drr err hrr lendmld (ix+m2),hlld (ix+m2+2),deor hl,dejp nz,Loop10 ; 15* abarbeiten; Bit 22..8ld hl,(ix+Op) ; 17. Iteration separatld (ix+xx2),hlld hl,(ix+Op+2)ld (ix+xx2+2),hlIsSame: ld hl,(ix+xx2)sub hl,(ix+XRoot)ld (ix+xx2),hlld hl,(ix+xx2+2)sbc hl,(ix+XRoot+2)ld (ix+xx2+2),hlld de,(ix+XRoot+2) ; mitsamt Carry...ld hl,(ix+XRoot)srl drr err hrr ljr nc,NoC1set 7,dNoC1: ld (ix+XRoot+2),hl ; auf neues Alignment umstellenld (ix+XRoot),dedecw (ix+xx2) ; Carry von 0-$4000: xx2 -= m2jr nz,NoC2decw (ix+xx2+2)NoC2: bit 7,(ix+xx2+3)jr nz,DontSet7or (ix+xx2+3),0c0h ; 0-$4000: x2 -= m2, Teil 2ld hl,(ix+xx2)ld (ix+Op),hlld hl,(ix+xx2+2)ld (ix+Op+2),hlor (ix+XRoot+1),40h; xroot += m2DontSet7: ld hl,(ix+Op) ; x auf neues Alignment umstellenld de,(ix+Op+2)ld (ix+Op),deld (ix+Op+2),hlld hl,1000h ; m2 - obere Haelfte schon 0ld (ix+m2),hlLoop20: ld hl,(ix+Op) ; xx2 = xld (ix+xx2),hlld hl,(ix+Op+2)ld (ix+xx2+2),hlLoop21: ld hl,(ix+xx2) ; xx2 -= xrootsub hl,(ix+XRoot)ld (ix+xx2),hlld hl,(ix+xx2+2)sbc hl,(ix+XRoot+2)ld (ix+xx2+2),hlsrl (ix+XRoot+3) ; XRoot = XRoot/2rr (ix+XRoot+2)rr (ix+XRoot+1)rr (ix+XRoot)ld hl,(ix+xx2) ; x2 -= m2sub hl,(ix+m2)ld (ix+xx2),hlld hl,(ix+xx2+2)sbc hl,(ix+m2+2)ld (ix+xx2+2),hljr m,DontSet2ld hl,(ix+xx2) ; x = xx2ld (ix+Op),hlld hl,(ix+xx2+2)ld (ix+Op+2),hlld hl,(ix+XRoot) ; xroot += m2or hl,(ix+m2)ld (ix+XRoot),hlld hl,(ix+XRoot+2)or hl,(ix+m2+2)ld (ix+XRoot+2),hlld hl,(ix+m2) ; m2 /= 4ld de,(ix+m2+2)rept 2srl drr err hrr lendmld (ix+m2),hlld (ix+m2+2),deor hl,dejr nz,Loop21jr FinishDontSet2: ld hl,(ix+m2) ; m2 /= 4ld de,(ix+m2+2)rept 2srl drr err hrr lendmld (ix+m2),hlld (ix+m2+2),deor hl,dejp nz,Loop20 ; 7* abarbeitenFinish: ld hl,(ix+Op) ; Aufrunden notwendig ?sub hl,(ix+XRoot)ld (ix+Op),hlld hl,(ix+Op+2)sub hl,(ix+XRoot+2)ld (ix+Op+2),hljr ule,NoIncincw (ix+XRoot) ; wenn ja, durchfuehrenjr nz,NoIncincw (ix+XRoot)NoInc: res 7,(ix+XRoot+2) ; impl. Eins loeschenld hl,(ix+XRoot+2) ; Exponent einbauenor hl,iyld bc,hl ; Ergebnis in BC-DEld de,(ix+XRoot)jr EndDomainError: ld bc,0ffc0h ; - NAN zuueckgebenld de,0jr EndZero: ld bc,0 ; Ergebnis 0ld de,bcEnd: pop iy ; Register zurueckpop hlpop afunlk ix ; Stackrahmen abbauenretd 4 ; Endeendp;------------------------------------------------------------------------------; Zehnerpotenz bildensubproc fPot10push ix ; Register rettenpush iypush hlld bc,(One+2) ; Ausgangspunkt fuers Multiplizierenld de,(One)ld ix,(Ten+2) ; zu benutzende Potenzld iy,(Ten)or hl,hl ; negative Potenz?jr p,IsPosld ix,(Tenth+2) ; dann eben mit Zehntelld iy,(Tenth)xor hl,-1 ; Zweierkomplementinc hlIsPos:or hl,hl ; weiter multiplizieren ?jr z,End ; nein, Endebit 0,l ; Restpotenz ungerade ?jr z,IsEvenpush bc ; ja: einzeln multiplizierenpush depush ixpush iycall fmulIsEven: srl hrr lpush bc ; naechste Potenz berechnenpush depush ix ; durch quadrierenpush iypush ixpush iycall fmulld ix,bcld iy,depop depop bcjr IsPos ; weitersuchenEnd:pop hl ; Register zurueckpop iypop ixret ; Endeendp;------------------------------------------------------------------------------subproc fOutDecOp equ 6 ; Adresse OperandFormat equ 4 ; FormatdeskriptorDefLocal Temp,4 ; 64-Bit-Erweiterung Dividentlink ix,LocalSizepush af ; Register rettenpush bcpush depush hlbit 7,(ix+Op+3) ; negativ ?jr z,IsPosld (iy),'-' ; ja: vermerken...inc iyld hl,(ix+Op) ; ...und Zweierkomplementxor hl,-1ld (ix+Op),hlld hl,(ix+Op+2)xor hl,-1ld (ix+Op+2),hlincw (ix+Op)jr nz,GoOnincw (ix+Op+2)jr GoOnIsPos: bit 7,(ix+Format+1) ; Pluszeichen ausgeben ?jr nz,GoOnld (iy),'+'inc iyGoOn: res 7,(ix+Format+1) ; Plusflag loeschenld de,0 ; Nullflag & Zaehler loeschenInLoop: ld hl,0 ; Division vorbereitenld (ix+Temp),hl ; dazu auf 64 Bit erweiternld (ix+Temp+2),hlld b,32 ; 32-Bit-DivisionDivLoop: sll (ix+Op) ; eins weiterschiebenrl (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 nachherld hl,(ix+Temp) ; probeweise abziehensub hl,10ld (ix+Temp),hlld hl,(ix+Temp+2)sbc hl,0ld (ix+Temp+2),hljr nc,DivOK ; passt es ?ld hl,(ix+Temp) ; nein, zuruecknehmenadd hl,10ld (ix+Temp),hlld hl,(ix+Temp+2)adc hl,0ld (ix+Temp+2),hlscf ; ins Ergebnis 0 einschiebenDivOK: ccf ; neues Ergebnisbitrl (ix+Op) ; von unten einschiebendjnz DivLoopld a,(ix+Temp) ; ASCII-Offset addierenadd a,'0'bit 0,d ; schon im Nullbereich ?jr z,NormValld a,(ix+Format) ; ja, dann gewuenschtes LeerzeichenNormVal: push af ; auf LIFO legeninc e ; ein Zeichen mehrld 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 Nulljr nz,InLoop ; falls <>0, auf jeden Fall weiterld d,0ffh ; Flag auf True setzenld a,e ; ansonsten nur weiter, falls minimalecp a,(ix+Format+1) ; Zahl noch nicht erreichtjr ult,InLoopld b,e ; jetzt Zeichen ausgebenOutLoop: pop afld (iy),ainc iydjnz OutLooppop hl ; Register zurueckpop depop bcpop afunlk ixretd 6endp;------------------------------------------------------------------------------; Wandlung Float-->ASCIIproc fftoaOp equ 8 ; Lage Eingabe auf StackFormat equ 6 ; Lage Formatdeskriptor auf StackBuffer equ 4 ; PufferadresseDefLocal Copy,4 ; Temporaerkopie der ZahlDefLocal ExpSave,2 ; berechneter Exponentlink ix,LocalSize ; Platz fuer Exponenten/Kopie der Zahlpush af ; Register rettenpush depush iypush hlld iy,(ix+Buffer) ; Pufferadresse holenld hl,(ix+Op) ; Zahl kopierenld (ix+Copy),hlld hl,(ix+Op+2)res 7,h ; dabei Vorzeichen loeschenld (ix+Copy+2),hlld a,'+' ; Annahme positivsll (ix+Op) ; Vorzeichen herausschiebenrl (ix+Op+1) ; und in Carry bringenrl (ix+Op+2)rl (ix+Op+3)jr c,IsNeg ; Minuszeichen immer erforderlichbit 0,(ix+Format+1) ; Pluszeichen dagegen optionaljr nz,NoMantSgnjr WrMantSgnIsNeg: ld a,'-' ; negative ZahlWrMantSgn: ld (iy),a ; Vorzeichen ablegeninc iyNoMantSgn:ld l,(ix+Op+3) ; Exponent herausholen...ld h,0 ; ...auf 16 Bit erweitern...ld bc,(ix+Op+1) ; ...und in Quelle loeschenld (ix+Op+2),bcld b,(ix+Op)ld c,0ld (ix+Op),bccp hl,MaxExpo ; Sonderwerte ?jp z,SpecialVals ; ja-->or hl,hl ; Zahl denormal ?jr nz,IsNormal ; nein, normal weiterld a,(ix+Op+3) ; falls Mantisse Null,or a,(ix+Op+2) ; nicht normalisierenor a,(ix+Op+1)jr z,IsNullNormalize: sll (ix+Op+1) ; ansonsten schieben, bis fuehrenderl (ix+Op+2) ; Eins darl (ix+Op+3)jr c,IsNormaldec hljr NormalizeIsNormal: sub hl,Bias ; Bias abziehenIsNull:ld b,h ; Zweierexponenten in Float wandelnld c,hpush bcpush hlcall fitofpush bc ; in Dezimalexponenten wandelnpush decpsh bc,Ld10call fdivbit 7,b ; Zahl negativ ?jr z,NoCorrpush bc ; dann noch eins abziehen wegenpush de ; unterer Gaussklammercpsh bc,Onecall fsubNoCorr: push bc ; den Ausflug in Float beendenpush decall fftoild (ix+ExpSave),de ; Exponenten rettenld bc,(ix+Copy+2) ; Originalzahlpush bcld bc,(ix+Copy)push bcld hl,de ; durch die Zehnerpotenzcall fPot10 ; des Exponentenpush bcpush decall fdiv ; teilenAgain: ld (ix+Copy),de ; Ergebnis zwischen 1...9,999 rettenld (ix+Copy+2),bcpush bc ; Vorkommastelle berechnenpush decall fftoicp e,10 ; doch etwas drueber ?jr ult,NoRoundErrld bc,(ix+Copy+2) ; dann nocheinmal zehntelnpush bcld bc,(ix+Copy)push bccpsh bc,Tenthcall fmulincw (ix+ExpSave)jr AgainNoRoundErr: add e,'0' ; Vorkommastelle nach ASCIIld (iy),e ; ablegeninc iysub e,'0' ; wieder rueckgaengig machencp (ix+Format),0 ; gar keine Nachkommastellen ?jr eq,NoCommald (iy),'.' ; Dezimalpunkt ausgebeninc iypush bc ; Vorkomma nach Float wandelnpush decall fitofpush bcpush decpsh bc,ix+Copy ; von alter Zahl abziehencall fsubxor b,80h ; war verkehrtherumpush bc ; zum Skalieren auf Stackpush deld l,(ix+Format) ; passende Skalierungskonstante ausrechnenld h,0call fPot10push bcpush decall fmul ; hochskalierenpush bc ; Rundungpush decpsh bc,Halfcall faddpush bc ; Stellen nach Integerpush decall fftoipush bc ; entspr. ausgebenpush deld b,(ix+Format) ; Format fuer fOutDec aufbauenset 7,b ; kein Pluszeichenld c,'0' ; Fuellzeichen Nullenpush bccall fOutDecbit 5,(ix+Format+1) ; Nullen am Ende abraeumen ?jr nz,CleanZerosNoComma:ld a,(ix+Format+1) ; falls Minimalstellenzahl Exponent=0and a,00011100b ; und Exponent=0, vergessenor a,(ix+ExpSave)or a,(ix+ExpSave+1)jr z,Endld (iy),'E' ; Exponenten ausgebeninc iyld hl,(ix+ExpSave)ld b,hld c,hpush bcpush hlld c,'0' ; evtl. vornullenld b,(ix+Format+1)rrc b ; Bit 1-->Bit 7rrc band b,87hpush bccall fOutDecEnd: ld (iy),0 ; NUL-Zeichen als Terminiererld de,iy ; Endezeiger nach DEpop hl ; Register zurueckpop iyex de,hl ; zur Subtraktion tauschensub hl,de ; = Zahl geschriebener Zeichenex de,hl ; HL wieder originalld bc,de ; Ergebnis nach BCpop depop afunlk ix ; Stackrahmen abbauenretd 8 ; EndeSpecialVals: ld a,(ix+Op+3) ; Mantisse Null ?or a,(ix+Op+2)or a,(ix+Op+1)jr nz,IsNANld (iy),'I' ; ja: Unendlichkeitld (iy+1),'N'ld (iy+2),'F'add iy,3jr EndIsNAN: ld (iy),'N' ; nein: NANld (iy+1),'A'ld (iy+2),'N'add iy,3jr EndCleanZeros: cp (iy-1),'0' ; Null am Ende ?jr nz,CleanNoZero ; nein, Endedec iy ; ja: Zaehler runter, so dass ueber-jr CleanZeros ; schrieben wird und neuer VersuchCleanNoZero: cp (iy-1),'.' ; evtl. Komma entfernbar ?jr nz,Ready ; nein-->dec iy ; ja: noch ein Zeichen wenigerReady: jrl NoCommaendp;------------------------------------------------------------------------------; Wandlung ASCII-->Floatproc fatofSrcAddr equ 4 ; Lage Parameter auf StackDefLocal Flags,2 ; SteuerflagsDefLocal Exp,2 ; Speicher ExponentDefLocal Mant,4 ; Speicher fuer MantissenzwischenwertDefLocal Factor,4 ; Speicher fuer Zehnerpotenzlink ix,LocalSize ; Stackrahmen aufbauenpush af ; Register rettenpush hlpush iyld iy,(ix+SrcAddr) ; Zeigeradresse ladenld (ix+Flags),01h ; Phase 1 (Mantisse), noch kein Vorzeichenld (ix+Flags+1),0ld bc,(Ten) ; in der Mantisse mit 10 hochmultiplizierenld (ix+Factor),bcld bc,(Ten+2)ld (ix+Factor+2),bcld bc,0 ; Exponent mit 0 vorbelegenld (ix+Exp),bcld (ix+Mant),bc ; Mantisse auchld (ix+Mant+2),bcReadLoop: ld a,(iy) ; ein neues Zeichen holeninc iycp a,0 ; Endezeichen ?jp eq,Combine ; ja, zusammenbauencp a,' ' ; Leerzeichen ignorierenjr eq,ReadLoopcp a,'+' ; Pluszeichen gnadenhalber zulassenjr ne,NoPlus ; ist aber nur ein Dummybit 0,(ix+Flags+1) ; schon ein Vorzeichen dagewesen ?jp nz,Error ; dann Fehlerset 0,(ix+Flags+1) ; ansonsten einfach setzenjr ReadLoopNoPlus:cp a,'-' ; Minuszeichen bewirkt schon eher etwasjr ne,NoMinusbit 0,(ix+Flags+1) ; darf auch nur einmal auftretenjp nz,Errorset 0,(ix+Flags+1)cp (ix+Flags),1 ; je nach Phase anderes Flag setzenjr ne,MinPhase3set 1,(ix+Flags+1) ; bei Mantisse Bit 1...jr ReadLoopMinPhase3: set 2,(ix+Flags+1) ; ...bei Exponent Bit 2jr ReadLoopNoMinus:cp a,'.' ; Umschaltung Phase 2 (Nachkomma) ?jr ne,NoPointcp (ix+Flags),1 ; bish. Phase muss Eins seinjp ne,Errorld (ix+Flags),2 ; neue Phase eintragenset 0,(ix+Flags+1) ; Nachkomma darf kein Vorzeichen habenld bc,(Tenth) ; im Nachkomma durch 10 teilenld (ix+Factor),bcld bc,(Tenth+2)ld (ix+Factor+2),bcjr ReadLoopNoPoint:cp a,'e' ; kleines & grosses E zulassenjr eq,IsEcp a,'E'jr ne,NoEIsE: cp (ix+Flags),3 ; vorh. Phase muss 1 oder 2 seinjp eq,Errorld (ix+Flags),3 ; vermerkenres 0,(ix+Flags+1) ; Vorzeichen wieder zulassenjr ReadLoopNoE:sub a,'0' ; jetzt nur noch 0..9 zugelassenjp c,Errorcp a,9jp ugt,Errorset 0,(ix+Flags+1) ; nach Ziffern keine Vorzeichen mehr zulassencp (ix+Flags),1 ; Phase 1 (Mantisse) :jr ne,NoPhase1cpsh bc,ix+Mant ; bish. Mantisse * 10cpsh bc,ix+Factorcall fmulpush bc ; Ziffer dazuaddierenpush deld e,ald d,0ld bc,0push bcpush decall fitofpush bcpush decall faddld (ix+Mant),de ; Mantisse zuruecklegenld (ix+Mant+2),bcjrl ReadLoopNoPhase1:cp (ix+Flags),2 ; Phase 2 (Nachkomma) :jr nz,NoPhase2ld e,a ; Stelle nach Floatld d,0ld bc,0push bcpush decall fitofpush bc ; mit Zehnerpotenz skalierenpush decpsh bc,ix+Factorcall fmulpush bc ; zur Mantisse addierenpush decpsh bc,ix+Mantcall faddld (ix+Mant),de ; Mantisse zuruecklegenld (ix+Mant+2),bccpsh bc,ix+Factor ; Faktor * 1/10cpsh bc,Tenthcall fmulld (ix+Factor),deld (ix+Factor+2),bcjrl ReadLoopNoPhase2:ld hl,(ix+Exp)mul hl,10 ; Exponent heraufmultiplizierenadd a,lld l,ald a,0adc h,0cp hl,45 ; Minimum ist 1E-45jr ugt,Errorld (ix+Exp),hljrl ReadLoopCombine: ld hl,(ix+Exp)bit 2,(ix+Flags+1) ; Exponent negativ ?jr z,ExpPosxor hl,-1inc hlExpPos: call fPot10 ; Zehnerpotenz des Exponenten bildenpush bcpush decpsh bc,ix+Mant ; mit Mantisse kombinierencall fmulbit 1,(ix+Flags+1) ; Mantisse negativ ?jr z,ManPosset 7,bManPos: rcf ; Ende ohne FehlerEnd: pop iy ; Register zurueckpop hlpop afunlk ix ; Rahmen abbauenretd 2 ; EndeError: ld hl,iy ; rel. Zeichenposition ermittelnsub hl,(ix+SrcAddr)ld bc,hlscf ; Ende mit Fehlerjr Endendp;------------------------------------------------------------------------------; gemeinsames Endeendsection