Merge remote branch 'origin/sparc-dev'
[akaros.git] / kern / arch / sparc / sparcfpu.c
1 /* Author: Andrew S. Waterman
2  *         Parallel Computing Laboratory
3  *         Electrical Engineering and Computer Sciences
4  *         University of California, Berkeley
5  *
6  * Copyright (c) 2008, The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in the
15  *       documentation and/or other materials provided with the distribution.
16  *     * Neither the name of the University of California, Berkeley nor the
17  *       names of its contributors may be used to endorse or promote products
18  *       derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS ''AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE REGENTS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32
33 #include <arch/sparcfpu.h>
34 #include <assert.h>
35 #include <string.h>
36
37 void sparcfpu_init(sparcfpu_t* fpu)
38 {
39   memset(fpu->freg,0,sizeof(fpu->freg));
40   memset(&fpu->FSR,0,sizeof(fpu->FSR));
41   static_assert(sizeof(fpu->FSR) == 4);
42   softfloat_init(&fpu->softfloat);
43 }
44
45 void sparcfpu_setFSR(sparcfpu_t* fpu, uint32_t newFSR)
46 {
47   fpu->FSR.rd = newFSR >> 30;
48   fpu->FSR.TEM = newFSR >> 23;
49   fpu->FSR.ftt = newFSR >> 14;
50   fpu->FSR.aexc = newFSR >> 5;
51   fpu->FSR.cexc = newFSR;
52 }
53
54 uint32_t sparcfpu_getFSR(sparcfpu_t* fpu)
55 {
56   return fpu->FSR.rd   << 30 |
57          fpu->FSR.TEM  << 23 |
58          fpu->FSR.ftt  << 14 |
59          fpu->FSR.aexc <<  5 |
60          fpu->FSR.cexc;
61 }
62
63 #define fpop1_trap_if(cond,code) do { if(cond) { fpu->FSR.ftt = (code); goto fpop1_done; } } while(0)
64 #define fpop2_trap_if(cond,code) do { if(cond) { fpu->FSR.ftt = (code); goto fpop2_done; } } while(0)
65
66 #define handle_exceptions(fpop,allowed) do { \
67   assert(!(fpu->softfloat.float_exception_flags & ~(allowed))); \
68   if(fpu->FSR.TEM & fpu->softfloat.float_exception_flags) \
69   { \
70     fpu->FSR.cexc = fpu->softfloat.float_exception_flags; \
71     fpop##_trap_if(1,fp_trap_IEEE_754_exception); \
72   } \
73   fpu->FSR.aexc |= fpu->softfloat.float_exception_flags; \
74   } while(0)
75
76 #define fpop1_handle_exceptions(allowed) handle_exceptions(fpop1,allowed)
77 #define fpop2_handle_exceptions(allowed) handle_exceptions(fpop2,allowed)
78
79 #define fpop1_check_double_align(reg) fpop1_trap_if((reg)&1,fp_trap_invalid_fp_register)
80 #define fpop2_check_double_align(reg) fpop2_trap_if((reg)&1,fp_trap_invalid_fp_register)
81 #define fpop1_check_quad_align(reg) fpop1_trap_if((reg)&3,fp_trap_invalid_fp_register)
82 #define fpop2_check_quad_align(reg) fpop2_trap_if((reg)&3,fp_trap_invalid_fp_register)
83
84 void sparcfpu_fpop1(sparcfpu_t* fpu, fp_insn_t insn)
85 {
86   fpu->FSR.ftt = 0;
87   fpu->softfloat.float_exception_flags = 0;
88   fpu->softfloat.float_rounding_mode = fpu->FSR.rd;
89
90   switch(insn.opf)
91   {
92     case opFiTOs: {
93       float32 f = int32_to_float32(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2));
94       fpop1_handle_exceptions(float_flag_inexact);
95       sparcfpu_wrregs(fpu,insn.rd,f);
96       break;
97     }
98     case opFiTOd: {
99       fpop1_check_double_align(insn.rd);
100       float64 f = int32_to_float64(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2));
101       fpop1_handle_exceptions(0);
102       sparcfpu_wrregd(fpu,insn.rd,f);
103       break;
104     }
105     case opFiTOq: {
106       fpop1_check_quad_align(insn.rd);
107       float128 f = int32_to_float128(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2));
108       fpop1_handle_exceptions(0);
109       sparcfpu_wrregq(fpu,insn.rd,f);
110       break;
111     }
112     case opFsTOi: {
113       fpu->softfloat.float_rounding_mode = float_round_to_zero;
114       int32_t i = float32_to_int32(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2));
115       fpop1_handle_exceptions(float_flag_inexact | float_flag_invalid);
116       sparcfpu_wrregs(fpu,insn.rd,i);
117       break;
118     }
119     case opFdTOi: {
120       fpu->softfloat.float_rounding_mode = float_round_to_zero;
121       fpop1_check_double_align(insn.rs2);
122       int32_t i = float64_to_int32(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs2));
123       fpop1_handle_exceptions(float_flag_inexact | float_flag_invalid);
124       sparcfpu_wrregs(fpu,insn.rd,i);
125       break;
126     }
127     case opFqTOi: {
128       fpu->softfloat.float_rounding_mode = float_round_to_zero;
129       fpop1_check_quad_align(insn.rs2);
130       int32_t i = float128_to_int32(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs2));
131       fpop1_handle_exceptions(float_flag_inexact | float_flag_invalid);
132       sparcfpu_wrregs(fpu,insn.rd,i);
133       break;
134     }
135     case opFsTOd: {
136       fpop1_check_double_align(insn.rd);
137       float64 f = float32_to_float64(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2));
138       fpop1_handle_exceptions(float_flag_invalid);
139       sparcfpu_wrregd(fpu,insn.rd,f);
140       break;
141     }
142     case opFsTOq: {
143       fpop1_check_quad_align(insn.rd);
144       float128 f = float32_to_float128(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2));
145       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
146       sparcfpu_wrregq(fpu,insn.rd,f);
147       break;
148     }
149     case opFdTOs: {
150       fpop1_check_double_align(insn.rs2);
151       float32 f = float64_to_float32(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs2));
152       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
153       sparcfpu_wrregs(fpu,insn.rd,f);
154       break;
155     }
156     case opFdTOq: {
157       fpop1_check_double_align(insn.rs2);
158       fpop1_check_quad_align(insn.rd);
159       float128 f = float64_to_float128(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs2));
160       fpop1_handle_exceptions(float_flag_invalid);
161       sparcfpu_wrregq(fpu,insn.rd,f);
162       break;
163     }
164     case opFqTOs: {
165       fpop1_check_quad_align(insn.rs2);
166       float32 f = float128_to_float32(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs2));
167       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
168       sparcfpu_wrregs(fpu,insn.rd,f);
169       break;
170     }
171     case opFqTOd: {
172       fpop1_check_quad_align(insn.rs2);
173       fpop1_check_double_align(insn.rd);
174       float64 f = float128_to_float64(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs2));
175       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
176       sparcfpu_wrregd(fpu,insn.rd,f);
177       break;
178     }
179     case opFMOVs:
180       sparcfpu_wrregs(fpu,insn.rd,sparcfpu_regs(fpu,insn.rs2));
181       break;
182     case opFNEGs:
183       sparcfpu_wrregs(fpu,insn.rd,sparcfpu_regs(fpu,insn.rs2) ^ 0x80000000);
184       break;
185     case opFABSs:
186       sparcfpu_wrregs(fpu,insn.rd,sparcfpu_regs(fpu,insn.rs2) &~0x80000000);
187       break;
188     case opFSQRTs: {
189       float32 f = float32_sqrt(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2));
190       fpop1_handle_exceptions(float_flag_inexact | float_flag_invalid);
191       sparcfpu_wrregs(fpu,insn.rd,f);
192       break;
193     }
194     case opFSQRTd: {
195       fpop1_check_double_align(insn.rs2);      
196       fpop1_check_double_align(insn.rd);      
197       float64 f = float64_sqrt(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs2));
198       fpop1_handle_exceptions(float_flag_inexact | float_flag_invalid);
199       sparcfpu_wrregd(fpu,insn.rd,f);
200       break;
201     }
202     case opFSQRTq: {
203       fpop1_check_quad_align(insn.rs2);      
204       fpop1_check_quad_align(insn.rd);      
205       float128 f = float128_sqrt(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs2));
206       fpop1_handle_exceptions(float_flag_inexact | float_flag_invalid);
207       sparcfpu_wrregq(fpu,insn.rd,f);
208       break;
209     }
210     case opFADDs: {
211       float32 f = float32_add(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1),sparcfpu_regs(fpu,insn.rs2));
212       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
213       sparcfpu_wrregs(fpu,insn.rd,f);
214       break;
215     }
216     case opFADDd: {
217       fpop1_check_double_align(insn.rs1);
218       fpop1_check_double_align(insn.rs2);
219       fpop1_check_double_align(insn.rd);      
220       float64 f = float64_add(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1),sparcfpu_regd(fpu,insn.rs2));
221       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
222       sparcfpu_wrregd(fpu,insn.rd,f);
223       break;
224     }
225     case opFADDq: {
226       fpop1_check_quad_align(insn.rs1);
227       fpop1_check_quad_align(insn.rs2);
228       fpop1_check_quad_align(insn.rd);      
229       float128 f = float128_add(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs1),sparcfpu_regq(fpu,insn.rs2));
230       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
231       sparcfpu_wrregq(fpu,insn.rd,f);
232       break;
233     }
234     case opFSUBs: {
235       float32 f = float32_sub(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1),sparcfpu_regs(fpu,insn.rs2));
236       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
237       sparcfpu_wrregs(fpu,insn.rd,f);
238       break;
239     }
240     case opFSUBd: {
241       fpop1_check_double_align(insn.rs1);
242       fpop1_check_double_align(insn.rs2);
243       fpop1_check_double_align(insn.rd);      
244       float64 f = float64_sub(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1),sparcfpu_regd(fpu,insn.rs2));
245       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
246       sparcfpu_wrregd(fpu,insn.rd,f);
247       break;
248     }
249     case opFSUBq: {
250       fpop1_check_quad_align(insn.rs1);
251       fpop1_check_quad_align(insn.rs2);
252       fpop1_check_quad_align(insn.rd);      
253       float128 f = float128_sub(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs1),sparcfpu_regq(fpu,insn.rs2));
254       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
255       sparcfpu_wrregq(fpu,insn.rd,f);
256       break;
257     }
258     case opFMULs: {
259       float32 f = float32_mul(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1),sparcfpu_regs(fpu,insn.rs2));
260       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
261       sparcfpu_wrregs(fpu,insn.rd,f);
262       break;
263     }
264     case opFMULd: {
265       fpop1_check_double_align(insn.rs1);
266       fpop1_check_double_align(insn.rs2);
267       fpop1_check_double_align(insn.rd);      
268       float64 f = float64_mul(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1),sparcfpu_regd(fpu,insn.rs2));
269       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
270       sparcfpu_wrregd(fpu,insn.rd,f);
271       break;
272     }
273     case opFMULq: {
274       fpop1_check_quad_align(insn.rs1);
275       fpop1_check_quad_align(insn.rs2);
276       fpop1_check_quad_align(insn.rd);      
277       float128 f = float128_mul(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs1),sparcfpu_regq(fpu,insn.rs2));
278       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
279       sparcfpu_wrregq(fpu,insn.rd,f);
280       break;
281     }
282     case opFsMULd: {
283       fpop1_check_double_align(insn.rd);      
284       float64 f = float64_mul(&fpu->softfloat,float32_to_float64(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1)),float32_to_float64(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2)));
285       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
286       sparcfpu_wrregd(fpu,insn.rd,f);
287       break;
288     }
289     case opFdMULq: {
290       fpop1_check_double_align(insn.rs1);
291       fpop1_check_double_align(insn.rs2);
292       fpop1_check_quad_align(insn.rd);      
293       float128 f = float128_mul(&fpu->softfloat,float64_to_float128(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1)),float64_to_float128(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs2)));
294       fpop1_handle_exceptions(float_flag_inexact | float_flag_overflow | float_flag_underflow | float_flag_invalid);
295       sparcfpu_wrregq(fpu,insn.rd,f);
296       break;
297     }
298     case opFDIVs: {
299       float32 f = float32_div(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1),sparcfpu_regs(fpu,insn.rs2));
300       fpop1_handle_exceptions(float_flag_inexact | float_flag_divbyzero | float_flag_overflow | float_flag_underflow | float_flag_invalid);
301       sparcfpu_wrregs(fpu,insn.rd,f);
302       break;
303     }
304     case opFDIVd: {
305       fpop1_check_double_align(insn.rs1);
306       fpop1_check_double_align(insn.rs2);
307       fpop1_check_double_align(insn.rd);      
308       float64 f = float64_div(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1),sparcfpu_regd(fpu,insn.rs2));
309       fpop1_handle_exceptions(float_flag_inexact | float_flag_divbyzero | float_flag_overflow | float_flag_underflow | float_flag_invalid);
310       sparcfpu_wrregd(fpu,insn.rd,f);
311       break;
312     }
313     case opFDIVq: {
314       fpop1_check_quad_align(insn.rs1);
315       fpop1_check_quad_align(insn.rs2);
316       fpop1_check_quad_align(insn.rd);      
317       float128 f = float128_div(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs1),sparcfpu_regq(fpu,insn.rs2));
318       fpop1_handle_exceptions(float_flag_inexact | float_flag_divbyzero | float_flag_overflow | float_flag_underflow | float_flag_invalid);
319       sparcfpu_wrregq(fpu,insn.rd,f);
320       break;
321     }
322   }
323
324   fpop1_done:
325   ;
326 }
327
328 void sparcfpu_fpop2(sparcfpu_t* fpu, fp_insn_t insn)
329 {
330   fpu->FSR.ftt = 0;
331   fpu->softfloat.float_exception_flags = 0;
332   fpu->softfloat.float_rounding_mode = fpu->FSR.rd;
333
334   switch(insn.opf)
335   {
336     case opFCMPs: {
337       int eq = float32_eq(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1),sparcfpu_regs(fpu,insn.rs2));
338       fpop2_handle_exceptions(float_flag_invalid);
339       int lt = float32_lt(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1),sparcfpu_regs(fpu,insn.rs2));
340       int gt = float32_lt(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2),sparcfpu_regs(fpu,insn.rs1));
341       assert(eq+lt+gt <= 1);
342       fpu->FSR.fcc = eq ? 0 : (lt ? 1 : (gt ? 2 : 3));
343       break;
344     }
345     case opFCMPEs: {
346       int eq = float32_eq_signaling(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1),sparcfpu_regs(fpu,insn.rs2));
347       fpop2_handle_exceptions(float_flag_invalid);
348       int lt = float32_lt(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs1),sparcfpu_regs(fpu,insn.rs2));
349       int gt = float32_lt(&fpu->softfloat,sparcfpu_regs(fpu,insn.rs2),sparcfpu_regs(fpu,insn.rs1));
350       assert(eq+lt+gt <= 1);
351       fpu->FSR.fcc = eq ? 0 : (lt ? 1 : (gt ? 2 : 3));
352       break;
353     }
354     case opFCMPd: {
355       fpop2_check_double_align(insn.rs1);
356       fpop2_check_double_align(insn.rs2);
357       int eq = float64_eq(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1),sparcfpu_regd(fpu,insn.rs2));
358       fpop2_handle_exceptions(float_flag_invalid);
359       int lt = float64_lt(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1),sparcfpu_regd(fpu,insn.rs2));
360       int gt = float64_lt(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs2),sparcfpu_regd(fpu,insn.rs1));
361       assert(eq+lt+gt <= 1);
362       fpu->FSR.fcc = eq ? 0 : (lt ? 1 : (gt ? 2 : 3));
363       break;
364     }
365     case opFCMPEd: {
366       fpop2_check_double_align(insn.rs1);
367       fpop2_check_double_align(insn.rs2);
368       int eq = float64_eq_signaling(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1),sparcfpu_regd(fpu,insn.rs2));
369       fpop2_handle_exceptions(float_flag_invalid);
370       int lt = float64_lt(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs1),sparcfpu_regd(fpu,insn.rs2));
371       int gt = float64_lt(&fpu->softfloat,sparcfpu_regd(fpu,insn.rs2),sparcfpu_regd(fpu,insn.rs1));
372       assert(eq+lt+gt <= 1);
373       fpu->FSR.fcc = eq ? 0 : (lt ? 1 : (gt ? 2 : 3));
374       break;
375     }
376     case opFCMPq: {
377       fpop2_check_quad_align(insn.rs1);
378       fpop2_check_quad_align(insn.rs2);
379       int eq = float128_eq(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs1),sparcfpu_regq(fpu,insn.rs2));
380       fpop2_handle_exceptions(float_flag_invalid);
381       int lt = float128_lt(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs1),sparcfpu_regq(fpu,insn.rs2));
382       int gt = float128_lt(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs2),sparcfpu_regq(fpu,insn.rs1));
383       assert(eq+lt+gt <= 1);
384       fpu->FSR.fcc = eq ? 0 : (lt ? 1 : (gt ? 2 : 3));
385       break;
386     }
387     case opFCMPEq: {
388       fpop2_check_quad_align(insn.rs1);
389       fpop2_check_quad_align(insn.rs2);
390       int eq = float128_eq_signaling(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs1),sparcfpu_regq(fpu,insn.rs2));
391       fpop2_handle_exceptions(float_flag_invalid);
392       int lt = float128_lt(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs1),sparcfpu_regq(fpu,insn.rs2));
393       int gt = float128_lt(&fpu->softfloat,sparcfpu_regq(fpu,insn.rs2),sparcfpu_regq(fpu,insn.rs1));
394       assert(eq+lt+gt <= 1);
395       fpu->FSR.fcc = eq ? 0 : (lt ? 1 : (gt ? 2 : 3));
396       break;
397     }
398   }
399
400   fpop2_done:
401   ;
402 }
403
404 void sparcfpu_wrregs(sparcfpu_t* fpu, uint32_t reg, float32 val)
405 {
406   assert(reg < 32);
407   fpu->freg[reg] = val;
408 }
409
410 void sparcfpu_wrregd(sparcfpu_t* fpu, uint32_t reg, float64 val)
411 {
412   assert(reg < 32 && !(reg&1));
413   sparcfpu_wrregs(fpu,reg,(uint32_t)(val>>32));
414   sparcfpu_wrregs(fpu,reg+1,(uint32_t)val);
415 }
416
417 void sparcfpu_wrregq(sparcfpu_t* fpu, uint32_t reg, float128 val)
418 {
419   assert(reg < 32 && !(reg&3));
420   sparcfpu_wrregd(fpu,reg,val.high);
421   sparcfpu_wrregd(fpu,reg+2,val.low);
422 }
423
424 float32 sparcfpu_regs(sparcfpu_t* fpu, uint32_t reg)
425 {
426   assert(reg < 32);
427   return fpu->freg[reg];
428 }
429
430 float64 sparcfpu_regd(sparcfpu_t* fpu, uint32_t reg)
431 {
432   assert(reg < 32 && !(reg&1));
433   return (((float64)sparcfpu_regs(fpu,reg))<<32) | (float64)sparcfpu_regs(fpu,reg+1);
434 }
435
436 float128 sparcfpu_regq(sparcfpu_t* fpu, uint32_t reg)
437 {
438   assert(reg < 32 && !(reg&3));
439   float128 f;
440   f.high = sparcfpu_regd(fpu,reg);
441   f.low = sparcfpu_regd(fpu,reg+2);
442   return f;
443 }