xref: /netbsd-src/external/gpl3/gcc.old/dist/libgcc/config/rl78/fpbit-sf.S (revision 36ac495d2b3ea2b9d96377b2143ebfedac224b92)
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
609