Blame | Last modification | View Log | Download | RSS feed
; FLOAT.I68;-----------------------------------------------------------------------------; Fliesskommaroutinen fuer den PC-PAR 68000, Version ohne 68881; entnommen mc 11/88, c't...;-----------------------------------------------------------------------------; Definitionenvorz equ 0subflag equ 1maxexpo equ 255bias equ 127extend equ $10e equ $402df854 ; exp(1)ln2 equ $3f317218 ; ln(2)ln10 equ $40135d8e ; ln(10)eins equ $3f800000 ; 1.0zwei equ $40000000 ; 2.0pi2 equ $40c90fdb ; Pi*2pi equ $40490fdb ; Pipihalf equ $3fc90fdb ; Pi/2;-----------------------------------------------------------------------------; Librarykopf:S_FloatLib: dc.l S_floatlibend-S_floatlibstart ; LaengeS_floatlibstart:dc.l -1 ; Speicher fuer Zeigerdc.b "FLOAT",0 ; Nameds 0;-----------------------------------------------------------------------------; Sprungtabelle:bra.l S_faddbra.l S_fsubbra.l S_fmulbra.l S_fdivbra.l S_fmul2bra.l S_fsqrtbra.l S_fabsbra.l S_floatlibnopbra.l S_fcmpbra.l S_fitofbra.l S_fftoibra.l S_floatlibnopbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_fexpbra.l S_fsinhbra.l S_fcoshbra.l S_ftanhbra.l S_fcothbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_flnbra.l S_flogbra.l S_fasinhbra.l S_facoshbra.l S_fatanhbra.l S_facothbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_fsinbra.l S_fcosbra.l S_ftanbra.l S_fcotbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_floatlibnopbra.l S_fasinbra.l S_facosbra.l S_fatanbra.l S_facot;-----------------------------------------------------------------------------; Konstanten :S_Const1 dc.s 1.0;-----------------------------------------------------------------------------; Nullprozedur :S_floatlibnop: rts;-----------------------------------------------------------------------------; Addition : D0.S = D0.S + D1.Sds 0S_fadd:addq.l #1,_fadd_cnt.wmovem.l d1-d5,-(a7) ; benoetigte Register rettenrol.l #1,d0 ; Operanden rotieren und in Formrol.l #1,d1 ; eeee eeee ffff ... fffs bringenmove.l d0,d2sub.l d1,d2 ; Differenz beider Zahlen bildenbcc.s fadd_1exg d0,d1 ; ggf. vertauschen, so dass derfadd_1: move.b d0,d3 ; kleinere in Register D1 stehtand.b #1,d3 ; maskiere das Vorzeichenbitbtst #vorz,d2 ; haben beide gleiches Vorzeichen ?beq.s fadd_2 ; bei verschiedenen Vorzeichenbset #subflag,d3 ; Flag fuer Subtraktion setzenfadd_2: rol.l #8,d0 ; Form: ffff ... fffs eeee eeeeclr.w d4 ; Exponent der ersten Zahlmove.b d0,d4 ; wird im Register D4 aufgebautsne d0 ; falls ungleich Null, dannror.l #1,d0 ; implizite Eins, sonst impliziteclr.b d0 ; Null erzeugen, neu positionierenrol.l #8,d1 ; jetzt das gleiche fuer denclr.w d5 ; zweiten Operanden, der Exponentmove.b d1,d5 ; kommt ins Register D5sne d1ror.l #1,d1clr.b d1; In den Registern D0 und D1 stehen jetzt nur noch die Mantissen; im Format ffff ... ffff 0000 0000, also linksbuendig, wobei die; ehemals implizite Null bzw. Eins nun explizit an erster Stelle steht.; In den Registern D4 und D5 stehen die Exponenten der beiden Zahlen.; Das Vorzeichen des Ergebnisses sowie die Subtraktionsflags sind im; Register D3 zwischengespeichert.move.w d4,d2 ; Jetzt Differenz der Exponentensub.w d5,d2 ; berechnencmp.w #24,d2 ; groesser als 24 ?bgt.s fadd_rnd ; ja, --> Ergebnis ist groessere Zahllsr.l d2,d1 ; Mantisse um (D2)-Bits verschiebenbtst #subflag,d3 ; Subtraktion oder Addition ?bne.s fadd_subtr ; ggf. zur Subtraktion springenadd.l d1,d0 ; die beiden Mantissen addierenbcc.s fadd_rnd ; kein Ueberlauf --> zum Rundenroxr.l #1,d0 ; Ueberlauf einschiebenaddq.w #1,d4 ; Exponent korrigierenbra.s fadd_rnd ; und zum Rundenfadd_subtr: sub.l d1,d0 ; die beiden Mantissen subtrahierenbeq.s fadd_zero ; bei Null ist das Gesamtergebnis Nullbmi.s fadd_rnd ; bei fuehrender Eins zum Rundenfadd_nrm: tst.w d4 ; Exponent ist schon Null ?beq.s fadd_rnd ; dann ist Ergebnis denormalisiertsubq.w #1,d4 ; Exponent erniedrigenlsl.l #1,d0 ; Mantisse normalisieren bisbpl.s fadd_nrm ; fuehrende Eins auftauchtfadd_rnd: add.l #$80,d0 ; jetzt Runden auf Bit hinterbcc.s fadd_nov ; Mantisseroxr.l #1,d0 ; bei Ueberlauf Mantisse normalisierenaddq.w #1,d4 ; und Exponent korrigierenfadd_nov: clr.b d0 ; Rest-Mantisse loeschentst.l d0 ; Ist die Mantisse komplett Null ?beq.s fadd_zero ; ja, dann ist Ergebnis auch Nullcmp.w #maxexpo,d4 ; Exponent-Ueberlauf ?blt.s fadd_nuemove.w #maxexpo,d4 ; Unendlich Exponent = maxexpoclr.l d0 ; Mantisse = Nullbra.s fadd_denfadd_nue: tst.w d4 ; Exponent Null ( Zahl denormalisiert? )beq.s fadd_den ; ja -->lsl.l #1,d0 ; fuehrendes Bit wird nicht gespeichertfadd_den: move.b d4,d0 ; Exponent einsetzenror.l #8,d0 ; Form: eeee eeee ffff ... fffxroxr.b #1,d3 ; Vorzeichen in Carry schiebenroxr.l #1,d0 ; Form: seee eeee efff ... fffffadd_zero:movem.l (a7)+,d1-d5 ; Register restaurierenrts ; Ende, Ergebnis steht in D0.L;-----------------------------------------------------------------------------; Subtraktion : D0.S = D0.S - D1.Sds 0S_fsub:bchg #31,d1 ; Vorzeichen des zweiten Operandenbra S_fadd ; invertieren und zur Addition springen;-----------------------------------------------------------------------------; Multiplikation : D0.S = D0.S * D1.Sds 0S_fmul:addq.l #1,_fmul_cnt.wmovem.l d1-d5,-(a7) ; benoetigte Register rettenmove.l d0,d2 ; Operand 1 kopiereneor.l d1,d2 ; EXOR um Vorzeichen zu bestimmenswap d0 ; Registerhaelften Operand 1 vertauschenmove.l d0,d3 ; Operand 1 ab jetzt in Register D3and.w #$7f,d3 ; Exponent und Vorzeichen loeschenand.w #$7f80,d0 ; Exponent maskierenbeq.s fmul_dn1 ; gleich Null: Zahl ist denormalisiertbset #7,d3 ; implizite Eins einsetzensub.w #$0080,d0 ; Bias kompensierenfmul_dn1: swap d1 ; jetzt Operand 2 behandelnmove.w d1,d4and.w #$7f,d1and.w #$7f80,d4beq.s fmul_dn2bset #7,d1sub.w #$0080,d4 ; Bias kompensierenfmul_dn2: add.w d0,d4 ; Exponenten addierenlsr.w #7,d4 ; richtig positionierensub.w #bias-3,d4 ; Bias-3 subtrahierencmp.w #-24,d4 ; totaler Unterlauf ?blt.s fmul_zero ; ja, dann ist Ergebnis Nullmove.w d3,d0 ; oberes Mantissenwort von Operand 1mulu d1,d0 ; mal oberem Mantissenwort von Op2swap d0 ; entspricht Verschiebung um 16 Bit; Das obere Wort von D0 ist nach der Multiplikation auf jeden Fall Null,; da die oberen Mantissenworte nur im Bereich 0 ... 255 liegen.; Das groete moegliche Ergebnis ist also 255 x 255 = 65025 = 0000FE01.; Nach der Vertauschung erhalten wir also eine Zahl der xxxx 0000.; Die untere Registerhaelfte von D0 koennen wir kurzzeitig als Zwischen-; speicher verwenden.move.w d3,d0 ; oberes Wort von Operand 1 merkenswap d3 ; jetzt unteres Wort Op1 mal oberes Op2move.w d1,d5mulu d3,d5 ; Ergebnis steht im D5swap d1 ; jetzt unteres Wort Op1 mal unteres Op2mulu d1,d3 ; Ergebnis steht im D3swap d3 ; entspricht Verschiebung um 16 Bitmulu d0,d1 ; jetzt oberes Wort Op1 mal unteres Op2move.w d3,d0 ; zum ersten Zwischenergebnis dazuadd.l d5,d0 ; jetzt alles aufaddierenadd.l d1,d0beq.s fmul_res ; falls Mantisse Null auch Ergebnis Nullbmi.s fmul_rnd ; fuehrende Eins? dann zum Runden; Im Register D0.L befinden sich die oberen 32 Bit des Produktes,; im oberen Wort von D3 die restlichen 16 Bit.tst.w d4 ; Exponent ist negativ ?bmi.s fmul_unt ; ggf. Unterlauf behandelnfmul_nor: tst.w d4 ; Exponent = Null ?beq.s fmul_rnd ; falls Null, dann zum Rundenroxl.l #1,d3 ; Im oberen Wort von D3 sind dieroxl.l #1,d0 ; niedrigsten Bits des Produktessubq.w #1,d4 ; Exponent korrigierentst.l d0 ; Mantisse testenbpl.s fmul_nor ; bis fuehrende Eins auftauchtfmul_rnd: add.l #$80,d0 ; Rundungbcc.s fmul_novroxr.l #1,d0 ; Ueberlauf einschiebenaddq.w #1,d4 ; Exponent korrigierenfmul_nov: cmp.w #maxexpo,d4 ; Exponent-Ueberlauf ?blt.s fmul_nuefdiv_err: move.w #maxexpo,d4 ; Ueberlauf: Exponent = Maxexpoclr.l d0 ; Mantisse = Nullbra.s fmul_denfmul_nue: tst.w d4 ; Exponent = Null ?beq.s fmul_den ; falls Null, dann denormalisiertlsl.l #1,d0 ; fuehrende Eins wird nicht abgespeichertfmul_den: move.b d4,d0 ; Exponent einsetzenror.l #8,d0 ; Form: eeee eeee ffff ... fffxroxl.l #1,d2 ; Vorzeichen in Carry schiebenroxr.l #1,d0 ; und ins Ergebnis einsetzenfmul_res: movem.l (a7)+,d1-d5 ; Register restaurierenrtsfmul_zero: clr.l d0 ; Null erzeugenbra.s fmul_res ; Ende, Ergebnis steht in D0.Lfmul_unt: cmp.w #-24,d4 ; totaler Unterlauf ?ble.s fmul_zero ; Dann ist das Ergebnis auf jeden Fall Nullneg.w d4 ; sonst Shift-Zaehler erzeugenlsr.l d4,d0 ; und Zahl denormalisierenclr.w d4 ; Exponent ist Null als Kennzeichenbra.s fmul_rnd ; fuer eine denormalisierte Zahl;-----------------------------------------------------------------------------; Division : D0.S = D0.S / D1.Sds 0S_fdiv:addq.l #1,_fdiv_cnt.wmovem.l d1-d5,-(a7) ; benoetigte Register rettenmove.l d0,d2 ; Operand 1 kopiereneor.l d1,d2 ; EXOR um Vorzeichen zu bestimmenswap d0 ; Registerhaelften Operand 1 vertauschenmove.l d0,d3 ; Operand 1 ab jetzt in Register D3and.w #$7f,d3 ; Exponent und Vorzeichen loeschenand.w #$7f80,d0 ; Exponent maskierenbeq.s fdiv_dn1 ; gleich Null: Zahl ist denormalisiertbset #7,d3 ; implizite Eins einsetzensub.w #$0080,d0 ; Bias kompensierenfdiv_dn1: swap d1 ; jetzt Operand 2 behandelnmove.w d1,d4and.w #$7f,d1and.w #$7f80,d4beq.s fdiv_dn2bset #7,d1sub.w #$0080,d4fdiv_dn2: sub.w d4,d0 ; Exponenten subtrahierenmove.w d0,d4 ; Exponent nach D4 kopierenasr.w #7,d4 ; richtig positionierenadd.w #bias,d4 ; Bias addierencmp.w #-24,d4 ; totaler Ueberlauf ?blt.s fmul_zero ; ja, dann ist Ergebnis Nullswap d1 ; Form: 0fff ... ffff 0000 0000beq.s fdiv_err ; falls Divisor Null, dann wirdlsl.l #7,d1 ; als Ergebnis unendlich ausgegebenswap d3beq.s fmul_zero ; falls Divident Null --> Ergebnis Nulllsl.l #7,d3fdiv_nlp: btst #30,d1 ; ist der Divisor normalisiert ?bne.s fdiv_nor ; ja, -->addq.w #1,d4 ; nein, Exponent erhoehenlsl.l #1,d1 ; Divisor verschieben bis Form 01ff ..bra.s fdiv_nlpfdiv_nor: clr.l d0 ; Ergebnis vorbesetzenadd.w #25,d4 ; Exponent ist nicht groesser als Nullfdiv_lop: move.l d3,d5 ; Divident zwischenspeichernsub.l d1,d3 ; Divisor abzieheneori #extend,ccr ; X-Bit invertierenbcc.s fdiv_one ; kein Carry: Divisor passtmove.l d5,d3 ; zurueckkopieren (X-Bit unveraendert!)fdiv_one: roxl.l #1,d0 ; Ergebnis aufbauenlsl.l #1,d3 ; Divident verschiebensubq.w #1,d4 ; Exponent erniedrigenbeq.s fdiv_den ; falls Null, dann denormalisiertbtst #24,d0 ; fuehrende Eins in Ergebnis-Mantisse?beq.s fdiv_lop ; nein, weiter rechnenfdiv_den: lsl.l #7,d0 ; Mantisse positionierenbeq fmul_res ; Null ?bra fmul_rnd ; zum Runden;-----------------------------------------------------------------------------; Multiplikation mit einer Zweierpotenz: D0.S=D0.S * 2^(D1.W)ds 0S_fmul2:addq.l #1,_fmul_cnt.wmovem.l d1-d2,-(a7) ; Register rettenmove.l d0,d2 ; Vorzeichen in D2 Bit 31 merkenlsl.l #1,d0 ; Vorzeichen rausschiebenbeq.s fmul2_zero ; falls Null, dann ist Ergebnis Nullrol.l #8,d0 ; Form: ffff ... fff0 eeee eeeeclr.w d2 ; auf Wort vorbereitenmove.b d0,d2 ; Exponent in D2beq.s fmul2_dentst.w d1 ; Multiplikation oder Division?bmi.s fmul2_div ; (neg. Exponent entspr. Div.)add.w d1,d2 ; Summe der Exponenten bildencmp.w #maxexpo,d2 ; Ueberlauf?bge.s fmul2_over ; ja, Ergebnis ist unendlichfmul2_res: move.b d2,d0 ; Ergebnisexponent einsetzenror.l #8,d0 ; Form: eeee eeee ffff ... fffxroxl.l #1,d2 ; Vorzeichen ins X-Bitroxr.l #1,d0 ; und ins Ergebnis einschiebenfmul2_zero: movem.l (a7)+,d1-d2 ; Register restaurierenrtsfmul2_over: move.w #maxexpo,d2 ; Unendlich: Exponent = maxexpoclr.l d0 ; Mantisse = Nullbra.s fmul2_resfmul2_div: add.w d1,d2 ; Summe der Exponenten bildenbgt.s fmul2_res ; Unterlauf? nein --> Ergebnisori #Extend,ccr ; implizite Eins real machenroxr.l #1,d0 ; Form: 1fff ... ffff xxxx xxxxfmul2_dnr: tst.w d2 ; Exponent = Null ?beq.s fmul2_res ; ja, Ergebnis ist denormalisiertlsr.l #1,d0 ; Mantisse denormalisierenbeq.s fmul2_zero ; totaler Unterlauf: Ergebnis ist Nulladdq.w #1,d2 ; Exponent korrigierenbra.s fmul2_dnrfmul2_ddd: add.w d1,d2 ; Summe der Exponenten bildenbra.s fmul2_dnr ; mit denormalisiereter Eingabe bearbeitenfmul2_den: tst.w d1 ; Multiplikation oder Divisionbmi.s fmul2_dddclr.b d0 ; Form: ffff ... fff0 0000 0000fmul2_nor: lsl.l #1,d0 ; Mantisse nach links schiebenbcs.s fmul2_stp ; bis fuehrende Eins auftauchtsubq.w #1,d1 ; oder zweiter Exponent Null wirdbne.s fmul2_norbra.s fmul2_res ; Ergebnis abliefernfmul2_stp: add.w d1,d2 ; Rest zum Exponenten addierenbra.s fmul2_res ; Bias stimmt auch ( jetzt 127 statt 126);-----------------------------------------------------------------------------; Vergleich zweier Zahlen: cmp d0,d1S_fcmp:bclr #31,d0 ; Zahl 1 >=0 ?bne.s fcmp_2fcmp_1:bclr #31,d1 ; Zahl 2 >=0 ?bne.s fcmp_12fcmp_11:cmp.l d1,d0 ; beide Zahlen >=0rts ; dann Betraege vergleichenfcmp_12:moveq.l #1,d0 ; Zahl 1 >=0 und Zahl 2 <0cmp.l #-1,d0rtsfcmp_2:bclr #31,d1 ; Zahl 2 >=0 ?bne.s fcmp_22fcmp_21:moveq.l #-1,d0 ; Zahl 1 <0 und Zahl 2 >=0cmp.w #1,d0 ; dann kleinerrtsfcmp_22:neg.l d0neg.l d1cmp.l d1,d0 ; beide Zahlen <0, dann ver-rts ; kehrtherum vergleichen;-----------------------------------------------------------------------------; Longint-->Gleitkomma; D0.L --> D0.SS_fitof:movem.l d1-d2,-(a7) ; Register rettentst.l d0 ; Integer ist Null ?beq.s fitof_res; Ergebnis ist auch Nullsmi d1 ; Vorzeichen in D1 merkenbpl.s fitof_posneg.l d0 ; ggf. Integer negierenfitof_pos: move.w #bias+32,d2 ; Exponent vorbesetzenfitof_shift: subq.w #1,d2 ; Mantisse verschiebenlsl.l #1,d0 ; bis fuehrende Eins rausfliegtbcc.s fitof_shiftmove.b d2,d0 ; Exponent einsetzenror.l #8,d0 ; Zahl positionierenroxr.b #1,d1 ; Vorzeichen in X-Bitroxr.l #1,d0 ; und ins Ergebnisfitof_res: movem.l (a7)+,d1-d2 ; fertigrts;-----------------------------------------------------------------------------; Gleitkomma --> Longint:; D0.S --> D0.LS_fftoi:movem.l d1-d2,-(a7) ; Register rettenroxl.l #1,d0 ; Vorzeichen in Carryscs d1 ; in D1 merkenrol.l #8,d0 ; Form: ffff ... fffx eeee eeeemove.b d0,d2 ; Exponent extrahierensub.b #bias,d2 ; Bias subtrahierenbmi.s fftoi_zero ; kleiner Null -> Ergebnis = Nullcmp.b #31,d2 ; Ueberlauf?bge.s fftoi_overori #extend,ccr ; Implizite Eins explizit machenroxr.l #1,d0clr.b d0 ; Form: 1fff ... ffff 0000 0000fftoi_shft:lsr.l #1,d0 ; jetzt Verschiebung bisaddq.b #1,d2 ; Exponent stimmtcmp.b #31,d2bne.s fftoi_shfttst.b d1 ; Zahl negativ ?bpl.s fftoi_posneg.l d0 ; ggf. Ergebnis negierenfftoi_pos:movem.l (a7)+,d1-d2 ; Register wieder holenrtsfftoi_zero:clr.l d0 ; Unterlauf; Ergebnis ist Nullbra.s fftoi_posfftoi_over:move.l #$7fffffff,d0 ; Ueberlauf: Maxint zurueckgebentst.b d1 ; positiv oder negativ ?bpl.s fftoi_posnot.l d0 ; Einser-Komplement erzeugt Minintbra.s fftoi_pos;-----------------------------------------------------------------------------; Quadratwurzel : D0.S-->D0.Sds 0fsqrt_domainerror:move.l #$ffc00000,d0 ; -NAN zurueckgebenmovem.l (a7)+,d1-d4rtsfsqrt_sq0:clr.l d0movem.l (a7)+,d1-d4rtsS_fsqrt:addq.l #1,_fsqrt_cnt.wmovem.l d1-d4,-(a7) ; D1-D4 werden sonst zerstoertmove.l d0,d4bmi.s fsqrt_domainerror ; Fehler bei negativem Argumentswap d4 ; MSW des Argumentsand.l #$7f80,d4 ; Exponent isolierenbeq.s fsqrt_sq0 ; Zahl ist 0, wenn Exponent 0and.l #$007fffff,d0 ; Mantisse isolierensub.w #$7f*$80,d4 ; Exponent im Zweierkomplementbclr #7,d4 ; Exponent ungerade? (und LSB auf 0)beq.s fsqrt_evenexpadd.l d0,d0 ; ja: Mantisse * 2add.l #$01000000-$00800000,d0 ; Hidden Bit setzen, 1.Iterationfsqrt_evenexp:; 1. Iteration fuer geraden Exponenten: Hidden Bit nicht setzenasr.w #1,d4 ; Exponent/2 mit Vorzeichenadd.w #$7f*$80,d4 ; Exponent wieder in Offset-Darst.swap d4 ; neuen Exponenten im MSW aufhebenlsl.l #7,d0 ; x ausrichtenmove.l #$40000000,d2 ; xroot nach erster Iterationmove.l #$10000000,d3 ; m2=2 << (MaxBit-1);fsqrt_loop10:move.l d0,d1 ; xx2 = xfsqrt_loop11:sub.l d2,d1 ; xx2 -= rootlsr.l #1,d2 ; xroot >>= 1sub.l d3,d1 ; x2 -= m2bmi.s fsqrt_dontset1move.l d1,d0 ; x = xx2or.l d3,d2 ; xroot += m2lsr.l #2,d3 ; m2 >>= 2bne.s fsqrt_loop11bra.s fsqrt_d0d1samefsqrt_dontset1:lsr.l #2,d3 ; m2 >>= 2bne.s fsqrt_loop10 ; Schleife 15* abarbeiten; Bit 22..8; 17. Iteration (Bit 7) mit separatem Code durchfuehren:move.l d0,d1 ; xx2 = xfsqrt_d0d1same:sub.l d2,d1 ; xx2 -= rootror.l #1,d2 ; xroot >>= 1 mitsamt Carry...swap d2 ; auf neues Alignment umstellensubq.l #1,d1 ; Carry von 0-0x4000: x2 -= m2; Teil 1bmi.s fsqrt_dontset7or.l #-$40000000,d1 ; 0 - 0x4000: x2 -= m2, Teil 2move.l d1,d0 ; x = xx2or.w #$4000,d2 ; xroot += m2fsqrt_dontset7:swap d0 ; x auf neues Alignment umstellenmove.w #$1000,d3 ; m2 - Bit 16..31 bereits 0fsqrt_loop20:move.l d0,d1 ; xx2 = xfsqrt_loop21:sub.l d2,d1 ; xx2 -= xrootlsr.l #1,d2 ; xroot >>= 1sub.l d3,d1 ; x2 -= m2bmi.s fsqrt_dontset2move.l d1,d0 ; x = xx2or.w d3,d2 ; xroot += m2lsr.w #2,d3 ; m2 >>= 2bne.s fsqrt_loop21bra.s fsqrt_finishfsqrt_dontset2:lsr.w #2,d3 ; m2 >>= 2bne.s fsqrt_loop20 ; Schleife 7 * abarbeiten (n=6..0)fsqrt_finish:sub.l d2,d0 ; Aufrunden notwendig ?bls.s fsqrt_noincaddq.l #1,d2 ; wenn ja, durchfuehrenfsqrt_noinc:bclr #23,d2 ; Hidden Bit loeschenor.l d4,d2 ; Exponent und Mantisse kombinierenmove.l d2,d0 ; Ergebnismovem.l (a7)+,d1-d4rts ; Z-,S-, und V-Flag o.k.;-----------------------------------------------------------------------------; Absolutbetrag: D0.S--> D0.Sds 0S_fabs: bclr #31,d0 ; ganz einfach...rts;-----------------------------------------------------------------------------; Exponentialfunktion: D0.S--> D0.S; Die "krummen" Konstanten legen wir als hex ab, damit es keine Vergleichs-; fehler durch Rundungsvarianzen gibt.S_fexp_Const0: dc.l $3FB8AA3B ; ld(exp(1.0)) = ld(e) = 1/ln(2)S_fexp_ConstA: dc.l $3D0DF4E0 ; 0.034657359038 PolynomkonstantenS_fexp_ConstB: dc.l $411F4606 ; 9.9545957821S_fexp_ConstC: dc.l $441A7E3A ; 617.97226953S_fexp_ConstD: dc.l $42AED5C2 ; 87.417498202ds 0S_fexp: movem.l d1-d5,-(sp)bclr #31,d0 ; Vorzeichen loeschen und nach D2 rettensne d2move.l S_fexp_Const0(pc),d1 ; auf 2erpotenz umrechnenbsr S_fmulmove.l d0,d3 ; in Ganzzahlanteil und Nach-bsr S_fftoi ; kommastellen (z) zerlegenmove.l d0,d4 ; Ganzzahlanteil nach D4bsr S_fitofmove.l d0,d1move.l d3,d0bsr S_fsubmove.l d0,d3move.l d0,d1 ; z^2 berechnenbsr S_fmulmove.l d0,d5 ; noch zu gebrauchenmove.l S_fexp_ConstD(pc),d1 ; --> D+z^2bsr S_faddmove.l d0,d1 ; --> C/(..)move.l S_fexp_ConstC(pc),d0bsr S_fdivmove.l d0,d1 ; --> B-(..)move.l S_fexp_ConstB(pc),d0bsr S_fsubmove.l d3,d1 ; --> (..)-zbsr S_fsubexg d0,d5 ; Ergebnis rettenmove.l S_fexp_ConstA(pc),d1 ; A*z^2 berechnenbsr S_fmulmove.l d5,d1 ; ergibt Nennerbsr S_faddmove.l d0,d1 ; Quotient bildenmove.l d3,d0bsr S_fdivmoveq #1,d1 ; verdoppelnbsr S_fmul2move.l S_Const1(pc),d1 ; 1 addierenbsr S_faddmove.l d4,d1 ; Potenzierenbsr S_fmul2tst.b d2 ; war Argument negativ ?beq.s S_fexp_ArgPosmove.l d0,d1 ; dann Kehrwert bildenmove.l S_Const1(pc),d0bsr S_fdivTerminate:S_fexp_ArgPos: movem.l (sp)+,d1-d5rts;------------------------------------------------------------------------------; Sinus hyperbolicus: D0.S-->D0.SS_fsinh:movem.l d1-d2,-(a7) ; Register rettenbsr S_fexp ; exp(x) berechnenmove.l d0,d2 ; in D2 merkenmove.l d0,d1 ; exp(-x)=1/exp(x) berechnenmove.l #eins,d0bsr S_fdivmove.l d0,d1 ; Teilergebnisse subtrahierenmove.l d2,d0bsr S_fsubmove.w #-1,d1 ; halbierenbsr S_fmul2movem.l (a7)+,d1-d2 ; Register zurueckrts;------------------------------------------------------------------------------; Cosinus hyperbolicus: D0.S-->D0.SS_fcosh:movem.l d1-d2,-(a7) ; Register rettenbsr S_fexp ; exp(x) berechnenmove.l d0,d2 ; in D2 merkenmove.l d0,d1 ; exp(-x)=1/exp(x) berechnenmove.l #eins,d0bsr S_fdivmove.l d2,d1 ; Teilergebnisse addierenbsr S_faddmove.w #-1,d1 ; halbierenbsr S_fmul2movem.l (a7)+,d1-d2 ; Register zurueckrts;-----------------------------------------------------------------------------; Tangens hyperbolicus: D0.S-->D0.SS_ftanh:movem.l d1-d3,-(a7) ; Register sichernbsr S_fexp ; exp(x) berechnenmove.l d0,d2 ; in D2 merkenmove.l d0,d1 ; exp(-x)=1/exp(x) berechnenmove.l #eins,d0bsr S_fdivmove.l d0,d3 ; in D3 merkenmove.l d2,d1 ; Summe=Nenner berechnenbsr S_faddexg d0,d2 ; jetzt exp(x) in D0, Nennermove.l d3,d1 ; in D2bsr S_fsub ; Zaehler berechnenmove.l d2,d1 ; Quotient berechnenbsr S_fdivmovem.l (a7)+,d1-d3 ; Register zurueckrts;-----------------------------------------------------------------------------; Cotangens hyperbolicus: D0.S-->D0.SS_fcoth:tst.l d0 ; Argument Null ?beq.s S_fcoth_valerr ; dann zur Fehlerroutinemovem.l d1-d3,-(a7) ; Register sichernbsr S_fexp ; exp(x) berechnenmove.l d0,d2 ; in D2 merkenmove.l d0,d1 ; exp(-x)=1/exp(x) berechnenmove.l #eins,d0bsr S_fdivmove.l d0,d3 ; in D3 merkenmove.l d0,d1 ; Differenz=Nenner berechnenmove.l d2,d0bsr S_fsubexg d0,d2 ; jetzt exp(x) in D0, Nennermove.l d3,d1 ; in D2bsr S_fadd ; Zaehler berechnenmove.l d2,d1 ; Quotient berechnenbsr S_fdivmovem.l (a7)+,d1-d3 ; Register zurueckrtsS_fcoth_valerr:move.l #$7f800000,d0 ; +INF zurueckgebenrts;-----------------------------------------------------------------------------; nat. Logarithmus: D0.S-->D0.Sds 0S_fln:tst.l d0 ; Argument <=0 ?ble S_fln_errvalmovem.l d1-d7,-(a7) ; Register rettenmove.l d0,d3 ; Argument sichernmove.l #eins,d1 ; Zahl>1?bsr S_fsub ; ( dies ist sinnvoll beitst.l d0 ; Zahlen <<1 );smi d7 ; und die Vorzeichenumkehr merkenbpl.s S_fln_gr1 ; ja-->o.k.move.l d3,d1 ; ansonsten Kehrwert bildenmove.l #eins,d0bsr S_fdivmove.l d0,d3S_fln_gr1:clr.l d2 ; Merker = NullS_fln_nrm:move.l d3,d0 ; Zahl > 1 ?move.l #eins,d1bsr S_fsubbmi.s S_fln_isokbeq.s S_fln_isoksub.l #$00800000,d3 ; ja-->Zahl durch 2 teilen...addq.w #1,d2 ; ...und Merker erhoehenbra.s S_fln_nrm ; nochmal probierenS_fln_isok:move.l d0,d3 ; Zahl um Eins erniedrigt abspeichernmove.l d0,d4 ; yz:=ymoveq.l #1,d6 ; zaehler:=1clr.l d5 ; Summe:=0bchg #31,d3 ; Multiplikator negativS_fln_loop:move.l d6,d0 ; Zaehler in Gleitkomma wandelnbsr S_fitofmove.l d0,d1 ; s:=s+yz/zaehler*vzmove.l d4,d0bsr S_fdivmove.l d5,d1bsr S_faddcmp.l d5,d0 ; noch signifikant ?beq.s S_fln_loopendmove.l d0,d5addq.w #1,d6 ; zaehler:=zaehler+1cmp.w #10,d6 ; Schleife fertig ?beq.s S_fln_loopendmove.l d4,d0 ; yz:=yz*ymove.l d3,d1bsr S_fmulmove.l d0,d4bra.s S_fln_loopS_fln_loopend:move.l d2,d0 ; Merker in Gleitkommabsr S_fitofmove.l #ln2,d1 ; * ln(2)bsr S_fmulmove.l d5,d1 ; s:=s+merkerbsr S_faddtst.b d7 ; noch Vorzeichen tauschen ?beq.s S_fln_endbchg #31,d0S_fln_end:movem.l (a7)+,d1-d7 ; Register zurueckrtsS_fln_errval:move.l #$ffc00000,d0 ; -NAN zurueckgebenrts;-----------------------------------------------------------------------------; 10er-Logarithmus : D0.S --> D0.SS_flog:tst.l d0 ; Argument <=0 ?ble.s S_flog_errvalbsr S_fln ; nat. Logarithmus bildenmove.l #ln10,d1 ; umrechnenbsr S_fdivrtsS_flog_errval:move.l #$ffc00000,d0 ; -NAN zurueckgebenrts;-----------------------------------------------------------------------------; Areasinus hyperbolicus: D0.S-->D0.S == ln[x+sqrt(x*x+1)]S_fasinh:movem.l d1-d2,-(a7)move.l d0,d2 ; Argument sichernmove.l d0,d1 ; quadrierenbsr S_fmulmove.l #eins,d1 ; 1 addierenbsr S_faddbsr S_fsqrt ; Wurzel ziehenmove.l d2,d1 ; Argument addierenbsr S_faddbsr S_fln ; Logarithmus des ganzenmovem.l (a7)+,d1-d2rts;-----------------------------------------------------------------------------; Areacosinus hyperbolicus: D0.S-->D0.S == ln[x+sqrt(x*x-1)]S_facosh:movem.l d1-d2,-(a7) ; Register sichernmove.l d0,d2 ; Argument sichernmove.l #eins,d1 ; Argument <1 ?bsr S_fcmpbmi.s S_facosh_errvalmove.l d2,d0 ; Argument zurueckmove.l d0,d1 ; quadrierenbsr S_fmulmove.l #eins,d1 ; 1 abziehenbsr S_fsubbsr S_fsqrt ; Wurzel ziehenmove.l d2,d1 ; Argument addierenbsr S_faddbsr S_fln ; Logarithmus des ganzenmovem.l (a7)+,d1-d2 ; Register zurueckrtsS_facosh_errval:movem.l (a7)+,d1-d2 ; Register zurueckmove.l #$ffc00000,d0 ; NAN zurueckgebenrts;-----------------------------------------------------------------------------; Areatangens hyperbolicus: D0.S-->D0.S == 0.5*ln((1+x)/(1-x))S_fatanh:movem.l d1-d2,-(a7) ; Register sichernmove.l d0,d2 ; Argument sichernbclr #31,d0 ; Vorzeichen wegcmp.l #eins,d0beq.s S_fatanh_inf ; =1-->INFbhi.s S_fatanh_errval ; >1-->NANmove.l d2,d1 ; Nenner berechnenmove.l #eins,d0bsr S_fsubexg d0,d2 ; Zaehler berechnenmove.l #eins,d1bsr S_faddmove.l d2,d1 ; Quotient darausbsr S_fdivbsr S_fln ; logarithmierenmove.w #-1,d1 ; halbierenbsr S_fmul2movem.l (a7)+,d1-d2 ; Register zurueckrtsS_fatanh_inf:move.l #$ff000000,d0 ; vorzeichenbehaftete Unend-roxr.l #1,d0 ; lichkeitmovem.l (a7)+,d1-d2 ; Register zurueckrtsS_fatanh_errval:move.l #$7fc00000,d0 ; NAN gebenmovem.l (a7)+,d1-d2 ; Register zurueckrts;-----------------------------------------------------------------------------; Areakotangens hyperbolicus: D0.S--> D0.S == 0.5*ln((1+x)/(x-1))S_facoth:movem.l d1-d2,-(a7) ; Register sichernmove.l d0,d2 ; Argument sichernroxl.l #1,d0 ; Vorzeichen in X-Flagcmp.l #eins*2,d0beq.s S_facoth_inf ; =1-->INFbmi.s S_facoth_errval ; <1-->NANmove.l d2,d0 ; Nenner berechnenmove.l #eins,d1bsr S_fsubexg d0,d2 ; Zaehler berechnenmove.l #eins,d1bsr S_faddmove.l d2,d1 ; Quotient darausbsr S_fdivbsr S_fln ; logarithmierenmove.w #-1,d1 ; halbierenbsr S_fmul2movem.l (a7)+,d1-d2 ; Register zurueckrtsS_facoth_inf:move.l #$ff000000,d0 ; vorzeichenbehaftete Unend-roxr.l #1,d0 ; lichkeitmovem.l (a7)+,d1-d2 ; Register zurueckrtsS_facoth_errval:move.l #$7fc00000,d0 ; NAN gebenmovem.l (a7)+,d1-d2 ; Register zurueckrts;-----------------------------------------------------------------------------; Kosinusfunktion: D0.S--> D0.Sds 0S_fcos:movem.l d1-d6,-(a7) ; Register rettenbclr #31,d0 ; cos(-x)=cos(x)move.l #pi2,d1 ; auf Bereich 0..2*Pi reduzierenS_fcos_subtr:cmp.l d1,d0 ; x>=2*Pi ?blo.s S_fcos_subend ; ja-->Endebchg #31,d1 ; fuer Subtraktionbsr S_fadd ; reduzierenbchg #31,d1 ; Subtrahend wieder richtigbra.s S_fcos_subtrS_fcos_subend:cmp.l #pi,d0 ; x>Pi ?blo.s S_fcos_nosubexg d0,d1 ; ja-->cos(x)=cos(2*Pi-x)bsr S_fsubS_fcos_nosub:move.l d0,d1 ; wir brauchen nur x^2bsr S_fmulbset #31,d0move.l d0,d3 ; -x^2 in D3move.l d0,d4 ; D4 enthaelt laufende Potenz von x^2; inkl. Vorzeichenmove.l #zwei,d5 ; D5 enthaelt laufende Fakultaetmove.l #eins,d2 ; D2 enthaelt Summemoveq.l #2,d6 ; D6 enthaelt ZaehlerS_fcos_loop:move.l d5,d1 ; s:=s+yz/zaehlermove.l d4,d0bsr S_fdivmove.l d2,d1bsr S_faddcmp.l d2,d0 ; Veraendert sich Summe noch ?beq.s S_fcos_endmove.l d0,d2addq.b #2,d6 ; i:=i+1cmp.b #22,d6 ; i=11 ?beq.s S_fcos_endmove.w d6,d0 ; Fakultaet erhhen: *(2n-1)*(2n)mulu.w d6,d0 ; =4*n^2-2*nsub.w d6,d0bsr S_fitof ; dazumultiplizierenmove.l d5,d1bsr S_fmulmove.l d0,d5move.l d4,d0 ; yz:=yz*ymove.l d3,d1bsr S_fmulmove.l d0,d4bra.s S_fcos_loopS_fcos_end:; Ergebnis bereits in D0movem.l (a7)+,d1-d6 ; Register zurueckrts;----------------------------------------------------------------------------; Sinus : D0.S-->D0.SS_fsin:move.l d1,-(a7) ; Register rettenmove.l #pihalf,d1 ; sin(x)=cos(x-pi/2)bsr S_fsubbsr S_fcosmove.l (a7)+,d1 ; Register zurueckrts;-----------------------------------------------------------------------------; Tangens: D0.S-->D0.SS_ftan:movem.l d1-d4,-(a7) ; Register rettentst.l d0 ; Vorzeichen merkensmi d4bclr #31,d0move.l #pi,d1 ; auf Bereich 0..Pi reduzierenS_ftan_subtr:cmp.l d1,d0 ; x>=Pi ?blo.s S_ftan_subend ; ja-->Endebchg #31,d1 ; fuer Subtraktionbsr S_fadd ; reduzierenbchg #31,d1 ; Subtrahend wieder richtigbra.s S_ftan_subtrS_ftan_subend:move.l d0,d2 ; Argument merkenbsr S_fcos ; Nenner rechnenmove.l d0,d3 ; Nenner merkenmove.l d0,d1 ; sqr(1-x^2) rechnenbsr S_fmulmove.l d0,d1move.l #eins,d0bsr S_fsubbsr S_fsqrtmove.l d3,d1bsr S_fdiv ; Quotienttst.b d4 ; Vorzeichen dazubeq.s S_ftan_nonegbchg #31,d0S_ftan_noneg:movem.l (a7)+,d1-d4 ; Register zurueckrts;-----------------------------------------------------------------------------; Kotangens: D0.S-->D0.SS_fcot:movem.l d1-d4,-(a7) ; Register rettentst.l d0 ; Vorzeichen merkensmi d4bclr #31,d0move.l #pi,d1 ; auf Bereich 0..Pi reduzierenS_fcot_subtr:cmp.l d1,d0 ; x>=Pi ?blo.s S_fcot_subend ; ja-->Endebchg #31,d1 ; fuer Subtraktionbsr S_fadd ; reduzierenbchg #31,d1 ; Subtrahend wieder richtigbra.s S_fcot_subtrS_fcot_subend:move.l d0,d2 ; Argument merkenbsr S_fcos ; Zaehler rechnenmove.l d0,d3 ; Zaehler merkenmove.l d0,d1 ; sqr(1-x^2) rechnenbsr S_fmulmove.l d0,d1move.l #eins,d0bsr S_fsubbsr S_fsqrtmove.l d0,d1move.l d3,d0bsr S_fdiv ; Quotienttst.b d4 ; Vorzeichen dazubeq.s S_fcot_nonegbchg #31,d0S_fcot_noneg:movem.l (a7)+,d1-d4 ; Register zurueckrts;-----------------------------------------------------------------------------; Arcustangens: D0.S-->D0.SS_fatan:movem.l d1-d6,-(a7) ; Register sichernsubq.l #2,a7 ; Platz fuer Hilfsvariablentst.l d0 ; Vorzeichen merken...smi (a7)bclr #31,d0 ; ...und loeschencmp.l #eins,d0 ; Argument>1 ?shi 1(a7) ; ja :bls.s S_fatan_no1 ; nein :move.l d0,d1 ; ja : Kehrwert bildenmove.l #eins,d0bsr S_fdivS_fatan_no1:move.l #3,d2 ; Zaehler initialisierenmove.l d0,d5 ; Summe initialisierenmove.l d0,d4 ; laufende Potenz = x^1move.l d0,d1 ; x^2 berechnenbsr S_fmulmove.l d0,d3bset #31,d3 ; immer mit -x^2 multiplizierenS_fatan_loop:move.l d4,d0 ; naechste Potenz ausrechnenmove.l d3,d1bsr S_fmulmove.l d0,d4move.l d2,d0 ; Nenner in Gleitkommabsr S_fitofmove.l d0,d1 ; Division ausfuehrenmove.l d4,d0bsr S_fdivmove.l d5,d1 ; zur Summe addierenbsr S_faddcmp.l d0,d5 ; noch signifikant ?beq.s S_fatan_endloop ; nein-->Endemove.l d0,d5addq.l #2,d2 ; Zaehler erhoehencmp.l #61,d2 ; fertig ?bne.s S_fatan_loopS_fatan_endloop:move.l d5,d0 ; Ergebnis in D0 bringentst.b 1(a7) ; war Argument < 1 ?beq.s S_fatan_not2bchg #31,d0 ; ja : Erg.=Pi/2-Ergmove.l #pihalf,d1bsr S_faddS_fatan_not2:tst.b (a7) ; Vorzeichen dazubeq.s S_fatan_not1bset #31,d0S_fatan_not1:addq.l #2,a7 ; Hilfsvar. abraeumenmovem.l (a7)+,d1-d6 ; Register zurueckrts;-----------------------------------------------------------------------------; Arcuskotangens: D0.S-->D0.SS_facot:move.l d1,-(a7) ; Register sichernbsr S_fatan ; acot(x)=pi/2-atan(x)bchg #31,d0move.l #pihalf,d1bsr S_faddmove.l (a7)+,d1 ; Register zurueckrts;-----------------------------------------------------------------------------; Arcussinus: D0.S --> D0.SS_fasin:movem.l d1-d2,-(a7) ; Register rettenmove.l d0,d2 ; Argument merkenmove.l d0,d1 ; Quadrat berechnenbsr S_fmulbset #31,d0 ; 1-x^2 bildenmove.l #eins,d1bsr S_faddtst.l d0 ; Sonderfaelle abfangenbmi.s S_fasin_errval ; <0 geht nichtbeq.s S_fasin_inf ; Endwertebsr S_fsqrt ; Wurzel ...move.l d0,d1 ; ... und Quotientmove.l d2,d0bsr S_fdivbsr S_fatan ; zuletzt das wichtigstemovem.l (a7)+,d1-d2 ; Register zurueckrtsS_fasin_errval:move.l #$7fc00000,d0 ; NAN zurueckgebenmovem.l (a7)+,d1-d2 ; Register zurueckrtsS_fasin_inf:move.l #pihalf,d0 ; +- pi/2 zurueckgebenand.l #$80000000,d2 ; Vorzeichen dazuor.l d2,d0movem.l (a7)+,d1-d2 ; Register zurueckrts;-----------------------------------------------------------------------------; Arcuskosinus: D0.S --> D0.SS_facos:tst.l d0 ; Argument=0 ?beq.s S_facos_infmove.l d0,d2 ; Argument merkenmove.l d0,d1 ; Quadrat berechnenbsr S_fmulbset #31,d0 ; 1-x^2 bildenmove.l #eins,d1bsr S_faddtst.l d0 ; Sonderfaelle abfangenbmi.s S_facos_errval ; <0 geht nichtbsr S_fsqrt ; Wurzel ...move.l d2,d1 ; ... und Quotientbsr S_fdivbsr S_fatan ; zuletzt das wichtigstemovem.l (a7)+,d1-d2 ; Register zurueckrtsS_facos_errval:move.l #$7fc00000,d0 ; NAN zurueckgebenmovem.l (a7)+,d1-d2 ; Register zurueckrtsS_facos_inf:move.l #pihalf,d0 ; +- pi/2 zurueckgebenand.l #$80000000,d2 ; Vorzeichen dazuor.l d2,d0movem.l (a7)+,d1-d2 ; Register zurueckrtsS_floatlibend: