^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * fp_util.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright Roman Zippel, 1997. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Redistribution and use in source and binary forms, with or without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * modification, are permitted provided that the following conditions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * are met:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * 1. Redistributions of source code must retain the above copyright
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * notice, and the entire permission notice in its entirety,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * including the disclaimer of warranties.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * 2. Redistributions in binary form must reproduce the above copyright
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * notice, this list of conditions and the following disclaimer in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * documentation and/or other materials provided with the distribution.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * 3. The name of the author may not be used to endorse or promote
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * products derived from this software without specific prior
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * written permission.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * ALTERNATIVELY, this product may be distributed under the terms of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * the GNU General Public License, in which case the provisions of the GPL are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * required INSTEAD OF the above restrictions. (This clause is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * necessary due to a potential bad interaction between the GPL and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * the restrictions contained in a BSD-style copyright.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * OF THE POSSIBILITY OF SUCH DAMAGE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include "fp_emu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * Here are lots of conversion and normalization functions mainly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * used by fp_scan.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * Note that these functions are optimized for "normal" numbers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * these are handled first and exit as fast as possible, this is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * especially important for fp_normalize_ext/fp_conv_ext2ext, as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * it's called very often.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * The register usage is optimized for fp_scan.S and which register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * is currently at that time unused, be careful if you want change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * something here. %d0 and %d1 is always usable, sometimes %d2 (or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * only the lower half) most function have to return the %a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * unmodified, so that the caller can immediately reuse it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .globl fp_ill, fp_end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) | exits from fp_scan:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) | illegal instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) fp_ill:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) printf ,"fp_illegal\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) | completed instruction
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) fp_end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) tst.l (TASK_MM-8,%a2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) jmi 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) tst.l (TASK_MM-4,%a2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) jmi 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) tst.l (TASK_MM,%a2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) jpl 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) 1: printf ,"oops:%p,%p,%p\n",3,%a2@(TASK_MM-8),%a2@(TASK_MM-4),%a2@(TASK_MM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) 2: clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) .globl fp_conv_long2ext, fp_conv_single2ext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) .globl fp_conv_double2ext, fp_conv_ext2ext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) .globl fp_normalize_ext, fp_normalize_double
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .globl fp_normalize_single, fp_normalize_single_fast
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .globl fp_conv_ext2double, fp_conv_ext2single
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .globl fp_conv_ext2long, fp_conv_ext2short
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .globl fp_conv_ext2byte
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .globl fp_finalrounding_single, fp_finalrounding_single_fast
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .globl fp_finalrounding_double
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .globl fp_finalrounding, fp_finaltest, fp_final
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * First several conversion functions from a source operand
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * into the extended format. Note, that only fp_conv_ext2ext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * normalizes the number and is always called after the other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * conversion functions, which only move the information into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * fp_ext structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) | fp_conv_long2ext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) | args: %d0 = source (32-bit long)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) | %a0 = destination (ptr to struct fp_ext)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) fp_conv_long2ext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) printf PCONV,"l2e: %p -> %p(",2,%d0,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) clr.l %d1 | sign defaults to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) tst.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) jeq fp_l2e_zero | is source zero?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) jpl 1f | positive?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) moveq #1,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) neg.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 1: swap %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) move.w #0x3fff+31,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) move.l %d1,(%a0)+ | set sign / exp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) move.l %d0,(%a0)+ | set mantissa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) subq.l #8,%a0 | restore %a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) printf PCONV,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) | source is zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) fp_l2e_zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) clr.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) clr.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) printf PCONV,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) | fp_conv_single2ext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) | args: %d0 = source (single-precision fp value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) | %a0 = dest (struct fp_ext *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) fp_conv_single2ext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) printf PCONV,"s2e: %p -> %p(",2,%d0,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) lsl.l #8,%d0 | shift mantissa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) lsr.l #8,%d1 | exponent / sign
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) lsr.l #7,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) lsr.w #8,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) jeq fp_s2e_small | zero / denormal?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) cmp.w #0xff,%d1 | NaN / Inf?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) jeq fp_s2e_large
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) bset #31,%d0 | set explizit bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) add.w #0x3fff-0x7f,%d1 | re-bias the exponent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) move.l %d0,(%a0)+ | high lword of fp_ext.mant
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) clr.l (%a0) | low lword = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) printf PCONV,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) | zeros and denormalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) fp_s2e_small:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) | exponent is zero, so explizit bit is already zero too
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) tst.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) jeq 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) move.w #0x4000-0x7f,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) jra 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) | infinities and NAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) fp_s2e_large:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) bclr #31,%d0 | clear explizit bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) move.w #0x7fff,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) jra 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) fp_conv_double2ext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #ifdef FPU_EMU_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) getuser.l %a1@(0),%d0,fp_err_ua2,%a1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) getuser.l %a1@(4),%d1,fp_err_ua2,%a1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) printf PCONV,"d2e: %p%p -> %p(",3,%d0,%d1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) getuser.l (%a1)+,%d0,fp_err_ua2,%a1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) lsl.l #8,%d0 | shift high mantissa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) lsl.l #3,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) lsr.l #8,%d1 | exponent / sign
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) lsr.l #7,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) lsr.w #5,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) jeq fp_d2e_small | zero / denormal?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) cmp.w #0x7ff,%d1 | NaN / Inf?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) jeq fp_d2e_large
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) bset #31,%d0 | set explizit bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) add.w #0x3fff-0x3ff,%d1 | re-bias the exponent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 9: move.l %d1,(%a0)+ | fp_ext.sign, fp_ext.exp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) move.l %d0,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) getuser.l (%a1)+,%d0,fp_err_ua2,%a1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) lsl.l #8,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) lsl.l #3,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) moveq #21,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) lsr.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) or.l %d1,-(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) printf PCONV,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) | zeros and denormalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) fp_d2e_small:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) | exponent is zero, so explizit bit is already zero too
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) tst.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) jeq 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) move.w #0x4000-0x3ff,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) jra 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) | infinities and NAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) fp_d2e_large:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) bclr #31,%d0 | clear explizit bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) move.w #0x7fff,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) jra 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) | fp_conv_ext2ext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) | originally used to get longdouble from userspace, now it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) | called before arithmetic operations to make sure the number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) | is normalized [maybe rename it?].
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) | args: %a0 = dest (struct fp_ext *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) | returns 0 in %d0 for a NaN, otherwise 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) fp_conv_ext2ext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) printf PCONV,"e2e: %p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) printf PCONV,"), "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) move.l (%a0)+,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) cmp.w #0x7fff,%d0 | Inf / NaN?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) jeq fp_e2e_large
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) jpl fp_e2e_small | zero / denorm?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) | The high bit is set, so normalization is irrelevant.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) fp_e2e_checkround:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) move.b (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) jne fp_e2e_round
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) printf PCONV,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) printf PCONV,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) moveq #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) fp_e2e_round:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) fp_set_sr FPSR_EXC_INEX2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) clr.b (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) move.w (FPD_RND,FPDATA),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) jne fp_e2e_roundother | %d2 == 0, round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) tst.b %d0 | test guard bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) jpl 9f | zero is closer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) btst #0,(11,%a0) | test lsb bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) jne fp_e2e_doroundup | round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) lsl.b #1,%d0 | check low bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) jeq 9f | round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) fp_e2e_doroundup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) addq.l #1,(8,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) jcc 9f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) addq.l #1,(4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) jcc 9f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) move.w #0x8000,(4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) addq.w #1,(2,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 9: printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) fp_e2e_roundother:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) jcs 9b | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) jhi 1f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) tst.b (1,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) jne fp_e2e_doroundup | negative, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) jra 9b | positive, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 1: tst.b (1,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) jeq fp_e2e_doroundup | positive, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) jra 9b | negative, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) | zeros and subnormals:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) | try to normalize these anyway.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) fp_e2e_small:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) jne fp_e2e_small1 | high lword zero?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) move.l (4,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) jne fp_e2e_small2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) move.b (-4,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) jne fp_e2e_small3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) | Genuine zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) clr.w -(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) subq.l #2,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) moveq #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) | definitely subnormal, need to shift all 64 bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) fp_e2e_small1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) bfffo %d0{#0,#32},%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) move.w -(%a0),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) sub.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) | Pathologically small, denormalize.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) add.w %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) clr.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 1: move.w %d2,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) move.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) jeq fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) | fancy 64-bit double-shift begins here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) lsl.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) move.l %d0,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) lsl.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) and.w #0x1f,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) lsr.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) or.l %d1,-(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) fp_e2e_extra1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) move.b (-4,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) add.w #24,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) clr.b (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) lsl.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) or.l %d0,(4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) jra fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 1: addq.w #8,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) lsl.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) move.b %d0,(-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) lsr.l #8,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) or.l %d0,(4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) jra fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) | pathologically small subnormal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) fp_e2e_small2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) bfffo %d0{#0,#32},%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) add.w #32,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) move.w -(%a0),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) sub.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) | Beyond pathologically small, denormalize.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) add.w %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) clr.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 1: move.w %d2,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) ext.l %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) jeq fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) clr.l (4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) sub.w #32,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) jcs 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) lsl.l %d1,%d0 | lower lword needs only to be shifted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) move.l %d0,(%a0) | into the higher lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) move.b (-4,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) clr.b (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) neg.w %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) add.w #32,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) bfins %d0,(%a0){%d1,#8}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) jra fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 1: neg.w %d1 | lower lword is splitted between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) bfins %d0,(%a0){%d1,#32} | higher and lower lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) #ifndef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) jra fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) move.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) jra fp_e2e_extra1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) | These are extremely small numbers, that will mostly end up as zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) | anyway, so this is only important for correct rounding.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) fp_e2e_small3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) bfffo %d0{#24,#8},%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) add.w #40,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) move.w -(%a0),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) sub.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) | Pathologically small, denormalize.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) add.w %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) clr.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 1: move.w %d2,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) ext.l %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) jeq fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) cmp.w #8,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) jcs 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 1: clr.b (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) sub.w #64,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) jcs 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) add.w #24,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) lsl.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) jra fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 1: neg.w %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) bfins %d0,(%a0){%d1,#8}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) jra fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 2: lsl.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) move.b %d0,(-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) lsr.l #8,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) move.b %d0,(7,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) jra fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 1: move.l %d0,%d1 | lower lword is splitted between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) lsl.l %d2,%d0 | higher and lower lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) move.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) add.w #32,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) lsr.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) move.l %d0,-(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) jra fp_e2e_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) | Infinities and NaNs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) fp_e2e_large:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) move.l (%a0)+,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) jne 3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 1: tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) jne 4f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) moveq #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 2: subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) printf PCONV,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) printf PCONV,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) | we have maybe a NaN, shift off the highest bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 3: lsl.l #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) jeq 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) | we have a NaN, clear the return value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 4: clrl %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) jra 2b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * Normalization functions. Call these on the output of general
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) * FP operators, and before any conversion into the destination
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) * formats. fp_normalize_ext has always to be called first, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * following conversion functions expect an already normalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) | fp_normalize_ext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) | normalize an extended in extended (unpacked) format, basically
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) | it does the same as fp_conv_ext2ext, additionally it also does
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) | the necessary postprocessing checks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) | args: %a0 (struct fp_ext *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) | NOTE: it does _not_ modify %a0/%a1 and the upper word of %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) fp_normalize_ext:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) printf PNORM,"ne: %p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) printf PNORM,"), "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) move.l (%a0)+,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) cmp.w #0x7fff,%d0 | Inf / NaN?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) jeq fp_ne_large
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) jpl fp_ne_small | zero / denorm?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) | The high bit is set, so normalization is irrelevant.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) fp_ne_checkround:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) move.b (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) jne fp_ne_round
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) fp_ne_round:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) fp_set_sr FPSR_EXC_INEX2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) clr.b (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) move.w (FPD_RND,FPDATA),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) jne fp_ne_roundother | %d2 == 0, round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) tst.b %d0 | test guard bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) jpl 9f | zero is closer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) btst #0,(11,%a0) | test lsb bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) jne fp_ne_doroundup | round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) lsl.b #1,%d0 | check low bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) jeq 9f | round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) fp_ne_doroundup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) addq.l #1,(8,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) jcc 9f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) addq.l #1,(4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) jcc 9f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) addq.w #1,(2,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) move.w #0x8000,(4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 9: printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) fp_ne_roundother:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) jcs 9b | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) jhi 1f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) tst.b (1,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) jne fp_ne_doroundup | negative, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) jra 9b | positive, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 1: tst.b (1,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) jeq fp_ne_doroundup | positive, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) jra 9b | negative, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) | Zeros and subnormal numbers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) | These are probably merely subnormal, rather than "denormalized"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) | numbers, so we will try to make them normal again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) fp_ne_small:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) jne fp_ne_small1 | high lword zero?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) move.l (4,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) jne fp_ne_small2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) move.b (-4,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) jne fp_ne_small3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) | Genuine zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) clr.w -(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) subq.l #2,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) | Subnormal.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) fp_ne_small1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) bfffo %d0{#0,#32},%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) move.w -(%a0),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) sub.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) | Pathologically small, denormalize.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) add.w %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) clr.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) fp_set_sr FPSR_EXC_UNFL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 1: move.w %d2,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) move.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) jeq fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) | This is exactly the same 64-bit double shift as seen above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) lsl.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) move.l %d0,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) lsl.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) and.w #0x1f,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) lsr.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) or.l %d1,-(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) fp_ne_extra1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) move.b (-4,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) add.w #24,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) clr.b (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) lsl.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) or.l %d0,(4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) jra fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 1: addq.w #8,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) lsl.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) move.b %d0,(-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) lsr.l #8,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) or.l %d0,(4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) jra fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) | May or may not be subnormal, if so, only 32 bits to shift.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) fp_ne_small2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) bfffo %d0{#0,#32},%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) add.w #32,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) move.w -(%a0),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) sub.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) | Beyond pathologically small, denormalize.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) add.w %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) clr.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) fp_set_sr FPSR_EXC_UNFL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 1: move.w %d2,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) ext.l %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) jeq fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) clr.l (4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) sub.w #32,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) jcs 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) lsl.l %d1,%d0 | lower lword needs only to be shifted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) move.l %d0,(%a0) | into the higher lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) #ifdef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) move.b (-4,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) clr.b (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) neg.w %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) add.w #32,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) bfins %d0,(%a0){%d1,#8}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) jra fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 1: neg.w %d1 | lower lword is splitted between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) bfins %d0,(%a0){%d1,#32} | higher and lower lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) #ifndef CONFIG_M68KFPU_EMU_EXTRAPREC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) jra fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) move.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) jra fp_ne_extra1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) | These are extremely small numbers, that will mostly end up as zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) | anyway, so this is only important for correct rounding.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) fp_ne_small3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) bfffo %d0{#24,#8},%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) add.w #40,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) move.w -(%a0),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) sub.w %d1,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) | Pathologically small, denormalize.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) add.w %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) clr.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) 1: move.w %d2,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) ext.l %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) jeq fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) cmp.w #8,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) jcs 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) 1: clr.b (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) sub.w #64,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) jcs 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) add.w #24,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) lsl.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) jra fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 1: neg.w %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) bfins %d0,(%a0){%d1,#8}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) jra fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 2: lsl.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) move.b %d0,(-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) lsr.l #8,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) move.b %d0,(7,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) jra fp_ne_checkround
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) | Infinities and NaNs, again, same as above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) fp_ne_large:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) move.l (%a0)+,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) jne 3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 1: tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) jne 4f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 2: subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) | we have maybe a NaN, shift off the highest bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 3: move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) lsl.l #1,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) jne 4f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) clr.l (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) jra 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) | we have a NaN, test if it is signaling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 4: bset #30,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) jne 2b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) fp_set_sr FPSR_EXC_SNAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) move.l %d0,(-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) jra 2b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) | these next two do rounding as per the IEEE standard.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) | values for the rounding modes appear to be:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) | 0: Round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) | 1: Round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) | 2: Round to -Infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) | 3: Round to +Infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) | both functions expect that fp_normalize was already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) | called (and extended argument is already normalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) | as far as possible), these are used if there is different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) | rounding precision is selected and before converting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) | into single/double
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) | fp_normalize_double:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) | normalize an extended with double (52-bit) precision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) | args: %a0 (struct fp_ext *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) fp_normalize_double:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) printf PNORM,"nd: %p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) printf PNORM,"), "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) move.l (%a0)+,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) tst.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) jeq fp_nd_zero | zero / denormalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) cmp.w #0x7fff,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) jeq fp_nd_huge | NaN / infinitive.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) sub.w #0x4000-0x3ff,%d2 | will the exponent fit?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) jcs fp_nd_small | too small.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) cmp.w #0x7fe,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) jcc fp_nd_large | too big.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) addq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) move.l (%a0),%d0 | low lword of mantissa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) | now, round off the low 11 bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) fp_nd_round:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) moveq #21,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) lsl.l %d1,%d0 | keep 11 low bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) jne fp_nd_checkround | Are they non-zero?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) | nothing to do here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 9: subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) | Be careful with the X bit! It contains the lsb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) | from the shift above, it is needed for round to nearest.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) fp_nd_checkround:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) fp_set_sr FPSR_EXC_INEX2 | INEX2 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) and.w #0xf800,(2,%a0) | clear bits 0-10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) move.w (FPD_RND,FPDATA),%d2 | rounding mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) jne 2f | %d2 == 0, round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) tst.l %d0 | test guard bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) jpl 9b | zero is closer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) | here we test the X bit by adding it to %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) clr.w %d2 | first set z bit, addx only clears it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) addx.w %d2,%d2 | test lsb bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) | IEEE754-specified "round to even" behaviour. If the guard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) | bit is set, then the number is odd, so rounding works like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) | in grade-school arithmetic (i.e. 1.5 rounds to 2.0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) | Otherwise, an equal distance rounds towards zero, so as not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) | to produce an odd number. This is strange, but it is what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) | the standard says.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) jne fp_nd_doroundup | round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) lsl.l #1,%d0 | check low bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) jeq 9b | round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) fp_nd_doroundup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) | round (the mantissa, that is) towards infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) add.l #0x800,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) jcc 9b | no overflow, good.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) addq.l #1,-(%a0) | extend to high lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) jcc 1f | no overflow, good.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) | Yow! we have managed to overflow the mantissa. Since this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) | only happens when %d1 was 0xfffff800, it is now zero, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) | reset the high bit, and increment the exponent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) move.w #0x8000,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) addq.w #1,-(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) cmp.w #0x43ff,(%a0)+ | exponent now overflown?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) jeq fp_nd_large | yes, so make it infinity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 1: subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 2: subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) jcs 9b | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) jhi 3f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) | Round to +Inf or -Inf. High word of %d2 contains the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) | sign of the number, by the way.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) swap %d2 | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) tst.b %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) jne fp_nd_doroundup | negative, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) jra 9b | positive, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 3: swap %d2 | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) tst.b %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) jeq fp_nd_doroundup | positive, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) jra 9b | negative, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) | Exponent underflow. Try to make a denormal, and set it to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) | the smallest possible fraction if this fails.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) fp_nd_small:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) fp_set_sr FPSR_EXC_UNFL | set UNFL bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) move.w #0x3c01,(-2,%a0) | 2**-1022
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) neg.w %d2 | degree of underflow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) cmp.w #32,%d2 | single or double shift?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) jcc 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) | Again, another 64-bit double shift.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) lsr.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) move.l %d0,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) lsr.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) add.w #32,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) lsl.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) or.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) move.l (%a0),%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) | Check to see if we shifted off any significant bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) lsl.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) jeq fp_nd_round | Nope, round.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) bset #0,%d0 | Yes, so set the "sticky bit".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) jra fp_nd_round | Now, round.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) | Another 64-bit single shift and store
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) 1: sub.w #32,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) cmp.w #32,%d2 | Do we really need to shift?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) jcc 2f | No, the number is too small.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) clr.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) lsr.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) add.w #32,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) | Again, check to see if we shifted off any significant bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) bset #0,%d0 | Sticky bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) 1: move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) lsl.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) jeq fp_nd_round
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) bset #0,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) jra fp_nd_round
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) | Sorry, the number is just too small.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) 2: clr.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) moveq #1,%d0 | Smallest possible fraction,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) jra fp_nd_round | round as desired.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) | zero and denormalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) fp_nd_zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) tst.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) rts | zero. nothing to do.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) | These are not merely subnormal numbers, but true denormals,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) | i.e. pathologically small (exponent is 2**-16383) numbers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) | It is clearly impossible for even a normal extended number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) | with that exponent to fit into double precision, so just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) | write these ones off as "too darn small".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) 1: fp_set_sr FPSR_EXC_UNFL | Set UNFL bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) clr.l -(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) move.w #0x3c01,-(%a0) | i.e. 2**-1022
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) addq.l #6,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) moveq #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) jra fp_nd_round | round.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) | Exponent overflow. Just call it infinity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) fp_nd_large:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) move.w #0x7ff,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) and.w (6,%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) fp_set_sr FPSR_EXC_INEX2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) 1: fp_set_sr FPSR_EXC_OVFL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) move.w (FPD_RND,FPDATA),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) jne 3f | %d2 = 0 round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) 1: move.w #0x7fff,(-2,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) clr.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) 2: subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) 3: subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) jcs 5f | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) jhi 4f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) tst.b (-3,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) jne 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) jra 5f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) 4: tst.b (-3,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) jeq 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) 5: move.w #0x43fe,(-2,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) moveq #-1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) move.l %d0,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) move.w #0xf800,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) move.l %d0,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) jra 2b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) | Infinities or NaNs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) fp_nd_huge:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) | fp_normalize_single:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) | normalize an extended with single (23-bit) precision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) | args: %a0 (struct fp_ext *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) fp_normalize_single:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) printf PNORM,"ns: %p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) printf PNORM,") "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) addq.l #2,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) move.w (%a0)+,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) jeq fp_ns_zero | zero / denormalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) cmp.w #0x7fff,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) jeq fp_ns_huge | NaN / infinitive.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) sub.w #0x4000-0x7f,%d2 | will the exponent fit?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) jcs fp_ns_small | too small.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) cmp.w #0xfe,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) jcc fp_ns_large | too big.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) move.l (%a0)+,%d0 | get high lword of mantissa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) fp_ns_round:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) tst.l (%a0) | check the low lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) | Set a sticky bit if it is non-zero. This should only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) | affect the rounding in what would otherwise be equal-
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) | distance situations, which is what we want it to do.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) bset #0,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) 1: clr.l (%a0) | zap it from memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) | now, round off the low 8 bits of the hi lword.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) tst.b %d0 | 8 low bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) jne fp_ns_checkround | Are they non-zero?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) | nothing to do here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) fp_ns_checkround:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) fp_set_sr FPSR_EXC_INEX2 | INEX2 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) clr.b -(%a0) | clear low byte of high lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) subq.l #3,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) move.w (FPD_RND,FPDATA),%d2 | rounding mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) jne 2f | %d2 == 0, round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) tst.b %d0 | test guard bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) jpl 9f | zero is closer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) btst #8,%d0 | test lsb bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) | round to even behaviour, see above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) jne fp_ns_doroundup | round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) lsl.b #1,%d0 | check low bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) jeq 9f | round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) fp_ns_doroundup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) | round (the mantissa, that is) towards infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) add.l #0x100,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) jcc 9f | no overflow, good.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) | Overflow. This means that the %d1 was 0xffffff00, so it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) | is now zero. We will set the mantissa to reflect this, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) | increment the exponent (checking for overflow there too)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) move.w #0x8000,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) addq.w #1,-(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) cmp.w #0x407f,(%a0)+ | exponent now overflown?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) jeq fp_ns_large | yes, so make it infinity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) 9: subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) | check nondefault rounding modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) 2: subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) jcs 9b | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) jhi 3f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) tst.b (-3,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) jne fp_ns_doroundup | negative, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) jra 9b | positive, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) 3: tst.b (-3,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) jeq fp_ns_doroundup | positive, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) jra 9b | negative, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) | Exponent underflow. Try to make a denormal, and set it to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) | the smallest possible fraction if this fails.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) fp_ns_small:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) fp_set_sr FPSR_EXC_UNFL | set UNFL bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) move.w #0x3f81,(-2,%a0) | 2**-126
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) neg.w %d2 | degree of underflow
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) cmp.w #32,%d2 | single or double shift?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) jcc 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) | a 32-bit shift.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) lsr.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) move.l %d0,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) | Check to see if we shifted off any significant bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) add.w #32,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) lsl.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) bset #0,%d0 | Sticky bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) | Check the lower lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) 1: tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) jeq fp_ns_round
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) clr (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) bset #0,%d0 | Sticky bit.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) jra fp_ns_round
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) | Sorry, the number is just too small.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) 2: clr.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) moveq #1,%d0 | Smallest possible fraction,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) jra fp_ns_round | round as desired.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) | Exponent overflow. Just call it infinity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) fp_ns_large:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) tst.b (3,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) fp_set_sr FPSR_EXC_INEX2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) 1: fp_set_sr FPSR_EXC_OVFL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) move.w (FPD_RND,FPDATA),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) jne 3f | %d2 = 0 round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) 1: move.w #0x7fff,(-2,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) clr.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) 2: subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) 3: subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) jcs 5f | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) jhi 4f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) tst.b (-3,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) jne 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) jra 5f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) 4: tst.b (-3,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) jeq 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) 5: move.w #0x407e,(-2,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) move.l #0xffffff00,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) jra 2b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) | zero and denormalized
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) fp_ns_zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) tst.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) rts | zero. nothing to do.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) | These are not merely subnormal numbers, but true denormals,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) | i.e. pathologically small (exponent is 2**-16383) numbers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) | It is clearly impossible for even a normal extended number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) | with that exponent to fit into single precision, so just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) | write these ones off as "too darn small".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) 1: fp_set_sr FPSR_EXC_UNFL | Set UNFL bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) clr.l -(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) move.w #0x3f81,-(%a0) | i.e. 2**-126
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) addq.l #6,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) moveq #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) jra fp_ns_round | round.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) | Infinities or NaNs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) fp_ns_huge:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) | fp_normalize_single_fast:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) | normalize an extended with single (23-bit) precision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) | this is only used by fsgldiv/fsgdlmul, where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) | operand is not completly normalized.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) | args: %a0 (struct fp_ext *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) fp_normalize_single_fast:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) printf PNORM,"nsf: %p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) printf PNORM,") "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) addq.l #2,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) move.w (%a0)+,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) cmp.w #0x7fff,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) jeq fp_nsf_huge | NaN / infinitive.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) move.l (%a0)+,%d0 | get high lword of mantissa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) fp_nsf_round:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) tst.l (%a0) | check the low lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) | Set a sticky bit if it is non-zero. This should only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) | affect the rounding in what would otherwise be equal-
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) | distance situations, which is what we want it to do.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) bset #0,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) 1: clr.l (%a0) | zap it from memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) | now, round off the low 8 bits of the hi lword.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) tst.b %d0 | 8 low bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) jne fp_nsf_checkround | Are they non-zero?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) | nothing to do here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) fp_nsf_checkround:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) fp_set_sr FPSR_EXC_INEX2 | INEX2 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) clr.b -(%a0) | clear low byte of high lword
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) subq.l #3,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) move.w (FPD_RND,FPDATA),%d2 | rounding mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) jne 2f | %d2 == 0, round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) tst.b %d0 | test guard bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) jpl 9f | zero is closer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) btst #8,%d0 | test lsb bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) | round to even behaviour, see above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) jne fp_nsf_doroundup | round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) lsl.b #1,%d0 | check low bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) jeq 9f | round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) fp_nsf_doroundup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) | round (the mantissa, that is) towards infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) add.l #0x100,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) jcc 9f | no overflow, good.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) | Overflow. This means that the %d1 was 0xffffff00, so it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) | is now zero. We will set the mantissa to reflect this, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) | increment the exponent (checking for overflow there too)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) move.w #0x8000,(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) addq.w #1,-(%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) cmp.w #0x407f,(%a0)+ | exponent now overflown?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) jeq fp_nsf_large | yes, so make it infinity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) 9: subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) | check nondefault rounding modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) 2: subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) jcs 9b | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) jhi 3f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) tst.b (-3,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) jne fp_nsf_doroundup | negative, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) jra 9b | positive, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) 3: tst.b (-3,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) jeq fp_nsf_doroundup | positive, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) jra 9b | negative, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) | Exponent overflow. Just call it infinity.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) fp_nsf_large:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) tst.b (3,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) fp_set_sr FPSR_EXC_INEX2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) 1: fp_set_sr FPSR_EXC_OVFL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) move.w (FPD_RND,FPDATA),%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) jne 3f | %d2 = 0 round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) 1: move.w #0x7fff,(-2,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) clr.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) 2: subq.l #8,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) 3: subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) jcs 5f | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) jhi 4f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) tst.b (-3,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) jne 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) jra 5f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) 4: tst.b (-3,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) jeq 1b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) 5: move.w #0x407e,(-2,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) move.l #0xffffff00,(%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) clr.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) jra 2b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) | Infinities or NaNs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) fp_nsf_huge:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) printf PNORM,"%p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) printx PNORM,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) printf PNORM,")\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) | conv_ext2int (macro):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) | Generates a subroutine that converts an extended value to an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) | integer of a given size, again, with the appropriate type of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) | rounding.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) | Macro arguments:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) | s: size, as given in an assembly instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) | b: number of bits in that size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) | Subroutine arguments:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) | %a0: source (struct fp_ext *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) | Returns the integer in %d0 (like it should)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) .macro conv_ext2int s,b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) .set inf,(1<<(\b-1))-1 | i.e. MAXINT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) printf PCONV,"e2i%d: %p(",2,#\b,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) printf PCONV,") "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) addq.l #2,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) move.w (%a0)+,%d2 | exponent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) jeq fp_e2i_zero\b | zero / denorm (== 0, here)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) cmp.w #0x7fff,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) jeq fp_e2i_huge\b | Inf / NaN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) sub.w #0x3ffe,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) jcs fp_e2i_small\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) cmp.w #\b,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) jhi fp_e2i_large\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) lsl.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) jne fp_e2i_round\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) tst.l (4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) jne fp_e2i_round\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) add.w #32,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) lsr.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) 9: tst.w (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) tst.\s %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) jmi fp_e2i_large\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) printf PCONV,"-> %p\n",1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) 1: neg.\s %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) jpl fp_e2i_large\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) 1: printf PCONV,"-> %p\n",1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) fp_e2i_round\b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) fp_set_sr FPSR_EXC_INEX2 | INEX2 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) neg.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) add.w #32,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) .if \b>16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) jeq 5f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) .endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) lsr.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) move.w (FPD_RND,FPDATA),%d2 | rounding mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) jne 2f | %d2 == 0, round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) tst.l %d1 | test guard bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) jpl 9b | zero is closer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) btst %d2,%d0 | test lsb bit (%d2 still 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) jne fp_e2i_doroundup\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) lsl.l #1,%d1 | check low bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) jne fp_e2i_doroundup\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) tst.l (4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) jeq 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) fp_e2i_doroundup\b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) addq.l #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) jra 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) | check nondefault rounding modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) 2: subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) jcs 9b | %d2 < 2, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) jhi 3f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) tst.w (-4,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) jne fp_e2i_doroundup\b | negative, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) jra 9b | positive, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) 3: tst.w (-4,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) jeq fp_e2i_doroundup\b | positive, round to infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) jra 9b | negative, round to zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) | we are only want -2**127 get correctly rounded here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) | since the guard bit is in the lower lword.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) | everything else ends up anyway as overflow.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) .if \b>16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) 5: move.w (FPD_RND,FPDATA),%d2 | rounding mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) jne 2b | %d2 == 0, round to nearest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) move.l (4,%a0),%d1 | test guard bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) jpl 9b | zero is closer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) lsl.l #1,%d1 | check low bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) jne fp_e2i_doroundup\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) jra 9b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) .endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) fp_e2i_zero\b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) tst.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) jeq 3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) 1: subq.l #4,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) fp_clr_sr FPSR_EXC_UNFL | fp_normalize_ext has set this bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) fp_e2i_small\b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) fp_set_sr FPSR_EXC_INEX2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) move.w (FPD_RND,FPDATA),%d2 | rounding mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) subq.w #2,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) jcs 3f | %d2 < 2, round to nearest/zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) jhi 2f | %d2 > 2, round to +infinity
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) tst.w (-4,%a0) | to -inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) jeq 3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) subq.\s #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) jra 3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) 2: tst.w (-4,%a0) | to +inf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) jne 3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) addq.\s #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) 3: printf PCONV,"-> %p\n",1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) fp_e2i_large\b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) fp_set_sr FPSR_EXC_OPERR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) move.\s #inf,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) tst.w (-4,%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) addq.\s #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) 1: printf PCONV,"-> %p\n",1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) fp_e2i_huge\b:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) move.\s (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) jeq fp_e2i_large\b
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) | fp_normalize_ext has set this bit already
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) | and made the number nonsignaling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) 1: fp_tst_sr FPSR_EXC_SNAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) fp_set_sr FPSR_EXC_OPERR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) 1: printf PCONV,"-> %p\n",1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) .endm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) fp_conv_ext2long:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) conv_ext2int l,32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) fp_conv_ext2short:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) conv_ext2int w,16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) fp_conv_ext2byte:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) conv_ext2int b,8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) fp_conv_ext2double:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) jsr fp_normalize_double
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) printf PCONV,"e2d: %p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) printf PCONV,"), "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) move.l (%a0)+,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) cmp.w #0x7fff,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) move.w #0x7ff,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) move.l (%a0)+,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) jra 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) 1: sub.w #0x3fff-0x3ff,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) move.l (%a0)+,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) jmi 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) clr.w %d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) 2: lsl.w #5,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) lsl.l #7,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) lsl.l #8,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) lsl.l #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) lsr.l #4,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) lsr.l #8,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) or.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) putuser.l %d0,(%a1)+,fp_err_ua2,%a1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) moveq #21,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) lsl.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) move.l (%a0),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) lsr.l #4,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) lsr.l #7,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) or.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) putuser.l %d0,(%a1),fp_err_ua2,%a1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) #ifdef FPU_EMU_DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) getuser.l %a1@(-4),%d0,fp_err_ua2,%a1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) getuser.l %a1@(0),%d1,fp_err_ua2,%a1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) printf PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) fp_conv_ext2single:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) jsr fp_normalize_single
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) printf PCONV,"e2s: %p(",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) printx PCONV,%a0@
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) printf PCONV,"), "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) move.l (%a0)+,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) cmp.w #0x7fff,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) move.w #0xff,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) move.l (%a0)+,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) jra 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) 1: sub.w #0x3fff-0x7f,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) move.l (%a0)+,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) jmi 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) clr.w %d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) 2: lsl.w #8,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) lsl.l #7,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) lsl.l #8,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) bclr #31,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) lsr.l #8,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) or.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) printf PCONV,"%08x\n",1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) rts
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) | special return addresses for instr that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) | encode the rounding precision in the opcode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) | (e.g. fsmove,fdmove)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) fp_finalrounding_single:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) addq.l #8,%sp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) jsr fp_normalize_ext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) jsr fp_normalize_single
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) jra fp_finaltest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) fp_finalrounding_single_fast:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) addq.l #8,%sp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) jsr fp_normalize_ext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) jsr fp_normalize_single_fast
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) jra fp_finaltest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) fp_finalrounding_double:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) addq.l #8,%sp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) jsr fp_normalize_ext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) jsr fp_normalize_double
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) jra fp_finaltest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) | fp_finaltest:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) | set the emulated status register based on the outcome of an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) | emulated instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) fp_finalrounding:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) addq.l #8,%sp
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) | printf ,"f: %p\n",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) jsr fp_normalize_ext
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) move.w (FPD_PREC,FPDATA),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) subq.w #1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) jcs fp_finaltest
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) jsr fp_normalize_single
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) jra 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) 1: jsr fp_normalize_double
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) 2:| printf ,"f: %p\n",1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) fp_finaltest:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) | First, we do some of the obvious tests for the exception
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) | status byte and condition code bytes of fp_sr here, so that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) | they do not have to be handled individually by every
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) | emulated instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) clr.l %d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) addq.l #1,%a0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) tst.b (%a0)+ | sign
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) bset #FPSR_CC_NEG-24,%d0 | N bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) 1: cmp.w #0x7fff,(%a0)+ | exponent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) jeq 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) | test for zero
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) moveq #FPSR_CC_Z-24,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) tst.l (%a0)+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) jne 9f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) jne 9f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) jra 8f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) | infinitiv and NAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) 2: moveq #FPSR_CC_NAN-24,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) move.l (%a0)+,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) lsl.l #1,%d2 | ignore high bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) jne 8f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) tst.l (%a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) jne 8f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) moveq #FPSR_CC_INF-24,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) 8: bset %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) 9: move.b %d0,(FPD_FPSR+0,FPDATA) | set condition test result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) | move instructions enter here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) | Here, we test things in the exception status byte, and set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) | other things in the accrued exception byte accordingly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) | Emulated instructions can set various things in the former,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) | as defined in fp_emu.h.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) fp_final:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) move.l (FPD_FPSR,FPDATA),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) btst #FPSR_EXC_SNAN,%d0 | EXC_SNAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) btst #FPSR_EXC_OPERR,%d0 | EXC_OPERR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) jeq 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) 1: bset #FPSR_AEXC_IOP,%d0 | set IOP bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) 2: btst #FPSR_EXC_OVFL,%d0 | EXC_OVFL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) bset #FPSR_AEXC_OVFL,%d0 | set OVFL bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) 1: btst #FPSR_EXC_UNFL,%d0 | EXC_UNFL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) btst #FPSR_EXC_INEX2,%d0 | EXC_INEX2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) bset #FPSR_AEXC_UNFL,%d0 | set UNFL bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) 1: btst #FPSR_EXC_DZ,%d0 | EXC_INEX1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) bset #FPSR_AEXC_DZ,%d0 | set DZ bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) 1: btst #FPSR_EXC_OVFL,%d0 | EXC_OVFL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) btst #FPSR_EXC_INEX2,%d0 | EXC_INEX2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) jne 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) btst #FPSR_EXC_INEX1,%d0 | EXC_INEX1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) jeq 2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) 1: bset #FPSR_AEXC_INEX,%d0 | set INEX bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) 2: move.l %d0,(FPD_FPSR,FPDATA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) | same as above, greatly optimized, but untested (yet)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) move.l %d0,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) lsr.l #5,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) move.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) lsr.l #4,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) or.l %d0,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) and.b #0x08,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) move.l %d2,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) lsr.l #6,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) or.l %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) move.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) lsr.l #4,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) or.b #0xdf,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) and.b %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) move.l %d2,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) lsr.l #7,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) and.b #0x80,%d1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) or.b %d1,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) and.b #0xf8,%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) or.b %d0,%d2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) move.l %d2,(FPD_FPSR,FPDATA)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) move.b (FPD_FPSR+2,FPDATA),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) and.b (FPD_FPCR+2,FPDATA),%d0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) jeq 1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) printf ,"send signal!!!\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) 1: jra fp_end