xref: /onnv-gate/usr/src/uts/sparc/v9/fpu/v9instr.c (revision 0:68f95e015346)
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