Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}