1/*-
2 * Copyright (c) 2010 by Peter Jeremy <peterjeremy@acm.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD$");
28
29#include <sys/param.h>
30
31#include <math.h>
32#include <stdio.h>
33#include <stdlib.h>
34
35#include "__sparc_utrap_private.h"
36#include "fpu_extern.h"
37#include "fpu_reg.h"
38
39static u_long	ireg[32];
40
41void
42__utrap_panic(const char *msg)
43{
44
45	fprintf(stderr, "panic: %s\n", msg);
46	exit(1);
47}
48
49void __utrap_write(const char *msg)
50{
51
52	fprintf(stderr, "%s", msg);
53}
54
55u_long
56__emul_fetch_reg(struct utrapframe *uf, int reg)
57{
58
59	return (ireg[reg]);
60}
61
62typedef unsigned char int8;
63typedef unsigned int int32;
64typedef unsigned long int64;
65typedef unsigned int float32;
66typedef unsigned long float64;
67typedef struct {
68	unsigned long high, low;
69} float128;
70typedef unsigned long flag;
71
72struct utrapframe utf;
73
74u_int32_t __fpreg[64];
75
76static __inline float128
77__fpu_getreg128(int r)
78{
79	float128 v;
80
81	v.high = ((u_int64_t)__fpreg[r] << 32 | (u_int64_t)__fpreg[r + 1]);
82	v.low = ((u_int64_t)__fpreg[r + 2] << 32 | (u_int64_t)__fpreg[r + 3]);
83	return (v);
84}
85
86static __inline void
87__fpu_setreg128(int r, float128 v)
88{
89
90	__fpreg[r] = (u_int32_t)(v.high >> 32);
91	__fpreg[r + 1] = (u_int32_t)v.high;
92	__fpreg[r + 2] = (u_int32_t)(v.low >> 32);
93	__fpreg[r + 3] = (u_int32_t)v.low;
94}
95
96/*
97-------------------------------------------------------------------------------
98Clears the system's IEC/IEEE floating-point exception flags.  Returns the
99previous value of the flags.
100-------------------------------------------------------------------------------
101*/
102#include <fenv.h>
103#include <ieeefp.h>
104
105int8 syst_float_flags_clear(void)
106{
107	int32 flags;
108
109	flags = (utf.uf_fsr & FE_ALL_EXCEPT) >> 5;
110	utf.uf_fsr &= ~(u_long)FE_ALL_EXCEPT;
111	return (flags);
112}
113
114static void
115emul_trap(const u_int *insn, u_long mask)
116{
117	u_int32_t savreg[64];
118	int i;
119
120	for (i = 0; i < 64; i++)
121	    savreg[i] = __fpreg[i];
122
123	utf.uf_fsr = (utf.uf_fsr & ~FSR_FTT_MASK) |
124		(FSR_FTT_UNFIN << FSR_FTT_SHIFT);
125	utf.uf_pc = (u_long)insn;
126	if (__fpu_exception(&utf) == 0)
127	    __asm("stx %%fsr,%0" : "=m" (utf.uf_fsr));
128
129	for (i = 0; i < 64; i++) {
130		if (!(mask & (1UL << i)) && savreg[i] != __fpreg[i]) {
131			fprintf(stderr, "### %2d %08x != %08x\n",
132			    i, savreg[i], __fpreg[i]);
133		}
134	}
135}
136
137extern u_int insn_int32_to_float32;
138extern u_int insn_int32_to_float64;
139extern u_int insn_int32_to_float128;
140extern u_int insn_int64_to_float32;
141extern u_int insn_int64_to_float64;
142extern u_int insn_int64_to_float128;
143extern u_int insn_float32_to_int32_round_to_zero;
144extern u_int insn_float32_to_int64_round_to_zero;
145extern u_int insn_float32_to_float64;
146extern u_int insn_float32_to_float128;
147extern u_int insn_float32_add;
148extern u_int insn_float32_sub;
149extern u_int insn_float32_mul;
150extern u_int insn_float32_div;
151extern u_int insn_float32_sqrt;
152extern u_int insn_float32_cmp;
153extern u_int insn_float32_cmpe;
154extern u_int insn_float64_to_int32_round_to_zero;
155extern u_int insn_float64_to_int64_round_to_zero;
156extern u_int insn_float64_to_float32;
157extern u_int insn_float64_to_float128;
158extern u_int insn_float64_add;
159extern u_int insn_float64_sub;
160extern u_int insn_float64_mul;
161extern u_int insn_float64_div;
162extern u_int insn_float64_sqrt;
163extern u_int insn_float64_cmp;
164extern u_int insn_float64_cmpe;
165extern u_int insn_float128_to_int32_round_to_zero;
166extern u_int insn_float128_to_int64_round_to_zero;
167extern u_int insn_float128_to_float32;
168extern u_int insn_float128_to_float64;
169extern u_int insn_float128_add;
170extern u_int insn_float128_sub;
171extern u_int insn_float128_mul;
172extern u_int insn_float128_div;
173extern u_int insn_float128_sqrt;
174extern u_int insn_float128_cmp;
175extern u_int insn_float128_cmpe;
176
177float32
178syst_int32_to_float32(int32 a)
179{
180
181	__fpu_setreg(0, a);
182	emul_trap(&insn_int32_to_float32, 0x1UL);
183	return (__fpu_getreg(0));
184}
185
186float64
187syst_int32_to_float64(int32 a)
188{
189
190	__fpu_setreg(0, a);
191	emul_trap(&insn_int32_to_float64, 0x3UL);
192	return (__fpu_getreg64(0));
193}
194
195float128
196syst_int32_to_float128(int32 a)
197{
198
199	__fpu_setreg(0, a);
200	emul_trap(&insn_int32_to_float128, 0xfUL);
201	return (__fpu_getreg128(0));
202}
203
204float32
205syst_int64_to_float32(int64 a)
206{
207
208	__fpu_setreg64(0, a);
209	emul_trap(&insn_int64_to_float32, 0x1UL);
210	return (__fpu_getreg(0));
211}
212
213float64
214syst_int64_to_float64(int64 a)
215{
216
217	__fpu_setreg64(0, a);
218	emul_trap(&insn_int64_to_float64, 0x3UL);
219	return (__fpu_getreg64(0));
220}
221
222
223float128
224syst_int64_to_float128(int64 a)
225{
226
227	__fpu_setreg64(0, a);
228	emul_trap(&insn_int64_to_float128, 0xfUL);
229	return (__fpu_getreg128(0));
230}
231
232int32
233syst_float32_to_int32_round_to_zero(float32 a)
234{
235
236	__fpu_setreg(0, a);
237	emul_trap(&insn_float32_to_int32_round_to_zero, 0x1UL);
238	return (__fpu_getreg(0));
239}
240
241int64
242syst_float32_to_int64_round_to_zero(float32 a)
243{
244
245	__fpu_setreg(0, a);
246	emul_trap(&insn_float32_to_int64_round_to_zero, 0x3UL);
247	return (__fpu_getreg64(0));
248}
249
250float64
251syst_float32_to_float64(float32 a)
252{
253
254	__fpu_setreg(0, a);
255	emul_trap(&insn_float32_to_float64, 0x3UL);
256	return (__fpu_getreg64(0));
257}
258
259float128
260syst_float32_to_float128(float32 a)
261{
262
263	__fpu_setreg(0, a);
264	emul_trap(&insn_float32_to_float128, 0xfUL);
265	return (__fpu_getreg128(0));
266}
267
268float32
269syst_float32_add(float32 a, float32 b)
270{
271
272	__fpu_setreg(0, a);
273	__fpu_setreg(1, b);
274	emul_trap(&insn_float32_add, 0x1UL);
275	return (__fpu_getreg(0));
276}
277
278float32
279syst_float32_sub(float32 a, float32 b)
280{
281
282	__fpu_setreg(0, a);
283	__fpu_setreg(1, b);
284	emul_trap(&insn_float32_sub, 0x1UL);
285	return (__fpu_getreg(0));
286}
287
288float32
289syst_float32_mul(float32 a, float32 b)
290{
291
292	__fpu_setreg(0, a);
293	__fpu_setreg(1, b);
294	emul_trap(&insn_float32_mul, 0x1UL);
295	return (__fpu_getreg(0));
296}
297
298float32
299syst_float32_div(float32 a, float32 b)
300{
301
302	__fpu_setreg(0, a);
303	__fpu_setreg(1, b);
304	emul_trap(&insn_float32_div, 0x1UL);
305	return (__fpu_getreg(0));
306}
307
308float32
309syst_float32_sqrt(float32 a)
310{
311
312	__fpu_setreg(0, a);
313	emul_trap(&insn_float32_sqrt, 0x1UL);
314	return (__fpu_getreg(0));
315}
316
317flag syst_float32_eq(float32 a, float32 b)
318{
319	u_long r;
320
321	__fpu_setreg(0, a);
322	__fpu_setreg(1, b);
323	emul_trap(&insn_float32_cmp, 0x0UL);
324	__asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r));
325	return (r);
326}
327
328flag syst_float32_le(float32 a, float32 b)
329{
330	u_long r;
331
332	__fpu_setreg(0, a);
333	__fpu_setreg(1, b);
334	emul_trap(&insn_float32_cmpe, 0x0UL);
335	__asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r));
336	return (r);
337}
338
339flag syst_float32_lt(float32 a, float32 b)
340{
341	u_long r;
342
343	__fpu_setreg(0, a);
344	__fpu_setreg(1, b);
345	emul_trap(&insn_float32_cmpe, 0x0UL);
346	__asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r));
347	return (r);
348}
349
350flag syst_float32_eq_signaling(float32 a, float32 b)
351{
352	u_long r;
353
354	__fpu_setreg(0, a);
355	__fpu_setreg(1, b);
356	emul_trap(&insn_float32_cmpe, 0x0UL);
357	__asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r));
358	return (r);
359}
360
361flag syst_float32_le_quiet(float32 a, float32 b)
362{
363	u_long r;
364
365	__fpu_setreg(0, a);
366	__fpu_setreg(1, b);
367	emul_trap(&insn_float32_cmp, 0x0UL);
368	__asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r));
369	return (r);
370}
371
372flag syst_float32_lt_quiet(float32 a, float32 b)
373{
374	u_long r;
375
376	__fpu_setreg(0, a);
377	__fpu_setreg(1, b);
378	emul_trap(&insn_float32_cmp, 0x0UL);
379	__asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r));
380	return (r);
381}
382
383int32
384syst_float64_to_int32_round_to_zero(float64 a)
385{
386
387	__fpu_setreg64(0, a);
388	emul_trap(&insn_float64_to_int32_round_to_zero, 0x1UL);
389	return (__fpu_getreg(0));
390}
391
392int64
393syst_float64_to_int64_round_to_zero(float64 a)
394{
395
396	__fpu_setreg64(0, a);
397	emul_trap(&insn_float64_to_int64_round_to_zero, 0x3UL);
398	return (__fpu_getreg64(0));
399}
400
401float32
402syst_float64_to_float32(float64 a)
403{
404
405	__fpu_setreg64(0, a);
406	emul_trap(&insn_float64_to_float32, 0x1UL);
407	return (__fpu_getreg(0));
408}
409
410float128
411syst_float64_to_float128(float64 a)
412{
413
414	__fpu_setreg64(0, a);
415	emul_trap(&insn_float64_to_float128, 0xfUL);
416	return (__fpu_getreg128(0));
417}
418
419float64
420syst_float64_add(float64 a, float64 b)
421{
422
423	__fpu_setreg64(0, a);
424	__fpu_setreg64(2, b);
425	emul_trap(&insn_float64_add, 0x3UL);
426	return (__fpu_getreg64(0));
427}
428
429float64
430syst_float64_sub(float64 a, float64 b)
431{
432
433	__fpu_setreg64(0, a);
434	__fpu_setreg64(2, b);
435	emul_trap(&insn_float64_sub, 0x3UL);
436	return (__fpu_getreg64(0));
437}
438
439float64
440syst_float64_mul(float64 a, float64 b)
441{
442
443	__fpu_setreg64(0, a);
444	__fpu_setreg64(2, b);
445	emul_trap(&insn_float64_mul, 0x3UL);
446	return (__fpu_getreg64(0));
447}
448
449float64
450syst_float64_div(float64 a, float64 b)
451{
452
453	__fpu_setreg64(0, a);
454	__fpu_setreg64(2, b);
455	emul_trap(&insn_float64_div, 0x3UL);
456	return (__fpu_getreg64(0));
457}
458
459float64
460syst_float64_sqrt(float64 a)
461{
462
463	__fpu_setreg64(0, a);
464	emul_trap(&insn_float64_sqrt, 0x3UL);
465	return (__fpu_getreg64(0));
466}
467
468flag syst_float64_eq(float64 a, float64 b)
469{
470	u_long r;
471
472	__fpu_setreg64(0, a);
473	__fpu_setreg64(2, b);
474	emul_trap(&insn_float64_cmp, 0x0UL);
475	__asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r));
476	return (r);
477}
478
479flag syst_float64_le(float64 a, float64 b)
480{
481	u_long r;
482
483	__fpu_setreg64(0, a);
484	__fpu_setreg64(2, b);
485	emul_trap(&insn_float64_cmpe, 0x0UL);
486	__asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r));
487	return (r);
488}
489
490flag syst_float64_lt(float64 a, float64 b)
491{
492	u_long r;
493
494	__fpu_setreg64(0, a);
495	__fpu_setreg64(2, b);
496	emul_trap(&insn_float64_cmpe, 0x0UL);
497	__asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r));
498	return (r);
499}
500
501flag syst_float64_eq_signaling(float64 a, float64 b)
502{
503	u_long r;
504
505	__fpu_setreg64(0, a);
506	__fpu_setreg64(2, b);
507	emul_trap(&insn_float64_cmpe, 0x0UL);
508	__asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r));
509	return (r);
510}
511
512flag syst_float64_le_quiet(float64 a, float64 b)
513{
514	u_long r;
515
516	__fpu_setreg64(0, a);
517	__fpu_setreg64(2, b);
518	emul_trap(&insn_float64_cmp, 0x0UL);
519	__asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r));
520	return (r);
521}
522
523flag syst_float64_lt_quiet(float64 a, float64 b)
524{
525	u_long r;
526
527	__fpu_setreg64(0, a);
528	__fpu_setreg64(2, b);
529	emul_trap(&insn_float64_cmp, 0x0UL);
530	__asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r));
531	return (r);
532}
533
534int32
535syst_float128_to_int32_round_to_zero(float128 a)
536{
537
538	__fpu_setreg128(0, a);
539	emul_trap(&insn_float128_to_int32_round_to_zero, 0x1UL);
540	return (__fpu_getreg(0));
541}
542
543int64
544syst_float128_to_int64_round_to_zero(float128 a)
545{
546
547	__fpu_setreg128(0, a);
548	emul_trap(&insn_float128_to_int64_round_to_zero, 0x3UL);
549	return (__fpu_getreg64(0));
550}
551
552float32
553syst_float128_to_float32(float128 a)
554{
555
556	__fpu_setreg128(0, a);
557	emul_trap(&insn_float128_to_float32, 0x1UL);
558	return (__fpu_getreg(0));
559}
560
561float64
562syst_float128_to_float64(float128 a)
563{
564
565	__fpu_setreg128(0, a);
566	emul_trap(&insn_float128_to_float64, 0x3UL);
567	return (__fpu_getreg64(0));
568}
569
570float128
571syst_float128_add(float128 a, float128 b)
572{
573
574	__fpu_setreg128(0, a);
575	__fpu_setreg128(4, b);
576	emul_trap(&insn_float128_add, 0xfUL);
577	return (__fpu_getreg128(0));
578}
579
580float128
581syst_float128_sub(float128 a, float128 b)
582{
583
584	__fpu_setreg128(0, a);
585	__fpu_setreg128(4, b);
586	emul_trap(&insn_float128_sub, 0xfUL);
587	return (__fpu_getreg128(0));
588}
589
590float128
591syst_float128_mul(float128 a, float128 b)
592{
593
594	__fpu_setreg128(0, a);
595	__fpu_setreg128(4, b);
596	emul_trap(&insn_float128_mul, 0xfUL);
597	return (__fpu_getreg128(0));
598}
599
600float128
601syst_float128_div(float128 a, float128 b)
602{
603
604	__fpu_setreg128(0, a);
605	__fpu_setreg128(4, b);
606	emul_trap(&insn_float128_div, 0xfUL);
607	return (__fpu_getreg128(0));
608}
609
610float128
611syst_float128_sqrt(float128 a)
612{
613
614	__fpu_setreg128(0, a);
615	emul_trap(&insn_float128_sqrt, 0xfUL);
616	return (__fpu_getreg128(0));
617}
618
619flag syst_float128_eq(float128 a, float128 b)
620{
621	u_long r;
622
623	__fpu_setreg128(0, a);
624	__fpu_setreg128(4, b);
625	emul_trap(&insn_float128_cmp, 0x0UL);
626	__asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r));
627	return (r);
628}
629
630flag syst_float128_le(float128 a, float128 b)
631{
632	u_long r;
633
634	__fpu_setreg128(0, a);
635	__fpu_setreg128(4, b);
636	emul_trap(&insn_float128_cmpe, 0x0UL);
637	__asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r));
638	return (r);
639}
640
641flag syst_float128_lt(float128 a, float128 b)
642{
643	u_long r;
644
645	__fpu_setreg128(0, a);
646	__fpu_setreg128(4, b);
647	emul_trap(&insn_float128_cmpe, 0x0UL);
648	__asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r));
649	return (r);
650}
651
652flag syst_float128_eq_signaling(float128 a, float128 b)
653{
654	u_long r;
655
656	__fpu_setreg128(0, a);
657	__fpu_setreg128(4, b);
658	emul_trap(&insn_float128_cmpe, 0x0UL);
659	__asm __volatile("mov 0,%0; move %%fcc0,1,%0" : "=r" (r));
660	return (r);
661}
662
663flag syst_float128_le_quiet(float128 a, float128 b)
664{
665	u_long r;
666
667	__fpu_setreg128(0, a);
668	__fpu_setreg128(4, b);
669	emul_trap(&insn_float128_cmp, 0x0UL);
670	__asm __volatile("mov 0,%0; movle %%fcc0,1,%0" : "=r" (r));
671	return (r);
672}
673
674flag syst_float128_lt_quiet(float128 a, float128 b)
675{
676	u_long r;
677
678	__fpu_setreg128(0, a);
679	__fpu_setreg128(4, b);
680	emul_trap(&insn_float128_cmp, 0x0UL);
681	__asm __volatile("mov 0,%0; movl %%fcc0,1,%0" : "=r" (r));
682	return (r);
683}
684
685
686/*
687-------------------------------------------------------------------------------
688Sets the system's IEC/IEEE floating-point rounding mode.
689-------------------------------------------------------------------------------
690*/
691void syst_float_set_rounding_mode(int8 roundingMode)
692{
693
694	utf.uf_fsr &= ~FSR_RD_MASK;
695	utf.uf_fsr |= FSR_RD((unsigned int)roundingMode & 0x03);
696}
697
698/*
699-------------------------------------------------------------------------------
700Does nothing.
701-------------------------------------------------------------------------------
702*/
703void syst_float_set_rounding_precision(int8 precision)
704{
705
706}
707