17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 525cf1a30Sjl139090 * Common Development and Distribution License (the "License"). 625cf1a30Sjl139090 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 228159a906SSree Vemuri * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Main procedures for sparc FPU simulator. */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/fpu/fpu_simulator.h> 297c478bd9Sstevel@tonic-gate #include <sys/fpu/globals.h> 307c478bd9Sstevel@tonic-gate #include <sys/fpu/fpusystm.h> 317c478bd9Sstevel@tonic-gate #include <sys/proc.h> 327c478bd9Sstevel@tonic-gate #include <sys/signal.h> 337c478bd9Sstevel@tonic-gate #include <sys/siginfo.h> 347c478bd9Sstevel@tonic-gate #include <sys/thread.h> 357c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 377c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 38*bc0e9132SGordon Ross #include <sys/regset.h> 397c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 407c478bd9Sstevel@tonic-gate #include <sys/vis_simulator.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #define FPUINFO_KSTAT(opcode) { \ 437c478bd9Sstevel@tonic-gate extern void __dtrace_probe___fpuinfo_##opcode(uint64_t *); \ 447c478bd9Sstevel@tonic-gate uint64_t *stataddr = &fpuinfo.opcode.value.ui64; \ 457c478bd9Sstevel@tonic-gate __dtrace_probe___fpuinfo_##opcode(stataddr); \ 461a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&fpuinfo.opcode.value.ui64); \ 477c478bd9Sstevel@tonic-gate } 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate #define FPUINFO_KSTAT_PREC(prec, kstat_s, kstat_d, kstat_q) \ 507c478bd9Sstevel@tonic-gate if (prec < 2) { \ 517c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(kstat_s); \ 527c478bd9Sstevel@tonic-gate } else if (prec == 2) { \ 537c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(kstat_d); \ 547c478bd9Sstevel@tonic-gate } else { \ 557c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(kstat_q); \ 567c478bd9Sstevel@tonic-gate } 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * FPU simulator global kstat data 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate struct fpuinfo_kstat fpuinfo = { 627c478bd9Sstevel@tonic-gate { "fpu_sim_fmovs", KSTAT_DATA_UINT64}, 637c478bd9Sstevel@tonic-gate { "fpu_sim_fmovd", KSTAT_DATA_UINT64}, 647c478bd9Sstevel@tonic-gate { "fpu_sim_fmovq", KSTAT_DATA_UINT64}, 657c478bd9Sstevel@tonic-gate { "fpu_sim_fnegs", KSTAT_DATA_UINT64}, 667c478bd9Sstevel@tonic-gate { "fpu_sim_fnegd", KSTAT_DATA_UINT64}, 677c478bd9Sstevel@tonic-gate { "fpu_sim_fnegq", KSTAT_DATA_UINT64}, 687c478bd9Sstevel@tonic-gate { "fpu_sim_fabss", KSTAT_DATA_UINT64}, 697c478bd9Sstevel@tonic-gate { "fpu_sim_fabsd", KSTAT_DATA_UINT64}, 707c478bd9Sstevel@tonic-gate { "fpu_sim_fabsq", KSTAT_DATA_UINT64}, 717c478bd9Sstevel@tonic-gate { "fpu_sim_fsqrts", KSTAT_DATA_UINT64}, 727c478bd9Sstevel@tonic-gate { "fpu_sim_fsqrtd", KSTAT_DATA_UINT64}, 737c478bd9Sstevel@tonic-gate { "fpu_sim_fsqrtq", KSTAT_DATA_UINT64}, 747c478bd9Sstevel@tonic-gate { "fpu_sim_fadds", KSTAT_DATA_UINT64}, 757c478bd9Sstevel@tonic-gate { "fpu_sim_faddd", KSTAT_DATA_UINT64}, 767c478bd9Sstevel@tonic-gate { "fpu_sim_faddq", KSTAT_DATA_UINT64}, 777c478bd9Sstevel@tonic-gate { "fpu_sim_fsubs", KSTAT_DATA_UINT64}, 787c478bd9Sstevel@tonic-gate { "fpu_sim_fsubd", KSTAT_DATA_UINT64}, 797c478bd9Sstevel@tonic-gate { "fpu_sim_fsubq", KSTAT_DATA_UINT64}, 807c478bd9Sstevel@tonic-gate { "fpu_sim_fmuls", KSTAT_DATA_UINT64}, 817c478bd9Sstevel@tonic-gate { "fpu_sim_fmuld", KSTAT_DATA_UINT64}, 827c478bd9Sstevel@tonic-gate { "fpu_sim_fmulq", KSTAT_DATA_UINT64}, 837c478bd9Sstevel@tonic-gate { "fpu_sim_fdivs", KSTAT_DATA_UINT64}, 847c478bd9Sstevel@tonic-gate { "fpu_sim_fdivd", KSTAT_DATA_UINT64}, 857c478bd9Sstevel@tonic-gate { "fpu_sim_fdivq", KSTAT_DATA_UINT64}, 867c478bd9Sstevel@tonic-gate { "fpu_sim_fcmps", KSTAT_DATA_UINT64}, 877c478bd9Sstevel@tonic-gate { "fpu_sim_fcmpd", KSTAT_DATA_UINT64}, 887c478bd9Sstevel@tonic-gate { "fpu_sim_fcmpq", KSTAT_DATA_UINT64}, 897c478bd9Sstevel@tonic-gate { "fpu_sim_fcmpes", KSTAT_DATA_UINT64}, 907c478bd9Sstevel@tonic-gate { "fpu_sim_fcmped", KSTAT_DATA_UINT64}, 917c478bd9Sstevel@tonic-gate { "fpu_sim_fcmpeq", KSTAT_DATA_UINT64}, 927c478bd9Sstevel@tonic-gate { "fpu_sim_fsmuld", KSTAT_DATA_UINT64}, 937c478bd9Sstevel@tonic-gate { "fpu_sim_fdmulx", KSTAT_DATA_UINT64}, 947c478bd9Sstevel@tonic-gate { "fpu_sim_fstox", KSTAT_DATA_UINT64}, 957c478bd9Sstevel@tonic-gate { "fpu_sim_fdtox", KSTAT_DATA_UINT64}, 967c478bd9Sstevel@tonic-gate { "fpu_sim_fqtox", KSTAT_DATA_UINT64}, 977c478bd9Sstevel@tonic-gate { "fpu_sim_fxtos", KSTAT_DATA_UINT64}, 987c478bd9Sstevel@tonic-gate { "fpu_sim_fxtod", KSTAT_DATA_UINT64}, 997c478bd9Sstevel@tonic-gate { "fpu_sim_fxtoq", KSTAT_DATA_UINT64}, 1007c478bd9Sstevel@tonic-gate { "fpu_sim_fitos", KSTAT_DATA_UINT64}, 1017c478bd9Sstevel@tonic-gate { "fpu_sim_fitod", KSTAT_DATA_UINT64}, 1027c478bd9Sstevel@tonic-gate { "fpu_sim_fitoq", KSTAT_DATA_UINT64}, 1037c478bd9Sstevel@tonic-gate { "fpu_sim_fstoi", KSTAT_DATA_UINT64}, 1047c478bd9Sstevel@tonic-gate { "fpu_sim_fdtoi", KSTAT_DATA_UINT64}, 1057c478bd9Sstevel@tonic-gate { "fpu_sim_fqtoi", KSTAT_DATA_UINT64}, 1067c478bd9Sstevel@tonic-gate { "fpu_sim_fmovcc", KSTAT_DATA_UINT64}, 1077c478bd9Sstevel@tonic-gate { "fpu_sim_fmovr", KSTAT_DATA_UINT64}, 10825cf1a30Sjl139090 { "fpu_sim_fmadds", KSTAT_DATA_UINT64}, 10925cf1a30Sjl139090 { "fpu_sim_fmaddd", KSTAT_DATA_UINT64}, 11025cf1a30Sjl139090 { "fpu_sim_fmsubs", KSTAT_DATA_UINT64}, 11125cf1a30Sjl139090 { "fpu_sim_fmsubd", KSTAT_DATA_UINT64}, 11225cf1a30Sjl139090 { "fpu_sim_fnmadds", KSTAT_DATA_UINT64}, 11325cf1a30Sjl139090 { "fpu_sim_fnmaddd", KSTAT_DATA_UINT64}, 11425cf1a30Sjl139090 { "fpu_sim_fnmsubs", KSTAT_DATA_UINT64}, 11525cf1a30Sjl139090 { "fpu_sim_fnmsubd", KSTAT_DATA_UINT64}, 11625cf1a30Sjl139090 { "fpu_sim_invalid", KSTAT_DATA_UINT64}, 1177c478bd9Sstevel@tonic-gate }; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate struct visinfo_kstat visinfo = { 1207c478bd9Sstevel@tonic-gate { "vis_edge8", KSTAT_DATA_UINT64}, 1217c478bd9Sstevel@tonic-gate { "vis_edge8n", KSTAT_DATA_UINT64}, 1227c478bd9Sstevel@tonic-gate { "vis_edge8l", KSTAT_DATA_UINT64}, 1237c478bd9Sstevel@tonic-gate { "vis_edge8ln", KSTAT_DATA_UINT64}, 1247c478bd9Sstevel@tonic-gate { "vis_edge16", KSTAT_DATA_UINT64}, 1257c478bd9Sstevel@tonic-gate { "vis_edge16n", KSTAT_DATA_UINT64}, 1267c478bd9Sstevel@tonic-gate { "vis_edge16l", KSTAT_DATA_UINT64}, 1277c478bd9Sstevel@tonic-gate { "vis_edge16ln", KSTAT_DATA_UINT64}, 1287c478bd9Sstevel@tonic-gate { "vis_edge32", KSTAT_DATA_UINT64}, 1297c478bd9Sstevel@tonic-gate { "vis_edge32n", KSTAT_DATA_UINT64}, 1307c478bd9Sstevel@tonic-gate { "vis_edge32l", KSTAT_DATA_UINT64}, 1317c478bd9Sstevel@tonic-gate { "vis_edge32ln", KSTAT_DATA_UINT64}, 1327c478bd9Sstevel@tonic-gate { "vis_array8", KSTAT_DATA_UINT64}, 1337c478bd9Sstevel@tonic-gate { "vis_array16", KSTAT_DATA_UINT64}, 1347c478bd9Sstevel@tonic-gate { "vis_array32", KSTAT_DATA_UINT64}, 1357c478bd9Sstevel@tonic-gate { "vis_bmask", KSTAT_DATA_UINT64}, 1367c478bd9Sstevel@tonic-gate { "vis_fcmple16", KSTAT_DATA_UINT64}, 1377c478bd9Sstevel@tonic-gate { "vis_fcmpne16", KSTAT_DATA_UINT64}, 1387c478bd9Sstevel@tonic-gate { "vis_fcmpgt16", KSTAT_DATA_UINT64}, 1397c478bd9Sstevel@tonic-gate { "vis_fcmpeq16", KSTAT_DATA_UINT64}, 1407c478bd9Sstevel@tonic-gate { "vis_fcmple32", KSTAT_DATA_UINT64}, 1417c478bd9Sstevel@tonic-gate { "vis_fcmpne32", KSTAT_DATA_UINT64}, 1427c478bd9Sstevel@tonic-gate { "vis_fcmpgt32", KSTAT_DATA_UINT64}, 1437c478bd9Sstevel@tonic-gate { "vis_fcmpeq32", KSTAT_DATA_UINT64}, 1447c478bd9Sstevel@tonic-gate { "vis_fmul8x16", KSTAT_DATA_UINT64}, 1457c478bd9Sstevel@tonic-gate { "vis_fmul8x16au", KSTAT_DATA_UINT64}, 1467c478bd9Sstevel@tonic-gate { "vis_fmul8x16al", KSTAT_DATA_UINT64}, 1477c478bd9Sstevel@tonic-gate { "vis_fmul8sux16", KSTAT_DATA_UINT64}, 1487c478bd9Sstevel@tonic-gate { "vis_fmul8ulx16", KSTAT_DATA_UINT64}, 1497c478bd9Sstevel@tonic-gate { "vis_fmuld8sux16", KSTAT_DATA_UINT64}, 1507c478bd9Sstevel@tonic-gate { "vis_fmuld8ulx16", KSTAT_DATA_UINT64}, 1517c478bd9Sstevel@tonic-gate { "vis_fpack16", KSTAT_DATA_UINT64}, 1527c478bd9Sstevel@tonic-gate { "vis_fpack32", KSTAT_DATA_UINT64}, 1537c478bd9Sstevel@tonic-gate { "vis_fpackfix", KSTAT_DATA_UINT64}, 1547c478bd9Sstevel@tonic-gate { "vis_fexpand", KSTAT_DATA_UINT64}, 1557c478bd9Sstevel@tonic-gate { "vis_fpmerge", KSTAT_DATA_UINT64}, 1567c478bd9Sstevel@tonic-gate { "vis_pdist", KSTAT_DATA_UINT64}, 1578159a906SSree Vemuri { "vis_pdistn", KSTAT_DATA_UINT64}, 1587c478bd9Sstevel@tonic-gate { "vis_bshuffle", KSTAT_DATA_UINT64}, 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate }; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* PUBLIC FUNCTIONS */ 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate int fp_notp = 1; /* fp checking not a problem */ 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1677c478bd9Sstevel@tonic-gate static enum ftt_type 1687c478bd9Sstevel@tonic-gate _fp_fpu_simulator( 1697c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to fpu simulator data */ 1707c478bd9Sstevel@tonic-gate fp_inst_type inst, /* FPU instruction to simulate. */ 1717c478bd9Sstevel@tonic-gate fsr_type *pfsr, /* Pointer to image of FSR to read and write. */ 1727c478bd9Sstevel@tonic-gate uint64_t gsr) /* Image of GSR to read */ 1737c478bd9Sstevel@tonic-gate { 1747c478bd9Sstevel@tonic-gate unpacked us1, us2, ud; /* Unpacked operands and result. */ 1757c478bd9Sstevel@tonic-gate uint32_t nrs1, nrs2, nrd; /* Register number fields. */ 1767c478bd9Sstevel@tonic-gate uint32_t usr, andexcep; 1777c478bd9Sstevel@tonic-gate fsr_type fsr; 1787c478bd9Sstevel@tonic-gate enum fcc_type cc; 1797c478bd9Sstevel@tonic-gate uint32_t nfcc; /* fcc number field. */ 1807c478bd9Sstevel@tonic-gate uint64_t lusr; 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate nrs1 = inst.rs1; 1837c478bd9Sstevel@tonic-gate nrs2 = inst.rs2; 1847c478bd9Sstevel@tonic-gate nrd = inst.rd; 1857c478bd9Sstevel@tonic-gate fsr = *pfsr; 1867c478bd9Sstevel@tonic-gate pfpsd->fp_current_exceptions = 0; /* Init current exceptions. */ 1877c478bd9Sstevel@tonic-gate pfpsd->fp_fsrtem = fsr.tem; /* Obtain fsr's tem */ 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * Obtain rounding direction and precision 1907c478bd9Sstevel@tonic-gate */ 1917c478bd9Sstevel@tonic-gate pfpsd->fp_direction = GSR_IM(gsr) ? GSR_IRND(gsr) : fsr.rnd; 1927c478bd9Sstevel@tonic-gate pfpsd->fp_precision = fsr.rnp; 19325cf1a30Sjl139090 1949d0d62adSJason Beloro if (inst.op3 == 0x37) { /* IMPDEP2B FMA-fused opcode */ 19525cf1a30Sjl139090 fp_fma_inst_type *fma_inst; 19625cf1a30Sjl139090 uint32_t nrs3; 19725cf1a30Sjl139090 unpacked us3; 19825cf1a30Sjl139090 unpacked ust; 19925cf1a30Sjl139090 fma_inst = (fp_fma_inst_type *) &inst; 20025cf1a30Sjl139090 nrs2 = fma_inst->rs2; 20125cf1a30Sjl139090 nrs3 = fma_inst->rs3; 20225cf1a30Sjl139090 switch (fma_inst->var) { 20325cf1a30Sjl139090 case fmadd: 20425cf1a30Sjl139090 _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz); 20525cf1a30Sjl139090 _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz); 20625cf1a30Sjl139090 _fp_mul(pfpsd, &us1, &us2, &ust); 20725cf1a30Sjl139090 if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) { 20825cf1a30Sjl139090 _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz); 20925cf1a30Sjl139090 _fp_add(pfpsd, &ust, &us3, &ud); 21025cf1a30Sjl139090 _fp_pack(pfpsd, &ud, nrd, fma_inst->sz); 21125cf1a30Sjl139090 } 21225cf1a30Sjl139090 FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fmadds, 21325cf1a30Sjl139090 fpu_sim_fmaddd, fpu_sim_invalid); 21425cf1a30Sjl139090 break; 21525cf1a30Sjl139090 case fmsub: 21625cf1a30Sjl139090 _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz); 21725cf1a30Sjl139090 _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz); 21825cf1a30Sjl139090 _fp_mul(pfpsd, &us1, &us2, &ust); 21925cf1a30Sjl139090 if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) { 22025cf1a30Sjl139090 _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz); 22125cf1a30Sjl139090 _fp_sub(pfpsd, &ust, &us3, &ud); 22225cf1a30Sjl139090 _fp_pack(pfpsd, &ud, nrd, fma_inst->sz); 22325cf1a30Sjl139090 } 22425cf1a30Sjl139090 FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fmsubs, 22525cf1a30Sjl139090 fpu_sim_fmsubd, fpu_sim_invalid); 22625cf1a30Sjl139090 break; 22725cf1a30Sjl139090 case fnmadd: 22825cf1a30Sjl139090 _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz); 22925cf1a30Sjl139090 _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz); 23025cf1a30Sjl139090 _fp_mul(pfpsd, &us1, &us2, &ust); 23125cf1a30Sjl139090 if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) { 23225cf1a30Sjl139090 _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz); 233371c605bShyw if (ust.fpclass != fp_quiet && 234371c605bShyw ust.fpclass != fp_signaling) 235371c605bShyw ust.sign ^= 1; 236371c605bShyw _fp_sub(pfpsd, &ust, &us3, &ud); 23725cf1a30Sjl139090 _fp_pack(pfpsd, &ud, nrd, fma_inst->sz); 23825cf1a30Sjl139090 } 23925cf1a30Sjl139090 FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fnmadds, 24025cf1a30Sjl139090 fpu_sim_fnmaddd, fpu_sim_invalid); 24125cf1a30Sjl139090 break; 24225cf1a30Sjl139090 case fnmsub: 24325cf1a30Sjl139090 _fp_unpack(pfpsd, &us1, nrs1, fma_inst->sz); 24425cf1a30Sjl139090 _fp_unpack(pfpsd, &us2, nrs2, fma_inst->sz); 24525cf1a30Sjl139090 _fp_mul(pfpsd, &us1, &us2, &ust); 24625cf1a30Sjl139090 if ((pfpsd->fp_current_exceptions & fsr.tem) == 0) { 24725cf1a30Sjl139090 _fp_unpack(pfpsd, &us3, nrs3, fma_inst->sz); 248371c605bShyw if (ust.fpclass != fp_quiet && 249371c605bShyw ust.fpclass != fp_signaling) 250371c605bShyw ust.sign ^= 1; 251371c605bShyw _fp_add(pfpsd, &ust, &us3, &ud); 25225cf1a30Sjl139090 _fp_pack(pfpsd, &ud, nrd, fma_inst->sz); 25325cf1a30Sjl139090 } 25425cf1a30Sjl139090 FPUINFO_KSTAT_PREC(fma_inst->sz, fpu_sim_fnmsubs, 25525cf1a30Sjl139090 fpu_sim_fnmsubd, fpu_sim_invalid); 25625cf1a30Sjl139090 } 25725cf1a30Sjl139090 } else { 2587c478bd9Sstevel@tonic-gate nfcc = nrd & 0x3; 2597c478bd9Sstevel@tonic-gate if (inst.op3 == 0x35) { /* fpop2 */ 2607c478bd9Sstevel@tonic-gate fsr.cexc = 0; 2617c478bd9Sstevel@tonic-gate *pfsr = fsr; 2627c478bd9Sstevel@tonic-gate if ((inst.opcode & 0xf) == 0) { 2637c478bd9Sstevel@tonic-gate if ((fp_notp) && (inst.prec == 0)) 2647c478bd9Sstevel@tonic-gate return (ftt_unimplemented); 2657c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fmovcc); 2667c478bd9Sstevel@tonic-gate return (fmovcc(pfpsd, inst, pfsr)); /* fmovcc */ 2677c478bd9Sstevel@tonic-gate } else if ((inst.opcode & 0x7) == 1) { 2687c478bd9Sstevel@tonic-gate if ((fp_notp) && (inst.prec == 0)) 2697c478bd9Sstevel@tonic-gate return (ftt_unimplemented); 2707c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fmovr); 2717c478bd9Sstevel@tonic-gate return (fmovr(pfpsd, inst)); /* fmovr */ 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate /* ibit not valid for fpop1 instructions */ 2757c478bd9Sstevel@tonic-gate if ((fp_notp) && (inst.ibit != 0)) 2767c478bd9Sstevel@tonic-gate return (ftt_unimplemented); 2777c478bd9Sstevel@tonic-gate if ((fp_notp) && (inst.prec == 0)) { /* fxto[sdq], fito[sdq] */ 2787c478bd9Sstevel@tonic-gate if ((inst.opcode != flltos) && 2797c478bd9Sstevel@tonic-gate (inst.opcode != flltod) && 2807c478bd9Sstevel@tonic-gate (inst.opcode != flltox) && 2817c478bd9Sstevel@tonic-gate (inst.opcode != fitos) && 2827c478bd9Sstevel@tonic-gate (inst.opcode != fitod) && 2837c478bd9Sstevel@tonic-gate (inst.opcode != fitox)) { 2847c478bd9Sstevel@tonic-gate return (ftt_unimplemented); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate switch (inst.opcode) { 2887c478bd9Sstevel@tonic-gate case fmovs: /* also covers fmovd, fmovq */ 2897c478bd9Sstevel@tonic-gate if (inst.prec < 2) { /* fmovs */ 2907c478bd9Sstevel@tonic-gate _fp_unpack_word(pfpsd, &usr, nrs2); 2917c478bd9Sstevel@tonic-gate _fp_pack_word(pfpsd, &usr, nrd); 2927c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fmovs); 2937c478bd9Sstevel@tonic-gate } else { /* fmovd */ 2947c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2); 2957c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd); 2967c478bd9Sstevel@tonic-gate if (inst.prec > 2) { /* fmovq */ 2972f0fcb93SJason Beloro _fp_unpack_extword(pfpsd, &lusr, 2982f0fcb93SJason Beloro nrs2+2); 2997c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd+2); 3007c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fmovq); 3017c478bd9Sstevel@tonic-gate } else { 3027c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fmovd); 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate break; 3067c478bd9Sstevel@tonic-gate case fabss: /* also covers fabsd, fabsq */ 3077c478bd9Sstevel@tonic-gate if (inst.prec < 2) { /* fabss */ 3087c478bd9Sstevel@tonic-gate _fp_unpack_word(pfpsd, &usr, nrs2); 3097c478bd9Sstevel@tonic-gate usr &= 0x7fffffff; 3107c478bd9Sstevel@tonic-gate _fp_pack_word(pfpsd, &usr, nrd); 3117c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fabss); 3127c478bd9Sstevel@tonic-gate } else { /* fabsd */ 3137c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2); 3147c478bd9Sstevel@tonic-gate lusr &= 0x7fffffffffffffff; 3157c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd); 3167c478bd9Sstevel@tonic-gate if (inst.prec > 2) { /* fabsq */ 3172f0fcb93SJason Beloro _fp_unpack_extword(pfpsd, &lusr, 3182f0fcb93SJason Beloro nrs2+2); 3197c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd+2); 3207c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fabsq); 3217c478bd9Sstevel@tonic-gate } else { 3227c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fabsd); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate break; 3267c478bd9Sstevel@tonic-gate case fnegs: /* also covers fnegd, fnegq */ 3277c478bd9Sstevel@tonic-gate if (inst.prec < 2) { /* fnegs */ 3287c478bd9Sstevel@tonic-gate _fp_unpack_word(pfpsd, &usr, nrs2); 3297c478bd9Sstevel@tonic-gate usr ^= 0x80000000; 3307c478bd9Sstevel@tonic-gate _fp_pack_word(pfpsd, &usr, nrd); 3317c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fnegs); 3327c478bd9Sstevel@tonic-gate } else { /* fnegd */ 3337c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2); 3347c478bd9Sstevel@tonic-gate lusr ^= 0x8000000000000000; 3357c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd); 3367c478bd9Sstevel@tonic-gate if (inst.prec > 2) { /* fnegq */ 3372f0fcb93SJason Beloro _fp_unpack_extword(pfpsd, &lusr, 3382f0fcb93SJason Beloro nrs2+2); 3397c478bd9Sstevel@tonic-gate lusr ^= 0x0000000000000000; 3407c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd+2); 3417c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fnegq); 3427c478bd9Sstevel@tonic-gate } else { 3437c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fnegd); 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate break; 3477c478bd9Sstevel@tonic-gate case fadd: 3487c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 3497c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 3507c478bd9Sstevel@tonic-gate _fp_add(pfpsd, &us1, &us2, &ud); 3517c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &ud, nrd, inst.prec); 3527c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fadds, 3537c478bd9Sstevel@tonic-gate fpu_sim_faddd, fpu_sim_faddq); 3547c478bd9Sstevel@tonic-gate break; 3557c478bd9Sstevel@tonic-gate case fsub: 3567c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 3577c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 3587c478bd9Sstevel@tonic-gate _fp_sub(pfpsd, &us1, &us2, &ud); 3597c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &ud, nrd, inst.prec); 3607c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsubs, 3617c478bd9Sstevel@tonic-gate fpu_sim_fsubd, fpu_sim_fsubq); 3627c478bd9Sstevel@tonic-gate break; 3637c478bd9Sstevel@tonic-gate case fmul: 3647c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 3657c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 3667c478bd9Sstevel@tonic-gate _fp_mul(pfpsd, &us1, &us2, &ud); 3677c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &ud, nrd, inst.prec); 3687c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fmuls, 3697c478bd9Sstevel@tonic-gate fpu_sim_fmuld, fpu_sim_fmulq); 3707c478bd9Sstevel@tonic-gate break; 3717c478bd9Sstevel@tonic-gate case fsmuld: 3727c478bd9Sstevel@tonic-gate if ((fp_notp) && (inst.prec != 1)) 3737c478bd9Sstevel@tonic-gate return (ftt_unimplemented); 3747c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 3757c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 3767c478bd9Sstevel@tonic-gate _fp_mul(pfpsd, &us1, &us2, &ud); 37725cf1a30Sjl139090 _fp_pack(pfpsd, &ud, nrd, 37825cf1a30Sjl139090 (enum fp_op_type) ((int)inst.prec+1)); 3797c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fsmuld); 3807c478bd9Sstevel@tonic-gate break; 3817c478bd9Sstevel@tonic-gate case fdmulx: 3827c478bd9Sstevel@tonic-gate if ((fp_notp) && (inst.prec != 2)) 3837c478bd9Sstevel@tonic-gate return (ftt_unimplemented); 3847c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 3857c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 3867c478bd9Sstevel@tonic-gate _fp_mul(pfpsd, &us1, &us2, &ud); 38725cf1a30Sjl139090 _fp_pack(pfpsd, &ud, nrd, 38825cf1a30Sjl139090 (enum fp_op_type) ((int)inst.prec+1)); 3897c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fdmulx); 3907c478bd9Sstevel@tonic-gate break; 3917c478bd9Sstevel@tonic-gate case fdiv: 3927c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 3937c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 3947c478bd9Sstevel@tonic-gate _fp_div(pfpsd, &us1, &us2, &ud); 3957c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &ud, nrd, inst.prec); 3967c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fdivs, 3977c478bd9Sstevel@tonic-gate fpu_sim_fdivd, fpu_sim_fdivq); 3987c478bd9Sstevel@tonic-gate break; 3997c478bd9Sstevel@tonic-gate case fcmp: 4007c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 4017c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 4027c478bd9Sstevel@tonic-gate cc = _fp_compare(pfpsd, &us1, &us2, 0); 4037c478bd9Sstevel@tonic-gate if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) 4047c478bd9Sstevel@tonic-gate switch (nfcc) { 4057c478bd9Sstevel@tonic-gate case fcc_0: 4067c478bd9Sstevel@tonic-gate fsr.fcc0 = cc; 4077c478bd9Sstevel@tonic-gate break; 4087c478bd9Sstevel@tonic-gate case fcc_1: 4097c478bd9Sstevel@tonic-gate fsr.fcc1 = cc; 4107c478bd9Sstevel@tonic-gate break; 4117c478bd9Sstevel@tonic-gate case fcc_2: 4127c478bd9Sstevel@tonic-gate fsr.fcc2 = cc; 4137c478bd9Sstevel@tonic-gate break; 4147c478bd9Sstevel@tonic-gate case fcc_3: 4157c478bd9Sstevel@tonic-gate fsr.fcc3 = cc; 4167c478bd9Sstevel@tonic-gate break; 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmps, 4197c478bd9Sstevel@tonic-gate fpu_sim_fcmpd, fpu_sim_fcmpq); 4207c478bd9Sstevel@tonic-gate break; 4217c478bd9Sstevel@tonic-gate case fcmpe: 4227c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs1, inst.prec); 4237c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us2, nrs2, inst.prec); 4247c478bd9Sstevel@tonic-gate cc = _fp_compare(pfpsd, &us1, &us2, 1); 4257c478bd9Sstevel@tonic-gate if (!(pfpsd->fp_current_exceptions & pfpsd->fp_fsrtem)) 4267c478bd9Sstevel@tonic-gate switch (nfcc) { 4277c478bd9Sstevel@tonic-gate case fcc_0: 4287c478bd9Sstevel@tonic-gate fsr.fcc0 = cc; 4297c478bd9Sstevel@tonic-gate break; 4307c478bd9Sstevel@tonic-gate case fcc_1: 4317c478bd9Sstevel@tonic-gate fsr.fcc1 = cc; 4327c478bd9Sstevel@tonic-gate break; 4337c478bd9Sstevel@tonic-gate case fcc_2: 4347c478bd9Sstevel@tonic-gate fsr.fcc2 = cc; 4357c478bd9Sstevel@tonic-gate break; 4367c478bd9Sstevel@tonic-gate case fcc_3: 4377c478bd9Sstevel@tonic-gate fsr.fcc3 = cc; 4387c478bd9Sstevel@tonic-gate break; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fcmpes, 4417c478bd9Sstevel@tonic-gate fpu_sim_fcmped, fpu_sim_fcmpeq); 4427c478bd9Sstevel@tonic-gate break; 4437c478bd9Sstevel@tonic-gate case fsqrt: 4447c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 4457c478bd9Sstevel@tonic-gate _fp_sqrt(pfpsd, &us1, &ud); 4467c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &ud, nrd, inst.prec); 4477c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fsqrts, 4487c478bd9Sstevel@tonic-gate fpu_sim_fsqrtd, fpu_sim_fsqrtq); 4497c478bd9Sstevel@tonic-gate break; 4507c478bd9Sstevel@tonic-gate case ftoi: 4517c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 4527c478bd9Sstevel@tonic-gate pfpsd->fp_direction = fp_tozero; 4537c478bd9Sstevel@tonic-gate /* Force rounding toward zero. */ 4547c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &us1, nrd, fp_op_int32); 4557c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstoi, 4567c478bd9Sstevel@tonic-gate fpu_sim_fdtoi, fpu_sim_fqtoi); 4577c478bd9Sstevel@tonic-gate break; 4587c478bd9Sstevel@tonic-gate case ftoll: 4597c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 4607c478bd9Sstevel@tonic-gate pfpsd->fp_direction = fp_tozero; 4617c478bd9Sstevel@tonic-gate /* Force rounding toward zero. */ 4627c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &us1, nrd, fp_op_int64); 4637c478bd9Sstevel@tonic-gate FPUINFO_KSTAT_PREC(inst.prec, fpu_sim_fstox, 4647c478bd9Sstevel@tonic-gate fpu_sim_fdtox, fpu_sim_fqtox); 4657c478bd9Sstevel@tonic-gate break; 4667c478bd9Sstevel@tonic-gate case flltos: 4677c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); 4687c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &us1, nrd, fp_op_single); 4697c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fxtos); 4707c478bd9Sstevel@tonic-gate break; 4717c478bd9Sstevel@tonic-gate case flltod: 4727c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); 4737c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &us1, nrd, fp_op_double); 4747c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fxtod); 4757c478bd9Sstevel@tonic-gate break; 4767c478bd9Sstevel@tonic-gate case flltox: 4777c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, fp_op_int64); 4787c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &us1, nrd, fp_op_extended); 4797c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fxtoq); 4807c478bd9Sstevel@tonic-gate break; 4817c478bd9Sstevel@tonic-gate case fitos: 4827c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 4837c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &us1, nrd, fp_op_single); 4847c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fitos); 4857c478bd9Sstevel@tonic-gate break; 4867c478bd9Sstevel@tonic-gate case fitod: 4877c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 4887c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &us1, nrd, fp_op_double); 4897c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fitod); 4907c478bd9Sstevel@tonic-gate break; 4917c478bd9Sstevel@tonic-gate case fitox: 4927c478bd9Sstevel@tonic-gate _fp_unpack(pfpsd, &us1, nrs2, inst.prec); 4937c478bd9Sstevel@tonic-gate _fp_pack(pfpsd, &us1, nrd, fp_op_extended); 4947c478bd9Sstevel@tonic-gate FPUINFO_KSTAT(fpu_sim_fitoq); 4957c478bd9Sstevel@tonic-gate break; 4967c478bd9Sstevel@tonic-gate default: 4977c478bd9Sstevel@tonic-gate return (ftt_unimplemented); 4987c478bd9Sstevel@tonic-gate } 49925cf1a30Sjl139090 } 5007c478bd9Sstevel@tonic-gate fsr.cexc = pfpsd->fp_current_exceptions; 5017c478bd9Sstevel@tonic-gate andexcep = pfpsd->fp_current_exceptions & fsr.tem; 5027c478bd9Sstevel@tonic-gate if (andexcep != 0) { /* Signal an IEEE SIGFPE here. */ 5037c478bd9Sstevel@tonic-gate if (andexcep & (1 << fp_invalid)) { 5047c478bd9Sstevel@tonic-gate pfpsd->fp_trapcode = FPE_FLTINV; 5057c478bd9Sstevel@tonic-gate fsr.cexc = FSR_CEXC_NV; 5067c478bd9Sstevel@tonic-gate } else if (andexcep & (1 << fp_overflow)) { 5077c478bd9Sstevel@tonic-gate pfpsd->fp_trapcode = FPE_FLTOVF; 5087c478bd9Sstevel@tonic-gate fsr.cexc = FSR_CEXC_OF; 5097c478bd9Sstevel@tonic-gate } else if (andexcep & (1 << fp_underflow)) { 5107c478bd9Sstevel@tonic-gate pfpsd->fp_trapcode = FPE_FLTUND; 5117c478bd9Sstevel@tonic-gate fsr.cexc = FSR_CEXC_UF; 5127c478bd9Sstevel@tonic-gate } else if (andexcep & (1 << fp_division)) { 5137c478bd9Sstevel@tonic-gate pfpsd->fp_trapcode = FPE_FLTDIV; 5147c478bd9Sstevel@tonic-gate fsr.cexc = FSR_CEXC_DZ; 5157c478bd9Sstevel@tonic-gate } else if (andexcep & (1 << fp_inexact)) { 5167c478bd9Sstevel@tonic-gate pfpsd->fp_trapcode = FPE_FLTRES; 5177c478bd9Sstevel@tonic-gate fsr.cexc = FSR_CEXC_NX; 5187c478bd9Sstevel@tonic-gate } else { 5197c478bd9Sstevel@tonic-gate pfpsd->fp_trapcode = 0; 5207c478bd9Sstevel@tonic-gate } 5217c478bd9Sstevel@tonic-gate *pfsr = fsr; 5227c478bd9Sstevel@tonic-gate return (ftt_ieee); 5237c478bd9Sstevel@tonic-gate } else { /* Just set accrued exception field. */ 5249d0d62adSJason Beloro fsr.aexc |= pfpsd->fp_current_exceptions; 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate *pfsr = fsr; 5277c478bd9Sstevel@tonic-gate return (ftt_none); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate /* 5317c478bd9Sstevel@tonic-gate * fpu_vis_sim simulates fpu and vis instructions; 5327c478bd9Sstevel@tonic-gate * It can work with both real and pcb image registers. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate enum ftt_type 5357c478bd9Sstevel@tonic-gate fpu_vis_sim( 5367c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to simulator data */ 5377c478bd9Sstevel@tonic-gate fp_inst_type *pinst, /* Address of FPU instruction to simulate */ 5387c478bd9Sstevel@tonic-gate struct regs *pregs, /* Pointer to PCB image of registers. */ 5397c478bd9Sstevel@tonic-gate fsr_type *pfsr, /* Pointer to image of FSR to read and write */ 5407c478bd9Sstevel@tonic-gate uint64_t gsr, /* Image of GSR to read */ 5417c478bd9Sstevel@tonic-gate uint32_t inst) /* The FPU instruction to simulate */ 5427c478bd9Sstevel@tonic-gate { 5437c478bd9Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread); 5447c478bd9Sstevel@tonic-gate union { 5457c478bd9Sstevel@tonic-gate uint32_t i; 5467c478bd9Sstevel@tonic-gate fp_inst_type inst; 5477c478bd9Sstevel@tonic-gate } fp; 5487c478bd9Sstevel@tonic-gate kfpu_t *pfp = lwptofpu(lwp); 5497c478bd9Sstevel@tonic-gate enum ftt_type ftt; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate fp.i = inst; 5527c478bd9Sstevel@tonic-gate pfpsd->fp_trapaddr = (caddr_t)pinst; 5537c478bd9Sstevel@tonic-gate if (fpu_exists) { 5547c478bd9Sstevel@tonic-gate pfpsd->fp_current_read_freg = _fp_read_pfreg; 5557c478bd9Sstevel@tonic-gate pfpsd->fp_current_write_freg = _fp_write_pfreg; 5567c478bd9Sstevel@tonic-gate pfpsd->fp_current_read_dreg = _fp_read_pdreg; 5577c478bd9Sstevel@tonic-gate pfpsd->fp_current_write_dreg = _fp_write_pdreg; 5585892374fSdf157793 pfpsd->fp_current_read_gsr = _fp_read_pgsr; 5595892374fSdf157793 pfpsd->fp_current_write_gsr = _fp_write_pgsr; 5607c478bd9Sstevel@tonic-gate } else { 5617c478bd9Sstevel@tonic-gate pfpsd->fp_current_pfregs = pfp; 5627c478bd9Sstevel@tonic-gate pfpsd->fp_current_read_freg = _fp_read_vfreg; 5637c478bd9Sstevel@tonic-gate pfpsd->fp_current_write_freg = _fp_write_vfreg; 5647c478bd9Sstevel@tonic-gate pfpsd->fp_current_read_dreg = _fp_read_vdreg; 5657c478bd9Sstevel@tonic-gate pfpsd->fp_current_write_dreg = _fp_write_vdreg; 5665892374fSdf157793 pfpsd->fp_current_read_gsr = get_gsr; 5675892374fSdf157793 pfpsd->fp_current_write_gsr = set_gsr; 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) { 5717c478bd9Sstevel@tonic-gate ftt = vis_fpu_simulator(pfpsd, fp.inst, 5727c478bd9Sstevel@tonic-gate pregs, (ulong_t *)pregs->r_sp, pfp); 5737c478bd9Sstevel@tonic-gate return (ftt); 5747c478bd9Sstevel@tonic-gate } else if ((fp.inst.hibits == 2) && 57525cf1a30Sjl139090 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) || 5769d0d62adSJason Beloro (fp.inst.op3 == 0x37))) { 5777c478bd9Sstevel@tonic-gate ftt = _fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr); 5787c478bd9Sstevel@tonic-gate if (ftt == ftt_none || ftt == ftt_ieee) { 5797c478bd9Sstevel@tonic-gate pregs->r_pc = pregs->r_npc; 5807c478bd9Sstevel@tonic-gate pregs->r_npc += 4; 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate return (ftt); 5837c478bd9Sstevel@tonic-gate } else { 5847c478bd9Sstevel@tonic-gate ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, 5857c478bd9Sstevel@tonic-gate (ulong_t *)pregs->r_sp, pfp); 5867c478bd9Sstevel@tonic-gate return (ftt); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * fpu_simulator simulates FPU instructions only; 5927c478bd9Sstevel@tonic-gate * reads and writes FPU data registers directly. 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate enum ftt_type 5957c478bd9Sstevel@tonic-gate fpu_simulator( 5967c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to simulator data */ 5977c478bd9Sstevel@tonic-gate fp_inst_type *pinst, /* Address of FPU instruction to simulate */ 5987c478bd9Sstevel@tonic-gate fsr_type *pfsr, /* Pointer to image of FSR to read and write */ 5997c478bd9Sstevel@tonic-gate uint64_t gsr, /* Image of GSR to read */ 6007c478bd9Sstevel@tonic-gate uint32_t inst) /* The FPU instruction to simulate */ 6017c478bd9Sstevel@tonic-gate { 6027c478bd9Sstevel@tonic-gate union { 6037c478bd9Sstevel@tonic-gate uint32_t i; 6047c478bd9Sstevel@tonic-gate fp_inst_type inst; 6057c478bd9Sstevel@tonic-gate } fp; 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate fp.i = inst; 6087c478bd9Sstevel@tonic-gate pfpsd->fp_trapaddr = (caddr_t)pinst; 6097c478bd9Sstevel@tonic-gate pfpsd->fp_current_read_freg = _fp_read_pfreg; 6107c478bd9Sstevel@tonic-gate pfpsd->fp_current_write_freg = _fp_write_pfreg; 6117c478bd9Sstevel@tonic-gate pfpsd->fp_current_read_dreg = _fp_read_pdreg; 6127c478bd9Sstevel@tonic-gate pfpsd->fp_current_write_dreg = _fp_write_pdreg; 6135892374fSdf157793 pfpsd->fp_current_read_gsr = _fp_read_pgsr; 6145892374fSdf157793 pfpsd->fp_current_write_gsr = _fp_write_pgsr; 6157c478bd9Sstevel@tonic-gate return (_fp_fpu_simulator(pfpsd, fp.inst, pfsr, gsr)); 6167c478bd9Sstevel@tonic-gate } 6177c478bd9Sstevel@tonic-gate 6187c478bd9Sstevel@tonic-gate /* 6197c478bd9Sstevel@tonic-gate * fp_emulator simulates FPU and CPU-FPU instructions; reads and writes FPU 6207c478bd9Sstevel@tonic-gate * data registers from image in pfpu. 6217c478bd9Sstevel@tonic-gate */ 6227c478bd9Sstevel@tonic-gate enum ftt_type 6237c478bd9Sstevel@tonic-gate fp_emulator( 6247c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to simulator data */ 6257c478bd9Sstevel@tonic-gate fp_inst_type *pinst, /* Pointer to FPU instruction to simulate. */ 6267c478bd9Sstevel@tonic-gate struct regs *pregs, /* Pointer to PCB image of registers. */ 6277c478bd9Sstevel@tonic-gate void *prw, /* Pointer to locals and ins. */ 6287c478bd9Sstevel@tonic-gate kfpu_t *pfpu) /* Pointer to FPU register block. */ 6297c478bd9Sstevel@tonic-gate { 6307c478bd9Sstevel@tonic-gate klwp_id_t lwp = ttolwp(curthread); 6317c478bd9Sstevel@tonic-gate union { 6327c478bd9Sstevel@tonic-gate uint32_t i; 6337c478bd9Sstevel@tonic-gate fp_inst_type inst; 6347c478bd9Sstevel@tonic-gate } fp; 6357c478bd9Sstevel@tonic-gate enum ftt_type ftt; 6367c478bd9Sstevel@tonic-gate uint64_t gsr = get_gsr(pfpu); 6377c478bd9Sstevel@tonic-gate kfpu_t *pfp = lwptofpu(lwp); 6387c478bd9Sstevel@tonic-gate uint64_t tfsr; 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate tfsr = pfpu->fpu_fsr; 6417c478bd9Sstevel@tonic-gate pfpsd->fp_current_pfregs = pfpu; 6427c478bd9Sstevel@tonic-gate pfpsd->fp_current_read_freg = _fp_read_vfreg; 6437c478bd9Sstevel@tonic-gate pfpsd->fp_current_write_freg = _fp_write_vfreg; 6447c478bd9Sstevel@tonic-gate pfpsd->fp_current_read_dreg = _fp_read_vdreg; 6457c478bd9Sstevel@tonic-gate pfpsd->fp_current_write_dreg = _fp_write_vdreg; 6465892374fSdf157793 pfpsd->fp_current_read_gsr = get_gsr; 6475892374fSdf157793 pfpsd->fp_current_write_gsr = set_gsr; 6487c478bd9Sstevel@tonic-gate pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */ 6497c478bd9Sstevel@tonic-gate ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd); 6507c478bd9Sstevel@tonic-gate if (ftt != ftt_none) 6517c478bd9Sstevel@tonic-gate return (ftt); 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate if ((fp.inst.hibits == 2) && 65425cf1a30Sjl139090 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) || 6559d0d62adSJason Beloro (fp.inst.op3 == 0x37))) { 6567c478bd9Sstevel@tonic-gate ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr); 6577c478bd9Sstevel@tonic-gate /* Do not retry emulated instruction. */ 6587c478bd9Sstevel@tonic-gate pregs->r_pc = pregs->r_npc; 6597c478bd9Sstevel@tonic-gate pregs->r_npc += 4; 6607c478bd9Sstevel@tonic-gate pfpu->fpu_fsr = tfsr; 6617c478bd9Sstevel@tonic-gate if (ftt != ftt_none) { 6627c478bd9Sstevel@tonic-gate /* 6637c478bd9Sstevel@tonic-gate * Simulation generated an exception of some kind, 6647c478bd9Sstevel@tonic-gate * simulate the fp queue for a signal. 6657c478bd9Sstevel@tonic-gate */ 6667c478bd9Sstevel@tonic-gate pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst; 6677c478bd9Sstevel@tonic-gate pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i; 6687c478bd9Sstevel@tonic-gate pfpu->fpu_qcnt = 1; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate } else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) { 6717c478bd9Sstevel@tonic-gate ftt = vis_fpu_simulator(pfpsd, fp.inst, 6727c478bd9Sstevel@tonic-gate pregs, prw, pfp); 6737c478bd9Sstevel@tonic-gate } else 6747c478bd9Sstevel@tonic-gate ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate if (ftt != ftt_none) 6777c478bd9Sstevel@tonic-gate return (ftt); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * If we are single-stepping, don't emulate any more instructions. 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate if (lwp->lwp_pcb.pcb_step != STEP_NONE) 6837c478bd9Sstevel@tonic-gate return (ftt); 6847c478bd9Sstevel@tonic-gate again: 6857c478bd9Sstevel@tonic-gate /* 6867c478bd9Sstevel@tonic-gate * now read next instruction and see if it can be emulated 6877c478bd9Sstevel@tonic-gate */ 6887c478bd9Sstevel@tonic-gate pinst = (fp_inst_type *)pregs->r_pc; 6897c478bd9Sstevel@tonic-gate pfpsd->fp_trapaddr = (caddr_t)pinst; /* bad inst addr in case we trap */ 6907c478bd9Sstevel@tonic-gate ftt = _fp_read_inst((uint32_t *)pinst, &(fp.i), pfpsd); 6917c478bd9Sstevel@tonic-gate if (ftt != ftt_none) 6927c478bd9Sstevel@tonic-gate return (ftt); 6937c478bd9Sstevel@tonic-gate if ((fp.inst.hibits == 2) && /* fpops */ 69425cf1a30Sjl139090 ((fp.inst.op3 == 0x34) || (fp.inst.op3 == 0x35) || 6959d0d62adSJason Beloro (fp.inst.op3 == 0x37))) { 6967c478bd9Sstevel@tonic-gate ftt = _fp_fpu_simulator(pfpsd, fp.inst, (fsr_type *)&tfsr, gsr); 6977c478bd9Sstevel@tonic-gate /* Do not retry emulated instruction. */ 6987c478bd9Sstevel@tonic-gate pfpu->fpu_fsr = tfsr; 6997c478bd9Sstevel@tonic-gate pregs->r_pc = pregs->r_npc; 7007c478bd9Sstevel@tonic-gate pregs->r_npc += 4; 7017c478bd9Sstevel@tonic-gate if (ftt != ftt_none) { 7027c478bd9Sstevel@tonic-gate /* 7037c478bd9Sstevel@tonic-gate * Simulation generated an exception of some kind, 7047c478bd9Sstevel@tonic-gate * simulate the fp queue for a signal. 7057c478bd9Sstevel@tonic-gate */ 7067c478bd9Sstevel@tonic-gate pfpu->fpu_q->FQu.fpq.fpq_addr = (uint32_t *)pinst; 7077c478bd9Sstevel@tonic-gate pfpu->fpu_q->FQu.fpq.fpq_instr = fp.i; 7087c478bd9Sstevel@tonic-gate pfpu->fpu_qcnt = 1; 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate } else if ((fp.inst.hibits == 2) && (fp.inst.op3 == 0x36)) { 7117c478bd9Sstevel@tonic-gate ftt = vis_fpu_simulator(pfpsd, fp.inst, 7127c478bd9Sstevel@tonic-gate pregs, prw, pfp); 7137c478bd9Sstevel@tonic-gate } else if ( 7147c478bd9Sstevel@tonic-gate /* rd %gsr */ 7157c478bd9Sstevel@tonic-gate ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x28) && 7167c478bd9Sstevel@tonic-gate (fp.inst.rs1 == 0x13)) || 7177c478bd9Sstevel@tonic-gate /* wr %gsr */ 7187c478bd9Sstevel@tonic-gate ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x30) && 7197c478bd9Sstevel@tonic-gate (fp.inst.rd == 0x13)) || 7207c478bd9Sstevel@tonic-gate /* movcc */ 7217c478bd9Sstevel@tonic-gate ((fp.inst.hibits == 2) && ((fp.inst.op3 & 0x3f) == 0x2c) && 7227c478bd9Sstevel@tonic-gate (((fp.i>>18) & 0x1) == 0)) || 7237c478bd9Sstevel@tonic-gate /* fbpcc */ 7247c478bd9Sstevel@tonic-gate ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 5)) || 7257c478bd9Sstevel@tonic-gate /* fldst */ 7267c478bd9Sstevel@tonic-gate ((fp.inst.hibits == 3) && ((fp.inst.op3 & 0x38) == 0x20)) || 7277c478bd9Sstevel@tonic-gate /* fbcc */ 7287c478bd9Sstevel@tonic-gate ((fp.inst.hibits == 0) && (((fp.i>>22) & 0x7) == 6))) { 7297c478bd9Sstevel@tonic-gate ftt = _fp_iu_simulator(pfpsd, fp.inst, pregs, prw, pfpu); 7307c478bd9Sstevel@tonic-gate } else 7317c478bd9Sstevel@tonic-gate return (ftt); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate if (ftt != ftt_none) 7347c478bd9Sstevel@tonic-gate return (ftt); 7357c478bd9Sstevel@tonic-gate else 7367c478bd9Sstevel@tonic-gate goto again; 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate /* 7407c478bd9Sstevel@tonic-gate * FPU simulator global kstat data 7417c478bd9Sstevel@tonic-gate */ 7427c478bd9Sstevel@tonic-gate struct fpustat_kstat fpustat = { 7437c478bd9Sstevel@tonic-gate { "fpu_ieee_traps", KSTAT_DATA_UINT64 }, 7447c478bd9Sstevel@tonic-gate { "fpu_unfinished_traps", KSTAT_DATA_UINT64 }, 7457c478bd9Sstevel@tonic-gate { "fpu_unimplemented", KSTAT_DATA_UINT64 }, 7467c478bd9Sstevel@tonic-gate }; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate kstat_t *fpu_kstat = NULL; 7497c478bd9Sstevel@tonic-gate kstat_t *fpuinfo_kstat = NULL; 7507c478bd9Sstevel@tonic-gate kstat_t *visinfo_kstat = NULL; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate void 7537c478bd9Sstevel@tonic-gate fp_kstat_init(void) 7547c478bd9Sstevel@tonic-gate { 7557c478bd9Sstevel@tonic-gate const uint_t fpustat_ndata = sizeof (fpustat) / sizeof (kstat_named_t); 7567c478bd9Sstevel@tonic-gate const uint_t fpuinfo_ndata = sizeof (fpuinfo) / sizeof (kstat_named_t); 7577c478bd9Sstevel@tonic-gate const uint_t visinfo_ndata = sizeof (visinfo) /sizeof (kstat_named_t); 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate ASSERT(fpu_kstat == NULL); 7607c478bd9Sstevel@tonic-gate if ((fpu_kstat = kstat_create("unix", 0, "fpu_traps", "misc", 7617c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, fpustat_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) { 7627c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_traps failed", 7637c478bd9Sstevel@tonic-gate CPU->cpu_id); 7647c478bd9Sstevel@tonic-gate } else { 7657c478bd9Sstevel@tonic-gate fpu_kstat->ks_data = (void *)&fpustat; 7667c478bd9Sstevel@tonic-gate kstat_install(fpu_kstat); 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate ASSERT(fpuinfo_kstat == NULL); 7707c478bd9Sstevel@tonic-gate if ((fpuinfo_kstat = kstat_create("unix", 0, "fpu_info", "misc", 7717c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, fpuinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) { 7727c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "CPU%d: kstat_create for fpu_info failed", 7737c478bd9Sstevel@tonic-gate CPU->cpu_id); 7747c478bd9Sstevel@tonic-gate } else { 7757c478bd9Sstevel@tonic-gate fpuinfo_kstat->ks_data = (void *)&fpuinfo; 7767c478bd9Sstevel@tonic-gate kstat_install(fpuinfo_kstat); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate ASSERT(visinfo_kstat == NULL); 7797c478bd9Sstevel@tonic-gate if ((visinfo_kstat = kstat_create("unix", 0, "vis_info", "misc", 7807c478bd9Sstevel@tonic-gate KSTAT_TYPE_NAMED, visinfo_ndata, KSTAT_FLAG_VIRTUAL)) == NULL) { 7817c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "CPU%d: kstat_create for vis_info failed", 7827c478bd9Sstevel@tonic-gate CPU->cpu_id); 7837c478bd9Sstevel@tonic-gate } else { 7847c478bd9Sstevel@tonic-gate visinfo_kstat->ks_data = (void *)&visinfo; 7857c478bd9Sstevel@tonic-gate kstat_install(visinfo_kstat); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate void 7907c478bd9Sstevel@tonic-gate fp_kstat_update(enum ftt_type ftt) 7917c478bd9Sstevel@tonic-gate { 7927c478bd9Sstevel@tonic-gate ASSERT((ftt == ftt_ieee) || (ftt == ftt_unfinished) || 7937c478bd9Sstevel@tonic-gate (ftt == ftt_unimplemented)); 7947c478bd9Sstevel@tonic-gate if (ftt == ftt_ieee) 7951a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&fpustat.fpu_ieee_traps.value.ui64); 7967c478bd9Sstevel@tonic-gate else if (ftt == ftt_unfinished) 7971a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&fpustat.fpu_unfinished_traps.value.ui64); 7987c478bd9Sstevel@tonic-gate else if (ftt == ftt_unimplemented) 7991a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&fpustat.fpu_unimplemented_traps.value.ui64); 8007c478bd9Sstevel@tonic-gate } 801