1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Main procedures for sparc FPU simulator. */
27
28 #include <sys/fpu/fpu_simulator.h>
29 #include <sys/fpu/globals.h>
30 #include <sys/fpu/fpusystm.h>
31 #include <sys/proc.h>
32 #include <sys/signal.h>
33 #include <sys/siginfo.h>
34 #include <sys/thread.h>
35 #include <sys/cpuvar.h>
36 #include <sys/cmn_err.h>
37 #include <sys/atomic.h>
38 #include <sys/privregs.h>
39 #include <sys/vis_simulator.h>
40
41 #define FPUINFO_KSTAT(opcode) { \
42 extern void __dtrace_probe___fpuinfo_##opcode(uint64_t *); \
43 uint64_t *stataddr = &fpuinfo.opcode.value.ui64; \
44 __dtrace_probe___fpuinfo_##opcode(stataddr); \
45 atomic_inc_64(&fpuinfo.opcode.value.ui64); \
46 }
47
48 #define FPUINFO_KSTAT_PREC(prec, kstat_s, kstat_d, kstat_q) \
49 if (prec < 2) { \
50 FPUINFO_KSTAT(kstat_s); \
51 } else if (prec == 2) { \
52 FPUINFO_KSTAT(kstat_d); \
53 } else { \
54 FPUINFO_KSTAT(kstat_q); \
55 }
56
57 /*
58 * FPU simulator global kstat data
59 */
60 struct fpuinfo_kstat fpuinfo = {
61 { "fpu_sim_fmovs", KSTAT_DATA_UINT64},
62 { "fpu_sim_fmovd", KSTAT_DATA_UINT64},
63 { "fpu_sim_fmovq", KSTAT_DATA_UINT64},
64 { "fpu_sim_fnegs", KSTAT_DATA_UINT64},
65 { "fpu_sim_fnegd", KSTAT_DATA_UINT64},
66 { "fpu_sim_fnegq", KSTAT_DATA_UINT64},
67 { "fpu_sim_fabss", KSTAT_DATA_UINT64},
68 { "fpu_sim_fabsd", KSTAT_DATA_UINT64},
69 { "fpu_sim_fabsq", KSTAT_DATA_UINT64},
70 { "fpu_sim_fsqrts", KSTAT_DATA_UINT64},
71 { "fpu_sim_fsqrtd", KSTAT_DATA_UINT64},
72 { "fpu_sim_fsqrtq", KSTAT_DATA_UINT64},
73 { "fpu_sim_fadds", KSTAT_DATA_UINT64},
74 { "fpu_sim_faddd", KSTAT_DATA_UINT64},
75 { "fpu_sim_faddq", KSTAT_DATA_UINT64},
76 { "fpu_sim_fsubs", KSTAT_DATA_UINT64},
77 { "fpu_sim_fsubd", KSTAT_DATA_UINT64},
78 { "fpu_sim_fsubq", KSTAT_DATA_UINT64},
79 { "fpu_sim_fmuls", KSTAT_DATA_UINT64},
80 { "fpu_sim_fmuld", KSTAT_DATA_UINT64},
81 { "fpu_sim_fmulq", KSTAT_DATA_UINT64},
82 { "fpu_sim_fdivs", KSTAT_DATA_UINT64},
83 { "fpu_sim_fdivd", KSTAT_DATA_UINT64},
84 { "fpu_sim_fdivq", KSTAT_DATA_UINT64},
85 { "fpu_sim_fcmps", KSTAT_DATA_UINT64},
86 { "fpu_sim_fcmpd", KSTAT_DATA_UINT64},
87 { "fpu_sim_fcmpq", KSTAT_DATA_UINT64},
88 { "fpu_sim_fcmpes", KSTAT_DATA_UINT64},
89 { "fpu_sim_fcmped", KSTAT_DATA_UINT64},
90 { "fpu_sim_fcmpeq", KSTAT_DATA_UINT64},
91 { "fpu_sim_fsmuld", KSTAT_DATA_UINT64},
92 { "fpu_sim_fdmulx", KSTAT_DATA_UINT64},
93 { "fpu_sim_fstox", KSTAT_DATA_UINT64},
94 { "fpu_sim_fdtox", KSTAT_DATA_UINT64},
95 { "fpu_sim_fqtox", KSTAT_DATA_UINT64},
96 { "fpu_sim_fxtos", KSTAT_DATA_UINT64},
97 { "fpu_sim_fxtod", KSTAT_DATA_UINT64},
98 { "fpu_sim_fxtoq", KSTAT_DATA_UINT64},
99 { "fpu_sim_fitos", KSTAT_DATA_UINT64},
100 { "fpu_sim_fitod", KSTAT_DATA_UINT64},
101 { "fpu_sim_fitoq", KSTAT_DATA_UINT64},
102 { "fpu_sim_fstoi", KSTAT_DATA_UINT64},
103 { "fpu_sim_fdtoi", KSTAT_DATA_UINT64},
104 { "fpu_sim_fqtoi", KSTAT_DATA_UINT64},
105 { "fpu_sim_fmovcc", KSTAT_DATA_UINT64},
106 { "fpu_sim_fmovr", KSTAT_DATA_UINT64},
107 { "fpu_sim_fmadds", KSTAT_DATA_UINT64},
108 { "fpu_sim_fmaddd", KSTAT_DATA_UINT64},
109 { "fpu_sim_fmsubs", KSTAT_DATA_UINT64},
110 { "fpu_sim_fmsubd", KSTAT_DATA_UINT64},
111 { "fpu_sim_fnmadds", KSTAT_DATA_UINT64},
112 { "fpu_sim_fnmaddd", KSTAT_DATA_UINT64},
113 { "fpu_sim_fnmsubs", KSTAT_DATA_UINT64},
114 { "fpu_sim_fnmsubd", KSTAT_DATA_UINT64},
115 { "fpu_sim_invalid", KSTAT_DATA_UINT64},
116 };
117
118 struct visinfo_kstat visinfo = {
119 { "vis_edge8", KSTAT_DATA_UINT64},
120 { "vis_edge8n", KSTAT_DATA_UINT64},
121 { "vis_edge8l", KSTAT_DATA_UINT64},
122 { "vis_edge8ln", KSTAT_DATA_UINT64},
123 { "vis_edge16", KSTAT_DATA_UINT64},
124 { "vis_edge16n", KSTAT_DATA_UINT64},
125 { "vis_edge16l", KSTAT_DATA_UINT64},
126 { "vis_edge16ln", KSTAT_DATA_UINT64},
127 { "vis_edge32", KSTAT_DATA_UINT64},
128 { "vis_edge32n", KSTAT_DATA_UINT64},
129 { "vis_edge32l", KSTAT_DATA_UINT64},
130 { "vis_edge32ln", KSTAT_DATA_UINT64},
131 { "vis_array8", KSTAT_DATA_UINT64},
132 { "vis_array16", KSTAT_DATA_UINT64},
133 { "vis_array32", KSTAT_DATA_UINT64},
134 { "vis_bmask", KSTAT_DATA_UINT64},
135 { "vis_fcmple16", KSTAT_DATA_UINT64},
136 { "vis_fcmpne16", KSTAT_DATA_UINT64},
137 { "vis_fcmpgt16", KSTAT_DATA_UINT64},
138 { "vis_fcmpeq16", KSTAT_DATA_UINT64},
139 { "vis_fcmple32", KSTAT_DATA_UINT64},
140 { "vis_fcmpne32", KSTAT_DATA_UINT64},
141 { "vis_fcmpgt32", KSTAT_DATA_UINT64},
142 { "vis_fcmpeq32", KSTAT_DATA_UINT64},
143 { "vis_fmul8x16", KSTAT_DATA_UINT64},
144 { "vis_fmul8x16au", KSTAT_DATA_UINT64},
145 { "vis_fmul8x16al", KSTAT_DATA_UINT64},
146 { "vis_fmul8sux16", KSTAT_DATA_UINT64},
147 { "vis_fmul8ulx16", KSTAT_DATA_UINT64},
148 { "vis_fmuld8sux16", KSTAT_DATA_UINT64},
149 { "vis_fmuld8ulx16", KSTAT_DATA_UINT64},
150 { "vis_fpack16", KSTAT_DATA_UINT64},
151 { "vis_fpack32", KSTAT_DATA_UINT64},
152 { "vis_fpackfix", KSTAT_DATA_UINT64},
153 { "vis_fexpand", KSTAT_DATA_UINT64},
154 { "vis_fpmerge", KSTAT_DATA_UINT64},
155 { "vis_pdist", KSTAT_DATA_UINT64},
156 { "vis_pdistn", KSTAT_DATA_UINT64},
157 { "vis_bshuffle", KSTAT_DATA_UINT64},
158
159 };
160
161 /* PUBLIC FUNCTIONS */
162
163 int fp_notp = 1; /* fp checking not a problem */
164
165 /* ARGSUSED */
166 static enum ftt_type
_fp_fpu_simulator(fp_simd_type * pfpsd,fp_inst_type inst,fsr_type * pfsr,uint64_t gsr)167 _fp_fpu_simulator(
168 fp_simd_type *pfpsd, /* Pointer to fpu simulator data */
169 fp_inst_type inst, /* FPU instruction to simulate. */
170 fsr_type *pfsr, /* Pointer to image of FSR to read and write. */
171 uint64_t gsr) /* Image of GSR to read */
172 {
173 unpacked us1, us2, ud; /* Unpacked operands and result. */
174 uint32_t nrs1, nrs2, nrd; /* Register number fields. */
175 uint32_t usr, andexcep;
176 fsr_type fsr;
177 enum fcc_type cc;
178 uint32_t nfcc; /* fcc number field. */
179 uint64_t lusr;
180
181 nrs1 = inst.rs1;
182 nrs2 = inst.rs2;
183 nrd = inst.rd;
184 fsr = *pfsr;
185 pfpsd->fp_current_exceptions = 0; /* Init current exceptions. */
186 pfpsd->fp_fsrtem = fsr.tem; /* Obtain fsr's tem */
187 /*
188 * Obtain rounding direction and precision
189 */
190 pfpsd->fp_direction = GSR_IM(gsr) ? GSR_IRND(gsr) : fsr.rnd;
191 pfpsd->fp_precision = fsr.rnp;
192
193 if (inst.op3 == 0x37) { /* IMPDEP2B FMA-fused opcode */
194 fp_fma_inst_type *fma_inst;
195 uint32_t nrs3;
196 unpacked us3;
197 unpacked ust;
198 fma_inst = (fp_fma_inst_type *) &inst;
199 nrs2 = fma_inst->rs2;
200 nrs3 = fma_inst->rs3;
201 switch (fma_inst->var) {
202 case fmadd:
203 _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz);
204 _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz);
205 _fp_mul(pfpsd, &us1, &us2, &ust);
206 if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) {
207 _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz);
208 _fp_add(pfpsd, &ust, &us3, &ud);
209 _fp_pack(pfpsd, &ud, nrd, fma_inst->sz);
210 }
211 FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fmadds,
212 fpu_sim_fmaddd, fpu_sim_invalid);
213 break;
214 case fmsub:
215 _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz);
216 _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz);
217 _fp_mul(pfpsd, &us1, &us2, &ust);
218 if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) {
219 _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz);
220 _fp_sub(pfpsd, &ust, &us3, &ud);
221 _fp_pack(pfpsd, &ud, nrd, fma_inst->sz);
222 }
223 FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fmsubs,
224 fpu_sim_fmsubd, fpu_sim_invalid);
225 break;
226 case fnmadd:
227 _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz);
228 _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz);
229 _fp_mul(pfpsd, &us1, &us2, &ust);
230 if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) {
231 _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz);
232 if (ust.fpclass != fp_quiet &&
233 ust.fpclass != fp_signaling)
234 ust.sign ^= 1;
235 _fp_sub(pfpsd, &ust, &us3, &ud);
236 _fp_pack(pfpsd, &ud, nrd, fma_inst->sz);
237 }
238 FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fnmadds,
239 fpu_sim_fnmaddd, fpu_sim_invalid);
240 break;
241 case fnmsub:
242 _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz);
243 _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz);
244 _fp_mul(pfpsd, &us1, &us2, &ust);
245 if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) {
246 _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz);
247 if (ust.fpclass != fp_quiet &&
248 ust.fpclass != fp_signaling)
249 ust.sign ^= 1;
250 _fp_add(pfpsd, &ust, &us3, &ud);
251 _fp_pack(pfpsd, &ud, nrd, fma_inst->sz);
252 }
253 FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fnmsubs,
254 fpu_sim_fnmsubd, fpu_sim_invalid);
255 }
256 } else {
257 nfcc = nrd & 0x3;
258 if (inst.op3 == 0x35) { /* fpop2 */
259 fsr.cexc = 0;
260 *pfsr = fsr;
261 if ((inst.opcode & 0xf) == 0) {
262 if ((fp_notp) && (inst.prec == 0))
263 return (ftt_unimplemented);
264 FPUINFO_KSTAT(fpu_sim_fmovcc);
265 return (fmovcc(pfpsd, inst, pfsr)); /* fmovcc */
266 } else if ((inst.opcode & 0x7) == 1) {
267 if ((fp_notp) && (inst.prec == 0))
268 return (ftt_unimplemented);
269 FPUINFO_KSTAT(fpu_sim_fmovr);
270 return (fmovr(pfpsd, inst)); /* fmovr */
271 }
272 }
273 /* ibit not valid for fpop1 instructions */
274 if ((fp_notp) && (inst.ibit != 0))
275 return (ftt_unimplemented);
276 if ((fp_notp) && (inst.prec == 0)) { /* fxto[sdq], fito[sdq] */
277 if ((inst.opcode != flltos) &&
278 (inst.opcode != flltod) &&
279 (inst.opcode != flltox) &&
280 (inst.opcode != fitos) &&
281 (inst.opcode != fitod) &&
282 (inst.opcode != fitox)) {
283 return (ftt_unimplemented);
284 }
285 }
286 switch (inst.opcode) {
287 case fmovs: /* also covers fmovd, fmovq */
288 if (inst.prec < 2) { /* fmovs */
289 _fp_unpack_word(pfpsd, &usr, nrs2);
290 _fp_pack_word(pfpsd, &usr, nrd);
291 FPUINFO_KSTAT(fpu_sim_fmovs);
292 } else { /* fmovd */
293 _fp_unpack_extword(pfpsd, &lusr, nrs2);
294 _fp_pack_extword(pfpsd, &lusr, nrd);
295 if (inst.prec > 2) { /* fmovq */
296 _fp_unpack_extword(pfpsd, &lusr,
297 nrs2+2);
298 _fp_pack_extword(pfpsd, &lusr, nrd+2);
299 FPUINFO_KSTAT(fpu_sim_fmovq);
300 } else {
301 FPUINFO_KSTAT(fpu_sim_fmovd);
302 }
303 }
304 break;
305 case fabss: /* also covers fabsd, fabsq */
306 if (inst.prec < 2) { /* fabss */
307 _fp_unpack_word(pfpsd, &usr, nrs2);
308 usr &= 0x7fffffff;
309 _fp_pack_word(pfpsd, &usr, nrd);
310 FPUINFO_KSTAT(fpu_sim_fabss);
311 } else { /* fabsd */
312 _fp_unpack_extword(pfpsd, &lusr, nrs2);
313 lusr &= 0x7fffffffffffffff;
314 _fp_pack_extword(pfpsd, &lusr, nrd);
315 if (inst.prec > 2) { /* fabsq */
316 _fp_unpack_extword(pfpsd, &lusr,
317 nrs2+2);
318 _fp_pack_extword(pfpsd, &lusr, nrd+2);
319 FPUINFO_KSTAT(fpu_sim_fabsq);
320 } else {
321 FPUINFO_KSTAT(fpu_sim_fabsd);
322 }
323 }
324 break;
325 case fnegs: /* also covers fnegd, fnegq */
326 if (inst.prec < 2) { /* fnegs */
327 _fp_unpack_word(pfpsd, &usr, nrs2);
328 usr ^= 0x80000000;
329 _fp_pack_word(pfpsd, &usr, nrd);
330 FPUINFO_KSTAT(fpu_sim_fnegs);
331 } else { /* fnegd */
332 _fp_unpack_extword(pfpsd, &lusr, nrs2);
333 lusr ^= 0x8000000000000000;
334 _fp_pack_extword(pfpsd, &lusr, nrd);
335 if (inst.prec > 2) { /* fnegq */
336 _fp_unpack_extword(pfpsd, &lusr,
337 nrs2+2);
338 lusr ^= 0x0000000000000000;
339 _fp_pack_extword(pfpsd, &lusr, nrd+2);
340 FPUINFO_KSTAT(fpu_sim_fnegq);
341 } else {
342 FPUINFO_KSTAT(fpu_sim_fnegd);
343 }
344 }
345 break;
346 case fadd:
347 _fp_unpack(pfpsd, &us1, nrs1, inst.prec);
348 _fp_unpack(pfpsd, &us2, nrs2, inst.prec);
349 _fp_add(pfpsd, &us1, &us2, &ud);
350 _fp_pack(pfpsd, &ud, nrd, inst.prec);
351 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fadds,
352 fpu_sim_faddd, fpu_sim_faddq);
353 break;
354 case fsub:
355 _fp_unpack(pfpsd, &us1, nrs1, inst.prec);
356 _fp_unpack(pfpsd, &us2, nrs2, inst.prec);
357 _fp_sub(pfpsd, &us1, &us2, &ud);
358 _fp_pack(pfpsd, &ud, nrd, inst.prec);
359 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsubs,
360 fpu_sim_fsubd, fpu_sim_fsubq);
361 break;
362 case fmul:
363 _fp_unpack(pfpsd, &us1, nrs1, inst.prec);
364 _fp_unpack(pfpsd, &us2, nrs2, inst.prec);
365 _fp_mul(pfpsd, &us1, &us2, &ud);
366 _fp_pack(pfpsd, &ud, nrd, inst.prec);
367 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fmuls,
368 fpu_sim_fmuld, fpu_sim_fmulq);
369 break;
370 case fsmuld:
371 if ((fp_notp) && (inst.prec != 1))
372 return (ftt_unimplemented);
373 _fp_unpack(pfpsd, &us1, nrs1, inst.prec);
374 _fp_unpack(pfpsd, &us2, nrs2, inst.prec);
375 _fp_mul(pfpsd, &us1, &us2, &ud);
376 _fp_pack(pfpsd, &ud, nrd,
377 (enum fp_op_type) ((int)inst.prec+1));
378 FPUINFO_KSTAT(fpu_sim_fsmuld);
379 break;
380 case fdmulx:
381 if ((fp_notp) && (inst.prec != 2))
382 return (ftt_unimplemented);
383 _fp_unpack(pfpsd, &us1, nrs1, inst.prec);
384 _fp_unpack(pfpsd, &us2, nrs2, inst.prec);
385 _fp_mul(pfpsd, &us1, &us2, &ud);
386 _fp_pack(pfpsd, &ud, nrd,
387 (enum fp_op_type) ((int)inst.prec+1));
388 FPUINFO_KSTAT(fpu_sim_fdmulx);
389 break;
390 case fdiv:
391 _fp_unpack(pfpsd, &us1, nrs1, inst.prec);
392 _fp_unpack(pfpsd, &us2, nrs2, inst.prec);
393 _fp_div(pfpsd, &us1, &us2, &ud);
394 _fp_pack(pfpsd, &ud, nrd, inst.prec);
395 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fdivs,
396 fpu_sim_fdivd, fpu_sim_fdivq);
397 break;
398 case fcmp:
399 _fp_unpack(pfpsd, &us1, nrs1, inst.prec);
400 _fp_unpack(pfpsd, &us2, nrs2, inst.prec);
401 cc = _fp_compare(pfpsd, &us1, &us2, 0);
402 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
403 switch (nfcc) {
404 case fcc_0:
405 fsr.fcc0 = cc;
406 break;
407 case fcc_1:
408 fsr.fcc1 = cc;
409 break;
410 case fcc_2:
411 fsr.fcc2 = cc;
412 break;
413 case fcc_3:
414 fsr.fcc3 = cc;
415 break;
416 }
417 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmps,
418 fpu_sim_fcmpd, fpu_sim_fcmpq);
419 break;
420 case fcmpe:
421 _fp_unpack(pfpsd, &us1, nrs1, inst.prec);
422 _fp_unpack(pfpsd, &us2, nrs2, inst.prec);
423 cc = _fp_compare(pfpsd, &us1, &us2, 1);
424 if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem))
425 switch (nfcc) {
426 case fcc_0:
427 fsr.fcc0 = cc;
428 break;
429 case fcc_1:
430 fsr.fcc1 = cc;
431 break;
432 case fcc_2:
433 fsr.fcc2 = cc;
434 break;
435 case fcc_3:
436 fsr.fcc3 = cc;
437 break;
438 }
439 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmpes,
440 fpu_sim_fcmped, fpu_sim_fcmpeq);
441 break;
442 case fsqrt:
443 _fp_unpack(pfpsd, &us1, nrs2, inst.prec);
444 _fp_sqrt(pfpsd, &us1, &ud);
445 _fp_pack(pfpsd, &ud, nrd, inst.prec);
446 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsqrts,
447 fpu_sim_fsqrtd, fpu_sim_fsqrtq);
448 break;
449 case ftoi:
450 _fp_unpack(pfpsd, &us1, nrs2, inst.prec);
451 pfpsd->fp_direction = fp_tozero;
452 /* Force rounding toward zero. */
453 _fp_pack(pfpsd, &us1, nrd, fp_op_int32);
454 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstoi,
455 fpu_sim_fdtoi, fpu_sim_fqtoi);
456 break;
457 case ftoll:
458 _fp_unpack(pfpsd, &us1, nrs2, inst.prec);
459 pfpsd->fp_direction = fp_tozero;
460 /* Force rounding toward zero. */
461 _fp_pack(pfpsd, &us1, nrd, fp_op_int64);
462 FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstox,
463 fpu_sim_fdtox, fpu_sim_fqtox);
464 break;
465 case flltos:
466 _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
467 _fp_pack(pfpsd, &us1, nrd, fp_op_single);
468 FPUINFO_KSTAT(fpu_sim_fxtos);
469 break;
470 case flltod:
471 _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
472 _fp_pack(pfpsd, &us1, nrd, fp_op_double);
473 FPUINFO_KSTAT(fpu_sim_fxtod);
474 break;
475 case flltox:
476 _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64);
477 _fp_pack(pfpsd, &us1, nrd, fp_op_extended);
478 FPUINFO_KSTAT(fpu_sim_fxtoq);
479 break;
480 case fitos:
481 _fp_unpack(pfpsd, &us1, nrs2, inst.prec);
482 _fp_pack(pfpsd, &us1, nrd, fp_op_single);
483 FPUINFO_KSTAT(fpu_sim_fitos);
484 break;
485 case fitod:
486 _fp_unpack(pfpsd, &us1, nrs2, inst.prec);
487 _fp_pack(pfpsd, &us1, nrd, fp_op_double);
488 FPUINFO_KSTAT(fpu_sim_fitod);
489 break;
490 case fitox:
491 _fp_unpack(pfpsd, &us1, nrs2, inst.prec);
492 _fp_pack(pfpsd, &us1, nrd, fp_op_extended);
493 FPUINFO_KSTAT(fpu_sim_fitoq);
494 break;
495 default:
496 return (ftt_unimplemented);
497 }
498 }
499 fsr.cexc = pfpsd->fp_current_exceptions;
500 andexcep = pfpsd->fp_current_exceptions & fsr.tem;
501 if (andexcep != 0) { /* Signal an IEEE SIGFPE here. */
502 if (andexcep & (1 << fp_invalid)) {
503 pfpsd->fp_trapcode = FPE_FLTINV;
504 fsr.cexc = FSR_CEXC_NV;
505 } else if (andexcep & (1 << fp_overflow)) {
506 pfpsd->fp_trapcode = FPE_FLTOVF;
507 fsr.cexc = FSR_CEXC_OF;
508 } else if (andexcep & (1 << fp_underflow)) {
509 pfpsd->fp_trapcode = FPE_FLTUND;
510 fsr.cexc = FSR_CEXC_UF;
511 } else if (andexcep & (1 << fp_division)) {
512 pfpsd->fp_trapcode = FPE_FLTDIV;
513 fsr.cexc = FSR_CEXC_DZ;
514 } else if (andexcep & (1 << fp_inexact)) {
515 pfpsd->fp_trapcode = FPE_FLTRES;
516 fsr.cexc = FSR_CEXC_NX;
517 } else {
518 pfpsd->fp_trapcode = 0;
519 }
520 *pfsr = fsr;
521 return (ftt_ieee);
522 } else { /* Just set accrued exception field. */
523 fsr.aexc |= pfpsd->fp_current_exceptions;
524 }
525 *pfsr = fsr;
526 return (ftt_none);
527 }
528
529 /*
530 * fpu_vis_sim simulates fpu and vis instructions;
531 * It can work with both real and pcb image registers.
532 */
533 enum ftt_type
fpu_vis_sim(fp_simd_type * pfpsd,fp_inst_type * pinst,struct regs * pregs,fsr_type * pfsr,uint64_t gsr,uint32_t inst)534 fpu_vis_sim(
535 fp_simd_type *pfpsd, /* Pointer to simulator data */
536 fp_inst_type *pinst, /* Address of FPU instruction to simulate */
537 struct regs *pregs, /* Pointer to PCB image of registers. */
538 fsr_type *pfsr, /* Pointer to image of FSR to read and write */
539 uint64_t gsr, /* Image of GSR to read */
540 uint32_t inst) /* The FPU instruction to simulate */
541 {
542 klwp_id_t lwp = ttolwp(curthread);
543 union {
544 uint32_t i;
545 fp_inst_type inst;
546 } fp;
547 kfpu_t *pfp = lwptofpu(lwp);
548 enum ftt_type ftt;
549
550 fp.i = inst;
551 pfpsd->fp_trapaddr = (caddr_t)pinst;
552 if (fpu_exists) {
553 pfpsd->fp_current_read_freg = _fp_read_pfreg;
554 pfpsd->fp_current_write_freg = _fp_write_pfreg;
555 pfpsd->fp_current_read_dreg = _fp_read_pdreg;
556 pfpsd->fp_current_write_dreg = _fp_write_pdreg;
557 pfpsd->fp_current_read_gsr = _fp_read_pgsr;
558 pfpsd->fp_current_write_gsr = _fp_write_pgsr;
559 } else {
560 pfpsd->fp_current_pfregs = pfp;
561 pfpsd->fp_current_read_freg = _fp_read_vfreg;
562 pfpsd->fp_current_write_freg = _fp_write_vfreg;
563 pfpsd->fp_current_read_dreg = _fp_read_vdreg;
564 pfpsd->fp_current_write_dreg = _fp_write_vdreg;
565 pfpsd->fp_current_read_gsr = get_gsr;
566 pfpsd->fp_current_write_gsr = set_gsr;
567 }
568
569 if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
570 ftt = vis_fpu_simulator(pfpsd, fp.inst,
571 pregs, (ulong_t *)pregs->r_sp, pfp);
572 return (ftt);
573 } else if ((fp.inst.hibits == 2) &&
574 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) ||
575 (fp.inst.op3 == 0x37))) {
576 ftt = _fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr);
577 if (ftt == ftt_none || ftt == ftt_ieee) {
578 pregs->r_pc = pregs->r_npc;
579 pregs->r_npc += 4;
580 }
581 return (ftt);
582 } else {
583 ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs,
584 (ulong_t *)pregs->r_sp, pfp);
585 return (ftt);
586 }
587 }
588
589 /*
590 * fpu_simulator simulates FPU instructions only;
591 * reads and writes FPU data registers directly.
592 */
593 enum ftt_type
fpu_simulator(fp_simd_type * pfpsd,fp_inst_type * pinst,fsr_type * pfsr,uint64_t gsr,uint32_t inst)594 fpu_simulator(
595 fp_simd_type *pfpsd, /* Pointer to simulator data */
596 fp_inst_type *pinst, /* Address of FPU instruction to simulate */
597 fsr_type *pfsr, /* Pointer to image of FSR to read and write */
598 uint64_t gsr, /* Image of GSR to read */
599 uint32_t inst) /* The FPU instruction to simulate */
600 {
601 union {
602 uint32_t i;
603 fp_inst_type inst;
604 } fp;
605
606 fp.i = inst;
607 pfpsd->fp_trapaddr = (caddr_t)pinst;
608 pfpsd->fp_current_read_freg = _fp_read_pfreg;
609 pfpsd->fp_current_write_freg = _fp_write_pfreg;
610 pfpsd->fp_current_read_dreg = _fp_read_pdreg;
611 pfpsd->fp_current_write_dreg = _fp_write_pdreg;
612 pfpsd->fp_current_read_gsr = _fp_read_pgsr;
613 pfpsd->fp_current_write_gsr = _fp_write_pgsr;
614 return (_fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr));
615 }
616
617 /*
618 * fp_emulator simulates FPU and CPU-FPU instructions; reads and writes FPU
619 * data registers from image in pfpu.
620 */
621 enum ftt_type
fp_emulator(fp_simd_type * pfpsd,fp_inst_type * pinst,struct regs * pregs,void * prw,kfpu_t * pfpu)622 fp_emulator(
623 fp_simd_type *pfpsd, /* Pointer to simulator data */
624 fp_inst_type *pinst, /* Pointer to FPU instruction to simulate. */
625 struct regs *pregs, /* Pointer to PCB image of registers. */
626 void *prw, /* Pointer to locals and ins. */
627 kfpu_t *pfpu) /* Pointer to FPU register block. */
628 {
629 klwp_id_t lwp = ttolwp(curthread);
630 union {
631 uint32_t i;
632 fp_inst_type inst;
633 } fp;
634 enum ftt_type ftt;
635 uint64_t gsr = get_gsr(pfpu);
636 kfpu_t *pfp = lwptofpu(lwp);
637 uint64_t tfsr;
638
639 tfsr = pfpu->fpu_fsr;
640 pfpsd->fp_current_pfregs = pfpu;
641 pfpsd->fp_current_read_freg = _fp_read_vfreg;
642 pfpsd->fp_current_write_freg = _fp_write_vfreg;
643 pfpsd->fp_current_read_dreg = _fp_read_vdreg;
644 pfpsd->fp_current_write_dreg = _fp_write_vdreg;
645 pfpsd->fp_current_read_gsr = get_gsr;
646 pfpsd->fp_current_write_gsr = set_gsr;
647 pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */
648 ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd);
649 if (ftt != ftt_none)
650 return (ftt);
651
652 if ((fp.inst.hibits == 2) &&
653 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) ||
654 (fp.inst.op3 == 0x37))) {
655 ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr);
656 /* Do not retry emulated instruction. */
657 pregs->r_pc = pregs->r_npc;
658 pregs->r_npc += 4;
659 pfpu->fpu_fsr = tfsr;
660 if (ftt != ftt_none) {
661 /*
662 * Simulation generated an exception of some kind,
663 * simulate the fp queue for a signal.
664 */
665 pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst;
666 pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i;
667 pfpu->fpu_qcnt = 1;
668 }
669 } else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
670 ftt = vis_fpu_simulator(pfpsd, fp.inst,
671 pregs, prw, pfp);
672 } else
673 ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu);
674
675 if (ftt != ftt_none)
676 return (ftt);
677
678 /*
679 * If we are single-stepping, don't emulate any more instructions.
680 */
681 if (lwp->lwp_pcb.pcb_step != STEP_NONE)
682 return (ftt);
683 again:
684 /*
685 * now read next instruction and see if it can be emulated
686 */
687 pinst = (fp_inst_type *)pregs->r_pc;
688 pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */
689 ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd);
690 if (ftt != ftt_none)
691 return (ftt);
692 if ((fp.inst.hibits == 2) && /* fpops */
693 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) ||
694 (fp.inst.op3 == 0x37))) {
695 ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr);
696 /* Do not retry emulated instruction. */
697 pfpu->fpu_fsr = tfsr;
698 pregs->r_pc = pregs->r_npc;
699 pregs->r_npc += 4;
700 if (ftt != ftt_none) {
701 /*
702 * Simulation generated an exception of some kind,
703 * simulate the fp queue for a signal.
704 */
705 pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst;
706 pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i;
707 pfpu->fpu_qcnt = 1;
708 }
709 } else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) {
710 ftt = vis_fpu_simulator(pfpsd, fp.inst,
711 pregs, prw, pfp);
712 } else if (
713 /* rd %gsr */
714 ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x28) &&
715 (fp.inst.rs1 == 0x13)) ||
716 /* wr %gsr */
717 ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x30) &&
718 (fp.inst.rd == 0x13)) ||
719 /* movcc */
720 ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x2c) &&
721 (((fp.i>>18) & 0x1) == 0)) ||
722 /* fbpcc */
723 ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 5)) ||
724 /* fldst */
725 ((fp.inst.hibits == 3) && ((fp.inst.op3 & 0x38) == 0x20)) ||
726 /* fbcc */
727 ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 6))) {
728 ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu);
729 } else
730 return (ftt);
731
732 if (ftt != ftt_none)
733 return (ftt);
734 else
735 goto again;
736 }
737
738 /*
739 * FPU simulator global kstat data
740 */
741 struct fpustat_kstat fpustat = {
742 { "fpu_ieee_traps", KSTAT_DATA_UINT64 },
743 { "fpu_unfinished_traps", KSTAT_DATA_UINT64 },
744 { "fpu_unimplemented", KSTAT_DATA_UINT64 },
745 };
746
747 kstat_t *fpu_kstat = NULL;
748 kstat_t *fpuinfo_kstat = NULL;
749 kstat_t *visinfo_kstat = NULL;
750
751 void
fp_kstat_init(void)752 fp_kstat_init(void)
753 {
754 const uint_t fpustat_ndata = sizeof (fpustat) / sizeof (kstat_named_t);
755 const uint_t fpuinfo_ndata = sizeof (fpuinfo) / sizeof (kstat_named_t);
756 const uint_t visinfo_ndata = sizeof (visinfo) /sizeof (kstat_named_t);
757
758 ASSERT(fpu_kstat == NULL);
759 if ((fpu_kstat = kstat_create("unix", 0, "fpu_traps", "misc",
760 KSTAT_TYPE_NAMED, fpustat_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
761 cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_traps failed",
762 CPU->cpu_id);
763 } else {
764 fpu_kstat->ks_data = (void *)&fpustat;
765 kstat_install(fpu_kstat);
766 }
767
768 ASSERT(fpuinfo_kstat == NULL);
769 if ((fpuinfo_kstat = kstat_create("unix", 0, "fpu_info", "misc",
770 KSTAT_TYPE_NAMED, fpuinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
771 cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_info failed",
772 CPU->cpu_id);
773 } else {
774 fpuinfo_kstat->ks_data = (void *)&fpuinfo;
775 kstat_install(fpuinfo_kstat);
776 }
777 ASSERT(visinfo_kstat == NULL);
778 if ((visinfo_kstat = kstat_create("unix", 0, "vis_info", "misc",
779 KSTAT_TYPE_NAMED, visinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) {
780 cmn_err(CE_WARN, "CPU%d: kstat_create for vis_info failed",
781 CPU->cpu_id);
782 } else {
783 visinfo_kstat->ks_data = (void *)&visinfo;
784 kstat_install(visinfo_kstat);
785 }
786 }
787
788 void
fp_kstat_update(enum ftt_type ftt)789 fp_kstat_update(enum ftt_type ftt)
790 {
791 ASSERT((ftt == ftt_ieee) || (ftt == ftt_unfinished) ||
792 (ftt == ftt_unimplemented));
793 if (ftt == ftt_ieee)
794 atomic_inc_64(&fpustat.fpu_ieee_traps.value.ui64);
795 else if (ftt == ftt_unfinished)
796 atomic_inc_64(&fpustat.fpu_unfinished_traps.value.ui64);
797 else if (ftt == ftt_unimplemented)
798 atomic_inc_64(&fpustat.fpu_unimplemented_traps.value.ui64);
799 }
800