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 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 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 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 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 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 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