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