|
|
1.1.1.2 ! root 1: /* $Id: sparc-insns.c,v 1.7 2010/02/14 14:39:35 fredette Exp $ */ 1.1 root 2: 3: /* ic/sparc/sparc-insns.c - SPARC instruction functions: */ 4: 5: /* 6: * Copyright (c) 2005 Matt Fredette 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by Matt Fredette. 20: * 4. The name of the author may not be used to endorse or promote products 21: * derived from this software without specific prior written permission. 22: * 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33: * POSSIBILITY OF SUCH DAMAGE. 34: */ 35: 36: /* includes: */ 37: #include "sparc-impl.h" 1.1.1.2 ! root 38: #include <tme/misc.h> 1.1 root 39: 1.1.1.2 ! root 40: _TME_RCSID("$Id: sparc-insns.c,v 1.7 2010/02/14 14:39:35 fredette Exp $"); 1.1 root 41: 1.1.1.2 ! root 42: #undef TME_SPARC_VERSION ! 43: #define TME_SPARC_VERSION(ic) (8) 1.1 root 44: 45: TME_SPARC_FORMAT3(tme_sparc32_illegal, tme_uint32_t) 46: { 1.1.1.2 ! root 47: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 48: } 49: 50: /* the coprocessor instructions are all illegal for now: */ 51: TME_SPARC_FORMAT3(tme_sparc32_cpop1, tme_uint32_t) 52: { 1.1.1.2 ! root 53: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 54: } 55: TME_SPARC_FORMAT3(tme_sparc32_cpop2, tme_uint32_t) 56: { 1.1.1.2 ! root 57: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 58: } 59: TME_SPARC_FORMAT3(tme_sparc32_ldc, tme_uint32_t) 60: { 1.1.1.2 ! root 61: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 62: } 63: TME_SPARC_FORMAT3(tme_sparc32_ldcsr, tme_uint32_t) 64: { 1.1.1.2 ! root 65: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 66: } 67: TME_SPARC_FORMAT3(tme_sparc32_lddc, tme_uint32_t) 68: { 1.1.1.2 ! root 69: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 70: } 71: TME_SPARC_FORMAT3(tme_sparc32_stc, tme_uint32_t) 72: { 1.1.1.2 ! root 73: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 74: } 75: TME_SPARC_FORMAT3(tme_sparc32_stcsr, tme_uint32_t) 76: { 1.1.1.2 ! root 77: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 78: } 79: TME_SPARC_FORMAT3(tme_sparc32_stdc, tme_uint32_t) 80: { 1.1.1.2 ! root 81: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 82: } 83: TME_SPARC_FORMAT3(tme_sparc32_stdcq, tme_uint32_t) 84: { 85: TME_SPARC_INSN_PRIV; 1.1.1.2 ! root 86: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 87: } 88: 89: TME_SPARC_FORMAT3(tme_sparc32_rdasr, tme_uint32_t) 90: { 91: unsigned int reg_rs1; 92: unsigned int reg_rd; 93: tme_uint32_t value; 94: 95: reg_rs1 = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, (0x1f << 14)); 96: reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD); 97: 98: /* rdy: */ 99: if (reg_rs1 == 0) { 100: value = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_Y); 101: } 102: 103: /* stbar: */ 104: else if (reg_rs1 == 15 && reg_rd == 0) { 105: TME_SPARC_INSN_OK; 106: } 107: 108: else { 109: 110: /* all other rdasr instructions are privileged: */ 111: TME_SPARC_INSN_PRIV; 112: 113: value = 0; 114: abort(); 115: } 116: 117: TME_SPARC_FORMAT3_RD = value; 118: TME_SPARC_INSN_OK; 119: } 120: 121: TME_SPARC_FORMAT3(tme_sparc32_rdpsr, tme_uint32_t) 122: { 123: TME_SPARC_INSN_PRIV; 124: TME_SPARC_FORMAT3_RD = ic->tme_sparc32_ireg_psr; 125: TME_SPARC_INSN_OK; 126: } 127: 128: TME_SPARC_FORMAT3(tme_sparc32_rdwim, tme_uint32_t) 129: { 130: TME_SPARC_INSN_PRIV; 131: TME_SPARC_FORMAT3_RD = ic->tme_sparc32_ireg_wim; 132: TME_SPARC_INSN_OK; 133: } 134: 135: TME_SPARC_FORMAT3(tme_sparc32_rdtbr, tme_uint32_t) 136: { 137: TME_SPARC_INSN_PRIV; 138: TME_SPARC_FORMAT3_RD = ic->tme_sparc32_ireg_tbr; 139: TME_SPARC_INSN_OK; 140: } 141: 142: TME_SPARC_FORMAT3(tme_sparc32_wrasr, tme_uint32_t) 143: { 144: unsigned int reg_rd; 145: tme_uint32_t value_xor; 146: 147: reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD); 148: value_xor = TME_SPARC_FORMAT3_RS1 ^ TME_SPARC_FORMAT3_RS2; 149: 150: /* "WRY ... writes r[rs1] xor r[rs2] if the i field is zero, or 151: r[rs1] xor sign_ext(simm13) if the i field is one, to the 152: writable fields of the specified IU state register. (Note the 153: exclusive-or operation.) Note that WRY is distinguished from 154: WRASR only by the rd field. The rd field must be zero and op3 = 155: 0x30 to write the Y register." */ 156: if (reg_rd == 0) { 157: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_Y) = value_xor; 158: } 159: 160: else { 161: 162: /* all other wrasr instructions are privileged: */ 163: TME_SPARC_INSN_PRIV; 164: 165: abort(); 166: } 167: 168: TME_SPARC_INSN_OK; 169: } 170: 171: TME_SPARC_FORMAT3(tme_sparc32_wrpsr, tme_uint32_t) 172: { 173: tme_uint32_t value; 174: tme_uint32_t mask_writable; 175: tme_uint32_t insn; 176: unsigned int cwp; 1.1.1.2 ! root 177: unsigned int cwp_offset; 1.1 root 178: 179: TME_SPARC_INSN_PRIV; 180: 1.1.1.2 ! root 181: /* if we haven't detected the idle PC yet: */ ! 182: if (__tme_predict_false(TME_SPARC_IDLE_TYPE_PC_STATE(ic->tme_sparc_idle_pcs_32[0]) != 0)) { ! 183: ! 184: /* "WRPSR ... writes r[rs1] xor r[rs2] if the i field is zero, or ! 185: r[rs1] xor sign_ext(simm13) if the i field is one, to the ! 186: writable fields of the specified IU state register. (Note the ! 187: exclusive-or operation.)" */ ! 188: value = TME_SPARC_FORMAT3_RS1 ^ TME_SPARC_FORMAT3_RS2; ! 189: ! 190: /* the sunos32-type-0 idle type detects these four instructions ! 191: in disassembly order: ! 192: ! 193: swtch(): ! 194: [...] ! 195: rd %psr, %l0 ! 196: andn %l0, 0xf00, %g1 ! 197: or %g1, 0xa00, %g1 ! 198: mov %g1, %psr ! 199: ! 200: and then these two instructions in disassembly order, when ! 201: %g1 sets PIL to 0x0: ! 202: ! 203: sw_testq(): ! 204: [...] ! 205: mov %g1, %psr ! 206: b,a disp22 ; idle() ! 207: ! 208: this detects swtch.s:idle() via swtch() and sw_testq() ! 209: in SunOS/sparc 4.1.4: */ ! 210: if (TME_SPARC_IDLE_TYPE_IS(ic, TME_SPARC_IDLE_TYPE_SUNOS32_TYPE_0)) { ! 211: if (((tme_sparc_fetch_nearby(ic, -3) ! 212: & ~ ((tme_uint32_t) ! 213: ((31 << 14) /* rs1 (reserved) */ ! 214: + (1 << 13) /* i (reserved) */ ! 215: + 0x1fff))) /* imm13 (reserved) */ ! 216: == ((tme_uint32_t) ! 217: (2 << 30) /* format */ ! 218: + (16 << 25) /* rd (%l0) */ ! 219: + (0x29 << 19))) /* op3 (rdpsr) */ ! 220: && (tme_sparc_fetch_nearby(ic, -2) ! 221: == ((tme_uint32_t) ! 222: (2 << 30) /* format */ ! 223: + (1 << 25) /* rd (%g1) */ ! 224: + (0x05 << 19) /* op3 (andn) */ ! 225: + (16 << 14) /* rs1 (%l0) */ ! 226: + (1 << 13) /* i */ ! 227: + TME_SPARC32_PSR_PIL)) ! 228: && (tme_sparc_fetch_nearby(ic, -1) ! 229: == ((tme_uint32_t) ! 230: (2 << 30) /* format */ ! 231: + (1 << 25) /* rd (%g1) */ ! 232: + (0x02 << 19) /* op3 (or) */ ! 233: + (1 << 14) /* rs1 (%g1) */ ! 234: + (1 << 13) /* i */ ! 235: + (0xa * _TME_FIELD_MASK_FACTOR(TME_SPARC32_PSR_PIL)))) ! 236: && ((TME_SPARC_INSN ! 237: & ~ ((tme_uint32_t) ! 238: (31 << 25) /* rd (reserved) */ ! 239: + (255 << 5))) /* unused (zero) */ ! 240: == ((tme_uint32_t) ! 241: (2 << 30) /* format */ ! 242: + (0x31 << 19) /* op3 (wrpsr) */ ! 243: + (1 << 14) /* rs1 (%g1) */ ! 244: + (0 << 13) /* i */ ! 245: + (0 << 0)))) { /* rs2 (%g0) */ ! 246: ! 247: /* enter state two: */ ! 248: ic->tme_sparc_idle_pcs_32[0] = TME_SPARC_IDLE_TYPE_PC_STATE(2); ! 249: } ! 250: else if (ic->tme_sparc_idle_pcs_32[0] == TME_SPARC_IDLE_TYPE_PC_STATE(2) ! 251: && (value & TME_SPARC32_PSR_PIL) == 0 ! 252: && ((TME_SPARC_INSN ! 253: & ~ ((tme_uint32_t) ! 254: (31 << 25) /* rd (reserved) */ ! 255: + (255 << 5))) /* unused (zero) */ ! 256: == ((tme_uint32_t) ! 257: (2 << 30) /* format */ ! 258: + (0x31 << 19) /* op3 (wrpsr) */ ! 259: + (1 << 14) /* rs1 (%g1) */ ! 260: + (0 << 13) /* i */ ! 261: + (0 << 0))) /* rs2 (%g0) */ ! 262: && (((insn = tme_sparc_fetch_nearby(ic, 1)) ! 263: & ~ ((tme_uint32_t) ! 264: 0x3fffff)) /* disp22 */ ! 265: == ((0 << 30) /* format */ ! 266: + (1 << 29) /* a */ ! 267: + ((TME_SPARC_COND_NOT ! 268: + TME_SPARC_COND_N) << 25) /* cond (a) */ ! 269: + (2 << 22)))) { /* op2 (bicc) */ ! 270: ! 271: /* we have detected the idle PC: */ ! 272: ic->tme_sparc_idle_pcs_32[0] ! 273: = (ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC) ! 274: + sizeof(tme_uint32_t) ! 275: + (TME_FIELD_MASK_EXTRACTS(insn, (tme_uint32_t) 0x003fffff) << 2)); ! 276: tme_sparc_recode_invalidate_all(ic); ! 277: } ! 278: ! 279: /* otherwise, reset to state one: */ ! 280: else { ! 281: ic->tme_sparc_idle_pcs_32[0] = TME_SPARC_IDLE_TYPE_PC_STATE(1); ! 282: } ! 283: } ! 284: ! 285: /* the netbsd32-type-0 idle type detects these five instructions ! 286: in disassembly order: ! 287: ! 288: idle_enter(): ! 289: [...] ! 290: wr %l1, 0, %psr ; or wr %g1, 0, %psr ! 291: [any] ! 292: [any] ! 293: bnz,a disp22 ; idle_leave() ! 294: wr %l1, (IPL_SCHED << 8), %psr ; or wr %g1, PSR_PIL, %psr ! 295: ! 296: this detects locore.s:idle_enter() and idle_leave() in ! 297: NetBSD/sparc 1.6 through 4.99.19 (until locore.s revision 1.233 ! 298: on 20070517): */ ! 299: if (TME_SPARC_IDLE_TYPE_IS(ic, TME_SPARC_IDLE_TYPE_NETBSD32_TYPE_0)) { ! 300: if ((value & TME_SPARC32_PSR_PIL) == 0 ! 301: && ((TME_SPARC_INSN ! 302: & ~((tme_uint32_t) ! 303: (31 << 25) /* rd (reserved) */ ! 304: + (16 << 14))) /* rs1 (mask %ln to %gn) */ ! 305: == ((tme_uint32_t) ! 306: (2 << 30) /* format */ ! 307: + (0x31 << 19) /* op3 (wrpsr) */ ! 308: + (1 << 14) /* rs1 (%g1) */ ! 309: + (1 << 13) /* i */ ! 310: + 0)) ! 311: && (((insn = tme_sparc_fetch_nearby(ic, 3)) ! 312: & ~ ((tme_uint32_t) ! 313: 0x3fffff)) /* disp22 */ ! 314: == ((0 << 30) /* format */ ! 315: + (1 << 29) /* a */ ! 316: + ((TME_SPARC_COND_NOT ! 317: + TME_SPARC_COND_E) << 25) /* cond (nz) */ ! 318: + (2 << 22))) /* op2 (bicc) */ ! 319: && ((tme_sparc_fetch_nearby(ic, 4) ! 320: & ~((tme_uint32_t) ! 321: (31 << 25) /* rd (reserved) */ ! 322: + (16 << 14) /* rs1 (mask %ln to %gn) */ ! 323: + (0x4 << 8))) /* imm13 (mask PSR_PIL to (IPL_SCHED << 8)) */ ! 324: == ((tme_uint32_t) ! 325: (2 << 30) /* format */ ! 326: + (0x31 << 19) /* op3 (wrpsr) */ ! 327: + (0x01 << 14) /* rs1 (%g1) */ ! 328: + (1 << 13) /* i */ ! 329: + (0x0b * _TME_FIELD_MASK_FACTOR(TME_SPARC32_PSR_PIL))))) { ! 330: ! 331: /* we have detected the range of idle loop PCs: */ ! 332: ic->tme_sparc_idle_pcs_32[0] ! 333: = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC); ! 334: ic->tme_sparc_idle_pcs_32[1] ! 335: = (ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC) ! 336: + (sizeof(tme_uint32_t) * 3) ! 337: + (TME_FIELD_MASK_EXTRACTS(insn, (tme_uint32_t) 0x003fffff) << 2)); ! 338: tme_sparc_recode_invalidate_all(ic); ! 339: } ! 340: } ! 341: ! 342: /* the netbsd32-type-1 idle type detects these three instructions ! 343: in disassembly order: ! 344: ! 345: cpu_switchto(): ! 346: [...] ! 347: wr %g2, IPL_SCHED << 8 ,%psr ! 348: ret ! 349: restore %g0, %g1, %o0 ! 350: cpu_idle: ! 351: ! 352: this detects locore.s:cpu_idle() via cpu_switchto() in ! 353: NetBSD/sparc 4.99.20 through this current writing ! 354: (starting with locore.s revision 1.233 on 20070517) ! 355: but only in a non-MULTIPROCESSOR kernel: */ ! 356: if (TME_SPARC_IDLE_TYPE_IS(ic, TME_SPARC_IDLE_TYPE_NETBSD32_TYPE_1)) { ! 357: if (((TME_SPARC_INSN ! 358: & ~ ((tme_uint32_t) ! 359: (31 << 25))) /* rd (reserved) */ ! 360: == ((tme_uint32_t) ! 361: (2 << 30) /* format */ ! 362: + (0x31 << 19) /* op3 (wrpsr) */ ! 363: + (2 << 14) /* rs1 (%g2) */ ! 364: + (1 << 13) /* i */ ! 365: + (0xb * _TME_FIELD_MASK_FACTOR(TME_SPARC32_PSR_PIL)))) ! 366: && (tme_sparc_fetch_nearby(ic, 1) ! 367: == ((tme_uint32_t) ! 368: (2 << 30) /* format */ ! 369: + (0 << 25) /* rd (%g0) */ ! 370: + (0x38 << 19) /* op3 (jmpl) */ ! 371: + (31 << 14) /* rs1 (%i7) */ ! 372: + (1 << 13) /* i */ ! 373: + 8)) /* simm13 */ ! 374: && ((tme_sparc_fetch_nearby(ic, 2) ! 375: & ~ ((tme_uint32_t) ! 376: (0xff << 5))) /* unused (zero) */ ! 377: == ((tme_uint32_t) ! 378: (2 << 30) /* format */ ! 379: + (8 << 25) /* rd (%o0) */ ! 380: + (0x3d << 19) /* op3 (restore) */ ! 381: + (0 << 14) /* rs1 (%g0) */ ! 382: + (0 << 13) /* i */ ! 383: + (1 << 0)))) { /* rs2 (%g1) */ ! 384: ! 385: /* we have detected the idle PC: */ ! 386: ic->tme_sparc_idle_pcs_32[0] ! 387: = (ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC) ! 388: + (sizeof(tme_uint32_t) * 3)); ! 389: tme_sparc_recode_invalidate_all(ic); ! 390: } ! 391: } ! 392: } ! 393: ! 394: /* otherwise, if this is the idle PC: */ ! 395: else if (__tme_predict_false(ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC) ! 396: == ic->tme_sparc_idle_pcs_32[0])) { ! 397: ! 398: /* if this idle type has an idle PC range that begins with this ! 399: wrpsr: */ ! 400: if (TME_SPARC_IDLE_TYPE_IS(ic, ! 401: (TME_SPARC_IDLE_TYPE_NETBSD32_TYPE_0 ! 402: ))) { ! 403: ! 404: /* we don't mark an idle now, to avoid duplicating the idle PC ! 405: range checking code in sparc-execute.c. but assuming that ! 406: the idle conditions exist, to accelerate going idle we zero ! 407: the remaining instruction burst: */ ! 408: ic->_tme_sparc_instruction_burst_remaining = 0; ! 409: ic->_tme_sparc_instruction_burst_other = TRUE; ! 410: } ! 411: } ! 412: 1.1 root 413: /* "WRPSR ... writes r[rs1] xor r[rs2] if the i field is zero, or 414: r[rs1] xor sign_ext(simm13) if the i field is one, to the 415: writable fields of the specified IU state register. (Note the 416: exclusive-or operation.)" */ 417: value = TME_SPARC_FORMAT3_RS1 ^ TME_SPARC_FORMAT3_RS2; 418: 419: /* "If the result of a WRPSR instruction would cause the CWP field 420: of the PSR to point to an unimplemented window, it causes an 421: illegal_instruction trap and does not write the PSR." */ 422: cwp = TME_FIELD_MASK_EXTRACTU(value, TME_SPARC32_PSR_CWP); 423: if (__tme_predict_false(cwp >= ic->tme_sparc_nwindows)) { 1.1.1.2 ! root 424: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 425: } 426: 427: /* set the new CWP offset: */ 1.1.1.2 ! root 428: TME_SPARC32_CWP_UPDATE(ic, cwp, cwp_offset); 1.1 root 429: 430: /* set the new PSR value: */ 431: mask_writable = (TME_SPARC32_PSR_ICC 432: | TME_SPARC32_PSR_EC 433: | TME_SPARC32_PSR_EF 434: | TME_SPARC32_PSR_PIL 435: | TME_SPARC32_PSR_S 436: | TME_SPARC32_PSR_PS 437: | TME_SPARC32_PSR_ET 438: | TME_SPARC32_PSR_CWP); 439: value = (value & mask_writable) | (ic->tme_sparc32_ireg_psr & ~mask_writable); 440: ic->tme_sparc32_ireg_psr = value; 441: 442: /* redispatch, since the executor may have cached information 443: derived from the PSR (for example, default data ASI, ITLB, etc.) 444: that we need to invalidate: */ 445: tme_sparc_redispatch(ic); 446: /* NOTREACHED */ 447: } 448: 449: TME_SPARC_FORMAT3(tme_sparc32_wrwim, tme_uint32_t) 450: { 451: tme_uint32_t value; 452: 453: TME_SPARC_INSN_PRIV; 454: 455: /* "WRWIM ... writes r[rs1] xor r[rs2] if the i field is zero, or 456: r[rs1] xor sign_ext(simm13) if the i field is one, to the 457: writable fields of the specified IU state register. (Note the 458: exclusive-or operation.)" */ 459: value = TME_SPARC_FORMAT3_RS1 ^ TME_SPARC_FORMAT3_RS2; 460: 461: /* "A WRWIM with all bits set to 1, followed by a RDWIM, yields a 462: bit vector in which the imple- mented windows (and only the 463: implemented windows) are indicated by 1s." */ 464: value &= (0xffffffff >> (32 - ic->tme_sparc_nwindows)); 465: 466: ic->tme_sparc32_ireg_wim = value; 467: 468: TME_SPARC_INSN_OK; 469: } 470: 471: TME_SPARC_FORMAT3(tme_sparc32_wrtbr, tme_uint32_t) 472: { 473: tme_uint32_t value; 474: 475: TME_SPARC_INSN_PRIV; 476: 477: /* "WRTBR ... writes r[rs1] xor r[rs2] if the i field is zero, or 478: r[rs1] xor sign_ext(simm13) if the i field is one, to the 479: writable fields of the specified IU state register. (Note the 480: exclusive-or operation.)" */ 481: value = TME_SPARC_FORMAT3_RS1 ^ TME_SPARC_FORMAT3_RS2; 482: 483: /* "Bits 11 through 4 comprise the trap type (tt) field. This 8-bit 484: field is written by the hardware when a trap occurs, and retains 485: its value until the next trap. It provides an offset into the 486: trap table. The WRTBR instruction does not affect the tt 487: field. TBR_zero (0) Bits 3 through 0 are zeroes. The WRTBR 488: instruction does not affect this field. For future compatibility, 489: supervisor software should only issue a WRTBR instruction with a 490: zero value in this field." */ 491: value = (value & 0xfffff000) | (ic->tme_sparc32_ireg_tbr & 0x00000ff0); 492: ic->tme_sparc32_ireg_tbr = value; 493: 494: TME_SPARC_INSN_OK; 495: } 496: 497: TME_SPARC_FORMAT3(tme_sparc32_flush, tme_uint32_t) 498: { 499: /* nothing to do */ 500: TME_SPARC_INSN_OK; 501: } 502: 503: TME_SPARC_FORMAT3(tme_sparc32_rett, tme_uint32_t) 504: { 505: tme_uint32_t psr; 506: unsigned int cwp; 1.1.1.2 ! root 507: unsigned int cwp_offset; 1.1 root 508: tme_uint32_t pc_next_next; 509: 510: /* "One of several traps may occur when an RETT is executed. These 511: are described in priority order (highest priority first): 512: 513: If traps are enabled (ET=1) and the processor is in user mode 514: (S=0), a privileged_instruction trap occurs. 515: 516: If traps are enabled (ET=1) and the processor is in supervisor 517: mode (S=1), an illegal_instruction trap occurs. 518: 519: If traps are disabled (ET=0), and (a) the processor is in user 520: mode (S=0), or (b) a window_underflow condition is detected (WIM 521: and 2^new_CWP ) = 1, or (c) either of the low-order two bits of 522: the target address is nonzero, then the processor indicates a 523: trap condition of (a) privileged_instruction, (b) 524: window_underflow, or (c) mem_address_not_aligned (respectively) 525: in the tt field of the TBR register, and enters the error_mode 526: state." */ 527: psr = ic->tme_sparc32_ireg_psr; 528: 529: if (__tme_predict_false((psr & TME_SPARC32_PSR_S) == 0)) { 1.1.1.2 ! root 530: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_privileged_instruction); 1.1 root 531: } 532: 533: if (__tme_predict_false((psr & TME_SPARC32_PSR_ET) != 0)) { 1.1.1.2 ! root 534: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_illegal_instruction); 1.1 root 535: } 536: 537: cwp = TME_FIELD_MASK_EXTRACTU(psr, TME_SPARC32_PSR_CWP); 538: cwp += 1; 539: cwp %= ic->tme_sparc_nwindows; 540: if (ic->tme_sparc32_ireg_wim & (((tme_uint32_t) 1) << cwp)) { 1.1.1.2 ! root 541: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_window_underflow); 1.1 root 542: } 543: 544: pc_next_next = TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2; 545: if (__tme_predict_false((pc_next_next % sizeof(tme_uint32_t)) != 0)) { 1.1.1.2 ! root 546: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_mem_address_not_aligned); 1.1 root 547: } 548: 549: /* set the new PSR: */ 550: TME_FIELD_MASK_DEPOSITU(psr, TME_SPARC32_PSR_CWP, cwp); 551: psr |= TME_SPARC32_PSR_ET; 552: psr &= ~TME_SPARC32_PSR_S; 553: psr |= ((psr & TME_SPARC32_PSR_PS) * (TME_SPARC32_PSR_S / TME_SPARC32_PSR_PS)); 554: ic->tme_sparc32_ireg_psr = psr; 555: 556: /* set the new CWP offset: */ 1.1.1.2 ! root 557: TME_SPARC32_CWP_UPDATE(ic, cwp, cwp_offset); 1.1 root 558: 559: /* set the delayed control transfer: */ 560: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT) = pc_next_next; 561: 562: /* redispatch, since the executor may have cached information 563: derived from the PSR (for example, default data ASI, ITLB, etc.) 564: that we need to invalidate: */ 565: tme_sparc_redispatch(ic); 566: } 567: 568: TME_SPARC_FORMAT3(tme_sparc32_save_restore, tme_uint32_t) 569: { 570: int direction; 571: tme_uint32_t psr; 572: unsigned int cwp; 573: unsigned int cwp_offset; 574: unsigned int reg_rd; 575: 576: /* calculate the window direction: */ 577: direction = -1 + (((TME_SPARC_INSN & TME_BIT(19)) != 0) * 2); 578: 579: /* calculate the new CWP: */ 580: psr = ic->tme_sparc32_ireg_psr; 581: cwp = TME_FIELD_MASK_EXTRACTU(psr, TME_SPARC32_PSR_CWP); 582: cwp += direction; 583: cwp %= ic->tme_sparc_nwindows; 584: 585: /* if the new window is invalid: */ 586: if (__tme_predict_false((ic->tme_sparc32_ireg_wim & (((tme_uint32_t) 1) << cwp)) != 0)) { 587: TME_SPARC_INSN_TRAP((direction < 0) 1.1.1.2 ! root 588: ? TME_SPARC32_TRAP_window_overflow ! 589: : TME_SPARC32_TRAP_window_underflow); 1.1 root 590: } 591: 592: /* write the new PSR: */ 593: TME_FIELD_MASK_DEPOSITU(psr, TME_SPARC32_PSR_CWP, cwp); 594: ic->tme_sparc32_ireg_psr = psr; 595: 596: /* set the new CWP offset: */ 1.1.1.2 ! root 597: TME_SPARC32_CWP_UPDATE(ic, cwp, cwp_offset); 1.1 root 598: 599: /* decode rd: */ 600: reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD); 601: TME_SPARC_REG_INDEX(ic, reg_rd); 602: 603: /* do the add: */ 604: ic->tme_sparc_ireg_uint32(reg_rd) = TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2; 605: 606: TME_SPARC_INSN_OK; 607: } 608: 609: TME_SPARC_FORMAT3(tme_sparc32_ticc, tme_uint32_t) 610: { 611: tme_uint8_t conds_mask_icc; 612: tme_uint16_t conds_mask; 613: unsigned int cond; 614: 615: conds_mask_icc = _tme_sparc_conds_icc[TME_FIELD_MASK_EXTRACTU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_ICC)]; 616: 617: /* add the not-conditions to the conditions mask: */ 618: conds_mask = conds_mask_icc ^ 0xff; 619: conds_mask = (conds_mask << 8) | conds_mask_icc; 620: 621: /* get the condition field: */ 622: cond = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, (0xf << 25)); 623: 624: /* if this condition is true: */ 625: if (conds_mask & TME_BIT(cond)) { 1.1.1.2 ! root 626: TME_SPARC_INSN_TRAP(TME_SPARC32_TRAP_trap_instruction((TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2) & 0x7f)); ! 627: } ! 628: ! 629: TME_SPARC_INSN_OK; ! 630: } ! 631: ! 632: #ifdef TME_HAVE_INT64_T ! 633: ! 634: #undef TME_SPARC_VERSION ! 635: #define TME_SPARC_VERSION(ic) (9) ! 636: ! 637: TME_SPARC_FORMAT3(tme_sparc64_movcc, tme_uint64_t) ! 638: { ! 639: tme_uint32_t insn; ! 640: tme_uint32_t cond; ! 641: tme_uint32_t cc; ! 642: tme_uint32_t conds_mask; ! 643: tme_uint32_t cc_i; ! 644: ! 645: insn = TME_SPARC_INSN; ! 646: ! 647: /* get the cond field: */ ! 648: cond = TME_BIT(TME_FIELD_MASK_EXTRACTU(insn, (0xf << 14))); ! 649: ! 650: /* if cc2 is set, this is an integer instruction: */ ! 651: if (insn & TME_BIT(18)) { ! 652: ! 653: /* if cc0 is set, this is an illegal instruction: */ ! 654: if (__tme_predict_false(insn & TME_BIT(11))) { ! 655: TME_SPARC_INSN_ILL(ic); ! 656: } ! 657: ! 658: /* get %icc or %xcc, depending on cc1: */ ! 659: cc = ic->tme_sparc64_ireg_ccr; ! 660: if (insn & TME_BIT(12)) { ! 661: cc /= (TME_SPARC64_CCR_XCC / TME_SPARC64_CCR_ICC); ! 662: } ! 663: cc = TME_FIELD_MASK_EXTRACTU(cc, TME_SPARC64_CCR_ICC); ! 664: ! 665: /* get the conditions mask: */ ! 666: conds_mask = _tme_sparc_conds_icc[cc]; ! 667: } ! 668: ! 669: /* otherwise, this is a floating-point instruction: */ ! 670: else { ! 671: TME_SPARC_INSN_FPU; ! 672: ! 673: /* get the right %fcc: */ ! 674: cc_i = TME_FIELD_MASK_EXTRACTU(insn, (0x3 << 11)); ! 675: if (cc_i == 0) { ! 676: cc = TME_FIELD_MASK_EXTRACTU(ic->tme_sparc_fpu_fsr, TME_SPARC_FSR_FCC); ! 677: } ! 678: else { ! 679: cc = (ic->tme_sparc_fpu_xfsr >> (2 * (cc_i - 1))) & 0x3; ! 680: } ! 681: ! 682: /* get the conditions mask: */ ! 683: conds_mask = _tme_sparc_conds_fcc[cc]; ! 684: } ! 685: ! 686: /* add the not-conditions to the conditions mask: */ ! 687: conds_mask += ((~conds_mask) << 8); ! 688: ! 689: /* if this condition is true, move the register: */ ! 690: if (conds_mask & cond) { ! 691: TME_SPARC_FORMAT3_RD ! 692: = ((insn & TME_BIT(13)) ! 693: ? TME_FIELD_MASK_EXTRACTS(insn, (tme_uint64_t) 0x7ff) ! 694: : TME_SPARC_FORMAT3_RS2); 1.1 root 695: } 1.1.1.2 ! root 696: TME_SPARC_INSN_OK; ! 697: } ! 698: ! 699: TME_SPARC_FORMAT3(tme_sparc64_movr, tme_uint64_t) ! 700: { ! 701: tme_int64_t rs1; ! 702: tme_uint32_t conds_mask; ! 703: tme_uint32_t insn; ! 704: unsigned int cond; 1.1 root 705: 1.1.1.2 ! root 706: /* make a conditions mask, with the E and LE conditions if the ! 707: register is zero, and with the L and LE conditions if the ! 708: register is less than zero: */ ! 709: rs1 = TME_SPARC_FORMAT3_RS1; ! 710: conds_mask ! 711: = (((rs1 == 0) ! 712: * (TME_BIT(TME_SPARC_COND_E) ! 713: + TME_BIT(TME_SPARC_COND_LE))) ! 714: | ((rs1 < 0) ! 715: * (TME_BIT(TME_SPARC_COND_L) ! 716: + TME_BIT(TME_SPARC_COND_LE)))); ! 717: ! 718: /* add the not-conditions to the conditions mask: */ ! 719: conds_mask += ((~conds_mask) << 4); ! 720: ! 721: /* get the instruction: */ ! 722: insn = TME_SPARC_INSN; ! 723: ! 724: /* get the condition: */ ! 725: cond = TME_FIELD_MASK_EXTRACTU(insn, (0x7 << 10)); ! 726: if (__tme_predict_false((cond & 3) == TME_SPARC_COND_N)) { ! 727: TME_SPARC_INSN_ILL(ic); ! 728: } ! 729: ! 730: /* if the comparison is true, move the register: */ ! 731: if (conds_mask & (1 << cond)) { ! 732: TME_SPARC_FORMAT3_RD ! 733: = ((insn & TME_BIT(13)) ! 734: ? TME_FIELD_MASK_EXTRACTS(insn, (tme_uint64_t) 0x3ff) ! 735: : TME_SPARC_FORMAT3_RS2); ! 736: } 1.1 root 737: TME_SPARC_INSN_OK; 738: } 739: 1.1.1.2 ! root 740: TME_SPARC_FORMAT3(tme_sparc64_tcc, tme_uint64_t) 1.1 root 741: { 1.1.1.2 ! root 742: tme_uint32_t insn; ! 743: tme_uint32_t cc; ! 744: tme_uint32_t conds_mask; ! 745: tme_uint32_t cond; ! 746: tme_uint32_t sw_trap; ! 747: ! 748: insn = TME_SPARC_INSN; ! 749: ! 750: /* if cc0 is set, this is an illegal instruction: */ ! 751: if (__tme_predict_false(insn & TME_BIT(11))) { ! 752: TME_SPARC_INSN_ILL(ic); ! 753: } ! 754: ! 755: /* get %icc or %xcc, depending on cc1: */ ! 756: cc = ic->tme_sparc64_ireg_ccr; ! 757: if (insn & TME_BIT(12)) { ! 758: cc /= (TME_SPARC64_CCR_XCC / TME_SPARC64_CCR_ICC); ! 759: } ! 760: cc = TME_FIELD_MASK_EXTRACTU(cc, TME_SPARC64_CCR_ICC); ! 761: ! 762: /* get the conditions mask: */ ! 763: conds_mask = _tme_sparc_conds_icc[cc]; ! 764: ! 765: /* add the not-conditions to the conditions mask: */ ! 766: conds_mask += ((~conds_mask) << 8); ! 767: ! 768: /* get the cond field: */ ! 769: cond = TME_FIELD_MASK_EXTRACTU(insn, (0xf << 25)); ! 770: ! 771: /* if this condition is true: */ ! 772: if (conds_mask & TME_BIT(cond)) { ! 773: sw_trap ! 774: = ((TME_SPARC_FORMAT3_RS1 ! 775: + ((insn & TME_BIT(13)) ! 776: ? TME_FIELD_MASK_EXTRACTU(insn, 0x7f) ! 777: : TME_SPARC_FORMAT3_RS2)) ! 778: & 0x7f); ! 779: TME_SPARC_INSN_TRAP(TME_SPARC64_TRAP_trap_instruction(sw_trap)); ! 780: } 1.1 root 781: TME_SPARC_INSN_OK; 782: } 1.1.1.2 ! root 783: ! 784: TME_SPARC_FORMAT3(tme_sparc64_save_restore, tme_uint64_t) 1.1 root 785: { 1.1.1.2 ! root 786: tme_uint32_t winstates; ! 787: tme_uint32_t winstates_addend; ! 788: tme_uint32_t trap; ! 789: tme_uint32_t winstates_mask; ! 790: tme_uint32_t cwp; ! 791: unsigned int cwp_offset; ! 792: unsigned int reg_rd; ! 793: ! 794: /* log the save or restore: */ ! 795: tme_sparc_log(ic, 250, TME_OK, ! 796: (TME_SPARC_LOG_HANDLE(ic), ! 797: _("%s cwp %u canrestore %u cansave %u otherwin %u cleanwin %u"), ! 798: ((TME_SPARC_INSN & TME_BIT(19)) ! 799: ? "restore" ! 800: : "save"), ! 801: ic->tme_sparc64_ireg_cwp, ! 802: ic->tme_sparc64_ireg_canrestore, ! 803: ic->tme_sparc64_ireg_cansave, ! 804: ic->tme_sparc64_ireg_otherwin, ! 805: ic->tme_sparc64_ireg_cleanwin)); ! 806: ! 807: /* get the common sparc register-window state registers: */ ! 808: winstates = ic->tme_sparc64_ireg_winstates; ! 809: ! 810: /* assume that this is a restore: */ ! 811: /* "If the RESTORE instruction does not trap, it decrements the CWP ! 812: (mod NWINDOWS) to restore the register window [...] It also ! 813: updates the state of the register windows by decrementing ! 814: CANRESTORE and incrementing CANSAVE." */ ! 815: winstates_addend ! 816: = (TME_SPARC64_WINSTATES_CWP(-1) ! 817: + TME_SPARC64_WINSTATES_CANRESTORE(-1) ! 818: + TME_SPARC64_WINSTATES_CANSAVE(+1)); ! 819: ! 820: /* if this is a save: */ ! 821: if ((TME_SPARC_INSN & TME_BIT(19)) == 0) { ! 822: ! 823: /* "If CANSAVE != 0, the SAVE instruction checks whether the new ! 824: window needs to be cleaned. It causes a clean_window trap if ! 825: the number of unused clean windows is zero, that is, (CLEANWIN ! 826: - CANRESTORE = 0)" */ ! 827: #if TME_SPARC64_WINSTATES_CWP(1) != 1 ! 828: #error "TME_SPARC64_WINSTATES_CWP() changed" ! 829: #endif ! 830: if (__tme_predict_false(ic->tme_sparc64_ireg_cleanwin ! 831: == ((tme_uint8_t) ! 832: (winstates ! 833: / TME_SPARC64_WINSTATES_CANRESTORE(1))))) { ! 834: ! 835: /* NB: we still have to check if CANSAVE == 0; a spill trap ! 836: happens before a clean window trap: */ ! 837: /* NB: if this is a spill trap, the exact trap vector will be ! 838: generated by tme_sparc64_trap(): */ ! 839: trap ! 840: = ((winstates & TME_SPARC64_WINSTATES_CANSAVE(-1)) ! 841: ? TME_SPARC64_TRAP_clean_window ! 842: : TME_SPARC64_TRAP_spill_normal(0)); ! 843: ! 844: /* trap: */ ! 845: tme_sparc64_trap(ic, trap); ! 846: TME_SPARC_INSN_OK; ! 847: } ! 848: ! 849: /* "If the SAVE instruction does not trap, it increments the CWP ! 850: (mod NWINDOWS) to provide a new register window and updates the ! 851: state of the register windows by decrementing CANSAVE and ! 852: incrementing CANRESTORE." */ ! 853: winstates_addend ! 854: = (TME_SPARC64_WINSTATES_CWP(+1) ! 855: + TME_SPARC64_WINSTATES_CANRESTORE(+1) ! 856: + TME_SPARC64_WINSTATES_CANSAVE(-1)); ! 857: } ! 858: ! 859: /* update the common sparc register-window state registers: */ ! 860: winstates += winstates_addend; ! 861: ! 862: /* get any mask for the common sparc register-window state registers: */ ! 863: winstates_mask = ic->tme_sparc64_ireg_winstates_mask; ! 864: ! 865: /* iff this instruction traps, one of CANRESTORE and CANSAVE (the ! 866: one that this instruction decrements) must not have carried out ! 867: of its -1 addend: */ ! 868: if (__tme_predict_false((winstates ! 869: & (TME_SPARC64_WINSTATES_CANRESTORE(-1) ! 870: + TME_SPARC64_WINSTATES_CANRESTORE(1) ! 871: + TME_SPARC64_WINSTATES_CANSAVE(-1) ! 872: + TME_SPARC64_WINSTATES_CANSAVE(1))) == 0)) { ! 873: ! 874: /* NB: the exact spill or fill trap vector will be generated by ! 875: tme_sparc64_trap(): */ ! 876: trap ! 877: = ((TME_SPARC_INSN & TME_BIT(19)) ! 878: ? TME_SPARC64_TRAP_fill_normal(0) ! 879: : TME_SPARC64_TRAP_spill_normal(0)); ! 880: ! 881: /* trap: */ ! 882: tme_sparc64_trap(ic, trap); ! 883: TME_SPARC_INSN_OK; ! 884: } ! 885: ! 886: /* if the common sparc register-window state registers can be ! 887: masked: */ ! 888: assert (winstates_mask != 0); ! 889: if (TRUE) { ! 890: ! 891: /* write the updated common sparc register-window state registers: */ ! 892: winstates &= winstates_mask; ! 893: ic->tme_sparc64_ireg_winstates = winstates; ! 894: ! 895: /* get the updated CWP: */ ! 896: #if TME_SPARC64_WINSTATES_CWP(1) != 1 ! 897: #error "TME_SPARC64_WINSTATES_CWP() changed" ! 898: #endif ! 899: cwp = (tme_uint8_t) (winstates / TME_SPARC64_WINSTATES_CWP(1)); ! 900: } ! 901: ! 902: /* set the new CWP offset: */ ! 903: TME_SPARC64_CWP_UPDATE(ic, cwp, cwp_offset); ! 904: ! 905: /* decode rd: */ ! 906: reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD); ! 907: TME_SPARC_REG_INDEX(ic, reg_rd); ! 908: ! 909: /* do the add: */ ! 910: ic->tme_sparc_ireg_uint64(reg_rd) = TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2; ! 911: 1.1 root 912: TME_SPARC_INSN_OK; 913: } 914: 1.1.1.2 ! root 915: TME_SPARC_FORMAT3(tme_sparc64_return, tme_uint64_t) ! 916: { ! 917: unsigned int reg_i0; ! 918: tme_uint32_t winstates; ! 919: tme_uint64_t pc_next_next; ! 920: tme_uint32_t ls_faults; ! 921: tme_uint32_t winstates_mask; ! 922: tme_uint32_t cwp; ! 923: unsigned int cwp_offset; ! 924: ! 925: /* log the return: */ ! 926: reg_i0 = 24; ! 927: TME_SPARC_REG_INDEX(ic, reg_i0); ! 928: tme_sparc_log(ic, 250, TME_OK, ! 929: (TME_SPARC_LOG_HANDLE(ic), ! 930: _("return 0x%016" TME_PRIx64 " cwp %u canrestore %u cansave %u otherwin %u cleanwin %u %%i0 0x%016" TME_PRIx64" %%g1 0x%016" TME_PRIx64" %%g2 0x%016" TME_PRIx64" %%g3 0x%016" TME_PRIx64" %%g4 0x%016" TME_PRIx64" %%g5 0x%016" TME_PRIx64), ! 931: (TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2), ! 932: ic->tme_sparc64_ireg_cwp, ! 933: ic->tme_sparc64_ireg_canrestore, ! 934: ic->tme_sparc64_ireg_cansave, ! 935: ic->tme_sparc64_ireg_otherwin, ! 936: ic->tme_sparc64_ireg_cleanwin, ! 937: ic->tme_sparc_ireg_uint64(reg_i0), ! 938: ic->tme_sparc_ireg_uint64(TME_SPARC_G0_OFFSET(ic) + TME_SPARC_IREG_G1), ! 939: ic->tme_sparc_ireg_uint64(TME_SPARC_G0_OFFSET(ic) + TME_SPARC_IREG_G2), ! 940: ic->tme_sparc_ireg_uint64(TME_SPARC_G0_OFFSET(ic) + TME_SPARC_IREG_G3), ! 941: ic->tme_sparc_ireg_uint64(TME_SPARC_G0_OFFSET(ic) + TME_SPARC_IREG_G4), ! 942: ic->tme_sparc_ireg_uint64(TME_SPARC_G0_OFFSET(ic) + TME_SPARC_IREG_G5))); ! 943: ! 944: /* get the common sparc register-window state registers: */ ! 945: winstates = ic->tme_sparc64_ireg_winstates; ! 946: ! 947: /* "The RETURN instruction [...] has the window semantics of a ! 948: RESTORE instruction" */ ! 949: /* "If the RESTORE instruction does not trap, it decrements the CWP ! 950: (mod NWINDOWS) to restore the register window [...] It also ! 951: updates the state of the register windows by decrementing ! 952: CANRESTORE and incrementing CANSAVE." */ ! 953: winstates ! 954: += (TME_SPARC64_WINSTATES_CWP(-1) ! 955: + TME_SPARC64_WINSTATES_CANRESTORE(-1) ! 956: + TME_SPARC64_WINSTATES_CANSAVE(+1)); ! 957: ! 958: /* if CANRESTORE didn't carry out of its -1 addend: */ ! 959: if (__tme_predict_false((winstates ! 960: & (TME_SPARC64_WINSTATES_CANRESTORE(-1) ! 961: + TME_SPARC64_WINSTATES_CANRESTORE(1))) == 0)) { ! 962: ! 963: /* trap: */ ! 964: /* NB: the exact fill trap vector will be generated by ! 965: tme_sparc64_trap(): */ ! 966: tme_sparc64_trap(ic, TME_SPARC64_TRAP_fill_normal(0)); ! 967: TME_SPARC_INSN_OK; ! 968: } ! 969: ! 970: /* get the target address: */ ! 971: pc_next_next = TME_SPARC_FORMAT3_RS1 + TME_SPARC_FORMAT3_RS2; ! 972: pc_next_next &= ic->tme_sparc_address_mask; ! 973: ! 974: /* do the delayed control transfer: */ ! 975: ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT_NEXT) = pc_next_next; ! 976: ! 977: /* check that the target address is aligned and not in the virtual ! 978: address hole: */ ! 979: ls_faults = TME_SPARC_LS_FAULT_NONE; ! 980: if (__tme_predict_false((pc_next_next ! 981: + ic->tme_sparc64_ireg_va_hole_start) ! 982: > ((ic->tme_sparc64_ireg_va_hole_start * 2) - 1))) { ! 983: ls_faults += TME_SPARC64_LS_FAULT_VA_RANGE_NNPC; ! 984: } ! 985: if (__tme_predict_false(((unsigned int) pc_next_next) % sizeof(tme_uint32_t))) { ! 986: ls_faults += TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED; ! 987: } ! 988: ! 989: /* if the target address has caused a trap: */ ! 990: if (__tme_predict_false(ls_faults != TME_SPARC_LS_FAULT_NONE)) { ! 991: tme_sparc_nnpc_trap(ic, ls_faults); ! 992: } ! 993: ! 994: /* get any mask for the common sparc register-window state registers: */ ! 995: winstates_mask = ic->tme_sparc64_ireg_winstates_mask; ! 996: ! 997: /* if the common sparc register-window state registers can be ! 998: masked: */ ! 999: assert (winstates_mask != 0); ! 1000: if (TRUE) { ! 1001: ! 1002: /* write the updated common sparc register-window state registers: */ ! 1003: winstates &= winstates_mask; ! 1004: ic->tme_sparc64_ireg_winstates = winstates; ! 1005: ! 1006: /* get the updated CWP: */ ! 1007: #if TME_SPARC64_WINSTATES_CWP(1) != 1 ! 1008: #error "TME_SPARC64_WINSTATES_CWP() changed" ! 1009: #endif ! 1010: cwp = (tme_uint8_t) (winstates / TME_SPARC64_WINSTATES_CWP(1)); ! 1011: } ! 1012: ! 1013: /* set the new CWP offset: */ ! 1014: TME_SPARC64_CWP_UPDATE(ic, cwp, cwp_offset); ! 1015: ! 1016: /* redispatch, since if we're running from a recode instructions ! 1017: thunk, and we don't redispatch, our pc_next_next will be lost: */ ! 1018: /* XXX FIXME - return is too complicated to not need an assist, but ! 1019: if we could preserve its pc_next_next in the insns thunk, we ! 1020: could avoid this expensive redispatch: */ ! 1021: tme_sparc_redispatch(ic); ! 1022: } ! 1023: ! 1024: TME_SPARC_FORMAT3(tme_sparc64_saved_restored, tme_uint64_t) ! 1025: { ! 1026: tme_uint32_t insn; ! 1027: tme_uint32_t winstates_addend_insn; ! 1028: tme_uint32_t winstates_addend_otherwin; ! 1029: tme_uint32_t cleanwin; ! 1030: tme_uint32_t winstates; ! 1031: tme_uint32_t winstates_mask; ! 1032: ! 1033: TME_SPARC_INSN_PRIV; ! 1034: ! 1035: /* log the saved or restored: */ ! 1036: tme_sparc_log(ic, 250, TME_OK, ! 1037: (TME_SPARC_LOG_HANDLE(ic), ! 1038: _("%s cwp %u canrestore %u cansave %u otherwin %u cleanwin %u"), ! 1039: ((TME_SPARC_INSN & TME_BIT(25)) ! 1040: ? "restored" ! 1041: : "saved"), ! 1042: ic->tme_sparc64_ireg_cwp, ! 1043: ic->tme_sparc64_ireg_canrestore, ! 1044: ic->tme_sparc64_ireg_cansave, ! 1045: ic->tme_sparc64_ireg_otherwin, ! 1046: ic->tme_sparc64_ireg_cleanwin)); ! 1047: ! 1048: insn = TME_SPARC_INSN; ! 1049: ! 1050: /* if fcn is greater than one (if any of bits 26 through 29 are ! 1051: set), this is an illegal instruction: */ ! 1052: if (__tme_predict_false(insn & (TME_BIT(30) - TME_BIT(26)))) { ! 1053: TME_SPARC_INSN_ILL(ic); ! 1054: } ! 1055: ! 1056: /* assume that this is a saved: */ ! 1057: /* "SAVED increments CANSAVE. If OTHERWIN = 0, it decrements ! 1058: CANRESTORE. If OTHERWIN != 0, it decrements OTHERWIN. */ ! 1059: winstates_addend_insn = TME_SPARC64_WINSTATES_CANSAVE(+1); ! 1060: winstates_addend_otherwin = TME_SPARC64_WINSTATES_CANRESTORE(-1); ! 1061: ! 1062: /* if this is a restored: */ ! 1063: if (insn & TME_BIT(25)) { ! 1064: ! 1065: /* "RESTORED increments CANRESTORE. If CLEANWIN < (NWINDOWS - 1), ! 1066: RESTORED increments CLEANWIN. If OTHERWIN = 0, it decrements ! 1067: CANSAVE. If OTHERWIN != 0, it decrements OTHERWIN" */ ! 1068: cleanwin = ic->tme_sparc64_ireg_cleanwin + 1; ! 1069: cleanwin -= (cleanwin >= ic->tme_sparc_nwindows); ! 1070: ic->tme_sparc64_ireg_cleanwin = cleanwin; ! 1071: winstates_addend_insn = TME_SPARC64_WINSTATES_CANRESTORE(+1); ! 1072: winstates_addend_otherwin = TME_SPARC64_WINSTATES_CANSAVE(-1); ! 1073: } ! 1074: ! 1075: /* get the common sparc register-window state registers and ! 1076: increment either CANSAVE or CANRESTORE: */ ! 1077: winstates = winstates_addend_insn; ! 1078: winstates += ic->tme_sparc64_ireg_winstates; ! 1079: ! 1080: /* if OTHERWIN is nonzero, decrement OTHERWIN instead of the ! 1081: other of CANSAVE or CANRESTORE: */ ! 1082: if (winstates & TME_SPARC64_WINSTATES_OTHERWIN(-1)) { ! 1083: winstates_addend_otherwin = TME_SPARC64_WINSTATES_OTHERWIN(-1); ! 1084: } ! 1085: winstates += winstates_addend_otherwin; ! 1086: ! 1087: /* get any mask for the common sparc register-window state registers: */ ! 1088: winstates_mask = ic->tme_sparc64_ireg_winstates_mask; ! 1089: ! 1090: /* if the common sparc register-window state registers can be ! 1091: masked: */ ! 1092: assert (winstates_mask != 0); ! 1093: if (TRUE) { ! 1094: ! 1095: /* write the updated common sparc register-window state registers: */ ! 1096: winstates &= winstates_mask; ! 1097: ic->tme_sparc64_ireg_winstates = winstates; ! 1098: } ! 1099: ! 1100: TME_SPARC_INSN_OK; ! 1101: } ! 1102: ! 1103: TME_SPARC_FORMAT3(tme_sparc64_flushw, tme_uint64_t) ! 1104: { ! 1105: /* "FLUSHW acts as a NOP if CANSAVE = NWINDOWS - 2. ! 1106: Otherwise, there is more than one active window, so ! 1107: FLUSHW causes a spill exception." */ ! 1108: if ((ic->tme_sparc64_ireg_cansave + 2) ! 1109: != TME_SPARC_NWINDOWS(ic)) { ! 1110: ! 1111: /* NB: the exact spill vector will be generated by ! 1112: tme_sparc64_trap(): */ ! 1113: tme_sparc64_trap(ic, TME_SPARC64_TRAP_spill_normal(0)); ! 1114: } ! 1115: ! 1116: /* if we haven't detected the idle PC yet: */ ! 1117: if (__tme_predict_false(TME_SPARC_IDLE_TYPE_PC_STATE(ic->tme_sparc_idle_pcs_64[0]) != 0)) { ! 1118: ! 1119: /* the netbsd64-type-1 idle type detects these five instructions ! 1120: in disassembly order: ! 1121: ! 1122: cpu_idle(): ! 1123: retl ! 1124: nop ! 1125: cpu_switchto(): ! 1126: save %sp, simm13, %sp ! 1127: flushw ! 1128: wrpr %g0, PSTATE_KERN, %pstate ! 1129: ! 1130: this detects locore.s:cpu_idle() via cpu_switchto() in ! 1131: NetBSD/sparc64 4.99.21 through this current writing ! 1132: (starting with locore.s revision 1.250 on 20070528): */ ! 1133: /* NB: in locore.s revisions 1.244 through 1.249, there was an ! 1134: additional flushw at the beginning of cpu_switchto(). we ! 1135: assume that nobody cares about -current kernels from this ! 1136: period not idling, and don't detect this: */ ! 1137: if (TME_SPARC_IDLE_TYPE_IS(ic, TME_SPARC_IDLE_TYPE_NETBSD64_TYPE_1)) { ! 1138: if ((tme_sparc_fetch_nearby(ic, -3) ! 1139: == ((tme_uint32_t) ! 1140: (2 << 30) /* format */ ! 1141: + (0 << 25) /* rd (%g0) */ ! 1142: + (0x38 << 19) /* op3 (jmpl) */ ! 1143: + (15 << 14) /* rs1 (%o7) */ ! 1144: + (1 << 13) /* i */ ! 1145: + 8)) /* simm13 */ ! 1146: && (tme_sparc_fetch_nearby(ic, -2) ! 1147: == ((0 << 30) /* format */ ! 1148: + (0 << 25) /* rd (%g0) */ ! 1149: + (4 << 22) ! 1150: + 0)) /* imm22 */ ! 1151: && ((tme_sparc_fetch_nearby(ic, -1) ! 1152: & (0 - (tme_uint32_t) (1 << 13))) ! 1153: == ((tme_uint32_t) ! 1154: (2 << 30) /* format */ ! 1155: + (14 << 25) /* rd (%o6) */ ! 1156: + (0x3c << 19) /* op3 (save) */ ! 1157: + (14 << 14) /* rs1 (%o6) */ ! 1158: + (1 << 13))) ! 1159: && ((tme_sparc_fetch_nearby(ic, 1) ! 1160: & ~ (tme_uint32_t) TME_SPARC64_PSTATE_AM) ! 1161: == ((tme_uint32_t) ! 1162: (2 << 30) /* format */ ! 1163: + (6 << 25) /* %pstate */ ! 1164: + (0x32 << 19) /* op3 (wrpr) */ ! 1165: + (0 << 14) /* rs1 (%g0) */ ! 1166: + (1 << 13) /* i */ ! 1167: + TME_SPARC64_PSTATE_PRIV))) { ! 1168: ! 1169: /* we have detected the idle PC: */ ! 1170: ic->tme_sparc_idle_pcs_64[0] ! 1171: = (ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC) ! 1172: - (sizeof(tme_uint32_t) * 3)); ! 1173: tme_sparc_recode_invalidate_all(ic); ! 1174: } ! 1175: } ! 1176: } ! 1177: ! 1178: TME_SPARC_INSN_OK; ! 1179: } ! 1180: ! 1181: TME_SPARC_FORMAT3(tme_sparc64_prefetch, tme_uint64_t) ! 1182: { ! 1183: tme_uint32_t fcn; ! 1184: ! 1185: /* "In nonprivileged code, a prefetch instruction has the same ! 1186: observable effect as a NOP; its execution is nonblocking and ! 1187: cannot cause an observable trap. In particular, a prefetch ! 1188: instruction shall not trap if it is applied to an illegal or ! 1189: nonexistent memory address." */ ! 1190: /* we interpret this to mean that there are no ASI and address ! 1191: combinations that can cause a privileged_action trap, which means ! 1192: we can ignore them altogether: */ ! 1193: /* NB: we assume that all sparc64 implementations treat prefetch ! 1194: the same for privileged and nonprivileged code: */ ! 1195: ! 1196: fcn = TME_SPARC_INSN & (0x1f << 25); ! 1197: fcn -= (5 << 25); ! 1198: if (__tme_predict_false(fcn <= ((15 - 5) << 25))) { ! 1199: TME_SPARC_INSN_ILL(ic); ! 1200: } ! 1201: ! 1202: TME_SPARC_INSN_OK; ! 1203: } ! 1204: ! 1205: TME_SPARC_FORMAT3(tme_sparc64_rdpr, tme_uint64_t) ! 1206: { ! 1207: unsigned int reg_rs1; ! 1208: unsigned int tl; ! 1209: tme_uint64_t value; ! 1210: tme_uint64_t va_hole_start; ! 1211: ! 1212: TME_SPARC_INSN_PRIV; ! 1213: ! 1214: /* assume that we aren't reading a virtual address that can't be in ! 1215: any virtual address hole: */ ! 1216: va_hole_start = 0; ! 1217: ! 1218: /* dispatch on rs1: */ ! 1219: reg_rs1 = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RS1); ! 1220: switch (reg_rs1) { ! 1221: ! 1222: /* TPC, TNPC, TSTATE, TT: */ ! 1223: case 0: ! 1224: case 1: ! 1225: case 2: ! 1226: case 3: ! 1227: tl = ic->tme_sparc64_ireg_tl; ! 1228: if (tl > 0) { ! 1229: switch (reg_rs1) { ! 1230: case 0: ! 1231: value = ic->tme_sparc64_ireg_tpc(tl); ! 1232: va_hole_start = ic->tme_sparc64_ireg_va_hole_start; ! 1233: break; ! 1234: case 1: ! 1235: value = ic->tme_sparc64_ireg_tnpc(tl); ! 1236: va_hole_start = ic->tme_sparc64_ireg_va_hole_start; ! 1237: break; ! 1238: case 2: value = ic->tme_sparc64_ireg_tstate(tl); break; ! 1239: default: value = ic->tme_sparc64_ireg_tt(tl); break; ! 1240: } ! 1241: break; ! 1242: } ! 1243: /* FALLTHROUGH */ ! 1244: ! 1245: default: ! 1246: TME_SPARC_INSN_ILL(ic); ! 1247: TME_SPARC_INSN_OK; ! 1248: ! 1249: /* TICK: */ ! 1250: case 4: ! 1251: tme_sparc_recode_verify_reg_tick(ic, &TME_SPARC_FORMAT3_RD); ! 1252: if (tme_sparc_recode_verify_replay_last_pc(ic) != 0) { ! 1253: TME_SPARC_INSN_OK; ! 1254: } ! 1255: value = tme_misc_cycles_scaled(&ic->tme_sparc_cycles_scaling, 0).tme_value64_uint; ! 1256: value += ic->tme_sparc64_ireg_tick_offset; ! 1257: value &= TME_SPARC64_TICK_COUNTER; ! 1258: if (__tme_predict_false(ic->tme_sparc64_ireg_tick_npt)) { ! 1259: value |= TME_SPARC64_TICK_NPT; ! 1260: } ! 1261: tme_sparc_recode_verify_reg_tick_now(ic, &value); ! 1262: break; ! 1263: ! 1264: case 5: ! 1265: value = ic->tme_sparc64_ireg_tba; ! 1266: va_hole_start = ic->tme_sparc64_ireg_va_hole_start; ! 1267: break; ! 1268: case 6: value = ic->tme_sparc64_ireg_pstate; break; ! 1269: case 7: value = ic->tme_sparc64_ireg_tl; break; ! 1270: case 8: value = ic->tme_sparc64_ireg_pil; break; ! 1271: case 9: value = ic->tme_sparc64_ireg_cwp; break; ! 1272: case 10: value = ic->tme_sparc64_ireg_cansave; break; ! 1273: case 11: value = ic->tme_sparc64_ireg_canrestore; break; ! 1274: case 12: value = ic->tme_sparc64_ireg_cleanwin; break; ! 1275: case 13: value = ic->tme_sparc64_ireg_otherwin; break; ! 1276: case 14: value = ic->tme_sparc64_ireg_wstate; break; ! 1277: ! 1278: /* XXX FIXME - add support for implementations with an FQ: */ ! 1279: #if 0 ! 1280: /* FQ: */ ! 1281: case 15: ! 1282: break; ! 1283: #endif /* 0 */ ! 1284: ! 1285: case 31: value = ic->tme_sparc64_ireg_ver; break; ! 1286: } ! 1287: ! 1288: /* get any virtual address hole form value: */ ! 1289: value = value | (0 - (va_hole_start * 2)); ! 1290: value = (value ^ va_hole_start) + va_hole_start; ! 1291: ! 1292: TME_SPARC_FORMAT3_RD = value; ! 1293: TME_SPARC_INSN_OK; ! 1294: } ! 1295: ! 1296: /* this detects the sunos64-type-0 idle type during an splhigh() ! 1297: call: */ ! 1298: static void ! 1299: _tme_sparc64_idle_type_sunos64_type_0_splhigh(struct tme_sparc *ic) ! 1300: { ! 1301: tme_uint64_t address_splhigh; ! 1302: unsigned int reg_index; ! 1303: tme_uint64_t address_call_splhigh; ! 1304: tme_uint32_t insn_ld; ! 1305: tme_uint64_t address_t_startpc; ! 1306: tme_uint32_t dtlb_hash; ! 1307: const struct tme_sparc_tlb *dtlb; ! 1308: const tme_shared tme_uint8_t *memory; ! 1309: tme_uint64_t address_idle; ! 1310: int size_idle; ! 1311: ! 1312: /* at this point, we have already detected that we are in splhigh(): ! 1313: ! 1314: splhigh(): ! 1315: rdpr %pil, %o1 ! 1316: [any] ! 1317: [any] ! 1318: [any] ! 1319: wrpr 0xa, %pil ! 1320: ! 1321: PC is at the wrpr instruction. get the address of splhigh(): */ ! 1322: address_splhigh ! 1323: = (ic->tme_sparc_ireg_int64(TME_SPARC_IREG_PC) ! 1324: - (sizeof(tme_uint32_t) ! 1325: * 4)); ! 1326: ! 1327: /* we want to detect when splhigh() has been called as part of these ! 1328: instructions in disp.c:disp(), in disassembly order: ! 1329: ! 1330: disp(): ! 1331: [...] ! 1332: call disp_getwork ! 1333: mov %i3, %o0 ! 1334: orcc %g0, %o0, %l0 ! 1335: bne,a disp+any ! 1336: [any] ! 1337: call splhigh ! 1338: ld [ %i3 + any ], %l0 ! 1339: ! 1340: when disp() has no thread to run on this CPU, it calls ! 1341: disp.c:disp_getwork() to see if it can get a thread to run from ! 1342: another CPU. if it can't get a thread to run, it calls splhigh() ! 1343: before setting the idle thread to run. ! 1344: ! 1345: the delay slot after the splhigh() call loads the kthread_t * for ! 1346: the idle thread into %l0. ! 1347: ! 1348: the third address-sized member of a kthread_t is the initial PC ! 1349: for the thread, which for the idle thread will be disp.c:idle(). ! 1350: ! 1351: since splhigh() doesn't establish its own register window, as ! 1352: long as we can detect the specific splhigh() call above, will be ! 1353: able to detect the address of idle() through it's caller's %l0. ! 1354: ! 1355: the challenge is to detect this specific splhigh() call. we take ! 1356: advantage of the fact that disp_getwork() contains its own call ! 1357: to splhigh(), and since splhigh() doesn't establish its own ! 1358: register window, the return address that its caller will use ! 1359: should be in %i7: */ ! 1360: ! 1361: /* assume that splhigh()'s caller is disp_getwork(), and that ! 1362: disp_getwork()'s caller is disp(), and get what should be the ! 1363: address of the disp() call to splhigh(): */ ! 1364: reg_index = 31; /* %i7 */ ! 1365: TME_SPARC_REG_INDEX(ic, reg_index); ! 1366: address_call_splhigh ! 1367: = (ic->tme_sparc_ireg_uint64(reg_index) ! 1368: + (sizeof(tme_uint32_t) ! 1369: * 5)); ! 1370: ! 1371: /* if this is a call to splhigh(): */ ! 1372: if (tme_sparc_insn_peek(ic, ! 1373: address_call_splhigh) ! 1374: == ((((tme_uint32_t) 0x1) << 30) /* format */ ! 1375: + (((address_splhigh ! 1376: - address_call_splhigh) ! 1377: / sizeof(tme_uint32_t)) ! 1378: & ((1 << 30) - 1)))) { /* disp30 */ ! 1379: ! 1380: /* if the next instruction is a ld or ldx of %l0: */ ! 1381: insn_ld ! 1382: = tme_sparc_insn_peek(ic, ! 1383: (address_call_splhigh ! 1384: + sizeof(tme_uint32_t))); ! 1385: if (((insn_ld ! 1386: & ((tme_uint32_t) ! 1387: (0x3 << 30) ! 1388: + TME_SPARC_FORMAT3_MASK_RD)) ! 1389: == ((tme_uint32_t) ! 1390: (0x3 << 30) /* format */ ! 1391: + (16 << 25))) /* rd (%l0) */ ! 1392: && (((insn_ld & (0x3f << 19)) ! 1393: == (0x00 << 19)) /* op3 (ld) */ ! 1394: || ((insn_ld & (0x3f << 19)) ! 1395: == (0x0b << 19)))) { /* op3 (ldx) */ ! 1396: ! 1397: /* we have detected the disp() call of splhigh(). enter state ! 1398: two: */ ! 1399: ic->tme_sparc_idle_pcs_64[0] ! 1400: = (address_call_splhigh ! 1401: + TME_SPARC_IDLE_TYPE_PC_STATE(2)); ! 1402: } ! 1403: } ! 1404: ! 1405: /* if this is the splhigh() call from disp(): */ ! 1406: reg_index = 15; /* %o7 */ ! 1407: TME_SPARC_REG_INDEX(ic, reg_index); ! 1408: if (ic->tme_sparc_ireg_uint64(reg_index) ! 1409: == (ic->tme_sparc_idle_pcs_64[0] ! 1410: - TME_SPARC_IDLE_TYPE_PC_STATE(2))) { ! 1411: ! 1412: /* get the address of the t_startpc member in the kthread_t * in ! 1413: %l0. the t_startpc member is the third address-sized ! 1414: member: */ ! 1415: reg_index = 16; /* %l0 */ ! 1416: TME_SPARC_REG_INDEX(ic, reg_index); ! 1417: address_t_startpc = ic->tme_sparc_ireg_uint64(reg_index); ! 1418: address_t_startpc ! 1419: += ((ic->tme_sparc64_ireg_pstate ! 1420: & TME_SPARC64_PSTATE_AM) ! 1421: ? (sizeof(tme_uint32_t) * 2) ! 1422: : (sizeof(tme_uint64_t) * 2)); ! 1423: address_t_startpc &= ic->tme_sparc_address_mask; ! 1424: ! 1425: /* get the DTLB entry for the t_startpc member: */ ! 1426: dtlb_hash ! 1427: = TME_SPARC_TLB_HASH(ic, ! 1428: ic->tme_sparc_memory_context_default, ! 1429: address_t_startpc); ! 1430: dtlb = &ic->tme_sparc_tlbs[TME_SPARC_DTLB_ENTRY(ic, dtlb_hash)]; ! 1431: ! 1432: /* if the t_startpc member hits the DTLB: */ ! 1433: memory = dtlb->tme_sparc_tlb_emulator_off_read; ! 1434: if (tme_bus_tlb_is_valid(&dtlb->tme_sparc_tlb_bus_tlb) ! 1435: && dtlb->tme_sparc_tlb_context == ic->tme_sparc_memory_context_default ! 1436: && address_t_startpc >= (tme_bus_addr64_t) dtlb->tme_sparc_tlb_addr_first ! 1437: && (address_t_startpc + sizeof(tme_uint64_t) - 1) <= (tme_bus_addr64_t) dtlb->tme_sparc_tlb_addr_last ! 1438: && TME_SPARC_TLB_ASI_MASK_OK(dtlb, ic->tme_sparc_asi_mask_data) ! 1439: && (dtlb->tme_sparc_tlb_asi_mask & TME_SPARC64_ASI_FLAG_NO_FAULT) == 0 ! 1440: && memory != TME_EMULATOR_OFF_UNDEF) { ! 1441: ! 1442: /* read the t_startpc member: */ ! 1443: if (ic->tme_sparc64_ireg_pstate ! 1444: & TME_SPARC64_PSTATE_AM) { ! 1445: address_idle ! 1446: = tme_memory_bus_read32((const tme_shared tme_uint32_t *) (memory + address_t_startpc), ! 1447: dtlb->tme_sparc_tlb_bus_rwlock, ! 1448: sizeof(tme_uint32_t), ! 1449: sizeof(tme_uint64_t)); ! 1450: address_idle = tme_betoh_u32(address_idle); ! 1451: } ! 1452: else { ! 1453: address_idle ! 1454: = tme_memory_bus_read64((const tme_shared tme_uint64_t *) (memory + address_t_startpc), ! 1455: dtlb->tme_sparc_tlb_bus_rwlock, ! 1456: sizeof(tme_uint64_t), ! 1457: sizeof(tme_uint64_t)); ! 1458: address_idle = tme_betoh_u64(address_idle); ! 1459: } ! 1460: ! 1461: /* get the size of idle(): */ ! 1462: for (size_idle = 1; size_idle < 150; size_idle++) { ! 1463: ! 1464: /* if this is a save instruction: */ ! 1465: if ((tme_sparc_insn_peek(ic, ! 1466: (address_idle ! 1467: + (size_idle ! 1468: * sizeof(tme_uint32_t)))) ! 1469: & ((tme_uint32_t) ! 1470: (0x3 << 30) /* format */ ! 1471: + (0x3f << 19))) /* op3 */ ! 1472: == ((tme_uint32_t) ! 1473: (2 << 30) /* format */ ! 1474: + (0x3c << 19))) { /* op3 (save) */ ! 1475: break; ! 1476: } ! 1477: } ! 1478: ! 1479: /* we have detected idle(): */ ! 1480: ic->tme_sparc_idle_pcs_64[0] = address_idle; ! 1481: ic->tme_sparc_idle_pcs_64[1] = address_idle + (size_idle * sizeof(tme_uint32_t)); ! 1482: tme_sparc_recode_invalidate_all(ic); ! 1483: } ! 1484: } ! 1485: } ! 1486: ! 1487: TME_SPARC_FORMAT3(tme_sparc64_wrpr, tme_uint64_t) ! 1488: { ! 1489: unsigned int reg_rd; ! 1490: tme_uint64_t value_xor; ! 1491: tme_uint64_t va_hole_start; ! 1492: tme_uint64_t value_xor_va_hole; ! 1493: unsigned int tl; ! 1494: unsigned int pil; ! 1495: signed int pil_change; ! 1496: unsigned int cwp; ! 1497: unsigned int cwp_offset; ! 1498: ! 1499: TME_SPARC_INSN_PRIV; ! 1500: ! 1501: /* get the xor form value to write: */ ! 1502: value_xor = TME_SPARC_FORMAT3_RS1 ^ TME_SPARC_FORMAT3_RS2; ! 1503: ! 1504: /* get the xor virtual address hole form value to write: */ ! 1505: va_hole_start = ic->tme_sparc64_ireg_va_hole_start; ! 1506: value_xor_va_hole = value_xor | (0 - (va_hole_start * 2)); ! 1507: value_xor_va_hole = (value_xor_va_hole ^ va_hole_start) + va_hole_start; ! 1508: ! 1509: /* dispatch on rd: */ ! 1510: reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD); ! 1511: switch (reg_rd) { ! 1512: ! 1513: /* TPC, TNPC, TSTATE, TT: */ ! 1514: case 0: ! 1515: case 1: ! 1516: case 2: ! 1517: case 3: ! 1518: tl = ic->tme_sparc64_ireg_tl; ! 1519: if (tl > 0) { ! 1520: switch (reg_rd) { ! 1521: case 0: ic->tme_sparc64_ireg_tpc(tl) = value_xor_va_hole; break; ! 1522: case 1: ic->tme_sparc64_ireg_tnpc(tl) = value_xor_va_hole; break; ! 1523: case 2: ic->tme_sparc64_ireg_tstate(tl) = value_xor; break; ! 1524: default: ic->tme_sparc64_ireg_tt(tl) = value_xor; break; ! 1525: } ! 1526: break; ! 1527: } ! 1528: /* FALLTHROUGH */ ! 1529: ! 1530: default: ! 1531: TME_SPARC_INSN_ILL(ic); ! 1532: TME_SPARC_INSN_OK; ! 1533: ! 1534: /* TICK: */ ! 1535: case 4: ! 1536: ic->tme_sparc64_ireg_tick_npt = (value_xor & TME_SPARC64_TICK_NPT) != 0; ! 1537: ic->tme_sparc64_ireg_tick_offset ! 1538: = ((value_xor & TME_SPARC64_TICK_COUNTER) ! 1539: - tme_misc_cycles_scaled(&ic->tme_sparc_cycles_scaling, 0).tme_value64_uint); ! 1540: break; ! 1541: ! 1542: case 5: ic->tme_sparc64_ireg_tba = value_xor_va_hole & ~ (tme_uint64_t) ((2 << 14) - (1 << 0)); break; ! 1543: ! 1544: /* a write to the PSTATE register causes a redispatch because we may ! 1545: need to update cached state derived from it: */ ! 1546: case 6: ! 1547: (*ic->_tme_sparc64_update_pstate)(ic, value_xor, TME_SPARC_TRAP_none); ! 1548: tme_sparc_redispatch(ic); ! 1549: TME_SPARC_INSN_OK; ! 1550: ! 1551: /* a write to the TL register causes a redispatch because we may ! 1552: need to update cached state derived from it: */ ! 1553: case 7: ! 1554: ic->tme_sparc64_ireg_tl = value_xor & 0x7; ! 1555: tme_sparc_redispatch(ic); ! 1556: TME_SPARC_INSN_OK; ! 1557: ! 1558: case 8: ! 1559: ! 1560: /* get the next value of PIL: */ ! 1561: pil = value_xor & 0xf; ! 1562: ! 1563: /* see how PIL is changing: */ ! 1564: pil_change = ic->tme_sparc64_ireg_pil; ! 1565: pil_change = pil - pil_change; ! 1566: ! 1567: /* if we are about to raise PIL: */ ! 1568: if (pil_change > 0) { ! 1569: ! 1570: /* do an interrupt check: */ ! 1571: (*ic->_tme_sparc_external_check)(ic, TME_SPARC_EXTERNAL_CHECK_PCS_UPDATED); ! 1572: } ! 1573: ! 1574: /* update PIL: */ ! 1575: ic->tme_sparc64_ireg_pil = pil; ! 1576: ! 1577: /* if we have lowered PIL: */ ! 1578: if (pil_change < 0) { ! 1579: ! 1580: /* do an interrupt check: */ ! 1581: (*ic->_tme_sparc_external_check)(ic, TME_SPARC_EXTERNAL_CHECK_NULL); ! 1582: } ! 1583: ! 1584: /* if we haven't detected the idle PC yet: */ ! 1585: if (__tme_predict_false(TME_SPARC_IDLE_TYPE_PC_STATE(ic->tme_sparc_idle_pcs_64[0]) != 0)) { ! 1586: ! 1587: /* if this is a "wrpr 0, %pil" instruction: */ ! 1588: if (TME_SPARC_INSN ! 1589: == ((tme_uint32_t) ! 1590: (2 << 30) /* format */ ! 1591: + (8 << 25) /* rd (%pil) */ ! 1592: + (0x32 << 19) /* op3 (wrpr) */ ! 1593: + (0 << 14) /* rs1 (%g0) */ ! 1594: + (1 << 13) /* i */ ! 1595: + 0)) { /* simm13 */ ! 1596: ! 1597: /* the netbsd64-type-0 idle type detects these two instructions ! 1598: in disassembly order: ! 1599: ! 1600: idle(): ! 1601: [...] ! 1602: wrpr %g0, PSTATE_INTR, %pstate ! 1603: wrpr %g0, 0, %pil ! 1604: ! 1605: this detects locore.s:idle() in NetBSD/sparc64 1.6 ! 1606: through 4.99.19 (until revision 1.244 of locore.s on ! 1607: 20070517): */ ! 1608: if (TME_SPARC_IDLE_TYPE_IS(ic, TME_SPARC_IDLE_TYPE_NETBSD64_TYPE_0)) { ! 1609: if ((tme_sparc_fetch_nearby(ic, -1) ! 1610: & ~ (tme_uint32_t) TME_SPARC64_PSTATE_AM) ! 1611: == ((tme_uint32_t) ! 1612: (2 << 30) /* format */ ! 1613: + (6 << 25) /* rd (%pstate) */ ! 1614: + (0x32 << 19) /* op3 (wrpr) */ ! 1615: + (0 << 14) /* rs1 (%g0) */ ! 1616: + (1 << 13) /* i */ ! 1617: + (TME_SPARC64_PSTATE_PRIV ! 1618: + TME_SPARC64_PSTATE_IE))) { /* PSTATE_INTR */ ! 1619: ! 1620: /* we have detected the idle PC: */ ! 1621: ic->tme_sparc_idle_pcs_64[0] ! 1622: = ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC); ! 1623: tme_sparc_recode_invalidate_all(ic); ! 1624: } ! 1625: } ! 1626: } ! 1627: ! 1628: /* if this is a "wrpr 0xa, %pil" instruction: */ ! 1629: if (TME_SPARC_INSN ! 1630: == ((tme_uint32_t) ! 1631: (2 << 30) /* format */ ! 1632: + (8 << 25) /* rd (%pil) */ ! 1633: + (0x32 << 19) /* op3 (wrpr) */ ! 1634: + (0 << 14) /* rs1 (%g0) */ ! 1635: + (1 << 13) /* i */ ! 1636: + 0xa)) { /* simm13 */ ! 1637: ! 1638: /* the sunos64-type-0 idle type begins by detecting these ! 1639: instructions in disassembly order: ! 1640: ! 1641: splhigh(): ! 1642: rdpr %pil, %o1 ! 1643: [any] ! 1644: [any] ! 1645: [any] ! 1646: wrpr 0xa, %pil ! 1647: ! 1648: this detects sparcv9_subr.s:splhigh() in Solaris 8 and ! 1649: probably others: */ ! 1650: if (TME_SPARC_IDLE_TYPE_IS(ic, TME_SPARC_IDLE_TYPE_SUNOS64_TYPE_0)) { ! 1651: if ((tme_sparc_fetch_nearby(ic, -4) ! 1652: & (0xffffffff ! 1653: - 0x3fff)) /* bits 0..13 reserved */ ! 1654: == ((tme_uint32_t) ! 1655: (2 << 30) /* format */ ! 1656: + (0x9 << 25) /* rd (%o1) */ ! 1657: + (0x2a << 19) /* op3 (rdpr) */ ! 1658: + (8 << 14))) { /* rs1 (pil) */ ! 1659: ! 1660: /* try to detect the idle loop: */ ! 1661: _tme_sparc64_idle_type_sunos64_type_0_splhigh(ic); ! 1662: } ! 1663: } ! 1664: } ! 1665: } ! 1666: ! 1667: /* otherwise, if this is the idle PC, and the idle type marks the ! 1668: idle at this wrpr to %pil: */ ! 1669: else if (__tme_predict_false(ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC) ! 1670: == ic->tme_sparc_idle_pcs_64[0])) { ! 1671: if (TME_SPARC_IDLE_TYPE_IS(ic, ! 1672: (TME_SPARC_IDLE_TYPE_NETBSD64_TYPE_0 ! 1673: ))) { ! 1674: ! 1675: /* mark the idle: */ ! 1676: TME_SPARC_IDLE_MARK(ic); ! 1677: } ! 1678: } ! 1679: ! 1680: break; ! 1681: ! 1682: case 9: ! 1683: /* XXX FIXME - the V9 architecture manual says the effect of ! 1684: writing a CWP greater than or equal to NWINDOWS is ! 1685: implementation-dependent. we assume that all of our ! 1686: implementations will always write it mod NWINDOWS: */ ! 1687: cwp = value_xor; ! 1688: cwp %= ic->tme_sparc_nwindows; ! 1689: ic->tme_sparc64_ireg_cwp = cwp; ! 1690: TME_SPARC64_CWP_UPDATE(ic, cwp, cwp_offset); ! 1691: break; ! 1692: case 10: ic->tme_sparc64_ireg_cansave = value_xor; break; ! 1693: case 11: ic->tme_sparc64_ireg_canrestore = value_xor; break; ! 1694: case 12: ic->tme_sparc64_ireg_cleanwin = value_xor; break; ! 1695: case 13: ic->tme_sparc64_ireg_otherwin = value_xor; break; ! 1696: case 14: ic->tme_sparc64_ireg_wstate = value_xor; break; ! 1697: ! 1698: /* XXX FIXME - add support for implementations with an FQ: */ ! 1699: #if 0 ! 1700: /* FQ: */ ! 1701: case 15: ! 1702: break; ! 1703: #endif /* 0 */ ! 1704: } ! 1705: ! 1706: TME_SPARC_INSN_OK; ! 1707: } ! 1708: ! 1709: TME_SPARC_FORMAT3(tme_sparc64_rdasr, tme_uint64_t) ! 1710: { ! 1711: unsigned int reg_rs1; ! 1712: tme_uint64_t value; ! 1713: ! 1714: /* dispatch on rs1: */ ! 1715: reg_rs1 = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RS1); ! 1716: switch (reg_rs1) { ! 1717: ! 1718: case 0: value = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_Y << 1); break; ! 1719: case 2: value = ic->tme_sparc64_ireg_ccr; break; ! 1720: case 3: value = ic->tme_sparc64_ireg_asi; break; ! 1721: case 4: ! 1722: tme_sparc_recode_verify_reg_tick(ic, &TME_SPARC_FORMAT3_RD); ! 1723: if (tme_sparc_recode_verify_replay_last_pc(ic) != 0) { ! 1724: TME_SPARC_INSN_OK; ! 1725: } ! 1726: value = tme_misc_cycles_scaled(&ic->tme_sparc_cycles_scaling, 0).tme_value64_uint; ! 1727: value += ic->tme_sparc64_ireg_tick_offset; ! 1728: value &= TME_SPARC64_TICK_COUNTER; ! 1729: if (__tme_predict_false(ic->tme_sparc64_ireg_tick_npt)) { ! 1730: if (__tme_predict_false(!TME_SPARC_PRIV(ic))) { ! 1731: tme_sparc64_trap(ic, TME_SPARC64_TRAP_privileged_action); ! 1732: } ! 1733: value |= TME_SPARC64_TICK_NPT; ! 1734: } ! 1735: tme_sparc_recode_verify_reg_tick_now(ic, &value); ! 1736: break; ! 1737: case 5: value = ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC); break; ! 1738: case 6: value = ic->tme_sparc64_ireg_fprs; break; ! 1739: ! 1740: case 15: ! 1741: if (__tme_predict_true(TME_SPARC_INSN & TME_SPARC_FORMAT3_MASK_RD) == 0) { ! 1742: /* XXX FIXME - we need to implement barriers: */ ! 1743: TME_SPARC_INSN_OK; ! 1744: } ! 1745: ! 1746: /* FALLTHROUGH */ ! 1747: default: ! 1748: TME_SPARC_INSN_ILL(ic); ! 1749: TME_SPARC_INSN_OK; ! 1750: } ! 1751: ! 1752: TME_SPARC_FORMAT3_RD = value; ! 1753: TME_SPARC_INSN_OK; ! 1754: } ! 1755: ! 1756: TME_SPARC_FORMAT3(tme_sparc64_wrasr, tme_uint64_t) ! 1757: { ! 1758: tme_uint64_t value_xor; ! 1759: unsigned int reg_rd; ! 1760: ! 1761: /* get the value to write: */ ! 1762: value_xor = TME_SPARC_FORMAT3_RS1 ^ TME_SPARC_FORMAT3_RS2; ! 1763: ! 1764: /* dispatch on rd: */ ! 1765: reg_rd = TME_FIELD_MASK_EXTRACTU(TME_SPARC_INSN, TME_SPARC_FORMAT3_MASK_RD); ! 1766: switch (reg_rd) { ! 1767: ! 1768: case 0: ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_Y << 1) = value_xor; TME_SPARC_INSN_OK; ! 1769: case 2: ic->tme_sparc64_ireg_ccr = value_xor; TME_SPARC_INSN_OK; ! 1770: ! 1771: /* a write to the ASI register causes a redispatch because we may ! 1772: need to update cached state derived from it: */ ! 1773: case 3: ! 1774: ic->tme_sparc64_ireg_asi = value_xor; ! 1775: tme_sparc_redispatch(ic); ! 1776: TME_SPARC_INSN_OK; ! 1777: ! 1778: case 6: ic->tme_sparc64_ireg_fprs = value_xor; TME_SPARC_INSN_OK; ! 1779: ! 1780: /* a valid sir must be handled in the CPU-specific wrasr function: */ ! 1781: default: ! 1782: assert (reg_rd != 15 ! 1783: || ((TME_SPARC_INSN ! 1784: & (TME_SPARC_FORMAT3_MASK_RS1 ! 1785: | TME_BIT(13))) ! 1786: != TME_BIT(13))); ! 1787: TME_SPARC_INSN_ILL(ic); ! 1788: TME_SPARC_INSN_OK; ! 1789: } ! 1790: } ! 1791: ! 1792: TME_SPARC_FORMAT3(tme_sparc64_done_retry, tme_uint64_t) ! 1793: { ! 1794: tme_uint32_t fcn; ! 1795: unsigned long tl; ! 1796: tme_uint64_t pc_next; ! 1797: tme_uint64_t pc_next_next; ! 1798: tme_uint32_t tstate_0_31; ! 1799: tme_uint32_t cwp; ! 1800: unsigned int cwp_offset; ! 1801: tme_uint32_t pstate; ! 1802: ! 1803: /* get the (still-shifted) fcn, and TL: */ ! 1804: fcn = TME_SPARC_INSN & (0x1f << 25); ! 1805: tl = ic->tme_sparc64_ireg_tl; ! 1806: ! 1807: /* fcn and TL must be legal: */ ! 1808: if (__tme_predict_false(fcn > (1 << 25) ! 1809: || tl == 0)) { ! 1810: TME_SPARC_INSN_ILL(ic); ! 1811: } ! 1812: ! 1813: TME_SPARC_INSN_PRIV; ! 1814: ! 1815: /* assume that this is a done: */ ! 1816: pc_next = ic->tme_sparc64_ireg_tnpc(tl); ! 1817: pc_next_next = pc_next + sizeof(tme_uint32_t); ! 1818: ! 1819: /* if this is a retry: */ ! 1820: if (fcn == (1 << 25)) { ! 1821: pc_next_next = pc_next; ! 1822: pc_next = ic->tme_sparc64_ireg_tpc(tl); ! 1823: } ! 1824: ! 1825: /* update the PCs: */ ! 1826: pc_next &= ic->tme_sparc_address_mask; ! 1827: pc_next_next &= ic->tme_sparc_address_mask; ! 1828: ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT) = pc_next; ! 1829: ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT_NEXT) = pc_next_next; ! 1830: ! 1831: /* update CCR directly from TSTATE: */ ! 1832: ic->tme_sparc64_ireg_ccr = ic->tme_sparc64_ireg_tstate_ccr(tl); ! 1833: ! 1834: /* get the least-significant 32 bits of TSTATE: */ ! 1835: tstate_0_31 = ic->tme_sparc64_ireg_tstate(tl); ! 1836: ! 1837: /* log the done or retry: */ ! 1838: tme_sparc_log(ic, 250, TME_OK, ! 1839: (TME_SPARC_LOG_HANDLE(ic), ! 1840: _("%s tl %u next-%%pc 0x%016" TME_PRIx64 " tstate_0_31 0x%08" TME_PRIx32), ! 1841: (fcn == (1 << 25) ! 1842: ? "retry" ! 1843: : "done"), ! 1844: (unsigned int) tl, ! 1845: pc_next, ! 1846: tstate_0_31)); ! 1847: ! 1848: /* update TL: */ ! 1849: ic->tme_sparc64_ireg_tl = tl - 1; ! 1850: ! 1851: /* update CWP: */ ! 1852: #if (TME_SPARC64_TSTATE_MASK_CWP & 1) == 0 ! 1853: #error "TME_SPARC64_TSTATE_MASK_CWP changed" ! 1854: #endif ! 1855: cwp = (tme_uint8_t) tstate_0_31; ! 1856: assert (ic->tme_sparc64_ireg_winstates_mask != 0); ! 1857: cwp &= ic->tme_sparc64_ireg_winstates_mask; ! 1858: ic->tme_sparc64_ireg_cwp = cwp; ! 1859: TME_SPARC64_CWP_UPDATE(ic, cwp, cwp_offset); ! 1860: ! 1861: /* get the value for PSTATE: */ ! 1862: tstate_0_31 ! 1863: /= (_TME_FIELD_MASK_FACTOR(TME_SPARC64_TSTATE_MASK_PSTATE) ! 1864: / _TME_FIELD_MASK_FACTOR(TME_SPARC64_TSTATE_MASK_CWP)); ! 1865: pstate ! 1866: = (tstate_0_31 ! 1867: & (TME_SPARC64_TSTATE_MASK_PSTATE ! 1868: / _TME_FIELD_MASK_FACTOR(TME_SPARC64_TSTATE_MASK_PSTATE))); ! 1869: ! 1870: /* update ASI: */ ! 1871: tstate_0_31 ! 1872: /= (_TME_FIELD_MASK_FACTOR(TME_SPARC64_TSTATE_MASK_ASI) ! 1873: / _TME_FIELD_MASK_FACTOR(TME_SPARC64_TSTATE_MASK_PSTATE)); ! 1874: ic->tme_sparc64_ireg_asi ! 1875: = (tstate_0_31 ! 1876: & (TME_SPARC64_TSTATE_MASK_ASI ! 1877: / _TME_FIELD_MASK_FACTOR(TME_SPARC64_TSTATE_MASK_ASI))); ! 1878: ! 1879: /* update PSTATE: */ ! 1880: (*ic->_tme_sparc64_update_pstate)(ic, pstate, TME_SPARC_TRAP_none); ! 1881: ! 1882: /* redispatch, since the executor may have cached information ! 1883: derived from PSTATE, ASI, etc., that we need to invalidate: */ ! 1884: tme_sparc_redispatch(ic); ! 1885: } ! 1886: ! 1887: TME_SPARC_FORMAT3(tme_sparc64_illegal_instruction, tme_uint64_t) ! 1888: { ! 1889: TME_SPARC_INSN_ILL(ic); ! 1890: } ! 1891: ! 1892: #endif /* TME_HAVE_INT64_T */ ! 1893: ! 1894: #undef TME_SPARC_VERSION ! 1895: #define TME_SPARC_VERSION(ic) _TME_SPARC_VERSION(ic) ! 1896: 1.1 root 1897: #include "sparc-insns-auto.c"
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.