; ; File: FP020OPS.a ; ; Contains: xxx put contents here xxx ; ; Written by: xxx put writers here xxx ; ; Copyright: © 1990 by Apple Computer, Inc., all rights reserved. ; ; This file is used in these builds: Mac32 ; ; Change History (most recent first): ; ; <5> 9/15/90 BG Removed <3>, <4>. 040s are behaving more reliably now. ; <4> 7/17/90 BG Found more places to add EclipseNOPs. ; <3> 7/4/90 BG Added EclipseNOPs for flakey 040s. ; <2> 4/14/90 JJ Made changes to support new binary-to-decimal, 96-bit precision, ; and improved Pack 5. ; <1> 3/2/90 JJ First checked in. ; ; To Do: ; ;----------------------------------------------------------- ; File: FPOPS.a ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; FPOPS ---Floating point operations ; Copyright Apple Computer, Inc., 1983,1984,1985,1989,1990 ; All Rights Reserved ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 02JUL82: WRITTEN J. COONEN ; 12AUG82: TIDIED UP (JTC) ; 01SEP82: RND MODE ENCODINGS CHANGED (JTC) ; 12DEC82: PROJ MODE OUT (JTC) ; 25JAN90: modified for 68020 SANE (JPO) ; ; ASSUME REGISTER MASK: DO-ARITHMETIC ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPADD---ADDITION/SUBTRACTION OPERATIONS ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; TO SUBTRAC JUST FLIP THE SIGN AND XOR-SIGN BITS IN D6.B. ;----------------------------------------------------------- SUBTOP: EORI.B #$A0,D6 ; BITS #7 AND #5 ADDTOP: MOVE.W ADDCASE(D3),D3 ; JMP ADDTOP(D3) ADDCASE: ; DST + SRC DC.W ADDNUM - ADDTOP ; NUM + NUM DC.W ADDS0 - ADDTOP ; NUM + 0 DC.W RSRC - ADDTOP ; NUM + INF DC.W ADDD0 - ADDTOP ; 0 + NUM DC.W ADD00 - ADDTOP ; 0 + 0 DC.W RSRC - ADDTOP ; 0 + INF DC.W RDSTSGN- ADDTOP ; INF + NUM DC.W RDSTSGN- ADDTOP ; INF + 0 DC.W ADDINF - ADDTOP ; INF + INF ;----------------------------------------------------------- ; ADD 2 FINITE NUMBERS HAS TWO SPECIAL CASES, WHEN ONE OF ; THE SRC OR DST IS 0. IN THAT CASE JUST BE SURE NONZERO ; OPERAND IS PLACED IN RESULT BUFFER, TO BE SUBJECT TO THE ; COERCION TO THE DESTINATION. ;----------------------------------------------------------- ADDNUM: ;----------------------------------------------------------- ; FIRST ALIGN SO "LARGER" EXP IN A4, LARGER SIGN IN D6.#7 ; "SMALLER" DIGITS ARE IN D4,5 FOR SHIFTING; "LARGER" DIGITS ; ARE IN D3,A2 (CANNOT USE A1 SINCE NEED TO ADDX.L. ; ASSUME SRC IS "LARGER", SO SWAP ITS DIGS WITH DST. ;----------------------------------------------------------- MOVE.L D4,D3 ; CAN'T ADDX FROM A REGS MOVE.L A1,D4 EXG D5,A2 MOVE.W A4,D0 ; SEXP, WORD IS ENOUGH SUB.W A3,D0 ; SEXP - DEXP BEQ ADDEM ; NO SHIFT IF EXP'S = BGT.S @1 ; JUST SHIFT DST IN D4,5 ;----------------------------------------------------------- ; DST IS LARGER: ; AS PART OF SWAP, MUST MOVE DST SIGN TO LEAD BIT OF D7 BYTE ; BUT WITHOUT MOVING THE XOR, WHICH WILL BE TESTED... ;----------------------------------------------------------- EXG D5,A2 ; SWAP LO BITS EXG D4,D3 ; SWAP HI BITS NEG.W D0 ; TRUE SHIFT COUNT MOVEA.L A3,A4 ; LARGER EXP ADD.B D6,D6 ; SHIFT SRC SIGN OUT ASR.B #1,D6 ; RESTORE X0R TO PLACE & DUPLICATE DST SIGN ;----------------------------------------------------------- ; Do fast right shift of D4/D5 into D4/D5/D7. Translate sticky ; information in D7.L into D7.W. ;----------------------------------------------------------- @1: CMPI #66,D0 ; SPECIAL FAST ROUTINE IF SHIFT OF > 66 BITS BHI ADDSHLOTS MOVEA.L D0,A3 ; save shift value in A3 ADD D0,D0 ; jmp to appropriate routine MOVE ADDSHCASE(D0),D0 JMP ADDNUM(D0) ADDSHCASE: DC.W ADDEM - ADDNUM DC.W ADDSH1 - ADDNUM DC.W ADDSH2 - ADDNUM DC.W ADDSH3 - ADDNUM DC.W ADDSH4 - ADDNUM DC.W ADDSH5 - ADDNUM DC.W ADDSH6 - ADDNUM DC.W ADDSH7 - ADDNUM DC.W ADDSH8 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH16 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH2TO31 - ADDNUM DC.W ADDSH32 - ADDNUM DC.W ADDSH33 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH33TO63 - ADDNUM DC.W ADDSH64 - ADDNUM DC.W ADDSH65 - ADDNUM DC.W ADDSH66 - ADDNUM ADDSHLOTS: MOVEQ #0,D4 MOVEQ #0,D5 ST D7 BRA ADDEM ADDSH66: OR D4,D5 TST.L D5 SNE D7 LSR.L #2,D4 BRA.S BIGSTICK ADDSH65: OR D4,D5 TST.L D5 SNE D7 LSR.L #1,D4 BRA.S BIGSTICK ADDSH64: TST.L D5 SNE D7 ; gather stickies BIGSTICK: OR.L D4,D7 MOVEQ #0,D4 MOVEQ #0,D5 BRA.S FIXST ; fix stickies ;----------------------------------------------------------- ; SHIFT OF 33-63 BITS ;----------------------------------------------------------- ADDSH33TO63: MOVE.L A3,D0 ; restore shift count to D0 MOVE.L D5,D7 ; D7 <- D5 SUBI #32,D0 ; decr shift count by 32 MOVE.L D4,D5 ; D5 <- D4 ROR.L D0,D7 ; rotate D7 right by new count LSR.L D0,D5 ; shift D5 right by new count BFTST D7{0:D0} ; test for low sticky BEQ.S @3 ORI #$FF,D7 @3: BFINS D4,D7{0:D0} ; shift high sticky bits in MOVEQ #0,D4 ; zero D4 BRA.S FIXST ; fix stickies ADDSH33: MOVE.L D5,D7 ; shift right 32 bits MOVE.L D4,D5 MOVEQ #0,D4 LSR.L #1,D5 ; shift right one more bit ROXR.L #1,D7 SCS D7 ; keep low sticky BRA.S FIXST ; fix stickies ADDSH32: MOVE.L D5,D7 ; 32-bit shift is easy MOVE.L D4,D5 MOVEQ #0,D4 BRA.S FIXST ; fix stickies ;----------------------------------------------------------- ; SHIFT OF 2-31 BITS ;----------------------------------------------------------- ADDSH2TO31: MOVE.L A3,D0 ; D0 <- shift count BFINS D5,D7{0:D0} ; shift bits into D7 from D5 LSR.L D0,D5 ; shift D5 right BFINS D4,D5{0:D0} ; shift bits into D5 from D4 LSR.L D0,D4 ; shift D4 ;----------------------------------------------------------- ; Fix stickies (convert from D7.L to D7.W) ;----------------------------------------------------------- FIXST: TST.W D7 ; test D7.W SNE D1 ; set D1 if nonzero CLR.W D7 ; zero D7.W and swap SWAP D7 OR.B D1,D7 ; OR in D1.B BRA.S ADDEM ; done ADDSH16: MOVE.W D5,D7 MOVE.W D4,D5 SWAP D5 CLR.W D4 SWAP D4 BRA.S ADDEM ADDSH8: BFINS D5,D7{16:8} MOVE.B D4,D5 ROR.L #8,D5 LSR.L #8,D4 BRA.S ADDEM ADDSH7: BFINS D5,D7{16:7} LSR.L #7,D5 BFINS D4,D5{0:7} LSR.L #7,D4 BRA.S ADDEM ADDSH6: BFINS D5,D7{16:6} LSR.L #6,D5 BFINS D4,D5{0:6} LSR.L #6,D4 BRA.S ADDEM ADDSH5: BFINS D5,D7{16:5} LSR.L #5,D5 BFINS D4,D5{0:5} LSR.L #5,D4 BRA.S ADDEM ADDSH4: BFINS D5,D7{16:4} LSR.L #4,D5 BFINS D4,D5{0:4} LSR.L #4,D4 BRA.S ADDEM ADDSH3: BFINS D5,D7{16:3} LSR.L #3,D5 BFINS D4,D5{0:3} LSR.L #3,D4 BRA.S ADDEM ADDSH2: BFINS D5,D7{16:2} LSR.L #2,D5 BFINS D4,D5{0:2} LSR.L #2,D4 BRA.S ADDEM ADDSH1: LSR.L #1,D4 ROXR.L #1,D5 ROXR.W #1,D7 ;----------------------------------------------------------- ; OPERANDS ARE NOW ALIGNED. TEST FOR +/- AND DO IT. ;----------------------------------------------------------- ADDEM: BTST #5,D6 ; TEST XOR OF SIGNS BNE.S SUBMAG ;----------------------------------------------------------- ; ADD MAGNITUDE: ADD THE WORDS AND CHECK FOR CARRY-OUT. ;----------------------------------------------------------- ADD.L A2,D5 ADDX.L D3,D4 BCC COERCE ROXR.L #1,D4 ; ADJUST RIGHT ROXR.L #1,D5 ROXR.W #1,D7 ; NO STICKIES CAN BE LOST SCS D1 OR.B D1,D7 ADDQ.L #1,A4 ; BUMP EXP @15: BRA COERCE ;----------------------------------------------------------- ; SIMPLIFY BY SUBTRACTING LARGE OP IN D3,A2 FROM SMALL IN ; D4,5,7 AND THEN CHECKING FOR SPECIAL CASES. IF ZERO, JUMP ; OUT TO 0+0 CODE. IF GREATER, FLIP SIGN. IF LESS (USUAL) ; JUST NEGATE. ;----------------------------------------------------------- SUBMAG: NOT.B D6 ; ASSUME >, WITH SIGN CHG SUB.L A2,D5 SUBX.L D3,D4 BEQ.S ZEROSUM ; STORE ZERO WITH SIGN BCC NORMCOERCE ; GOT IT RIGHT NEG.W D7 ; FLIP DIGITS NEGX.L D5 NEGX.L D4 NOT.B D6 ; FLIP SIGN BACK @7: BRA NORMCOERCE ;----------------------------------------------------------- ; NOW SET EXP=0 AND FIX SIGN ACCORDING TO ROUNDING MODE. ; IN THE SPECIAL CASE OF TWO 0'S, AVOID THE UNDERFLOW ; COERCION WILL SIGNAL IN S/D RESTRICTION. ;----------------------------------------------------------- ADD00: BTST #5,D6 ; SAME SIGN? BEQ.S ADDQ00 ; YES, EASY ZEROSUM: SUBA.L A4,A4 ; 0 EXP CLR.B D6 ; ASSUME POSITIVE BTST #RNDHI,(A0) ; 10 -- RND MINUS BEQ.S ADDQ00 BTST #RNDLO,(A0) BNE.S ADDQ00 NOT.B D6 ; MAKE NEG ADDQ00: RTS ; DON'T COERCE 0 ;----------------------------------------------------------- ; IF DST=0, HAVE RES=SRC. BUT IF SRC=0 MUST SET RES=DST. ; THESE CASES AVOID EXTRANEOUS SHIFTING OF ZERO OPERAND. ;----------------------------------------------------------- ADDS0: MOVE.L A2,D5 ; LO DIGS MOVE.L A1,D4 ; HI DIGS MOVE.L A3,A4 ; EXP ADD.B D6,D6 ; SIGN ADDD0: BRA COERCE ;----------------------------------------------------------- ; SINCE PROJECTIVE MODE OUT, ; SUM OF TWO INFS ALWAYS DEPENDS UPON THEIR SIGNS. ;----------------------------------------------------------- ADDINF: BTST #5,D6 ; SAME SIGN? BNE.S @25 RTS @25: MOVEQ #NANADD,D0 ; MARK ERROR BRA INVALIDOP ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPMUL ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 07JUL82: WRITTEN BY JEROME COONEN ; 12AUG82: MULU32 ROUTINE TIGHTENED. ; 09JUN83: DON'T USE A5 AS TEMP CELL. ; 26JAN89: MODIFIED FOR 68020 SANE (JPO). ; ;----------------------------------------------------------- MULTOP: ROL.B #2,D6 ; GET XOR SIGNS MOVEQ #NANMUL,D0 ; ASSUME THE WORST MOVE.W MULCASE(D3),D3 JMP MULTOP(D3) MULCASE: ; DST * SRC DC.W MULNUM - MULTOP ; NUM * NUM DC.W RSRC - MULTOP ; NUM * 0 DC.W RSRC - MULTOP ; NUM * INF DC.W RDST - MULTOP ; 0 * NUM DC.W RSRC - MULTOP ; 0 * 0 DC.W INVALIDOP - MULTOP ; 0 * INF DC.W RDST - MULTOP ; INF * NUM DC.W INVALIDOP - MULTOP ; INF * 0 DC.W RSRC - MULTOP ; INF * INF MULNUM: ;----------------------------------------------------------- ; HAVE: X.XXXXX * Y.YYYYYY --> ZZ.ZZZZZZZ BEFORE ; NORMALIZATION AND COERCION. SO SUBTRACT (BIAS-1) TO ; ACCOUNT FOR BINARY POINT ONE BIT TO RIGHT. FOR EXAMPLE, ; 1 * 1 COMES OUT: 2^1 * 0.10000000... WHICH IN TURN ; IS NORAMALIZED TO 2^0 * 1.000000... ;----------------------------------------------------------- ADDA.L A3,A4 ; ADD EXP'S SUBA.W #$3FFE,A4 ; SUBTRACT (BIAS - 1) ;----------------------------------------------------------- ; Multiply is a D register hog, so some state must be saved. ; ; 64*64 multiply is accomplished in 4 32*32 products, using ; the MULU.L 32*32 instruction of the MC68020. ; ; Special provisions are made for the three special cases: ; both operands have 32 trailing zeros or any one operand ; has 32 trailing zeros. ; ; The basic register mask throughout is: ; A1: D6 save ; A2,A3: SRC bits ; A4: result exponent ; D0,D1: used to pass operands to 32*32 mult and return results ; D2,3: DST bits ; D4,5,7: 64-bit product and round bits ; D6: zero ;----------------------------------------------------------- MOVE.L A1,D2 ; D2 <- DST.HI MOVE.L A2,D3 ; D3 <- DST.LO MOVEA.L D6,A1 ; save D6 in A1 MOVEA.L D4,A2 ; A2 <- SRC.HI MOVEA.L D5,A3 ; A3 <- SRC.LO MOVEQ #0,D7 ; exact at first MOVEQ #0,D6 ; D6 <- 0 MOVE.L A2,D5 ; D4/5 = SRC.HI * DST.HI MULU.L D2,D4:D5 MOVE.L A3,D7 ; SRC.LO * DST.HI BEQ.S HILO ; skip if SRC.LO = 0 MULU.L D2,D0:D7 ; RESULT.LO in D7 ADD.L D0,D5 ; RESULT.HI added to D4/5 ADDX.L D6,D4 HILO: MOVE.L D3,D0 ; SRC.HI * DST.LO BEQ.S MULDONE ; done if DST.LO = 0 MOVE.L A2,D1 MULU.L D0,D0:D1 ADD.L D1,D7 ; result added to D4/5/7 ADDX.L D0,D5 ADDX.L D6,D4 ;----------------------------------------------------------- ; Fourth 32*32 product is SRC.LO * DST.LO. High result is ; added into D7 with carry propagating through D5/4. Nonzero ; low result causes low order stickies to be set in D7. ;----------------------------------------------------------- MOVE.L A3,D1 ; SRC.LO BEQ.S MULDONE ; done if SRC.LO = 0 MULU.L D3,D0:D1 ADD.L D0,D7 ; add to D7 ADDX.L D6,D5 ; propagate carry to D4/5 ADDX.L D6,D4 TST.L D1 ; set low sticky if D1 != 0 SNE D1 OR.B D1,D7 ;----------------------------------------------------------- ; Clean up after multiplication. Restore D6 and transfer ; stickies down to D7.W. ;----------------------------------------------------------- MULDONE: MOVE.L A1,D6 ; restore D6 TST.W D7 ; test D7.W SNE D1 ; set D1 if nonzero CLR.W D7 ; zero D7.W and swap SWAP D7 OR.B D1,D7 ; OR in D1.B BRA NORMCOERCE ; normalize if necessary & coerce ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPDIV ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 03JUL82: WRITTEN BY JEROME COONEN ; 12AUG82: SINGLE CASE FIXED UP (JTC) ; 26JAN90: MODIFIED FOR 68020 SANE (JPO) ; ; ASSUME REGISTER MASK: DO-ARITHMETIC ;----------------------------------------------------------- DIVTOP: ROL.B #2,D6 ; GET XOR SIGNS MOVEQ #NANDIV,D0 ; JUST IN CASE... MOVE.W DIVDCASE(D3),D3 JMP DIVTOP(D3) DIVDCASE: ; DST / SRC DC.W DIVNUM - DIVTOP ; NUM / NUM DC.W DIVBY0 - DIVTOP ; NUM / 0 DC.W DIVBYI - DIVTOP ; NUM / INF DC.W RDST - DIVTOP ; 0 / NUM DC.W INVALIDOP - DIVTOP ; 0 / 0 DC.W RDST - DIVTOP ; 0 / INF DC.W RDST - DIVTOP ; INF / NUM DC.W RDST - DIVTOP ; INF / 0 DC.W INVALIDOP - DIVTOP ; INF / INF ;----------------------------------------------------------- ; DIV BY ZERO: SET THE ERROR BIT, STUFF INF, RET. ;----------------------------------------------------------- DIVBY0: BSET #ERRZ+8,D6 MOVEA.W #$7FFF,A4 ; BIG EXP MOVEQ #0,D4 ; ZERO DIGS MOVE.L D4,D5 RTS ;----------------------------------------------------------- ; DIV BY INF: STORE 0 AND RET. ;----------------------------------------------------------- DIVBYI: SUBA.L A4,A4 ; ZERO EXP MOVE.L A4,D4 ; AND DIGS... MOVE.L D4,D5 RTS ;----------------------------------------------------------- ; Dividing numbers involves the nonrestoring divide subroutine ; DIV32 shared with the REMAINDER algorithm. This subroutine ; essentially calculates 32 bits of quotient of a 64 / 64 ; division and also returns a shifted remainder. ;----------------------------------------------------------- DIVNUM: ;----------------------------------------------------------- ; FIGURE RESULT EXPONENT AS THOUGH DST >= SRC. WILL COMPUTE ; AN EXTRA QUOTIENT BIT JUST IN CASE DST < SRC, IN WHICH ; CASE EXP WILL BE DECREMENTED. ;----------------------------------------------------------- EXG A3,A4 ; SWAP EXPS SUBA.L A3,A4 ; DEXP - SEXP ADDA.W #$3FFF,A4 ; REBIAS ;----------------------------------------------------------- ; DST >= SRC: 64+1 QUO BITS, LAST IS ROUND. ; DST < SRC: 64+1 QUO BITS, FIRST IS 1, LAST IS ROUND. ; TRICK: IN ORDER TO GET EXTRA (ROUND) BIT IN D4,5, LET ; LEADING BIT (KNOWN TO BE 1) BE SHIFTED OUT OF ; D4,5 DURING DIVISION. THEN PUT IT BACK ON RETURN. ; USE SPECIAL CASE STARTUP CODE TO DISTINGUISH THE DST < SRC ; CASE THAT REQUIRES TWEAKS OF REMAINDER AND EXPONENT. ; ; Set up funny register mask for nonrestoring division ; A2 - quotient high longword ; A3 - D6 save ; A4 - exponent of result ; D2,D3 - dividend cum shifted remainder ; D4,D5 - divisor ; D1 - holds 0 ; scratch registers are D0,D6,D7 ; *** NOTE CAN DO BETTER ON FIRST STEP BECAUSE OF TEST ABOVE ;----------------------------------------------------------- DIVNONRESTORING: MOVE.L D6,A3 ; save D6 contents in A3 for duration MOVE.L A1,D2 ; D2 <- DST.HI MOVE.L A2,D3 ; D3 <- DST.LO MOVEQ #0,D1 ; D1 <- 0 MOVE.L D2,D6 ; save DST.HI for case DST < SRC below SUB.L D5,D3 ; get leading 1 bit in quotient via subtraction SUBX.L D4,D2 ; of SRC (divisor) from DST (dividend) BCC.S BGNDIVD ; DST >= SRC; begin division steps SUBQ.L #1,A4 ; DST < SRC; decrement exponent and ADD.L A2,D3 ; correct remainder by adding DST to it ADDX.L D6,D2 BGNDIVD: BSR.S DIV32 ; get first quotient longword MOVE.L D0,A2 ; save in A2 BSR.S DIV32 ; get second quotient longword MOVE.L D0,D5 ; put quotient in D4/D5 MOVE.L A2,D4 MOVE.L A3,D6 ; restore D6 ;----------------------------------------------------------- ; Clean up prior to return. ; Remainder is in D2/D3 and shifted quotient is in D4/5. ; Adjust quotient and put round/stickies in D7.W ;----------------------------------------------------------- MOVEQ #1,D7 ; it's almost zero LSR.L #1,D7 ; D7 = 0 and X bit set ROXR.L #1,D4 ; shift leading 1 bit into quotient ROXR.L #1,D5 ROXR.W #1,D7 ; shift round bit into D7.W OR.L D2,D3 ; test all remainder bits SNE D7 ; set stickies if nonzero BRA COERCE ; coerce result ;----------------------------------------------------------- ; Subroutine DIV32 calculates a 32-bit quotient from a 64-bit ; dividend and a 64-bit divisor. It also returns a shifted ; (by 32 bits) remainder. This subroutine uses the MULU.L and ; DIVU.L instructions of the MC68020. ; ; D2,D3 - dividend cum shifted remainder ; D1 - bits to be shifted into low half of remainder (usually zero) ; D4,D5 - divisor ; D0 - 32-bit quotient ; D6,D7 - scratch registers ;----------------------------------------------------------- DIV32: DIVU.L D4,D2:D3 ; divide step (64-bit / 32-bit) BVS.S DIVDONE ; rare overflow handler MOVE.L D3,D0 ; initialize quotient word MOVE.L D3,D7 ; multiply quotient by rest MULU.L D5,D6:D7 ; of divisor (32 bits) CTNDIV: MOVE.L D1,D3 ; shifted remainder in D1/D2 SUB.L D7,D3 ; subtract correction from remainder SUBX.L D6,D2 BCC.S DIVOK ; OK if no carry ONEMORE: SUBQ.L #1,D0 ; correction produced carry; decr quotient ADD.L D5,D3 ; and adjust remainder upward until positive ADDX.L D4,D2 BCC.S ONEMORE DIVOK: RTS ; return ;----------------------------------------------------------- ; Division has produced an overflow (very rare case). Fix ; it up. ;----------------------------------------------------------- DIVDONE: MOVE.L D5,D6 ; DIVU.L overflow MOVEQ #0,D7 ; set D6/7 to $100000000 * D5 MOVE.L D3,D2 ; simulate remainder for quotient of $100000000 MOVEQ #0,D0 ; quotient effectively $100000000 BRA.S CTNDIV ; adjust remainder and quotient ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPREM ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 07JUL82: WRITTEN BY JEROME COONEN ; 12AUG82: TIDIED UP. (JTC) ; 12OCT82: RETURN QUO TO D0 FIXED. (JTC) ; 12DEC82: ONLY PLACE WHERE D0.W MODIFIED (JTC) ; 05AUG83: FIX BUG IN QUOTIENT WHEN SIGN MUST BE ADJUSTED (JTC) ; 26JAN90: MODIFIED FOR MC68020 SANE (JPO) ; ; ******** IMPORTANT STACK DEPENDENCY -- SEE BELOW ******** ; ; THE REMAINDER OPERATION DIVIDES DST/SRC TO GET ----ALL--- ; QUOTIENT BITS (POSSIBLY THOUSANDS OF THEM) AND THEN ; RETURNS THE RESULTING REMAINDER, REDUCED TO LESS THAN OR ; EQUAL TO (1/2)*DVR. IT ALSO RETURNS THE SIGN AND LOW ; SEVEN INTEGER QUOTIENT BITS IN REGISTER D0.W AS A ; TWO'S-COMPLEMENT INTEGER. THIS KLUGE IS ; EXTREMELY USEFUL FOR ELEMENTARY FUNCTION EVALUATION ; WHERE, SAY, REMAINDER BY (PI/4) IS NOT USEFUL WITHOUT ; AN INDICATION OF THE OCTANT (GIVEN BY THE QUOTIENT) AS ; WELL AS THE REMAINDER. ; ; TO GET THE PROPERLY REDUCED QUOTIENT, IT IS EASIEST TO ; DIVIDE ALL THE WAY THROUGH THE FIRST FRACTION QUOTIENT ; BIT, AND THEN PATCH UP. IF THE QUOTIENT TURNS OUT TO BE ; ZERO, ITS SIGN IS ARBITRARILY SET TO THAT OF THE DST. ; ; Integer quotient reduction is accomplished in one of two ; ways, depending upon the difference in exponent value for ; the two operands. For small values (< 9) of this difference, ; a standard restoring division algorithm is used. For larger ; values, repeated calls are made to the DIV32 subroutine, ; which chews off 32 bits of quotient at a time. In the latter ; case, the original dividend is preshifted to accommodate extra ; bits (MOD 32) ; ; ASSUME THE MASK: DO-ARITHMETIC, WITH D7=0 FOR THE ; CCR AND ROUND INFO. ; ; SOME ASSUMPTIONS ABOUT THE STACK ARE NECESSARY. ; WHEN THE REGISTERS WERE SAVED WITH MOVEM.L, D0 WAS ; LEFT NEAREST THE TOP OF THE STACK. ALL THAT IS ABOVE ; IT NOW IS THE RETURN ADDRESS, "PREPACK:" IN FPCONTROL. ; THUS DO.W, WHICH GETS THE INTEGER QUOTIENT, IS AT 6(SP). ;----------------------------------------------------------- ;----------------------------------------------------------- ; DO SOME BOOKKEEPING FIRST. PLACE DEFAULT 0 QUO IN D0. ; ASSUME THE RESULT WILL HAVE DST SIGN, AND NOTE THAT QUO ; SIGN IS MOVED TO BIT #6 OF D6. ; AND STORE ERROR CODE IN D0 IN CASE OF INVALID. ; ; P754 REQUIRES THAT THE PRECISION CONTROL BE DISABLED HERE. ;----------------------------------------------------------- REMTOP: CLR.W 6(SP) ; QUO SET TO 0 (D0.W saved on stack) ADD.B D6,D6 ; ALIGN DST SIGN, MOVING QUO MOVEQ #NANREM,D0 ; ASSUME THE WORST... ANDI.L #$3FFFFFFF,D6 ; SET DST TO EXT'D PRECISION MOVE.W REMCASE(D3),D3 JMP REMTOP(D3) REMCASE: ; DST REM SRC DC.W REMNUM - REMTOP ; NUM REM NUM DC.W INVALIDOP - REMTOP ; NUM REM 0 DC.W REMDST - REMTOP ; NUM REM INF DC.W RDST - REMTOP ; 0 REM NUM DC.W INVALIDOP - REMTOP ; 0 REM 0 DC.W RDST - REMTOP ; 0 REM INF DC.W INVALIDOP - REMTOP ; INF REM NUM DC.W INVALIDOP - REMTOP ; INF REM 0 DC.W INVALIDOP - REMTOP ; INF REM INF ;----------------------------------------------------------- ; DEXP - SEXP + 1 = NUMBER OF INTEGER QUO BITS. GET ONE ; MORE TO AID IN ROUNDING. CASES ON (DEXP - SEXP + 1): ; >= 0 -- RUN DIVDE AND RESTORE TO GET THOSE BITS ; < 0 -- DST IS ALREADY LESS THAN HALF SRC, SO JUST ; COERCE (AND QUO = 0). ;----------------------------------------------------------- REMNUM: MOVE.L A3,D0 ; DST EXP ADDQ.L #1,D0 SUB.L A4,D0 ; DEXP - SEXP + 1 BPL.S REMDIV ; MUST DO IT ALL... REMDST: MOVE.L A1,D4 ; RESULT IS DST MOVE.L A2,D5 MOVEA.L A3,A4 BRA.S REMFIN ;----------------------------------------------------------- ; Set tentative REM exponent to SEXP-1, since REM will be reduced ; to at most half of SRC. Then determine from size of exponent ; difference in D0 which algorithm to use. ;----------------------------------------------------------- REMDIV: SUBQ.L #1,A4 ; tentative exponent CMPI.L #9,D0 BGT.S REMSHIFT ; many integer bits to chew off ;----------------------------------------------------------- ; OFF TO RESTORE WITH ITS REGISTER MASK: ; D0: MAGNITUDE COUNT D1,D2: DIVIDEND ; D4,D5: QUOTIENT D3,A2: DIVISOR ;----------------------------------------------------------- MOVE.L A1,D1 ; DST IS DIVIDEND MOVE.L A2,D2 MOVE.L D4,D3 ; SRC IS DIVISOR MOVEA.L D5,A2 ADDQ.L #1,D0 ; INITIALIZE LOOP COUNT BSR.S RESTORE ;----------------------------------------------------------- ; AFTER ALL QUOTIENT BITS AND FIRST FRACTION BIT HAVE BEEN ; EVALUATED INTO D4,5 (LEADING BITS ARE LOST OFF THE LEFT) ; THERE ARE THREE CASES ("REM" IS RESULT OF DIV LOOP): ; ; LOW QUO BIT = 0 --> REM < HALF DVR, ALL DONE ; ; LOW QUO BIT = 1 AND REM = 0 --> HALF-WAY CASE, WHERE ; SIGN OF REM (= HALF DIVISOR) IS DETERMINED ; SO LOW INT QUO BIT WILL BE 0 ; ; LOW QUO BIT = 1 AND REM > 0 --> TRUE REM > HALF DVR, ; SO FLIP SIGN AND SUBTACT. THIS IS TRICKY ; AND RATHER NONINTUITIVE. THE POINT IS THAT ; DIVIDING THROUGH TO THE FIRST FRAC QUO BIT ; REDUCES THE EXP OF REM TO DVR-1; BUT THE ; DIV ALGORITHM DOES NOT SHIFT ON THE LAST ; STEP, SO THE REM LINES UP PROPERLY WITH ; THE DVR FOR THE SUBTRACTION (THOUGH THEIR ; EXPONENTS SEEM TO DIFFER BY ONE). AND THE ; DIV ALGORITHM GUARANTEES THAT THE REM IT ; LEAVES IS LESS THAN THE DVR, SO THERE CAN ; BE NO CARRY OUT. ;----------------------------------------------------------- REMPOSTRESTORING: BTST #0,D5 ; LOW QUO BIT BEQ.S REMQUO ; 0 --> JUST STUFF QUO TST.L D1 BNE.S @3 ; CASE 3 TST.L D2 BNE.S @3 ; CASE 3 BTST #1,D5 ; CASE 2 DECIDED ON LO INT BEQ.S @5 ; IF EVEN, LEAVE QUO BUT SET REM @3: BCHG #7,D6 ; FLIP REM SIGN ADDQ.W #2,D5 ; INCREMENT QUO BY 1 (IN SECOND BIT) @5: EXG D2,A2 ; SWAP DVR AND REM EXG D1,D3 SUB.L A2,D2 ; DVR - REM SUBX.L D3,D1 ;----------------------------------------------------------- ; NOW EXTRACT LOW 7 INTEGER BITS (REMEMBER GOT FIRST FRAC), ; NEGATE IF NECESSARY, EXTEND TO WORD, AND STORE. ;----------------------------------------------------------- REMQUO: LSR.B #1,D5 ; KILL FRAC BIT BTST #6,D6 ; TEST QUO SIGN BEQ.S @9 NEG.B D5 @9: EXT.W D5 ; EXTEND SIGNED BYTE TO WORD MOVE.W D5,6(SP) ; STORE IN SAVED D0.W MOVE.L D1,D4 ; STUFF REM BITS MOVE.L D2,D5 REMFIN: MOVEQ #0,D7 ; zero stickies BRA ZNORMCOERCE ; STORE THE RESULT ;----------------------------------------------------------- ; ASSUME FUNNY REGISTER MASK: RESTORING-DIVISION ; D0 - QUO BIT COUNT ; D1,2 - DIVIDEND CUM REMAINDER ; D3,A2 - DIVISOR (CAN ADD, NOT ADDX FROM A-REG) ; D4,5 - WILL BE QUOTIENT ;----------------------------------------------------------- RESTORE: MOVEQ #0,D4 ; CLEAR QUOTIENT MOVE.L D4,D5 BRA.S @2 ; SKIP SHIFT ON 1ST STEP @1: ADD.L D5,D5 ; SHIFT QUO ADDX.L D4,D4 ; IGNORE CARRY ON LAST STEP ADD.L D2,D2 ; SHIFT REM ADDX.L D1,D1 BCS.S @4 ; HAVE TO SUBTRACT @2: CMP.L D3,D1 ; DVD.HI - DVR.HI BNE.S @3 CMP.L A2,D2 @3: BCS.S @5 ; SKIP SUB IF DVD < DVR @4: ADDQ.B #1,D5 ; SET QUO BIT (NO CARRY) SUB.L A2,D2 SUBX.L D3,D1 @5: SUBQ.W #1,D0 ; LOOP COUNT BNE.S @1 RTS ;----------------------------------------------------------- ; Remainder algorithm using DIV32 subroutine handles larger ; exponent differences much faster than RESTORE algorithm. ; ; D2/D3/D1: dividend/shifted remainder (96 bits) ; D4/D5: divisor ; D0/D6/D7: scratch ; A1: loop count ;----------------------------------------------------------- REMSHIFT: MOVEA.L D6,A3 ; A3 <- D6 value MOVE.L A1,D3 ; D3 <- dividend.HI MOVE.L A2,D1 ; D1 <- dividend.LO MOVEQ #0,D2 ; D2 <- 0 MOVEA.L D0,A2 ; A2 <- shift count (∆EXP + 1) ANDI.L #$1F,D0 ; D0 <- alignment shift count (0 to 31 possible) BEQ.S @1 ; if zero, do first DIV32 ; shift dividend in D3/D1 left into D2/D3/D1 BFEXTU D3{0:D0},D2 ; shift bits from D3 high to D2 low LSL.L D0,D3 ; shift D3 left BFEXTU D1{0:D0},D6 ; extract D1 high bits LSL.L D0,D1 ; shift D1 left OR.L D6,D3 ; insert extracted D1 bits into shifted D3 ;----------------------------------------------------------- ; Do initial division of D2:D3:D1 by D4/D5. 32-bit quotient in ; D0, remainder (shifted by 32 bits) in D2/D3. ;----------------------------------------------------------- @1: BSR DIV32 ;----------------------------------------------------------- ; Remaining number of REM steps, if any, are done 32 at a time, ; using DIV32. Final D0 value is lowest 32 bits of the ; quotient, and the REM result is in D2/D3. ;----------------------------------------------------------- MOVE.L A2,D6 ; Get number of remaining 32-bit steps BFEXTU D6{16:11},D6 BEQ.S REMDIVDONE ; If zero, clean up MOVE.L D6,A1 ; A1 <- # OF 32-bit REM steps MOVEQ #0,D1 ; zero trailing remainder bits REMLP32: BSR DIV32 SUBQ.L #1,A1 MOVE.L A1,D6 BNE.S REMLP32 REMDIVDONE: MOVE.L D2,D1 ; remainder to D1/D2 MOVE.L D3,D2 MOVE.L D4,D3 ; divisor to D3/A2 MOVEA.L D5,A2 MOVE.L D0,D5 ; quotient to D5 MOVE.L A3,D6 ; restore A6 BRA REMPOSTRESTORING ; finish up REM ;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPCMP ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 03JUL82: WRITTEN BY JEROME COONEN ; 12AUG82: TIDIED UP (JTC) ; 12DEC82: PROJ MODE OUT (JTC) ; ; WITH ALL NUMBERS NORMALIZED, COMPARISONS ARE QUITE EASY. ; THE TRICK IS TO PICK UP THE UNORDERED CASES FROM NAN ; COERCIONS AND TO AVOID FLOATING COERCIONS (SINCE THE ONLY ; RESULT IS A CCR VALUE). ;----------------------------------------------------------- ;----------------------------------------------------------- ; DO A JSR RATHER THAN JMP TO SPECIAL CASE ROUTINES IN ORDER ; TO TIDY UP END CASES: EXPECT CCR SETTING IN D0.W. ; AT END: MOVE FROM D0.LO TO D7.HI AND SIGNAL INVALID ; IN CMPX ON UNORD. ;----------------------------------------------------------- CMPTOP: MOVE.W CMPCASE(D3),D3 JSR CMPTOP(D3) CMPFIN: ; PICK UP HERE FROM NANS CMPI.W #CMPU,D0 ; UNORDERED? BNE.S @1 BTST #OPIFCPX+16,D6 ; CHECK WHETHER TO BARF BEQ.S @1 BSET #ERRI+8,D6 @1: MOVE.W D0,D7 ; ALIGN CCR BITS IN D7.HI SWAP D7 RTS CMPCASE: ; DST - SRC DC.W CMPNUM - CMPTOP ; NUM - NUM DC.W CMPS0 - CMPTOP ; NUM - 0 DC.W CMPD0 - CMPTOP ; NUM - INF DC.W CMPD0 - CMPTOP ; 0 - NUM DC.W CMP0 - CMPTOP ; 0 - 0 DC.W CMPD0 - CMPTOP ; 0 - INF DC.W CMPS0 - CMPTOP ; INF - NUM DC.W CMPS0 - CMPTOP ; INF - 0 DC.W CMPINF - CMPTOP ; INF - INF ;----------------------------------------------------------- ; NUM VS. 0: DISGUISE AS (0 VS. -NUM) AND FALL THROUGH. ;----------------------------------------------------------- CMPS0: ADD.B D6,D6 ; DST SGN -> SRC SLOT NOT.B D6 ;----------------------------------------------------------- ; 0 VS. NUM: SIGN OF NUM DETERMINES >. ;----------------------------------------------------------- CMPD0: MOVEQ #CMPG,D0 ; ASSUME > TST.B D6 ; TST SRC SIGN BMI.S @1 MOVEQ #CMPL,D0 ; 0 < POSITIVE @1: RTS ;----------------------------------------------------------- ; INF VS. INF: EITHER =, OR SAME AS 0 VS. NUM. ;----------------------------------------------------------- CMPINF: BTST #5,D6 ; EQ -> SIGNS = BNE.S CMPD0 CMP0: MOVEQ #CMPE,D0 RTS ;----------------------------------------------------------- ; NUM VS. NUM: IF SIGNS DIFFER, SAME AS 0 VS. NUM. ; IF SAME JUST COMPARE THE WORDS, TAKING ACCOUNT FOR COMMON ; SIGN. ;----------------------------------------------------------- CMPNUM: BTST #5,D6 ; NE -> TRIVIAL BNE.S CMPD0 CMPA.L A4,A3 ; DST - SRC EXP'S BGT.S @1 BLT.S @2 CMPA.L D4,A1 ; DST.HI - SRC.HI BHI.S @1 ; HI -> UNSIGNED GREATER BCS.S @2 ; CS -> UNSIGNED LESS CMPA.L D5,A2 BEQ.S CMP0 ; THEY ARE = BCS.S @2 ;----------------------------------------------------------- ; THEY'RE > UNLESS NEGATIVE. ;----------------------------------------------------------- @1: NOT.B D6 ;----------------------------------------------------------- ; THEY'RE < UNLESS NEGATIVE. ;----------------------------------------------------------- @2: MOVEQ #CMPL,D0 TST.B D6 BPL.S @21 MOVEQ #CMPG,D0 @21: RTS ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPCVT ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 03JUL82: WRITTEN BY JEROME COONEN ; 12AUG82: TIDIED UP (JTC) ; 13OCT82: CHANGE INVALID SIGNALS ON EXT --> COMP (JTC). ; 28DEC82: FIX CASE OF LEFT SHIFT IN IALIGN (JTC). ; 29DEC82: FIX BUG IN FORCING CHOP MODE. (JTC) ; 30DEC82: UNFIX 28DEC82 FIX -- UNNECESSARY (JTC). ; ;----------------------------------------------------------- ;----------------------------------------------------------- ; CONVERSIONS TO EXTENDED ARE TRIVIAL, REQUIRING COERCION ; ONLY FOR FINITE, NONZERO VALUES ;----------------------------------------------------------- CVT2E: TST.W D3 ; IS IT 0 OR INF? BEQ COERCE ; COERCE IF NOT RTS ;----------------------------------------------------------- ; ROUND TO INTEGER REQUIRES RIGHT ALIGNMENT FOR TINIES, ; NOTHING FOR LARGE, 0, OR INF VALUES ;----------------------------------------------------------- RINT: TST.W D3 ; 0 OR INF? BEQ.S @1 RTS ; SKIP IF 0 OR INF @1: BSR.S IPALIGN ; ALIGN BIN PT AT RIGHT MOVEA.W (A0),A2 ; SAVE MODES, ARTIFICIALLY BRA.S COMINT ;----------------------------------------------------------- ; TRUNC TO INTEGER REQUIRES RIGHT ALIGNMENT FOR TINIES, ; NOTHING FOR LARGE, 0, OR INF VALUES ;----------------------------------------------------------- TINT: TST.W D3 ; 0 OR INF? BEQ.S @1 RTS ; SKIP IF 0 OR INF @1: ;----------------------------------------------------------- ; NOW FAKE CHOP MODE BITS, BUT BE CAREFUL NOT TO LOSE ; ERROR FLAGS OR OLD MODE. ; BUG: CHOP CHANGED FROM 01 TO 11 AT LAST MINUTE IN DESIGN, ; BUT CHANGE WAS MISSED HERE. ;----------------------------------------------------------- BSR.S IPALIGN ; ALIGN BIN PT AT RIGHT MOVEA.W (A0),A2 ; SAVE MODES ETC. BSET #RNDHI,(A0) ; CHOP = 11 BSET #RNDLO,(A0) COMINT: BSR COERCE ; COERCE, MAYBE 0 MOVE.W A2,(A0) ; RECALL MODES ;----------------------------------------------------------- ; AFTER COERCE MAY HAVE 0, UNNORM, OR NORMALIZED. ;----------------------------------------------------------- TST.L D4 ; IF NORMALIZED, ALL SET BMI.S @9 BNE.S @5 TST.L D5 BNE.S @5 SUBA.L A4,A4 ; SET TO 0 RTS @5: SUBQ.L #1,A4 ADD.L D5,D5 ADDX.L D4,D4 BPL.S @5 @9: RTS ;----------------------------------------------------------- ; IPALIGN SETS UP BINARY POINT NO FURTHER RIGHT THAN 24, ; 53, 64 BITS AS SPECIFIED BY THE COERCION INFO. ;----------------------------------------------------------- IPALIGN: TST.L D6 ; IS IT SINGLE? (#SPREC) BMI.S @1 BTST #DPREC+16,D6 ; IS IT DOUBLE? BEQ.S IALIGN ; USUAL EXTD CASE MOVEQ #52,D0 BRA.S FINALIGN @1: MOVEQ #23,D0 BRA.S FINALIGN IALIGN: MOVEQ #63,D0 FINALIGN: ADDI.W #$3FFF,D0 MOVE.W D0,D1 ; SAVE POSSIBLE NEW EXP SUB.L A4,D0 ; INTEXP - EXP BGT.S @7 RTS ; RETURN LE IF TOO BIG @7: MOVEA.W D1,A4 ; PLACE NEW EXP BSR RTSHIFT MOVE #0000,CCR ; FUDGE CCR = GT RTS ;----------------------------------------------------------- ; CONVERSIONS FROM EXTENDED ARE MORE COMPLICATED, IF THE ; RESULT IS INTXX OR COMP64, BECAUSE OF THE OVERFLOW CASES. ;----------------------------------------------------------- CVTE2: BTST #DSTINT+16,D6 ; 1 -> INTEGER BEQ.S CVT2E ; AS ABOVE FOR FLOATS ;----------------------------------------------------------- ; FIRST BYPASS O, INF CASES. ;----------------------------------------------------------- CMPI.W #2,D3 ; 2 -> ZERO, DONE BNE.S @2 RTS @2: CMPI.W #4,D3 ; 4 -> INF -> OFLOW BNE.S @4 MOVEQ #-1,D4 ; ENSURE OVERFLOW FOUND BRA.S IOFLOW ;----------------------------------------------------------- ; USE IALIGN TO PUT BIN PT TO RIGHT OF D5, RETURNING LE IF ; INTEGER OVERFLOW (NO SPECIAL HANDLING REQUIRED SINCE THE ; VALUE IS ASSURED TO BE NORMALIZED, FORCING OVERFLOW). ;----------------------------------------------------------- @4: BSR.S IALIGN BLE.S IOFLOW ; MUST HAVE LEADING ONE ;----------------------------------------------------------- ; SET UP CALL TO ROUND AS THOUGH RESULT IS EXT. SINCE LEAD ; BIT IS 0, ROUNDING CANNOT CARRY OUT AND MODIFY EXP. ;----------------------------------------------------------- MOVEQ #0,D1 ; PUT EXT INC INFO MOVEQ #1,D2 BTST #0,D5 ; GET NOT LSB TO Z FOR ROUND BSR ROUND ;----------------------------------------------------------- ; NOW CHECK THE HORRENDOUS CASES FOR INTEGER OVERFLOW, ; FOR EACH OF THE THREE FORMATS. ; FORMAT CODES: 4-INT16 5-INT32 6-COMP64 ; LET INTXX CASES SHARE CODE. ;----------------------------------------------------------- IOFLOW: MOVEQ #1,D1 ; $80000000 --> D1 ROR.L #1,D1 BTST #DSTLO+16,D6 ; CHECK FOR INT32 BNE.S @21 BTST #DSTMD+16,D6 ; CHECK FOR COMP64 BNE.S @41 SWAP D1 ; $00008000 --> D1 @21: TST.L D4 ; ANY HI BITS? BNE.S @25 CMP.L D1,D5 ; BIGGEST MAGNITUDE BHI.S @25 BCS.S @23 ; NO OFLOW TST.B D6 ; IS IT NEGATIVE? BPL.S @25 ; NO, OFLOW @23: TST.B D6 ; NEGATIVE INTEGER? BPL.S @24 NEG.L D5 ; NEGATE ALL 64 BITS NEGX.L D4 @24: RTS @25: MOVE.L D1,D5 @27: BSET #ERRI+8,D6 BCLR #ERRX+8,D6 ; CLEAR INEXACT IF INVALID RTS @41: TST.L D4 ; JUST CHECK LEAD BIT BPL.S @23 MOVEQ #0,D5 MOVE.L D1,D4 ; D1 IS $80000000 BRA.S @27 ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPSQRT ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 03JUL82: WRITTEN BY JEROME COONEN ; 12AUG82: TIDIED UP (JTC) ; 12DEC82: PROJ MODE OUT (JTC) ; 29JAN90: MODIFIED FOR MC68020 SANE (JPO) ;----------------------------------------------------------- SQRTTOP: CMPI.W #2,D3 ; IS THE OPERAND 0? BNE.S @1 RTS ; ROOT(+-0) = +-0 @1: MOVEQ #NANSQRT,D0 ; CODE BYTE, JUST IN CASE TST.B D6 ; NEGATIVE, POSSIBLY INF? BMI INVALIDOP ; WHETHER NUM OR INF CMPI.W #4,D3 ; IS THE OPERAND +INF? BNE.S @10 RTS ; ROOT(AFF +INF) = +INF @10: ;-------------------------------------------------------------------- ; Square root of a normalized positive extended number is evaluated ; using a modified version of the K. C. Johnson algorithm. This bit ; chop method attempts to find the largest extended number whose square ; is no larger than the radicand (operand). The rood is evaluated to ; 65 bits in order to determine the rounding bit, and the sticky bit is ; obtained from any residual remainder. ; ; The basic register mask is: ; radicand/remainder significand: D1.B D2 D3 ; square root exponent: A4.W ; square root significand: D0.B D4 D5 ; loop: bit mask/counter D6 ; scratch: D7 ; D6 save register: A3 ; ; First step is to halve the exponent and adjust the bias, keeping ; track of whether the true exponent is odd or even. Cases, after ; right shift are: ; C=1---(2K) + $3FFF -> K + 1FFF, so rebias by $2000 ; C=0---(2K + 1) + $3FFF -> K + 2000, so rebias by $1FFF ; and shift radicand 1 extra bit left. ;-------------------------------------------------------------------- MOVE.W A4,D0 ; divide exponent by 2 ASR.W #1,D0 MOVE SR,D7 ; save carry for later BCC.S @2 ADDQ.W #1,D0 @2: ADDI.W #$1FFF,D0 ; rebias MOVEA.W D0,A4 ; store result exponent ;-------------------------------------------------------------------- ; Initialize radicand for rooting. Use A3 as temp for D6 ;-------------------------------------------------------------------- MOVEA.L D6,A3 MOVE.L D5,D3 ; radicand in D2/D3 initially MOVE.L D4,D2 ;-------------------------------------------------------------------- ; Now shift radicand to align binary point between D0 and D2. ; Requires 1 shift for even exp, 2 shifts for odd, for which ; we saved flags above in D7. ;-------------------------------------------------------------------- ADD.L D3,D3 ADDX.L D2,D2 MOVEQ #1,D1 MOVE D7,CCR ; CARRY=0 -> odd exp -> extra shift BCS.S @4 ADD.L D3,D3 ADDX.L D2,D2 ADDX.W D1,D1 ;-------------------------------------------------------------------- ; Now initialize remainder by subtracting 1 from D1.B ;-------------------------------------------------------------------- @4: SUBQ.W #1,D1 ;-------------------------------------------------------------------- ; Initialize root in D0.B (low bit only), D4/D5. After J ; iterations of the bit chop loop, these 65 bits will hold: ; 0, followed by 64 - J zeros. ; At the end of each iteration, bit J+1 (from MSB) is evaluated: ; 0, followed by 63 - J zeros. ; ; Since the root will be normalized, we can bypass the first iteration ; of the loop and initialize the root for the second iteration: ; D0 <- 1, D4 <- 0, AND D5 <- 0. ;-------------------------------------------------------------------- MOVEQ #1,D0 MOVEQ #0,D4 MOVE.L D4,D5 ;-------------------------------------------------------------------- ; Initialize bit mask D6 to $40000000 ;-------------------------------------------------------------------- MOVE.L #$40000000,D6 BRA.S @8 ; branch into loop ;-------------------------------------------------------------------- ; Top of loop for high longword (D4) ;-------------------------------------------------------------------- @6: ADD.L D3,D3 ; double remainder ADDX.L D2,D2 ADDX.W D1,D1 @8: OR.L D6,D4 ; create 01000.... ;-------------------------------------------------------------------- ; Try remainder - root (short version since D5 = 0) ;-------------------------------------------------------------------- SUB.L D4,D2 SUBX.W D0,D1 BCC.S @11 ; no carry -> new root bit = 1 ADD.L D4,D2 ; carry -> new root bit = 0 ADDX.W D0,D1 ; restore previous positive remainder EOR.L D6,D4 ; clr final 1 bit in D4 BRA.S @12 @11: ADD.L D6,D4 @12: LSR.L #1,D6 ; shift mask bit right for next iteration BCC.S @6 ;-------------------------------------------------------------------- ; Evaluate 33rd bit by brute force (transition between D4 and D5). ; Set D6 = $80000000. ;-------------------------------------------------------------------- MOVE.L #$80000000,D6 ; D6 <- $80000000 ADD.L D3,D3 ; double remainder ADDX.L D2,D2 ADDX.W D1,D1 SUB.L D6,D3 ; remainder - root SUBX.L D4,D2 SUBX.W D0,D1 BCC.S @14 ; no carry; set D4 bit 0 ADD.L D6,D3 ; carry; restore positive remainder ADDX.L D4,D2 ADDX.W D0,D1 BRA.S @16 ; D4 bit 0 remains clear @14: ADDQ.W #1,D4 ;-------------------------------------------------------------------- ; Quick exit if remainder after 33 bits is zero ;-------------------------------------------------------------------- @16: MOVE.L D3,D7 ; current remainder zero? OR.W D1,D7 OR.L D2,D7 BNE.S @18 ; no; do 33 more bits (inexact with sticky set) LSR.W #1,D0 ; yes; shift result into D4/D5 ROXR.L #1,D4 ROXR.L #1,D5 BRA.S ROOTDONE ; finish up SQRT with round/stickies clear ;-------------------------------------------------------------------- ; Set up for 34th-64th bits of root (D5 bits 31 through 1) ;-------------------------------------------------------------------- @18: ROR.L #1,D6 ; bit mask (D6) = $40000000 ;-------------------------------------------------------------------- ; Loop for root bits 31 through 1 in D5 ;-------------------------------------------------------------------- @20: ADD.L D3,D3 ; double remainder ADDX.L D2,D2 ADDX.W D1,D1 OR.L D6,D5 ; create 010000... SUB.L D5,D3 ; remainder - root (wider subtraction) SUBX.L D4,D2 SUBX.W D0,D1 BCC.S @22 ; no carry; new root bit = 1 ADD.L D5,D3 ; carry; restore positive remainder ADDX.L D4,D2 ADDX.W D0,D1 EOR.L D6,D5 ; zero trailing 1 bit in D5 BRA.S @24 ; new root bit remains clear @22: ADD.L D6,D5 @24: LSR.L #1,D6 ; update bit mask BCC.S @20 ;-------------------------------------------------------------------- ; Evaluate round bit by brute force. First shift root 1 bit right ; into D4/D5. Next force the setting of the X bit. Then subtract ; (with extend) D7(zero)/D4/D5 from unshifted remainder in D1/D2/D3. ; Set round bit if no carry results. Sticky bits will always be set ; because root is irrational. ;-------------------------------------------------------------------- MOVEQ #0,D7 ; clr D7 ADDQ.W #1,D5 ; set lowest bit LSR.W #1,D0 ; shift 64-bit root into D4/D5, ROXR.L #1,D4 ; setting X bit on final shift ROXR.L #1,D5 SUBX.L D5,D3 ; subtract root from unshifted remainder SUBX.L D4,D2 ; with initial borrow SUBX.W D7,D1 BCS.S @26 ; carry -> round bit is zero MOVE.W #$8000,D7 ; no carry -> round bit is one @26: ADD.W #$00FF,D7 ; set sticky bits ROOTDONE: MOVE.L A3,D6 ; restore D6 BRA COERCE ; coerce result ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPSLOG ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 28DEC82: BUILT FROM SQRT BY JEROME COONEN ; 29APR83: CLASS ADDED (JTC) ; 09JUN83: PRESERVE A5,A6 (JTC) ; 30JAN90: MODIFIED FOR MC68020 SANE (JPO) ;----------------------------------------------------------- LOGBTOP: CLR.B D6 ; SIGN IS IRRELEVANT CMPI.W #2,D3 ; IS THE OPERAND +-0? BNE.S @1 ;----------------------------------------------------------- ; LOGB(+-0) --> DIV BY ZERO --> ERROR BIT, STUFF -INF, RET. ;----------------------------------------------------------- ORI.W #$0880,D6 ; POOR MAN'S BSET'S MOVEA.W #$7FFF,A4 ; BIG EXP MOVEQ #0,D4 ; ZERO DIGS MOVE.L D4,D5 RTS @1: CMPI.W #4,D3 ; IS THE OPERAND +-INF? BNE.S @10 ;----------------------------------------------------------- ; LOGB(+-INF) --> +INF --> RET. ;----------------------------------------------------------- RTS ;----------------------------------------------------------- ; LOGB(finite and nonzero) --> exponent, normalized as a ; floating-point number. Never exceptional. Uses fast ; normalization. ;----------------------------------------------------------- @10: MOVEQ #0,D5 ; clear the low significant bits SUBA.W #$3FFF,A4 ; unbias exponent MOVE.L A4,D4 ; move as integer BGT.S @12 ; positive BLT.S @11 ; negative RTS ; zero @11: ORI.B #$80,D6 ; negative; set sign NEG.L D4 ; magnitude of value @12: MOVEA.W #$401E,A4 ; exponent = 31, biased BFFFO D4{0:0},D0 ; find first one bit in D4 LSL.L D0,D4 ; shift left to normalize SUBA.W D0,A4 ; adjust exponent RTS ;----------------------------------------------------------- ; SCALB BEHAVES MUCH LIKE LOGB, EXCEPT THAT THE INTEGER ; ARGUMENT MUST BE PULL FROM ITS SOURCE LOCATION, IT IS ; MORE CONVENIENT NOT TO UNPACK THE INPUT INTEGER TO ; FLOATING-POINT FORM. COUNT ON INTEGER'S ADDRESS IN ; LKADR2(A6). ; EASY CASES -- SCALB(N, ZERO/INF/NAN) --> ZERO/INF/NAN. ;----------------------------------------------------------- SCALBTOP: TST.W D3 ; IS THE OPERAND +-0, +-INF? BEQ.S @1 RTS ;----------------------------------------------------------- ; JUST ADD THE INTEGER ADJUSTMENT INTO THE EXPONENT IN A4, ; AND CHECK FOR OVER/UNDERFLOW. ;----------------------------------------------------------- @1: MOVEA.L LKADR2(A6),A3 ; SRC ADDRESS ADDA.W (A3),A4 BRA COERCE ;----------------------------------------------------------- ; CLASS PLACES INTEGER CODE AT DST ADDRESS. THE CODE TIES ; IN USEFULLY WITH THE PASCAL ENUMERATED TYPES IN SANE. ; IT IS THE SANE VALUE PLUS ONE, WITH THE SIGN OF THE INPUT ; OPERAND. IN SANE, THE SIGN IS PLACED IN A SEPARATE INT. ; THE VALUES ARE THUS: ; SNAN 1 ; QNAN 2 ; INF 3 ; ZERO 4 ; NORMAL 5 ; DENORM 6 ;----------------------------------------------------------- CLASSTOP: MOVEQ #5,D0 ; ASSUME NORMAL NUMBER TST.L D3 ; CHECK FOR DENORM BMI.S @98 ; possible subnormal BEQ.S CLASSFIN SUBQ.W #2,D0 ; ASSUME INF CMPI.W #4,D3 ; INF CODE BEQ.S CLASSFIN BRA.S @99 ; otherwise, zero @98: ; possible subnormal MOVE.W LKOP(A6),D1 ; isolate format ANDI.W #$1800,D1 BNE.S @99 ; subnormal if single or double classify MOVE.L A4,D1 ; subnormal if exponent is negative BPL.S CLASSFIN ; otherwise, normal @99: ADDQ.W #1,D0 ; subnormal; code value is 6 CLASSFIN: TST.B D6 ; NONZERO -> NEGATIVE BEQ.S @100 NEG.W D0 @100: MOVEA.L LKADR1(A6),A3 MOVE.W D0,(A3) RTS ;----------------------------------------------------------- ;----------------------------------------------------------- ; old FPODDS ;----------------------------------------------------------- ;----------------------------------------------------------- ;----------------------------------------------------------- ; 05JUL82: WRITTEN BY JEROME COONEN ; 27APR83: NEGATE, ABS, COPYSIGN ADDED. (JTC) ; 02MAY83: NEXTAFTER ADDED. (JTC) ; 04MAY83: SETXCP ADDED. (JTC) ; 09JUN83: A5,A6 PRESERVED. ; 09JUL83: ENTRY/EXIT, TESTXCP ADDED. (JTC) ; 30JAN90: MODIFIED FOR MC68020 SANE. (JPO) ; ; FOR CONVENIENCE, MOVE DST->A1, SRC->A2 TO HAVE POINTERS. ; ; JUMP TO MISCELLANEOUS ROUTINE BASED ON INDEX IN OPCODE IN ; D6. DEPEND ON REGISTER MASK: ODDBALLS WITH STATE POINTER ; IN A0 AND ONE OPERAND ADDRESS IN A1. ; AT END, MUST JUMP TO FINISHUP SEQUENCES POPX, AS ; APPROPRIATE. ;----------------------------------------------------------- ODDBALL: MOVEM.L LKADR1(A6),A1-A2 ; GET DST, SRC ADRS MOVE.W ODDTAB(D7),D7 ; INDEX INTO TABLE JMP ODDBALL(D7) ; DO ODD-NUMBERED OP ;----------------------------------------------------------- ; JUMP FROM INDEX-1, AFTER CHECK FOR LEGITIMACY. ;----------------------------------------------------------- ODDTAB: DC.W PUTW - ODDBALL ; PUT STATE WORD DC.W GETW - ODDBALL ; GET STATE WORD DC.W PUTV - ODDBALL ; PUT TRAP VECTOR DC.W GETV - ODDBALL ; GET TRAP VECTOR DC.W D2B - ODDBALL ; DECIMAL TO BINARY DC.W B2D - ODDBALL ; BINARY TO DECIMAL DC.W NEGZ - ODDBALL ; NEGATE -- ANY FORMAT DC.W ABSZ - ODDBALL ; ABS -- ANY FORMAT DC.W CPSZ - ODDBALL ; COPY SIGN -- ANY FORMAT DC.W NEXTZ - ODDBALL ; NEXTAFTER: S, D, X DC.W SETXCP - ODDBALL ; SET EXCEPTION, HALT IF... DC.W ENTRYP - ODDBALL ; ENTRY PROTOCOL DC.W EXITP - ODDBALL ; EXIT PROTOCOL DC.W TESTXCP- ODDBALL ; TEST AN EXCEPTION. ;----------------------------------------------------------- ; THE STATE ROUTINES ARE TRIVIAL, AND ALL "RETURN" TO POP1. ;----------------------------------------------------------- PUTW: MOVE.W (A1),(A0) BRA POP1 ENTRYP: MOVE.W (A0),(A1) CLR.W (A0) BRA POP1 GETW: MOVE.W (A0),(A1) BRA POP1 PUTV: MOVE.L (A1),2(A0) BRA POP1 GETV: MOVE.L 2(A0),(A1) BRA POP1 NEGZ: BCHG #7,(A1) BRA POP1 ABSZ: BCLR #7,(A1) BRA POP1 ;----------------------------------------------------------- ; TEST AN EXCEPTION WHOSE INDEX IS (A1). SET BYTE (A1) TO ; 1 (TRUE) IF THE EXCEPTION IS SET, SET IT TO 0 (FALSE) IF ; N0T SET. ;----------------------------------------------------------- TESTXCP: MOVE.W (A1),D0 ; FETCH INPUT INDEX BTST D0,(A0) ; EXCEPTION BITS IN HI BYTE SNE D0 NEG.B D0 MOVE.B D0,(A1) ; RESULT CODE BRA POP1 ;----------------------------------------------------------- ; NOTE THAT COPYSIGN COPIES THE SIGN OF THE "DST" ARGUMENT ; ONTO THAT OF THE "SRC" ARGUMENT. ;----------------------------------------------------------- CPSZ: BTST #7,(A1) BEQ.S @1 BSET #7,(A2) BRA.S @2 @1: BCLR #7,(A2) @2: BRA POP2 ;----------------------------------------------------------- ; NEXTAFTER FUNCTION: BEHAVES LIKE NONARITHMETIC OPS, BUT ; MAY SET ERROR FLAGS, SO EXITS THROUGH CHKERR RATHER THAN ; POP2. CALLS REFP020 FOR COMPARE, MULTIPLY (NAN PRECEDENCE), ; CLASS, AND CONVERT. ; NOTE THAT NEXTAFTER CHANGES ITS *****SOURCE***** ARGUMENT ; IN THE DIRECTION OF THE DESTINATION ARGUMENT. ;----------------------------------------------------------- NEXTZ: ;----------------------------------------------------------- ; ON ENTRY, D6.W IS OPCODE, A1 IS DST, A2 IS SRC, A0 STATE. ; USE OTHER REGISTERS FREELY, BUT MUST ALIGN OPWORD IN D6.HI ; WITH PROPER MASK FOR EXIT THROUGH CHKERR. D6.L0 WILL HOLD ; ERROR FLAGS. MASK OF OPERAND FORMAT BITS INTO D5 FOR USE ; AS MASK FOR CALLING CONVERSION AND INC/DEC ROUTINES. ; STACK FRAME = (A4) = DST-EXT; INT; SRC-EXT ; ; Code modified to support 96-bit extended operands. <23 MAR 90; JPO> ; Added normalization of SRC operand, atomic exception ; signaling, and default rounding during calculation ; of NEXTAFTER values. <3 APR 90; JPO> ; ;----------------------------------------------------------- SUBA.W #22,SP ; NEED 2 EXTENDEDS AND 1 INTEGER MOVEA.L SP,A4 ; FRAME POINTER THROUGHOUT WHOLE FCN MOVE.W (A0),D3 ; save old environment in D3 for duration CLR.W (A0) ; set default environment MOVEQ #0,D2 ; zero D2 MOVE.W D6,D5 ; COPY OPCODE ANDI.W #$3800,D5 ; isolate format bits in D5 BNE.S @2 ; single or double format MOVE.B #$20,D2 ; isolate FPX96 bit in D2 AND.B D6,D2 BEQ.S @2 ; 80-bit extended MOVE.W (A2),2(A2) ; convert 96-bit SRC to 80-bit and ADDQ.L #2,A2 ; update pointer to latter @2: ADDQ.W #1,D6 ; SET #TWOADRS BIT CHEAPLY SWAP D6 ; ALIGN IN HI WORD, LIKE ARITH OPS CLR.W D6 ; ZERO FLAG AND SIGN BITS ;----------------------------------------------------------- ; CONVERT SRC TO EXTENDED ;----------------------------------------------------------- PEA (A2) ; SRC OPERAND ADDRESS PEA 12(A4) ; STACK FRAME ADDR MOVEQ #OP2EXT,D0 ; CONVERT TO 80-BIT EXT OPCODE OR.W D5,D0 ; ...WITH FORMAT MOVE.W D0,-(SP) BSR REFP020 TST.W D5 ; IF EXTENDED FORMAT, OVERWRITE BNE.S @3 ; SRC WITH CONVERTED SRC TO ; AVOID PROBLEM OF UNNORMALIZED VALUES MOVE.L 12(A4),(A2) MOVE.L 16(A4),4(A2) MOVE.W 20(A4),8(A2) ;----------------------------------------------------------- ; COMPARE SRC WITH ZERO. IF IT'S EQUAL, ADJUSTMENTS WILL ; BE MADE IN DECREMENT ROUTINES BELOW. ;----------------------------------------------------------- @3: BFEXTU 12(A4){1:15},D1 ; extract EXP field from SRC OR.L 14(A4),D1 ; OR in SIG.HI and SIG.LO OR.L 18(A4),D1 SNE D4 ; D4.BYTE IS 1'S IF SRC IS ZERO ;----------------------------------------------------------- ; CONVERT DST TO EXTENDED ;----------------------------------------------------------- PEA (A1) PEA (A4) OR.B D2,D0 ; may be 96-bit DST MOVE.W D0,-(SP) BSR REFP020 TST.B D2 ; if 96-bit DST, shrink to 80-bit BEQ.S @4 ; in stack frame MOVE.L 4(A4),2(A4) MOVE.L 8(A4),6(A4) ;----------------------------------------------------------- ; COMPARE THE TWO EXTENDED OPERANDS ;----------------------------------------------------------- @4: PEA (A4) ; DST OPERAND PEA 12(A4) ; SRC OPERAND MOVE.W #OPCMP,-(SP) BSR REFP020 ;----------------------------------------------------------- ; IF OVERFLOW IS SET, THE OPERANDS ARE UNORDERED, THAT IS, ; ONE OF THEM IS A NAN. USE THE MULTIPLY OPERATION TO FORCE ; THE PRECEDENT NAN (IF THERE ARE TWO) TO THE SRC ;----------------------------------------------------------- BVC.S NXORD PEA (A4) ; DST OPERAND PEA 12(A4) ; SRC OPERAND MOVE.W #OPMUL,-(SP) BSR REFP020 ;----------------------------------------------------------- ; NOW CONVERT THE PRECEDENT NAN BACK TO INPUT FORMAT. ;----------------------------------------------------------- PEA 12(A4) ; SRC OPERAND IS OUTPUT PEA (A2) ; SRC ADDRESS MOVEQ #OPEXT2,D0 ; CVT FROM 80-BIT EXT OPCODE OR.W D5,D0 ; OVERLAY THE FORMAT MOVE.W D0,-(SP) BSR REFP020 BRA NXFIN ;----------------------------------------------------------- ; GET HERE IF THE TWO OPERANDS ARE ORDERED. IF THEY ARE ; EQUAL, THERE IS NOTHING TO DO; OTHERWISE MUST INC OR DEC ; THE SRC OP AS APPROPRIATE. NOTE THE ONE *****FUNNY***** ; CASE: IF THE SRC IS ZERO, THEN ITS SIGN MAY BE MISLEADING. ; FOR INSTANCE, NEXT(-0, 3) SHOULD BE +0INC1. BUT THE MINUS ; SIGN ON 0 CAUSES A DEC TO BE ISSUED INSTEAD. THE FIX IS ; TO MAKE DEC SMART ENOUGH TO KNOW THAT IF 0 IS DEC-ED, THE ; SIGN SHOULD BE FLIPPED AND THE OPERAND SHOULD BE INC-ED ; INSTEAD. ;----------------------------------------------------------- NXORD: BEQ NXFIN BCC.S NXGREAT ;----------------------------------------------------------- ; GET HERE WHEN SRC < DST. INC IF SRC IS +, DEC IF - ;----------------------------------------------------------- BTST #7,(A2) ; SIGN BIT OF SRC OPERAND BEQ.S NXINC BRA NXDEC ;----------------------------------------------------------- ; GET HERE WHEN SRC > DST. DEC IF SRC IS +, INC IF - ;----------------------------------------------------------- NXGREAT: BTST #7,(A2) BEQ NXDEC ;----------------------------------------------------------- ; INCREMENT BY A UNIT IN THE LAST PLACE, ACCORDING TO THE ; FORMAT MASK IN D5. THE FORMAT IS IN BITS $3800. THE ONLY ; POSSIBLE CASES ARE: ; $1000 -- SINGLE ; $0800 -- DOUBLE ; $0000 -- EXTENDED ;----------------------------------------------------------- NXINC: ;----------------------------------------------------------- ; SINGLE CASE: ;----------------------------------------------------------- BTST #SRCMD,D5 ; TEST $1000 BIT BEQ.S @11 ADDQ.L #1,(A2) BRA.S NXERR ;----------------------------------------------------------- ; DOUBLE CASE: ;----------------------------------------------------------- @11: BTST #SRCLO,D5 ; TEST $0800 BIT BEQ.S @15 ADDQ.L #1,4(A2) BCC.S @13 ADDQ.L #1,(A2) @13: BRA.S NXERR ;----------------------------------------------------------- ; EXTENDED CASE: BE SURE OUTPUT INFINITY HAS LEADING 0 BIT. ;----------------------------------------------------------- @15: ADDQ.L #1,6(A2) BCC.S NXERR ADDQ.L #1,2(A2) BCC.S NXERR ROXR 2(A2) ADDQ.W #1,(A2) CMPI.W #$7FFF,(A2) BEQ.S @16 CMPI.W #$FFFF,(A2) BNE.S NXERR @16: BCLR #7,2(A2) ; Clr explicit bit in infinite result ;----------------------------------------------------------- ; TEST FOR EXCEPTIONS ACCORDING TO IEEE. NEXT(HUGE, INF) ; YIELDS INF WITH OVERFLOW AND INEXACT SIGNALED. ; NEXT(TINY, 0) YIELDS SOME DENORMAL WITH UNDERFLOW ; AND INEXACT. JUST SET THE APPROPRIATE BITS IN D6.LO AND ; EXIT AS THOUGH A TRUE ARITHMETIC OPERATION. THE FIRST ; STEP IS TO FIND THE CLASS OF THE INC/DEC-ED SRC OPERAND. ;----------------------------------------------------------- NXERR: PEA (A2) PEA 10(A4) ; ADDRESS OF INTEGER MOVEQ #OPCLASS,D0 OR.W D5,D0 MOVE.W D0,-(SP) BSR REFP020 ;----------------------------------------------------------- ; KILL THE SIGN OF THE CLASS RESULT AND PLACE IN REGISTER ; THE CODES ARE: ; 1 SNAN -- CAN'T HAPPEN ; 2 QNAN -- CAN'T HAPPEN ; 3 INF -- OVERFLOW AND INEXACT ; 4 ZERO -- UNDERFLOW AND INEXACT ; 5 NORMAL -- OK ; 6 DENORMAL -- UNDERFLOW AND INEXACT ;----------------------------------------------------------- MOVE.W 10(A4),D1 BPL.S @1 NEG.W D1 @1: ;----------------------------------------------------------- ; CHECK FOR INFINITE RESULT (WHICH MUST HAVE COME FROM FIN). ;----------------------------------------------------------- CMPI.W #CLINF,D1 BNE.S @3 ORI.W #ERRWXO,D6 ; SET INEXACT AND OVERFLOW BRA.S NXFIN @3: CMPI.W #CLNORM,D1 BEQ.S NXFIN ORI.W #ERRWXU,D6 ; SET INEXACT AND UNDERFLOW ;----------------------------------------------------------- ; EXIT THROUGH POINT IN FPCONTROL AFTER CLEANING STACK ;----------------------------------------------------------- NXFIN: ADDA.W #22,SP ; RESTORE STACK TST.B D2 ; if 96-bit extended result, BEQ.S @1 ; expand result MOVE.W (A2),-2(A2) @1: MOVE.W (A0),D7 ; D7 <- flags due to conversions MOVE.W D3,(A0) ; restore old environment OR.W D7,D6 ; OR all flags together MOVEQ #0,D0 ; clr D7 (will be CCR value) BRA CHKERR ;----------------------------------------------------------- ; DECREMENT, WATCHING FOR ZERO VALUE. BRANCH TREE IS LIKE ; THAT OF INC ABOVE. ;----------------------------------------------------------- NXDEC: BTST #SRCMD,D5 ; CHECK $1000 BIT FOR SINGLE BEQ.S @21 TST.B D4 ; D4.B IS NON0 IF OPERAND IS BNE.S @201 BCHG #7,(A2) ADDQ.L #1,(A2) BRA.S NXERR @201: SUBQ.L #1,(A2) BRA.S NXERR ;----------------------------------------------------------- ; DOUBLE CASE ;----------------------------------------------------------- @21: BTST #SRCLO,D5 ; CHECK $0800 BIT FOR DOUBLE BEQ.S @25 TST.B D4 ; D4.B IS NON0 IF OP IS BNE.S @211 BCHG #7,(A2) ADDQ.W #1,6(A2) BRA.S NXERR @211: SUBQ.L #1,4(A2) BCC.S @213 SUBQ.L #1,(A2) @213: BRA.S NXERR ;----------------------------------------------------------- ; EXTENDED CASE ;----------------------------------------------------------- @25: TST.B D4 BNE.S @251 BCHG #7,(A2) ADDQ.W #1,8(A2) BRA NXERR @251: SUBQ.L #1,6(A2) ; DEC LOW LONG BCC.S @259 ; NO C MEANS FINE SUBQ.L #1,2(A2) BMI.S @257 ; MAY HAVE BORROWED TST.W (A2) ; MIN EXP? BEQ.S @259 ; YES --> DONE CMPI.W #$8000,(A2) BEQ.S @259 ADDI.W #$8000,2(A2) BRA.S @258 @257: BCC.S @259 ; NO CARRY --> DONE @258: SUBQ.W #1,(A2) @259: BRA NXERR ;----------------------------------------------------------- ; SET EXCEPTION AND HALT IF ENABLED. SIMPLY SET THE ; SUITABLE BIT IN THE BYTE MASK $00001F00 IN D6 AND EXIT ; THROUGH FPCONTROL, AS THOUGH ARITHMETIC WERE PERFORMED. ;----------------------------------------------------------- SETXCP: SWAP D6 ; ALIGN IN HI WORD, LIKE ARITH OPS CLR.W D6 ; ZERO FLAG AND SIGN BITS MOVE.W (A1),D0 ; FETCH INPUT WORD INDEX ADDQ.W #8,D0 ; ALIGN TO SECOND BYTE BSET D0,D6 BRA CHKERR ; EXIT THROUGH FPCONTROL ;----------------------------------------------------------- ; RESTORE OLD ENVIRONMENT, AND CHECK CURRENT ERRS FOR HALT ;----------------------------------------------------------- EXITP: SWAP D6 ; ALIGN OPWORD, LIKE ARITH MOVE.W #$1F00,D6 ; SET UP FLAG MASK #ERRO ; #ERRU #ERRX #ERRI #ERRZ AND.W (A0),D6 ; SAVE CURRENT ERRORS MOVE.W (A1),(A0) ; RESTORE OLD STATE EPEXIT: BRA CHKERR ; EXIT VIA FPCONTROL