1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate /* Integer Unit simulator for Sparc FPU simulator. */
30*7c478bd9Sstevel@tonic-gate
31*7c478bd9Sstevel@tonic-gate #include <sys/fpu/fpu_simulator.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/fpu/globals.h>
33*7c478bd9Sstevel@tonic-gate
34*7c478bd9Sstevel@tonic-gate #include <sys/privregs.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/vis_simulator.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/asi.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/simulate.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/model.h>
39*7c478bd9Sstevel@tonic-gate
40*7c478bd9Sstevel@tonic-gate #define FPU_REG_FIELD uint32_reg /* Coordinate with FPU_REGS_TYPE. */
41*7c478bd9Sstevel@tonic-gate #define FPU_DREG_FIELD uint64_reg /* Coordinate with FPU_DREGS_TYPE. */
42*7c478bd9Sstevel@tonic-gate #define FPU_FSR_FIELD uint64_reg /* Coordinate with V9_FPU_FSR_TYPE. */
43*7c478bd9Sstevel@tonic-gate
44*7c478bd9Sstevel@tonic-gate /*
45*7c478bd9Sstevel@tonic-gate * Simulator for loads and stores between floating-point unit and memory.
46*7c478bd9Sstevel@tonic-gate */
47*7c478bd9Sstevel@tonic-gate enum ftt_type
fldst(fp_simd_type * pfpsd,fp_inst_type pinst,struct regs * pregs,void * prw)48*7c478bd9Sstevel@tonic-gate fldst(
49*7c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* FPU simulator data. */
50*7c478bd9Sstevel@tonic-gate fp_inst_type pinst, /* FPU instruction to simulate. */
51*7c478bd9Sstevel@tonic-gate struct regs *pregs, /* Pointer to PCB image of registers. */
52*7c478bd9Sstevel@tonic-gate void *prw) /* Pointer to locals and ins. */
53*7c478bd9Sstevel@tonic-gate {
54*7c478bd9Sstevel@tonic-gate uint32_t sz_bits, asi = 0;
55*7c478bd9Sstevel@tonic-gate uint64_t fea, tea;
56*7c478bd9Sstevel@tonic-gate uint64_t *ea;
57*7c478bd9Sstevel@tonic-gate enum ftt_type ftt;
58*7c478bd9Sstevel@tonic-gate char *badaddr = (caddr_t)(-1);
59*7c478bd9Sstevel@tonic-gate union {
60*7c478bd9Sstevel@tonic-gate fp_inst_type inst;
61*7c478bd9Sstevel@tonic-gate int32_t i;
62*7c478bd9Sstevel@tonic-gate } fp;
63*7c478bd9Sstevel@tonic-gate
64*7c478bd9Sstevel@tonic-gate fp.inst = pinst;
65*7c478bd9Sstevel@tonic-gate if ((pinst.op3 >> 4) & 1) {
66*7c478bd9Sstevel@tonic-gate if (pinst.ibit) {
67*7c478bd9Sstevel@tonic-gate asi = (uint32_t)((pregs->r_tstate >> TSTATE_ASI_SHIFT) &
68*7c478bd9Sstevel@tonic-gate TSTATE_ASI_MASK);
69*7c478bd9Sstevel@tonic-gate } else {
70*7c478bd9Sstevel@tonic-gate asi = (fp.i >> 5) & 0xff;
71*7c478bd9Sstevel@tonic-gate }
72*7c478bd9Sstevel@tonic-gate /* check for ld/st alternate and highest defined V9 asi */
73*7c478bd9Sstevel@tonic-gate if (((pinst.op3 & 0x30) == 0x30) && (asi > ASI_SNFL))
74*7c478bd9Sstevel@tonic-gate return (vis_fldst(pfpsd, pinst, pregs, prw, asi));
75*7c478bd9Sstevel@tonic-gate }
76*7c478bd9Sstevel@tonic-gate
77*7c478bd9Sstevel@tonic-gate if (pinst.ibit == 0) { /* effective address = rs1 + rs2 */
78*7c478bd9Sstevel@tonic-gate ftt = read_iureg(pfpsd, pinst.rs1, pregs, prw, &fea);
79*7c478bd9Sstevel@tonic-gate if (ftt != ftt_none)
80*7c478bd9Sstevel@tonic-gate return (ftt);
81*7c478bd9Sstevel@tonic-gate ftt = read_iureg(pfpsd, pinst.rs2, pregs, prw, &tea);
82*7c478bd9Sstevel@tonic-gate if (ftt != ftt_none)
83*7c478bd9Sstevel@tonic-gate return (ftt);
84*7c478bd9Sstevel@tonic-gate ea = (uint64_t *)(fea + tea);
85*7c478bd9Sstevel@tonic-gate } else { /* effective address = rs1 + imm13 */
86*7c478bd9Sstevel@tonic-gate /* Extract simm13 field. */
87*7c478bd9Sstevel@tonic-gate fea = (uint64_t)((fp.i << 19) >> 19);
88*7c478bd9Sstevel@tonic-gate ftt = read_iureg(pfpsd, pinst.rs1, pregs, prw, &tea);
89*7c478bd9Sstevel@tonic-gate if (ftt != ftt_none)
90*7c478bd9Sstevel@tonic-gate return (ftt);
91*7c478bd9Sstevel@tonic-gate ea = (uint64_t *)(fea + tea);
92*7c478bd9Sstevel@tonic-gate }
93*7c478bd9Sstevel@tonic-gate sz_bits = pinst.op3 & 0x3;
94*7c478bd9Sstevel@tonic-gate switch (sz_bits) { /* map size bits to a number */
95*7c478bd9Sstevel@tonic-gate case 0: /* ldf{a}/stf{a} */
96*7c478bd9Sstevel@tonic-gate /* Must be word-aligned. */
97*7c478bd9Sstevel@tonic-gate if (((uintptr_t)ea & 0x3) != 0)
98*7c478bd9Sstevel@tonic-gate return (ftt_alignment);
99*7c478bd9Sstevel@tonic-gate break;
100*7c478bd9Sstevel@tonic-gate case 1: if (pinst.rd == 0) { /* ldfsr/stfsr */
101*7c478bd9Sstevel@tonic-gate /* Must be word-aligned. */
102*7c478bd9Sstevel@tonic-gate if (((uintptr_t)ea & 0x3) != 0)
103*7c478bd9Sstevel@tonic-gate return (ftt_alignment);
104*7c478bd9Sstevel@tonic-gate } else { /* ldxfsr/stxfsr */
105*7c478bd9Sstevel@tonic-gate /* Must be extword-aligned. */
106*7c478bd9Sstevel@tonic-gate if (((uintptr_t)ea & 0x7) != 0)
107*7c478bd9Sstevel@tonic-gate return (ftt_alignment);
108*7c478bd9Sstevel@tonic-gate }
109*7c478bd9Sstevel@tonic-gate break;
110*7c478bd9Sstevel@tonic-gate case 2: /* ldqf{a}/stqf{a} */
111*7c478bd9Sstevel@tonic-gate /* Require only word alignment. */
112*7c478bd9Sstevel@tonic-gate if (((uintptr_t)ea & 0x3) != 0)
113*7c478bd9Sstevel@tonic-gate return (ftt_alignment);
114*7c478bd9Sstevel@tonic-gate break;
115*7c478bd9Sstevel@tonic-gate case 3: /* lddf{a}/stdf{a} */
116*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_ILP32) {
117*7c478bd9Sstevel@tonic-gate /* Require 64 bit-alignment. */
118*7c478bd9Sstevel@tonic-gate if (((uintptr_t)ea & 0x7) != 0)
119*7c478bd9Sstevel@tonic-gate return (ftt_alignment);
120*7c478bd9Sstevel@tonic-gate } else {
121*7c478bd9Sstevel@tonic-gate if (((uintptr_t)ea & 0x3) != 0)
122*7c478bd9Sstevel@tonic-gate return (ftt_alignment);
123*7c478bd9Sstevel@tonic-gate }
124*7c478bd9Sstevel@tonic-gate }
125*7c478bd9Sstevel@tonic-gate
126*7c478bd9Sstevel@tonic-gate pfpsd->fp_trapaddr = (caddr_t)ea; /* setup bad addr in case we trap */
127*7c478bd9Sstevel@tonic-gate if ((pinst.op3 >> 2) & 1) /* store */
128*7c478bd9Sstevel@tonic-gate pfpsd->fp_traprw = S_READ;
129*7c478bd9Sstevel@tonic-gate else
130*7c478bd9Sstevel@tonic-gate pfpsd->fp_traprw = S_WRITE;
131*7c478bd9Sstevel@tonic-gate
132*7c478bd9Sstevel@tonic-gate switch (do_unaligned(pregs, &badaddr)) {
133*7c478bd9Sstevel@tonic-gate case SIMU_FAULT:
134*7c478bd9Sstevel@tonic-gate return (ftt_fault);
135*7c478bd9Sstevel@tonic-gate case SIMU_ILLEGAL:
136*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
137*7c478bd9Sstevel@tonic-gate case SIMU_SUCCESS:
138*7c478bd9Sstevel@tonic-gate break;
139*7c478bd9Sstevel@tonic-gate }
140*7c478bd9Sstevel@tonic-gate pregs->r_pc = pregs->r_npc; /* Do not retry emulated instruction. */
141*7c478bd9Sstevel@tonic-gate pregs->r_npc += 4;
142*7c478bd9Sstevel@tonic-gate return (ftt_none);
143*7c478bd9Sstevel@tonic-gate }
144*7c478bd9Sstevel@tonic-gate
145*7c478bd9Sstevel@tonic-gate /*
146*7c478bd9Sstevel@tonic-gate * Floating-point conditional moves between floating point unit registers.
147*7c478bd9Sstevel@tonic-gate */
148*7c478bd9Sstevel@tonic-gate static enum ftt_type
fmovcc_fcc(fp_simd_type * pfpsd,fp_inst_type inst,fsr_type * pfsr,enum cc_type cc)149*7c478bd9Sstevel@tonic-gate fmovcc_fcc(
150*7c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to fpu simulator data */
151*7c478bd9Sstevel@tonic-gate fp_inst_type inst, /* FPU instruction to simulate. */
152*7c478bd9Sstevel@tonic-gate fsr_type *pfsr, /* Pointer to image of FSR to read and write. */
153*7c478bd9Sstevel@tonic-gate enum cc_type cc) /* FSR condition code field from fcc[0-3] */
154*7c478bd9Sstevel@tonic-gate {
155*7c478bd9Sstevel@tonic-gate uint32_t moveit;
156*7c478bd9Sstevel@tonic-gate fsr_type fsr;
157*7c478bd9Sstevel@tonic-gate enum fcc_type fcc;
158*7c478bd9Sstevel@tonic-gate enum icc_type {
159*7c478bd9Sstevel@tonic-gate fmovn, fmovne, fmovlg, fmovul, fmovl, fmovug, fmovg, fmovu,
160*7c478bd9Sstevel@tonic-gate fmova, fmove, fmovue, fmovge, fmovuge, fmovle, fmovule, fmovo
161*7c478bd9Sstevel@tonic-gate } cond;
162*7c478bd9Sstevel@tonic-gate
163*7c478bd9Sstevel@tonic-gate fsr = *pfsr;
164*7c478bd9Sstevel@tonic-gate switch (cc) {
165*7c478bd9Sstevel@tonic-gate case fcc_0:
166*7c478bd9Sstevel@tonic-gate fcc = fsr.fcc0;
167*7c478bd9Sstevel@tonic-gate break;
168*7c478bd9Sstevel@tonic-gate case fcc_1:
169*7c478bd9Sstevel@tonic-gate fcc = fsr.fcc1;
170*7c478bd9Sstevel@tonic-gate break;
171*7c478bd9Sstevel@tonic-gate case fcc_2:
172*7c478bd9Sstevel@tonic-gate fcc = fsr.fcc2;
173*7c478bd9Sstevel@tonic-gate break;
174*7c478bd9Sstevel@tonic-gate case fcc_3:
175*7c478bd9Sstevel@tonic-gate fcc = fsr.fcc3;
176*7c478bd9Sstevel@tonic-gate break;
177*7c478bd9Sstevel@tonic-gate default:
178*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
179*7c478bd9Sstevel@tonic-gate }
180*7c478bd9Sstevel@tonic-gate
181*7c478bd9Sstevel@tonic-gate cond = (enum icc_type) (inst.rs1 & 0xf);
182*7c478bd9Sstevel@tonic-gate switch (cond) {
183*7c478bd9Sstevel@tonic-gate case fmovn:
184*7c478bd9Sstevel@tonic-gate moveit = 0;
185*7c478bd9Sstevel@tonic-gate break;
186*7c478bd9Sstevel@tonic-gate case fmovl:
187*7c478bd9Sstevel@tonic-gate moveit = fcc == fcc_less;
188*7c478bd9Sstevel@tonic-gate break;
189*7c478bd9Sstevel@tonic-gate case fmovg:
190*7c478bd9Sstevel@tonic-gate moveit = fcc == fcc_greater;
191*7c478bd9Sstevel@tonic-gate break;
192*7c478bd9Sstevel@tonic-gate case fmovu:
193*7c478bd9Sstevel@tonic-gate moveit = fcc == fcc_unordered;
194*7c478bd9Sstevel@tonic-gate break;
195*7c478bd9Sstevel@tonic-gate case fmove:
196*7c478bd9Sstevel@tonic-gate moveit = fcc == fcc_equal;
197*7c478bd9Sstevel@tonic-gate break;
198*7c478bd9Sstevel@tonic-gate case fmovlg:
199*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_less) || (fcc == fcc_greater);
200*7c478bd9Sstevel@tonic-gate break;
201*7c478bd9Sstevel@tonic-gate case fmovul:
202*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_unordered) || (fcc == fcc_less);
203*7c478bd9Sstevel@tonic-gate break;
204*7c478bd9Sstevel@tonic-gate case fmovug:
205*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_unordered) || (fcc == fcc_greater);
206*7c478bd9Sstevel@tonic-gate break;
207*7c478bd9Sstevel@tonic-gate case fmovue:
208*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_unordered) || (fcc == fcc_equal);
209*7c478bd9Sstevel@tonic-gate break;
210*7c478bd9Sstevel@tonic-gate case fmovge:
211*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_greater) || (fcc == fcc_equal);
212*7c478bd9Sstevel@tonic-gate break;
213*7c478bd9Sstevel@tonic-gate case fmovle:
214*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_less) || (fcc == fcc_equal);
215*7c478bd9Sstevel@tonic-gate break;
216*7c478bd9Sstevel@tonic-gate case fmovne:
217*7c478bd9Sstevel@tonic-gate moveit = fcc != fcc_equal;
218*7c478bd9Sstevel@tonic-gate break;
219*7c478bd9Sstevel@tonic-gate case fmovuge:
220*7c478bd9Sstevel@tonic-gate moveit = fcc != fcc_less;
221*7c478bd9Sstevel@tonic-gate break;
222*7c478bd9Sstevel@tonic-gate case fmovule:
223*7c478bd9Sstevel@tonic-gate moveit = fcc != fcc_greater;
224*7c478bd9Sstevel@tonic-gate break;
225*7c478bd9Sstevel@tonic-gate case fmovo:
226*7c478bd9Sstevel@tonic-gate moveit = fcc != fcc_unordered;
227*7c478bd9Sstevel@tonic-gate break;
228*7c478bd9Sstevel@tonic-gate case fmova:
229*7c478bd9Sstevel@tonic-gate moveit = 1;
230*7c478bd9Sstevel@tonic-gate break;
231*7c478bd9Sstevel@tonic-gate default:
232*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
233*7c478bd9Sstevel@tonic-gate }
234*7c478bd9Sstevel@tonic-gate if (moveit) { /* Move fpu register. */
235*7c478bd9Sstevel@tonic-gate uint32_t nrs2, nrd;
236*7c478bd9Sstevel@tonic-gate uint32_t usr;
237*7c478bd9Sstevel@tonic-gate uint64_t lusr;
238*7c478bd9Sstevel@tonic-gate
239*7c478bd9Sstevel@tonic-gate nrs2 = inst.rs2;
240*7c478bd9Sstevel@tonic-gate nrd = inst.rd;
241*7c478bd9Sstevel@tonic-gate if (inst.prec < 2) { /* fmovs */
242*7c478bd9Sstevel@tonic-gate _fp_unpack_word(pfpsd, &usr, nrs2);
243*7c478bd9Sstevel@tonic-gate _fp_pack_word(pfpsd, &usr, nrd);
244*7c478bd9Sstevel@tonic-gate } else { /* fmovd */
245*7c478bd9Sstevel@tonic-gate /* fix register encoding */
246*7c478bd9Sstevel@tonic-gate if ((nrs2 & 1) == 1)
247*7c478bd9Sstevel@tonic-gate nrs2 = (nrs2 & 0x1e) | 0x20;
248*7c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2);
249*7c478bd9Sstevel@tonic-gate if ((nrd & 1) == 1)
250*7c478bd9Sstevel@tonic-gate nrd = (nrd & 0x1e) | 0x20;
251*7c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd);
252*7c478bd9Sstevel@tonic-gate if (inst.prec > 2) { /* fmovq */
253*7c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2+2);
254*7c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd+2);
255*7c478bd9Sstevel@tonic-gate }
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate return (ftt_none);
259*7c478bd9Sstevel@tonic-gate }
260*7c478bd9Sstevel@tonic-gate
261*7c478bd9Sstevel@tonic-gate /*
262*7c478bd9Sstevel@tonic-gate * Integer conditional moves between floating point unit registers.
263*7c478bd9Sstevel@tonic-gate */
264*7c478bd9Sstevel@tonic-gate static enum ftt_type
fmovcc_icc(fp_simd_type * pfpsd,fp_inst_type inst,enum cc_type cc)265*7c478bd9Sstevel@tonic-gate fmovcc_icc(
266*7c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to fpu simulator data */
267*7c478bd9Sstevel@tonic-gate fp_inst_type inst, /* FPU instruction to simulate. */
268*7c478bd9Sstevel@tonic-gate enum cc_type cc) /* CCR condition code field from tstate */
269*7c478bd9Sstevel@tonic-gate {
270*7c478bd9Sstevel@tonic-gate int moveit;
271*7c478bd9Sstevel@tonic-gate enum icc_type {
272*7c478bd9Sstevel@tonic-gate fmovn, fmove, fmovle, fmovl, fmovleu, fmovcs, fmovneg, fmovvs,
273*7c478bd9Sstevel@tonic-gate fmova, fmovne, fmovg, fmovge, fmovgu, fmovcc, fmovpos, fmovvc
274*7c478bd9Sstevel@tonic-gate } cond;
275*7c478bd9Sstevel@tonic-gate
276*7c478bd9Sstevel@tonic-gate struct regs *pregs;
277*7c478bd9Sstevel@tonic-gate uint64_t tstate;
278*7c478bd9Sstevel@tonic-gate union {
279*7c478bd9Sstevel@tonic-gate uint32_t i;
280*7c478bd9Sstevel@tonic-gate ccr_type cc;
281*7c478bd9Sstevel@tonic-gate } ccr;
282*7c478bd9Sstevel@tonic-gate
283*7c478bd9Sstevel@tonic-gate pregs = lwptoregs(curthread->t_lwp);
284*7c478bd9Sstevel@tonic-gate tstate = pregs->r_tstate;
285*7c478bd9Sstevel@tonic-gate switch (cc) {
286*7c478bd9Sstevel@tonic-gate case icc:
287*7c478bd9Sstevel@tonic-gate ccr.i = (uint32_t)((tstate >> TSTATE_CCR_SHIFT) & 0xf);
288*7c478bd9Sstevel@tonic-gate break;
289*7c478bd9Sstevel@tonic-gate case xcc:
290*7c478bd9Sstevel@tonic-gate ccr.i = (uint32_t)(((tstate >> TSTATE_CCR_SHIFT) & 0xf0) >> 4);
291*7c478bd9Sstevel@tonic-gate break;
292*7c478bd9Sstevel@tonic-gate }
293*7c478bd9Sstevel@tonic-gate
294*7c478bd9Sstevel@tonic-gate cond = (enum icc_type) (inst.rs1 & 0xf);
295*7c478bd9Sstevel@tonic-gate switch (cond) {
296*7c478bd9Sstevel@tonic-gate case fmovn:
297*7c478bd9Sstevel@tonic-gate moveit = 0;
298*7c478bd9Sstevel@tonic-gate break;
299*7c478bd9Sstevel@tonic-gate case fmove:
300*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.z);
301*7c478bd9Sstevel@tonic-gate break;
302*7c478bd9Sstevel@tonic-gate case fmovle:
303*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.z | (ccr.cc.n ^ ccr.cc.v));
304*7c478bd9Sstevel@tonic-gate break;
305*7c478bd9Sstevel@tonic-gate case fmovl:
306*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.n ^ ccr.cc.v);
307*7c478bd9Sstevel@tonic-gate break;
308*7c478bd9Sstevel@tonic-gate case fmovleu:
309*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.c | ccr.cc.z);
310*7c478bd9Sstevel@tonic-gate break;
311*7c478bd9Sstevel@tonic-gate case fmovcs:
312*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.c);
313*7c478bd9Sstevel@tonic-gate break;
314*7c478bd9Sstevel@tonic-gate case fmovneg:
315*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.n);
316*7c478bd9Sstevel@tonic-gate break;
317*7c478bd9Sstevel@tonic-gate case fmovvs:
318*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.v);
319*7c478bd9Sstevel@tonic-gate break;
320*7c478bd9Sstevel@tonic-gate case fmova:
321*7c478bd9Sstevel@tonic-gate moveit = 1;
322*7c478bd9Sstevel@tonic-gate break;
323*7c478bd9Sstevel@tonic-gate case fmovne:
324*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.z == 0);
325*7c478bd9Sstevel@tonic-gate break;
326*7c478bd9Sstevel@tonic-gate case fmovg:
327*7c478bd9Sstevel@tonic-gate moveit = (int)((ccr.cc.z | (ccr.cc.n ^ ccr.cc.v)) == 0);
328*7c478bd9Sstevel@tonic-gate break;
329*7c478bd9Sstevel@tonic-gate case fmovge:
330*7c478bd9Sstevel@tonic-gate moveit = (int)((ccr.cc.n ^ ccr.cc.v) == 0);
331*7c478bd9Sstevel@tonic-gate break;
332*7c478bd9Sstevel@tonic-gate case fmovgu:
333*7c478bd9Sstevel@tonic-gate moveit = (int)((ccr.cc.c | ccr.cc.z) == 0);
334*7c478bd9Sstevel@tonic-gate break;
335*7c478bd9Sstevel@tonic-gate case fmovcc:
336*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.c == 0);
337*7c478bd9Sstevel@tonic-gate break;
338*7c478bd9Sstevel@tonic-gate case fmovpos:
339*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.n == 0);
340*7c478bd9Sstevel@tonic-gate break;
341*7c478bd9Sstevel@tonic-gate case fmovvc:
342*7c478bd9Sstevel@tonic-gate moveit = (int)(ccr.cc.v == 0);
343*7c478bd9Sstevel@tonic-gate break;
344*7c478bd9Sstevel@tonic-gate default:
345*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate if (moveit) { /* Move fpu register. */
348*7c478bd9Sstevel@tonic-gate uint32_t nrs2, nrd;
349*7c478bd9Sstevel@tonic-gate uint32_t usr;
350*7c478bd9Sstevel@tonic-gate uint64_t lusr;
351*7c478bd9Sstevel@tonic-gate
352*7c478bd9Sstevel@tonic-gate nrs2 = inst.rs2;
353*7c478bd9Sstevel@tonic-gate nrd = inst.rd;
354*7c478bd9Sstevel@tonic-gate if (inst.prec < 2) { /* fmovs */
355*7c478bd9Sstevel@tonic-gate _fp_unpack_word(pfpsd, &usr, nrs2);
356*7c478bd9Sstevel@tonic-gate _fp_pack_word(pfpsd, &usr, nrd);
357*7c478bd9Sstevel@tonic-gate } else { /* fmovd */
358*7c478bd9Sstevel@tonic-gate /* fix register encoding */
359*7c478bd9Sstevel@tonic-gate if ((nrs2 & 1) == 1)
360*7c478bd9Sstevel@tonic-gate nrs2 = (nrs2 & 0x1e) | 0x20;
361*7c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2);
362*7c478bd9Sstevel@tonic-gate if ((nrd & 1) == 1)
363*7c478bd9Sstevel@tonic-gate nrd = (nrd & 0x1e) | 0x20;
364*7c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd);
365*7c478bd9Sstevel@tonic-gate if (inst.prec > 2) { /* fmovq */
366*7c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2+2);
367*7c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd+2);
368*7c478bd9Sstevel@tonic-gate }
369*7c478bd9Sstevel@tonic-gate }
370*7c478bd9Sstevel@tonic-gate }
371*7c478bd9Sstevel@tonic-gate return (ftt_none);
372*7c478bd9Sstevel@tonic-gate }
373*7c478bd9Sstevel@tonic-gate
374*7c478bd9Sstevel@tonic-gate /*
375*7c478bd9Sstevel@tonic-gate * Simulator for moving fp register on condition (FMOVcc).
376*7c478bd9Sstevel@tonic-gate * FMOVccq (Quad version of instruction) not supported by Ultra-1, so this
377*7c478bd9Sstevel@tonic-gate * code must always be present.
378*7c478bd9Sstevel@tonic-gate */
379*7c478bd9Sstevel@tonic-gate enum ftt_type
fmovcc(fp_simd_type * pfpsd,fp_inst_type inst,fsr_type * pfsr)380*7c478bd9Sstevel@tonic-gate fmovcc(
381*7c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to fpu simulator data */
382*7c478bd9Sstevel@tonic-gate fp_inst_type inst, /* FPU instruction to simulate. */
383*7c478bd9Sstevel@tonic-gate fsr_type *pfsr) /* Pointer to image of FSR to read and write. */
384*7c478bd9Sstevel@tonic-gate {
385*7c478bd9Sstevel@tonic-gate enum cc_type opf_cc;
386*7c478bd9Sstevel@tonic-gate
387*7c478bd9Sstevel@tonic-gate opf_cc = (enum cc_type) ((inst.ibit << 2) | (inst.opcode >> 4));
388*7c478bd9Sstevel@tonic-gate if ((opf_cc == icc) || (opf_cc == xcc)) {
389*7c478bd9Sstevel@tonic-gate return (fmovcc_icc(pfpsd, inst, opf_cc));
390*7c478bd9Sstevel@tonic-gate } else {
391*7c478bd9Sstevel@tonic-gate return (fmovcc_fcc(pfpsd, inst, pfsr, opf_cc));
392*7c478bd9Sstevel@tonic-gate }
393*7c478bd9Sstevel@tonic-gate }
394*7c478bd9Sstevel@tonic-gate
395*7c478bd9Sstevel@tonic-gate /*
396*7c478bd9Sstevel@tonic-gate * Simulator for moving fp register on integer register condition (FMOVr).
397*7c478bd9Sstevel@tonic-gate * FMOVrq (Quad version of instruction) not supported by Ultra-1, so this
398*7c478bd9Sstevel@tonic-gate * code must always be present.
399*7c478bd9Sstevel@tonic-gate */
400*7c478bd9Sstevel@tonic-gate enum ftt_type
fmovr(fp_simd_type * pfpsd,fp_inst_type inst)401*7c478bd9Sstevel@tonic-gate fmovr(
402*7c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to fpu simulator data */
403*7c478bd9Sstevel@tonic-gate fp_inst_type inst) /* FPU instruction to simulate. */
404*7c478bd9Sstevel@tonic-gate {
405*7c478bd9Sstevel@tonic-gate struct regs *pregs;
406*7c478bd9Sstevel@tonic-gate ulong_t *prw;
407*7c478bd9Sstevel@tonic-gate uint32_t nrs1;
408*7c478bd9Sstevel@tonic-gate enum ftt_type ftt;
409*7c478bd9Sstevel@tonic-gate enum rcond_type {
410*7c478bd9Sstevel@tonic-gate none, fmovre, fmovrlez, fmovrlz,
411*7c478bd9Sstevel@tonic-gate nnone, fmovrne, fmovrgz, fmovrgez
412*7c478bd9Sstevel@tonic-gate } rcond;
413*7c478bd9Sstevel@tonic-gate int64_t moveit, r;
414*7c478bd9Sstevel@tonic-gate
415*7c478bd9Sstevel@tonic-gate nrs1 = inst.rs1;
416*7c478bd9Sstevel@tonic-gate if (nrs1 > 15) /* rs1 must be a global register */
417*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
418*7c478bd9Sstevel@tonic-gate if (inst.ibit) /* ibit must be unused */
419*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
420*7c478bd9Sstevel@tonic-gate pregs = lwptoregs(curthread->t_lwp);
421*7c478bd9Sstevel@tonic-gate prw = (ulong_t *)pregs->r_sp;
422*7c478bd9Sstevel@tonic-gate ftt = read_iureg(pfpsd, nrs1, pregs, prw, (uint64_t *)&r);
423*7c478bd9Sstevel@tonic-gate if (ftt != ftt_none)
424*7c478bd9Sstevel@tonic-gate return (ftt);
425*7c478bd9Sstevel@tonic-gate rcond = (enum rcond_type) (inst.opcode >> 3) & 7;
426*7c478bd9Sstevel@tonic-gate switch (rcond) {
427*7c478bd9Sstevel@tonic-gate case fmovre:
428*7c478bd9Sstevel@tonic-gate moveit = r == 0;
429*7c478bd9Sstevel@tonic-gate break;
430*7c478bd9Sstevel@tonic-gate case fmovrlez:
431*7c478bd9Sstevel@tonic-gate moveit = r <= 0;
432*7c478bd9Sstevel@tonic-gate break;
433*7c478bd9Sstevel@tonic-gate case fmovrlz:
434*7c478bd9Sstevel@tonic-gate moveit = r < 0;
435*7c478bd9Sstevel@tonic-gate break;
436*7c478bd9Sstevel@tonic-gate case fmovrne:
437*7c478bd9Sstevel@tonic-gate moveit = r != 0;
438*7c478bd9Sstevel@tonic-gate break;
439*7c478bd9Sstevel@tonic-gate case fmovrgz:
440*7c478bd9Sstevel@tonic-gate moveit = r > 0;
441*7c478bd9Sstevel@tonic-gate break;
442*7c478bd9Sstevel@tonic-gate case fmovrgez:
443*7c478bd9Sstevel@tonic-gate moveit = r >= 0;
444*7c478bd9Sstevel@tonic-gate break;
445*7c478bd9Sstevel@tonic-gate default:
446*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
447*7c478bd9Sstevel@tonic-gate }
448*7c478bd9Sstevel@tonic-gate if (moveit) { /* Move fpu register. */
449*7c478bd9Sstevel@tonic-gate uint32_t nrs2, nrd;
450*7c478bd9Sstevel@tonic-gate uint32_t usr;
451*7c478bd9Sstevel@tonic-gate uint64_t lusr;
452*7c478bd9Sstevel@tonic-gate
453*7c478bd9Sstevel@tonic-gate nrs2 = inst.rs2;
454*7c478bd9Sstevel@tonic-gate nrd = inst.rd;
455*7c478bd9Sstevel@tonic-gate if (inst.prec < 2) { /* fmovs */
456*7c478bd9Sstevel@tonic-gate _fp_unpack_word(pfpsd, &usr, nrs2);
457*7c478bd9Sstevel@tonic-gate _fp_pack_word(pfpsd, &usr, nrd);
458*7c478bd9Sstevel@tonic-gate } else { /* fmovd */
459*7c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2);
460*7c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd);
461*7c478bd9Sstevel@tonic-gate if (inst.prec > 2) { /* fmovq */
462*7c478bd9Sstevel@tonic-gate _fp_unpack_extword(pfpsd, &lusr, nrs2+2);
463*7c478bd9Sstevel@tonic-gate _fp_pack_extword(pfpsd, &lusr, nrd+2);
464*7c478bd9Sstevel@tonic-gate }
465*7c478bd9Sstevel@tonic-gate }
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate return (ftt_none);
468*7c478bd9Sstevel@tonic-gate }
469*7c478bd9Sstevel@tonic-gate
470*7c478bd9Sstevel@tonic-gate /*
471*7c478bd9Sstevel@tonic-gate * Move integer register on condition (MOVcc).
472*7c478bd9Sstevel@tonic-gate */
473*7c478bd9Sstevel@tonic-gate enum ftt_type
movcc(fp_simd_type * pfpsd,fp_inst_type pinst,struct regs * pregs,void * prw,kfpu_t * pfpu)474*7c478bd9Sstevel@tonic-gate movcc(
475*7c478bd9Sstevel@tonic-gate fp_simd_type *pfpsd, /* Pointer to fpu simulator data */
476*7c478bd9Sstevel@tonic-gate fp_inst_type pinst, /* FPU instruction to simulate. */
477*7c478bd9Sstevel@tonic-gate struct regs *pregs, /* Pointer to PCB image of registers. */
478*7c478bd9Sstevel@tonic-gate void *prw, /* Pointer to locals and ins. */
479*7c478bd9Sstevel@tonic-gate kfpu_t *pfpu) /* Pointer to FPU register block. */
480*7c478bd9Sstevel@tonic-gate
481*7c478bd9Sstevel@tonic-gate {
482*7c478bd9Sstevel@tonic-gate fsr_type fsr;
483*7c478bd9Sstevel@tonic-gate enum cc_type cc;
484*7c478bd9Sstevel@tonic-gate enum fcc_type fcc;
485*7c478bd9Sstevel@tonic-gate enum icc_type {
486*7c478bd9Sstevel@tonic-gate fmovn, fmovne, fmovlg, fmovul, fmovl, fmovug, fmovg, fmovu,
487*7c478bd9Sstevel@tonic-gate fmova, fmove, fmovue, fmovge, fmovuge, fmovle, fmovule, fmovo
488*7c478bd9Sstevel@tonic-gate } cond;
489*7c478bd9Sstevel@tonic-gate uint32_t moveit;
490*7c478bd9Sstevel@tonic-gate enum ftt_type ftt = ftt_none;
491*7c478bd9Sstevel@tonic-gate
492*7c478bd9Sstevel@tonic-gate cc = (enum cc_type) (pinst.opcode >> 0x4) & 3;
493*7c478bd9Sstevel@tonic-gate fsr.ll = pfpu->fpu_fsr;
494*7c478bd9Sstevel@tonic-gate cond = (enum icc_type) (pinst.rs1 & 0xf);
495*7c478bd9Sstevel@tonic-gate switch (cc) {
496*7c478bd9Sstevel@tonic-gate case fcc_0:
497*7c478bd9Sstevel@tonic-gate fcc = fsr.fcc0;
498*7c478bd9Sstevel@tonic-gate break;
499*7c478bd9Sstevel@tonic-gate case fcc_1:
500*7c478bd9Sstevel@tonic-gate fcc = fsr.fcc1;
501*7c478bd9Sstevel@tonic-gate break;
502*7c478bd9Sstevel@tonic-gate case fcc_2:
503*7c478bd9Sstevel@tonic-gate fcc = fsr.fcc2;
504*7c478bd9Sstevel@tonic-gate break;
505*7c478bd9Sstevel@tonic-gate case fcc_3:
506*7c478bd9Sstevel@tonic-gate fcc = fsr.fcc3;
507*7c478bd9Sstevel@tonic-gate break;
508*7c478bd9Sstevel@tonic-gate default:
509*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
510*7c478bd9Sstevel@tonic-gate }
511*7c478bd9Sstevel@tonic-gate
512*7c478bd9Sstevel@tonic-gate switch (cond) {
513*7c478bd9Sstevel@tonic-gate case fmovn:
514*7c478bd9Sstevel@tonic-gate moveit = 0;
515*7c478bd9Sstevel@tonic-gate break;
516*7c478bd9Sstevel@tonic-gate case fmovl:
517*7c478bd9Sstevel@tonic-gate moveit = fcc == fcc_less;
518*7c478bd9Sstevel@tonic-gate break;
519*7c478bd9Sstevel@tonic-gate case fmovg:
520*7c478bd9Sstevel@tonic-gate moveit = fcc == fcc_greater;
521*7c478bd9Sstevel@tonic-gate break;
522*7c478bd9Sstevel@tonic-gate case fmovu:
523*7c478bd9Sstevel@tonic-gate moveit = fcc == fcc_unordered;
524*7c478bd9Sstevel@tonic-gate break;
525*7c478bd9Sstevel@tonic-gate case fmove:
526*7c478bd9Sstevel@tonic-gate moveit = fcc == fcc_equal;
527*7c478bd9Sstevel@tonic-gate break;
528*7c478bd9Sstevel@tonic-gate case fmovlg:
529*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_less) || (fcc == fcc_greater);
530*7c478bd9Sstevel@tonic-gate break;
531*7c478bd9Sstevel@tonic-gate case fmovul:
532*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_unordered) || (fcc == fcc_less);
533*7c478bd9Sstevel@tonic-gate break;
534*7c478bd9Sstevel@tonic-gate case fmovug:
535*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_unordered) || (fcc == fcc_greater);
536*7c478bd9Sstevel@tonic-gate break;
537*7c478bd9Sstevel@tonic-gate case fmovue:
538*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_unordered) || (fcc == fcc_equal);
539*7c478bd9Sstevel@tonic-gate break;
540*7c478bd9Sstevel@tonic-gate case fmovge:
541*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_greater) || (fcc == fcc_equal);
542*7c478bd9Sstevel@tonic-gate break;
543*7c478bd9Sstevel@tonic-gate case fmovle:
544*7c478bd9Sstevel@tonic-gate moveit = (fcc == fcc_less) || (fcc == fcc_equal);
545*7c478bd9Sstevel@tonic-gate break;
546*7c478bd9Sstevel@tonic-gate case fmovne:
547*7c478bd9Sstevel@tonic-gate moveit = fcc != fcc_equal;
548*7c478bd9Sstevel@tonic-gate break;
549*7c478bd9Sstevel@tonic-gate case fmovuge:
550*7c478bd9Sstevel@tonic-gate moveit = fcc != fcc_less;
551*7c478bd9Sstevel@tonic-gate break;
552*7c478bd9Sstevel@tonic-gate case fmovule:
553*7c478bd9Sstevel@tonic-gate moveit = fcc != fcc_greater;
554*7c478bd9Sstevel@tonic-gate break;
555*7c478bd9Sstevel@tonic-gate case fmovo:
556*7c478bd9Sstevel@tonic-gate moveit = fcc != fcc_unordered;
557*7c478bd9Sstevel@tonic-gate break;
558*7c478bd9Sstevel@tonic-gate case fmova:
559*7c478bd9Sstevel@tonic-gate moveit = 1;
560*7c478bd9Sstevel@tonic-gate break;
561*7c478bd9Sstevel@tonic-gate default:
562*7c478bd9Sstevel@tonic-gate return (ftt_unimplemented);
563*7c478bd9Sstevel@tonic-gate }
564*7c478bd9Sstevel@tonic-gate if (moveit) { /* Move fpu register. */
565*7c478bd9Sstevel@tonic-gate uint32_t nrd;
566*7c478bd9Sstevel@tonic-gate uint64_t r;
567*7c478bd9Sstevel@tonic-gate
568*7c478bd9Sstevel@tonic-gate nrd = pinst.rd;
569*7c478bd9Sstevel@tonic-gate if (pinst.ibit == 0) { /* copy the value in r[rs2] */
570*7c478bd9Sstevel@tonic-gate uint32_t nrs2;
571*7c478bd9Sstevel@tonic-gate
572*7c478bd9Sstevel@tonic-gate nrs2 = pinst.rs2;
573*7c478bd9Sstevel@tonic-gate ftt = read_iureg(pfpsd, nrs2, pregs, prw, &r);
574*7c478bd9Sstevel@tonic-gate if (ftt != ftt_none)
575*7c478bd9Sstevel@tonic-gate return (ftt);
576*7c478bd9Sstevel@tonic-gate ftt = write_iureg(pfpsd, nrd, pregs, prw, &r);
577*7c478bd9Sstevel@tonic-gate } else { /* use sign_ext(simm11) */
578*7c478bd9Sstevel@tonic-gate union {
579*7c478bd9Sstevel@tonic-gate fp_inst_type inst;
580*7c478bd9Sstevel@tonic-gate int32_t i;
581*7c478bd9Sstevel@tonic-gate } fp;
582*7c478bd9Sstevel@tonic-gate
583*7c478bd9Sstevel@tonic-gate fp.inst = pinst; /* Extract simm11 field */
584*7c478bd9Sstevel@tonic-gate r = (fp.i << 21) >> 21;
585*7c478bd9Sstevel@tonic-gate ftt = write_iureg(pfpsd, nrd, pregs, prw, &r);
586*7c478bd9Sstevel@tonic-gate }
587*7c478bd9Sstevel@tonic-gate }
588*7c478bd9Sstevel@tonic-gate pregs->r_pc = pregs->r_npc; /* Do not retry emulated instruction. */
589*7c478bd9Sstevel@tonic-gate pregs->r_npc += 4;
590*7c478bd9Sstevel@tonic-gate return (ftt);
591*7c478bd9Sstevel@tonic-gate }
592