xref: /plan9/sys/src/cmd/qi/float.c (revision 6891d8578618fb7ccda4a131c122d4d0e6580c4b)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 #define Extern extern
6 #include "power.h"
7 
8 ulong	setfpscr(void);
9 void	setfpcc(double);
10 void	farith(ulong);
11 void	farith2(ulong);
12 void	fariths(ulong);
13 void	fcmp(ulong);
14 void	mtfsb1(ulong);
15 void	mcrfs(ulong);
16 void	mtfsb0(ulong);
17 void	mtfsf(ulong);
18 void	mtfsfi(ulong);
19 void	mffs(ulong);
20 void	mtfsf(ulong);
21 
22 Inst	op59[] = {
23 [18] {fariths, "fdivs", Ifloat},
24 [20] {fariths, "fsubs", Ifloat},
25 [21] {fariths, "fadds", Ifloat},
26 [22] {unimp, "fsqrts", Ifloat},
27 [24] {unimp, "fres", Ifloat},
28 [25] {fariths, "fmuls", Ifloat},
29 [28] {fariths, "fmsubs", Ifloat},
30 [29] {fariths, "fmadds", Ifloat},
31 [30] {fariths, "fnmsubs", Ifloat},
32 [31] {fariths, "fnmadds", Ifloat},
33 };
34 
35 Inset	ops59 = {op59, nelem(op59)};
36 
37 Inst	op63a[] = {
38 [12] {farith, "frsp", Ifloat},
39 [14] {farith, "fctiw", Ifloat},
40 [15] {farith, "fctiwz", Ifloat},
41 [18] {farith, "fdiv", Ifloat},
42 [20] {farith, "fsub", Ifloat},
43 [21] {farith, "fadd", Ifloat},
44 [22] {unimp, "frsqrt", Ifloat},
45 [23] {unimp, "fsel", Ifloat},
46 [25] {farith, "fmul", Ifloat},
47 [26] {unimp, "frsqrte", Ifloat},
48 [28] {farith, "fmsub", Ifloat},
49 [29] {farith, "fmadd", Ifloat},
50 [30] {farith, "fnmsub", Ifloat},
51 [31] {farith, "fnmadd", Ifloat},
52 };
53 
54 Inset	ops63a= {op63a, nelem(op63a)};
55 
56 Inst	op63b[] = {
57 [0] {fcmp, "fcmpu", Ifloat},
58 [32] {fcmp, "fcmpo", Ifloat},
59 [38] {mtfsb1, "mtfsb1", Ifloat},
60 [40] {farith2, "fneg", Ifloat},
61 [64] {mcrfs, "mcrfs", Ifloat},
62 [70] {mtfsb0, "mtfsb0", Ifloat},
63 [72] {farith2, "fmr", Ifloat},
64 [134] {mtfsfi, "mtfsfi", Ifloat},
65 [136] {farith2, "fnabs", Ifloat},
66 [264] {farith2, "fabs", Ifloat},
67 [583] {mffs, "mffs", Ifloat},
68 [711] {mtfsf, "mtfsf", Ifloat},
69 };
70 
71 Inset	ops63b = {op63b, nelem(op63b)};
72 
73 void
fpreginit(void)74 fpreginit(void)
75 {
76 	int i;
77 
78 	/* Normally initialised by the kernel */
79 	reg.fd[27] = 4503601774854144.0;
80 	reg.fd[29] = 0.5;
81 	reg.fd[28] = 0.0;
82 	reg.fd[30] = 1.0;
83 	reg.fd[31] = 2.0;
84 	for(i = 0; i < 27; i++)
85 		reg.fd[i] = reg.fd[28];
86 }
87 
88 static double
v2fp(uvlong v)89 v2fp(uvlong v)
90 {
91 	FPdbleword f;
92 
93 	f.hi = v>>32;
94 	f.lo = v;
95 	return f.x;
96 }
97 
98 static uvlong
fp2v(double d)99 fp2v(double d)
100 {
101 	FPdbleword f;
102 
103 	f.x = d;
104 	return ((uvlong)f.hi<<32) | f.lo;
105 }
106 
107 void
lfs(ulong ir)108 lfs(ulong ir)
109 {
110 	ulong ea;
111 	int imm, ra, rd, upd;
112 	union {
113 		ulong	i;
114 		float	f;
115 	} u;
116 
117 	getairr(ir);
118 	ea = imm;
119 	upd = (ir&(1L<<26))!=0;
120 	if(ra) {
121 		ea += reg.r[ra];
122 		if(upd)
123 			reg.r[ra] = ea;
124 	} else {
125 		if(upd)
126 			undef(ir);
127 	}
128 	if(trace)
129 		itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
130 
131 	u.i = getmem_w(ea);
132 	reg.fd[rd] = u.f;
133 }
134 
135 void
lfsx(ulong ir)136 lfsx(ulong ir)
137 {
138 	ulong ea;
139 	int rd, ra, rb, upd;
140 	union {
141 		ulong	i;
142 		float	f;
143 	} u;
144 
145 	getarrr(ir);
146 	ea = reg.r[rb];
147 	upd = ((ir>>1)&0x3FF)==567;
148 	if(ra){
149 		ea += reg.r[ra];
150 		if(upd)
151 			reg.r[ra] = ea;
152 		if(trace)
153 			itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
154 	} else {
155 		if(upd)
156 			undef(ir);
157 		if(trace)
158 			itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
159 	}
160 
161 	u.i = getmem_w(ea);
162 	reg.fd[rd] = u.f;
163 }
164 
165 void
lfd(ulong ir)166 lfd(ulong ir)
167 {
168 	ulong ea;
169 	int imm, ra, rd, upd;
170 
171 	getairr(ir);
172 	ea = imm;
173 	upd = (ir&(1L<<26))!=0;
174 	if(ra) {
175 		ea += reg.r[ra];
176 		if(upd)
177 			reg.r[ra] = ea;
178 	} else {
179 		if(upd)
180 			undef(ir);
181 	}
182 	if(trace)
183 		itrace("%s\tf%d,%ld(r%d) ea=%lux", ci->name, rd, imm, ra, ea);
184 
185 	reg.fd[rd] = v2fp(getmem_v(ea));
186 }
187 
188 void
lfdx(ulong ir)189 lfdx(ulong ir)
190 {
191 	ulong ea;
192 	int rd, ra, rb, upd;
193 
194 	getarrr(ir);
195 	ea = reg.r[rb];
196 	upd = ((ir>>1)&0x3FF)==631;
197 	if(ra){
198 		ea += reg.r[ra];
199 		if(upd)
200 			reg.r[ra] = ea;
201 		if(trace)
202 			itrace("%s\tf%d,(r%d+r%d) ea=%lux", ci->name, rd, ra, rb, ea);
203 	} else {
204 		if(upd)
205 			undef(ir);
206 		if(trace)
207 			itrace("%s\tf%d,(r%d) ea=%lux", ci->name, rd, rb, ea);
208 	}
209 
210 	reg.fd[rd] = v2fp(getmem_v(ea));
211 }
212 
213 void
stfs(ulong ir)214 stfs(ulong ir)
215 {
216 	ulong ea;
217 	int imm, ra, rd, upd;
218 	union {
219 		float f;
220 		ulong w;
221 	} u;
222 
223 	getairr(ir);
224 	ea = imm;
225 	upd = (ir&(1L<<26))!=0;
226 	if(ra) {
227 		ea += reg.r[ra];
228 		if(upd)
229 			reg.r[ra] = ea;
230 	} else {
231 		if(upd)
232 			undef(ir);
233 	}
234 	if(trace)
235 		itrace("%s\tf%d,%ld(r%d) %lux=%g",
236 					ci->name, rd, imm, ra, ea, reg.fd[rd]);
237 	u.f = reg.fd[rd];	/* BUG: actual PPC conversion is more subtle than this */
238 	putmem_w(ea, u.w);
239 }
240 
241 void
stfsx(ulong ir)242 stfsx(ulong ir)
243 {
244 	ulong ea;
245 	int rd, ra, rb, upd;
246 	union {
247 		float	f;
248 		ulong	w;
249 	} u;
250 
251 	getarrr(ir);
252 	ea = reg.r[rb];
253 	upd = getxo(ir)==695;
254 	if(ra){
255 		ea += reg.r[ra];
256 		if(upd)
257 			reg.r[ra] = ea;
258 		if(trace)
259 			itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, (float)reg.fd[rd]);
260 	} else {
261 		if(upd)
262 			undef(ir);
263 		if(trace)
264 			itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, (float)reg.fd[rd]);
265 	}
266 
267 	u.f = reg.fd[rd];	/* BUG: actual PPC conversion is more subtle than this */
268 	putmem_w(ea, u.w);
269 }
270 
271 void
stfd(ulong ir)272 stfd(ulong ir)
273 {
274 	ulong ea;
275 	int imm, ra, rd, upd;
276 
277 	getairr(ir);
278 	ea = imm;
279 	upd = (ir&(1L<<26))!=0;
280 	if(ra) {
281 		ea += reg.r[ra];
282 		if(upd)
283 			reg.r[ra] = ea;
284 	} else {
285 		if(upd)
286 			undef(ir);
287 	}
288 	if(trace)
289 		itrace("%s\tf%d,%ld(r%d) %lux=%g",
290 					ci->name, rd, imm, ra, ea, reg.fd[rd]);
291 
292 	putmem_v(ea, fp2v(reg.fd[rd]));
293 }
294 
295 void
stfdx(ulong ir)296 stfdx(ulong ir)
297 {
298 	ulong ea;
299 	int rd, ra, rb, upd;
300 
301 	getarrr(ir);
302 	ea = reg.r[rb];
303 	upd = ((ir>>1)&0x3FF)==759;
304 	if(ra){
305 		ea += reg.r[ra];
306 		if(upd)
307 			reg.r[ra] = ea;
308 		if(trace)
309 			itrace("%s\tf%d,(r%d+r%d) %lux=%g", ci->name, rd, ra, rb, ea, reg.fd[rd]);
310 	} else {
311 		if(upd)
312 			undef(ir);
313 		if(trace)
314 			itrace("%s\tf%d,(r%d) %lux=%g", ci->name, rd, rb, ea, reg.fd[rd]);
315 	}
316 
317 	putmem_v(ea, fp2v(reg.fd[rd]));
318 }
319 
320 void
mcrfs(ulong ir)321 mcrfs(ulong ir)
322 {
323 	ulong rd, ra, rb;
324 	static ulong fpscr0[] ={
325 		FPS_FX|FPS_OX,
326 		FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,
327 		FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,
328 		FPS_VXVC,
329 		0,
330 		FPS_VXCVI,
331 	};
332 
333 	getarrr(ir);
334 	if(rb || ra&3 || rd&3)
335 		undef(ir);
336 	ra >>= 2;
337 	rd >>= 2;
338 	reg.cr = (reg.cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, reg.fpscr));
339 	reg.fpscr &= ~fpscr0[ra];
340 	if(trace)
341 		itrace("mcrfs\tcrf%d,crf%d\n", rd, ra);
342 }
343 
344 void
mffs(ulong ir)345 mffs(ulong ir)
346 {
347 	int rd, ra, rb;
348 	FPdbleword d;
349 
350 	getarrr(ir);
351 	if(ra || rb)
352 		undef(ir);
353 	d.hi = 0xFFF80000UL;
354 	d.lo = reg.fpscr;
355 	reg.fd[rd] = d.x;
356 	/* it's anyone's guess how CR1 should be set when ir&1 */
357 	reg.cr &= ~mkCR(1, 0xE);	/* leave SO, reset others */
358 	if(trace)
359 		itrace("mffs%s\tfr%d\n", ir&1?".":"", rd);
360 }
361 
362 void
mtfsb1(ulong ir)363 mtfsb1(ulong ir)
364 {
365 	int rd, ra, rb;
366 
367 	getarrr(ir);
368 	if(ra || rb)
369 		undef(ir);
370 	reg.fpscr |= (1L << (31-rd));
371 	/* BUG: should set summary bits */
372 	if(ir & 1)
373 		reg.cr &= ~mkCR(1, 0xE);	/* BUG: manual unclear: leave SO, reset others? */
374 	if(trace)
375 		itrace("mtfsb1%s\tfr%d\n", ir&1?".":"", rd);
376 }
377 
378 void
mtfsb0(ulong ir)379 mtfsb0(ulong ir)
380 {
381 	int rd, ra, rb;
382 
383 	getarrr(ir);
384 	if(ra || rb)
385 		undef(ir);
386 	reg.fpscr &= ~(1L << (31-rd));
387 	if(ir & 1)
388 		reg.cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */
389 	if(trace)
390 		itrace("mtfsb0%s\tfr%d\n", ir&1?".":"", rd);
391 }
392 
393 void
mtfsf(ulong ir)394 mtfsf(ulong ir)
395 {
396 	int fm, rb, i;
397 	FPdbleword d;
398 	ulong v;
399 
400 	if(ir & ((1L << 25)|(1L << 16)))
401 		undef(ir);
402 	rb = (ir >> 11) & 0x1F;
403 	fm = (ir >> 17) & 0xFF;
404 	d.x = reg.fd[rb];
405 	v = d.lo;
406 	for(i=0; i<8; i++)
407 		if(fm & (1 << (7-i)))
408 			reg.fpscr = (reg.fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
409 	/* BUG: should set FEX and VX `according to the usual rule' */
410 	if(ir & 1)
411 		reg.cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */
412 	if(trace)
413 		itrace("mtfsf%s\t#%.2x,fr%d", ir&1?".":"", fm, rb);
414 }
415 
416 void
mtfsfi(ulong ir)417 mtfsfi(ulong ir)
418 {
419 	int imm, rd;
420 
421 	if(ir & ((0x7F << 16)|(1L << 11)))
422 		undef(ir);
423 	rd = (ir >> 23) & 0xF;
424 	imm = (ir >> 12) & 0xF;
425 	reg.fpscr = (reg.fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
426 	/* BUG: should set FEX and VX `according to the usual rule' */
427 	if(ir & 1)
428 		reg.cr &= ~mkCR(1, 0xE);		/* BUG: manual unclear: leave SO, reset others? */
429 	if(trace)
430 		itrace("mtfsfi%s\tcrf%d,#%x", ir&1?".":"", rd, imm);
431 }
432 
433 void
fcmp(ulong ir)434 fcmp(ulong ir)
435 {
436 	int fc, rd, ra, rb;
437 
438 	getarrr(ir);
439 	if(rd & 3)
440 		undef(ir);
441 	rd >>= 2;
442 	SET(fc);
443 	switch(getxo(ir)) {
444 	default:
445 		undef(ir);
446 	case 0:
447 		if(trace)
448 			itrace("fcmpu\tcr%d,f%d,f%d", rd, ra, rb);
449 		if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {
450 			fc = CRFU;
451 			break;
452 		}
453 		if(reg.fd[ra] == reg.fd[rb]) {
454 			fc = CREQ;
455 			break;
456 		}
457 		if(reg.fd[ra] < reg.fd[rb]) {
458 			fc = CRLT;
459 			break;
460 		}
461 		if(reg.fd[ra] > reg.fd[rb]) {
462 			fc = CRGT;
463 			break;
464 		}
465 		print("qi: fcmp error\n");
466 		break;
467 	case 32:
468 		if(trace)
469 			itrace("fcmpo\tcr%d,f%d,f%d", rd, ra, rb);
470 		if(isNaN(reg.fd[ra]) || isNaN(reg.fd[rb])) {	/* BUG: depends whether quiet or signalling ... */
471 			fc = CRFU;
472 			Bprint(bioout, "invalid_fp_register\n");
473 			longjmp(errjmp, 0);
474 		}
475 		if(reg.fd[ra] == reg.fd[rb]) {
476 			fc = CREQ;
477 			break;
478 		}
479 		if(reg.fd[ra] < reg.fd[rb]) {
480 			fc = CRLT;
481 			break;
482 		}
483 		if(reg.fd[ra] > reg.fd[rb]) {
484 			fc = CRGT;
485 			break;
486 		}
487 		print("qi: fcmp error\n");
488 		break;
489 
490 	}
491 	fc >>= 28;
492 	reg.cr = (reg.cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
493 	reg.fpscr = (reg.fpscr & ~0xF800) | (fc<<11);
494 	/* BUG: update FX, VXSNAN, VXVC */
495 }
496 
497 /*
498  * the farith functions probably don't produce the right results
499  * in the presence of NaNs, Infs, etc., esp. wrt exception handling,
500  */
501 void
fariths(ulong ir)502 fariths(ulong ir)
503 {
504 	int rd, ra, rb, rc, fmt;
505 	char *cc;
506 	ulong fpscr;
507 
508 	fmt = 0;
509 	rc = (ir>>6)&0x1F;
510 	getarrr(ir);
511 	switch(getxo(ir)&0x1F) {	/* partial XO decode */
512 	default:
513 		undef(ir);
514 	case 18:
515 		if((float)reg.fd[rb] == 0.0) {
516 			Bprint(bioout, "fp_exception ZX\n");
517 			reg.fpscr |= FPS_ZX | FPS_FX;
518 			longjmp(errjmp, 0);
519 		}
520 		reg.fd[rd] = (float)(reg.fd[ra] / reg.fd[rb]);
521 		break;
522 	case 20:
523 		reg.fd[rd] = (float)(reg.fd[ra] - reg.fd[rb]);
524 		break;
525 	case 21:
526 		reg.fd[rd] = (float)(reg.fd[ra] + reg.fd[rb]);
527 		break;
528 	case 25:
529 		reg.fd[rd] = (float)(reg.fd[ra] * reg.fd[rc]);
530 		rb = rc;
531 		break;
532 	case 28:
533 		reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
534 		fmt = 2;
535 		break;
536 	case 29:
537 		reg.fd[rd] = (float)((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
538 		fmt = 2;
539 		break;
540 	case 30:
541 		reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
542 		fmt = 2;
543 		break;
544 	case 31:
545 		reg.fd[rd] = (float)-((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
546 		fmt = 2;
547 		break;
548 	}
549 	if(fmt==1 && ra)
550 		undef(ir);
551 	fpscr = setfpscr();
552 	setfpcc(reg.fd[rd]);
553 	cc = "";
554 	if(ir & 1) {
555 		cc = ".";
556 		reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
557 	}
558 	if(trace) {
559 		switch(fmt) {
560 		case 0:
561 			itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
562 			break;
563 		case 1:
564 			itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
565 			break;
566 		case 2:
567 			itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
568 			break;
569 		}
570 	}
571 }
572 
573 void
farith(ulong ir)574 farith(ulong ir)
575 {
576 	vlong vl;
577 	int rd, ra, rb, rc, fmt;
578 	char *cc;
579 	ulong fpscr;
580 	int nocc;
581 	double d;
582 
583 	fmt = 0;
584 	nocc = 0;
585 	rc = (ir>>6)&0x1F;
586 	getarrr(ir);
587 	switch(getxo(ir)&0x1F) { /* partial XO decode */
588 	default:
589 		undef(ir);
590 	case 12:	/* frsp */
591 		reg.fd[rd] = (float)reg.fd[rb];
592 		fmt = 1;
593 		break;
594 	case 14:	/* fctiw */	/* BUG: ignores rounding mode */
595 	case 15:	/* fctiwz */
596 		d = reg.fd[rb];
597 		if(d >= 0x7fffffff)
598 			vl = 0x7fffffff;
599 		else if(d < 0x80000000)
600 			vl = 0x80000000;
601 		else
602 			vl = d;
603 		reg.fd[rd] = v2fp(vl);
604 		fmt = 1;
605 		nocc = 1;
606 		break;
607 	case 18:
608 		if(reg.fd[rb] == 0.0) {
609 			Bprint(bioout, "fp_exception ZX\n");
610 			reg.fpscr |= FPS_ZX | FPS_FX;
611 			longjmp(errjmp, 0);
612 		}
613 		reg.fd[rd] = reg.fd[ra] / reg.fd[rb];
614 		break;
615 	case 20:
616 		reg.fd[rd] = reg.fd[ra] - reg.fd[rb];
617 		break;
618 	case 21:
619 		reg.fd[rd] = reg.fd[ra] + reg.fd[rb];
620 		break;
621 	case 25:
622 		reg.fd[rd] = reg.fd[ra] * reg.fd[rc];
623 		rb = rc;
624 		break;
625 	case 28:
626 		reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) - reg.fd[rb];
627 		fmt = 2;
628 		break;
629 	case 29:
630 		reg.fd[rd] = (reg.fd[ra] * reg.fd[rc]) + reg.fd[rb];
631 		fmt = 2;
632 		break;
633 	case 30:
634 		reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) - reg.fd[rb]);
635 		fmt = 2;
636 		break;
637 	case 31:
638 		reg.fd[rd] = -((reg.fd[ra] * reg.fd[rc]) + reg.fd[rb]);
639 		fmt = 2;
640 		break;
641 	}
642 	if(fmt==1 && ra)
643 		undef(ir);
644 	fpscr = setfpscr();
645 	if(nocc == 0)
646 		setfpcc(reg.fd[rd]);
647 	cc = "";
648 	if(ir & 1) {
649 		cc = ".";
650 		reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
651 	}
652 	if(trace) {
653 		switch(fmt) {
654 		case 0:
655 			itrace("%s%s\tfr%d,fr%d,fr%d", ci->name, cc, rd, ra, rb);
656 			break;
657 		case 1:
658 			itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
659 			break;
660 		case 2:
661 			itrace("%s%s\tfr%d,fr%d,fr%d,fr%d", ci->name, cc, rd, ra, rc, rb);
662 			break;
663 		}
664 	}
665 }
666 
667 void
farith2(ulong ir)668 farith2(ulong ir)
669 {
670 	int rd, ra, rb;
671 	char *cc;
672 	ulong fpscr;
673 
674 	getarrr(ir);
675 	switch(getxo(ir)) { /* full XO decode */
676 	default:
677 		undef(ir);
678 	case 40:
679 		reg.fd[rd] = -reg.fd[rb];
680 		break;
681 	case 72:
682 		reg.fd[rd] = reg.fd[rb];
683 		break;
684 	case 136:
685 		reg.fd[rd] = -fabs(reg.fd[rb]);
686 		break;
687 	case 264:
688 		reg.fd[rd] = fabs(reg.fd[rb]);
689 		break;
690 	}
691 	if(ra)
692 		undef(ir);
693 	fpscr = setfpscr();
694 	setfpcc(reg.fd[rd]);
695 	cc = "";
696 	if(ir & 1) {
697 		cc = ".";
698 		reg.cr = (reg.cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
699 	}
700 	if(trace)
701 		itrace("%s%s\tfr%d,fr%d", ci->name, cc, rd, rb);
702 }
703 
704 ulong
setfpscr(void)705 setfpscr(void)
706 {
707 	ulong fps, fpscr;
708 
709 	fps = getfsr();
710 	fpscr = reg.fpscr;
711 	if(fps & FPAOVFL)
712 		fpscr |= FPS_OX;
713 	if(fps & FPAINEX)
714 		fpscr |= FPS_XX;
715 	if(fps & FPAUNFL)
716 		fpscr |= FPS_UX;
717 	if(fps & FPAZDIV)
718 		fpscr |= FPS_ZX;
719 	if(fpscr != reg.fpscr) {
720 		fpscr |= FPS_FX;
721 		reg.fpscr = fpscr;
722 	}
723 	return fpscr;
724 }
725 
726 void
setfpcc(double r)727 setfpcc(double r)
728 {
729 	int c;
730 
731 	c = 0;
732 	if(r == 0)
733 		c |= 2;
734 	else if(r < 0)
735 		c |= 4;
736 	else
737 		c |= 8;
738 	if(isNaN(r))
739 		c |= 1;
740 	reg.fpscr = (reg.fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
741 }
742