|
|
1.1 ! root 1: /* $Id: sparc-execute.c,v 1.5 2007/03/29 01:06:59 fredette Exp $ */ ! 2: ! 3: /* ic/sparc/sparc-execute.c - executes SPARC instructions: */ ! 4: ! 5: /* ! 6: * Copyright (c) 2005 Matt Fredette ! 7: * All rights reserved. ! 8: * ! 9: * Redistribution and use in source and binary forms, with or without ! 10: * modification, are permitted provided that the following conditions ! 11: * are met: ! 12: * 1. Redistributions of source code must retain the above copyright ! 13: * notice, this list of conditions and the following disclaimer. ! 14: * 2. Redistributions in binary form must reproduce the above copyright ! 15: * notice, this list of conditions and the following disclaimer in the ! 16: * documentation and/or other materials provided with the distribution. ! 17: * 3. All advertising materials mentioning features or use of this software ! 18: * must display the following acknowledgement: ! 19: * This product includes software developed by Matt Fredette. ! 20: * 4. The name of the author may not be used to endorse or promote products ! 21: * derived from this software without specific prior written permission. ! 22: * ! 23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ! 24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ! 25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ! 26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, ! 27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ! 28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR ! 29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ! 31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ! 32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ! 33: * POSSIBILITY OF SUCH DAMAGE. ! 34: */ ! 35: ! 36: _TME_RCSID("$Id: sparc-execute.c,v 1.5 2007/03/29 01:06:59 fredette Exp $"); ! 37: ! 38: /* includes: */ ! 39: #include "sparc-auto.h" ! 40: ! 41: #if (TME_SPARC_VERSION(ic) < 9) ! 42: #define tme_sparc_ireg_t tme_uint32_t ! 43: #define tme_sparc_ireg(x) tme_sparc_ireg_uint32(x) ! 44: #define tme_sparc_idle_type_pc tme_sparc_idle_type_pc32 ! 45: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 46: #define tme_sparc_ireg_t tme_uint64_t ! 47: #define tme_sparc_ireg(x) tme_sparc_ireg_uint64(x) ! 48: #define tme_sparc_idle_type_pc tme_sparc_idle_type_pc64 ! 49: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 50: ! 51: /* the sparc instruction executor: */ ! 52: static void ! 53: _TME_SPARC_EXECUTE_NAME(struct tme_sparc *ic) ! 54: { ! 55: tme_uint32_t asi_mask_insn; ! 56: tme_uint32_t asi_mask_data; ! 57: struct tme_sparc_tlb *itlb_current; ! 58: struct tme_sparc_tlb itlb_invalid; ! 59: tme_sparc_ireg_t pc; ! 60: tme_uint32_t insn; ! 61: unsigned int opcode; ! 62: unsigned int reg_rs1; ! 63: unsigned int reg_rs2; ! 64: unsigned int reg_rd; ! 65: int annulled; ! 66: int rc; ! 67: tme_uint8_t conds_mask_icc; ! 68: tme_uint8_t conds_mask_fcc; ! 69: tme_uint16_t conds_mask; ! 70: unsigned int cond; ! 71: ! 72: /* get the default address space identifiers and masks: */ ! 73: if (TME_SPARC_VERSION(ic) < 9) { ! 74: if (TME_SPARC_PRIV(ic)) { ! 75: asi_mask_insn = TME_SPARC32_ASI_MASK_SI; ! 76: asi_mask_data = TME_SPARC32_ASI_MASK_SD; ! 77: } ! 78: else { ! 79: asi_mask_insn = TME_SPARC32_ASI_MASK_UI; ! 80: asi_mask_data = TME_SPARC32_ASI_MASK_UD; ! 81: } ! 82: } ! 83: else { ! 84: asi_mask_data ! 85: = ((ic->tme_sparc64_ireg_pstate & TME_SPARC64_PSTATE_CLE) ! 86: ? TME_SPARC64_ASI_MASK_PRIMARY_LITTLE ! 87: : TME_SPARC64_ASI_MASK_PRIMARY); ! 88: asi_mask_insn = asi_mask_data; ! 89: } ! 90: ic->tme_sparc_asi_mask_insn = asi_mask_insn; ! 91: ic->tme_sparc_asi_mask_data = asi_mask_data; ! 92: ! 93: /* create an invalid instruction TLB entry, and use it as the initial ! 94: current instruction TLB entry: */ ! 95: tme_bus_tlb_construct(&itlb_invalid.tme_sparc_tlb_bus_tlb); ! 96: itlb_invalid.tme_sparc_tlb_addr_first = 1; ! 97: itlb_invalid.tme_sparc_tlb_addr_last = 0; ! 98: itlb_current = &itlb_invalid; ! 99: ! 100: /* busy the invalid instruction TLB entry: */ ! 101: assert (ic->_tme_sparc_itlb_busy == NULL); ! 102: tme_sparc_tlb_busy(itlb_current); ! 103: ic->_tme_sparc_itlb_busy = itlb_current; ! 104: ! 105: /* the first instruction will not be annulled: */ ! 106: annulled = FALSE; ! 107: ! 108: for (;;) { ! 109: ! 110: /* if we have used up our instruction burst: */ ! 111: if (__tme_predict_false(ic->_tme_sparc_instruction_burst_remaining == 0)) { ! 112: ! 113: /* try to acquire the external mutex and check for external ! 114: resets, halts, or interrupts, and process them: */ ! 115: rc = tme_mutex_trylock(&ic->tme_sparc_external_mutex); ! 116: if (__tme_predict_true(TME_THREADS_ERRNO(rc) == TME_OK)) { ! 117: #if TME_SPARC_VERSION(ic) < 9 ! 118: tme_sparc32_external_check(ic); ! 119: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 120: tme_sparc64_external_check(ic); ! 121: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 122: ! 123: /* unlock the external mutex: */ ! 124: tme_mutex_unlock(&ic->tme_sparc_external_mutex); ! 125: } ! 126: ! 127: /* start a new instruction burst: */ ! 128: ic->_tme_sparc_instruction_burst_remaining ! 129: = ic->_tme_sparc_instruction_burst; ! 130: ! 131: /* if we are in the idle loop: */ ! 132: if (__tme_predict_false((ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT) ! 133: == ic->tme_sparc_idle_type_pc) ! 134: && TME_SPARC_IDLE_TYPE_IS(ic, ! 135: (TME_SPARC_IDLE_TYPE_SUNOS32_TYPE_0)))) { ! 136: tme_sparc_do_idle(ic); ! 137: } ! 138: ! 139: /* if this is a cooperative threading system: */ ! 140: #if TME_THREADS_COOPERATIVE ! 141: ! 142: /* unbusy the current instruction TLB entry: */ ! 143: assert (ic->_tme_sparc_itlb_busy == itlb_current); ! 144: tme_sparc_tlb_unbusy(itlb_current); ! 145: ic->_tme_sparc_itlb_busy = NULL; ! 146: ! 147: /* yield: */ ! 148: tme_thread_yield(); ! 149: #endif /* TME_THREADS_COOPERATIVE */ ! 150: } ! 151: ! 152: /* we are going to use one instruction in the burst: */ ! 153: ic->_tme_sparc_instruction_burst_remaining--; ! 154: #ifdef _TME_SPARC_STATS ! 155: ic->tme_sparc_stats.tme_sparc_stats_insns_total++; ! 156: #endif /* _TME_SPARC_STATS */ ! 157: ! 158: /* update the PCs and get the PC of the instruction to execute: */ ! 159: pc = ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT); ! 160: ic->tme_sparc_ireg(TME_SPARC_IREG_PC) = pc; ! 161: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT) = ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT); ! 162: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) += sizeof(tme_uint32_t); ! 163: ! 164: /* NB that we only save instruction TLB entries that allow fast ! 165: reading, and we also change tme_sparc_tlb_addr_last to be the ! 166: last PC covered by the entry (it's normally the last address ! 167: covered by the entry). this allows us to do minimal checking ! 168: of the current instruction TLB entry at itlb_current: */ ! 169: ! 170: /* if the current instruction TLB entry covers this address: */ ! 171: if (__tme_predict_true(itlb_current->tme_sparc_tlb_addr_first <= pc ! 172: && pc <= itlb_current->tme_sparc_tlb_addr_last)) { ! 173: ! 174: /* fetch the instruction: */ ! 175: insn = tme_memory_bus_read32((const tme_shared tme_uint32_t *) (itlb_current->tme_sparc_tlb_emulator_off_read + pc), ! 176: itlb_current->tme_sparc_tlb_bus_rwlock, ! 177: sizeof(tme_uint32_t), ! 178: sizeof(tme_sparc_ireg_t)); ! 179: insn = tme_betoh_u32(insn); ! 180: } ! 181: ! 182: /* otherwise, our current TLB entry doesn't cover this address: */ ! 183: else { ! 184: ! 185: /* unbusy the current instruction TLB entry: */ ! 186: assert (ic->_tme_sparc_itlb_busy == itlb_current); ! 187: tme_sparc_tlb_unbusy(itlb_current); ! 188: ! 189: /* rehash the current instruction TLB entry: */ ! 190: itlb_current = tme_memory_atomic_pointer_read(struct tme_sparc_tlb *, ! 191: ic->_tme_sparc_itlb_array, ! 192: &ic->_tme_sparc_tlb_rwlock); ! 193: itlb_current += (pc >> 10) % _TME_SPARC_ITLB_HASH_SIZE; ! 194: ! 195: /* busy the current instruction TLB entry: */ ! 196: tme_sparc_tlb_busy(itlb_current); ! 197: ic->_tme_sparc_itlb_busy = itlb_current; ! 198: ! 199: /* if the new current instruction TLB entry is valid and covers ! 200: this address: */ ! 201: if (tme_bus_tlb_is_valid(&itlb_current->tme_sparc_tlb_bus_tlb) ! 202: && __tme_predict_true(TME_SPARC_TLB_ASI_MASK_OK(itlb_current, asi_mask_insn) ! 203: && itlb_current->tme_sparc_tlb_addr_first <= pc ! 204: && pc <= itlb_current->tme_sparc_tlb_addr_last)) { ! 205: ! 206: /* fetch the instruction: */ ! 207: insn = tme_memory_bus_read32((const tme_shared tme_uint32_t *) (itlb_current->tme_sparc_tlb_emulator_off_read + pc), ! 208: itlb_current->tme_sparc_tlb_bus_rwlock, ! 209: sizeof(tme_uint32_t), ! 210: sizeof(tme_sparc_ireg_t)); ! 211: insn = tme_betoh_u32(insn); ! 212: } ! 213: ! 214: /* otherwise, the new current instruction TLB entry is not valid ! 215: or does not cover this address: */ ! 216: else { ! 217: ! 218: /* we never fill TLB entries on the stack because we never ! 219: callout multiple fills at the same time, so the global TLB ! 220: entry pointer always points back to the TLB entry. this ! 221: also means that we don't have to call tme_bus_tlb_back() ! 222: after the fill: */ ! 223: itlb_current->tme_sparc_tlb_bus_tlb.tme_bus_tlb_global = &itlb_current->tme_sparc_tlb_bus_tlb; ! 224: ! 225: /* loop until we can busy a valid TLB entry: */ ! 226: do { ! 227: ! 228: /* unbusy the current instruction TLB entry for filling: */ ! 229: tme_bus_tlb_unbusy_fill(&itlb_current->tme_sparc_tlb_bus_tlb); ! 230: ! 231: /* fill the current instruction TLB entry: */ ! 232: #ifdef _TME_SPARC_STATS ! 233: ic->tme_sparc_stats.tme_sparc_stats_itlb_fill++; ! 234: #endif /* _TME_SPARC_STATS */ ! 235: (*ic->_tme_sparc_bus_connection->tme_sparc_bus_tlb_fill) ! 236: (ic->_tme_sparc_bus_connection, ! 237: itlb_current, ! 238: asi_mask_insn, ! 239: ic->tme_sparc_ireg(TME_SPARC_IREG_PC), ! 240: TME_BUS_CYCLE_READ); ! 241: ! 242: /* busy the current instruction TLB entry: */ ! 243: tme_sparc_tlb_busy(itlb_current); ! 244: ! 245: } while (tme_bus_tlb_is_invalid(&itlb_current->tme_sparc_tlb_bus_tlb)); ! 246: ! 247: /* the current instruction TLB entry must now cover this ! 248: address and allow reading: */ ! 249: /* NB that tme_sparc_tlb_addr_last has not been changed yet: */ ! 250: assert (TME_SPARC_TLB_ASI_MASK_OK(itlb_current, asi_mask_insn) ! 251: && itlb_current->tme_sparc_tlb_addr_first <= pc ! 252: && pc <= itlb_current->tme_sparc_tlb_addr_last ! 253: && (itlb_current->tme_sparc_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF ! 254: || (itlb_current->tme_sparc_tlb_cycles_ok & TME_BUS_CYCLE_READ))); ! 255: ! 256: /* if this current instruction TLB entry covers the entire ! 257: instruction and allows fast reading: */ ! 258: if (__tme_predict_true(itlb_current->tme_sparc_tlb_addr_last >= (pc + (sizeof(tme_uint32_t) - 1)) ! 259: && itlb_current->tme_sparc_tlb_emulator_off_read != TME_EMULATOR_OFF_UNDEF)) { ! 260: ! 261: /* fetch the instruction: */ ! 262: insn = tme_memory_bus_read32((const tme_shared tme_uint32_t *) (itlb_current->tme_sparc_tlb_emulator_off_read + pc), ! 263: itlb_current->tme_sparc_tlb_bus_rwlock, ! 264: sizeof(tme_uint32_t), ! 265: sizeof(tme_sparc_ireg_t)); ! 266: insn = tme_betoh_u32(insn); ! 267: ! 268: /* modify tme_sparc_tlb_addr_last of this first to represent the last valid ! 269: PC covered by the entry: */ ! 270: itlb_current->tme_sparc_tlb_addr_last ! 271: &= (((tme_bus_addr_t) 0) - sizeof(tme_uint32_t)); ! 272: } ! 273: ! 274: /* otherwise, this instruction TLB entry does not cover the ! 275: entire instruction and/or it does not allow fast reading. ! 276: fetching an instruction here may mean making multiple bus ! 277: cycles. exactly what happens in this case is ! 278: implementation-dependent, so we call an ! 279: implementation-specific function here to handle it: */ ! 280: else { ! 281: ! 282: /* unbusy the current instruction TLB entry and poison it, ! 283: so we won't try to do any fast fetches with it: */ ! 284: assert (ic->_tme_sparc_itlb_busy == itlb_current); ! 285: tme_sparc_tlb_unbusy(itlb_current); ! 286: itlb_current->tme_sparc_tlb_addr_first = 1; ! 287: itlb_current->tme_sparc_tlb_addr_last = 0; ! 288: ic->_tme_sparc_itlb_busy = NULL; ! 289: ! 290: /* NB that while annulled instructions are always fetched, ! 291: fetching an annulled instruction can never generate an ! 292: instruction_access exception, since the annul bit is not ! 293: part of the architected state. so we pass in the ! 294: annulled indication to the slow instruction fetcher: */ ! 295: insn = (*ic->_tme_sparc_fetch_slow)(ic, annulled); ! 296: #ifdef _TME_SPARC_STATS ! 297: ic->tme_sparc_stats.tme_sparc_stats_insns_slow++; ! 298: #endif /* _TME_SPARC_STATS */ ! 299: ! 300: /* busy the invalid instruction TLB entry: */ ! 301: itlb_current = &itlb_invalid; ! 302: assert (ic->_tme_sparc_itlb_busy == NULL); ! 303: tme_sparc_tlb_busy(itlb_current); ! 304: ic->_tme_sparc_itlb_busy = itlb_current; ! 305: } ! 306: } ! 307: ! 308: /* if this instruction has been annulled: */ ! 309: if (__tme_predict_false(annulled)) { ! 310: ! 311: /* the netbsd32-type-0 idle type is detected when an annulled ! 312: "wr %g1, PSR_PIL, %psr" or "wr %l1, (IPL_SCHED << 8), %psr" ! 313: instruction is found four instructions after (in ! 314: disassembly order, not execution order) a "wr %g1, 0, %psr" ! 315: or "wr %l1, 0, %psr" instruction that sets PIL to 0x0: */ ! 316: if (__tme_predict_false((insn ! 317: & ~((31 << 25) /* rd (reserved) */ ! 318: | (0x10 << 14) /* rs1 (mask %ln to %gn) */ ! 319: | (0x4 << 8))) /* imm13 (mask PSR_PIL to (IPL_SCHED << 8)) */ ! 320: == ((tme_uint32_t) ! 321: (2 << 30) /* format */ ! 322: | (0x31 << 19) /* op3 (wrpsr) */ ! 323: | (0x01 << 14) /* rs1 (%g1) */ ! 324: | (1 << 13) /* i */ ! 325: | 0x0b00))) { /* imm13 (IPL_SCHED << 8) */ ! 326: if (TME_SPARC_IDLE_TYPE_IS(ic, TME_SPARC_IDLE_TYPE_NETBSD32_TYPE_0)) { ! 327: if (ic->tme_sparc_ireg(TME_SPARC_IREG_PC) ! 328: == (ic->tme_sparc_idle_type_pc ! 329: - TME_SPARC_IDLE_TYPE_PC_STATE(1) ! 330: + (sizeof(tme_uint32_t) * 4))) { ! 331: ic->tme_sparc_idle_type_pc = ic->tme_sparc_ireg(TME_SPARC_IREG_PC); ! 332: } ! 333: if (ic->tme_sparc_ireg(TME_SPARC_IREG_PC) ! 334: == ic->tme_sparc_idle_type_pc) { ! 335: tme_sparc_do_idle(ic); ! 336: } ! 337: } ! 338: } ! 339: ! 340: /* make this instruction a nop: */ ! 341: insn = 0x01000000; ! 342: } ! 343: ! 344: /* the next instruction will not be annulled: */ ! 345: annulled = FALSE; ! 346: } ! 347: ! 348: /* start this instruction: */ ! 349: ic->_tme_sparc_insn = insn; ! 350: #ifdef _TME_SPARC_VERIFY ! 351: if (ic->tme_sparc_ireg(TME_SPARC_IREG_PC) == 0x6000) { ! 352: tme_sparc_verify_hook(); ! 353: } ! 354: #endif ! 355: ! 356: /* set %g0 to zero: */ ! 357: ic->tme_sparc_ireg(TME_SPARC_IREG_G0) = 0; ! 358: ! 359: /* if this is a format three instruction (op is two or three): */ ! 360: if (__tme_predict_true(insn >= 0x80000000)) { ! 361: ! 362: /* if the i bit is zero: */ ! 363: if (__tme_predict_true((insn & TME_BIT(13)) == 0)) { ! 364: ! 365: /* decode rs2: */ ! 366: reg_rs2 = TME_FIELD_MASK_EXTRACTU(insn, TME_SPARC_FORMAT3_MASK_RS2); ! 367: TME_SPARC_REG_INDEX(ic, reg_rs2); ! 368: } ! 369: ! 370: /* otherwise, the i bit is one: */ ! 371: else { ! 372: ! 373: /* decode simm13: */ ! 374: ic->tme_sparc_ireg(TME_SPARC_IREG_IMM) = TME_FIELD_MASK_EXTRACTS(insn, (tme_sparc_ireg_t) 0x1fff); ! 375: reg_rs2 = TME_SPARC_IREG_IMM; ! 376: } ! 377: ! 378: /* decode rs1: */ ! 379: reg_rs1 = TME_FIELD_MASK_EXTRACTU(insn, TME_SPARC_FORMAT3_MASK_RS1); ! 380: TME_SPARC_REG_INDEX(ic, reg_rs1); ! 381: ! 382: /* decode rd: */ ! 383: reg_rd = TME_FIELD_MASK_EXTRACTU(insn, TME_SPARC_FORMAT3_MASK_RD); ! 384: TME_SPARC_REG_INDEX(ic, reg_rd); ! 385: ! 386: /* form the opcode index: */ ! 387: opcode = TME_FIELD_MASK_EXTRACTU(insn, (0x3f << 19)); ! 388: opcode += ((insn >> (30 - 6)) & 0x40); ! 389: ! 390: /* run the instruction: */ ! 391: (*_TME_SPARC_EXECUTE_OPMAP[opcode]) ! 392: (ic, ! 393: &ic->tme_sparc_ireg(reg_rs1), ! 394: &ic->tme_sparc_ireg(reg_rs2), ! 395: &ic->tme_sparc_ireg(reg_rd)); ! 396: } ! 397: ! 398: /* otherwise, if this is a format two instruction: */ ! 399: else if (__tme_predict_true(insn < 0x40000000)) { ! 400: ! 401: /* dispatch on op2: */ ! 402: switch (TME_FIELD_MASK_EXTRACTU(insn, (0x7 << 22))) { ! 403: default: ! 404: ! 405: case 0: /* UNIMP: */ ! 406: #if TME_SPARC_VERSION(ic) < 9 ! 407: tme_sparc32_trap(ic, TME_SPARC_TRAP_illegal_instruction); ! 408: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 409: tme_sparc64_trap(ic, TME_SPARC_TRAP_illegal_instruction); ! 410: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 411: continue; ! 412: ! 413: case 2: /* Bicc: */ ! 414: conds_mask_icc = _tme_sparc_conds_icc[ ! 415: #if TME_SPARC_VERSION(ic) < 9 ! 416: TME_FIELD_MASK_EXTRACTU(ic->tme_sparc32_ireg_psr, TME_SPARC32_PSR_ICC) ! 417: #else /* TME_SPARC_VERSION(ic) >= 9 */ ! 418: TME_FIELD_MASK_EXTRACTU(ic->tme_sparc64_ireg_ccr, TME_SPARC64_CCR_ICC) ! 419: #endif /* TME_SPARC_VERSION(ic) >= 9 */ ! 420: ]; ! 421: ! 422: /* add the not-conditions to the conditions mask: */ ! 423: conds_mask = conds_mask_icc ^ 0xff; ! 424: conds_mask = (conds_mask << 8) | conds_mask_icc; ! 425: break; ! 426: ! 427: case 4: /* SETHI: */ ! 428: ! 429: /* decode rd: */ ! 430: reg_rd = TME_FIELD_MASK_EXTRACTU(insn, TME_SPARC_FORMAT3_MASK_RD); ! 431: TME_SPARC_REG_INDEX(ic, reg_rd); ! 432: ic->tme_sparc_ireg(reg_rd) = (insn << 10); ! 433: continue; ! 434: ! 435: case 6: /* FBfcc: */ ! 436: TME_SPARC_INSN_FPU; ! 437: conds_mask_fcc = _tme_sparc_conds_fcc[TME_FIELD_MASK_EXTRACTU(ic->tme_sparc_fpu_fsr, TME_SPARC_FSR_FCC)]; ! 438: ! 439: /* add the not-conditions to the conditions mask: */ ! 440: conds_mask = conds_mask_fcc ^ 0xff; ! 441: conds_mask = (conds_mask << 8) | conds_mask_fcc; ! 442: break; ! 443: } ! 444: ! 445: /* get the condition field: */ ! 446: cond = TME_FIELD_MASK_EXTRACTU(insn, (0xf << 25)); ! 447: ! 448: /* if this conditional branch is taken: */ ! 449: if (conds_mask & TME_BIT(cond)) { ! 450: ! 451: /* do the delayed control transfer: */ ! 452: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) ! 453: = (ic->tme_sparc_ireg(TME_SPARC_IREG_PC) ! 454: + (TME_FIELD_MASK_EXTRACTS(insn, (tme_sparc_ireg_t) 0x003fffff) << 2)); ! 455: ! 456: /* if this is a delayed control transfer to the idle loop: */ ! 457: if (__tme_predict_false(ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) ! 458: == ic->tme_sparc_idle_type_pc)) { ! 459: if (TME_SPARC_IDLE_TYPE_IS(ic, (TME_SPARC_IDLE_TYPE_SUNOS32_TYPE_0))) { ! 460: ! 461: /* reduce this instruction burst to include only the delay ! 462: instruction. before the next instruction burst begins ! 463: (on the first instruction of the idle loop) we will ! 464: detect that and go idle: */ ! 465: ic->_tme_sparc_instruction_burst_remaining = 1; ! 466: } ! 467: } ! 468: ! 469: /* if this was a conditional branch, clear the annul bit in ! 470: the instruction image: */ ! 471: if (cond & 7) { ! 472: insn &= ~TME_BIT(29); ! 473: } ! 474: } ! 475: ! 476: /* if the annul bit it set: */ ! 477: if (insn & TME_BIT(29)) { ! 478: ! 479: /* the next instruction will be annulled. to get the ! 480: execution loop to pay attention to the annulled bit, ! 481: make the current instruction TLB entry invalid: */ ! 482: annulled = TRUE; ! 483: assert (ic->_tme_sparc_itlb_busy == itlb_current); ! 484: tme_sparc_tlb_unbusy(itlb_current); ! 485: itlb_current = &itlb_invalid; ! 486: tme_sparc_tlb_busy(itlb_current); ! 487: ic->_tme_sparc_itlb_busy = itlb_current; ! 488: /* NB that we have to make sure the next instruction gets executed ! 489: in the immediate next iteration of the execution loop, since the ! 490: annulled bit is not part of the architected CPU state, and we also ! 491: want to do good emulation and actually fetch the instruction (as ! 492: opposed to just advancing the PCs now). to do this, we make sure ! 493: that there is at least one more instruction left in the burst: */ ! 494: ic->_tme_sparc_instruction_burst_remaining += (ic->_tme_sparc_instruction_burst_remaining == 0); ! 495: } ! 496: } ! 497: ! 498: /* otherwise, this is a format one instruction: */ ! 499: else { ! 500: ! 501: /* get the current PC: */ ! 502: pc = ic->tme_sparc_ireg(TME_SPARC_IREG_PC); ! 503: ! 504: /* write the PC of the CALL into r[15]: */ ! 505: ic->tme_sparc_ireg(ic->tme_sparc_cwp_offset + 15) = pc; ! 506: ! 507: /* log the call: */ ! 508: tme_sparc_log(ic, 250, TME_OK, ! 509: (TME_SPARC_LOG_HANDLE(ic), ! 510: _("call 0x%08x"), ! 511: pc + (insn << 2))); ! 512: ! 513: /* do the delayed control transfer: */ ! 514: ic->tme_sparc_ireg(TME_SPARC_IREG_PC_NEXT_NEXT) = pc + (insn << 2); ! 515: } ! 516: } ! 517: ! 518: /* NOTREACHED */ ! 519: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.