4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 /* Integer Unit simulator for Sparc FPU simulator. */
31 #include <sys/fpu/fpu_simulator.h>
32 #include <sys/fpu/globals.h>
34 #include <sys/privregs.h>
35 #include <sys/vis_simulator.h>
37 #include <sys/simulate.h>
38 #include <sys/model.h>
40 #define FPU_REG_FIELD uint32_reg /* Coordinate with FPU_REGS_TYPE. */
41 #define FPU_DREG_FIELD uint64_reg /* Coordinate with FPU_DREGS_TYPE. */
42 #define FPU_FSR_FIELD uint64_reg /* Coordinate with V9_FPU_FSR_TYPE. */
45 * Simulator for loads and stores between floating-point unit and memory.
49 fp_simd_type
*pfpsd
, /* FPU simulator data. */
50 fp_inst_type pinst
, /* FPU instruction to simulate. */
51 struct regs
*pregs
, /* Pointer to PCB image of registers. */
52 void *prw
) /* Pointer to locals and ins. */
54 uint32_t sz_bits
, asi
= 0;
58 char *badaddr
= (caddr_t
)(-1);
65 if ((pinst
.op3
>> 4) & 1) {
67 asi
= (uint32_t)((pregs
->r_tstate
>> TSTATE_ASI_SHIFT
) &
70 asi
= (fp
.i
>> 5) & 0xff;
72 /* check for ld/st alternate and highest defined V9 asi */
73 if (((pinst
.op3
& 0x30) == 0x30) && (asi
> ASI_SNFL
))
74 return (vis_fldst(pfpsd
, pinst
, pregs
, prw
, asi
));
77 if (pinst
.ibit
== 0) { /* effective address = rs1 + rs2 */
78 ftt
= read_iureg(pfpsd
, pinst
.rs1
, pregs
, prw
, &fea
);
81 ftt
= read_iureg(pfpsd
, pinst
.rs2
, pregs
, prw
, &tea
);
84 ea
= (uint64_t *)(fea
+ tea
);
85 } else { /* effective address = rs1 + imm13 */
86 /* Extract simm13 field. */
87 fea
= (uint64_t)((fp
.i
<< 19) >> 19);
88 ftt
= read_iureg(pfpsd
, pinst
.rs1
, pregs
, prw
, &tea
);
91 ea
= (uint64_t *)(fea
+ tea
);
93 sz_bits
= pinst
.op3
& 0x3;
94 switch (sz_bits
) { /* map size bits to a number */
95 case 0: /* ldf{a}/stf{a} */
96 /* Must be word-aligned. */
97 if (((uintptr_t)ea
& 0x3) != 0)
98 return (ftt_alignment
);
100 case 1: if (pinst
.rd
== 0) { /* ldfsr/stfsr */
101 /* Must be word-aligned. */
102 if (((uintptr_t)ea
& 0x3) != 0)
103 return (ftt_alignment
);
104 } else { /* ldxfsr/stxfsr */
105 /* Must be extword-aligned. */
106 if (((uintptr_t)ea
& 0x7) != 0)
107 return (ftt_alignment
);
110 case 2: /* ldqf{a}/stqf{a} */
111 /* Require only word alignment. */
112 if (((uintptr_t)ea
& 0x3) != 0)
113 return (ftt_alignment
);
115 case 3: /* lddf{a}/stdf{a} */
116 if (get_udatamodel() == DATAMODEL_ILP32
) {
117 /* Require 64 bit-alignment. */
118 if (((uintptr_t)ea
& 0x7) != 0)
119 return (ftt_alignment
);
121 if (((uintptr_t)ea
& 0x3) != 0)
122 return (ftt_alignment
);
126 pfpsd
->fp_trapaddr
= (caddr_t
)ea
; /* setup bad addr in case we trap */
127 if ((pinst
.op3
>> 2) & 1) /* store */
128 pfpsd
->fp_traprw
= S_READ
;
130 pfpsd
->fp_traprw
= S_WRITE
;
132 switch (do_unaligned(pregs
, &badaddr
)) {
136 return (ftt_unimplemented
);
140 pregs
->r_pc
= pregs
->r_npc
; /* Do not retry emulated instruction. */
146 * Floating-point conditional moves between floating point unit registers.
150 fp_simd_type
*pfpsd
, /* Pointer to fpu simulator data */
151 fp_inst_type inst
, /* FPU instruction to simulate. */
152 fsr_type
*pfsr
, /* Pointer to image of FSR to read and write. */
153 enum cc_type cc
) /* FSR condition code field from fcc[0-3] */
159 fmovn
, fmovne
, fmovlg
, fmovul
, fmovl
, fmovug
, fmovg
, fmovu
,
160 fmova
, fmove
, fmovue
, fmovge
, fmovuge
, fmovle
, fmovule
, fmovo
178 return (ftt_unimplemented
);
181 cond
= (enum icc_type
) (inst
.rs1
& 0xf);
187 moveit
= fcc
== fcc_less
;
190 moveit
= fcc
== fcc_greater
;
193 moveit
= fcc
== fcc_unordered
;
196 moveit
= fcc
== fcc_equal
;
199 moveit
= (fcc
== fcc_less
) || (fcc
== fcc_greater
);
202 moveit
= (fcc
== fcc_unordered
) || (fcc
== fcc_less
);
205 moveit
= (fcc
== fcc_unordered
) || (fcc
== fcc_greater
);
208 moveit
= (fcc
== fcc_unordered
) || (fcc
== fcc_equal
);
211 moveit
= (fcc
== fcc_greater
) || (fcc
== fcc_equal
);
214 moveit
= (fcc
== fcc_less
) || (fcc
== fcc_equal
);
217 moveit
= fcc
!= fcc_equal
;
220 moveit
= fcc
!= fcc_less
;
223 moveit
= fcc
!= fcc_greater
;
226 moveit
= fcc
!= fcc_unordered
;
232 return (ftt_unimplemented
);
234 if (moveit
) { /* Move fpu register. */
241 if (inst
.prec
< 2) { /* fmovs */
242 _fp_unpack_word(pfpsd
, &usr
, nrs2
);
243 _fp_pack_word(pfpsd
, &usr
, nrd
);
245 /* fix register encoding */
247 nrs2
= (nrs2
& 0x1e) | 0x20;
248 _fp_unpack_extword(pfpsd
, &lusr
, nrs2
);
250 nrd
= (nrd
& 0x1e) | 0x20;
251 _fp_pack_extword(pfpsd
, &lusr
, nrd
);
252 if (inst
.prec
> 2) { /* fmovq */
253 _fp_unpack_extword(pfpsd
, &lusr
, nrs2
+2);
254 _fp_pack_extword(pfpsd
, &lusr
, nrd
+2);
262 * Integer conditional moves between floating point unit registers.
266 fp_simd_type
*pfpsd
, /* Pointer to fpu simulator data */
267 fp_inst_type inst
, /* FPU instruction to simulate. */
268 enum cc_type cc
) /* CCR condition code field from tstate */
272 fmovn
, fmove
, fmovle
, fmovl
, fmovleu
, fmovcs
, fmovneg
, fmovvs
,
273 fmova
, fmovne
, fmovg
, fmovge
, fmovgu
, fmovcc
, fmovpos
, fmovvc
283 pregs
= lwptoregs(curthread
->t_lwp
);
284 tstate
= pregs
->r_tstate
;
287 ccr
.i
= (uint32_t)((tstate
>> TSTATE_CCR_SHIFT
) & 0xf);
290 ccr
.i
= (uint32_t)(((tstate
>> TSTATE_CCR_SHIFT
) & 0xf0) >> 4);
294 cond
= (enum icc_type
) (inst
.rs1
& 0xf);
300 moveit
= (int)(ccr
.cc
.z
);
303 moveit
= (int)(ccr
.cc
.z
| (ccr
.cc
.n
^ ccr
.cc
.v
));
306 moveit
= (int)(ccr
.cc
.n
^ ccr
.cc
.v
);
309 moveit
= (int)(ccr
.cc
.c
| ccr
.cc
.z
);
312 moveit
= (int)(ccr
.cc
.c
);
315 moveit
= (int)(ccr
.cc
.n
);
318 moveit
= (int)(ccr
.cc
.v
);
324 moveit
= (int)(ccr
.cc
.z
== 0);
327 moveit
= (int)((ccr
.cc
.z
| (ccr
.cc
.n
^ ccr
.cc
.v
)) == 0);
330 moveit
= (int)((ccr
.cc
.n
^ ccr
.cc
.v
) == 0);
333 moveit
= (int)((ccr
.cc
.c
| ccr
.cc
.z
) == 0);
336 moveit
= (int)(ccr
.cc
.c
== 0);
339 moveit
= (int)(ccr
.cc
.n
== 0);
342 moveit
= (int)(ccr
.cc
.v
== 0);
345 return (ftt_unimplemented
);
347 if (moveit
) { /* Move fpu register. */
354 if (inst
.prec
< 2) { /* fmovs */
355 _fp_unpack_word(pfpsd
, &usr
, nrs2
);
356 _fp_pack_word(pfpsd
, &usr
, nrd
);
358 /* fix register encoding */
360 nrs2
= (nrs2
& 0x1e) | 0x20;
361 _fp_unpack_extword(pfpsd
, &lusr
, nrs2
);
363 nrd
= (nrd
& 0x1e) | 0x20;
364 _fp_pack_extword(pfpsd
, &lusr
, nrd
);
365 if (inst
.prec
> 2) { /* fmovq */
366 _fp_unpack_extword(pfpsd
, &lusr
, nrs2
+2);
367 _fp_pack_extword(pfpsd
, &lusr
, nrd
+2);
375 * Simulator for moving fp register on condition (FMOVcc).
376 * FMOVccq (Quad version of instruction) not supported by Ultra-1, so this
377 * code must always be present.
381 fp_simd_type
*pfpsd
, /* Pointer to fpu simulator data */
382 fp_inst_type inst
, /* FPU instruction to simulate. */
383 fsr_type
*pfsr
) /* Pointer to image of FSR to read and write. */
387 opf_cc
= (enum cc_type
) ((inst
.ibit
<< 2) | (inst
.opcode
>> 4));
388 if ((opf_cc
== icc
) || (opf_cc
== xcc
)) {
389 return (fmovcc_icc(pfpsd
, inst
, opf_cc
));
391 return (fmovcc_fcc(pfpsd
, inst
, pfsr
, opf_cc
));
396 * Simulator for moving fp register on integer register condition (FMOVr).
397 * FMOVrq (Quad version of instruction) not supported by Ultra-1, so this
398 * code must always be present.
402 fp_simd_type
*pfpsd
, /* Pointer to fpu simulator data */
403 fp_inst_type inst
) /* FPU instruction to simulate. */
410 none
, fmovre
, fmovrlez
, fmovrlz
,
411 nnone
, fmovrne
, fmovrgz
, fmovrgez
416 if (nrs1
> 15) /* rs1 must be a global register */
417 return (ftt_unimplemented
);
418 if (inst
.ibit
) /* ibit must be unused */
419 return (ftt_unimplemented
);
420 pregs
= lwptoregs(curthread
->t_lwp
);
421 prw
= (ulong_t
*)pregs
->r_sp
;
422 ftt
= read_iureg(pfpsd
, nrs1
, pregs
, prw
, (uint64_t *)&r
);
425 rcond
= (enum rcond_type
) (inst
.opcode
>> 3) & 7;
446 return (ftt_unimplemented
);
448 if (moveit
) { /* Move fpu register. */
455 if (inst
.prec
< 2) { /* fmovs */
456 _fp_unpack_word(pfpsd
, &usr
, nrs2
);
457 _fp_pack_word(pfpsd
, &usr
, nrd
);
459 _fp_unpack_extword(pfpsd
, &lusr
, nrs2
);
460 _fp_pack_extword(pfpsd
, &lusr
, nrd
);
461 if (inst
.prec
> 2) { /* fmovq */
462 _fp_unpack_extword(pfpsd
, &lusr
, nrs2
+2);
463 _fp_pack_extword(pfpsd
, &lusr
, nrd
+2);
471 * Move integer register on condition (MOVcc).
475 fp_simd_type
*pfpsd
, /* Pointer to fpu simulator data */
476 fp_inst_type pinst
, /* FPU instruction to simulate. */
477 struct regs
*pregs
, /* Pointer to PCB image of registers. */
478 void *prw
, /* Pointer to locals and ins. */
479 kfpu_t
*pfpu
) /* Pointer to FPU register block. */
486 fmovn
, fmovne
, fmovlg
, fmovul
, fmovl
, fmovug
, fmovg
, fmovu
,
487 fmova
, fmove
, fmovue
, fmovge
, fmovuge
, fmovle
, fmovule
, fmovo
490 enum ftt_type ftt
= ftt_none
;
492 cc
= (enum cc_type
) (pinst
.opcode
>> 0x4) & 3;
493 fsr
.ll
= pfpu
->fpu_fsr
;
494 cond
= (enum icc_type
) (pinst
.rs1
& 0xf);
509 return (ftt_unimplemented
);
517 moveit
= fcc
== fcc_less
;
520 moveit
= fcc
== fcc_greater
;
523 moveit
= fcc
== fcc_unordered
;
526 moveit
= fcc
== fcc_equal
;
529 moveit
= (fcc
== fcc_less
) || (fcc
== fcc_greater
);
532 moveit
= (fcc
== fcc_unordered
) || (fcc
== fcc_less
);
535 moveit
= (fcc
== fcc_unordered
) || (fcc
== fcc_greater
);
538 moveit
= (fcc
== fcc_unordered
) || (fcc
== fcc_equal
);
541 moveit
= (fcc
== fcc_greater
) || (fcc
== fcc_equal
);
544 moveit
= (fcc
== fcc_less
) || (fcc
== fcc_equal
);
547 moveit
= fcc
!= fcc_equal
;
550 moveit
= fcc
!= fcc_less
;
553 moveit
= fcc
!= fcc_greater
;
556 moveit
= fcc
!= fcc_unordered
;
562 return (ftt_unimplemented
);
564 if (moveit
) { /* Move fpu register. */
569 if (pinst
.ibit
== 0) { /* copy the value in r[rs2] */
573 ftt
= read_iureg(pfpsd
, nrs2
, pregs
, prw
, &r
);
576 ftt
= write_iureg(pfpsd
, nrd
, pregs
, prw
, &r
);
577 } else { /* use sign_ext(simm11) */
583 fp
.inst
= pinst
; /* Extract simm11 field */
584 r
= (fp
.i
<< 21) >> 21;
585 ftt
= write_iureg(pfpsd
, nrd
, pregs
, prw
, &r
);
588 pregs
->r_pc
= pregs
->r_npc
; /* Do not retry emulated instruction. */