|
|
1.1 ! root 1: /* $Id: sparc-rc-insns.c,v 1.8 2010/06/05 17:00:47 fredette Exp $ */ ! 2: ! 3: /* ic/sparc/sparc-rc-insns.c - SPARC recode instruction support: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2008 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: #if TME_SPARC_RECODE_SIZE(ic) == TME_RECODE_SIZE_32 ! 37: ! 38: _TME_RCSID("$Id: sparc-rc-insns.c,v 1.8 2010/06/05 17:00:47 fredette Exp $"); ! 39: ! 40: /* macros: */ ! 41: ! 42: /* the sparc instruction recoder is mostly driven by the 32-bit ! 43: control value kept in the sparc_recode variable. this value ! 44: includes various fields and flags, and is initially taken from the ! 45: sparc instruction's entry in _tme_sparc_recode_insn_opmap[]. this ! 46: entry provides only the least significant 16 bits; other ! 47: more-significant bits may be added as recoding proceeds: */ ! 48: ! 49: /* the opcode for the recode instruction: */ ! 50: #define TME_SPARC_RECODE_INSN_OPCODE(x) ((tme_uint8_t) (x)) ! 51: #define TME_SPARC_RECODE_INSN_OPCODE_MASK (0xff) ! 52: ! 53: /* if set, the PC and PC_next registers must be valid for this sparc ! 54: instruction, either because the sparc instruction itself needs them ! 55: to be valid, or because the situation calls for them to be valid ! 56: (for example, when TME_SPARC_RECODE_INSN_LAST is also set): */ ! 57: #define TME_SPARC_RECODE_INSN_UPDATE_PCS (1 << 8) ! 58: ! 59: /* if set, this sparc instruction will be the last one recoded in this ! 60: instructions thunk: */ ! 61: #define TME_SPARC_RECODE_INSN_LAST (1 << 9) ! 62: ! 63: /* when TME_SPARC_RECODE_INSN_UPDATE_INSN is set, these flags are set ! 64: if this sparc instruction doesn't take rs2/simm13 and/or rs1 source ! 65: operands: */ ! 66: #define TME_SPARC_RECODE_INSN_NO_RS2 (1 << 10) ! 67: #define TME_SPARC_RECODE_INSN_NO_RS1 (1 << 11) ! 68: ! 69: /* when the recode opcode is TME_RECODE_OPCODE_GUEST, this flag is set ! 70: if this sparc instruction doesn't write any sparc register visible ! 71: to recode: */ ! 72: #define TME_SPARC_RECODE_INSN_NO_RD (1 << 12) ! 73: ! 74: /* if set, the TME_SPARC_IREG_INSN register must be valid for this ! 75: sparc instruction, usually because it uses a generic assist ! 76: function that needs the instruction word: */ ! 77: #define TME_SPARC_RECODE_INSN_UPDATE_INSN (1 << 13) ! 78: ! 79: /* if set, this is a shift instruction: */ ! 80: #define TME_SPARC_RECODE_INSN_SHIFT (1 << 14) ! 81: ! 82: /* when TME_SPARC_RECODE_INSN_UPDATE_INSN is clear, this is set if ! 83: this sparc instruction needs TME_RECODE_FLAG_CARRY set with the ! 84: %icc.C flag: */ ! 85: #define TME_SPARC_RECODE_INSN_DEFC (TME_SPARC_RECODE_INSN_NO_RS2) ! 86: ! 87: /* when TME_SPARC_RECODE_INSN_UPDATE_INSN is clear, this is set if ! 88: this sparc instruction updates the sparc condition codes: */ ! 89: #define TME_SPARC_RECODE_INSN_CC (TME_SPARC_RECODE_INSN_NO_RS1) ! 90: ! 91: /* NB: the following sparc_recode flags cannot be used in the 16-bit ! 92: _tme_sparc_recode_insn_opmap[]: */ ! 93: ! 94: /* if set, this suppresses the normal recoding of the sparc ! 95: instruction itself (although any TME_SPARC_RECODE_INSN_UPDATE_PCS ! 96: will still be done): */ ! 97: #define TME_SPARC_RECODE_INSN_NONE (1 << 16) ! 98: ! 99: /* if set, this is a v9 32-bit right shift: */ ! 100: #define TME_SPARC_RECODE_INSN_SHIFT_RIGHT (1 << 17) ! 101: ! 102: /* if set, after the normal recoding of the sparc instruction, a ! 103: recode endif will be emitted: */ ! 104: #define TME_SPARC_RECODE_INSN_NEED_ENDIF (1 << 18) ! 105: ! 106: /* when TME_SPARC_RECODE_INSN_LAST is set, this is any recode chain ! 107: information for the instructions thunk: */ ! 108: #define TME_SPARC_RECODE_CHAIN_INFO(x) ((x) << 19) ! 109: #if (TME_RECODE_CHAIN_INFO_UNCONDITIONAL | TME_RECODE_CHAIN_INFO_CONDITIONAL | TME_RECODE_CHAIN_INFO_NEAR | TME_RECODE_CHAIN_INFO_FAR | TME_RECODE_CHAIN_INFO_JUMP | TME_RECODE_CHAIN_INFO_RETURN | TME_RECODE_CHAIN_INFO_CALL) > 0x1f ! 110: #error "TME_RECODE_CHAIN_INFO_ values changed" ! 111: #endif ! 112: ! 113: /* these are composite values used in ! 114: _tme_sparc_recode_insn_opmap[]: */ ! 115: ! 116: /* this sparc instruction needs an assist: */ ! 117: #define TME_SPARC_RECODE_INSN_ASSIST \ ! 118: (TME_RECODE_OPCODE_GUEST \ ! 119: | TME_SPARC_RECODE_INSN_UPDATE_INSN) ! 120: ! 121: /* this sparc instruction needs an assist, and can trap: */ ! 122: #define TME_SPARC_RECODE_INSN_ASSIST_CANTRAP \ ! 123: (TME_SPARC_RECODE_INSN_ASSIST \ ! 124: | TME_SPARC_RECODE_INSN_UPDATE_PCS) ! 125: ! 126: /* this sparc instruction needs an assist, can trap, and the assist ! 127: function does not need source operands from the rs1 and rs2/simm13 ! 128: fields: */ ! 129: #define TME_SPARC_RECODE_INSN_ASSIST_FULL \ ! 130: (TME_SPARC_RECODE_INSN_ASSIST_CANTRAP \ ! 131: | TME_SPARC_RECODE_INSN_NO_RS2 \ ! 132: | TME_SPARC_RECODE_INSN_NO_RS1) ! 133: ! 134: /* this sparc instruction is undefined: */ ! 135: #define TME_SPARC_RECODE_INSN_UNDEF TME_SPARC_RECODE_INSN_ASSIST_FULL ! 136: ! 137: /* this sparc instruction is a load: */ ! 138: #define TME_SPARC_RECODE_INSN_LD \ ! 139: (TME_SPARC_RECODE_INSN_UPDATE_PCS \ ! 140: | TME_RECODE_OPCODE_RW) ! 141: ! 142: /* this sparc instruction is a store: */ ! 143: #define TME_SPARC_RECODE_INSN_ST \ ! 144: (TME_SPARC_RECODE_INSN_UPDATE_PCS \ ! 145: | TME_RECODE_OPCODE_RW) ! 146: ! 147: /* this sparc instruction is a load alternate: */ ! 148: #define TME_SPARC_RECODE_INSN_LDA \ ! 149: (TME_SPARC_VERSION(ic) < 9 \ ! 150: ? TME_SPARC_RECODE_INSN_ASSIST_CANTRAP \ ! 151: : TME_SPARC_RECODE_INSN_LD) ! 152: ! 153: /* rename various things by the architecture size: */ ! 154: #define tme_sparc_idle_type_pc _TME_SPARC_RECODE_SIZE(tme_sparc_idle_type_pc,/**/) ! 155: #define _tme_sparc_recode_insn_opmap _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_opmap) ! 156: #define _tme_sparc_execute_opmap _TME_SPARC_RECODE_SIZE(_tme_sparc,_execute_opmap) ! 157: #define tme_sparc_recode_insn_current _TME_SPARC_RECODE_SIZE(tme_sparc,_recode_insn_current) ! 158: #define tme_sparc_recode_insn_assist_redispatch _TME_SPARC_RECODE_SIZE(tme_sparc,_recode_insn_assist_redispatch) ! 159: #define _tme_sparc_recode_insn_assist _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_assist) ! 160: #define _tme_sparc_recode_insn_assist_full _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_assist_full) ! 161: #define _tme_sparc_recode_insn_assist_jmpl _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_assist_jmpl) ! 162: #define _tme_sparc_recode_insn_assist_unimpl _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_assist_unimpl) ! 163: #define _tme_sparc_recode_insns_total _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insns_total) ! 164: #define _tme_sparc_recode_insn_branch_delay_bad _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_insn_branch_delay_bad) ! 165: #define _tme_sparc_recode_recode _TME_SPARC_RECODE_SIZE(_tme_sparc,_recode_recode) ! 166: ! 167: #endif /* TME_SPARC_RECODE_SIZE(ic) == TME_RECODE_SIZE_32 */ ! 168: ! 169: /* this maps format three opcodes into sparc recode controls: */ ! 170: static const tme_uint16_t _tme_sparc_recode_insn_opmap[128] = { ! 171: ! 172: /* op=2: arithmetic, logical, shift, and remaining: */ ! 173: ! 174: /* 000000 */ TME_RECODE_OPCODE_ADD, ! 175: /* 000001 */ TME_RECODE_OPCODE_AND, ! 176: /* 000010 */ TME_RECODE_OPCODE_OR, ! 177: /* 000011 */ TME_RECODE_OPCODE_XOR, ! 178: /* 000100 */ TME_RECODE_OPCODE_SUB, ! 179: /* 000101 */ TME_RECODE_OPCODE_ANDN, ! 180: /* 000110 */ TME_RECODE_OPCODE_ORN, ! 181: /* 000111 */ TME_RECODE_OPCODE_XORN, ! 182: /* 001000 */ TME_RECODE_OPCODE_ADDC | TME_SPARC_RECODE_INSN_DEFC, ! 183: #if TME_SPARC_VERSION(ic) < 9 ! 184: /* 001001 */ TME_SPARC_RECODE_INSN_UNDEF, ! 185: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 186: /* 101001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: mulx */ ! 187: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 188: /* 001010 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* umul */ ! 189: /* 001011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* smul */ ! 190: /* 001100 */ TME_RECODE_OPCODE_SUBC | TME_SPARC_RECODE_INSN_DEFC, ! 191: #if TME_SPARC_VERSION(ic) < 9 ! 192: /* 001101 */ TME_SPARC_RECODE_INSN_UNDEF, ! 193: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 194: /* 001101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: udivx */ ! 195: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 196: /* 001110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* udiv */ ! 197: /* 001111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* sdiv */ ! 198: /* 010000 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_ADD, ! 199: /* 010001 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_AND, ! 200: /* 010010 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_OR, ! 201: /* 010011 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_XOR, ! 202: /* 010100 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_SUB, ! 203: /* 010101 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_ANDN, ! 204: /* 010110 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_ORN, ! 205: /* 010111 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_XORN, ! 206: /* 011000 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_ADDC | TME_SPARC_RECODE_INSN_DEFC, ! 207: /* 011001 */ TME_SPARC_RECODE_INSN_UNDEF, ! 208: /* 011010 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* umulcc */ ! 209: /* 011011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* smulcc */ ! 210: /* 011100 */ TME_SPARC_RECODE_INSN_CC | TME_RECODE_OPCODE_SUBC | TME_SPARC_RECODE_INSN_DEFC, ! 211: /* 011101 */ TME_SPARC_RECODE_INSN_UNDEF, ! 212: /* 011110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* udivcc */ ! 213: /* 011111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* sdivcc */ ! 214: /* 100000 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* taddcc */ ! 215: /* 100001 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* tsubcc */ ! 216: /* 100010 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* taddcctv */ ! 217: /* 100011 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* tsubcctv */ ! 218: /* 100100 */ TME_SPARC_RECODE_INSN_ASSIST, /* mulscc */ ! 219: /* 100101 */ TME_RECODE_OPCODE_SHLL | TME_SPARC_RECODE_INSN_SHIFT, ! 220: /* 100110 */ TME_RECODE_OPCODE_SHRL | TME_SPARC_RECODE_INSN_SHIFT, ! 221: /* 100111 */ TME_RECODE_OPCODE_SHRA | TME_SPARC_RECODE_INSN_SHIFT, ! 222: /* 101000 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* rdasr */ ! 223: #if TME_SPARC_VERSION(ic) < 9 ! 224: /* 101001 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* rdpsr */ ! 225: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 226: /* 101001 */ TME_SPARC_RECODE_INSN_UNDEF, ! 227: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 228: /* 101010 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* rdwim (v9: rdpr) */ ! 229: /* 101011 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* rdtbr (v9: flushw) */ ! 230: #if TME_SPARC_VERSION(ic) < 9 ! 231: /* 101100 */ TME_SPARC_RECODE_INSN_UNDEF, ! 232: /* 101101 */ TME_SPARC_RECODE_INSN_UNDEF, ! 233: /* 101110 */ TME_SPARC_RECODE_INSN_UNDEF, ! 234: /* 101111 */ TME_SPARC_RECODE_INSN_UNDEF, ! 235: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 236: /* 101100 */ 0, /* v9: movcc (handled specially) */ ! 237: /* 101101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: sdivx */ ! 238: /* 101110 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP, /* v9: popc */ ! 239: /* 101111 */ 0, /* v9: movr (handled specially) */ ! 240: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 241: /* 110000 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* wrasr */ ! 242: #if TME_SPARC_VERSION(ic) < 9 ! 243: /* 110001 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* wrpsr */ ! 244: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 245: /* 110001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: saved/restored */ ! 246: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 247: /* 110010 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* wrwim (v9: wrpr) */ ! 248: #if TME_SPARC_VERSION(ic) < 9 ! 249: /* 110011 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* wrtbr */ ! 250: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 251: /* 110011 */ TME_SPARC_RECODE_INSN_UNDEF, ! 252: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 253: /* 110100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* fpop1 */ ! 254: /* 110101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* fpop2 */ ! 255: /* 110110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* cpop1 (v9: impdep1) */ ! 256: /* 110111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* cpop2 (v9: impdep2) */ ! 257: /* 111000 */ 0, /* jmpl (handled specially) */ ! 258: /* 111001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST, /* rett (v9: return) */ ! 259: /* 111010 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* ticc */ ! 260: /* 111011 */ TME_SPARC_RECODE_INSN_ASSIST | TME_SPARC_RECODE_INSN_NO_RD, /* flush */ ! 261: /* 111100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* save */ ! 262: /* 111101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* restore */ ! 263: #if TME_SPARC_VERSION(ic) < 9 ! 264: /* 111110 */ TME_SPARC_RECODE_INSN_UNDEF, ! 265: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 266: /* 111110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST, /* v9: done/retry */ ! 267: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 268: /* 111111 */ TME_SPARC_RECODE_INSN_UNDEF, ! 269: ! 270: /* op=3: memory instructions: */ ! 271: ! 272: /* 000000 */ TME_SPARC_RECODE_INSN_LD, /* ld (v9: lduw) */ ! 273: /* 000001 */ TME_SPARC_RECODE_INSN_LD, /* ldub */ ! 274: /* 000010 */ TME_SPARC_RECODE_INSN_LD, /* lduh */ ! 275: /* 000011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldd */ ! 276: /* 000100 */ TME_SPARC_RECODE_INSN_ST, /* st (v9: stw) */ ! 277: /* 000101 */ TME_SPARC_RECODE_INSN_ST, /* stb */ ! 278: /* 000110 */ TME_SPARC_RECODE_INSN_ST, /* sth */ ! 279: /* 000111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* std */ ! 280: #if TME_SPARC_VERSION(ic) < 9 ! 281: /* 001000 */ TME_SPARC_RECODE_INSN_UNDEF, ! 282: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 283: /* 001000 */ TME_SPARC_RECODE_INSN_LD, /* v9: ldsw */ ! 284: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 285: /* 001001 */ TME_SPARC_RECODE_INSN_LD, /* ldsb */ ! 286: /* 001010 */ TME_SPARC_RECODE_INSN_LD, /* ldsh */ ! 287: #if TME_SPARC_VERSION(ic) < 9 ! 288: /* 001011 */ TME_SPARC_RECODE_INSN_UNDEF, ! 289: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 290: /* 001011 */ TME_SPARC_RECODE_INSN_LD, /* v9: ldx */ ! 291: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 292: /* 001100 */ TME_SPARC_RECODE_INSN_UNDEF, ! 293: /* 001101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldstub */ ! 294: #if TME_SPARC_VERSION(ic) < 9 ! 295: /* 001110 */ TME_SPARC_RECODE_INSN_UNDEF, ! 296: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 297: /* 001110 */ TME_SPARC_RECODE_INSN_ST, /* v9: stx */ ! 298: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 299: /* 001111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* swap */ ! 300: /* 010000 */ TME_SPARC_RECODE_INSN_LDA, /* lda (v9: lduwa) */ ! 301: /* 010001 */ TME_SPARC_RECODE_INSN_LDA, /* lduba */ ! 302: /* 010010 */ TME_SPARC_RECODE_INSN_LDA, /* lduha */ ! 303: /* 010011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldda */ ! 304: /* 010100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* sta (v9: stwa) */ ! 305: /* 010101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* stba */ ! 306: /* 010110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* stha */ ! 307: /* 010111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* stda */ ! 308: #if TME_SPARC_VERSION(ic) < 9 ! 309: /* 011000 */ TME_SPARC_RECODE_INSN_UNDEF, ! 310: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 311: /* 011000 */ TME_SPARC_RECODE_INSN_LDA, /* v9: ldswa*/ ! 312: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 313: /* 011001 */ TME_SPARC_RECODE_INSN_LDA, /* ldsba */ ! 314: /* 011010 */ TME_SPARC_RECODE_INSN_LDA, /* ldsha */ ! 315: #if TME_SPARC_VERSION(ic) < 9 ! 316: /* 011011 */ TME_SPARC_RECODE_INSN_UNDEF, ! 317: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 318: /* 001011 */ TME_SPARC_RECODE_INSN_LDA, /* v9: ldxa*/ ! 319: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 320: /* 011100 */ TME_SPARC_RECODE_INSN_UNDEF, ! 321: /* 011101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldstuba */ ! 322: #if TME_SPARC_VERSION(ic) < 9 ! 323: /* 011110 */ TME_SPARC_RECODE_INSN_UNDEF, ! 324: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 325: /* 001110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_NO_RD, /* v9: stxa */ ! 326: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 327: /* 011111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* swapa */ ! 328: /* 100000 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldf */ ! 329: /* 100001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldfsr */ ! 330: #if TME_SPARC_VERSION(ic) < 9 ! 331: /* 100010 */ TME_SPARC_RECODE_INSN_UNDEF, ! 332: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 333: /* 100010 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: ldqf */ ! 334: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 335: /* 100011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* lddf */ ! 336: /* 100100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stf */ ! 337: /* 100101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stfsr */ ! 338: /* 100110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stdfq */ ! 339: /* 100111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stdf */ ! 340: /* 101000 */ TME_SPARC_RECODE_INSN_UNDEF, ! 341: /* 101001 */ TME_SPARC_RECODE_INSN_UNDEF, ! 342: /* 101010 */ TME_SPARC_RECODE_INSN_UNDEF, ! 343: /* 101011 */ TME_SPARC_RECODE_INSN_UNDEF, ! 344: /* 101100 */ TME_SPARC_RECODE_INSN_UNDEF, ! 345: #if TME_SPARC_VERSION(ic) < 9 ! 346: /* 101101 */ TME_SPARC_RECODE_INSN_UNDEF, ! 347: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 348: /* 101101 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* v9: prefetch */ ! 349: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 350: /* 101110 */ TME_SPARC_RECODE_INSN_UNDEF, ! 351: /* 101111 */ TME_SPARC_RECODE_INSN_UNDEF, ! 352: /* 110000 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldc (v9: ldfa) */ ! 353: #if TME_SPARC_VERSION(ic) < 9 ! 354: /* 110001 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* ldcsr */ ! 355: /* 110010 */ TME_SPARC_RECODE_INSN_UNDEF, ! 356: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 357: /* 110001 */ TME_SPARC_RECODE_INSN_UNDEF, ! 358: /* 110010 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: ldqfa */ ! 359: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 360: /* 110011 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* lddc (v9: lddfa) */ ! 361: /* 110100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stc (v9: stfa) */ ! 362: #if TME_SPARC_VERSION(ic) < 9 ! 363: /* 110101 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stcsr */ ! 364: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 365: /* 110101 */ TME_SPARC_RECODE_INSN_UNDEF, ! 366: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 367: /* 110110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stdcq (v9: stqfa) */ ! 368: /* 110111 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* stdc (v9: stdfa) */ ! 369: /* 111000 */ TME_SPARC_RECODE_INSN_UNDEF, ! 370: /* 111001 */ TME_SPARC_RECODE_INSN_UNDEF, ! 371: /* 111010 */ TME_SPARC_RECODE_INSN_UNDEF, ! 372: /* 111011 */ TME_SPARC_RECODE_INSN_UNDEF, ! 373: #if TME_SPARC_VERSION(ic) < 9 ! 374: /* 111100 */ TME_SPARC_RECODE_INSN_UNDEF, ! 375: /* 111101 */ TME_SPARC_RECODE_INSN_UNDEF, ! 376: /* 111110 */ TME_SPARC_RECODE_INSN_UNDEF, ! 377: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 378: /* 111100 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: casa */ ! 379: /* 111101 */ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP | TME_SPARC_RECODE_INSN_NO_RD, /* v9: prefetch */ ! 380: /* 111110 */ TME_SPARC_RECODE_INSN_ASSIST_FULL, /* v9: casxa */ ! 381: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 382: /* 111111 */ TME_SPARC_RECODE_INSN_UNDEF, ! 383: }; ! 384: ! 385: /* this returns the current instruction: */ ! 386: tme_uint32_t ! 387: tme_sparc_recode_insn_current(const struct tme_sparc *ic) ! 388: { ! 389: const struct tme_token *itlb_current_token; ! 390: const struct _TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,/**/) *recode_itlb_current; ! 391: const struct tme_sparc_tlb *itlb_current; ! 392: tme_uint32_t page_offset; ! 393: const tme_shared tme_uint32_t *_sparc_insn; ! 394: tme_uint32_t sparc_insn; ! 395: ! 396: /* in a cooperative threading system, the current ITLB entry must be ! 397: valid. in a noncooperative threading system, some master may be ! 398: in the process of invalidating the current ITLB entry: */ ! 399: itlb_current_token = ic->_tme_sparc_itlb_current_token; ! 400: assert (!TME_THREADS_COOPERATIVE || tme_token_is_valid(itlb_current_token)); ! 401: ! 402: /* get the current recode ITLB entry: */ ! 403: recode_itlb_current ! 404: = ((struct _TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,/**/) *) ! 405: (((const char *) itlb_current_token) ! 406: - (((char *) &(((struct _TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,/**/) *) 0)->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_token))) ! 407: - (char *) 0))); ! 408: ! 409: /* the current ITLB entry must cover the current context, ! 410: instruction ASI and PC, and allow fast reading: */ ! 411: itlb_current = &ic->tme_sparc_tlbs[(recode_itlb_current - &ic->_TME_SPARC_RECODE_SIZE(tme_sparc_recode_tlb,s)[0])]; ! 412: assert ((itlb_current->tme_sparc_tlb_context > ic->tme_sparc_memory_context_max ! 413: || itlb_current->tme_sparc_tlb_context == ic->tme_sparc_memory_context_default) ! 414: && TME_SPARC_TLB_ASI_MASK_OK(itlb_current, ic->tme_sparc_asi_mask_insn) ! 415: && itlb_current->tme_sparc_tlb_addr_first <= ic->tme_sparc_ireg(TME_SPARC_IREG_PC) ! 416: && ic->tme_sparc_ireg(TME_SPARC_IREG_PC) <= itlb_current->tme_sparc_tlb_addr_last ! 417: && itlb_current->tme_sparc_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF); ! 418: ! 419: /* fetch the instruction: */ ! 420: page_offset = recode_itlb_current->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_page); ! 421: page_offset ^= (tme_uint32_t) ic->tme_sparc_ireg(TME_SPARC_IREG_PC); ! 422: assert ((page_offset >> ic->tme_sparc_tlb_page_size_log2) == 0); ! 423: _sparc_insn ! 424: = ((const tme_shared tme_uint32_t *) ! 425: (recode_itlb_current->_TME_SPARC_RECODE_SIZE(tme_recode_tlb_c16_a,_memory) ! 426: + page_offset)); ! 427: sparc_insn ! 428: = tme_memory_bus_read32(_sparc_insn, ! 429: (tme_rwlock_t *) NULL, ! 430: sizeof(tme_uint32_t), ! 431: sizeof(tme_sparc_ireg_t)); ! 432: sparc_insn = tme_betoh_u32(sparc_insn); ! 433: ! 434: return (sparc_insn); ! 435: } ! 436: ! 437: /* this checks for conditions that require a redispatch out of recode ! 438: instruction thunks: */ ! 439: tme_recode_uguest_t ! 440: tme_sparc_recode_insn_assist_redispatch(struct tme_sparc *ic) ! 441: { ! 442: int redispatch_required; ! 443: ! 444: /* if the instruction TLB entry for this PC is invalid, or doesn't ! 445: cover the PC and context and ASI, or doesn't allow fast reading, ! 446: or isn't covered by any cacheable, or the page containing this PC ! 447: isn't still cache-valid (i.e., its contents have changed since we ! 448: cached recoded instructions for it), a redispatch is required: */ ! 449: /* NB: we check for the current PC, even though it's for an ! 450: instruction that has already completed. ! 451: ! 452: if PC and PC_next are on the same page, this does the right ! 453: thing. if PC and PC_next are on different pages, and the PC page ! 454: requires a redispatch but the PC_next page does not, this will ! 455: cause a needless redispatch. if PC and PC_next are on different ! 456: pages, and the PC page doesn't require a redispatch but the ! 457: PC_next page does, that will get handled by either ! 458: _TME_SPARC_EXECUTE_NAME()/tme_sparc_recode() or the host chain ! 459: out/chain in, because the current instructions thunk can't ! 460: cover both PC and PC_next. ! 461: ! 462: so, checking for the current PC never does the wrong thing, and ! 463: is useful for at least _tme_sparc_recode_ls_assist_ld(), which ! 464: must redispatch after executing a ld instruction that might be ! 465: different from the ld instruction at the time the instructions ! 466: thunk was recoded - because if the destination register has been ! 467: changed in the new instruction, if ! 468: _tme_sparc_recode_ls_assist_ld() did return to the instructions ! 469: thunk, it would incorrectly take the return value for the ! 470: destination register in the original instruction: */ ! 471: redispatch_required ! 472: = (_tme_sparc_recode_chain_src_key(ic, ! 473: ic->tme_sparc_ireg(TME_SPARC_IREG_PC)) ! 474: == TME_SPARC_RECODE_SRC_KEY_UNDEF); ! 475: ! 476: /* if the instruction burst has been set to zero by a ! 477: TME_BUS_CYCLE_SYNCHRONOUS_EVENT, a redispatch is required: */ ! 478: redispatch_required |= (ic->_tme_sparc_instruction_burst_remaining == 0); ! 479: ! 480: /* if a redispatch is required: */ ! 481: if (__tme_predict_false(redispatch_required)) { ! 482: ! 483: /* do the redispatch: */ ! 484: tme_sparc_redispatch(ic); ! 485: } ! 486: ! 487: return (0); ! 488: } ! 489: ! 490: /* the assist functions for format three instructions reference the ! 491: opmap in struct tme_sparc: */ ! 492: ! 493: /* the assist function for TME_SPARC_RECODE_INSN_ASSIST and ! 494: TME_SPARC_RECODE_INSN_ASSIST_CANTRAP instructions: */ ! 495: static tme_recode_uguest_t ! 496: _tme_sparc_recode_insn_assist(struct tme_ic *_ic, ! 497: tme_recode_uguest_t rs1, ! 498: tme_recode_uguest_t rs2) ! 499: { ! 500: struct tme_sparc *ic; ! 501: tme_uint32_t sparc_insn; ! 502: tme_uint32_t sparc_opcode; ! 503: #if TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) ! 504: tme_sparc_ireg_t rs1_buffer; ! 505: tme_sparc_ireg_t rs2_buffer; ! 506: #endif /* TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) */ ! 507: tme_sparc_ireg_t *_rs1; ! 508: tme_sparc_ireg_t *_rs2; ! 509: tme_sparc_ireg_t rd; ! 510: ! 511: /* recover our ic: */ ! 512: ic = (struct tme_sparc *) _ic; ! 513: ! 514: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist); ! 515: ! 516: /* set PC_next_next from PC_next: */ ! 517: /* NB that this sets PC_next_next to garbage unless this instruction ! 518: was a TME_SPARC_RECODE_INSN_ASSIST_CANTRAP: */ ! 519: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) ! 520: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT) ! 521: + sizeof(tme_uint32_t)); ! 522: ! 523: /* copy the instruction from the internal register into its normal ! 524: position: */ ! 525: sparc_insn = ic->tme_sparc_ireg(TME_SPARC_IREG_INSN); ! 526: ic->_tme_sparc_insn = sparc_insn; ! 527: ! 528: /* form the opcode index: */ ! 529: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19)); ! 530: sparc_opcode += ((sparc_insn >> (30 - 6)) & 0x40); ! 531: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_opcode[sparc_opcode]); ! 532: ! 533: /* run the instruction: */ ! 534: #if TME_RECODE_SIZE_GUEST_MAX > TME_SPARC_RECODE_SIZE(ic) ! 535: rs1_buffer = rs1; ! 536: rs2_buffer = rs2; ! 537: _rs1 = &rs1_buffer; ! 538: _rs2 = &rs2_buffer; ! 539: #else /* TME_RECODE_SIZE_GUEST_MAX == TME_SPARC_RECODE_SIZE(ic) */ ! 540: _rs1 = &rs1; ! 541: _rs2 = &rs2; ! 542: #endif /* TME_RECODE_SIZE_GUEST_MAX == TME_SPARC_RECODE_SIZE(ic) */ ! 543: #ifdef _TME_SPARC_RECODE_VERIFY ! 544: rd = 0; ! 545: #endif /* _TME_SPARC_RECODE_VERIFY */ ! 546: (*ic->_tme_sparc_execute_opmap[sparc_opcode]) ! 547: (ic, _rs1, _rs2, &rd); ! 548: ! 549: /* return the result: */ ! 550: return (rd); ! 551: } ! 552: ! 553: /* the assist function for TME_SPARC_RECODE_INSN_ASSIST_FULL ! 554: instructions: */ ! 555: static tme_recode_uguest_t ! 556: _tme_sparc_recode_insn_assist_full(struct tme_ic *_ic, ! 557: tme_recode_uguest_t _rs1, ! 558: tme_recode_uguest_t _rs2) ! 559: { ! 560: struct tme_sparc *ic; ! 561: tme_uint32_t sparc_insn; ! 562: unsigned int reg_rs1; ! 563: unsigned int reg_rs2; ! 564: unsigned int reg_rd; ! 565: tme_uint32_t sparc_opcode; ! 566: ! 567: /* recover our ic: */ ! 568: ic = (struct tme_sparc *) _ic; ! 569: ! 570: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_full); ! 571: ! 572: /* set PC_next_next from PC_next: */ ! 573: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) ! 574: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT) ! 575: + sizeof(tme_uint32_t)); ! 576: ! 577: /* copy the instruction from the internal register into its normal ! 578: position: */ ! 579: sparc_insn = ic->tme_sparc_ireg(TME_SPARC_IREG_INSN); ! 580: ic->_tme_sparc_insn = sparc_insn; ! 581: ! 582: /* if the i bit is zero: */ ! 583: if (__tme_predict_true((sparc_insn & TME_BIT(13)) == 0)) { ! 584: ! 585: /* decode rs2: */ ! 586: reg_rs2 = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2); ! 587: TME_SPARC_REG_INDEX(ic, reg_rs2); ! 588: } ! 589: ! 590: /* otherwise, the i bit is one: */ ! 591: else { ! 592: ! 593: /* decode simm13: */ ! 594: ic->tme_sparc_ireg(TME_SPARC_IREG_TMP(0)) = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x1fff); ! 595: reg_rs2 = TME_SPARC_IREG_TMP(0); ! 596: } ! 597: ! 598: /* decode rs1: */ ! 599: reg_rs1 = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1); ! 600: TME_SPARC_REG_INDEX(ic, reg_rs1); ! 601: ! 602: /* decode rd: */ ! 603: reg_rd = TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD); ! 604: TME_SPARC_REG_INDEX(ic, reg_rd); ! 605: ! 606: /* form the opcode index: */ ! 607: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19)); ! 608: sparc_opcode += ((sparc_insn >> (30 - 6)) & 0x40); ! 609: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_opcode[sparc_opcode]); ! 610: ! 611: /* run the instruction: */ ! 612: (*ic->_tme_sparc_execute_opmap[sparc_opcode]) ! 613: (ic, ! 614: &ic->tme_sparc_ireg(reg_rs1), ! 615: &ic->tme_sparc_ireg(reg_rs2), ! 616: &ic->tme_sparc_ireg(reg_rd)); ! 617: ! 618: /* set %g0 to zero, in case the instruction changed it: */ ! 619: ic->tme_sparc_ireg(TME_SPARC_G0_OFFSET(ic) + TME_SPARC_IREG_G0) = 0; ! 620: ! 621: /* return no result */ ! 622: return (tme_sparc_recode_insn_assist_redispatch(ic)); ! 623: ! 624: /* unused: */ ! 625: _rs1 = 0; ! 626: _rs2 = 0; ! 627: } ! 628: ! 629: /* the assist function for jmpl instructions: */ ! 630: static tme_recode_uguest_t ! 631: _tme_sparc_recode_insn_assist_jmpl(struct tme_ic *_ic, ! 632: tme_recode_uguest_t rs1, ! 633: tme_recode_uguest_t rs2) ! 634: { ! 635: struct tme_sparc *ic; ! 636: tme_sparc_ireg_t pc_next_next; ! 637: tme_uint32_t ls_faults; ! 638: ! 639: /* recover our ic: */ ! 640: ic = (struct tme_sparc *) _ic; ! 641: ! 642: TME_SPARC_STAT(ic, tme_sparc_stats_recode_assist_opcode[0x38 /* jmpl */]); ! 643: ! 644: /* get the target address: */ ! 645: pc_next_next = ((tme_sparc_ireg_t) rs1) + (tme_sparc_ireg_t) rs2; ! 646: ! 647: /* assume that the target address will not fault: */ ! 648: ls_faults = TME_SPARC_LS_FAULT_NONE; ! 649: ! 650: #if TME_SPARC_VERSION(ic) >= 9 ! 651: ! 652: /* mask the target address: */ ! 653: pc_next_next &= ic->tme_sparc_address_mask; ! 654: ! 655: /* if the target address is in a virtual address hole: */ ! 656: if (__tme_predict_false((pc_next_next ! 657: + ic->tme_sparc64_ireg_va_hole_start) ! 658: > ((ic->tme_sparc64_ireg_va_hole_start * 2) - 1))) { ! 659: ! 660: /* the target address is out of range: */ ! 661: ls_faults += TME_SPARC64_LS_FAULT_VA_RANGE_NNPC; ! 662: } ! 663: ! 664: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 665: ! 666: /* if the target address is not 32-bit aligned: */ ! 667: if (__tme_predict_false((((tme_uint32_t) pc_next_next) % sizeof(tme_uint32_t)) != 0)) { ! 668: ! 669: /* the target address is misaligned: */ ! 670: ls_faults += TME_SPARC_LS_FAULT_ADDRESS_NOT_ALIGNED; ! 671: } ! 672: ! 673: /* if the target address has faulted: */ ! 674: if (__tme_predict_false(ls_faults != TME_SPARC_LS_FAULT_NONE)) { ! 675: ! 676: /* set PC_next from PC: */ ! 677: /* NB: we don't need to set PC_next_next, because we're ! 678: faulting: */ ! 679: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT) ! 680: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC) ! 681: + sizeof(tme_uint32_t)); ! 682: ! 683: /* in case a CPU-specific trap function needs it, store a dummy ! 684: jmpl instruction: */ ! 685: ic->_tme_sparc_insn ! 686: = ((((tme_uint32_t) 2) << 30) ! 687: + (0x38 << 19) /* jmpl */ ! 688: ); ! 689: ! 690: /* fault: */ ! 691: tme_sparc_nnpc_trap(ic, ls_faults); ! 692: } ! 693: ! 694: /* return the target address: */ ! 695: return (pc_next_next); ! 696: } ! 697: ! 698: /* the assist function for unimplemented instructions: */ ! 699: static tme_recode_uguest_t ! 700: _tme_sparc_recode_insn_assist_unimpl(struct tme_ic *_ic, ! 701: tme_recode_uguest_t _rs1, ! 702: tme_recode_uguest_t _rs2) ! 703: { ! 704: struct tme_sparc *ic; ! 705: ! 706: /* recover our ic: */ ! 707: ic = (struct tme_sparc *) _ic; ! 708: ! 709: /* set PC_next_next from PC_next: */ ! 710: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) ! 711: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT) ! 712: + sizeof(tme_uint32_t)); ! 713: ! 714: /* trap: */ ! 715: #if TME_SPARC_VERSION(ic) < 9 ! 716: tme_sparc32_trap(ic, TME_SPARC32_TRAP_illegal_instruction); ! 717: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 718: tme_sparc64_trap(ic, TME_SPARC64_TRAP_illegal_instruction); ! 719: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 720: ! 721: /* return no result */ ! 722: return (0); ! 723: ! 724: /* unused: */ ! 725: _rs1 = 0; ! 726: _rs2 = 0; ! 727: } ! 728: ! 729: #ifdef _TME_SPARC_STATS ! 730: static tme_recode_uguest_t ! 731: _tme_sparc_recode_insns_total(struct tme_ic *_ic, ! 732: tme_recode_uguest_t _rs1, ! 733: tme_recode_uguest_t _rs2) ! 734: { ! 735: TME_SPARC_STAT_N(((struct tme_sparc *) _ic), ! 736: tme_sparc_stats_recode_insns_total, ! 737: (tme_uint32_t) _rs2); ! 738: return (0); ! 739: } ! 740: #endif /* _TME_SPARC_STATS */ ! 741: ! 742: /* this returns nonzero if the given instruction can't be recoded in a ! 743: branch delay slot. in general, an instruction can't be recoded in ! 744: a branch delay slot if it may set PC_next_next without doing a ! 745: redispatch, or if it may use a recode if/endif: */ ! 746: static int ! 747: _tme_sparc_recode_insn_branch_delay_bad(tme_uint32_t sparc_insn) ! 748: { ! 749: unsigned int sparc_opcode; ! 750: ! 751: /* if this is a format three instruction, and op is three: */ ! 752: if (sparc_insn >= 0xc0000000) { ! 753: ! 754: /* all of the instructions with op equal to three can be recoded ! 755: in a branch delay slot: */ ! 756: return (FALSE); ! 757: } ! 758: ! 759: /* otherwise, if this is a format three instruction, and op is ! 760: two: */ ! 761: else if (sparc_insn >= 0x80000000) { ! 762: ! 763: /* form the opcode index: */ ! 764: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19)); ! 765: ! 766: /* instructions that may set PC_next_next without doing a ! 767: redispatch, and instructions that may use a recode if/endif ! 768: can't be recoded in a branch delay slot: */ ! 769: return (sparc_opcode == 0x38 /* jmpl */ ! 770: || (TME_SPARC_VERSION(ic) >= 9 ! 771: && (sparc_opcode == 0x2c /* v9: movcc */ ! 772: || sparc_opcode == 0x2f))); /* v9: movr */ ! 773: } ! 774: ! 775: /* otherwise, if this is a format two instruction: */ ! 776: else if (__tme_predict_true(sparc_insn < 0x40000000)) { ! 777: ! 778: /* except for sethi instructions, format two instructions can't be ! 779: recoded in a branch delay slot - the other implemented format ! 780: two instructions are all branches that set PC_next_next: */ ! 781: return ((sparc_insn & (0x7 << 22)) != (0x4 << 22)); ! 782: } ! 783: ! 784: /* otherwise, this is a format three instruction: */ ! 785: else { ! 786: ! 787: /* we can't recode call instructions in branch delay slots, since ! 788: they set PC_next_next: */ ! 789: return (TRUE); ! 790: } ! 791: } ! 792: ! 793: /* the sparc instruction recoder: */ ! 794: static tme_recode_thunk_off_t ! 795: _tme_sparc_recode_recode(struct tme_sparc *ic, ! 796: const struct tme_sparc_tlb *itlb) ! 797: { ! 798: tme_uint32_t page_size; ! 799: unsigned int reg_guest_pc; ! 800: unsigned int recode_size_address; ! 801: struct tme_recode_insn *recode_insn; ! 802: struct tme_recode_insn *recode_insns_last_start; ! 803: tme_sparc_ireg_t pc_next; ! 804: tme_uint32_t sparc_insn_next; ! 805: tme_uint32_t sparc_insn_count; ! 806: tme_uint32_t pc_advance; ! 807: tme_uint32_t sparc_recode; ! 808: tme_sparc_ireg_t itlb_addr_last; ! 809: tme_recode_uguest_t (*sparc_assist) _TME_P((struct tme_ic *, tme_recode_uguest_t, tme_recode_uguest_t)); ! 810: tme_uint32_t sparc_insn; ! 811: tme_uint32_t sparc_opcode; ! 812: int recode_operand; ! 813: tme_sparc_ireg_t imm; ! 814: unsigned int shift_count_mask; ! 815: unsigned int cond; ! 816: const struct tme_recode_conds_thunk *conds_thunk; ! 817: tme_int32_t branch_displacement_raw; ! 818: tme_sparc_ireg_t branch_displacement; ! 819: const struct tme_recode_flags_thunk *flags_thunk; ! 820: int recode_operand_address; ! 821: tme_uint32_t chain_info; ! 822: ! 823: /* get the page size: */ ! 824: page_size = (((tme_uint32_t) 1) << ic->tme_sparc_tlb_page_size_log2); ! 825: ! 826: /* on entry to this function, PC has already been updated to be the ! 827: first instruction. on entry to an instructions thunk, PC hasn't ! 828: been updated yet, and PC_next is the first instruction: */ ! 829: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT); ! 830: ! 831: /* assume that addresses are guest size: */ ! 832: recode_size_address = TME_SPARC_RECODE_SIZE(ic); ! 833: ! 834: /* if this is a v9 CPU and PSTATE.AM is set: */ ! 835: if (TME_SPARC_VERSION(ic) >= 9 ! 836: && (ic->tme_sparc64_ireg_pstate ! 837: & TME_SPARC64_PSTATE_AM)) { ! 838: ! 839: /* addresses are only 32 bits wide: */ ! 840: recode_size_address = TME_RECODE_SIZE_32; ! 841: } ! 842: ! 843: /* start at the beginning of the recode instructions buffer: */ ! 844: recode_insn = &ic->tme_sparc_recode_insns[0]; ! 845: ! 846: /* calculate the worst-case position in the recode instructions ! 847: buffer, past which we may not be able to recode another sparc ! 848: instruction. this is actually an upper bound on the worst case, ! 849: found by counting the number of "recode_insn++" statements in ! 850: this function, and multiplying that by two so that branch ! 851: instructions can loop to recode a branch delay slot: */ ! 852: recode_insns_last_start = &ic->tme_sparc_recode_insns[TME_ARRAY_ELS(ic->tme_sparc_recode_insns) - (35 * 2)]; ! 853: ! 854: /* fetch the first instruction as the next instruction: */ ! 855: pc_next = ic->tme_sparc_ireg(TME_SPARC_IREG_PC); ! 856: sparc_insn_next ! 857: = tme_memory_bus_read32(((const tme_shared tme_uint32_t *) ! 858: (itlb->tme_sparc_tlb_emulator_off_read ! 859: + pc_next)), ! 860: itlb->tme_sparc_tlb_bus_rwlock, ! 861: sizeof(tme_uint32_t), ! 862: sizeof(tme_sparc_ireg_t)); ! 863: sparc_insn_next = tme_betoh_u32(sparc_insn_next); ! 864: sparc_insn_count = 0; ! 865: ! 866: /* the next instruction will be the first instruction: */ ! 867: pc_advance = 0 - (tme_uint32_t) sizeof(sparc_insn_next); ! 868: ! 869: /* clear the recode information: */ ! 870: sparc_recode = 0; ! 871: ! 872: /* if PC is at the last instruction address before tme_sparc_ireg_t ! 873: wrapping: */ ! 874: /* NB: we don't consider the v9 address mask here, because we only ! 875: need to protect against the pc_next local variable itself ! 876: wrapping its tme_sparc_ireg_t. if the v9 address mask is set for ! 877: 32 bits and PC is 0xfffffffc, pc_next will not wrap to zero - ! 878: instead it will advance to 0x100000000, but we also won't ! 879: continue to recode because that address is on a different ! 880: page: */ ! 881: assert (TME_SPARC_VERSION(ic) < 9 ! 882: || (pc_next < ic->tme_sparc_address_mask)); ! 883: if (__tme_predict_false(pc_next ! 884: == (tme_sparc_ireg_t) (0 - (tme_sparc_ireg_t) sizeof(tme_uint32_t)))) { ! 885: ! 886: /* recode is impossible here: */ ! 887: return (0); ! 888: } ! 889: ! 890: /* stop recoding after the last instruction on the page, or right ! 891: before the last instruction before tme_sparc_ireg_t wrapping, ! 892: whichever comes first: */ ! 893: itlb_addr_last ! 894: = ((pc_next ! 895: | (page_size - 1)) ! 896: - (sizeof(tme_uint32_t) - 1)); ! 897: if (__tme_predict_false(itlb_addr_last ! 898: == (tme_sparc_ireg_t) (0 - (tme_sparc_ireg_t) sizeof(tme_uint32_t)))) { ! 899: itlb_addr_last -= sizeof(tme_uint32_t); ! 900: } ! 901: assert (itlb_addr_last >= pc_next); ! 902: assert (itlb->tme_sparc_tlb_addr_last >= itlb_addr_last); ! 903: ! 904: /* loop recoding instructions: */ ! 905: for (;;) { ! 906: ! 907: /* reset the assist function: */ ! 908: sparc_assist = _tme_sparc_recode_insn_assist; ! 909: ! 910: /* make the next instruction the current instruction: */ ! 911: pc_advance += sizeof(sparc_insn); ! 912: sparc_insn = sparc_insn_next; ! 913: sparc_insn_count++; ! 914: ! 915: /* advance the PC of the next instruction: */ ! 916: pc_next += sizeof(sparc_insn); ! 917: ! 918: /* if the PC of the next instruction is still in this ! 919: page: */ ! 920: if (__tme_predict_true(pc_next <= itlb_addr_last)) { ! 921: ! 922: /* fetch the next instruction: */ ! 923: sparc_insn_next ! 924: = tme_memory_bus_read32(((const tme_shared tme_uint32_t *) ! 925: (itlb->tme_sparc_tlb_emulator_off_read ! 926: + pc_next)), ! 927: itlb->tme_sparc_tlb_bus_rwlock, ! 928: sizeof(tme_uint32_t), ! 929: sizeof(tme_sparc_ireg_t)); ! 930: sparc_insn_next = tme_betoh_u32(sparc_insn_next); ! 931: } ! 932: ! 933: /* otherwise, the instruction TLB entry doesn't cover the PC of ! 934: the next instruction: */ ! 935: else { ! 936: ! 937: /* the current instruction is the last instruction, and we need ! 938: to update the PC registers: */ ! 939: sparc_recode |= TME_SPARC_RECODE_INSN_LAST | TME_SPARC_RECODE_INSN_UPDATE_PCS; ! 940: ! 941: /* in case the current instruction is a control transfer ! 942: instruction, poison the next instruction to look like another ! 943: control transfer instruction. we use a call instruction: */ ! 944: sparc_insn_next = 0x40000000; ! 945: } ! 946: ! 947: /* if this is a format three instruction (op is two or three): */ ! 948: if (__tme_predict_true(sparc_insn >= 0x80000000)) { ! 949: ! 950: /* form the opcode index: */ ! 951: sparc_opcode = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x3f << 19)); ! 952: sparc_opcode += ((sparc_insn >> (30 - 6)) & 0x40); ! 953: ! 954: /* add in the recode information for this instruction: */ ! 955: sparc_recode |= _tme_sparc_recode_insn_opmap[sparc_opcode]; ! 956: ! 957: /* if this is a jmpl instruction: */ ! 958: if (__tme_predict_false(sparc_opcode == 0x38)) { ! 959: ! 960: /* if the next instruction can't be recoded when it's in a ! 961: branch delay slot (usually because it's also a control ! 962: transfer instruction): */ ! 963: if (__tme_predict_false(_tme_sparc_recode_insn_branch_delay_bad(sparc_insn_next))) { ! 964: ! 965: /* if we haven't recoded any instructions yet, recode is ! 966: impossible here: */ ! 967: if (recode_insn == &ic->tme_sparc_recode_insns[0]) { ! 968: return (0); ! 969: } ! 970: ! 971: /* stop recoding immediately, leaving the updated PC ! 972: pointing to the instruction before the jmpl: */ ! 973: assert (pc_advance >= sizeof(sparc_insn)); ! 974: pc_advance -= sizeof(sparc_insn); ! 975: sparc_insn_count--; ! 976: sparc_recode ! 977: |= (TME_SPARC_RECODE_INSN_UPDATE_PCS ! 978: | TME_SPARC_RECODE_INSN_NONE ! 979: | TME_SPARC_RECODE_INSN_LAST); ! 980: } ! 981: ! 982: /* otherwise, the next instruction can be recoded when it's in ! 983: a branch delay slot: */ ! 984: else { ! 985: ! 986: /* if PC doesn't already point to the jmpl instruction: */ ! 987: if (pc_advance != 0 ! 988: || reg_guest_pc != TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC)) { ! 989: ! 990: /* advance PC to the jmpl instruction: */ ! 991: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 992: recode_insn->tme_recode_insn_size = recode_size_address; ! 993: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc; ! 994: recode_insn->tme_recode_insn_operand_src[1] ! 995: = (pc_advance == 0 ! 996: ? TME_RECODE_OPERAND_ZERO ! 997: : TME_RECODE_OPERAND_IMM); ! 998: recode_insn->tme_recode_insn_imm_uguest = pc_advance; ! 999: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1000: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1001: recode_insn++; ! 1002: } ! 1003: ! 1004: /* if rs1 is %i7 or %o7, assume that this jmpl is doing a ! 1005: return, otherwise assume that this jmpl is doing a ! 1006: call. either way, the branch delay slot will be the ! 1007: last instruction: */ ! 1008: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1)); ! 1009: sparc_recode ! 1010: |= ((((recode_operand ! 1011: - TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) ! 1012: & 15 /* %o7 */) ! 1013: == 15 /* %o7 */) ! 1014: ? (TME_SPARC_RECODE_INSN_LAST ! 1015: + TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_RETURN ! 1016: + TME_RECODE_CHAIN_INFO_FAR ! 1017: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL)) ! 1018: : (TME_SPARC_RECODE_INSN_LAST ! 1019: + TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_CALL ! 1020: + TME_RECODE_CHAIN_INFO_FAR ! 1021: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL))); ! 1022: ! 1023: /* call the jmpl assist function. if this doesn't trap, it ! 1024: returns the target address for PC_next_next, which we put ! 1025: directly into PC_next: */ ! 1026: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_GUEST; ! 1027: recode_insn->tme_recode_insn_size = recode_size_address; ! 1028: recode_insn->tme_recode_insn_operand_src[0] ! 1029: = (recode_operand == TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0) ! 1030: ? TME_RECODE_OPERAND_ZERO ! 1031: : recode_operand); ! 1032: if (__tme_predict_true(sparc_insn & TME_BIT(13))) { ! 1033: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1034: recode_insn->tme_recode_insn_imm_uguest ! 1035: = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x1fff); ! 1036: } ! 1037: else { ! 1038: recode_insn->tme_recode_insn_operand_src[1] ! 1039: = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2)); ! 1040: } ! 1041: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT); ! 1042: recode_insn->tme_recode_insn_guest_func = _tme_sparc_recode_insn_assist_jmpl; ! 1043: recode_insn++; ! 1044: ! 1045: /* assume that rd is %g0: */ ! 1046: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1047: ! 1048: /* decode rd: */ ! 1049: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD)); ! 1050: ! 1051: /* if rd is not %g0: */ ! 1052: if (recode_operand != TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) { ! 1053: ! 1054: /* we will soon be able to find the PC of the jmpl in rd: */ ! 1055: reg_guest_pc = recode_operand; ! 1056: ! 1057: /* write the PC of the jmpl into the destination register: */ ! 1058: /* NB: we don't use recode_size_address here because we need to ! 1059: update the entire destination register: */ ! 1060: recode_insn->tme_recode_insn_operand_dst = recode_operand; ! 1061: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1062: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1063: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO; ! 1064: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1065: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1066: recode_insn++; ! 1067: } ! 1068: ! 1069: /* advance PC to the branch delay slot: */ ! 1070: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1071: recode_insn->tme_recode_insn_size = recode_size_address; ! 1072: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc; ! 1073: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1074: recode_insn->tme_recode_insn_imm_uguest = sizeof(sparc_insn); ! 1075: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1076: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1077: recode_insn++; ! 1078: pc_advance = 0 - (tme_uint32_t) sizeof(sparc_insn); ! 1079: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1080: ! 1081: /* loop now to fetch and recode the instruction in the branch ! 1082: delay slot: */ ! 1083: continue; ! 1084: } ! 1085: } ! 1086: ! 1087: /* otherwise, if this is a v9 movcc instruction: */ ! 1088: else if (__tme_predict_false(TME_SPARC_VERSION(ic) >= 9 ! 1089: && sparc_opcode == 0x2c)) { ! 1090: ! 1091: /* if cc2 is clear, or if cc1 is set, this is not an integer ! 1092: movcc: */ ! 1093: if (__tme_predict_false((sparc_insn ! 1094: & (TME_BIT(18) ! 1095: | TME_BIT(11))) ! 1096: != TME_BIT(18))) { ! 1097: ! 1098: /* this instruction needs a full assist: */ ! 1099: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL; ! 1100: } ! 1101: ! 1102: /* otherwise, this is an integer movcc: */ ! 1103: else { ! 1104: ! 1105: /* get the condition field: */ ! 1106: cond = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xf << 14)); ! 1107: ! 1108: /* get the conditions thunk to test: */ ! 1109: conds_thunk ! 1110: = ((sparc_insn & TME_BIT(12)) ! 1111: ? ic->tme_sparc_recode_conds_thunk_xcc ! 1112: : ic->tme_sparc_recode_conds_thunk_icc); ! 1113: ! 1114: /* define the first recode flag with the condition: */ ! 1115: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_DEFC; ! 1116: recode_insn->tme_recode_insn_operand_src[0] = (cond % TME_SPARC_COND_NOT); ! 1117: recode_insn->tme_recode_insn_operand_src[1] = 0 - (int) (cond / TME_SPARC_COND_NOT); ! 1118: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_FLAG(0); ! 1119: recode_insn->tme_recode_insn_conds_thunk = conds_thunk; ! 1120: recode_insn++; ! 1121: ! 1122: /* emit the if to test the first recode carry flag: */ ! 1123: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_IF; ! 1124: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_FLAG(0); ! 1125: recode_insn++; ! 1126: ! 1127: /* move the source operand to the destination register: */ ! 1128: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1129: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1130: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO; ! 1131: if (sparc_insn & TME_BIT(13)) { ! 1132: recode_insn->tme_recode_insn_imm_uguest ! 1133: = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x7ff); ! 1134: recode_operand = TME_RECODE_OPERAND_IMM; ! 1135: } ! 1136: else { ! 1137: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2)); ! 1138: } ! 1139: recode_insn->tme_recode_insn_operand_src[1] = recode_operand; ! 1140: recode_insn->tme_recode_insn_operand_dst ! 1141: = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD)); ! 1142: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1143: recode_insn++; ! 1144: ! 1145: /* emit the endif: */ ! 1146: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ENDIF; ! 1147: recode_insn++; ! 1148: ! 1149: /* suppress any instructions below: */ ! 1150: sparc_recode |= TME_SPARC_RECODE_INSN_NONE; ! 1151: } ! 1152: } ! 1153: ! 1154: /* otherwise, if this is a v9 movr instruction: */ ! 1155: else if (__tme_predict_false(TME_SPARC_VERSION(ic) >= 9 ! 1156: && sparc_opcode == 0x2f)) { ! 1157: ! 1158: /* get the condition field: */ ! 1159: cond = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x7 << 10)); ! 1160: ! 1161: /* this shifts the "not" bit in the condition up from bit ! 1162: two to bit three, to match the other branches: */ ! 1163: cond = (cond + 4) & (TME_SPARC_COND_NOT | 3); ! 1164: ! 1165: /* if this is an unimplemented movr: */ ! 1166: if (__tme_predict_false(!TME_SPARC_COND_IS_CONDITIONAL(cond))) { ! 1167: ! 1168: /* this instruction needs a full assist: */ ! 1169: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL; ! 1170: } ! 1171: ! 1172: /* otherwise, this is an implemented movr: */ ! 1173: else { ! 1174: ! 1175: /* test the register and set the internal "rcc" flags: */ ! 1176: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1)); ! 1177: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_AND; ! 1178: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1179: recode_insn->tme_recode_insn_operand_src[0] = recode_operand; ! 1180: recode_insn->tme_recode_insn_operand_src[1] = recode_operand; ! 1181: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_OPERAND_NULL; ! 1182: recode_insn->tme_recode_insn_flags_thunk = ic->tme_sparc_recode_flags_thunk_rcc; ! 1183: recode_insn++; ! 1184: ! 1185: /* define the first recode flag with the condition: */ ! 1186: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_DEFC; ! 1187: recode_insn->tme_recode_insn_operand_src[0] = (cond % TME_SPARC_COND_NOT); ! 1188: recode_insn->tme_recode_insn_operand_src[1] = 0 - (int) (cond / TME_SPARC_COND_NOT); ! 1189: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_FLAG(0); ! 1190: recode_insn->tme_recode_insn_conds_thunk = ic->tme_sparc_recode_conds_thunk_rcc; ! 1191: recode_insn++; ! 1192: ! 1193: /* emit the if to test the first recode carry flag: */ ! 1194: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_IF; ! 1195: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_FLAG(0); ! 1196: recode_insn++; ! 1197: ! 1198: /* move the source operand to the destination register: */ ! 1199: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1200: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1201: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO; ! 1202: if (sparc_insn & TME_BIT(13)) { ! 1203: recode_insn->tme_recode_insn_imm_uguest ! 1204: = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x3ff); ! 1205: recode_operand = TME_RECODE_OPERAND_IMM; ! 1206: } ! 1207: else { ! 1208: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2)); ! 1209: } ! 1210: recode_insn->tme_recode_insn_operand_src[1] = recode_operand; ! 1211: recode_insn->tme_recode_insn_operand_dst ! 1212: = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD)); ! 1213: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1214: recode_insn++; ! 1215: ! 1216: /* emit the endif: */ ! 1217: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ENDIF; ! 1218: recode_insn++; ! 1219: ! 1220: /* suppress any instructions below: */ ! 1221: sparc_recode |= TME_SPARC_RECODE_INSN_NONE; ! 1222: } ! 1223: } ! 1224: ! 1225: /* otherwise, if this is a v9 ld*a instruction: */ ! 1226: /* NB: all of the simple ld and st instructions that we handle ! 1227: here, have bit 21 (bit 2 in the opcode) set for a st, and ! 1228: clear for a ld: */ ! 1229: else if (__tme_predict_false(TME_SPARC_VERSION(ic) >= 9 ! 1230: && TME_SPARC_RECODE_INSN_OPCODE(sparc_recode) == TME_RECODE_OPCODE_RW ! 1231: && ((sparc_opcode ! 1232: & (TME_BIT(4) ! 1233: + TME_BIT(2))) ! 1234: == (TME_BIT(4) ! 1235: + !TME_BIT(2))))) { ! 1236: ! 1237: /* if the i bit is clear, and the immediate ASI is not ! 1238: ASI_PRIMARY_NOFAULT or ASI_PRIMARY_NOFAULT_LITTLE: */ ! 1239: if ((sparc_insn & TME_BIT(13)) == 0 ! 1240: && (TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xff << 5)) ! 1241: != (TME_SPARC64_ASI_FLAG_UNRESTRICTED ! 1242: + ((ic->tme_sparc64_ireg_pstate & TME_SPARC64_PSTATE_CLE) ! 1243: ? TME_SPARC64_ASI_FLAG_LITTLE ! 1244: : !TME_SPARC64_ASI_FLAG_LITTLE) ! 1245: + TME_SPARC64_ASI_FLAG_NO_FAULT))) { ! 1246: ! 1247: /* this instruction can't be a simple ld instruction: */ ! 1248: sparc_recode ! 1249: ^= (TME_SPARC_RECODE_INSN_LDA ! 1250: ^ TME_SPARC_RECODE_INSN_ASSIST_CANTRAP); ! 1251: } ! 1252: } ! 1253: ! 1254: /* if this instruction needs a full assist: */ ! 1255: if ((sparc_recode ! 1256: & (TME_SPARC_RECODE_INSN_OPCODE_MASK ! 1257: | TME_SPARC_RECODE_INSN_NO_RS2 ! 1258: | TME_SPARC_RECODE_INSN_NO_RS1)) ! 1259: == (TME_RECODE_OPCODE_GUEST ! 1260: | TME_SPARC_RECODE_INSN_NO_RS2 ! 1261: | TME_SPARC_RECODE_INSN_NO_RS1)) { ! 1262: ! 1263: /* set the full assist function: */ ! 1264: sparc_assist = _tme_sparc_recode_insn_assist_full; ! 1265: } ! 1266: } ! 1267: ! 1268: /* otherwise, if this is a format two instruction: */ ! 1269: else if (__tme_predict_true(sparc_insn < 0x40000000)) { ! 1270: ! 1271: /* dispatch on op2: */ ! 1272: switch (TME_FIELD_MASK_EXTRACTU(sparc_insn, (0x7 << 22))) { ! 1273: ! 1274: default: ! 1275: case 0: /* UNIMP: */ ! 1276: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST; ! 1277: sparc_assist = _tme_sparc_recode_insn_assist_unimpl; ! 1278: break; ! 1279: ! 1280: #if TME_SPARC_VERSION(ic) >= 9 ! 1281: case 1: /* BPcc */ ! 1282: case 3: /* BPr */ ! 1283: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 1284: case 2: /* Bicc: */ ! 1285: ! 1286: /* if the next instruction can't be recoded when it's in a ! 1287: branch delay slot (usually because it's also a control ! 1288: transfer instruction): */ ! 1289: if (__tme_predict_false(_tme_sparc_recode_insn_branch_delay_bad(sparc_insn_next))) { ! 1290: ! 1291: /* if we haven't recoded any instructions yet, recode is ! 1292: impossible here: */ ! 1293: if (recode_insn == &ic->tme_sparc_recode_insns[0]) { ! 1294: return (0); ! 1295: } ! 1296: ! 1297: /* stop recoding immediately, leaving the updated PC ! 1298: pointing to the instruction before the jmpl: */ ! 1299: assert (pc_advance >= sizeof(sparc_insn)); ! 1300: pc_advance -= sizeof(sparc_insn); ! 1301: sparc_insn_count--; ! 1302: sparc_recode ! 1303: |= (TME_SPARC_RECODE_INSN_UPDATE_PCS ! 1304: | TME_SPARC_RECODE_INSN_NONE ! 1305: | TME_SPARC_RECODE_INSN_LAST); ! 1306: break; ! 1307: } ! 1308: ! 1309: /* get the condition field: */ ! 1310: cond = TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xf << 25)); ! 1311: ! 1312: /* assume that this branch instruction tests a condition in ! 1313: the icc flags: */ ! 1314: conds_thunk = ic->tme_sparc_recode_conds_thunk_icc; ! 1315: ! 1316: /* if this is a BPr or a BPcc: */ ! 1317: if (TME_SPARC_VERSION(ic) >= 9 ! 1318: && (sparc_insn & (0x1 << 22))) { ! 1319: ! 1320: /* if this is a BPr: */ ! 1321: if (sparc_insn & (0x2 << 22)) { ! 1322: ! 1323: /* if this is an unimplemented BPr instruction: */ ! 1324: if (__tme_predict_false((sparc_insn & (1 << 28)) != 0 ! 1325: || (sparc_insn & (3 << 25)) == 0)) { ! 1326: ! 1327: /* do a full assist and stop recoding: */ ! 1328: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST; ! 1329: sparc_assist = _tme_sparc_recode_insn_assist_unimpl; ! 1330: break; ! 1331: } ! 1332: ! 1333: /* test the register and set the internal "rcc" flags: */ ! 1334: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1)); ! 1335: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_AND; ! 1336: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1337: recode_insn->tme_recode_insn_operand_src[0] = recode_operand; ! 1338: recode_insn->tme_recode_insn_operand_src[1] = recode_operand; ! 1339: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_OPERAND_NULL; ! 1340: recode_insn->tme_recode_insn_flags_thunk = ic->tme_sparc_recode_flags_thunk_rcc; ! 1341: recode_insn++; ! 1342: ! 1343: /* this shifts the "not" bit in the condition up from bit ! 1344: two to bit three, to match the other branches: */ ! 1345: cond = (cond + 4) & (TME_SPARC_COND_NOT | 3); ! 1346: ! 1347: /* we need to test the condition in the internal "rcc" flags: */ ! 1348: conds_thunk = ic->tme_sparc_recode_conds_thunk_rcc; ! 1349: ! 1350: /* get the raw branch displacement: */ ! 1351: branch_displacement_raw ! 1352: = ((tme_int16_t) ! 1353: (((sparc_insn & (0x3 << 20)) >> 6) ! 1354: | (sparc_insn & 0x3fff))); ! 1355: } ! 1356: ! 1357: /* otherwise, this is a BPcc: */ ! 1358: else { ! 1359: ! 1360: /* if this is an unimplemented BPcc instruction: */ ! 1361: if (__tme_predict_false((sparc_insn & (1 << 20)) != 0)) { ! 1362: ! 1363: /* do a full assist and stop recoding: */ ! 1364: sparc_recode |= TME_SPARC_RECODE_INSN_ASSIST_FULL | TME_SPARC_RECODE_INSN_LAST; ! 1365: sparc_assist = _tme_sparc_recode_insn_assist_unimpl; ! 1366: break; ! 1367: } ! 1368: ! 1369: /* if this BPcc is testing the xcc flags: */ ! 1370: if (sparc_insn & (1 << 21)) { ! 1371: conds_thunk = ic->tme_sparc_recode_conds_thunk_xcc; ! 1372: } ! 1373: ! 1374: /* get the raw branch displacement: */ ! 1375: branch_displacement_raw ! 1376: = ((tme_int32_t) ! 1377: TME_FIELD_MASK_EXTRACTS(sparc_insn, 0x0007ffff)); ! 1378: } ! 1379: } ! 1380: ! 1381: /* otherwise, this is a Bicc: */ ! 1382: else { ! 1383: ! 1384: /* get the raw branch displacement: */ ! 1385: branch_displacement_raw ! 1386: = ((tme_int32_t) ! 1387: TME_FIELD_MASK_EXTRACTS(sparc_insn, 0x003fffff)); ! 1388: } ! 1389: ! 1390: /* fully sign-extend the branch displacement: */ ! 1391: branch_displacement ! 1392: = ((tme_sparc_ireg_t) ! 1393: (tme_recode_guest_t) ! 1394: branch_displacement_raw); ! 1395: ! 1396: /* advance PC to the branch delay slot: */ ! 1397: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1398: recode_insn->tme_recode_insn_size = recode_size_address; ! 1399: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc; ! 1400: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1401: recode_insn->tme_recode_insn_imm_uguest = pc_advance + sizeof(sparc_insn); ! 1402: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1403: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1404: recode_insn++; ! 1405: pc_advance = 0 - (tme_uint32_t) sizeof(sparc_insn); ! 1406: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1407: ! 1408: /* if this isn't a branch always: */ ! 1409: if (cond != (TME_SPARC_COND_NOT | TME_SPARC_COND_N)) { ! 1410: ! 1411: /* assuming that the branch won't be taken, set PC_next to ! 1412: the instruction following the branch delay slot: */ ! 1413: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1414: recode_insn->tme_recode_insn_size = recode_size_address; ! 1415: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1416: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1417: recode_insn->tme_recode_insn_imm_uguest = sizeof(sparc_insn); ! 1418: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT); ! 1419: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1420: recode_insn++; ! 1421: } ! 1422: ! 1423: /* if this is a conditional branch: */ ! 1424: if (TME_SPARC_COND_IS_CONDITIONAL(cond)) { ! 1425: ! 1426: /* define the recode jump flag with the condition: */ ! 1427: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_DEFC; ! 1428: recode_insn->tme_recode_insn_operand_src[0] = (cond % TME_SPARC_COND_NOT); ! 1429: recode_insn->tme_recode_insn_operand_src[1] = 0 - (int) (cond / TME_SPARC_COND_NOT); ! 1430: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_FLAG_JUMP; ! 1431: recode_insn->tme_recode_insn_conds_thunk = conds_thunk; ! 1432: recode_insn++; ! 1433: ! 1434: /* emit the if to test the recode jump flag: */ ! 1435: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_IF; ! 1436: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_FLAG_JUMP; ! 1437: recode_insn++; ! 1438: } ! 1439: ! 1440: /* if this isn't a branch never: */ ! 1441: if (cond != TME_SPARC_COND_N) { ! 1442: ! 1443: /* if this branch target is within this same page, this chain ! 1444: can be near, otherwise it must be far: */ ! 1445: if ((((pc_next - sizeof(sparc_insn)) ! 1446: + (branch_displacement * sizeof(sparc_insn))) ! 1447: ^ (pc_next - sizeof(sparc_insn))) ! 1448: < page_size) { ! 1449: sparc_recode |= TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_NEAR); ! 1450: } ! 1451: else { ! 1452: sparc_recode |= TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_FAR); ! 1453: } ! 1454: ! 1455: /* if this is a branch always: */ ! 1456: if (cond == (TME_SPARC_COND_NOT | TME_SPARC_COND_N)) { ! 1457: ! 1458: /* the branch delay slot will be the last instruction, and ! 1459: after that we need an unconditional jump: */ ! 1460: sparc_recode ! 1461: |= (TME_SPARC_RECODE_INSN_LAST ! 1462: | TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_JUMP ! 1463: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL)); ! 1464: ! 1465: /* set PC_next to the branch target, using the address of ! 1466: the branch delay slot already in PC (which is one ! 1467: instruction away from the PC of the branch, to which ! 1468: the branch displacement is relative): */ ! 1469: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1470: branch_displacement -= 1; ! 1471: } ! 1472: ! 1473: /* otherwise, this is a conditional branch: */ ! 1474: else { ! 1475: ! 1476: /* the branch delay slot will be the last instruction, and ! 1477: after that we need an conditional jump: */ ! 1478: sparc_recode ! 1479: |= (TME_SPARC_RECODE_INSN_LAST ! 1480: | TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_JUMP ! 1481: + TME_RECODE_CHAIN_INFO_CONDITIONAL)); ! 1482: ! 1483: /* change PC_next to the branch target, from the ! 1484: instruction following the branch delay slot already in ! 1485: PC_next (which is two instructions away from the PC of ! 1486: the branch, to which the branch displacement is ! 1487: relative): */ ! 1488: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT); ! 1489: branch_displacement -= 2; ! 1490: } ! 1491: ! 1492: /* set PC_next to the branch target: */ ! 1493: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1494: recode_insn->tme_recode_insn_size = recode_size_address; ! 1495: recode_insn->tme_recode_insn_operand_src[0] = recode_operand; ! 1496: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1497: recode_insn->tme_recode_insn_imm_uguest = branch_displacement * sizeof(sparc_insn); ! 1498: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT); ! 1499: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1500: recode_insn++; ! 1501: } ! 1502: ! 1503: /* if this is a conditional branch: */ ! 1504: if (TME_SPARC_COND_IS_CONDITIONAL(cond)) { ! 1505: ! 1506: /* if this conditional branch never annuls the branch delay ! 1507: slot: */ ! 1508: if ((sparc_insn & TME_BIT(29)) == 0) { ! 1509: ! 1510: /* emit the endif: */ ! 1511: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ENDIF; ! 1512: recode_insn++; ! 1513: } ! 1514: ! 1515: /* otherwise, this conditional branch annuls the branch ! 1516: delay slot if the branch is not taken: */ ! 1517: else { ! 1518: ! 1519: /* we need to emit the endif after we emit the ! 1520: instructions for the branch delay slot: */ ! 1521: sparc_recode |= TME_SPARC_RECODE_INSN_NEED_ENDIF; ! 1522: } ! 1523: } ! 1524: ! 1525: /* otherwise, this is an unconditional branch: */ ! 1526: else { ! 1527: ! 1528: /* if the branch delay slot is annulled: */ ! 1529: if (sparc_insn & TME_BIT(29)) { ! 1530: ! 1531: /* don't bother to recode the instruction in the branch ! 1532: delay slot: */ ! 1533: sparc_recode |= TME_SPARC_RECODE_INSN_NONE; ! 1534: } ! 1535: } ! 1536: ! 1537: /* if this is a branch to . instruction: */ ! 1538: if (__tme_predict_false(branch_displacement_raw == 0)) { ! 1539: ! 1540: /* if this isn't a branch never, and this isn't an ! 1541: unconditional branch that annuls, and the branch with its ! 1542: delay instruction are a supported timing loop: */ ! 1543: if (cond != TME_SPARC_COND_N ! 1544: && (sparc_recode & TME_SPARC_RECODE_INSN_NONE) == 0 ! 1545: && tme_sparc_timing_loop_ok(sparc_insn, ! 1546: sparc_insn_next)) { ! 1547: ! 1548: /* store the branch delay instruction in the instruction register: */ ! 1549: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1550: recode_insn->tme_recode_insn_size = TME_RECODE_SIZE_32; ! 1551: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO; ! 1552: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1553: recode_insn->tme_recode_insn_imm_u32 = sparc_insn_next; ! 1554: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_INSN); ! 1555: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1556: recode_insn++; ! 1557: ! 1558: /* call the timing loop assist function: */ ! 1559: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_GUEST; ! 1560: recode_insn->tme_recode_insn_size = TME_RECODE_SIZE_32; ! 1561: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_IMM; ! 1562: recode_insn->tme_recode_insn_imm_u32 = sparc_insn; ! 1563: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_ZERO; ! 1564: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_OPERAND_NULL; ! 1565: recode_insn->tme_recode_insn_guest_func = tme_sparc_timing_loop_assist; ! 1566: recode_insn++; ! 1567: ! 1568: /* the branch delay instruction must be the last instruction: */ ! 1569: assert (sparc_recode & TME_SPARC_RECODE_INSN_LAST); ! 1570: ! 1571: /* advance to the branch delay instruction: */ ! 1572: assert (((tme_uint32_t) (pc_advance + sizeof(sparc_insn))) == 0 ! 1573: && reg_guest_pc == TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC)); ! 1574: pc_advance = 0; ! 1575: ! 1576: /* suppress the branch delay instruction: */ ! 1577: sparc_recode |= TME_SPARC_RECODE_INSN_NONE; ! 1578: ! 1579: /* do *not* loop now to fetch and recode the instruction ! 1580: in the branch delay slot: */ ! 1581: break; ! 1582: } ! 1583: } ! 1584: ! 1585: /* loop now to fetch and recode the instruction in the branch ! 1586: delay slot: */ ! 1587: continue; ! 1588: ! 1589: case 4: /* SETHI: */ ! 1590: ! 1591: /* unless this instruction is suppressed, load the constant ! 1592: into the register: */ ! 1593: if (!(sparc_recode & TME_SPARC_RECODE_INSN_NONE)) { ! 1594: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD)); ! 1595: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1596: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1597: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO; ! 1598: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1599: recode_insn->tme_recode_insn_imm_u32 = (tme_uint32_t) (sparc_insn << 10); ! 1600: recode_insn->tme_recode_insn_operand_dst = recode_operand; ! 1601: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1602: recode_insn++; ! 1603: } ! 1604: ! 1605: /* suppress any instructions below: */ ! 1606: sparc_recode |= TME_SPARC_RECODE_INSN_NONE; ! 1607: break; ! 1608: ! 1609: #if TME_SPARC_VERSION(ic) >= 9 ! 1610: case 5: /* FBPfcc */ ! 1611: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 1612: case 6: /* FBfcc: */ ! 1613: ! 1614: /* if we haven't recoded any instructions yet, recode is ! 1615: impossible here: */ ! 1616: if (recode_insn == &ic->tme_sparc_recode_insns[0]) { ! 1617: return (0); ! 1618: } ! 1619: ! 1620: /* stop recoding immediately, leaving the updated PC ! 1621: pointing to the instruction before the jmpl: */ ! 1622: assert (pc_advance >= sizeof(sparc_insn)); ! 1623: pc_advance -= sizeof(sparc_insn); ! 1624: sparc_insn_count--; ! 1625: sparc_recode ! 1626: |= (TME_SPARC_RECODE_INSN_UPDATE_PCS ! 1627: | TME_SPARC_RECODE_INSN_NONE ! 1628: | TME_SPARC_RECODE_INSN_LAST); ! 1629: break; ! 1630: } ! 1631: } ! 1632: ! 1633: /* otherwise, this is a format one instruction: */ ! 1634: else { ! 1635: ! 1636: /* if the next instruction can't be recoded when it's in a ! 1637: branch delay slot (usually because it's also a control ! 1638: transfer instruction): */ ! 1639: if (__tme_predict_false(_tme_sparc_recode_insn_branch_delay_bad(sparc_insn_next))) { ! 1640: ! 1641: /* if we haven't recoded any instructions yet, recode is ! 1642: impossible here: */ ! 1643: if (recode_insn == &ic->tme_sparc_recode_insns[0]) { ! 1644: return (0); ! 1645: } ! 1646: ! 1647: /* stop recoding immediately, leaving the updated PC ! 1648: pointing to the instruction before the jmpl: */ ! 1649: assert (pc_advance >= sizeof(sparc_insn)); ! 1650: pc_advance -= sizeof(sparc_insn); ! 1651: sparc_insn_count--; ! 1652: sparc_recode ! 1653: |= (TME_SPARC_RECODE_INSN_UPDATE_PCS ! 1654: | TME_SPARC_RECODE_INSN_NONE ! 1655: | TME_SPARC_RECODE_INSN_LAST); ! 1656: } ! 1657: ! 1658: /* otherwise, the next instruction can be recoded when it's in a ! 1659: branch delay slot: */ ! 1660: else { ! 1661: ! 1662: /* write the PC of the CALL into r[15]: */ ! 1663: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1664: recode_insn->tme_recode_insn_size = recode_size_address; ! 1665: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc; ! 1666: recode_insn->tme_recode_insn_operand_src[1] ! 1667: = (pc_advance == 0 ! 1668: ? TME_RECODE_OPERAND_ZERO ! 1669: : TME_RECODE_OPERAND_IMM); ! 1670: recode_insn->tme_recode_insn_imm_uguest = pc_advance; ! 1671: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(15); ! 1672: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1673: recode_insn++; ! 1674: ! 1675: /* if the PC is not guest size: */ ! 1676: if (recode_size_address < TME_SPARC_RECODE_SIZE(ic)) { ! 1677: ! 1678: /* zero-extend r[15] to guest size: */ ! 1679: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_EXTZ; ! 1680: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1681: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(15); ! 1682: recode_insn->tme_recode_insn_operand_src[1] = recode_size_address; ! 1683: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(15); ! 1684: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1685: recode_insn++; ! 1686: } ! 1687: ! 1688: /* advance PC to the branch delay slot: */ ! 1689: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1690: recode_insn->tme_recode_insn_size = recode_size_address; ! 1691: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(15); ! 1692: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1693: recode_insn->tme_recode_insn_imm_uguest = sizeof(sparc_insn); ! 1694: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1695: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1696: recode_insn++; ! 1697: pc_advance = 0 - (tme_uint32_t) sizeof(sparc_insn); ! 1698: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1699: ! 1700: /* write the target of the call into PC_next. NB that we have ! 1701: to account for the fact that PC already points to the ! 1702: branch delay slot, but the displacement is relative to the ! 1703: PC of the call instruction: */ ! 1704: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1705: recode_insn->tme_recode_insn_size = recode_size_address; ! 1706: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1707: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1708: recode_insn->tme_recode_insn_imm_uguest ! 1709: = ((tme_sparc_ireg_t) ! 1710: (((tme_recode_guest_t) ! 1711: (tme_int32_t) ! 1712: (sparc_insn << 2)) ! 1713: - sizeof(sparc_insn))); ! 1714: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT); ! 1715: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1716: recode_insn++; ! 1717: ! 1718: /* the branch delay slot will be the last instruction, and ! 1719: after that we need an unconditional call: */ ! 1720: sparc_recode ! 1721: |= (TME_SPARC_RECODE_INSN_LAST ! 1722: | TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_CALL ! 1723: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL)); ! 1724: ! 1725: /* if the call target is within this same page, ! 1726: the call can be near, otherwise the call must be far: */ ! 1727: if ((((pc_next - sizeof(sparc_insn)) ! 1728: + ((tme_sparc_ireg_t) ! 1729: (tme_recode_guest_t) ! 1730: (tme_int32_t) ! 1731: (sparc_insn << 2))) ! 1732: ^ (pc_next - sizeof(sparc_insn))) ! 1733: < page_size) { ! 1734: sparc_recode |= TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_NEAR); ! 1735: } ! 1736: else { ! 1737: sparc_recode |= TME_SPARC_RECODE_CHAIN_INFO(TME_RECODE_CHAIN_INFO_FAR); ! 1738: } ! 1739: ! 1740: continue; ! 1741: } ! 1742: } ! 1743: ! 1744: /* if we might not have enough space for recode insns for the next ! 1745: instruction: */ ! 1746: if (__tme_predict_false(recode_insn >= recode_insns_last_start)) { ! 1747: ! 1748: /* this will be the last instruction, and we need to update the ! 1749: PCs: */ ! 1750: sparc_recode |= TME_SPARC_RECODE_INSN_UPDATE_PCS | TME_SPARC_RECODE_INSN_LAST; ! 1751: } ! 1752: ! 1753: /* if this is the last instruction, we must be updating PC and ! 1754: PC_next: */ ! 1755: assert ((sparc_recode & TME_SPARC_RECODE_INSN_LAST) == 0 ! 1756: || (sparc_recode & TME_SPARC_RECODE_INSN_UPDATE_PCS) ! 1757: || (pc_advance == 0 ! 1758: && reg_guest_pc == TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC))); ! 1759: ! 1760: /* if we need PC and PC_next to be valid for this instruction: */ ! 1761: if (sparc_recode & TME_SPARC_RECODE_INSN_UPDATE_PCS) { ! 1762: ! 1763: /* if we need to update PC and PC_next: */ ! 1764: if (pc_advance > 0 ! 1765: || reg_guest_pc != TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC)) { ! 1766: ! 1767: /* advance PC: */ ! 1768: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1769: recode_insn->tme_recode_insn_size = recode_size_address; ! 1770: recode_insn->tme_recode_insn_operand_src[0] = reg_guest_pc; ! 1771: recode_insn->tme_recode_insn_operand_src[1] ! 1772: = (pc_advance == 0 ! 1773: ? TME_RECODE_OPERAND_ZERO ! 1774: : TME_RECODE_OPERAND_IMM); ! 1775: recode_insn->tme_recode_insn_imm_uguest = pc_advance; ! 1776: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1777: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1778: recode_insn++; ! 1779: pc_advance = 0; ! 1780: reg_guest_pc = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1781: ! 1782: /* set PC_next: */ ! 1783: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1784: recode_insn->tme_recode_insn_size = recode_size_address; ! 1785: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC); ! 1786: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1787: recode_insn->tme_recode_insn_imm_uguest = sizeof(sparc_insn); ! 1788: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_PC_NEXT); ! 1789: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1790: recode_insn++; ! 1791: } ! 1792: } ! 1793: ! 1794: /* if this instruction hasn't been suppressed: */ ! 1795: if (__tme_predict_true((sparc_recode & TME_SPARC_RECODE_INSN_NONE) == 0)) { ! 1796: ! 1797: /* if this instruction always or sometimes needs an assist: */ ! 1798: if (sparc_recode & TME_SPARC_RECODE_INSN_UPDATE_INSN) { ! 1799: ! 1800: /* store the instruction in the instruction register: */ ! 1801: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 1802: recode_insn->tme_recode_insn_size = TME_RECODE_SIZE_32; ! 1803: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO; ! 1804: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1805: recode_insn->tme_recode_insn_imm_u32 = sparc_insn; ! 1806: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_INSN); ! 1807: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1808: recode_insn++; ! 1809: ! 1810: /* if this instruction doesn't take rs2: */ ! 1811: if (sparc_recode & TME_SPARC_RECODE_INSN_NO_RS2) { ! 1812: ! 1813: /* clear the i bit and rs2, to force the second source ! 1814: operand to be %g0, or zero: */ ! 1815: sparc_insn &= ~(TME_BIT(13) | TME_SPARC_FORMAT3_MASK_RS2); ! 1816: } ! 1817: ! 1818: /* if this instruction doesn't take rs1: */ ! 1819: if (sparc_recode & TME_SPARC_RECODE_INSN_NO_RS1) { ! 1820: ! 1821: /* clear rs1, to force the first source operand to be %g0, ! 1822: or zero: */ ! 1823: sparc_insn &= ~TME_SPARC_FORMAT3_MASK_RS1; ! 1824: } ! 1825: } ! 1826: ! 1827: /* otherwise, this instruction doesn't need an assist: */ ! 1828: else { ! 1829: ! 1830: /* if this is an addx, addxcc, subx, or subxcc instruction: */ ! 1831: if (sparc_recode & TME_SPARC_RECODE_INSN_DEFC) { ! 1832: ! 1833: /* define the recode carry flag with the icc C flag: */ ! 1834: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_DEFC; ! 1835: recode_insn->tme_recode_insn_operand_src[0] = TME_SPARC_COND_CS; ! 1836: recode_insn->tme_recode_insn_operand_src[1] = 0; ! 1837: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_FLAG_CARRY; ! 1838: recode_insn->tme_recode_insn_conds_thunk = ic->tme_sparc_recode_conds_thunk_icc; ! 1839: recode_insn++; ! 1840: } ! 1841: ! 1842: /* because we set the flags thunk on the recode instruction ! 1843: now, this instruction can't be a shift (because a shift may ! 1844: make more than one recode instruction): */ ! 1845: assert ((sparc_recode ! 1846: & (TME_SPARC_RECODE_INSN_CC ! 1847: | TME_SPARC_RECODE_INSN_SHIFT)) ! 1848: != (TME_SPARC_RECODE_INSN_CC ! 1849: | TME_SPARC_RECODE_INSN_SHIFT)); ! 1850: ! 1851: /* assume that this instruction doesn't update flags: */ ! 1852: flags_thunk = NULL; ! 1853: ! 1854: /* if this instruction updates flags: */ ! 1855: if (sparc_recode & TME_SPARC_RECODE_INSN_CC) { ! 1856: ! 1857: /* set the right flags thunk for this instruction. NB that ! 1858: the least significant two bits of op3 are zero only for ! 1859: the additive instructions, and bit two of op3 is set only ! 1860: for a subtraction instruction: */ ! 1861: flags_thunk ! 1862: = ((sparc_insn & (0x3 << 19)) == 0 ! 1863: ? ((sparc_insn & (0x4 << 19)) ! 1864: ? ic->tme_sparc_recode_flags_thunk_sub ! 1865: : ic->tme_sparc_recode_flags_thunk_add) ! 1866: : ic->tme_sparc_recode_flags_thunk_logical); ! 1867: } ! 1868: ! 1869: /* set any flags thunk on this instruction: */ ! 1870: recode_insn->tme_recode_insn_flags_thunk = flags_thunk; ! 1871: } ! 1872: ! 1873: /* assume that if this is a shift, it's a 32-bit shift: */ ! 1874: shift_count_mask = 32 - 1; ! 1875: ! 1876: /* if this is a v9 shift: */ ! 1877: if (TME_SPARC_VERSION(ic) >= 9 ! 1878: && (sparc_recode & TME_SPARC_RECODE_INSN_SHIFT)) { ! 1879: ! 1880: /* if this is a 64-bit shift: */ ! 1881: if (sparc_insn & TME_BIT(12)) { ! 1882: ! 1883: /* this is a 64-bit shift: */ ! 1884: shift_count_mask = 64 - 1; ! 1885: } ! 1886: ! 1887: /* otherwise, this is a 32-bit shift: */ ! 1888: else { ! 1889: ! 1890: /* if this is a right shift: */ ! 1891: if (sparc_insn & TME_BIT(20)) { ! 1892: ! 1893: /* remember that this is a right shift: */ ! 1894: sparc_recode |= TME_SPARC_RECODE_INSN_SHIFT_RIGHT; ! 1895: ! 1896: /* decode rs1: */ ! 1897: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1)); ! 1898: ! 1899: /* extend rs1 into the second temporary register. if this ! 1900: is a shift right arithmetic, sign extend, else zero ! 1901: extend: */ ! 1902: recode_insn->tme_recode_insn_opcode ! 1903: = ((sparc_insn & TME_BIT(19)) ! 1904: ? TME_RECODE_OPCODE_EXTS ! 1905: : TME_RECODE_OPCODE_EXTZ); ! 1906: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1907: recode_insn->tme_recode_insn_operand_src[0] = recode_operand; ! 1908: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_SIZE_32; ! 1909: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(1)); ! 1910: recode_insn++; ! 1911: ! 1912: /* NB that the flags thunk for the final instruction was ! 1913: already set above (to NULL, because sparc shift ! 1914: instructions do not affect any condition codes), so we ! 1915: have to do the same since we advanced to the next ! 1916: instruction: */ ! 1917: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1918: } ! 1919: } ! 1920: } ! 1921: ! 1922: /* if the i bit is one: */ ! 1923: if (sparc_insn & TME_BIT(13)) { ! 1924: ! 1925: /* decode simm13: */ ! 1926: imm = TME_FIELD_MASK_EXTRACTS(sparc_insn, (tme_sparc_ireg_t) 0x1fff); ! 1927: ! 1928: /* if this is a shift instruction: */ ! 1929: if (__tme_predict_false(sparc_recode & TME_SPARC_RECODE_INSN_SHIFT)) { ! 1930: ! 1931: /* mask the immediate with the shift count mask: */ ! 1932: imm &= shift_count_mask; ! 1933: } ! 1934: ! 1935: /* if the immediate is zero, the second source operand is zero, ! 1936: otherwise the second source operand is the immediate: */ ! 1937: recode_insn->tme_recode_insn_imm_uguest = imm; ! 1938: recode_operand ! 1939: = (imm == 0 ! 1940: ? TME_RECODE_OPERAND_ZERO ! 1941: : TME_RECODE_OPERAND_IMM); ! 1942: } ! 1943: ! 1944: /* otherwise, the i bit is zero: */ ! 1945: else { ! 1946: ! 1947: /* decode rs2: */ ! 1948: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS2)); ! 1949: if (recode_operand == TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) { ! 1950: recode_operand = TME_RECODE_OPERAND_ZERO; ! 1951: } ! 1952: ! 1953: /* if this is a shift instruction: */ ! 1954: if (__tme_predict_false(sparc_recode & TME_SPARC_RECODE_INSN_SHIFT)) { ! 1955: ! 1956: /* make a temporary copy of the register with shift count, ! 1957: masked with the shift count mask, and use the temporary ! 1958: register as the second source operand: */ ! 1959: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_AND; ! 1960: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 1961: recode_insn->tme_recode_insn_operand_src[0] = recode_operand; ! 1962: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 1963: recode_insn->tme_recode_insn_imm_uguest = shift_count_mask; ! 1964: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(0)); ! 1965: recode_insn->tme_recode_insn_operand_dst = recode_operand; ! 1966: recode_insn++; ! 1967: ! 1968: /* NB that the flags thunk for the final instruction was ! 1969: already set above (to NULL, because sparc shift ! 1970: instructions do not affect any condition codes), so we ! 1971: have to do the same since we advanced to the next ! 1972: instruction: */ ! 1973: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 1974: } ! 1975: } ! 1976: ! 1977: /* set the second source operand: */ ! 1978: recode_insn->tme_recode_insn_operand_src[1] = recode_operand; ! 1979: ! 1980: /* decode rs1: */ ! 1981: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RS1)); ! 1982: if (recode_operand == TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) { ! 1983: recode_operand = TME_RECODE_OPERAND_ZERO; ! 1984: } ! 1985: ! 1986: /* if this is a v9 32-bit right shift: */ ! 1987: if (__tme_predict_false(TME_SPARC_VERSION(ic) >= 9 ! 1988: && (sparc_recode & TME_SPARC_RECODE_INSN_SHIFT_RIGHT))) { ! 1989: ! 1990: /* the first source operand is actually in the second ! 1991: temporary register: */ ! 1992: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(1)); ! 1993: } ! 1994: ! 1995: /* set the first source operand: */ ! 1996: recode_insn->tme_recode_insn_operand_src[0] = recode_operand; ! 1997: ! 1998: /* decode rd: */ ! 1999: recode_operand = TME_RECODE_REG_GUEST(TME_FIELD_MASK_EXTRACTU(sparc_insn, TME_SPARC_FORMAT3_MASK_RD)); ! 2000: if (recode_operand == TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0)) { ! 2001: recode_operand = TME_RECODE_OPERAND_NULL; ! 2002: } ! 2003: ! 2004: /* if this is a simple ld or st instruction: */ ! 2005: if (TME_SPARC_RECODE_INSN_OPCODE(sparc_recode) == TME_RECODE_OPCODE_RW) { ! 2006: ! 2007: /* assume that the first source operand is %g0, which makes ! 2008: the second source operand the guest address: */ ! 2009: recode_operand_address = recode_insn->tme_recode_insn_operand_src[1]; ! 2010: ! 2011: /* if the second source operand is %g0: */ ! 2012: if (recode_operand_address == TME_RECODE_OPERAND_ZERO) { ! 2013: ! 2014: /* nothing to do; the guest address is the first source ! 2015: operand, which is already in ! 2016: recode_insn->tme_recode_insn_operand_src[0]: */ ! 2017: } ! 2018: ! 2019: /* otherwise, the second source operand is not %g0: */ ! 2020: else { ! 2021: ! 2022: /* if the first source operand is not %g0: */ ! 2023: if (recode_insn->tme_recode_insn_operand_src[0] != TME_RECODE_OPERAND_ZERO) { ! 2024: ! 2025: /* add the two parts of the guest address into the ! 2026: temporary register: */ ! 2027: recode_operand_address = TME_RECODE_REG_GUEST(TME_SPARC_IREG_TMP(0)); ! 2028: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ADD; ! 2029: recode_insn->tme_recode_insn_size = recode_size_address; ! 2030: recode_insn->tme_recode_insn_operand_dst = recode_operand_address; ! 2031: recode_insn->tme_recode_insn_flags_thunk = NULL; ! 2032: recode_insn++; ! 2033: } ! 2034: ! 2035: /* set the guest address as the first source operand: */ ! 2036: recode_insn->tme_recode_insn_operand_src[0] = recode_operand_address; ! 2037: } ! 2038: ! 2039: /* if this is a st instruction: */ ! 2040: /* NB: all of the simple ld and st instructions that we handle ! 2041: here, have bit 21 set for a st, and clear for a ld: */ ! 2042: if (sparc_insn & (4 << 19)) { ! 2043: ! 2044: /* the second source operand is the register being ! 2045: stored: */ ! 2046: recode_insn->tme_recode_insn_operand_src[1] ! 2047: = ((TME_RECODE_OPERAND_NULL != TME_RECODE_OPERAND_ZERO ! 2048: && recode_operand == TME_RECODE_OPERAND_NULL) ! 2049: ? TME_RECODE_OPERAND_ZERO ! 2050: : recode_operand); ! 2051: ! 2052: /* the destination operand must be the recode %null: */ ! 2053: recode_operand = TME_RECODE_OPERAND_NULL; ! 2054: } ! 2055: ! 2056: /* otherwise, this is an ld instruction: */ ! 2057: else { ! 2058: ! 2059: /* the second source operand must be zero: */ ! 2060: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_ZERO; ! 2061: } ! 2062: ! 2063: /* set the read/write thunk: */ ! 2064: assert (TME_SPARC_VERSION(ic) >= 9 || (sparc_insn & (16 << 19)) == 0); ! 2065: recode_insn->tme_recode_insn_rw_thunk ! 2066: = ic->tme_sparc_recode_rw_thunks ! 2067: [TME_SPARC_RECODE_RW_THUNK_INDEX(ic, ! 2068: (TME_SPARC_RECODE_SIZE(ic) ! 2069: - (TME_SPARC_VERSION(ic) >= 9 ! 2070: && (ic->tme_sparc64_ireg_pstate & TME_SPARC64_PSTATE_AM))), ! 2071: ((TME_SPARC_VERSION(ic) >= 9 ! 2072: && (ic->tme_sparc64_ireg_pstate & TME_SPARC64_PSTATE_CLE)) ! 2073: ? TME_ENDIAN_LITTLE ! 2074: : TME_ENDIAN_BIG), ! 2075: (TME_SPARC_VERSION(ic) >= 9 ! 2076: && (sparc_insn & (16 << 19))), ! 2077: TME_FIELD_MASK_EXTRACTU(sparc_insn, (0xf << 19)))]; ! 2078: } ! 2079: ! 2080: /* otherwise, if this instruction needs an assist: */ ! 2081: else if (TME_SPARC_RECODE_INSN_OPCODE(sparc_recode) == TME_RECODE_OPCODE_GUEST) { ! 2082: ! 2083: /* set the assist function: */ ! 2084: recode_insn->tme_recode_insn_guest_func = sparc_assist; ! 2085: ! 2086: /* if this instruction needs a full assist: */ ! 2087: if ((sparc_recode ! 2088: & (TME_SPARC_RECODE_INSN_NO_RS2 ! 2089: | TME_SPARC_RECODE_INSN_NO_RS1)) ! 2090: == (TME_SPARC_RECODE_INSN_NO_RS2 ! 2091: | TME_SPARC_RECODE_INSN_NO_RS1)) { ! 2092: ! 2093: /* the source operands can be the recode %undef, since the ! 2094: full assist functions don't use the source operands: */ ! 2095: assert (sparc_assist == _tme_sparc_recode_insn_assist_full ! 2096: || sparc_assist == _tme_sparc_recode_insn_assist_unimpl ! 2097: ); ! 2098: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_UNDEF; ! 2099: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_UNDEF; ! 2100: ! 2101: /* assume that this instruction is not also marked ! 2102: TME_SPARC_RECODE_INSN_NO_RD, and force the destination ! 2103: operand to be the recode %null, to indicate that the ! 2104: assist can change any of the recode-visible ic state: */ ! 2105: recode_operand = TME_RECODE_OPERAND_NULL; ! 2106: } ! 2107: ! 2108: /* if this instruction's rd field doesn't encode a destination ! 2109: general register: */ ! 2110: if (sparc_recode & TME_SPARC_RECODE_INSN_NO_RD) { ! 2111: ! 2112: /* force the destination operand to be the fixed %g0: */ ! 2113: recode_operand = TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0); ! 2114: } ! 2115: } ! 2116: ! 2117: /* set the destination operand: */ ! 2118: recode_insn->tme_recode_insn_operand_dst = recode_operand; ! 2119: ! 2120: /* set the size: */ ! 2121: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 2122: ! 2123: /* set the opcode: */ ! 2124: recode_insn->tme_recode_insn_opcode = TME_SPARC_RECODE_INSN_OPCODE(sparc_recode); ! 2125: ! 2126: /* we have finished this instruction: */ ! 2127: recode_insn++; ! 2128: } ! 2129: ! 2130: /* if we need to, emit an endif: */ ! 2131: if (sparc_recode & TME_SPARC_RECODE_INSN_NEED_ENDIF) { ! 2132: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_ENDIF; ! 2133: recode_insn++; ! 2134: #ifndef NDEBUG ! 2135: sparc_recode &= ~TME_SPARC_RECODE_INSN_NEED_ENDIF; ! 2136: #endif ! 2137: } ! 2138: ! 2139: /* if this was the last instruction: */ ! 2140: if (sparc_recode & TME_SPARC_RECODE_INSN_LAST) { ! 2141: break; ! 2142: } ! 2143: ! 2144: /* clear sparc_recode: */ ! 2145: sparc_recode = 0; ! 2146: } ! 2147: ! 2148: /* make sure we didn't forget an endif: */ ! 2149: assert ((sparc_recode & TME_SPARC_RECODE_INSN_NEED_ENDIF) == 0); ! 2150: ! 2151: #ifdef _TME_SPARC_STATS ! 2152: /* update the recode instructions total: */ ! 2153: recode_insn->tme_recode_insn_opcode = TME_RECODE_OPCODE_GUEST; ! 2154: recode_insn->tme_recode_insn_size = TME_SPARC_RECODE_SIZE(ic); ! 2155: recode_insn->tme_recode_insn_operand_src[0] = TME_RECODE_OPERAND_ZERO; ! 2156: recode_insn->tme_recode_insn_operand_src[1] = TME_RECODE_OPERAND_IMM; ! 2157: recode_insn->tme_recode_insn_imm_u32 = sparc_insn_count; ! 2158: recode_insn->tme_recode_insn_operand_dst = TME_RECODE_REG_GUEST(TME_SPARC_IREG_G0); ! 2159: recode_insn->tme_recode_insn_guest_func = _tme_sparc_recode_insns_total; ! 2160: recode_insn++; ! 2161: #endif /* _TME_SPARC_STATS */ ! 2162: ! 2163: /* set the end of the instructions: */ ! 2164: ic->tme_sparc_recode_insns_group.tme_recode_insns_group_insns_end = recode_insn; ! 2165: ! 2166: /* get the chain information: */ ! 2167: chain_info ! 2168: = ((sparc_recode ! 2169: / TME_SPARC_RECODE_CHAIN_INFO(1)) ! 2170: & (TME_RECODE_CHAIN_INFO_UNCONDITIONAL ! 2171: | TME_RECODE_CHAIN_INFO_CONDITIONAL ! 2172: | TME_RECODE_CHAIN_INFO_NEAR ! 2173: | TME_RECODE_CHAIN_INFO_FAR ! 2174: | TME_RECODE_CHAIN_INFO_JUMP ! 2175: | TME_RECODE_CHAIN_INFO_RETURN ! 2176: | TME_RECODE_CHAIN_INFO_CALL ! 2177: )); ! 2178: ! 2179: /* if there is no chain information: */ ! 2180: if (chain_info == 0) { ! 2181: ! 2182: /* if the next PC is on the same page, make a chain jump near ! 2183: unconditional, otherwise make a chain jump far ! 2184: unconditional: */ ! 2185: if (pc_next <= itlb_addr_last) { ! 2186: chain_info += TME_RECODE_CHAIN_INFO_NEAR; ! 2187: } ! 2188: else { ! 2189: chain_info += TME_RECODE_CHAIN_INFO_FAR; ! 2190: } ! 2191: chain_info ! 2192: += (TME_RECODE_CHAIN_INFO_JUMP ! 2193: + TME_RECODE_CHAIN_INFO_UNCONDITIONAL); ! 2194: } ! 2195: ! 2196: /* otherwise, there is chain information. if the chain is ! 2197: conditional: */ ! 2198: else if ((chain_info ! 2199: & (TME_RECODE_CHAIN_INFO_UNCONDITIONAL ! 2200: | TME_RECODE_CHAIN_INFO_CONDITIONAL)) ! 2201: != TME_RECODE_CHAIN_INFO_UNCONDITIONAL) { ! 2202: ! 2203: /* if the alternate PC is on the same page, the alternate target ! 2204: can be near, otherwise it must be far: */ ! 2205: if (pc_next <= itlb_addr_last) { ! 2206: chain_info += TME_RECODE_CHAIN_INFO_ALTERNATE_NEAR; ! 2207: } ! 2208: else { ! 2209: chain_info += TME_RECODE_CHAIN_INFO_ALTERNATE_FAR; ! 2210: } ! 2211: } ! 2212: ! 2213: /* set the chain information: */ ! 2214: ic->tme_sparc_recode_insns_group.tme_recode_insns_group_chain_info = chain_info; ! 2215: ! 2216: /* make sure we didn't overflow the instructions buffer: */ ! 2217: assert (recode_insn <= &ic->tme_sparc_recode_insns[TME_ARRAY_ELS(ic->tme_sparc_recode_insns)]); ! 2218: ! 2219: /* recode these instructions: */ ! 2220: return (tme_recode_insns_thunk(ic->tme_sparc_recode_ic, ! 2221: &ic->tme_sparc_recode_insns_group)); ! 2222: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.