]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgcc/config/rl78/fpbit-sf.S
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / rl78 / fpbit-sf.S
CommitLineData
8410904a
NC
1; SF format is:
2;
3; [sign] 1.[23bits] E[8bits(n-127)]
4;
5; SEEEEEEE Emmmmmmm mmmmmmmm mmmmmmmm
6;
7; [A+0] mmmmmmmm
8; [A+1] mmmmmmmm
9; [A+2] Emmmmmmm
10; [A+3] SEEEEEEE
11;
12; Special values (xxx != 0):
13;
14; s1111111 10000000 00000000 00000000 infinity
15; s1111111 1xxxxxxx xxxxxxxx xxxxxxxx NaN
16; s0000000 00000000 00000000 00000000 zero
17; s0000000 0xxxxxxx xxxxxxxx xxxxxxxx denormals
18;
19; Note that CMPtype is "signed char" for rl78
20;
21
22#include "vregs.h"
23
24#define Z PSW.6
25
26START_FUNC ___negsf2
27
28 ;; Negate the floating point value.
29 ;; Input at [SP+4]..[SP+7].
30 ;; Output to R8..R11.
31
32 movw ax, [SP+4]
33 movw r8, ax
34 movw ax, [SP+6]
35 xor a, #0x80
36 movw r10, ax
37 ret
38
39END_FUNC ___negsf2
40
41;; ------------------internal functions used by later code --------------
42
43START_FUNC __int_isnan
44
45 ;; [HL] points to value, returns Z if it's a NaN
46
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
621:
63 set1 Z ; nan
64 ret
65
66END_FUNC __int_isnan
67
68START_FUNC __int_eithernan
69
70 ;; call from toplevel functions, returns Z if either number is a NaN,
71 ;; or NZ if both are OK.
72
73 movw ax, sp
74 addw ax, #8
75 movw hl, ax
76 call $!__int_isnan
77 bz $1f
78
79 movw ax, sp
80 addw ax, #12
81 movw hl, ax
82 call $!__int_isnan
831:
84 ret
85
86END_FUNC __int_eithernan
87
88START_FUNC __int_iszero
89
90 ;; [HL] points to value, returns Z if it's zero
91
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
98
99END_FUNC __int_iszero
100
101START_FUNC __int_cmpsf
102
103 ;; This is always called from some other function here,
104 ;; so the stack offsets are adjusted accordingly.
105
106 ;; X [SP+8] <=> Y [SP+12] : <a> <=> 0
107
108 movw ax, sp
109 addw ax, #8
110 movw hl, ax
111 call $!__int_iszero
112 bnz $1f
113
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
122
1232:
124 movw ax, sp
125 addw ax, #8
126 movw hl, ax
1271:
128 ;; At least one arg is non-zero so we can just compare magnitudes.
129 ;; Args are [HL] and [HL+4].
130
131 mov a, [HL+3]
132 xor a, [HL+7]
133 mov1 cy, a.7
134 bnc $1f
135
136 mov a, [HL+3]
137 sar a, 7
138 or a, #1
139 ret
140
1411: ;; 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
148
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
153
154 mov a, #0
155 ret
156
157xbig_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
162ybig_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
168
169END_FUNC __int_cmpsf
170
171;; ----------------------------------------------------------
172
173START_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.
178
179 ;; Input at [SP+4]..[SP+7].
180 ;; Output to R8..R9.
181
182 call $!__int_eithernan
183 bnz $1f
184 movw r8, #1
185 ret
1861:
187 call $!__int_cmpsf
188 mov r8, a
189 sar a, 7
190 mov r9, a
191 ret
192
193END_FUNC ___cmpsf2
194
195;; ----------------------------------------------------------
196
197 ;; These functions are all basically the same as ___cmpsf2
198 ;; except that they define how they handle NaNs.
199
200START_FUNC ___eqsf2
201 ;; Returns zero iff neither argument is NaN
202 ;; and both arguments are equal.
203START_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
206START_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.
209START_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.
212
213 ;; Input at [SP+4]..[SP+7].
214 ;; Output to R8.
215
216 mov r8, #1
217
218;;; Fall through
219
220START_ANOTHER_FUNC __int_cmp_common
221
222 call $!__int_eithernan
223 sknz
224 ;; return value (pre-filled-in below) for "either is nan"
225 ret
226
227 call $!__int_cmpsf
228 mov r8, a
229 ret
230
231END_ANOTHER_FUNC __int_cmp_common
232END_ANOTHER_FUNC ___ltsf2
233END_ANOTHER_FUNC ___lesf2
234END_ANOTHER_FUNC ___nesf2
235END_FUNC ___eqsf2
236
237START_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.
240START_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.
243
244 mov r8, #0xffff
245 br $__int_cmp_common
246
247END_ANOTHER_FUNC ___gtsf2
248END_FUNC ___gesf2
249
250;; ----------------------------------------------------------
251
252START_FUNC ___unordsf2
253 ;; Returns a nonzero value if either argument is NaN, otherwise 0.
254
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
261END_FUNC ___unordsf2
262
263;; ----------------------------------------------------------
264
265START_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.
271
272 ;; Input at [SP+4]..[SP+7], result is in (lsb) R8..R11 (msb).
273
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
2882: mov r8, #0
289 mov r10, #0x8000
290 ret
291
292 ;; Load the value into r10:r11:X:A
2931: movw ax, [SP+4]
294 movw r10, ax
295 movw ax, [SP+6]
296
297 ;; If the value is positive we can just use __fixunssfsi
298 bf a.7, $__int_fixunssfsi
299
300 ;; Otherwise we negate the value, call __fixunssfsi and
301 ;; then negate its result.
302 clr1 a.7
303 call $!__int_fixunssfsi
304
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
320
3211: ret
322
323END_FUNC ___fixsfsi
324
325START_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.
330
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]
337
338 ;; Fall through into the internal function.
339
340 .global __int_fixunssfsi
341__int_fixunssfsi:
342 ;; Input in (lsb) r10.r11.x.a (msb).
343
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
356
357 ;; Return zero.
3582: movw r8, #0
359 movw r10, #0
360 ret
361
362 ;; An exponent of -1 is either a NaN or infinity.
3631: 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
371
3726: 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.
3843: sub a, #127
385 bc $2b
386
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
3914:
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
396
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
406
407 mov a, r11
408 xch a, x
409 shr a, 1
410 set1 a.7
411
412 ;; Clear B:C:R12:R13
413 movw bc, #0
414 movw r12, #0
415
416 ;; Shift bits from the mantissa (A:X:R10) into (B:C:R12:R13),
417 ;; decrementing the exponent as we go.
418
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.
4295:
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
439
440 xch a, r12
441 rolc a, 1
442 xch a, r12
443
444 rolwc bc, 1
445
446 dec h
447 bnz $5b
448
449 ;; Result is currently in (lsb) r13.r12. c. b. (msb),
450 ;; Move it into (lsb) r8. r9. r10. r11 (msb).
451
452 mov a, r13
453 mov r8, a
454
455 mov a, r12
456 mov r9, a
457
458 mov a, c
459 mov r10, a
460
461 mov a, b
462 mov r11, a
463
464 ret
465
466END_FUNC ___fixunssfsi
467
468;; ------------------------------------------------------------------------
469
470START_FUNC ___floatsisf
471 ;; Converts its signed long argument into a floating point.
472 ;; Argument in [SP+4]..[SP+7]. Result in R8..R11.
473
474 ;; Get the argument.
475 movw ax, [SP+4]
476 movw bc, ax
477 movw ax, [SP+6]
478
479 ;; Test the sign bit. If the value is positive then drop into
480 ;; the unsigned conversion routine.
481 bf a.7, $2f
482
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
492
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
497
498 ;; Call the unsigned conversion routine.
499 call $!__int_floatunsisf
500
501 ;; Negate the result.
502 set1 r11.7
503
504 ;; Done.
505 ret
506
5071: ;; Return -0.0 aka 0xcf000000
508
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
517START_ANOTHER_FUNC ___floatunsisf
518 ;; Converts its unsigned long argument into a floating point.
519 ;; Argument in [SP+4]..[SP+7]. Result in R8..R11.
520
521 ;; Get the argument.
522 movw ax, [SP+4]
523 movw bc, ax
524 movw ax, [SP+6]
525
5262: ;; 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
538
539 ;; Return 0.0
540 movw r8, ax
541 movw r10, ax
542 ret
543
5441: ;; 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
549
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.
552
5532: shlw bc, 1
554 rolwc ax, 1
555 bc $3f
556 dec h
557 br $2b
558
559 ;; Ignore the first one bit - it is implicit in the IEEE format.
560 ;; The count of remaining bits is the exponent.
561
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
569
570
5713: shrw ax, 1
572 mov r10, a
573 mov a, x
574 mov r9, a
575
576 mov a, b
577 rorc a, 1
578
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
590
5915: ;; 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
598
5994: mov r8, a
600 mov a, h
601 shr a, 1
602 mov r11, a
603 sknc
604 set1 r10.7
605 ret
606
607END_ANOTHER_FUNC ___floatunsisf
608END_FUNC ___floatsisf