1*d6dfd9efSDavid du Colombier /*
2*d6dfd9efSDavid du Colombier * this doesn't attempt to implement Power architecture floating-point properties
3*d6dfd9efSDavid du Colombier * that aren't visible in the Inferno environment.
4*d6dfd9efSDavid du Colombier * all arithmetic is done in double precision.
5*d6dfd9efSDavid du Colombier * the FP trap status isn't updated.
6*d6dfd9efSDavid du Colombier */
7*d6dfd9efSDavid du Colombier #include "u.h"
8*d6dfd9efSDavid du Colombier #include "../port/lib.h"
9*d6dfd9efSDavid du Colombier #include "mem.h"
10*d6dfd9efSDavid du Colombier #include "dat.h"
11*d6dfd9efSDavid du Colombier #include "fns.h"
12*d6dfd9efSDavid du Colombier
13*d6dfd9efSDavid du Colombier #include "ureg.h"
14*d6dfd9efSDavid du Colombier
15*d6dfd9efSDavid du Colombier #include "fpi.h"
16*d6dfd9efSDavid du Colombier
17*d6dfd9efSDavid du Colombier #define REG(x) (*(long*)(((char*)em->ur)+roff[(x)]))
18*d6dfd9efSDavid du Colombier #define FR(x) (*(Internal*)em->fr[(x)&0x1F])
19*d6dfd9efSDavid du Colombier #define REGSP 0 /* in Plan 9, the user and kernel stacks are different */
20*d6dfd9efSDavid du Colombier
21*d6dfd9efSDavid du Colombier #define getulong(a) (*(ulong*)(a))
22*d6dfd9efSDavid du Colombier
23*d6dfd9efSDavid du Colombier enum {
24*d6dfd9efSDavid du Colombier CRLT = 1<<31,
25*d6dfd9efSDavid du Colombier CRGT = 1<<30,
26*d6dfd9efSDavid du Colombier CREQ = 1<<29,
27*d6dfd9efSDavid du Colombier CRSO = 1<<28,
28*d6dfd9efSDavid du Colombier CRFU = CRSO,
29*d6dfd9efSDavid du Colombier
30*d6dfd9efSDavid du Colombier CRFX = 1<<27,
31*d6dfd9efSDavid du Colombier CRFEX = 1<<26,
32*d6dfd9efSDavid du Colombier CRVX = 1<<25,
33*d6dfd9efSDavid du Colombier CROX = 1<<24,
34*d6dfd9efSDavid du Colombier };
35*d6dfd9efSDavid du Colombier
36*d6dfd9efSDavid du Colombier #define getCR(x,w) (((w)>>(28-(x*4)))&0xF)
37*d6dfd9efSDavid du Colombier #define mkCR(x,v) (((v)&0xF)<<(28-(x*4)))
38*d6dfd9efSDavid du Colombier
39*d6dfd9efSDavid du Colombier #define simm(xx, ii) xx = (short)(ii&0xFFFF);
40*d6dfd9efSDavid du Colombier #define getairr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; simm(imm,i)
41*d6dfd9efSDavid du Colombier #define getarrr(i) rd = (i>>21)&0x1f; ra = (i>>16)&0x1f; rb = (i>>11)&0x1f;
42*d6dfd9efSDavid du Colombier #define getop(i) ((i>>26)&0x3F)
43*d6dfd9efSDavid du Colombier #define getxo(i) ((i>>1)&0x3FF)
44*d6dfd9efSDavid du Colombier
45*d6dfd9efSDavid du Colombier #define FPS_FX (1<<31) /* exception summary (sticky) */
46*d6dfd9efSDavid du Colombier #define FPS_EX (1<<30) /* enabled exception summary */
47*d6dfd9efSDavid du Colombier #define FPS_VX (1<<29) /* invalid operation exception summary */
48*d6dfd9efSDavid du Colombier #define FPS_OX (1<<28) /* overflow exception OX (sticky) */
49*d6dfd9efSDavid du Colombier #define FPS_UX (1<<27) /* underflow exception UX (sticky) */
50*d6dfd9efSDavid du Colombier #define FPS_ZX (1<<26) /* zero divide exception ZX (sticky) */
51*d6dfd9efSDavid du Colombier #define FPS_XX (1<<25) /* inexact exception XX (sticky) */
52*d6dfd9efSDavid du Colombier #define FPS_VXSNAN (1<<24) /* invalid operation exception for SNaN (sticky) */
53*d6dfd9efSDavid du Colombier #define FPS_VXISI (1<<23) /* invalid operation exception for ∞-∞ (sticky) */
54*d6dfd9efSDavid du Colombier #define FPS_VXIDI (1<<22) /* invalid operation exception for ∞/∞ (sticky) */
55*d6dfd9efSDavid du Colombier #define FPS_VXZDZ (1<<21) /* invalid operation exception for 0/0 (sticky) */
56*d6dfd9efSDavid du Colombier #define FPS_VXIMZ (1<<20) /* invalid operation exception for ∞*0 (sticky) */
57*d6dfd9efSDavid du Colombier #define FPS_VXVC (1<<19) /* invalid operation exception for invalid compare (sticky) */
58*d6dfd9efSDavid du Colombier #define FPS_FR (1<<18) /* fraction rounded */
59*d6dfd9efSDavid du Colombier #define FPS_FI (1<<17) /* fraction inexact */
60*d6dfd9efSDavid du Colombier #define FPS_FPRF (1<<16) /* floating point result class */
61*d6dfd9efSDavid du Colombier #define FPS_FPCC (0xF<<12) /* <, >, =, unordered */
62*d6dfd9efSDavid du Colombier #define FPS_VXCVI (1<<8) /* enable exception for invalid integer convert (sticky) */
63*d6dfd9efSDavid du Colombier #define FPS_VE (1<<7) /* invalid operation exception enable */
64*d6dfd9efSDavid du Colombier #define FPS_OE (1<<6) /* enable overflow exceptions */
65*d6dfd9efSDavid du Colombier #define FPS_UE (1<<5) /* enable underflow */
66*d6dfd9efSDavid du Colombier #define FPS_ZE (1<<4) /* enable zero divide */
67*d6dfd9efSDavid du Colombier #define FPS_XE (1<<3) /* enable inexact exceptions */
68*d6dfd9efSDavid du Colombier #define FPS_RN (3<<0) /* rounding mode */
69*d6dfd9efSDavid du Colombier
70*d6dfd9efSDavid du Colombier typedef struct Emreg Emreg;
71*d6dfd9efSDavid du Colombier
72*d6dfd9efSDavid du Colombier struct Emreg {
73*d6dfd9efSDavid du Colombier Ureg* ur;
74*d6dfd9efSDavid du Colombier ulong (*fr)[3];
75*d6dfd9efSDavid du Colombier FPsave* ufp;
76*d6dfd9efSDavid du Colombier ulong ir;
77*d6dfd9efSDavid du Colombier char* name;
78*d6dfd9efSDavid du Colombier };
79*d6dfd9efSDavid du Colombier
80*d6dfd9efSDavid du Colombier int fpemudebug = 0;
81*d6dfd9efSDavid du Colombier
82*d6dfd9efSDavid du Colombier #undef OFR
83*d6dfd9efSDavid du Colombier #define OFR(X) ((ulong)&((Ureg*)0)->X)
84*d6dfd9efSDavid du Colombier
85*d6dfd9efSDavid du Colombier static int roff[] = {
86*d6dfd9efSDavid du Colombier OFR(r0), OFR(r1), OFR(r2), OFR(r3),
87*d6dfd9efSDavid du Colombier OFR(r4), OFR(r5), OFR(r6), OFR(r7),
88*d6dfd9efSDavid du Colombier OFR(r8), OFR(r9), OFR(r10), OFR(r11),
89*d6dfd9efSDavid du Colombier OFR(r12), OFR(r13), OFR(r14), OFR(r15),
90*d6dfd9efSDavid du Colombier OFR(r16), OFR(r17), OFR(r18), OFR(r19),
91*d6dfd9efSDavid du Colombier OFR(r20), OFR(r21), OFR(r22), OFR(r23),
92*d6dfd9efSDavid du Colombier OFR(r24), OFR(r25), OFR(r26), OFR(r27),
93*d6dfd9efSDavid du Colombier OFR(r28), OFR(r29), OFR(r30), OFR(r31),
94*d6dfd9efSDavid du Colombier };
95*d6dfd9efSDavid du Colombier
96*d6dfd9efSDavid du Colombier /*
97*d6dfd9efSDavid du Colombier * initial FP register values assumed by qc's code
98*d6dfd9efSDavid du Colombier */
99*d6dfd9efSDavid du Colombier static Internal fpreginit[] = {
100*d6dfd9efSDavid du Colombier /* s, e, l, h */
101*d6dfd9efSDavid du Colombier {0, 0x400, 0x00000000, 0x08000000}, /* F31=2.0 */
102*d6dfd9efSDavid du Colombier {0, 0x3FF, 0x00000000, 0x08000000}, /* F30=1.0 */
103*d6dfd9efSDavid du Colombier {0, 0x3FE, 0x00000000, 0x08000000}, /* F29=0.5 */
104*d6dfd9efSDavid du Colombier {0, 0x1, 0x00000000, 0x00000000}, /* F28=0.0 */
105*d6dfd9efSDavid du Colombier {0, 0x433, 0x00000000, 0x08000040}, /* F27=FREGCVI */
106*d6dfd9efSDavid du Colombier };
107*d6dfd9efSDavid du Colombier
108*d6dfd9efSDavid du Colombier static void
fadd(Emreg * em,Internal * d,int ra,int rb)109*d6dfd9efSDavid du Colombier fadd(Emreg *em, Internal *d, int ra, int rb)
110*d6dfd9efSDavid du Colombier {
111*d6dfd9efSDavid du Colombier Internal a, b;
112*d6dfd9efSDavid du Colombier
113*d6dfd9efSDavid du Colombier a = FR(ra);
114*d6dfd9efSDavid du Colombier b = FR(rb);
115*d6dfd9efSDavid du Colombier (a.s == b.s? fpiadd: fpisub)(&b, &a, d);
116*d6dfd9efSDavid du Colombier }
117*d6dfd9efSDavid du Colombier
118*d6dfd9efSDavid du Colombier static void
fsub(Emreg * em,Internal * d,int ra,int rb)119*d6dfd9efSDavid du Colombier fsub(Emreg *em, Internal *d, int ra, int rb)
120*d6dfd9efSDavid du Colombier {
121*d6dfd9efSDavid du Colombier Internal a, b;
122*d6dfd9efSDavid du Colombier
123*d6dfd9efSDavid du Colombier a = FR(ra);
124*d6dfd9efSDavid du Colombier b = FR(rb);
125*d6dfd9efSDavid du Colombier b.s ^= 1;
126*d6dfd9efSDavid du Colombier (b.s == a.s? fpiadd: fpisub)(&b, &a, d);
127*d6dfd9efSDavid du Colombier }
128*d6dfd9efSDavid du Colombier
129*d6dfd9efSDavid du Colombier static void
fmul(Emreg * em,Internal * d,int ra,int rb)130*d6dfd9efSDavid du Colombier fmul(Emreg *em, Internal *d, int ra, int rb)
131*d6dfd9efSDavid du Colombier {
132*d6dfd9efSDavid du Colombier Internal a, b;
133*d6dfd9efSDavid du Colombier
134*d6dfd9efSDavid du Colombier a = FR(ra);
135*d6dfd9efSDavid du Colombier b = FR(rb);
136*d6dfd9efSDavid du Colombier fpimul(&b, &a, d);
137*d6dfd9efSDavid du Colombier }
138*d6dfd9efSDavid du Colombier
139*d6dfd9efSDavid du Colombier static void
fdiv(Emreg * em,Internal * d,int ra,int rb)140*d6dfd9efSDavid du Colombier fdiv(Emreg *em, Internal *d, int ra, int rb)
141*d6dfd9efSDavid du Colombier {
142*d6dfd9efSDavid du Colombier Internal a, b;
143*d6dfd9efSDavid du Colombier
144*d6dfd9efSDavid du Colombier a = FR(ra);
145*d6dfd9efSDavid du Colombier b = FR(rb);
146*d6dfd9efSDavid du Colombier fpidiv(&b, &a, d);
147*d6dfd9efSDavid du Colombier }
148*d6dfd9efSDavid du Colombier
149*d6dfd9efSDavid du Colombier static void
fmsub(Emreg * em,Internal * d,int ra,int rc,int rb)150*d6dfd9efSDavid du Colombier fmsub(Emreg *em, Internal *d, int ra, int rc, int rb)
151*d6dfd9efSDavid du Colombier {
152*d6dfd9efSDavid du Colombier Internal a, c, b, t;
153*d6dfd9efSDavid du Colombier
154*d6dfd9efSDavid du Colombier a = FR(ra);
155*d6dfd9efSDavid du Colombier c = FR(rc);
156*d6dfd9efSDavid du Colombier b = FR(rb);
157*d6dfd9efSDavid du Colombier fpimul(&a, &c, &t);
158*d6dfd9efSDavid du Colombier b.s ^= 1;
159*d6dfd9efSDavid du Colombier (b.s == t.s? fpiadd: fpisub)(&b, &t, d);
160*d6dfd9efSDavid du Colombier }
161*d6dfd9efSDavid du Colombier
162*d6dfd9efSDavid du Colombier static void
fmadd(Emreg * em,Internal * d,int ra,int rc,int rb)163*d6dfd9efSDavid du Colombier fmadd(Emreg *em, Internal *d, int ra, int rc, int rb)
164*d6dfd9efSDavid du Colombier {
165*d6dfd9efSDavid du Colombier Internal a, c, b, t;
166*d6dfd9efSDavid du Colombier
167*d6dfd9efSDavid du Colombier a = FR(ra);
168*d6dfd9efSDavid du Colombier c = FR(rc);
169*d6dfd9efSDavid du Colombier b = FR(rb);
170*d6dfd9efSDavid du Colombier fpimul(&a, &c, &t);
171*d6dfd9efSDavid du Colombier (t.s == b.s? fpiadd: fpisub)(&b, &t, d);
172*d6dfd9efSDavid du Colombier }
173*d6dfd9efSDavid du Colombier
174*d6dfd9efSDavid du Colombier static ulong setfpscr(Emreg*);
175*d6dfd9efSDavid du Colombier static void setfpcc(Emreg*, int);
176*d6dfd9efSDavid du Colombier
177*d6dfd9efSDavid du Colombier static void
unimp(Emreg * em,ulong op)178*d6dfd9efSDavid du Colombier unimp(Emreg *em, ulong op)
179*d6dfd9efSDavid du Colombier {
180*d6dfd9efSDavid du Colombier char buf[60];
181*d6dfd9efSDavid du Colombier
182*d6dfd9efSDavid du Colombier snprint(buf, sizeof(buf), "sys: fp: pc=%lux unimp fp 0x%.8lux", em->ur->pc, op);
183*d6dfd9efSDavid du Colombier if(fpemudebug)
184*d6dfd9efSDavid du Colombier print("FPE: %s\n", buf);
185*d6dfd9efSDavid du Colombier error(buf);
186*d6dfd9efSDavid du Colombier /* no return */
187*d6dfd9efSDavid du Colombier }
188*d6dfd9efSDavid du Colombier
189*d6dfd9efSDavid du Colombier /*
190*d6dfd9efSDavid du Colombier * floating load/store
191*d6dfd9efSDavid du Colombier */
192*d6dfd9efSDavid du Colombier
193*d6dfd9efSDavid du Colombier static void
fpeairr(Emreg * em,ulong ir,void ** eap,int * rdp)194*d6dfd9efSDavid du Colombier fpeairr(Emreg *em, ulong ir, void **eap, int *rdp)
195*d6dfd9efSDavid du Colombier {
196*d6dfd9efSDavid du Colombier ulong ea;
197*d6dfd9efSDavid du Colombier long imm;
198*d6dfd9efSDavid du Colombier int ra, rd, upd;
199*d6dfd9efSDavid du Colombier
200*d6dfd9efSDavid du Colombier getairr(ir);
201*d6dfd9efSDavid du Colombier ea = imm;
202*d6dfd9efSDavid du Colombier upd = (ir&(1L<<26))!=0;
203*d6dfd9efSDavid du Colombier if(ra) {
204*d6dfd9efSDavid du Colombier ea += REG(ra);
205*d6dfd9efSDavid du Colombier if(upd){
206*d6dfd9efSDavid du Colombier if(REGSP && ra == REGSP)
207*d6dfd9efSDavid du Colombier panic("fpemu: r1 update"); /* can't do it because we're running on the same stack */
208*d6dfd9efSDavid du Colombier REG(ra) = ea;
209*d6dfd9efSDavid du Colombier }
210*d6dfd9efSDavid du Colombier } else {
211*d6dfd9efSDavid du Colombier if(upd)
212*d6dfd9efSDavid du Colombier unimp(em, ir);
213*d6dfd9efSDavid du Colombier }
214*d6dfd9efSDavid du Colombier *rdp = rd;
215*d6dfd9efSDavid du Colombier *eap = (void*)ea;
216*d6dfd9efSDavid du Colombier if(fpemudebug)
217*d6dfd9efSDavid du Colombier print("%8.8lux %s\tf%d,%ld(r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, imm, ra, ea, upd);
218*d6dfd9efSDavid du Colombier }
219*d6dfd9efSDavid du Colombier
220*d6dfd9efSDavid du Colombier static void
fpearrr(Emreg * em,ulong ir,int upd,void ** eap,int * rdp)221*d6dfd9efSDavid du Colombier fpearrr(Emreg *em, ulong ir, int upd, void **eap, int *rdp)
222*d6dfd9efSDavid du Colombier {
223*d6dfd9efSDavid du Colombier ulong ea;
224*d6dfd9efSDavid du Colombier int ra, rb, rd;
225*d6dfd9efSDavid du Colombier
226*d6dfd9efSDavid du Colombier getarrr(ir);
227*d6dfd9efSDavid du Colombier ea = REG(rb);
228*d6dfd9efSDavid du Colombier if(ra){
229*d6dfd9efSDavid du Colombier ea += REG(ra);
230*d6dfd9efSDavid du Colombier if(upd){
231*d6dfd9efSDavid du Colombier if(REGSP && ra == REGSP)
232*d6dfd9efSDavid du Colombier panic("fpemu: r1 update");
233*d6dfd9efSDavid du Colombier REG(ra) = ea;
234*d6dfd9efSDavid du Colombier }
235*d6dfd9efSDavid du Colombier if(fpemudebug)
236*d6dfd9efSDavid du Colombier print("%8.8lux %s\tf%d,(r%d+r%d) ea=%lux upd=%d\n", em->ur->pc, em->name, rd, ra, rb, ea, upd);
237*d6dfd9efSDavid du Colombier } else {
238*d6dfd9efSDavid du Colombier if(upd)
239*d6dfd9efSDavid du Colombier unimp(em, ir);
240*d6dfd9efSDavid du Colombier if(fpemudebug)
241*d6dfd9efSDavid du Colombier print("%8.8lux %s\tf%d,(r%d) ea=%lux\n", em->ur->pc, em->name, rd, rb, ea);
242*d6dfd9efSDavid du Colombier }
243*d6dfd9efSDavid du Colombier *eap = (void*)ea;
244*d6dfd9efSDavid du Colombier *rdp = rd;
245*d6dfd9efSDavid du Colombier }
246*d6dfd9efSDavid du Colombier
247*d6dfd9efSDavid du Colombier static void
lfs(Emreg * em,ulong ir)248*d6dfd9efSDavid du Colombier lfs(Emreg *em, ulong ir)
249*d6dfd9efSDavid du Colombier {
250*d6dfd9efSDavid du Colombier void *ea;
251*d6dfd9efSDavid du Colombier int rd;
252*d6dfd9efSDavid du Colombier
253*d6dfd9efSDavid du Colombier em->name = "lfs";
254*d6dfd9efSDavid du Colombier fpeairr(em, ir, &ea, &rd);
255*d6dfd9efSDavid du Colombier fpis2i(&FR(rd), (void*)ea);
256*d6dfd9efSDavid du Colombier }
257*d6dfd9efSDavid du Colombier
258*d6dfd9efSDavid du Colombier static void
lfsx(Emreg * em,ulong ir)259*d6dfd9efSDavid du Colombier lfsx(Emreg *em, ulong ir)
260*d6dfd9efSDavid du Colombier {
261*d6dfd9efSDavid du Colombier void *ea;
262*d6dfd9efSDavid du Colombier int rd;
263*d6dfd9efSDavid du Colombier
264*d6dfd9efSDavid du Colombier em->name = "lfsx";
265*d6dfd9efSDavid du Colombier fpearrr(em, ir, ((ir>>1)&0x3FF)==567, &ea, &rd);
266*d6dfd9efSDavid du Colombier fpis2i(&FR(rd), (void*)ea);
267*d6dfd9efSDavid du Colombier }
268*d6dfd9efSDavid du Colombier
269*d6dfd9efSDavid du Colombier static void
lfd(Emreg * em,ulong ir)270*d6dfd9efSDavid du Colombier lfd(Emreg *em, ulong ir)
271*d6dfd9efSDavid du Colombier {
272*d6dfd9efSDavid du Colombier void *ea;
273*d6dfd9efSDavid du Colombier int rd;
274*d6dfd9efSDavid du Colombier
275*d6dfd9efSDavid du Colombier em->name = "lfd";
276*d6dfd9efSDavid du Colombier fpeairr(em, ir, &ea, &rd);
277*d6dfd9efSDavid du Colombier fpid2i(&FR(rd), (void*)ea);
278*d6dfd9efSDavid du Colombier }
279*d6dfd9efSDavid du Colombier
280*d6dfd9efSDavid du Colombier static void
lfdx(Emreg * em,ulong ir)281*d6dfd9efSDavid du Colombier lfdx(Emreg *em, ulong ir)
282*d6dfd9efSDavid du Colombier {
283*d6dfd9efSDavid du Colombier void *ea;
284*d6dfd9efSDavid du Colombier int rd;
285*d6dfd9efSDavid du Colombier
286*d6dfd9efSDavid du Colombier em->name = "lfdx";
287*d6dfd9efSDavid du Colombier fpearrr(em, ir, ((ir>>1)&0x3FF)==631, &ea, &rd);
288*d6dfd9efSDavid du Colombier fpid2i(&FR(rd), (void*)ea);
289*d6dfd9efSDavid du Colombier }
290*d6dfd9efSDavid du Colombier
291*d6dfd9efSDavid du Colombier static void
stfs(Emreg * em,ulong ir)292*d6dfd9efSDavid du Colombier stfs(Emreg *em, ulong ir)
293*d6dfd9efSDavid du Colombier {
294*d6dfd9efSDavid du Colombier void *ea;
295*d6dfd9efSDavid du Colombier int rd;
296*d6dfd9efSDavid du Colombier Internal tmp;
297*d6dfd9efSDavid du Colombier
298*d6dfd9efSDavid du Colombier em->name = "stfs";
299*d6dfd9efSDavid du Colombier fpeairr(em, ir, &ea, &rd);
300*d6dfd9efSDavid du Colombier tmp = FR(rd);
301*d6dfd9efSDavid du Colombier fpii2s(ea, &tmp);
302*d6dfd9efSDavid du Colombier }
303*d6dfd9efSDavid du Colombier
304*d6dfd9efSDavid du Colombier static void
stfsx(Emreg * em,ulong ir)305*d6dfd9efSDavid du Colombier stfsx(Emreg *em, ulong ir)
306*d6dfd9efSDavid du Colombier {
307*d6dfd9efSDavid du Colombier void *ea;
308*d6dfd9efSDavid du Colombier int rd;
309*d6dfd9efSDavid du Colombier Internal tmp;
310*d6dfd9efSDavid du Colombier
311*d6dfd9efSDavid du Colombier em->name = "stfsx";
312*d6dfd9efSDavid du Colombier fpearrr(em, ir, getxo(ir)==695, &ea, &rd);
313*d6dfd9efSDavid du Colombier tmp = FR(rd);
314*d6dfd9efSDavid du Colombier fpii2s(ea, &tmp);
315*d6dfd9efSDavid du Colombier }
316*d6dfd9efSDavid du Colombier
317*d6dfd9efSDavid du Colombier static void
stfd(Emreg * em,ulong ir)318*d6dfd9efSDavid du Colombier stfd(Emreg *em, ulong ir)
319*d6dfd9efSDavid du Colombier {
320*d6dfd9efSDavid du Colombier void *ea;
321*d6dfd9efSDavid du Colombier int rd;
322*d6dfd9efSDavid du Colombier Internal tmp;
323*d6dfd9efSDavid du Colombier
324*d6dfd9efSDavid du Colombier em->name = "stfd";
325*d6dfd9efSDavid du Colombier fpeairr(em, ir, &ea, &rd);
326*d6dfd9efSDavid du Colombier tmp = FR(rd);
327*d6dfd9efSDavid du Colombier fpii2d(ea, &tmp);
328*d6dfd9efSDavid du Colombier }
329*d6dfd9efSDavid du Colombier
330*d6dfd9efSDavid du Colombier static void
stfdx(Emreg * em,ulong ir)331*d6dfd9efSDavid du Colombier stfdx(Emreg *em, ulong ir)
332*d6dfd9efSDavid du Colombier {
333*d6dfd9efSDavid du Colombier void *ea;
334*d6dfd9efSDavid du Colombier int rd;
335*d6dfd9efSDavid du Colombier Internal tmp;
336*d6dfd9efSDavid du Colombier
337*d6dfd9efSDavid du Colombier em->name = "stfdx";
338*d6dfd9efSDavid du Colombier fpearrr(em, ir, ((ir>>1)&0x3FF)==759, &ea, &rd);
339*d6dfd9efSDavid du Colombier tmp = FR(rd);
340*d6dfd9efSDavid du Colombier fpii2d(ea, &tmp);
341*d6dfd9efSDavid du Colombier }
342*d6dfd9efSDavid du Colombier
343*d6dfd9efSDavid du Colombier static void
mcrfs(Emreg * em,ulong ir)344*d6dfd9efSDavid du Colombier mcrfs(Emreg *em, ulong ir)
345*d6dfd9efSDavid du Colombier {
346*d6dfd9efSDavid du Colombier int rd, ra, rb;
347*d6dfd9efSDavid du Colombier static ulong fpscr0[] ={
348*d6dfd9efSDavid du Colombier FPS_FX|FPS_OX,
349*d6dfd9efSDavid du Colombier FPS_UX|FPS_ZX|FPS_XX|FPS_VXSNAN,
350*d6dfd9efSDavid du Colombier FPS_VXISI|FPS_VXIDI|FPS_VXZDZ|FPS_VXIMZ,
351*d6dfd9efSDavid du Colombier FPS_VXVC,
352*d6dfd9efSDavid du Colombier 0,
353*d6dfd9efSDavid du Colombier FPS_VXCVI,
354*d6dfd9efSDavid du Colombier };
355*d6dfd9efSDavid du Colombier
356*d6dfd9efSDavid du Colombier getarrr(ir);
357*d6dfd9efSDavid du Colombier if(rb || ra&3 || rd&3)
358*d6dfd9efSDavid du Colombier unimp(em, ir);
359*d6dfd9efSDavid du Colombier ra >>= 2;
360*d6dfd9efSDavid du Colombier rd >>= 2;
361*d6dfd9efSDavid du Colombier em->ur->cr = (em->ur->cr & ~mkCR(rd, 0xF)) | mkCR(rd, getCR(ra, em->ufp->fpscr));
362*d6dfd9efSDavid du Colombier em->ufp->fpscr &= ~fpscr0[ra];
363*d6dfd9efSDavid du Colombier if(fpemudebug)
364*d6dfd9efSDavid du Colombier print("%8.8lux mcrfs\tcrf%d,crf%d\n", em->ur->pc, rd, ra);
365*d6dfd9efSDavid du Colombier }
366*d6dfd9efSDavid du Colombier
367*d6dfd9efSDavid du Colombier static void
mffs(Emreg * em,ulong ir)368*d6dfd9efSDavid du Colombier mffs(Emreg *em, ulong ir)
369*d6dfd9efSDavid du Colombier {
370*d6dfd9efSDavid du Colombier int rd, ra, rb;
371*d6dfd9efSDavid du Colombier Double dw;
372*d6dfd9efSDavid du Colombier
373*d6dfd9efSDavid du Colombier getarrr(ir);
374*d6dfd9efSDavid du Colombier if(ra || rb)
375*d6dfd9efSDavid du Colombier unimp(em, ir);
376*d6dfd9efSDavid du Colombier dw.h = 0;
377*d6dfd9efSDavid du Colombier dw.l = ((uvlong)0xFFF8000L<<16)|em->ufp->fpscr;
378*d6dfd9efSDavid du Colombier fpid2i(&FR(rd), &dw);
379*d6dfd9efSDavid du Colombier /* it's anyone's guess how CR1 should be set when ir&1 */
380*d6dfd9efSDavid du Colombier em->ur->cr &= ~mkCR(1, 0xE); /* leave SO, reset others */
381*d6dfd9efSDavid du Colombier if(fpemudebug)
382*d6dfd9efSDavid du Colombier print("%8.8lux mffs%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
383*d6dfd9efSDavid du Colombier }
384*d6dfd9efSDavid du Colombier
385*d6dfd9efSDavid du Colombier static void
mtfsb1(Emreg * em,ulong ir)386*d6dfd9efSDavid du Colombier mtfsb1(Emreg *em, ulong ir)
387*d6dfd9efSDavid du Colombier {
388*d6dfd9efSDavid du Colombier int rd, ra, rb;
389*d6dfd9efSDavid du Colombier
390*d6dfd9efSDavid du Colombier getarrr(ir);
391*d6dfd9efSDavid du Colombier if(ra || rb)
392*d6dfd9efSDavid du Colombier unimp(em, ir);
393*d6dfd9efSDavid du Colombier em->ufp->fpscr |= (1L << (31-rd));
394*d6dfd9efSDavid du Colombier /* BUG: should set summary bits */
395*d6dfd9efSDavid du Colombier if(ir & 1)
396*d6dfd9efSDavid du Colombier em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
397*d6dfd9efSDavid du Colombier if(fpemudebug)
398*d6dfd9efSDavid du Colombier print("%8.8lux mtfsb1%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
399*d6dfd9efSDavid du Colombier }
400*d6dfd9efSDavid du Colombier
401*d6dfd9efSDavid du Colombier static void
mtfsb0(Emreg * em,ulong ir)402*d6dfd9efSDavid du Colombier mtfsb0(Emreg *em, ulong ir)
403*d6dfd9efSDavid du Colombier {
404*d6dfd9efSDavid du Colombier int rd, ra, rb;
405*d6dfd9efSDavid du Colombier
406*d6dfd9efSDavid du Colombier getarrr(ir);
407*d6dfd9efSDavid du Colombier if(ra || rb)
408*d6dfd9efSDavid du Colombier unimp(em, ir);
409*d6dfd9efSDavid du Colombier em->ufp->fpscr &= ~(1L << (31-rd));
410*d6dfd9efSDavid du Colombier if(ir & 1)
411*d6dfd9efSDavid du Colombier em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
412*d6dfd9efSDavid du Colombier if(fpemudebug)
413*d6dfd9efSDavid du Colombier print("%8.8lux mtfsb0%s\tfr%d\n", em->ur->pc, ir&1?".":"", rd);
414*d6dfd9efSDavid du Colombier }
415*d6dfd9efSDavid du Colombier
416*d6dfd9efSDavid du Colombier static void
mtfsf(Emreg * em,ulong ir)417*d6dfd9efSDavid du Colombier mtfsf(Emreg *em, ulong ir)
418*d6dfd9efSDavid du Colombier {
419*d6dfd9efSDavid du Colombier int fm, rb, i;
420*d6dfd9efSDavid du Colombier ulong v;
421*d6dfd9efSDavid du Colombier Internal b;
422*d6dfd9efSDavid du Colombier Double db;
423*d6dfd9efSDavid du Colombier
424*d6dfd9efSDavid du Colombier if(ir & ((1L << 25)|(1L << 16)))
425*d6dfd9efSDavid du Colombier unimp(em, ir);
426*d6dfd9efSDavid du Colombier rb = (ir >> 11) & 0x1F;
427*d6dfd9efSDavid du Colombier fm = (ir >> 17) & 0xFF;
428*d6dfd9efSDavid du Colombier b = FR(rb);
429*d6dfd9efSDavid du Colombier fpii2d(&db, &b); /* reconstruct hi/lo format to recover low word */
430*d6dfd9efSDavid du Colombier v = db.l;
431*d6dfd9efSDavid du Colombier for(i=0; i<8; i++)
432*d6dfd9efSDavid du Colombier if(fm & (1 << (7-i)))
433*d6dfd9efSDavid du Colombier em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(i, 0xF)) | mkCR(i, getCR(i, v));
434*d6dfd9efSDavid du Colombier /* BUG: should set FEX and VX `according to the usual rule' */
435*d6dfd9efSDavid du Colombier if(ir & 1)
436*d6dfd9efSDavid du Colombier em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
437*d6dfd9efSDavid du Colombier if(fpemudebug)
438*d6dfd9efSDavid du Colombier print("%8.8lux mtfsf%s\t#%.2x,fr%d\n", em->ur->pc, ir&1?".":"", fm, rb);
439*d6dfd9efSDavid du Colombier }
440*d6dfd9efSDavid du Colombier
441*d6dfd9efSDavid du Colombier static void
mtfsfi(Emreg * em,ulong ir)442*d6dfd9efSDavid du Colombier mtfsfi(Emreg *em, ulong ir)
443*d6dfd9efSDavid du Colombier {
444*d6dfd9efSDavid du Colombier int imm, rd;
445*d6dfd9efSDavid du Colombier
446*d6dfd9efSDavid du Colombier if(ir & ((0x7F << 16)|(1L << 11)))
447*d6dfd9efSDavid du Colombier unimp(em, ir);
448*d6dfd9efSDavid du Colombier rd = (ir >> 23) & 0xF;
449*d6dfd9efSDavid du Colombier imm = (ir >> 12) & 0xF;
450*d6dfd9efSDavid du Colombier em->ufp->fpscr = (em->ufp->fpscr & ~mkCR(rd, 0xF)) | mkCR(rd, imm);
451*d6dfd9efSDavid du Colombier /* BUG: should set FEX and VX `according to the usual rule' */
452*d6dfd9efSDavid du Colombier if(ir & 1)
453*d6dfd9efSDavid du Colombier em->ur->cr &= ~mkCR(1, 0xE); /* BUG: manual unclear: leave SO, reset others? */
454*d6dfd9efSDavid du Colombier if(fpemudebug)
455*d6dfd9efSDavid du Colombier print("%8.8lux mtfsfi%s\tcrf%d,#%x\n", em->ur->pc, ir&1?".":"", rd, imm);
456*d6dfd9efSDavid du Colombier }
457*d6dfd9efSDavid du Colombier
458*d6dfd9efSDavid du Colombier static void
fcmp(Emreg * em,ulong ir)459*d6dfd9efSDavid du Colombier fcmp(Emreg *em, ulong ir)
460*d6dfd9efSDavid du Colombier {
461*d6dfd9efSDavid du Colombier int fc, rd, ra, rb, sig, i;
462*d6dfd9efSDavid du Colombier Internal a, b;
463*d6dfd9efSDavid du Colombier
464*d6dfd9efSDavid du Colombier getarrr(ir);
465*d6dfd9efSDavid du Colombier if(rd & 3)
466*d6dfd9efSDavid du Colombier unimp(em, ir);
467*d6dfd9efSDavid du Colombier rd >>= 2;
468*d6dfd9efSDavid du Colombier sig = 0;
469*d6dfd9efSDavid du Colombier switch(getxo(ir)) {
470*d6dfd9efSDavid du Colombier default:
471*d6dfd9efSDavid du Colombier unimp(em, ir);
472*d6dfd9efSDavid du Colombier case 32:
473*d6dfd9efSDavid du Colombier if(fpemudebug)
474*d6dfd9efSDavid du Colombier print("%8.8lux fcmpo\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb);
475*d6dfd9efSDavid du Colombier sig = 1;
476*d6dfd9efSDavid du Colombier break;
477*d6dfd9efSDavid du Colombier case 0:
478*d6dfd9efSDavid du Colombier if(fpemudebug)
479*d6dfd9efSDavid du Colombier print("%8.8lux fcmpu\tcr%d,f%d,f%d\n", em->ur->pc, rd, ra, rb);
480*d6dfd9efSDavid du Colombier break;
481*d6dfd9efSDavid du Colombier }
482*d6dfd9efSDavid du Colombier if(IsWeird(&FR(ra)) || IsWeird(&FR(rb))) {
483*d6dfd9efSDavid du Colombier if(sig){
484*d6dfd9efSDavid du Colombier ; /* BUG: should trap if not masked ... */
485*d6dfd9efSDavid du Colombier }
486*d6dfd9efSDavid du Colombier fc = CRFU;
487*d6dfd9efSDavid du Colombier } else {
488*d6dfd9efSDavid du Colombier a = FR(ra);
489*d6dfd9efSDavid du Colombier b = FR(rb);
490*d6dfd9efSDavid du Colombier fpiround(&a);
491*d6dfd9efSDavid du Colombier fpiround(&b);
492*d6dfd9efSDavid du Colombier i = fpicmp(&a, &b);
493*d6dfd9efSDavid du Colombier if(i > 0)
494*d6dfd9efSDavid du Colombier fc = CRGT;
495*d6dfd9efSDavid du Colombier else if(i == 0)
496*d6dfd9efSDavid du Colombier fc = CREQ;
497*d6dfd9efSDavid du Colombier else
498*d6dfd9efSDavid du Colombier fc = CRLT;
499*d6dfd9efSDavid du Colombier }
500*d6dfd9efSDavid du Colombier fc >>= 28;
501*d6dfd9efSDavid du Colombier em->ur->cr = (em->ur->cr & ~mkCR(rd,~0)) | mkCR(rd, fc);
502*d6dfd9efSDavid du Colombier em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (fc<<11);
503*d6dfd9efSDavid du Colombier /* BUG: update FX, VXSNAN, VXVC */
504*d6dfd9efSDavid du Colombier }
505*d6dfd9efSDavid du Colombier
506*d6dfd9efSDavid du Colombier static void
fariths(Emreg * em,ulong ir)507*d6dfd9efSDavid du Colombier fariths(Emreg *em, ulong ir)
508*d6dfd9efSDavid du Colombier {
509*d6dfd9efSDavid du Colombier int rd, ra, rb, rc, fmt;
510*d6dfd9efSDavid du Colombier char *cc, *n;
511*d6dfd9efSDavid du Colombier ulong fpscr;
512*d6dfd9efSDavid du Colombier Internal *d;
513*d6dfd9efSDavid du Colombier
514*d6dfd9efSDavid du Colombier fmt = 0;
515*d6dfd9efSDavid du Colombier rc = (ir>>6)&0x1F;
516*d6dfd9efSDavid du Colombier getarrr(ir);
517*d6dfd9efSDavid du Colombier d = &FR(rd);
518*d6dfd9efSDavid du Colombier switch(getxo(ir)&0x1F) { /* partial XO decode */
519*d6dfd9efSDavid du Colombier case 22: /* fsqrts */
520*d6dfd9efSDavid du Colombier case 24: /* fres */
521*d6dfd9efSDavid du Colombier default:
522*d6dfd9efSDavid du Colombier unimp(em, ir);
523*d6dfd9efSDavid du Colombier return;
524*d6dfd9efSDavid du Colombier case 18:
525*d6dfd9efSDavid du Colombier if(IsZero(&FR(rb))) {
526*d6dfd9efSDavid du Colombier em->ufp->fpscr |= FPS_ZX | FPS_FX;
527*d6dfd9efSDavid du Colombier error("sys: fp: zero divide");
528*d6dfd9efSDavid du Colombier }
529*d6dfd9efSDavid du Colombier fdiv(em, d, ra, rb);
530*d6dfd9efSDavid du Colombier n = "fdivs";
531*d6dfd9efSDavid du Colombier break;
532*d6dfd9efSDavid du Colombier case 20:
533*d6dfd9efSDavid du Colombier fsub(em, d, ra, rb);
534*d6dfd9efSDavid du Colombier n = "fsubs";
535*d6dfd9efSDavid du Colombier break;
536*d6dfd9efSDavid du Colombier case 21:
537*d6dfd9efSDavid du Colombier fadd(em, d, ra, rb);
538*d6dfd9efSDavid du Colombier n = "fadds";
539*d6dfd9efSDavid du Colombier break;
540*d6dfd9efSDavid du Colombier case 25:
541*d6dfd9efSDavid du Colombier fmul(em, d, ra, rc);
542*d6dfd9efSDavid du Colombier rb = rc;
543*d6dfd9efSDavid du Colombier n = "fmuls";
544*d6dfd9efSDavid du Colombier break;
545*d6dfd9efSDavid du Colombier case 28:
546*d6dfd9efSDavid du Colombier fmsub(em, d, ra, rc, rb);
547*d6dfd9efSDavid du Colombier fmt = 2;
548*d6dfd9efSDavid du Colombier n = "fmsubs";
549*d6dfd9efSDavid du Colombier break;
550*d6dfd9efSDavid du Colombier case 29:
551*d6dfd9efSDavid du Colombier fmadd(em, d, ra, rc, rb);
552*d6dfd9efSDavid du Colombier fmt = 2;
553*d6dfd9efSDavid du Colombier n = "fmadds";
554*d6dfd9efSDavid du Colombier break;
555*d6dfd9efSDavid du Colombier case 30:
556*d6dfd9efSDavid du Colombier fmsub(em, d, ra, rc, rb);
557*d6dfd9efSDavid du Colombier d->s ^= 1;
558*d6dfd9efSDavid du Colombier fmt = 2;
559*d6dfd9efSDavid du Colombier n = "fnmsubs";
560*d6dfd9efSDavid du Colombier break;
561*d6dfd9efSDavid du Colombier case 31:
562*d6dfd9efSDavid du Colombier fmadd(em, d, ra, rc, rb);
563*d6dfd9efSDavid du Colombier d->s ^= 1;
564*d6dfd9efSDavid du Colombier fmt = 2;
565*d6dfd9efSDavid du Colombier n = "fnmadds";
566*d6dfd9efSDavid du Colombier break;
567*d6dfd9efSDavid du Colombier }
568*d6dfd9efSDavid du Colombier if(fmt==1 && ra)
569*d6dfd9efSDavid du Colombier unimp(em, ir);
570*d6dfd9efSDavid du Colombier fpscr = setfpscr(em);
571*d6dfd9efSDavid du Colombier setfpcc(em, rd);
572*d6dfd9efSDavid du Colombier cc = "";
573*d6dfd9efSDavid du Colombier if(ir & 1) {
574*d6dfd9efSDavid du Colombier cc = ".";
575*d6dfd9efSDavid du Colombier em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
576*d6dfd9efSDavid du Colombier }
577*d6dfd9efSDavid du Colombier if(fpemudebug) {
578*d6dfd9efSDavid du Colombier switch(fmt) {
579*d6dfd9efSDavid du Colombier case 0:
580*d6dfd9efSDavid du Colombier print("%8.8lux %s%s\tfr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rb);
581*d6dfd9efSDavid du Colombier break;
582*d6dfd9efSDavid du Colombier case 1:
583*d6dfd9efSDavid du Colombier print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
584*d6dfd9efSDavid du Colombier break;
585*d6dfd9efSDavid du Colombier case 2:
586*d6dfd9efSDavid du Colombier print("%8.8lux %s%s\tfr%d,fr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rc, rb);
587*d6dfd9efSDavid du Colombier break;
588*d6dfd9efSDavid du Colombier }
589*d6dfd9efSDavid du Colombier }
590*d6dfd9efSDavid du Colombier }
591*d6dfd9efSDavid du Colombier
592*d6dfd9efSDavid du Colombier static void
farith(Emreg * em,ulong ir)593*d6dfd9efSDavid du Colombier farith(Emreg *em, ulong ir)
594*d6dfd9efSDavid du Colombier {
595*d6dfd9efSDavid du Colombier Word w;
596*d6dfd9efSDavid du Colombier Double dv;
597*d6dfd9efSDavid du Colombier int rd, ra, rb, rc, fmt;
598*d6dfd9efSDavid du Colombier char *cc, *n;
599*d6dfd9efSDavid du Colombier ulong fpscr;
600*d6dfd9efSDavid du Colombier int nocc;
601*d6dfd9efSDavid du Colombier Internal *d;
602*d6dfd9efSDavid du Colombier
603*d6dfd9efSDavid du Colombier fmt = 0;
604*d6dfd9efSDavid du Colombier nocc = 0;
605*d6dfd9efSDavid du Colombier rc = (ir>>6)&0x1F;
606*d6dfd9efSDavid du Colombier getarrr(ir);
607*d6dfd9efSDavid du Colombier d = &FR(rd);
608*d6dfd9efSDavid du Colombier switch(getxo(ir)&0x1F) { /* partial XO decode */
609*d6dfd9efSDavid du Colombier case 22: /* frsqrt */
610*d6dfd9efSDavid du Colombier case 23: /* fsel */
611*d6dfd9efSDavid du Colombier case 26: /* fsqrte */
612*d6dfd9efSDavid du Colombier default:
613*d6dfd9efSDavid du Colombier unimp(em, ir);
614*d6dfd9efSDavid du Colombier return;
615*d6dfd9efSDavid du Colombier case 12: /* frsp */
616*d6dfd9efSDavid du Colombier *d = FR(rb); /* BUG: doesn't round to single precision */
617*d6dfd9efSDavid du Colombier fmt = 1;
618*d6dfd9efSDavid du Colombier n = "frsp";
619*d6dfd9efSDavid du Colombier break;
620*d6dfd9efSDavid du Colombier case 14: /* fctiw */ /* BUG: ignores rounding mode */
621*d6dfd9efSDavid du Colombier case 15: /* fctiwz */
622*d6dfd9efSDavid du Colombier fpii2w(&w, &FR(rb));
623*d6dfd9efSDavid du Colombier dv.h = 0;
624*d6dfd9efSDavid du Colombier dv.l = w;
625*d6dfd9efSDavid du Colombier fpid2i(d, &dv);
626*d6dfd9efSDavid du Colombier fmt = 1;
627*d6dfd9efSDavid du Colombier nocc = 1;
628*d6dfd9efSDavid du Colombier n = "fctiw";
629*d6dfd9efSDavid du Colombier break;
630*d6dfd9efSDavid du Colombier case 18:
631*d6dfd9efSDavid du Colombier if(IsZero(&FR(rb))) {
632*d6dfd9efSDavid du Colombier em->ufp->fpscr |= FPS_ZX | FPS_FX;
633*d6dfd9efSDavid du Colombier error("sys: fp: zero divide");
634*d6dfd9efSDavid du Colombier }
635*d6dfd9efSDavid du Colombier fdiv(em, d, ra, rb);
636*d6dfd9efSDavid du Colombier n = "fdiv";
637*d6dfd9efSDavid du Colombier break;
638*d6dfd9efSDavid du Colombier case 20:
639*d6dfd9efSDavid du Colombier fsub(em, d, ra, rb);
640*d6dfd9efSDavid du Colombier n = "fsub";
641*d6dfd9efSDavid du Colombier break;
642*d6dfd9efSDavid du Colombier case 21:
643*d6dfd9efSDavid du Colombier fadd(em, d, ra, rb);
644*d6dfd9efSDavid du Colombier n = "fadd";
645*d6dfd9efSDavid du Colombier break;
646*d6dfd9efSDavid du Colombier case 25:
647*d6dfd9efSDavid du Colombier fmul(em, d, ra, rc);
648*d6dfd9efSDavid du Colombier rb = rc;
649*d6dfd9efSDavid du Colombier n = "fmul";
650*d6dfd9efSDavid du Colombier break;
651*d6dfd9efSDavid du Colombier case 28:
652*d6dfd9efSDavid du Colombier fmsub(em, d, ra, rc, rb);
653*d6dfd9efSDavid du Colombier fmt = 2;
654*d6dfd9efSDavid du Colombier n = "fmsub";
655*d6dfd9efSDavid du Colombier break;
656*d6dfd9efSDavid du Colombier case 29:
657*d6dfd9efSDavid du Colombier fmadd(em, d, ra, rc, rb);
658*d6dfd9efSDavid du Colombier fmt = 2;
659*d6dfd9efSDavid du Colombier n = "fmadd";
660*d6dfd9efSDavid du Colombier break;
661*d6dfd9efSDavid du Colombier case 30:
662*d6dfd9efSDavid du Colombier fmsub(em, d, ra, rc, rb);
663*d6dfd9efSDavid du Colombier d->s ^= 1;
664*d6dfd9efSDavid du Colombier fmt = 2;
665*d6dfd9efSDavid du Colombier n = "fnmsub";
666*d6dfd9efSDavid du Colombier break;
667*d6dfd9efSDavid du Colombier case 31:
668*d6dfd9efSDavid du Colombier fmadd(em, d, ra, rc, rb);
669*d6dfd9efSDavid du Colombier d->s ^= 1;
670*d6dfd9efSDavid du Colombier fmt = 2;
671*d6dfd9efSDavid du Colombier n = "fnmadd";
672*d6dfd9efSDavid du Colombier break;
673*d6dfd9efSDavid du Colombier }
674*d6dfd9efSDavid du Colombier if(fmt==1 && ra)
675*d6dfd9efSDavid du Colombier unimp(em, ir);
676*d6dfd9efSDavid du Colombier fpscr = setfpscr(em);
677*d6dfd9efSDavid du Colombier if(nocc == 0)
678*d6dfd9efSDavid du Colombier setfpcc(em, rd);
679*d6dfd9efSDavid du Colombier cc = "";
680*d6dfd9efSDavid du Colombier if(ir & 1) {
681*d6dfd9efSDavid du Colombier cc = ".";
682*d6dfd9efSDavid du Colombier em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
683*d6dfd9efSDavid du Colombier }
684*d6dfd9efSDavid du Colombier if(fpemudebug) {
685*d6dfd9efSDavid du Colombier switch(fmt) {
686*d6dfd9efSDavid du Colombier case 0:
687*d6dfd9efSDavid du Colombier print("%8.8lux %s%s\tfr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rb);
688*d6dfd9efSDavid du Colombier break;
689*d6dfd9efSDavid du Colombier case 1:
690*d6dfd9efSDavid du Colombier print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
691*d6dfd9efSDavid du Colombier break;
692*d6dfd9efSDavid du Colombier case 2:
693*d6dfd9efSDavid du Colombier print("%8.8lux %s%s\tfr%d,fr%d,fr%d,fr%d\n", em->ur->pc, n, cc, rd, ra, rc, rb);
694*d6dfd9efSDavid du Colombier break;
695*d6dfd9efSDavid du Colombier }
696*d6dfd9efSDavid du Colombier }
697*d6dfd9efSDavid du Colombier }
698*d6dfd9efSDavid du Colombier
699*d6dfd9efSDavid du Colombier static void
farith2(Emreg * em,ulong ir)700*d6dfd9efSDavid du Colombier farith2(Emreg *em, ulong ir)
701*d6dfd9efSDavid du Colombier {
702*d6dfd9efSDavid du Colombier int rd, ra, rb;
703*d6dfd9efSDavid du Colombier char *cc, *n;
704*d6dfd9efSDavid du Colombier ulong fpscr;
705*d6dfd9efSDavid du Colombier Internal *d, *b;
706*d6dfd9efSDavid du Colombier
707*d6dfd9efSDavid du Colombier getarrr(ir);
708*d6dfd9efSDavid du Colombier if(ra)
709*d6dfd9efSDavid du Colombier unimp(em, ir);
710*d6dfd9efSDavid du Colombier d = &FR(rd);
711*d6dfd9efSDavid du Colombier b = &FR(rb);
712*d6dfd9efSDavid du Colombier switch(getxo(ir)) { /* full XO decode */
713*d6dfd9efSDavid du Colombier default:
714*d6dfd9efSDavid du Colombier unimp(em, ir);
715*d6dfd9efSDavid du Colombier case 40:
716*d6dfd9efSDavid du Colombier *d = *b;
717*d6dfd9efSDavid du Colombier d->s ^= 1;
718*d6dfd9efSDavid du Colombier n = "fneg";
719*d6dfd9efSDavid du Colombier break;
720*d6dfd9efSDavid du Colombier case 72:
721*d6dfd9efSDavid du Colombier *d = *b;
722*d6dfd9efSDavid du Colombier n = "fmr";
723*d6dfd9efSDavid du Colombier break;
724*d6dfd9efSDavid du Colombier case 136:
725*d6dfd9efSDavid du Colombier *d = *b;
726*d6dfd9efSDavid du Colombier d->s = 1;
727*d6dfd9efSDavid du Colombier n = "fnabs";
728*d6dfd9efSDavid du Colombier break;
729*d6dfd9efSDavid du Colombier case 264:
730*d6dfd9efSDavid du Colombier *d = *b;
731*d6dfd9efSDavid du Colombier d->s = 0;
732*d6dfd9efSDavid du Colombier n = "fabs";
733*d6dfd9efSDavid du Colombier break;
734*d6dfd9efSDavid du Colombier }
735*d6dfd9efSDavid du Colombier fpscr = setfpscr(em);
736*d6dfd9efSDavid du Colombier setfpcc(em, rd);
737*d6dfd9efSDavid du Colombier cc = "";
738*d6dfd9efSDavid du Colombier if(ir & 1) {
739*d6dfd9efSDavid du Colombier cc = ".";
740*d6dfd9efSDavid du Colombier em->ur->cr = (em->ur->cr & ~mkCR(1, ~0)) | mkCR(1, (fpscr>>28));
741*d6dfd9efSDavid du Colombier }
742*d6dfd9efSDavid du Colombier if(fpemudebug)
743*d6dfd9efSDavid du Colombier print("%8.8lux %s%s\tfr%d,fr%d\n", em->ur->pc, n, cc, rd, rb);
744*d6dfd9efSDavid du Colombier }
745*d6dfd9efSDavid du Colombier
746*d6dfd9efSDavid du Colombier static ulong
setfpscr(Emreg * em)747*d6dfd9efSDavid du Colombier setfpscr(Emreg *em)
748*d6dfd9efSDavid du Colombier {
749*d6dfd9efSDavid du Colombier ulong fps, fpscr;
750*d6dfd9efSDavid du Colombier
751*d6dfd9efSDavid du Colombier fps = 0; /* BUG: getfsr() */
752*d6dfd9efSDavid du Colombier fpscr = em->ufp->fpscr;
753*d6dfd9efSDavid du Colombier if(fps & FPAOVFL)
754*d6dfd9efSDavid du Colombier fpscr |= FPS_OX;
755*d6dfd9efSDavid du Colombier if(fps & FPAINEX)
756*d6dfd9efSDavid du Colombier fpscr |= FPS_XX;
757*d6dfd9efSDavid du Colombier if(fps & FPAUNFL)
758*d6dfd9efSDavid du Colombier fpscr |= FPS_UX;
759*d6dfd9efSDavid du Colombier if(fps & FPAZDIV)
760*d6dfd9efSDavid du Colombier fpscr |= FPS_ZX;
761*d6dfd9efSDavid du Colombier if(fpscr != em->ufp->fpscr) {
762*d6dfd9efSDavid du Colombier fpscr |= FPS_FX;
763*d6dfd9efSDavid du Colombier em->ufp->fpscr = fpscr;
764*d6dfd9efSDavid du Colombier }
765*d6dfd9efSDavid du Colombier return fpscr;
766*d6dfd9efSDavid du Colombier }
767*d6dfd9efSDavid du Colombier
768*d6dfd9efSDavid du Colombier static void
setfpcc(Emreg * em,int r)769*d6dfd9efSDavid du Colombier setfpcc(Emreg *em, int r)
770*d6dfd9efSDavid du Colombier {
771*d6dfd9efSDavid du Colombier int c;
772*d6dfd9efSDavid du Colombier Internal *d;
773*d6dfd9efSDavid du Colombier
774*d6dfd9efSDavid du Colombier d = &FR(r);
775*d6dfd9efSDavid du Colombier c = 0;
776*d6dfd9efSDavid du Colombier if(IsZero(d))
777*d6dfd9efSDavid du Colombier c |= 2;
778*d6dfd9efSDavid du Colombier else if(d->s == 1)
779*d6dfd9efSDavid du Colombier c |= 4;
780*d6dfd9efSDavid du Colombier else
781*d6dfd9efSDavid du Colombier c |= 8;
782*d6dfd9efSDavid du Colombier if(IsNaN(d))
783*d6dfd9efSDavid du Colombier c |= 1;
784*d6dfd9efSDavid du Colombier em->ufp->fpscr = (em->ufp->fpscr & ~0xF800) | (0<<15) | (c<<11); /* unsure about class bit */
785*d6dfd9efSDavid du Colombier }
786*d6dfd9efSDavid du Colombier
787*d6dfd9efSDavid du Colombier static uchar op63flag[32] = {
788*d6dfd9efSDavid du Colombier [12] 1, [14] 1, [15] 1, [18] 1, [20] 1, [21] 1, [22] 1,
789*d6dfd9efSDavid du Colombier [23] 1, [25] 1, [26] 1, [28] 1, [29] 1, [30] 1, [31] 1,
790*d6dfd9efSDavid du Colombier };
791*d6dfd9efSDavid du Colombier
792*d6dfd9efSDavid du Colombier /*
793*d6dfd9efSDavid du Colombier * returns the number of FP instructions emulated
794*d6dfd9efSDavid du Colombier */
795*d6dfd9efSDavid du Colombier int
fpipower(Ureg * ur)796*d6dfd9efSDavid du Colombier fpipower(Ureg *ur)
797*d6dfd9efSDavid du Colombier {
798*d6dfd9efSDavid du Colombier ulong op;
799*d6dfd9efSDavid du Colombier int xo;
800*d6dfd9efSDavid du Colombier Emreg emreg, *em;
801*d6dfd9efSDavid du Colombier FPsave *ufp;
802*d6dfd9efSDavid du Colombier int n;
803*d6dfd9efSDavid du Colombier
804*d6dfd9efSDavid du Colombier ufp = &up->fpsave; /* because all the state is in FPsave, it need not be saved/restored */
805*d6dfd9efSDavid du Colombier em = &emreg;
806*d6dfd9efSDavid du Colombier em->ur = ur;
807*d6dfd9efSDavid du Colombier em->fr = ufp->emreg;
808*d6dfd9efSDavid du Colombier em->ufp = ufp;
809*d6dfd9efSDavid du Colombier em->name = nil;
810*d6dfd9efSDavid du Colombier if(em->ufp->fpistate != FPactive) {
811*d6dfd9efSDavid du Colombier em->ufp->fpistate = FPactive;
812*d6dfd9efSDavid du Colombier em->ufp->fpscr = 0; /* TO DO */
813*d6dfd9efSDavid du Colombier for(n = 0; n < nelem(fpreginit); n++)
814*d6dfd9efSDavid du Colombier FR(31-n) = fpreginit[n];
815*d6dfd9efSDavid du Colombier }
816*d6dfd9efSDavid du Colombier for(n=0;;n++){
817*d6dfd9efSDavid du Colombier validaddr(ur->pc, 4, 0);
818*d6dfd9efSDavid du Colombier op = getulong(ur->pc);
819*d6dfd9efSDavid du Colombier em->ir = op;
820*d6dfd9efSDavid du Colombier if(fpemudebug > 1)
821*d6dfd9efSDavid du Colombier print("%8.8lux %8.8lux: ", ur->pc, op);
822*d6dfd9efSDavid du Colombier switch(op>>26){
823*d6dfd9efSDavid du Colombier default:
824*d6dfd9efSDavid du Colombier return n;
825*d6dfd9efSDavid du Colombier case 48: /* lfs */
826*d6dfd9efSDavid du Colombier case 49: /* lfsu */
827*d6dfd9efSDavid du Colombier lfs(em, op);
828*d6dfd9efSDavid du Colombier break;
829*d6dfd9efSDavid du Colombier case 50: /* lfd */
830*d6dfd9efSDavid du Colombier case 51: /* lfdu */
831*d6dfd9efSDavid du Colombier lfd(em, op);
832*d6dfd9efSDavid du Colombier break;
833*d6dfd9efSDavid du Colombier case 52: /* stfs */
834*d6dfd9efSDavid du Colombier case 53: /* stfsu */
835*d6dfd9efSDavid du Colombier stfs(em, op);
836*d6dfd9efSDavid du Colombier break;
837*d6dfd9efSDavid du Colombier case 54: /* stfd */
838*d6dfd9efSDavid du Colombier case 55: /* stfdu */
839*d6dfd9efSDavid du Colombier stfd(em, op);
840*d6dfd9efSDavid du Colombier break;
841*d6dfd9efSDavid du Colombier case 31: /* indexed load/store */
842*d6dfd9efSDavid du Colombier xo = getxo(op);
843*d6dfd9efSDavid du Colombier if((xo & 0x300) != 0x200)
844*d6dfd9efSDavid du Colombier return n;
845*d6dfd9efSDavid du Colombier switch(xo){
846*d6dfd9efSDavid du Colombier default:
847*d6dfd9efSDavid du Colombier return n;
848*d6dfd9efSDavid du Colombier case 535: /* lfsx */
849*d6dfd9efSDavid du Colombier case 567: /* lfsux */
850*d6dfd9efSDavid du Colombier lfsx(em, op);
851*d6dfd9efSDavid du Colombier break;
852*d6dfd9efSDavid du Colombier case 599: /* lfdx */
853*d6dfd9efSDavid du Colombier case 631: /* lfdux */
854*d6dfd9efSDavid du Colombier lfdx(em, op);
855*d6dfd9efSDavid du Colombier break;
856*d6dfd9efSDavid du Colombier case 663: /* stfsx */
857*d6dfd9efSDavid du Colombier case 695: /* stfsux */
858*d6dfd9efSDavid du Colombier stfsx(em, op);
859*d6dfd9efSDavid du Colombier break;
860*d6dfd9efSDavid du Colombier case 727: /* stfdx */
861*d6dfd9efSDavid du Colombier case 759: /* stfdux */
862*d6dfd9efSDavid du Colombier stfdx(em, op);
863*d6dfd9efSDavid du Colombier break;
864*d6dfd9efSDavid du Colombier }
865*d6dfd9efSDavid du Colombier break;
866*d6dfd9efSDavid du Colombier case 63: /* double precision */
867*d6dfd9efSDavid du Colombier xo = getxo(op);
868*d6dfd9efSDavid du Colombier if(op63flag[xo & 0x1F]){
869*d6dfd9efSDavid du Colombier farith(em, op);
870*d6dfd9efSDavid du Colombier break;
871*d6dfd9efSDavid du Colombier }
872*d6dfd9efSDavid du Colombier switch(xo){
873*d6dfd9efSDavid du Colombier default:
874*d6dfd9efSDavid du Colombier return n;
875*d6dfd9efSDavid du Colombier case 0: /* fcmpu */
876*d6dfd9efSDavid du Colombier case 32: /* fcmpo */
877*d6dfd9efSDavid du Colombier fcmp(em, op);
878*d6dfd9efSDavid du Colombier break;
879*d6dfd9efSDavid du Colombier case 40: /* fneg */
880*d6dfd9efSDavid du Colombier case 72: /* fmr */
881*d6dfd9efSDavid du Colombier case 136: /* fnabs */
882*d6dfd9efSDavid du Colombier case 264: /* fabs */
883*d6dfd9efSDavid du Colombier farith2(em, op);
884*d6dfd9efSDavid du Colombier break;
885*d6dfd9efSDavid du Colombier case 38:
886*d6dfd9efSDavid du Colombier mtfsb1(em, op);
887*d6dfd9efSDavid du Colombier break;
888*d6dfd9efSDavid du Colombier case 64:
889*d6dfd9efSDavid du Colombier mcrfs(em, op);
890*d6dfd9efSDavid du Colombier break;
891*d6dfd9efSDavid du Colombier case 70:
892*d6dfd9efSDavid du Colombier mtfsb0(em, op);
893*d6dfd9efSDavid du Colombier break;
894*d6dfd9efSDavid du Colombier case 134:
895*d6dfd9efSDavid du Colombier mtfsfi(em, op);
896*d6dfd9efSDavid du Colombier break;
897*d6dfd9efSDavid du Colombier case 583:
898*d6dfd9efSDavid du Colombier mffs(em, op);
899*d6dfd9efSDavid du Colombier break;
900*d6dfd9efSDavid du Colombier case 711:
901*d6dfd9efSDavid du Colombier mtfsf(em, op);
902*d6dfd9efSDavid du Colombier break;
903*d6dfd9efSDavid du Colombier }
904*d6dfd9efSDavid du Colombier break;
905*d6dfd9efSDavid du Colombier case 59: /* single precision */
906*d6dfd9efSDavid du Colombier fariths(em, op);
907*d6dfd9efSDavid du Colombier break;
908*d6dfd9efSDavid du Colombier }
909*d6dfd9efSDavid du Colombier ur->pc += 4;
910*d6dfd9efSDavid du Colombier if(anyhigher())
911*d6dfd9efSDavid du Colombier sched();
912*d6dfd9efSDavid du Colombier }
913*d6dfd9efSDavid du Colombier }
914*d6dfd9efSDavid du Colombier
915*d6dfd9efSDavid du Colombier /*
916*d6dfd9efSDavid du Colombier 50: lfd frD,d(rA)
917*d6dfd9efSDavid du Colombier 51: lfdu frD,d(rA)
918*d6dfd9efSDavid du Colombier 31,631: lfdux frD,rA,rB
919*d6dfd9efSDavid du Colombier 31,599: lfdx frD,rA,rB
920*d6dfd9efSDavid du Colombier 48: lfs frD,d(rA)
921*d6dfd9efSDavid du Colombier 49: lfsu frD,d(rA)
922*d6dfd9efSDavid du Colombier 31,567: lfsux frD,rA,rB
923*d6dfd9efSDavid du Colombier 31,535: lfsx frD,rA,rB
924*d6dfd9efSDavid du Colombier
925*d6dfd9efSDavid du Colombier 54: stfd frS,d(rA)
926*d6dfd9efSDavid du Colombier 55: stfdu frS,d(rA)
927*d6dfd9efSDavid du Colombier 31,759: stfdux frS,rA,rB
928*d6dfd9efSDavid du Colombier 31,727: stfdx frS,rA,rB
929*d6dfd9efSDavid du Colombier 52: stfs frS,d(rA)
930*d6dfd9efSDavid du Colombier 53: stfsu frS,d(rA)
931*d6dfd9efSDavid du Colombier 31,695: stfsux frS,rA,rB
932*d6dfd9efSDavid du Colombier 31,663: stfsx frS,rA,rB
933*d6dfd9efSDavid du Colombier
934*d6dfd9efSDavid du Colombier 63,64: mcrfs crfD,crfS
935*d6dfd9efSDavid du Colombier 63,583: mffs[.] frD
936*d6dfd9efSDavid du Colombier 63,70: mtfsb0[.] crbD
937*d6dfd9efSDavid du Colombier 63,38: mtfsb1[.] crbD
938*d6dfd9efSDavid du Colombier 63,711: mtfsf[.] FM,frB
939*d6dfd9efSDavid du Colombier 63,134: mtfsfi[.] crfD,IMM
940*d6dfd9efSDavid du Colombier */
941*d6dfd9efSDavid du Colombier
942*d6dfd9efSDavid du Colombier /*
943*d6dfd9efSDavid du Colombier float to int:
944*d6dfd9efSDavid du Colombier FMOVD g+0(SB),F1
945*d6dfd9efSDavid du Colombier FCTIWZ F1,F4
946*d6dfd9efSDavid du Colombier FMOVD F4,.rathole+0(SB)
947*d6dfd9efSDavid du Colombier MOVW .rathole+4(SB),R7
948*d6dfd9efSDavid du Colombier MOVW R7,l+0(SB)
949*d6dfd9efSDavid du Colombier */
950*d6dfd9efSDavid du Colombier
951*d6dfd9efSDavid du Colombier /*
952*d6dfd9efSDavid du Colombier int to float:
953*d6dfd9efSDavid du Colombier MOVW $1127219200,R9
954*d6dfd9efSDavid du Colombier MOVW l+0(SB),R7
955*d6dfd9efSDavid du Colombier MOVW R9,.rathole+0(SB)
956*d6dfd9efSDavid du Colombier XOR $-2147483648,R7,R6
957*d6dfd9efSDavid du Colombier MOVW R6,.rathole+4(SB)
958*d6dfd9efSDavid du Colombier FMOVD .rathole+0(SB),F0
959*d6dfd9efSDavid du Colombier FSUB F27,F0
960*d6dfd9efSDavid du Colombier
961*d6dfd9efSDavid du Colombier unsigned to float:
962*d6dfd9efSDavid du Colombier MOVW ul+0(SB),R5
963*d6dfd9efSDavid du Colombier MOVW R9,.rathole+0(SB)
964*d6dfd9efSDavid du Colombier XOR $-2147483648,R5,R4
965*d6dfd9efSDavid du Colombier MOVW R4,.rathole+4(SB)
966*d6dfd9efSDavid du Colombier FMOVD .rathole+0(SB),F3
967*d6dfd9efSDavid du Colombier FSUB F27,F3
968*d6dfd9efSDavid du Colombier FCMPU F3,F28
969*d6dfd9efSDavid du Colombier BGE ,3(PC)
970*d6dfd9efSDavid du Colombier FMOVD $4.29496729600000000e+09,F2
971*d6dfd9efSDavid du Colombier FADD F2,F3
972*d6dfd9efSDavid du Colombier FMOVD F3,g+0(SB)
973*d6dfd9efSDavid du Colombier */
974