-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFloat32.spin
969 lines (810 loc) · 79.5 KB
/
Float32.spin
1
''============================================================================='' Copyright (C) 2006-2007 Parallax, Inc. All rights reserved '''' @file Float32'' @target Propeller'''' IEEE 754 compliant 32-bit floating point math routines.'' This object supports the basic set of floating point routines using one cog.'''' ──Float32'''' @author Cam Thompson, Micromega Corporation '' @version'' V1.2 - March 26, 2007'' - fixed Pow to handle negative base values'' V1.1 - Oct 5, 2006'' - corrected constant value for Radians and Degrees'' V1.0 - May 17, 2006'' - original version''=============================================================================CON FAddCmd = 1 << 16 FSubCmd = 2 << 16 FMulCmd = 3 << 16 FDivCmd = 4 << 16 FFloatCmd = 5 << 16 FTruncCmd = 6 << 16 FRoundCmd = 7 << 16 FSqrCmd = 8 << 16 FCmpCmd = 9 << 16 SinCmd = 10 << 16 CosCmd = 11 << 16 TanCmd = 12 << 16 LogCmd = 13 << 16 Log10Cmd = 14 << 16 ExpCmd = 15 << 16 Exp10Cmd = 16 << 16 PowCmd = 17 << 16 FracCmd = 18 << 16 FModCmd = 19 << 16 SignFlag = $1 ZeroFlag = $2 NaNFlag = $8 VAR long cog long command, cmdReturn PUB start : okay'' start floating point engine in a new cog'' returns false if no cog available stop okay := cog := cognew(@getCommand, @command) + 1PUB stop'' stop floating point engine and release the cog if cog cogstop(cog~ - 1) command~ PUB FAdd(a, b) 'return sendCmd(FAddCmd + @a) command := FAddCmd + @a repeat while command return cmdReturn PUB FSub(a, b) 'return sendCmd(FSubCmd + @a) command := FSubCmd + @a repeat while command return cmdReturn PUB FMul(a, b) 'return sendCmd(FMulCmd + @a) command := FMulCmd + @a repeat while command return cmdReturn PUB FDiv(a, b) 'return sendCmd(FDivCmd + @a) command := FDivCmd + @a repeat while command return cmdReturnPUB FFloat(n) 'return sendCmd(FFloatCmd + @a) command := FFloatCmd + @n repeat while command return cmdReturn PUB FTrunc(a) 'return sendCmd(FTruncCmd + @a) command := FTruncCmd + @a repeat while command return cmdReturn PUB FRound(a) 'return sendCmd(FRoundCmd + @a) command := FRoundCmd + @a repeat while command return cmdReturn PUB FSqr(a) 'return sendCmd(FSqrCmd + @a) command := FSqrCmd + @a repeat while command return cmdReturn PUB FCmp(a, b) 'return sendCmd(FCmpCmd + @a) command := FCmpCmd + @a repeat while command return cmdReturnPUB Sin(a) 'return sendCmd(SinCmd + @a) command := SinCmd + @a repeat while command return cmdReturn PUB Cos(a) 'return sendCmd(CosCmd + @a) command := CosCmd + @a repeat while command return cmdReturn PUB Tan(a) 'return sendCmd(TanCmd + @a) command := TanCmd + @a repeat while command return cmdReturnPUB Log(a) 'return sendCmd(LogCmd + @a) command := LogCmd + @a repeat while command return cmdReturn PUB Log10(a) 'return sendCmd(Log10Cmd + @a) command := Log10Cmd + @a repeat while command return cmdReturn PUB Exp(a) 'return sendCmd(ExpCmd + @a) command := ExpCmd + @a repeat while command return cmdReturn PUB Exp10(a) 'return sendCmd(Exp10Cmd + @a) command := Exp10Cmd + @a repeat while command return cmdReturn PUB Pow(a, b) 'return sendCmd(PowCmd + @a) command := PowCmd + @a repeat while command return cmdReturnPUB Frac(a) 'return sendCmd(FracCmd + @a) command := FracCmd + @a repeat while command return cmdReturn PUB FMod(a, b) 'return sendCmd(FModCmd + @a) command := FModCmd + @a repeat while command return cmdReturnPUB FNeg(a) return a ^ $8000_0000PUB FAbs(a) return a & $7FFF_FFFF PUB Radians(a) | b, c b := a c := constant(pi / 180.0) 'sendCmd(FMulCmd + @a) command := FMulCmd + @b repeat while command return cmdReturn PUB Degrees(a) | b, c b := a c := constant(180.0 / pi) 'sendCmd(FMulCmd + @a) command := FMulCmd + @b repeat while command return cmdReturn PUB FMin(a, b) 'sendCmd(FCmpCmd + @a) command := FCmpCmd + @a repeat while command if cmdReturn < 0 return a return b PUB FMax(a, b) 'sendCmd(FCmpCmd + @a) command := FCmpCmd + @a repeat while command if cmdReturn < 0 return b return a'PRI sendCmd(cmd)' command := cmd' repeat while command' return cmdReturn DAT'---------------------------' Assembly language routines'--------------------------- orggetCommand rdlong t1, par wz ' wait for command if_z jmp #getCommand mov t2, t1 ' load fnumA rdlong fnumA, t2 add t2, #4 rdlong fnumB, t2 ' load fnumB shr t1, #16 wz ' get command cmp t1, #(FModCmd>>16)+1 wc ' check for valid command if_z_or_nc jmp #:exitNaN shl t1, #1 add t1, #:cmdTable-2 jmp t1 ' jump to command:cmdTable call #_FAdd ' command dispatch table jmp #endCommand call #_FSub jmp #endCommand call #_FMul jmp #endCommand call #_FDiv jmp #endCommand call #_FFloat jmp #endCommand call #_FTrunc jmp #endCommand call #_FRound jmp #endCommand call #_FSqr jmp #endCommand call #cmd_FCmp jmp #endCommand call #_Sin jmp #endCommand call #_Cos jmp #endCommand call #_Tan jmp #endCommand call #_Log jmp #endCommand call #_Log10 jmp #endCommand call #_Exp jmp #endCommand call #_Exp10 jmp #endCommand call #_Pow jmp #endCommand call #_Frac jmp #endCommand call #_FMod jmp #endCommand:cmdTableEnd:exitNaN mov fnumA, NaN ' unknown commandendCommand mov t1, par ' return result add t1, #4 wrlong fnumA, t1 wrlong Zero,par ' clear command status jmp #getCommand ' wait for next command'------------------------------------------------------------------------------cmd_FCmp call #_FCmp ' compare fnumA and fnumB mov fnumA, status ' return compare statuscmd_FCmp_ret ret'------------------------------------------------------------------------------' _FAdd fnumA = fnumA + fNumB' _FAddI fnumA = fnumA + {Float immediate}' _FSub fnumA = fnumA - fNumB' _FSubI fnumA = fnumA - {Float immediate}' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB, t1'------------------------------------------------------------------------------_FSubI movs :getB, _FSubI_ret ' get immediate value add _FSubI_ret, #1:getB mov fnumB, 0_FSub xor fnumB, Bit31 ' negate B jmp #_FAdd ' add values _FAddI movs :getB, _FAddI_ret ' get immediate value add _FAddI_ret, #1:getB mov fnumB, 0_FAdd call #_Unpack2 ' unpack two variables if_c_or_z jmp #_FAdd_ret ' check for NaN or B = 0 test flagA, #SignFlag wz ' negate A mantissa if negative if_nz neg manA, manA test flagB, #SignFlag wz ' negate B mantissa if negative if_nz neg manB, manB mov t1, expA ' align mantissas sub t1, expB abs t1, t1 max t1, #31 cmps expA, expB wz,wc if_nz_and_nc sar manB, t1 if_nz_and_c sar manA, t1 if_nz_and_c mov expA, expB add manA, manB ' add the two mantissas cmps manA, #0 wc, nr ' set sign of result if_c or flagA, #SignFlag if_nc andn flagA, #SignFlag abs manA, manA ' pack result and exit call #_Pack _FSubI_ret_FSub_ret _FAddI_ret_FAdd_ret ret '------------------------------------------------------------------------------' _FMul fnumA = fnumA * fNumB' _FMulI fnumA = fnumA * {Float immediate}' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB, t1, t2'------------------------------------------------------------------------------_FMulI movs :getB, _FMulI_ret ' get immediate value add _FMulI_ret, #1:getB mov fnumB, 0_FMul call #_Unpack2 ' unpack two variables if_c jmp #_FMul_ret ' check for NaN xor flagA, flagB ' get sign of result add expA, expB ' add exponents mov t1, #0 ' t2 = upper 32 bits of manB mov t2, #32 ' loop counter for multiply shr manB, #1 wc ' get initial multiplier bit :multiply if_c add t1, manA wc ' 32x32 bit multiply rcr t1, #1 wc rcr manB, #1 wc djnz t2, #:multiply shl t1, #3 ' justify result and exit mov manA, t1 call #_Pack _FMulI_ret_FMul_ret ret'------------------------------------------------------------------------------' _FDiv fnumA = fnumA / fNumB' _FDivI fnumA = fnumA / {Float immediate}' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB, t1, t2'------------------------------------------------------------------------------_FDivI movs :getB, _FDivI_ret ' get immediate value add _FDivI_ret, #1:getB mov fnumB, 0_FDiv call #_Unpack2 ' unpack two variables if_c_or_z mov fnumA, NaN ' check for NaN or divide by 0 if_c_or_z jmp #_FDiv_ret xor flagA, flagB ' get sign of result sub expA, expB ' subtract exponents mov t1, #0 ' clear quotient mov t2, #30 ' loop counter for divide:divide shl t1, #1 ' divide the mantissas cmps manA, manB wz,wc if_z_or_nc sub manA, manB if_z_or_nc add t1, #1 shl manA, #1 djnz t2, #:divide mov manA, t1 ' get result and exit call #_Pack _FDivI_ret_FDiv_ret ret'------------------------------------------------------------------------------' _FFloat fnumA = float(fnumA)' changes: fnumA, flagA, expA, manA'------------------------------------------------------------------------------ _FFloat mov flagA, fnumA ' get integer value mov fnumA, #0 ' set initial result to zero abs manA, flagA wz ' get absolute value of integer if_z jmp #_FFloat_ret ' if zero, exit shr flagA, #31 ' set sign flag mov expA, #31 ' set initial value for exponent:normalize shl manA, #1 wc ' normalize the mantissa if_nc sub expA, #1 ' adjust exponent if_nc jmp #:normalize rcr manA, #1 ' justify mantissa shr manA, #2 call #_Pack ' pack and exit_FFloat_ret ret'------------------------------------------------------------------------------' _FTrunc fnumA = fix(fnumA)' _FRound fnumA = fix(round(fnumA))' changes: fnumA, flagA, expA, manA, t1 '------------------------------------------------------------------------------_FTrunc mov t1, #0 ' set for no rounding jmp #fix_FRound mov t1, #1 ' set for roundingfix call #_Unpack ' unpack floating point value if_c jmp #_FRound_ret ' check for NaN shl manA, #2 ' left justify mantissa mov fnumA, #0 ' initialize result to zero neg expA, expA ' adjust for exponent value add expA, #30 wz cmps expA, #32 wc if_nc_or_z jmp #_FRound_ret shr manA, expA add manA, t1 ' round up 1/2 lsb shr manA, #1 test flagA, #signFlag wz ' check sign and exit sumnz fnumA, manA_FTrunc_ret_FRound_ret ret '------------------------------------------------------------------------------' _FSqr fnumA = sqrt(fnumA)' changes: fnumA, flagA, expA, manA, t1, t2, t3, t4, t5 '------------------------------------------------------------------------------_FSqr call #_Unpack ' unpack floating point value if_nc mov fnumA, #0 ' set initial result to zero if_c_or_z jmp #_FSqr_ret ' check for NaN or zero test flagA, #signFlag wz ' check for negative if_nz mov fnumA, NaN ' yes, then return NaN if_nz jmp #_FSqr_ret test expA, #1 wz ' if even exponent, shift mantissa if_z shr manA, #1 sar expA, #1 ' get exponent of root mov t1, Bit30 ' set root value to $4000_0000 ' mov t2, #31 ' get loop counter:sqrt or fnumA, t1 ' blend partial root into result mov t3, #32 ' loop counter for multiply mov t4, #0 mov t5, fnumA shr t5, #1 wc ' get initial multiplier bit :multiply if_c add t4, fnumA wc ' 32x32 bit multiply rcr t4, #1 wc rcr t5, #1 wc djnz t3, #:multiply cmps manA, t4 wc ' if too large remove partial root if_c xor fnumA, t1 shr t1, #1 ' shift partial root djnz t2, #:sqrt ' continue for all bits mov manA, fnumA ' store new mantissa value and exit shr manA, #1 call #_Pack_FSqr_ret ret'------------------------------------------------------------------------------' _FCmp set Z and C flags for fnumA - fNumB' _FCmpI set Z and C flags for fnumA - {Float immediate}' changes: status, t1'------------------------------------------------------------------------------_FCmpI movs :getB, _FCmpI_ret ' get immediate value add _FCmpI_ret, #1:getB mov fnumB, 0_FCmp mov t1, fnumA ' compare signs xor t1, fnumB and t1, Bit31 wz if_z jmp #:cmp1 ' same, then compare magnitude mov t1, fnumA ' check for +0 or -0 or t1, fnumB andn t1, Bit31 wz,wc if_z jmp #:exit test fnumA, Bit31 wc ' compare signs jmp #:exit:cmp1 test fnumA, Bit31 wz ' check signs if_nz jmp #:cmp2 cmp fnumA, fnumB wz,wc jmp #:exit:cmp2 cmp fnumB, fnumA wz,wc ' reverse test if negative:exit mov status, #1 ' if fnumA > fnumB, t1 = 1 if_c neg status, status ' if fnumA < fnumB, t1 = -1 if_z mov status, #0 ' if fnumA = fnumB, t1 = 0_FCmpI_ret_FCmp_ret ret'------------------------------------------------------------------------------' _Sin fnumA = sin(fnumA)' _Cos fnumA = cos(fnumA)' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB' changes: t1, t2, t3, t4, t5, t6'------------------------------------------------------------------------------_Cos call #_FAddI ' cos(x) = sin(x + pi/2) long pi / 2.0_Sin mov t6, fnumA ' save original angle call #_FDivI ' reduce angle to 0 to 2pi long 2.0 * pi call #_FTrunc cmp fnumA, NaN wz ' check for NaN if_z jmp #_Sin_ret call #_FFloat call #_FMulI long 2.0 * pi mov fnumB, fnumA mov fnumA, t6 call #_FSub call #_FMulI ' convert to 13 bit integer plus fraction long 8192.0 / (2.0 * pi) mov t5, fnumA ' get fraction call #_Frac mov t4, fnumA mov fnumA, t5 ' get integer call #_FTrunc test fnumA, Sin_90 wc ' set C flag for quandrant 2 or 4 test fnumA, Sin_180 wz ' set Z flag for quandrant 3 or 4 negc fnumA, fnumA ' if quandrant 2 or 4, negate offset or fnumA, SineTable ' blend in sine table address shl fnumA, #1 ' get table offset rdword t2, fnumA ' get first table value negnz t2, t2 ' if quandrant 3 or 4, negate add fnumA, #2 ' get second table value rdword t3, fnumA negnz t3, t3 ' if quandrant 3 or 4, negate mov fnumA, t2 ' result = float(value1) call #_FFloat mov fnumB, t4 wz ' exit if no fraction if_z jmp #:sin2 mov t5, fnumA ' interpolate the fractional value mov fnumA, t3 sub fnumA, t2 call #_FFloat call #_FMul mov fnumB, t5 call #_FAdd:sin2 call #_FDivI ' set range from -1.0 to 1.0 and exit long 65535.0_Cos_ret_Sin_ret ret'------------------------------------------------------------------------------' _Tan fnumA = tan(fnumA)' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB' changes: t1, t2, t3, t4, t5, t6, t7, t8'------------------------------------------------------------------------------_Tan mov t7, fnumA ' tan(x) = sin(x) / cos(x) call #_Cos mov t8, fnumA mov fnumA, t7 call #_Sin mov fnumB, t8 call #_FDiv_Tan_ret ret'------------------------------------------------------------------------------' _Log fnumA = log (base e) fnumA' _Log10 fnumA = log (base 10) fnumA' _Log2 fnumA = log (base 2) fnumA' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB, t1, t2, t3, t5'------------------------------------------------------------------------------_Log call #_Log2 ' log base e call #_FDivI long 1.442695041_Log_ret ret_Log10 call #_Log2 ' log base 10 call #_FDivI long 3.321928095_Log10_ret ret_Log2 call #_Unpack ' unpack variable if_z_or_c jmp #:exitNaN ' if NaN or <= 0, return NaN test flagA, #SignFlag wz if_nz jmp #:exitNaN mov t5, expA ' save exponent mov t1, manA ' get first 11 bits of fraction shr t1, #17 ' get table offset and t1, TableMask add t1, LogTable ' get table address call #float18Bits ' remainder = lower 18 bits mov t2, fnumA call #loadTable ' get fraction from log table mov fnumB, fnumA mov fnumA, t5 ' convert exponent to float call #_FFloat call #_FAdd ' result = exponent + fraction jmp #_Log2_ret:exitNaN mov fnumA, NaN ' return NaN_Log2_ret ret'------------------------------------------------------------------------------' _Exp fnumA = e ** fnumA' _Exp10 fnumA = 10 ** fnumA' _Exp2 fnumA = 2 ** fnumA' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB' changes: t1, t2, t3, t4, t5'------------------------------------------------------------------------------_Exp call #_FMulI ' e ** fnum long 1.442695041 jmp #_Exp2_Exp10 call #_FMulI ' 10 ** fnum long 3.321928095_Exp2 call #_Unpack ' unpack variable if_c jmp #_Exp2_ret ' check for NaN if_z mov fnumA, One ' if 0, return 1.0 if_z jmp #_Exp2_ret mov t5, fnumA ' save sign value call #_FTrunc ' get positive integer abs t4, fnumA mov fnumA, t5 call #_Frac ' get fraction call #_Unpack neg expA, expA ' get first 11 bits of fraction shr manA, expA mov t1, manA ' shr t1, #17 ' get table offset and t1, TableMask add t1, AlogTable ' get table address call #float18Bits ' remainder = lower 18 bits mov t2, fnumA call #loadTable ' get fraction from log table call #_FAddI ' add 1.0 long 1.0 call #_Unpack ' align fraction mov expA, t4 ' use integer as exponent call #_Pack test t5, Bit31 wz ' check if negative if_z jmp #_Exp2_ret mov fnumB, fnumA ' yes, then invert mov fnumA, One call #_FDiv_Exp_ret _Exp10_ret _Exp2_ret ret'------------------------------------------------------------------------------' _Pow fnumA = fnumA raised to power fnumB' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB' t1, t2, t3, t5, t6, t7'------------------------------------------------------------------------------_Pow mov t7, fnumA wc ' save sign of result if_nc jmp #:pow3 ' check if negative base mov fnumA, fnumB ' check exponent call #_Unpack mov fnumA, t7 ' restore base if_z jmp #:pow2 ' check for exponent = 0 test expA, Bit31 wz ' if exponent < 0, return NaN if_nz jmp #:pow1 max expA, #23 ' check if exponent = integer shl manA, expA and manA, Mask29 wz, nr if_z jmp #:pow2 ' yes, then check if odd :pow1 mov fnumA, NaN ' return NaN jmp #_Pow_ret:pow2 test manA, Bit29 wz ' if odd, then negate result if_z andn t7, Bit31:pow3 andn fnumA, Bit31 ' get |fnumA| mov t6, fnumB ' save power call #_Log2 ' get log of base mov fnumB, t6 ' multiply by power call #_FMul call #_Exp2 ' get result test t7, Bit31 wz ' check for negative if_nz xor fnumA, Bit31_Pow_ret ret'------------------------------------------------------------------------------' _Frac fnumA = fractional part of fnumA' changes: fnumA, flagA, expA, manA'------------------------------------------------------------------------------_Frac call #_Unpack ' get fraction test expA, Bit31 wz ' check for exp < 0 or NaN if_c_or_nz jmp #:exit max expA, #23 ' remove the integer shl manA, expA and manA, Mask29 mov expA, #0 ' return fraction:exit call #_Pack andn fnumA, Bit31_Frac_ret ret'------------------------------------------------------------------------------' _FMod fnumA = fnumA mod fnumB'------------------------------------------------------------------------------_FMod mov t4, fnumA ' save fnumA mov t5, fnumB ' save fnumB call #_FDiv ' a - float(fix(a/b)) * b call #_FTrunc call #_FFloat mov fnumB, t5 call #_FMul or fnumA, Bit31 mov fnumB, t4 andn fnumB, Bit31 call #_FAdd test t4, Bit31 wz ' if a < 0, set sign if_nz or fnumA, Bit31_FMod_ret ret'------------------------------------------------------------------------------' input: t1 table address (long)' t2 remainder (float) ' output: fnumA interpolated table value (float)' changes: fnumA, flagA, expA, manA, fnumB, t1, t2, t3'------------------------------------------------------------------------------loadTable rdword t3, t1 ' t3 = first table value cmp t2, #0 wz ' if remainder = 0, skip interpolation if_z mov t1, #0 if_z jmp #:load2 add t1, #2 ' load second table value test t1, #tableMask wz ' check for end of table if_z mov t1, #Bit16 ' t1 = second table value if_nz rdword t1, t1 sub t1, t3 ' t1 = t1 - t3:load2 mov manA, t3 ' convert t3 to float call #float16Bits mov t3, fnumA mov manA, t1 ' convert t1 to float call #float16Bits mov fnumB, t2 ' t1 = t1 * remainder call #_FMul mov fnumB, t3 ' result = t1 + t3 call #_FAddloadTable_ret retfloat18Bits shl manA, #14 ' float lower 18 bits jmp #floatBitsfloat16Bits shl manA, #16 ' float lower 16 bitsfloatBits shr manA, #3 ' align to bit 29 mov flagA, #0 ' convert table value to float mov expA, #0 call #_Pack ' pack and exitfloat18Bits_retfloat16Bits_retfloatBits_ret ret'------------------------------------------------------------------------------' input: fnumA 32-bit floating point value' fnumB 32-bit floating point value ' output: flagA fnumA flag bits (Nan, Infinity, Zero, Sign)' expA fnumA exponent (no bias)' manA fnumA mantissa (aligned to bit 29)' flagB fnumB flag bits (Nan, Infinity, Zero, Sign)' expB fnumB exponent (no bias)' manB fnumB mantissa (aligned to bit 29)' C flag set if fnumA or fnumB is NaN' Z flag set if fnumB is zero' changes: fnumA, flagA, expA, manA, fnumB, flagB, expB, manB, t1'------------------------------------------------------------------------------_Unpack2 mov t1, fnumA ' save A mov fnumA, fnumB ' unpack B to A call #_Unpack if_c jmp #_Unpack2_ret ' check for NaN mov fnumB, fnumA ' save B variables mov flagB, flagA mov expB, expA mov manB, manA mov fnumA, t1 ' unpack A call #_Unpack cmp manB, #0 wz ' set Z flag _Unpack2_ret ret'------------------------------------------------------------------------------' input: fnumA 32-bit floating point value ' output: flagA fnumA flag bits (Nan, Infinity, Zero, Sign)' expA fnumA exponent (no bias)' manA fnumA mantissa (aligned to bit 29)' C flag set if fnumA is NaN' Z flag set if fnumA is zero' changes: fnumA, flagA, expA, manA'------------------------------------------------------------------------------_Unpack mov flagA, fnumA ' get sign shr flagA, #31 mov manA, fnumA ' get mantissa and manA, Mask23 mov expA, fnumA ' get exponent shl expA, #1 shr expA, #24 wz if_z jmp #:zeroSubnormal ' check for zero or subnormal cmp expA, #255 wz ' check if finite if_nz jmp #:finite mov fnumA, NaN ' no, then return NaN mov flagA, #NaNFlag jmp #:exit2 :zeroSubnormal or manA, expA wz,nr ' check for zero if_nz jmp #:subnorm or flagA, #ZeroFlag ' yes, then set zero flag neg expA, #150 ' set exponent and exit jmp #:exit2 :subnorm shl manA, #7 ' fix justification for subnormals :subnorm2 test manA, Bit29 wz if_nz jmp #:exit1 shl manA, #1 sub expA, #1 jmp #:subnorm2:finite shl manA, #6 ' justify mantissa to bit 29 or manA, Bit29 ' add leading one bit :exit1 sub expA, #127 ' remove bias from exponent:exit2 test flagA, #NaNFlag wc ' set C flag cmp manA, #0 wz ' set Z flag_Unpack_ret ret '------------------------------------------------------------------------------' input: flagA fnumA flag bits (Nan, Infinity, Zero, Sign)' expA fnumA exponent (no bias)' manA fnumA mantissa (aligned to bit 29)' output: fnumA 32-bit floating point value' changes: fnumA, flagA, expA, manA '------------------------------------------------------------------------------_Pack cmp manA, #0 wz ' check for zero if_z mov expA, #0 if_z jmp #:exit1:normalize shl manA, #1 wc ' normalize the mantissa if_nc sub expA, #1 ' adjust exponent if_nc jmp #:normalize add expA, #2 ' adjust exponent add manA, #$100 wc ' round up by 1/2 lsb if_c add expA, #1 add expA, #127 ' add bias to exponent mins expA, Minus23 maxs expA, #255 cmps expA, #1 wc ' check for subnormals if_nc jmp #:exit1:subnormal or manA, #1 ' adjust mantissa ror manA, #1 neg expA, expA shr manA, expA mov expA, #0 ' biased exponent = 0:exit1 mov fnumA, manA ' bits 22:0 mantissa shr fnumA, #9 movi fnumA, expA ' bits 23:30 exponent shl flagA, #31 or fnumA, flagA ' bit 31 sign _Pack_ret ret'-------------------- constant values -----------------------------------------Zero long 0 ' constantsOne long $3F80_0000NaN long $7FFF_FFFFMinus23 long -23Mask23 long $007F_FFFFMask29 long $1FFF_FFFFBit16 long $0001_0000Bit29 long $2000_0000Bit30 long $4000_0000Bit31 long $8000_0000LogTable long $C000ALogTable long $D000TableMask long $0FFESineTable long $E000 >> 1Sin_90 long $0800Sin_180 long $1000'-------------------- local variables -----------------------------------------t1 res 1 ' temporary valuest2 res 1t3 res 1t4 res 1t5 res 1t6 res 1t7 res 1t8 res 1status res 1 ' last compare statusfnumA res 1 ' floating point A valueflagA res 1expA res 1manA res 1fnumB res 1 ' floating point B valueflagB res 1expB res 1manB res 1