123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608 |
- ; SF format is:
- ;
- ; [sign] 1.[23bits] E[8bits(n-127)]
- ;
- ; SEEEEEEE Emmmmmmm mmmmmmmm mmmmmmmm
- ;
- ; [A+0] mmmmmmmm
- ; [A+1] mmmmmmmm
- ; [A+2] Emmmmmmm
- ; [A+3] SEEEEEEE
- ;
- ; Special values (xxx != 0):
- ;
- ; s1111111 10000000 00000000 00000000 infinity
- ; s1111111 1xxxxxxx xxxxxxxx xxxxxxxx NaN
- ; s0000000 00000000 00000000 00000000 zero
- ; s0000000 0xxxxxxx xxxxxxxx xxxxxxxx denormals
- ;
- ; Note that CMPtype is "signed char" for rl78
- ;
-
- #include "vregs.h"
- #define Z PSW.6
- START_FUNC ___negsf2
- ;; Negate the floating point value.
- ;; Input at [SP+4]..[SP+7].
- ;; Output to R8..R11.
- movw ax, [SP+4]
- movw r8, ax
- movw ax, [SP+6]
- xor a, #0x80
- movw r10, ax
- ret
- END_FUNC ___negsf2
- ;; ------------------internal functions used by later code --------------
- START_FUNC __int_isnan
- ;; [HL] points to value, returns Z if it's a NaN
- mov a, [hl+2]
- and a, #0x80
- mov x, a
- mov a, [hl+3]
- and a, #0x7f
- cmpw ax, #0x7f80
- skz
- ret ; return NZ if not NaN
- mov a, [hl+2]
- and a, #0x7f
- or a, [hl+1]
- or a, [hl]
- bnz $1f
- clr1 Z ; Z, normal
- ret
- 1:
- set1 Z ; nan
- ret
- END_FUNC __int_isnan
- START_FUNC __int_eithernan
- ;; call from toplevel functions, returns Z if either number is a NaN,
- ;; or NZ if both are OK.
- movw ax, sp
- addw ax, #8
- movw hl, ax
- call $!__int_isnan
- bz $1f
- movw ax, sp
- addw ax, #12
- movw hl, ax
- call $!__int_isnan
- 1:
- ret
- END_FUNC __int_eithernan
- START_FUNC __int_iszero
- ;; [HL] points to value, returns Z if it's zero
- mov a, [hl+3]
- and a, #0x7f
- or a, [hl+2]
- or a, [hl+1]
- or a, [hl]
- ret
- END_FUNC __int_iszero
- START_FUNC __int_cmpsf
- ;; This is always called from some other function here,
- ;; so the stack offsets are adjusted accordingly.
- ;; X [SP+8] <=> Y [SP+12] : <a> <=> 0
- movw ax, sp
- addw ax, #8
- movw hl, ax
- call $!__int_iszero
- bnz $1f
- movw ax, sp
- addw ax, #12
- movw hl, ax
- call $!__int_iszero
- bnz $2f
- ;; At this point, both args are zero.
- mov a, #0
- ret
- 2:
- movw ax, sp
- addw ax, #8
- movw hl, ax
- 1:
- ;; At least one arg is non-zero so we can just compare magnitudes.
- ;; Args are [HL] and [HL+4].
- mov a, [HL+3]
- xor a, [HL+7]
- mov1 cy, a.7
- bnc $1f
- mov a, [HL+3]
- sar a, 7
- or a, #1
- ret
- 1: ;; Signs the same, compare magnitude. It's safe to lump
- ;; the sign bits, exponent, and mantissa together here, since they're
- ;; stored in the right sequence.
- movw ax, [HL+2]
- cmpw ax, [HL+6]
- bc $ybig_cmpsf ; branch if X < Y
- bnz $xbig_cmpsf ; branch if X > Y
- movw ax, [HL]
- cmpw ax, [HL+4]
- bc $ybig_cmpsf ; branch if X < Y
- bnz $xbig_cmpsf ; branch if X > Y
- mov a, #0
- ret
- xbig_cmpsf: ; |X| > |Y| so return A = 1 if pos, 0xff if neg
- mov a, [HL+3]
- sar a, 7
- or a, #1
- ret
- ybig_cmpsf: ; |X| < |Y| so return A = 0xff if pos, 1 if neg
- mov a, [HL+3]
- xor a, #0x80
- sar a, 7
- or a, #1
- ret
- END_FUNC __int_cmpsf
- ;; ----------------------------------------------------------
- START_FUNC ___cmpsf2
- ;; This functions calculates "A <=> B". That is, if A is less than B
- ;; they return -1, if A is greater than B, they return 1, and if A
- ;; and B are equal they return 0. If either argument is NaN the
- ;; behaviour is undefined.
- ;; Input at [SP+4]..[SP+7].
- ;; Output to R8..R9.
- call $!__int_eithernan
- bnz $1f
- movw r8, #1
- ret
- 1:
- call $!__int_cmpsf
- mov r8, a
- sar a, 7
- mov r9, a
- ret
- END_FUNC ___cmpsf2
- ;; ----------------------------------------------------------
- ;; These functions are all basically the same as ___cmpsf2
- ;; except that they define how they handle NaNs.
- START_FUNC ___eqsf2
- ;; Returns zero iff neither argument is NaN
- ;; and both arguments are equal.
- START_ANOTHER_FUNC ___nesf2
- ;; Returns non-zero iff either argument is NaN or the arguments are
- ;; unequal. Effectively __nesf2 is the same as __eqsf2
- START_ANOTHER_FUNC ___lesf2
- ;; Returns a value less than or equal to zero if neither
- ;; argument is NaN, and the first is less than or equal to the second.
- START_ANOTHER_FUNC ___ltsf2
- ;; Returns a value less than zero if neither argument is
- ;; NaN, and the first is strictly less than the second.
- ;; Input at [SP+4]..[SP+7].
- ;; Output to R8.
- mov r8, #1
- ;;; Fall through
- START_ANOTHER_FUNC __int_cmp_common
- call $!__int_eithernan
- sknz
- ;; return value (pre-filled-in below) for "either is nan"
- ret
- call $!__int_cmpsf
- mov r8, a
- ret
- END_ANOTHER_FUNC __int_cmp_common
- END_ANOTHER_FUNC ___ltsf2
- END_ANOTHER_FUNC ___lesf2
- END_ANOTHER_FUNC ___nesf2
- END_FUNC ___eqsf2
- START_FUNC ___gesf2
- ;; Returns a value greater than or equal to zero if neither argument
- ;; is a NaN and the first is greater than or equal to the second.
- START_ANOTHER_FUNC ___gtsf2
- ;; Returns a value greater than zero if neither argument
- ;; is NaN, and the first is strictly greater than the second.
- mov r8, #0xffff
- br $__int_cmp_common
- END_ANOTHER_FUNC ___gtsf2
- END_FUNC ___gesf2
- ;; ----------------------------------------------------------
- START_FUNC ___unordsf2
- ;; Returns a nonzero value if either argument is NaN, otherwise 0.
- call $!__int_eithernan
- movw r8, #0
- sknz ; this is from the call, not the movw
- movw r8, #1
- ret
-
- END_FUNC ___unordsf2
- ;; ----------------------------------------------------------
- START_FUNC ___fixsfsi
- ;; Converts its floating point argument into a signed long,
- ;; rounding toward zero.
- ;; The behaviour with NaNs and Infinities is not well defined.
- ;; We choose to return 0 for NaNs, -INTMAX for -inf and INTMAX for +inf.
- ;; This matches the behaviour of the C function in libgcc2.c.
- ;; Input at [SP+4]..[SP+7], result is in (lsb) R8..R11 (msb).
- ;; Special case handling for infinities as __fixunssfsi
- ;; will not give us the values that we want.
- movw ax, sp
- addw ax, #4
- movw hl, ax
- call !!__int_isinf
- bnz $1f
- mov a, [SP+7]
- bt a.7, $2f
- ;; +inf
- movw r8, #-1
- movw r10, #0x7fff
- ret
- ;; -inf
- 2: mov r8, #0
- mov r10, #0x8000
- ret
-
- ;; Load the value into r10:r11:X:A
- 1: movw ax, [SP+4]
- movw r10, ax
- movw ax, [SP+6]
- ;; If the value is positive we can just use __fixunssfsi
- bf a.7, $__int_fixunssfsi
- ;; Otherwise we negate the value, call __fixunssfsi and
- ;; then negate its result.
- clr1 a.7
- call $!__int_fixunssfsi
- movw ax, #0
- subw ax, r8
- movw r8, ax
- movw ax, #0
- sknc
- decw ax
- subw ax, r10
- movw r10, ax
-
- ;; Check for a positive result (which should only happen when
- ;; __fixunssfsi returns UINTMAX or 0). In such cases just return 0.
- mov a, r11
- bt a.7, $1f
- movw r10,#0x0
- movw r8, #0x0
- 1: ret
- END_FUNC ___fixsfsi
- START_FUNC ___fixunssfsi
- ;; Converts its floating point argument into an unsigned long
- ;; rounding towards zero. Negative arguments all become zero.
- ;; We choose to return 0 for NaNs and -inf, but UINTMAX for +inf.
- ;; This matches the behaviour of the C function in libgcc2.c.
- ;; Input at [SP+4]..[SP+7], result is in (lsb) R8..R11 (msb)
-
- ;; Get the input value.
- movw ax, [SP+4]
- movw r10, ax
- movw ax, [SP+6]
- ;; Fall through into the internal function.
-
- .global __int_fixunssfsi
- __int_fixunssfsi:
- ;; Input in (lsb) r10.r11.x.a (msb).
- ;; Test for a negative input. We shift the other bits at the
- ;; same time so that A ends up holding the whole exponent:
- ;;
- ;; before:
- ;; SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
- ;; A X R11 R10
- ;;
- ;; after:
- ;; EEEEEEEE MMMMMMM0 MMMMMMMM MMMMMMMM
- ;; A X R11 R10
- shlw ax, 1
- bnc $1f
- ;; Return zero.
- 2: movw r8, #0
- movw r10, #0
- ret
- ;; An exponent of -1 is either a NaN or infinity.
- 1: cmp a, #-1
- bnz $3f
- ;; For NaN we return 0. For infinity we return UINTMAX.
- mov a, x
- or a, r10
- or a, r11
- cmp0 a
- bnz $2b
- 6: movw r8, #-1 ; -1 => UINT_MAX
- movw r10, #-1
- ret
-
- ;; If the exponent is negative the value is < 1 and so the
- ;; converted value is 0. Note we must allow for the bias
- ;; applied to the exponent. Thus a value of 127 in the
- ;; EEEEEEEE bits actually represents an exponent of 0, whilst
- ;; a value less than 127 actually represents a negative exponent.
- ;; Also if the EEEEEEEE bits are all zero then this represents
- ;; either a denormal value or 0.0. Either way for these values
- ;; we return 0.
- 3: sub a, #127
- bc $2b
- ;; A now holds the bias adjusted exponent, which is known to be >= 0.
- ;; If the exponent is > 31 then the conversion will overflow.
- cmp a, #32
- bnc $6b
- 4:
- ;; Save the exponent in H. We increment it by one because we want
- ;; to be sure that the loop below will always execute at least once.
- inc a
- mov h, a
- ;; Get the top 24 bits of the mantissa into A:X:R10
- ;; Include the implicit 1-bit that is inherent in the IEEE fp format.
- ;;
- ;; before:
- ;; EEEEEEEE MMMMMMM0 MMMMMMMM MMMMMMMM
- ;; H X R11 R10
- ;; after:
- ;; EEEEEEEE 1MMMMMMM MMMMMMMM MMMMMMMM
- ;; H A X R10
- mov a, r11
- xch a, x
- shr a, 1
- set1 a.7
- ;; Clear B:C:R12:R13
- movw bc, #0
- movw r12, #0
- ;; Shift bits from the mantissa (A:X:R10) into (B:C:R12:R13),
- ;; decrementing the exponent as we go.
- ;; before:
- ;; MMMMMMMM MMMMMMMM MMMMMMMM xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
- ;; A X R10 B C R12 R13
- ;; first iter:
- ;; MMMMMMMM MMMMMMMM MMMMMMM0 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxM
- ;; A X R10 B C R12 R13
- ;; second iter:
- ;; MMMMMMMM MMMMMMMM MMMMMM00 xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxMM
- ;; A X R10 B C R12 R13
- ;; etc.
- 5:
- xch a, r10
- shl a, 1
- xch a, r10
-
- rolwc ax, 1
-
- xch a, r13
- rolc a, 1
- xch a, r13
- xch a, r12
- rolc a, 1
- xch a, r12
- rolwc bc, 1
-
- dec h
- bnz $5b
- ;; Result is currently in (lsb) r13.r12. c. b. (msb),
- ;; Move it into (lsb) r8. r9. r10. r11 (msb).
- mov a, r13
- mov r8, a
- mov a, r12
- mov r9, a
-
- mov a, c
- mov r10, a
- mov a, b
- mov r11, a
- ret
- END_FUNC ___fixunssfsi
- ;; ------------------------------------------------------------------------
- START_FUNC ___floatsisf
- ;; Converts its signed long argument into a floating point.
- ;; Argument in [SP+4]..[SP+7]. Result in R8..R11.
- ;; Get the argument.
- movw ax, [SP+4]
- movw bc, ax
- movw ax, [SP+6]
- ;; Test the sign bit. If the value is positive then drop into
- ;; the unsigned conversion routine.
- bf a.7, $2f
- ;; If negative convert to positive ...
- movw hl, ax
- movw ax, #0
- subw ax, bc
- movw bc, ax
- movw ax, #0
- sknc
- decw ax
- subw ax, hl
- ;; If the result is negative then the input was 0x80000000 and
- ;; we want to return -0.0, which will not happen if we call
- ;; __int_floatunsisf.
- bt a.7, $1f
- ;; Call the unsigned conversion routine.
- call $!__int_floatunsisf
- ;; Negate the result.
- set1 r11.7
- ;; Done.
- ret
- 1: ;; Return -0.0 aka 0xcf000000
- clrb a
- mov r8, a
- mov r9, a
- mov r10, a
- mov a, #0xcf
- mov r11, a
- ret
-
- START_ANOTHER_FUNC ___floatunsisf
- ;; Converts its unsigned long argument into a floating point.
- ;; Argument in [SP+4]..[SP+7]. Result in R8..R11.
- ;; Get the argument.
- movw ax, [SP+4]
- movw bc, ax
- movw ax, [SP+6]
- 2: ;; Internal entry point from __floatsisf
- ;; Input in AX (high) and BC (low)
- .global __int_floatunsisf
- __int_floatunsisf:
-
- ;; Special case handling for zero.
- cmpw ax, #0
- bnz $1f
- movw ax, bc
- cmpw ax, #0
- movw ax, #0
- bnz $1f
- ;; Return 0.0
- movw r8, ax
- movw r10, ax
- ret
- 1: ;; Pre-load the loop count/exponent.
- ;; Exponents are biased by 0x80 and we start the loop knowing that
- ;; we are going to skip the highest set bit. Hence the highest value
- ;; that we can get for the exponent is 0x1e (bits from input) + 0x80 = 0x9e.
- mov h, #0x9e
- ;; Move bits off the top of AX:BC until we hit a 1 bit.
- ;; Decrement the count of remaining bits as we go.
- 2: shlw bc, 1
- rolwc ax, 1
- bc $3f
- dec h
- br $2b
- ;; Ignore the first one bit - it is implicit in the IEEE format.
- ;; The count of remaining bits is the exponent.
- ;; Assemble the final floating point value. We have...
- ;; before:
- ;; EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM xxxxxxxx
- ;; H A X B C
- ;; after:
- ;; 0EEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
- ;; R11 R10 R9 R8
-
- 3: shrw ax, 1
- mov r10, a
- mov a, x
- mov r9, a
- mov a, b
- rorc a, 1
- ;; If the bottom bit of B was set before we shifted it out then we
- ;; need to round the result up. Unless none of the bits in C are set.
- ;; In this case we are exactly half-way between two values, and we
- ;; round towards an even value. We round up by increasing the
- ;; mantissa by 1. If this results in a zero mantissa we have to
- ;; increment the exponent. We round down by ignoring the dropped bits.
-
- bnc $4f
- cmp0 c
- sknz
- bf a.0, $4f
- 5: ;; Round the mantissa up by 1.
- add a, #1
- addc r9, #0
- addc r10, #0
- bf r10.7, $4f
- inc h
- clr1 r10.7
- 4: mov r8, a
- mov a, h
- shr a, 1
- mov r11, a
- sknc
- set1 r10.7
- ret
- END_ANOTHER_FUNC ___floatunsisf
- END_FUNC ___floatsisf
|