********************************************************************** * Floating Point Package 22/1/86 * * written by R.Soja, Motorola; modified for MC6801 by Tom Rogers * ********************************************************************** * All floating point routines use * * two, 3-byte operands located in RAM at OP1,OP2 * * Each is organised as: 7 bit exponent + 1 sign bit (2's complement)* * 15 bit mantissa + 1 sign bit * * (15 bit positive notation) * * Sign bit is always is always MSBit * * * * Routines implemented: * * 1. Addition MAD (FADD) OP1+OP2 * * 2. Subtraction MSB (FSUB) OP1-OP2 * * 3. Division MDV (FDIV) OP1/OP2 * * 4. Multiplication MML (FMUL) OP1*OP2 * * * * On exit from routine, OP1 contains result, OP2 is destroyed * * * * Two conversion routines are included: * * FLOATINT converts FP number in OP1 to unsigned integer in ACCD * * INTFLOAT converts unsigned integer in ACCD to FP number in OP1 * * An integer rounding subroutine (ROUND) is also included. * ********************************************************************** * * Note that NO ORG staements are included, as this package is intended to be * appended as a subroutine package to a main calling program. * RAM variables: * MANT1 DS.B 2 ;OP1 EXP1 DS.B 1 MANT2 DS.B 2 ;OP2 EXP2 DS.B 1 TEMP1 DS.B 2 ;used by routines TEMP2 DS.B 2 Y DS.B 2 ;substitute Y register QUOT DS.B 2 ;used by FDIV * * FP routines: MAD EQU * ;OP1 + OP2 => OP1 FADD EQU * BSR ALIGN BVS FADDEX ;If exponent difference too great, return. LDAA MANT1 ;Put sign bit of mantissa 1 in X reg. ANDA #$80 JSR XGDX LDAA MANT1 EORA MANT2 BMI SUBMANT ;If signs are same BSR GETABS ;then add positive parts of mantissas. ADDD MANT2 BPL FADD1 ;if MSBit of result set, then result has INC EXP1 ;overflowed, so increment exponent, while BVC FADD2 ;limiting value to upper bound. DEC EXP1 LDD #$7FFF BRA FADD1 FADD2 LSRD FADD1 STX MANT2 ;Save sign bit STD MANT1 ;and result, prior to JSR NORM ;normalising it. FADDEX RTS ;Return to calling program segment. SUBMANT BSR GETABS ;If signs are different, SUBD MANT2 ;then subtract positive parts of mantissas. BSR CONVFP ;Change 2s compl result to floating point format BRA FADD1 ;and store result (X contains corrected sign bit) * GETABS LDAA MANT2 ;Clear sign bits in MANT2 ANDA #$7F STAA MANT2 LDD MANT1 ;and MANT1 in ACCD ANDA #$7F RTS * MSB EQU * ;OP1 - OP2 => OP1 FSUB EQU * LDAA MANT2 ADDA #$80 ;Negate sign of mantissa 2 STAA MANT2 ;and perform addition BRA FADD * ALIGN CLRA LDAB EXP1 SUBB EXP2 BPL POS ;If EXP1 OP1 FDIV EQU * LDD MANT2 BEQ MAXRES ;Trap divide by 0 LDAA MANT1 EORA MANT2 BMI FDIV1 ;If signs are same CLR Y ;then result sign is positive CLR Y+1 ;( Y has result sign.) BRA FDIV2 FDIV1 LDX #$8000 STX Y ;else result sign is negative. FDIV2 LDAB EXP1 SUBB EXP2 BVC FDIV3 ;If V bit set then its an under/overflow, so STAA MANT1 ;! update result sign BCC MINRES ;! If C bit clear then force result to min limit BRA MAXRES ;! else force result to max limit, retaining sign FDIV3 STAB EXP1 ;Save result exponent LDX #16 ;Initialize shift counter JSR GETABS ;+ive part of MANT1 in D, +ive part of MANT2 in it COMPARE SUBD MANT2 ;Dividend minus divisor BCS RESTORE ;Borrow so need to restore dividend SEC ;else no borrow so set carry BRA SHIFT ;and go shift into quotient. RESTORE ADDD MANT2 ;Add divisor back to dividend CLC ;prep to shift a 0 SHIFT ROL QUOT+1 ;Shift 0 or 1 into quotient ROL QUOT LSLD ;Shift dividend left DEX ;All division done? BNE COMPARE ;not yet LDD QUOT ;else done so get quotient BPL FDIV4 ;If quot sign bit already clear, wrap up LSRD ;else open up sign bit INC EXP1 ;adjusting exponent. FDIV4 ADDD Y ;Update sign bit BRA NORM3 ;Ck. for -0, store result and return * MAXRES STAA TEMP1 ;Store A. LDAA MANT1 ;Maximise MSbyte of mantissa, retaining sign. ORAA #$7F STAA MANT1 LDAA TEMP1 ;Restore A. LDD #$FF7F ;Maximise LSbyte of mantissa, and exponent. STD MANT1+1 RTS * MINRES CLRA ;Result = 0 CLRB STD MANT1 CLR EXP1 RTS * MML EQU * ;OP1 * OP2 => OP1 FMUL EQU * LDAB EXP1 ;First, add exponents. ADDB EXP2 BVC FMUL1 ;If V bit is set then its an under/overflow, so STAA MANT1 ;! update result sign BCS MINRES ;! If C bit set then force result to min limit BRA MAXRES ;! else force result to max limit, retaining sign FMUL1 STAB EXP1 ;Store result exponent. LDAA MANT1 ;Evaluate result sign, and EORA MANT2 ;put it in X reg JSR XGDX STAA TEMP1 ;Store A. LDAA MANT1 ;Make both operands positive ANDA #$7F STAA MANT1 LDAA MANT2 ANDA #$7F STAA MANT2 LDAA TEMP1 ;Restore A. BSR CONVFPI ;Convert MANT1,MANT2 to unsigned integer format * ;!and return with result sign + MANT1 in Y reg LDAA MANT1 ;multiply MSbytes of mantissas. LDAB MANT2 MUL JSR XGDX ;Save 1st partial result in X LDAA MANT1+1 ;Cross multiply. LDAB MANT2 MUL ADCA #0 ;Round up and TAB CLRA ;restore weighting of partial result (in ACCD) STX MANT1 ;Add 1st and 2nd partial results ADDD MANT1 JSR XGDX ;Store updated partial result. STD TEMP1 ;Store D. LDD Y ;Restore MANT1 STD MANT1 LDD TEMP1 ;Restore D. LDAA MANT1 ;Cross multiply again. LDAB MANT2+1 MUL ADCA #0 ;Round up again. TAB CLRA ;Correctly weighted 3rd partial result now in ACCD STX MANT1 ;so add it to stored partial result. ADDD MANT1 BSR CONVIFP ;Convert integer in ACCD to FP format,and store. * ;Multiplication of LS bytes is unnecessary, as * ;the result will always overflow if both non-zero. RTS ;Return to calling program. * CONVFPI EQU * ;Enter with +ive MANT1,MANT2: result sign in X reg LSL MANT1+1 ;De-normalise both operands. ROL MANT1 LSL MANT2+1 ROL MANT2 LDD MANT1 CPX #0 ;Add result sign bit to ACCD BPL FPI1 ORAB #1 FPI1 JSR XGDY ;and save result sign+operand 1 in Y. RTS * CONVIFP EQU * LDX #0 STX MANT2 STD MANT1 ;Temporarily store result. JSR XGDY ;Move result sign bit LSRD ROR MANT2 ;to MANT2 before LDD MANT1 LSRD JSR NORM ;normalising result mantissa. IFP2 RTS ;Return with result stored in MANT1. * FLOATINT EQU * CLRB LDAA EXP1 ;If exponent <= 0 BGT FLTINT1 ;then clear ACCD and return. CLRA RTS FLTINT1 CLRA ;else LSL MANT1+1 ;adjust mantissa, destroying sign bit ROL MANT1 FLTINT2 LSL MANT1+1 ;then move mantissa into ACCD ROL MANT1 ROLB ROLA DEC EXP1 BNE FLTINT2 ;until exponent = 0 RTS * ROUND TST MANT1 ;Call IMMEDIATELY after FLOATINT if to be used. BPL ROUNDEX ;MANT1 has "leftover precision." ASL MANT1 ;If MSB of MANT1 is set, fraction >= .5 BPL ROUNDEX ;If next MSB set, fraction >= .75 ADDD #1 ;so increment D & return ROUNDEX RTS ;else just return. * INTFLOAT EQU * ;On entry, unsigned integer in ACCD LDX #0 ;Initialise result mantissa STX MANT1 CLR EXP1 ;and exponent. INTFLT1 LSRD ;Move integer to F.P. mantissa ROR MANT1 ROR MANT1+1 INC EXP1 ;adjusting exponent with every shift. CMPA #0 BNE INTFLT1 CMPB #0 BNE INTFLT1 ;When no more bits in ACCD ROR MANT1 ;clear sign bit as integer was always >=0 ROR MANT1+1 RTS * XGDX STD TEMP1 ;Store D STX TEMP2 ;and X. LDD TEMP2 ;Load D with X LDX TEMP1 ;and X with D. XGDXEX RTS * XGDY STD TEMP1 ;D in TEMP1 LDD Y ;Move Y STD TEMP2 ;to TEMP2. LDD TEMP1 ;Move D/TEMP1 STD Y ;to Y. LDD TEMP2 ;Put Y into D. XGDYEX RTS