2016-05-15 Harald Anlauf <anlauf@gmx.de>
[official-gcc.git] / libgcc / config / rl78 / fpbit-sf.S
blob042facee14eae64c95f77e3bc2f25dda7a61d454
1 ; SF format is:
3 ; [sign] 1.[23bits] E[8bits(n-127)]
5 ; SEEEEEEE Emmmmmmm mmmmmmmm mmmmmmmm
7 ; [A+0] mmmmmmmm
8 ; [A+1] mmmmmmmm
9 ; [A+2] Emmmmmmm
10 ; [A+3] SEEEEEEE
12 ; Special values (xxx != 0):
14 ;  s1111111 10000000 00000000 00000000  infinity
15 ;  s1111111 1xxxxxxx xxxxxxxx xxxxxxxx  NaN
16 ;  s0000000 00000000 00000000 00000000  zero
17 ;  s0000000 0xxxxxxx xxxxxxxx xxxxxxxx  denormals
19 ; Note that CMPtype is "signed char" for rl78
21         
22 #include "vregs.h"
24 #define Z       PSW.6
26 START_FUNC      ___negsf2
28         ;; Negate the floating point value.
29         ;; Input at [SP+4]..[SP+7].
30         ;; Output to R8..R11.
32         movw    ax, [SP+4]
33         movw    r8, ax
34         movw    ax, [SP+6]
35         xor     a, #0x80
36         movw    r10, ax
37         ret
39 END_FUNC        ___negsf2
41 ;; ------------------internal functions used by later code --------------
43 START_FUNC      __int_isnan
45         ;; [HL] points to value, returns Z if it's a NaN
47         mov     a, [hl+2]
48         and     a, #0x80
49         mov     x, a
50         mov     a, [hl+3]
51         and     a, #0x7f
52         cmpw    ax, #0x7f80
53         skz
54         ret                     ; return NZ if not NaN
55         mov     a, [hl+2]
56         and     a, #0x7f
57         or      a, [hl+1]
58         or      a, [hl]
59         bnz     $1f
60         clr1    Z               ; Z, normal
61         ret
63         set1    Z               ; nan
64         ret
66 END_FUNC        __int_isnan
68 START_FUNC      __int_eithernan
70         ;; call from toplevel functions, returns Z if either number is a NaN,
71         ;; or NZ if both are OK.
73         movw    ax, sp
74         addw    ax, #8
75         movw    hl, ax
76         call    $!__int_isnan
77         bz      $1f
79         movw    ax, sp
80         addw    ax, #12
81         movw    hl, ax
82         call    $!__int_isnan
84         ret
86 END_FUNC        __int_eithernan
88 START_FUNC      __int_iszero
90         ;; [HL] points to value, returns Z if it's zero
92         mov     a, [hl+3]
93         and     a, #0x7f
94         or      a, [hl+2]
95         or      a, [hl+1]
96         or      a, [hl]
97         ret
99 END_FUNC        __int_iszero
101 START_FUNC      __int_cmpsf
103         ;; This is always called from some other function here,
104         ;; so the stack offsets are adjusted accordingly.
106         ;; X [SP+8] <=> Y [SP+12] : <a> <=> 0
108         movw    ax, sp
109         addw    ax, #8
110         movw    hl, ax
111         call    $!__int_iszero
112         bnz     $1f
114         movw    ax, sp
115         addw    ax, #12
116         movw    hl, ax
117         call    $!__int_iszero
118         bnz     $2f
119         ;; At this point, both args are zero.
120         mov     a, #0
121         ret
124         movw    ax, sp
125         addw    ax, #8
126         movw    hl, ax
128         ;; At least one arg is non-zero so we can just compare magnitudes.
129         ;; Args are [HL] and [HL+4].
131         mov     a, [HL+3]
132         xor     a, [HL+7]
133         mov1    cy, a.7
134         bnc     $1f
136         mov     a, [HL+3]
137         sar     a, 7
138         or      a, #1
139         ret
141 1:      ;; Signs the same, compare magnitude.  It's safe to lump
142         ;; the sign bits, exponent, and mantissa together here, since they're
143         ;; stored in the right sequence.
144         movw    ax, [HL+2]
145         cmpw    ax, [HL+6]
146         bc      $ybig_cmpsf     ; branch if X < Y
147         bnz     $xbig_cmpsf     ; branch if X > Y
149         movw    ax, [HL]
150         cmpw    ax, [HL+4]
151         bc      $ybig_cmpsf     ; branch if X < Y
152         bnz     $xbig_cmpsf     ; branch if X > Y
154         mov     a, #0
155         ret
157 xbig_cmpsf:                     ; |X| > |Y| so return A = 1 if pos, 0xff if neg
158         mov     a, [HL+3]
159         sar     a, 7
160         or      a, #1
161         ret
162 ybig_cmpsf:                     ; |X| < |Y| so return A = 0xff if pos, 1 if neg
163         mov     a, [HL+3]
164         xor     a, #0x80
165         sar     a, 7
166         or      a, #1
167         ret
169 END_FUNC        __int_cmpsf
171 ;; ----------------------------------------------------------
173 START_FUNC      ___cmpsf2
174         ;; This functions calculates "A <=> B".  That is, if A is less than B
175         ;; they return -1, if A is greater than B, they return 1, and if A
176         ;; and B are equal they return 0.  If either argument is NaN the
177         ;; behaviour is undefined.
179         ;; Input at [SP+4]..[SP+7].
180         ;; Output to R8..R9.
182         call    $!__int_eithernan
183         bnz     $1f
184         movw    r8, #1
185         ret
187         call    $!__int_cmpsf
188         mov     r8, a
189         sar     a, 7
190         mov     r9, a
191         ret
193 END_FUNC        ___cmpsf2
195 ;; ----------------------------------------------------------
197         ;; These functions are all basically the same as ___cmpsf2
198         ;; except that they define how they handle NaNs.
200 START_FUNC              ___eqsf2
201         ;; Returns zero iff neither argument is NaN
202         ;; and both arguments are equal.
203 START_ANOTHER_FUNC      ___nesf2
204         ;; Returns non-zero iff either argument is NaN or the arguments are
205         ;; unequal.  Effectively __nesf2 is the same as __eqsf2
206 START_ANOTHER_FUNC      ___lesf2
207         ;; Returns a value less than or equal to zero if neither
208         ;; argument is NaN, and the first is less than or equal to the second.
209 START_ANOTHER_FUNC      ___ltsf2
210         ;; Returns a value less than zero if neither argument is
211         ;; NaN, and the first is strictly less than the second.
213         ;; Input at [SP+4]..[SP+7].
214         ;; Output to R8.
216         mov     r8, #1
218 ;;;  Fall through
220 START_ANOTHER_FUNC      __int_cmp_common
222         call    $!__int_eithernan
223         sknz
224         ;; return value (pre-filled-in below) for "either is nan"
225         ret
227         call    $!__int_cmpsf
228         mov     r8, a
229         ret
231 END_ANOTHER_FUNC        __int_cmp_common
232 END_ANOTHER_FUNC        ___ltsf2
233 END_ANOTHER_FUNC        ___lesf2
234 END_ANOTHER_FUNC        ___nesf2
235 END_FUNC                ___eqsf2
237 START_FUNC              ___gesf2
238         ;; Returns a value greater than or equal to zero if neither argument
239         ;; is a NaN and the first is greater than or equal to the second.
240 START_ANOTHER_FUNC      ___gtsf2
241         ;; Returns a value greater than zero if neither argument
242         ;; is NaN, and the first is strictly greater than the second.
244         mov     r8, #0xffff
245         br      $__int_cmp_common
247 END_ANOTHER_FUNC        ___gtsf2
248 END_FUNC                ___gesf2
250 ;; ----------------------------------------------------------
252 START_FUNC      ___unordsf2
253         ;; Returns a nonzero value if either argument is NaN, otherwise 0.
255         call    $!__int_eithernan
256         movw    r8, #0
257         sknz                    ; this is from the call, not the movw
258         movw    r8, #1
259         ret
260         
261 END_FUNC        ___unordsf2
263 ;; ----------------------------------------------------------
265 START_FUNC      ___fixsfsi
266         ;; Converts its floating point argument into a signed long,
267         ;; rounding toward zero.
268         ;; The behaviour with NaNs and Infinities is not well defined.
269         ;; We choose to return 0 for NaNs, -INTMAX for -inf and INTMAX for +inf.
270         ;; This matches the behaviour of the C function in libgcc2.c.
272         ;; Input at [SP+4]..[SP+7], result is in (lsb) R8..R11 (msb).
274         ;; Special case handling for infinities as __fixunssfsi
275         ;; will not give us the values that we want.
276         movw    ax, sp
277         addw    ax, #4
278         movw    hl, ax
279         call    !!__int_isinf
280         bnz     $1f
281         mov     a, [SP+7]
282         bt      a.7, $2f
283         ;; +inf
284         movw    r8, #-1
285         movw    r10, #0x7fff
286         ret
287         ;; -inf
288 2:      mov     r8, #0
289         mov     r10, #0x8000
290         ret
291         
292         ;; Load the value into r10:r11:X:A
293 1:      movw    ax, [SP+4]
294         movw    r10, ax
295         movw    ax, [SP+6]
297         ;; If the value is positive we can just use __fixunssfsi
298         bf      a.7, $__int_fixunssfsi
300         ;; Otherwise we negate the value, call __fixunssfsi and
301         ;; then negate its result.
302         clr1    a.7
303         call    $!__int_fixunssfsi
305         movw    ax, #0
306         subw    ax, r8
307         movw    r8, ax
308         movw    ax, #0
309         sknc
310         decw    ax
311         subw    ax, r10
312         movw    r10, ax
313         
314         ;; Check for a positive result (which should only happen when
315         ;; __fixunssfsi returns UINTMAX or 0).  In such cases just return 0.
316         mov     a, r11
317         bt      a.7, $1f
318         movw    r10,#0x0
319         movw    r8, #0x0
321 1:      ret
323 END_FUNC        ___fixsfsi
325 START_FUNC      ___fixunssfsi
326         ;; Converts its floating point argument into an unsigned long
327         ;; rounding towards zero.  Negative arguments all become zero.
328         ;; We choose to return 0 for NaNs and -inf, but UINTMAX for +inf.
329         ;; This matches the behaviour of the C function in libgcc2.c.
331         ;; Input at [SP+4]..[SP+7], result is in (lsb) R8..R11 (msb)
332         
333         ;; Get the input value.
334         movw    ax, [SP+4]
335         movw    r10, ax
336         movw    ax, [SP+6]
338         ;; Fall through into the internal function.
339         
340         .global __int_fixunssfsi
341 __int_fixunssfsi:
342         ;; Input in (lsb) r10.r11.x.a (msb).
344         ;; Test for a negative input.  We shift the other bits at the
345         ;; same time so that A ends up holding the whole exponent:
346         ;;
347         ;; before:
348         ;;   SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
349         ;;       A       X        R11     R10
350         ;;
351         ;; after:
352         ;;   EEEEEEEE MMMMMMM0 MMMMMMMM MMMMMMMM
353         ;;       A       X        R11     R10
354         shlw    ax, 1
355         bnc     $1f
357         ;; Return zero.
358 2:      movw    r8, #0
359         movw    r10, #0
360         ret
362         ;; An exponent of -1 is either a NaN or infinity.
363 1:      cmp     a, #-1
364         bnz     $3f
365         ;; For NaN we return 0.  For infinity we return UINTMAX.
366         mov     a, x
367         or      a, r10
368         or      a, r11
369         cmp0    a
370         bnz     $2b
372 6:      movw    r8, #-1         ; -1 => UINT_MAX
373         movw    r10, #-1
374         ret
375         
376         ;; If the exponent is negative the value is < 1 and so the
377         ;; converted value is 0.  Note we must allow for the bias
378         ;; applied to the exponent.  Thus a value of 127 in the
379         ;; EEEEEEEE bits actually represents an exponent of 0, whilst
380         ;; a value less than 127 actually represents a negative exponent.
381         ;; Also if the EEEEEEEE bits are all zero then this represents
382         ;; either a denormal value or 0.0.  Either way for these values
383         ;; we return 0.
384 3:      sub     a, #127
385         bc      $2b
387         ;; A now holds the bias adjusted exponent, which is known to be >= 0.
388         ;; If the exponent is > 31 then the conversion will overflow.
389         cmp     a, #32
390         bnc     $6b
392         ;; Save the exponent in H.  We increment it by one because we want
393         ;; to be sure that the loop below will always execute at least once.
394         inc     a
395         mov     h, a
397         ;; Get the top 24 bits of the mantissa into A:X:R10
398         ;; Include the implicit 1-bit that is inherent in the IEEE fp format.
399         ;;
400         ;; before:
401         ;;   EEEEEEEE MMMMMMM0 MMMMMMMM MMMMMMMM
402         ;;       H       X        R11     R10
403         ;; after:
404         ;;   EEEEEEEE 1MMMMMMM MMMMMMMM MMMMMMMM
405         ;;       H       A        X       R10
407         mov     a, r11
408         xch     a, x
409         shr     a, 1
410         set1    a.7
412         ;; Clear B:C:R12:R13
413         movw    bc, #0
414         movw    r12, #0
416         ;; Shift bits from the mantissa (A:X:R10) into (B:C:R12:R13),
417         ;; decrementing the exponent as we go.
419         ;; before:
420         ;;   MMMMMMMM MMMMMMMM MMMMMMMM   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
421         ;;       A        X      R10          B       C       R12      R13
422         ;; first iter:
423         ;;   MMMMMMMM MMMMMMMM MMMMMMM0   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxM
424         ;;       A        X      R10          B       C       R12      R13
425         ;; second iter:
426         ;;   MMMMMMMM MMMMMMMM MMMMMM00   xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxMM
427         ;;       A        X      R10          B       C       R12      R13
428         ;; etc.
430         xch     a, r10
431         shl     a, 1
432         xch     a, r10
433         
434         rolwc   ax, 1
435         
436         xch     a, r13
437         rolc    a, 1
438         xch     a, r13
440         xch     a, r12
441         rolc    a, 1
442         xch     a, r12
444         rolwc   bc, 1
445         
446         dec     h
447         bnz     $5b
449         ;; Result is currently in (lsb) r13.r12. c.  b.  (msb),
450         ;; Move it into           (lsb) r8. r9. r10. r11 (msb).
452         mov     a, r13
453         mov     r8, a
455         mov     a, r12
456         mov     r9, a
457         
458         mov     a, c
459         mov     r10, a
461         mov     a, b
462         mov     r11, a
464         ret
466 END_FUNC        ___fixunssfsi
468 ;; ------------------------------------------------------------------------
470 START_FUNC      ___floatsisf
471         ;; Converts its signed long argument into a floating point.
472         ;; Argument in [SP+4]..[SP+7].  Result in R8..R11.
474         ;; Get the argument.
475         movw    ax, [SP+4]
476         movw    bc, ax
477         movw    ax, [SP+6]
479         ;; Test the sign bit.  If the value is positive then drop into
480         ;; the unsigned conversion routine.
481         bf      a.7, $2f
483         ;; If negative convert to positive ...
484         movw    hl, ax
485         movw    ax, #0
486         subw    ax, bc
487         movw    bc, ax
488         movw    ax, #0
489         sknc
490         decw    ax
491         subw    ax, hl
493         ;; If the result is negative then the input was 0x80000000 and
494         ;; we want to return -0.0, which will not happen if we call
495         ;; __int_floatunsisf.
496         bt      a.7, $1f
498         ;;  Call the unsigned conversion routine.
499         call    $!__int_floatunsisf
501         ;; Negate the result.
502         set1    r11.7
504         ;; Done.
505         ret
507 1:      ;; Return -0.0 aka 0xcf000000
509         clrb    a
510         mov     r8, a
511         mov     r9, a
512         mov     r10, a
513         mov     a, #0xcf
514         mov     r11, a
515         ret
516         
517 START_ANOTHER_FUNC      ___floatunsisf
518         ;; Converts its unsigned long argument into a floating point.
519         ;; Argument in [SP+4]..[SP+7].  Result in R8..R11.
521         ;; Get the argument.
522         movw    ax, [SP+4]
523         movw    bc, ax
524         movw    ax, [SP+6]
526 2:      ;; Internal entry point from __floatsisf
527         ;; Input in AX (high) and BC (low)
528         .global __int_floatunsisf
529 __int_floatunsisf:
530         
531         ;; Special case handling for zero.
532         cmpw    ax, #0
533         bnz     $1f
534         movw    ax, bc
535         cmpw    ax, #0
536         movw    ax, #0
537         bnz     $1f
539         ;; Return 0.0
540         movw    r8, ax
541         movw    r10, ax
542         ret
544 1:      ;; Pre-load the loop count/exponent.
545         ;; Exponents are biased by 0x80 and we start the loop knowing that
546         ;; we are going to skip the highest set bit.  Hence the highest value
547         ;; that we can get for the exponent is 0x1e (bits from input) + 0x80 = 0x9e.
548         mov     h, #0x9e
550         ;; Move bits off the top of AX:BC until we hit a 1 bit.
551         ;; Decrement the count of remaining bits as we go.
553 2:      shlw    bc, 1
554         rolwc   ax, 1
555         bc      $3f
556         dec     h
557         br      $2b
559         ;; Ignore the first one bit - it is implicit in the IEEE format.
560         ;; The count of remaining bits is the exponent.
562         ;; Assemble the final floating point value.  We have...
563         ;; before:
564         ;;   EEEEEEEE MMMMMMMM MMMMMMMM MMMMMMMM xxxxxxxx
565         ;;       H        A       X        B         C
566         ;; after:
567         ;;   0EEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM
568         ;;      R11      R10      R9       R8
570         
571 3:      shrw    ax, 1
572         mov     r10, a
573         mov     a, x
574         mov     r9, a   
576         mov     a, b
577         rorc    a, 1    
579         ;; If the bottom bit of B was set before we shifted it out then we
580         ;; need to round the result up.  Unless none of the bits in C are set.
581         ;; In this case we are exactly half-way between two values, and we
582         ;; round towards an even value.  We round up by increasing the
583         ;; mantissa by 1.  If this results in a zero mantissa we have to
584         ;; increment the exponent.  We round down by ignoring the dropped bits.
585         
586         bnc     $4f
587         cmp0    c
588         sknz    
589         bf      a.0, $4f
591 5:      ;; Round the mantissa up by 1.
592         add     a, #1
593         addc    r9, #0
594         addc    r10, #0
595         bf      r10.7, $4f
596         inc     h
597         clr1    r10.7
599 4:      mov     r8, a
600         mov     a, h
601         shr     a, 1
602         mov     r11, a
603         sknc
604         set1    r10.7
605         ret
607 END_ANOTHER_FUNC        ___floatunsisf  
608 END_FUNC                ___floatsisf