Annotation of tme/ic/sparc/sparc-timing.c, revision 1.1.1.1

1.1       root        1: /* $Id: sparc-timing.c,v 1.3 2010/02/14 15:57:09 fredette Exp $ */
                      2: 
                      3: /* ic/sparc/sparc-timing.c - SPARC instruction timing support: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2009 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: /* includes: */
                     37: #include "sparc-impl.h"
                     38: 
                     39: _TME_RCSID("$Id: sparc-timing.c,v 1.3 2010/02/14 15:57:09 fredette Exp $");
                     40: 
                     41: /* macros: */
                     42: 
                     43: /* at or below this maximum number of microseconds, we will spin
                     44:    instead of yield: */
                     45: #define TME_SPARC_TIMING_SPIN_USEC_MAX         (4096)
                     46: 
                     47: /* normally, when we yield we do a plain yield so we are immediately
                     48:    runnable again.  this makes timing loops more accurate, at the
                     49:    expense of consuming the host CPU.  if this is nonzero, when we
                     50:    yield we will instead do a sleep or wait on an external event: */
                     51: #define TME_SPARC_TIMING_YIELD_BLOCK           (FALSE)
                     52: 
                     53: /* this does a timing loop update: */
                     54: static void
                     55: _tme_sparc_timing_loop_update(struct tme_sparc *ic,
                     56:                              tme_sparc_ireg_umax_t update_count_m1)
                     57: {
                     58:   tme_uint32_t insn_update;
                     59:   unsigned long opcode;
                     60:   unsigned int reg_rd;
                     61:   signed int immediate;
                     62:   tme_sparc_ireg_umax_t addend_total_m1;
                     63: 
                     64:   /* get the update instruction: */
                     65:   insn_update = ic->_tme_sparc_insn;
                     66: 
                     67:   /* get the opcode: */
                     68:   opcode = TME_FIELD_MASK_EXTRACTU(insn_update, (0x3f << 19));
                     69: 
                     70:   /* get the rd register: */
                     71:   reg_rd = TME_FIELD_MASK_EXTRACTU(insn_update, TME_SPARC_FORMAT3_MASK_RD);
                     72:   TME_SPARC_REG_INDEX(ic, reg_rd);
                     73: 
                     74:   /* get the immediate: */
                     75:   immediate = insn_update & 2;
                     76:   immediate = 1 - immediate;
                     77: 
                     78:   /* get the total addend: */
                     79:   addend_total_m1 = update_count_m1;
                     80:   if (ic->tme_sparc_timing_loop_addend < 0) {
                     81:     addend_total_m1 = -addend_total_m1;
                     82:   }
                     83: 
                     84:   /* if this is a v9 CPU: */
                     85:   if (TME_SPARC_VERSION(ic) >= 9) {
                     86: #ifdef TME_HAVE_INT64_T
                     87: 
                     88:     /* save the immediate: */
                     89:     ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_TMP(0)) = immediate;
                     90: 
                     91:     /* do all but one of the updates of the rd register directly: */
                     92:     ic->tme_sparc_ireg_uint64(reg_rd) += addend_total_m1;
                     93: 
                     94:     /* do the final update, including setting any condition codes: */
                     95:     (*(ic->_tme_sparc64_execute_opmap[opcode]))
                     96:       (ic, 
                     97:        &ic->tme_sparc_ireg_uint64(reg_rd),
                     98:        &ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_TMP(0)),
                     99:        &ic->tme_sparc_ireg_uint64(reg_rd));
                    100: 
                    101: #endif /* TME_HAVE_INT64_T */
                    102:   }
                    103: 
                    104:   /* otherwise, this is a v7 or v8 CPU: */
                    105:   else {
                    106: 
                    107:     /* save the immediate: */
                    108:     ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_TMP(0)) = immediate;
                    109: 
                    110:     /* do all but one of the updates of the rd register directly: */
                    111:     ic->tme_sparc_ireg_uint32(reg_rd) += addend_total_m1;
                    112: 
                    113:     /* do the final update, including setting any condition codes: */
                    114:     (*(ic->_tme_sparc32_execute_opmap[opcode]))
                    115:       (ic, 
                    116:        &ic->tme_sparc_ireg_uint32(reg_rd),
                    117:        &ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_TMP(0)),
                    118:        &ic->tme_sparc_ireg_uint32(reg_rd));
                    119:   }
                    120: }
                    121: 
                    122: /* this returns nonzero if the branch to . instruction and the update
                    123:    instruction in its delay slot are a supported timing loop: */
                    124: int
                    125: tme_sparc_timing_loop_ok(tme_uint32_t insn_branch_dot,
                    126:                         tme_uint32_t insn_update)
                    127: {
                    128:   unsigned int op2;
                    129:   tme_uint32_t conds_mask;
                    130:   unsigned int cond;
                    131: 
                    132:   /* if the update instruction is not an add, addcc, sub, or subcc
                    133:      with the i bit set: */
                    134:   if ((insn_update
                    135:        & ((tme_uint32_t)
                    136:          ((0x3 << 30)          /* format */
                    137:           + (0x2b << 19)       /* op3 (mask addcc to add, sub to add) */
                    138:           + (1 << 13))))       /* i */
                    139:       != ((tme_uint32_t)
                    140:          ((0x2 << 30)          /* format */
                    141:           + (0x00 << 19)       /* op3 (add) */
                    142:           + (1 << 13)))) {     /* i */
                    143: 
                    144:     /* we only support timing loops with plain add or subtract
                    145:        update instructions: */
                    146:     return (FALSE);
                    147:   }
                    148: 
                    149:   /* if the simm13 is not 1 or -1: */
                    150:   if (((insn_update
                    151:        + (insn_update & 2))
                    152:        & 0x1fff)
                    153:       != 1) {
                    154: 
                    155:     /* we only support timing loops with plain add or subtract update
                    156:        instructions with immediates of 1 or -1: */
                    157:     return (FALSE);
                    158:   }
                    159: 
                    160:   /* if rd is %g0: */
                    161: #if TME_SPARC_IREG_G0 != 0
                    162: #error "TME_SPARC_IREG_G0 changed"
                    163: #endif
                    164:   if ((insn_update & TME_SPARC_FORMAT3_MASK_RD) == 0) {
                    165: 
                    166:     /* we only support timing loops with plain add or subtract update
                    167:        instructions with destination registers other than %g0: */
                    168:     return (FALSE);
                    169:   }
                    170: 
                    171:   /* if rs1 and rd are not the same: */
                    172: #if TME_SPARC_FORMAT3_MASK_RD < TME_SPARC_FORMAT3_MASK_RS1
                    173: #error "TME_SPARC_FORMAT3_MASK_ values changed"
                    174: #endif
                    175:   if ((((insn_update
                    176:         / (TME_SPARC_FORMAT3_MASK_RD
                    177:            / TME_SPARC_FORMAT3_MASK_RS1))
                    178:        ^ insn_update)
                    179:        & TME_SPARC_FORMAT3_MASK_RS1) != 0) {
                    180: 
                    181:     /* we only support timing loops with plain add or subtract update
                    182:        instructions where the source register and destination register
                    183:        are the same: */
                    184:     return (FALSE);
                    185:   }
                    186: 
                    187:   /* all branch instructions are format two instructions: */
                    188:   assert ((insn_branch_dot & (tme_uint32_t) (0x3 << 30)) == 0);
                    189: 
                    190:   /* if this isn't a Bicc or a v9 BPcc instruction: */
                    191:   op2 = TME_FIELD_MASK_EXTRACTU(insn_branch_dot, (0x7 << 22));
                    192:   if (__tme_predict_false(op2 != 2 && op2 != 1)) {
                    193: 
                    194:     /* we support all timing loops with a branch to . instructions
                    195:        that don't depend on the integer condition codes: */
                    196:     return (TRUE);
                    197:   }
                    198: 
                    199:   /* otherwise, this is a Bicc or a v9 BPcc instruction: */
                    200:   else {
                    201: 
                    202:     /* if this is not an addcc or subcc instruction: */
                    203:     if (__tme_predict_false((insn_update & (0x10 << 19)) == 0)) {
                    204: 
                    205:       /* we support timing loops with Bicc and BPcc instructions even
                    206:         when the update instruction doesn't change the integer
                    207:         condition codes: */
                    208:       return (TRUE);
                    209:     }
                    210: 
                    211:     /* if this is a subcc instruction: */
                    212:     if (insn_update & (0x04 << 19)) {
                    213: 
                    214:       /* we support timing loops that use subcc with all conditions
                    215:         except for vc and vs (the overflow conditions) and never: */
                    216:       conds_mask
                    217:        = ((1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_N))
                    218:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_E))
                    219:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_LE))
                    220:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_L))
                    221:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_LEU))
                    222:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_CS))
                    223:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_NEG))
                    224:           + (1 << TME_SPARC_COND_E)
                    225:           + (1 << TME_SPARC_COND_LE)
                    226:           + (1 << TME_SPARC_COND_L)
                    227:           + (1 << TME_SPARC_COND_LEU)
                    228:           + (1 << TME_SPARC_COND_CS)
                    229:           + (1 << TME_SPARC_COND_NEG)
                    230:           );
                    231:     }
                    232: 
                    233:     /* otherwise, this is an addcc instruction: */
                    234:     else {
                    235: 
                    236:       /* we support timing loops that use addcc with only these
                    237:         conditions: */
                    238:       conds_mask
                    239:        = ((1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_N))
                    240:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_E))
                    241:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_CS))
                    242:           + (1 << (TME_SPARC_COND_NOT + TME_SPARC_COND_NEG))
                    243:           + (1 << TME_SPARC_COND_E)
                    244:           + (1 << TME_SPARC_COND_CS)
                    245:           + (1 << TME_SPARC_COND_NEG)
                    246:           );
                    247:     }
                    248: 
                    249:     /* if we don't support the condition: */
                    250:     cond = TME_FIELD_MASK_EXTRACTU(insn_branch_dot, (0xf << 25));
                    251:     if ((conds_mask & TME_BIT(cond)) == 0) {
                    252: 
                    253:       /* we don't support this timing loop: */
                    254:       return (FALSE);
                    255:     }
                    256: 
                    257:     /* otherwise, we support this timing loop: */
                    258:     return (TRUE);
                    259:   }
                    260: }
                    261: 
                    262: /* this starts a timing loop: */
                    263: static void
                    264: _tme_sparc_timing_loop_start(struct tme_sparc *ic,
                    265:                             tme_uint32_t insn_update)
                    266: {
                    267:   unsigned int reg_rd;
                    268:   tme_sparc_ireg_umax_t value_rd;
                    269:   signed int addend;
                    270:   tme_uint32_t insn_branch_dot;
                    271:   const struct timeval *sleep;
                    272:   unsigned int op2;
                    273:   unsigned int cond;
                    274:   tme_sparc_ireg_umax_t value_sign;
                    275:   tme_sparc_ireg_umax_t value_zero;
                    276:   tme_sparc_ireg_umax_t value_true_greatest;
                    277:   tme_sparc_ireg_umax_t value_test;
                    278:   tme_sparc_ireg_umax_t branch_taken_count_max_m1;
                    279:   unsigned int loop_cycles_each;
                    280:   tme_sparc_ireg_umax_t cycles_scaled_max;
                    281:   union tme_value64 cycles_finish;
                    282:   tme_sparc_ireg_umax_t usec;
                    283:   tme_uint32_t usec32;
                    284:   static struct timeval sleep_buffer;
                    285: 
                    286:   /* at this point, the timing loop branch to . has been taken, and
                    287:      the PCs have been updated, so both PC and PC_next_next point to
                    288:      the timing loop update instruction (in insn_update), and PC_next
                    289:      points to the timing loop branch to . instruction again.
                    290: 
                    291:      a taken conditional branch never annuls, and sparc-execute.c and
                    292:      sparc-rc-insns.c handle a "ba,a ." instruction specially, so we
                    293:      know that the update instruction must execute at least as many
                    294:      times as the timing loop branch to . is taken.
                    295: 
                    296:      the timing loop branch to . has just been taken (this is why
                    297:      PC_next_next is the same as PC).  this first take was when the
                    298:      branch to . was detected in sparc-execute.c, or when
                    299:      tme_sparc_timing_loop_assist() determined that the recode
                    300:      instructions thunk that called it did so after a taken branch.
                    301: 
                    302:      this very first take is implicit in the taken branch count that
                    303:      we compute and store in
                    304:      ic->tme_sparc_timing_loop_branch_taken_count_max_m1 and/or pass
                    305:      to _tme_sparc_timing_loop_update() - i.e., we always compute the
                    306:      taken branch count minus one.
                    307: 
                    308:      this is good because it is possible for the timing loop update
                    309:      instruction to be executed 2^cc_width times.  if initially %o3 is
                    310:      zero and %icc.Z is clear, this bne will be taken 2^32 times:
                    311: 
                    312:      bne .
                    313:      deccc %o3
                    314: 
                    315:      NB that in this specific case, where the timing loop branch to
                    316:      . does not annul, the timing loop update instruction will
                    317:      actually be run a total of (2^32)+1 times: 2^32 times
                    318:      corresponding to the 2^32 times that the branch is taken, plus
                    319:      one final time when the branch is *not* taken, but the update
                    320:      instruction is not annulled.
                    321: 
                    322:      this function only counts and performs the updates corresponding
                    323:      to the times that the branch is *taken*.
                    324:      _tme_sparc_timing_loop_update() does the count minus one updates
                    325:      directly in the destination register, followed by a true
                    326:      instruction execution for the last (to update any condition
                    327:      codes).
                    328: 
                    329:      whether or not the branch to . instruction annuls, and any needed
                    330:      "one final time" update instruction will be handled either by
                    331:      sparc-execute.c, or by a combination of the recode instructions
                    332:      thunk and tme_sparc_timing_loop_assist(): */
                    333: 
                    334:   /* NB: our caller has already saved the current host cycles counter
                    335:      in ic->tme_sparc_timing_loop_start: */
                    336: 
                    337:   /* get the rd register: */
                    338:   reg_rd = TME_FIELD_MASK_EXTRACTU(insn_update, TME_SPARC_FORMAT3_MASK_RD);
                    339:   TME_SPARC_REG_INDEX(ic, reg_rd);
                    340: 
                    341:   /* if this is a v9 CPU: */
                    342:   if (TME_SPARC_VERSION(ic) >= 9) {
                    343: #ifdef TME_HAVE_INT64_T
                    344: 
                    345:     /* get the rd register value: */
                    346:     value_rd = ic->tme_sparc_ireg_uint64(reg_rd);
                    347: 
                    348: #else  /* !TME_HAVE_INT64_T */
                    349: 
                    350:     /* silence uninitialized variable warnings: */
                    351:     value_rd = 0;
                    352: 
                    353: #endif /* !TME_HAVE_INT64_T */
                    354:   }
                    355: 
                    356:   /* otherwise, this is not a v9 CPU: */
                    357:   else {
                    358: 
                    359:     /* get the rd register value: */
                    360:     value_rd = (tme_int32_t) ic->tme_sparc_ireg_uint32(reg_rd);
                    361:   }
                    362: 
                    363:   /* assume that this is an add or addcc instruction: */
                    364:   addend = insn_update & 2;
                    365:   addend = 1 - addend;
                    366: 
                    367:   /* if this is a sub or subcc instruction: */
                    368:   if (insn_update & (0x04 << 19)) {
                    369: 
                    370:     /* complement the addend: */
                    371:     addend = -addend;
                    372:   }
                    373: 
                    374:   /* get the branch to . instruction: */
                    375:   insn_branch_dot = ic->_tme_sparc_insn;
                    376: 
                    377:   /* save the update instruction: */
                    378:   ic->_tme_sparc_insn = insn_update;
                    379: 
                    380:   /* save the addend: */
                    381:   ic->tme_sparc_timing_loop_addend = addend;
                    382: 
                    383:   /* assume that there isn't a maximum number of times that the branch
                    384:      to . can be taken (i.e., that the branch to . doesn't depend on
                    385:      the value of rd), as if the branch condition were always: */
                    386:   cond = TME_SPARC_COND_NOT + TME_SPARC_COND_N;
                    387: 
                    388:   /* assume that if the branch does depend on the value of rd, that
                    389:      the sign bit in values of rd is the last bit: */
                    390:   value_sign = 1;
                    391:   value_sign <<= ((sizeof(value_sign) * 8) - 1);
                    392: 
                    393:   /* silence uninitialized variable warnings: */
                    394:   value_zero = 0;
                    395:   value_true_greatest = 0;
                    396: 
                    397:   /* get the op2 field of the branch to . instruction: */
                    398:   op2 = TME_FIELD_MASK_EXTRACTU(insn_branch_dot, (0x7 << 22));
                    399: 
                    400:   /* if this is a v9 BPr: */
                    401:   if (op2 == 3) {
                    402: 
                    403:     /* if this BPr tests rd: */
                    404:     if (((insn_branch_dot
                    405:          ^ insn_update)
                    406:         & TME_SPARC_FORMAT3_MASK_RS1) == 0) {
                    407: 
                    408:       /* get the condition field, and shift the "not" bit from bit two
                    409:         to bit three, to match the other branches: */
                    410:       cond = TME_FIELD_MASK_EXTRACTU(insn_branch_dot, (0x7 << 25));
                    411:       cond = (cond + 4) & (TME_SPARC_COND_NOT | 3);
                    412:       
                    413:       /* dispatch on the condition: */
                    414:       if ((cond % TME_SPARC_COND_NOT) == TME_SPARC_COND_E) {
                    415:        value_zero = -addend;
                    416:        value_true_greatest = 0;
                    417:       }
                    418:       else {
                    419:        assert ((cond % TME_SPARC_COND_NOT) == TME_SPARC_COND_LE
                    420:                || (cond % TME_SPARC_COND_NOT) == TME_SPARC_COND_L);
                    421:        value_zero = value_sign - addend;
                    422: #if (TME_SPARC_COND_L & 1) == 0 || (TME_SPARC_COND_LE & 1) != 0
                    423: #error "TME_SPARC_COND_ values changed"
                    424: #endif
                    425:        value_true_greatest = value_sign - (cond & 1);
                    426:       }
                    427:     }
                    428:   }
                    429: 
                    430:   /* otherwise, if this is a Bicc or a v9 BPcc: */
                    431:   else if (op2 == 2 || op2 == 1) {
                    432: 
                    433:     /* if this is an addcc or subcc instruction: */
                    434:     if (insn_update & (0x10 << 19)) {
                    435: 
                    436:       /* get the condition: */
                    437:       cond = TME_FIELD_MASK_EXTRACTU(insn_branch_dot, (0xf << 25));
                    438: 
                    439:       /* if this is a Bicc, or a BPcc with the cc1 bit clear, the
                    440:         sign bit in values of rd is bit 31: */
                    441:       if (sizeof(value_sign) > sizeof(tme_uint32_t)
                    442:          && ((insn_branch_dot >> 21) & op2 & 1) == 0) {
                    443:        value_sign = (((tme_uint32_t) 1) << 31);
                    444:       }
                    445: 
                    446:       /* if this is a subcc instruction: */
                    447:       if (insn_update & (0x04 << 19)) {
                    448: 
                    449:        /* dispatch on the condition: */
                    450:        switch (cond % TME_SPARC_COND_NOT) {
                    451:        default:
                    452:          /* we should have caught this unsupported condition in
                    453:             tme_sparc_timing_loop_ok(): */
                    454:          assert (FALSE);
                    455:          /* FALLTHROUGH */
                    456:        case TME_SPARC_COND_N:
                    457:          /* nothing to do */
                    458:          break;
                    459:        case TME_SPARC_COND_E:
                    460:          value_zero = -addend;
                    461:          value_true_greatest = 0;
                    462:          break;
                    463:        case TME_SPARC_COND_LE:
                    464:          value_zero = value_sign;
                    465:          value_true_greatest = value_sign - addend;
                    466:          break;
                    467:        case TME_SPARC_COND_L:
                    468:          value_zero = value_sign;
                    469:          value_true_greatest = (value_sign - 1) - addend;
                    470:          break;
                    471:        case TME_SPARC_COND_LEU:
                    472:          value_zero = 0;
                    473:          value_true_greatest = (value_sign * 2) - addend;
                    474:          break;
                    475:        case TME_SPARC_COND_CS:
                    476:          value_zero = 0;
                    477:          value_true_greatest = (value_sign * 2) - (addend + 1);
                    478:          break;
                    479:        case TME_SPARC_COND_NEG:
                    480:          value_zero = value_sign - addend;
                    481:          value_true_greatest = value_sign - 1;
                    482:          break;
                    483:        }
                    484:       }
                    485: 
                    486:       /* otherwise, this is an addcc instruction: */
                    487:       else {
                    488: 
                    489:        /* dispatch on the condition: */
                    490:        switch (cond % TME_SPARC_COND_NOT) {
                    491:        default:
                    492:          /* we should have caught this unsupported condition in
                    493:             tme_sparc_timing_loop_ok(): */
                    494:          assert (FALSE);
                    495:          /* FALLTHROUGH */
                    496:        case TME_SPARC_COND_N:
                    497:          /* nothing to do */
                    498:          break;
                    499:        case TME_SPARC_COND_E:
                    500:          value_zero = -addend;
                    501:          value_true_greatest = 0;
                    502:          break;
                    503:        case TME_SPARC_COND_CS:
                    504:          value_zero = -addend;
                    505:          value_true_greatest = (value_sign * 2) - (addend - 1);
                    506:          break;
                    507:        case TME_SPARC_COND_NEG:
                    508:          value_zero = value_sign - addend;
                    509:          value_true_greatest = value_sign - 1;
                    510:          break;
                    511:        }
                    512:       }
                    513:     }
                    514:   }
                    515: 
                    516:   /* the condition can't be never: */
                    517:   assert (cond != TME_SPARC_COND_N);
                    518: 
                    519:   /* assume that, if we block, we will block forever: */
                    520:   sleep = (const struct timeval *) NULL;
                    521: 
                    522:   /* if the condition is always, there is no maximum number of times
                    523:      that the branch to . can be taken: */
                    524: #if TME_SPARC_COND_N != 0
                    525: #error "TME_SPARC_COND_ values changed"
                    526: #endif
                    527:   ic->tme_sparc_timing_loop_branch_taken_max = (cond % TME_SPARC_COND_NOT);
                    528:   if (cond == (TME_SPARC_COND_NOT + TME_SPARC_COND_N)) {
                    529: 
                    530:     /* we may never finish: */
                    531:     ic->tme_sparc_timing_loop_finish.tme_value64_uint32_lo = (0 - (tme_uint32_t) 1);
                    532:     ic->tme_sparc_timing_loop_finish.tme_value64_uint32_hi = (0 - (tme_uint32_t) 1);
                    533:   }
                    534: 
                    535:   /* otherwise, the condition isn't always, so there is a maximum
                    536:      number of times that the branch to . can be taken: */
                    537:   else {
                    538: 
                    539:     /* it's not possible for all (adjusted-to-zero) values to be true.
                    540:        at least all-bits-one must be false: */
                    541:     assert (value_true_greatest <= ((value_sign - 1) * 2));
                    542: 
                    543:     /* test the initial value of rd: */
                    544:     value_test = (value_rd - value_zero) & ((value_sign * 2) - 1);
                    545: 
                    546:     /* if the initial value of rd will make the condition (ignoring
                    547:        TME_SPARC_COND_NOT) true after the first rd update
                    548:        instruction: */
                    549:     if (value_test <= value_true_greatest) {
                    550: 
                    551:       /* if this condition has TME_SPARC_COND_NOT: */
                    552:       if (cond & TME_SPARC_COND_NOT) {
                    553: 
                    554:        /* the branch to . will only be taken the first time: */
                    555:        branch_taken_count_max_m1 = 1 - 1;
                    556:       }
                    557: 
                    558:       /* otherwise, if the addend is -1: */
                    559:       else if (addend < 0) {
                    560: 
                    561:        /* the branch to . will be taken the first time, followed by
                    562:           at most (value_test + 1) more times when the value of rd
                    563:           makes the condition true: */
                    564:        branch_taken_count_max_m1 = (1 + (value_test + 1)) - 1;
                    565:       }
                    566: 
                    567:       /* otherwise, the addend is 1: */
                    568:       else {
                    569: 
                    570:        /* the branch to . will be taken the first time, followed by
                    571:           at most ((value_true_greatest - value_test) + 1) more times
                    572:           when the value of rd makes the condition true: */
                    573:        branch_taken_count_max_m1 = (1 + ((value_true_greatest - value_test) + 1)) - 1;
                    574:       }
                    575:     }
                    576: 
                    577:     /* otherwise, the initial value of rd will make the condition
                    578:        (ignoring TME_SPARC_COND_NOT) false after the first update
                    579:        instruction: */
                    580:     else {
                    581: 
                    582:       /* if this condition doesn't have TME_SPARC_COND_NOT: */
                    583:       if ((cond & TME_SPARC_COND_NOT) == 0) {
                    584: 
                    585:        /* the branch to . will only be taken the first time: */
                    586:        branch_taken_count_max_m1 = 1 - 1;
                    587:       }
                    588: 
                    589:       /* otherwise, if the addend is -1: */
                    590:       else if (addend < 0) {
                    591: 
                    592:        /* the branch to . will be taken the first time, followed by
                    593:           at most (value_test - value_true_greatest) more times when
                    594:           the value of rd makes the condition false: */
                    595:        branch_taken_count_max_m1 = (1 + (value_test - value_true_greatest)) - 1;
                    596:       }
                    597: 
                    598:       /* otherwise, the addend is 1: */
                    599:       else {
                    600: 
                    601:        /* the branch to . will be taken the first time, followed by
                    602:           at most (~value_test + 1) more times when the value of rd
                    603:           makes the condition false: */
                    604:        branch_taken_count_max_m1 = ((1 + (~value_test + 1)) - 1) & ((value_sign * 2) - 1);
                    605:       }
                    606:     }
                    607: 
                    608:     /* set the maximum number of times the branch to . can be taken: */
                    609:     ic->tme_sparc_timing_loop_branch_taken_count_max_m1 = branch_taken_count_max_m1;
                    610: 
                    611:     /* if each loop iteration takes more than one cycle: */
                    612:     loop_cycles_each = ic->tme_sparc_timing_loop_cycles_each;
                    613:     if (__tme_predict_false(loop_cycles_each != 1)) {
                    614: 
                    615:       /* get the maximum number of cycles to loop: */
                    616:       /* NB: we try to deal with overflow: */
                    617:       if (__tme_predict_false(loop_cycles_each != 2)) {
                    618:        cycles_scaled_max
                    619:          = (branch_taken_count_max_m1
                    620:             * loop_cycles_each);
                    621:       }
                    622:       else {
                    623:        cycles_scaled_max = branch_taken_count_max_m1 * 2;
                    624:       }
                    625:       cycles_scaled_max += loop_cycles_each;
                    626:       if (__tme_predict_false(cycles_scaled_max < ic->tme_sparc_timing_loop_branch_taken_count_max_m1)) {
                    627:        cycles_scaled_max = 0 - (tme_sparc_ireg_umax_t) 1;
                    628:       }
                    629:     }
                    630: 
                    631:     /* otherwise, each loop iteration takes one cycle: */
                    632:     else {
                    633: 
                    634:       /* get the maximum number of cycles to loop: */
                    635:       /* NB: we try to deal with overflow: */
                    636:       cycles_scaled_max = branch_taken_count_max_m1 + 1;
                    637:       cycles_scaled_max -= (cycles_scaled_max == 0);
                    638:     }
                    639: 
                    640:     /* we can't be looping for zero cycles: */
                    641:     assert (cycles_scaled_max > 0);
                    642: 
                    643:     /* get the latest host cycle counter when the timing loop must
                    644:        finish, if it doesn't finish sooner: */
                    645: #ifdef TME_HAVE_INT64_T
                    646:     cycles_finish.tme_value64_uint = cycles_scaled_max;
                    647: #else  /* !TME_HAVE_INT64_T */
                    648:     cycles_finish.tme_value64_uint32_lo = cycles_scaled_max;
                    649:     cycles_finish.tme_value64_uint32_hi = 0;
                    650: #endif /* !TME_HAVE_INT64_T */
                    651:     cycles_finish
                    652:       = tme_misc_cycles_scaled(&ic->tme_sparc_cycles_unscaling,
                    653:                               &cycles_finish);
                    654:     (void) tme_value64_add(&cycles_finish, &ic->tme_sparc_timing_loop_start);
                    655:     ic->tme_sparc_timing_loop_finish = cycles_finish;
                    656: 
                    657:     /* if the number of cycles to spin is small enough that we should
                    658:        truly spin, instead of yield: */
                    659:     if (cycles_scaled_max
                    660:        <= (ic->tme_sparc_cycles_scaled_per_usec
                    661:            * TME_SPARC_TIMING_SPIN_USEC_MAX)) {
                    662: 
                    663:       /* spin: */
                    664:       tme_misc_cycles_spin_until(&ic->tme_sparc_timing_loop_finish);
                    665: 
                    666:       /* do the timing loop update: */
                    667:       _tme_sparc_timing_loop_update(ic,
                    668:                                    ic->tme_sparc_timing_loop_branch_taken_count_max_m1);
                    669: 
                    670:       /* unwind back to instruction execution: */
                    671:       return;
                    672:     }
                    673: 
                    674:     /* if we will block until an external event: */
                    675:     if (TME_SPARC_TIMING_YIELD_BLOCK) {
                    676: 
                    677:       /* if the number of cycles to loop doesn't fit in 32 bits: */
                    678:       if (__tme_predict_false(cycles_scaled_max
                    679:                              & ~ (tme_sparc_ireg_umax_t) (tme_uint32_t) (0 - (tme_uint32_t) 1))) {
                    680: 
                    681:        /* convert cycles into microseconds: */
                    682:        usec = cycles_scaled_max / ic->tme_sparc_cycles_scaled_per_usec;
                    683: 
                    684:        /* set the sleep time: */
                    685:        sleep_buffer.tv_sec = (usec / 1000000);
                    686:        sleep_buffer.tv_usec = (usec % 1000000);
                    687:       }
                    688: 
                    689:       /* otherwise, the number of cycles to loop fits in 32 bits: */
                    690:       else {
                    691: 
                    692:        /* convert cycles into microseconds: */
                    693:        usec32 = ((tme_uint32_t) cycles_scaled_max) / ic->tme_sparc_cycles_scaled_per_usec;
                    694: 
                    695:        /* assume that we will sleep for less than one second: */
                    696:        sleep_buffer.tv_sec = 0;
                    697: 
                    698:        /* if the sleep time is one second or more: */
                    699:        if (__tme_predict_false(usec32 >= 1000000)) {
                    700: 
                    701:          /* set the sleep time seconds: */
                    702:          sleep_buffer.tv_sec = (usec32 / 1000000);
                    703: 
                    704:          /* get the microseconds: */
                    705:          usec32 = (usec32 % 1000000);
                    706:        }
                    707: 
                    708:        /* set the sleep time microseconds: */
                    709:        sleep_buffer.tv_usec = usec32;
                    710:       }
                    711: 
                    712:       /* we won't block forever: */
                    713:       sleep = &sleep_buffer;
                    714:     }
                    715:   }
                    716: 
                    717:   /* unbusy the instruction TLB entry: */
                    718:   assert (ic->_tme_sparc_itlb_current_token != NULL);
                    719:   tme_token_unbusy(ic->_tme_sparc_itlb_current_token);
                    720: 
                    721:   /* if threads are cooperative: */
                    722:   if (TME_THREADS_COOPERATIVE) {
                    723: 
                    724:     /* forget the instruction TLB entry: */
                    725:     ic->_tme_sparc_itlb_current_token = NULL;
                    726: 
                    727:     /* we will redispatch into timing mode: */
                    728:     ic->_tme_sparc_mode = TME_SPARC_MODE_TIMING_LOOP;
                    729:   }
                    730: 
                    731:   /* if we're blocking: */
                    732:   if (TME_SPARC_TIMING_YIELD_BLOCK) {
                    733: 
                    734:     /* lock the external mutex: */
                    735:     tme_mutex_lock(&ic->tme_sparc_external_mutex);
                    736: 
                    737:     /* check one last time for any external signal: */
                    738:     if (tme_memory_atomic_read_flag(&ic->tme_sparc_external_flag)) {
                    739:       tme_memory_atomic_write_flag(&ic->tme_sparc_external_flag, FALSE);
                    740:       (*ic->_tme_sparc_external_check)(ic, TME_SPARC_EXTERNAL_CHECK_MUTEX_LOCKED);
                    741:     }
                    742: 
                    743:     /* block on the external signal condition: */
                    744:     if (sleep != NULL) {
                    745:       tme_cond_sleep_yield(&ic->tme_sparc_external_cond,
                    746:                           &ic->tme_sparc_external_mutex,
                    747:                           sleep);
                    748:     }
                    749:     else {
                    750:       tme_cond_wait_yield(&ic->tme_sparc_external_cond,
                    751:                          &ic->tme_sparc_external_mutex);
                    752:     }
                    753: 
                    754:     /* unlock the external mutex: */
                    755:     tme_mutex_unlock(&ic->tme_sparc_external_mutex);
                    756:   }
                    757:   
                    758:   /* otherwise, we're not blocking: */
                    759:   else {
                    760: 
                    761:     /* do the simple yield: */
                    762:     tme_thread_yield();
                    763:   }
                    764: 
                    765:   /* finish the timing loop: */
                    766:   tme_sparc_timing_loop_finish(ic);
                    767: 
                    768:   /* relock the instruction TLB entry: */
                    769:   tme_sparc_callout_relock(ic);
                    770: 
                    771:   /* unwind back to instruction execution: */
                    772:   return;
                    773: }
                    774: 
                    775: /* this possibly starts a timing loop from the instruction
                    776:    executor: */
                    777: void
                    778: tme_sparc_timing_loop_start(struct tme_sparc *ic)
                    779: {
                    780:   tme_uint32_t insn_update;
                    781:   tme_uint32_t insn_branch_dot;
                    782:   tme_sparc_ireg_umax_t pc;
                    783: 
                    784:   /* save the current host cycles counter: */
                    785:   ic->tme_sparc_timing_loop_start = tme_misc_cycles();
                    786: 
                    787:   /* get the update instruction from the branch delay slot: */
                    788:   insn_update = tme_sparc_fetch_nearby(ic, 1);
                    789: 
                    790:   /* get the branch to . instruction: */
                    791:   insn_branch_dot = ic->_tme_sparc_insn;
                    792: 
                    793:   /* if we don't support this timing loop: */
                    794:   if (!tme_sparc_timing_loop_ok(insn_branch_dot,
                    795:                                insn_update)) {
                    796:     return;
                    797:   }
                    798: 
                    799:   /* at this point, PC and PC_next_next both point to the branch to .,
                    800:      and PC_next points to the update instruction.  we have to advance
                    801:      the PCs, because _tme_sparc_timing_loop_update() expects PC and
                    802:      PC_next_next to point to the update instruction, PC_next to point
                    803:      to the branch to .: */
                    804: 
                    805:   /* if this is a v9 CPU: */
                    806:   if (TME_SPARC_VERSION(ic) >= 9) {
                    807: #ifdef TME_HAVE_INT64_T
                    808: 
                    809:     /* advance the PCs: */
                    810:     pc = ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT);
                    811:     assert (ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC)
                    812:            == ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT_NEXT));
                    813:     assert (((ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC)
                    814:              + sizeof(tme_uint32_t))
                    815:             & ic->tme_sparc_address_mask)
                    816:            == pc);
                    817:     ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT)
                    818:       = ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT_NEXT);
                    819:     ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC) = pc;
                    820:     ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT_NEXT) = pc;
                    821: 
                    822: #endif /* TME_HAVE_INT64_T */
                    823:   }
                    824: 
                    825:   /* otherwise, this is a v7 or v8 CPU: */
                    826:   else {
                    827: 
                    828:     /* advance the PCs: */
                    829:     pc = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT);
                    830:     assert (ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC)
                    831:            == ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT));
                    832:     assert ((ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC)
                    833:              + sizeof(tme_uint32_t))
                    834:            == pc);
                    835:     ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT)
                    836:       = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT);
                    837:     ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC) = pc;
                    838:     ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT) = pc;
                    839:   }
                    840: 
                    841:   /* start the timing loop: */
                    842:   _tme_sparc_timing_loop_start(ic,
                    843:                               insn_update);
                    844: }
                    845: 
                    846: #if TME_HAVE_RECODE
                    847: 
                    848: /* the recode assist function for timing loops: */
                    849: tme_recode_uguest_t
                    850: tme_sparc_timing_loop_assist(struct tme_ic *_ic,
                    851:                             tme_recode_uguest_t insn_branch_dot,
                    852:                             tme_recode_uguest_t junk)
                    853: {
                    854:   struct tme_sparc *ic;
                    855:   tme_sparc_ireg_umax_t pc_next_next;
                    856:   int branch_dot_taken;
                    857:   tme_uint32_t insn_update;
                    858: 
                    859:   /* recover our ic: */
                    860:   ic = (struct tme_sparc *) _ic;
                    861: 
                    862:   /* save the branch to . instruction in the normal instruction
                    863:      position: */
                    864:   /* NB: we do this even though PC currently points to the timing loop
                    865:      update instruction: */
                    866:   ic->_tme_sparc_insn = insn_branch_dot;
                    867: 
                    868:   /* save the current host cycles counter: */
                    869:   ic->tme_sparc_timing_loop_start = tme_misc_cycles();
                    870: 
                    871:   /* NB: unlike tme_sparc_timing_loop_start(), this function may be
                    872:      called after the branch to . has *not* been taken.  this happens
                    873:      when the branch to . is conditional and does not annul - this is
                    874:      the "one final time" update instruction discussed in
                    875:      _tme_sparc_timing_loop_start().
                    876: 
                    877:      at this point, PC points to the update instruction, PC_next
                    878:      points to the branch to . (if the branch to . was taken) or to
                    879:      the instruction following the update instruction (if the branch
                    880:      to . was not taken and does not annul): */
                    881: 
                    882:   /* if this is a v9 CPU: */
                    883:   if (TME_SPARC_VERSION(ic) >= 9) {
                    884: #ifdef TME_HAVE_INT64_T
                    885: 
                    886:     /* set PC_next_next from PC_next: */
                    887:     pc_next_next
                    888:       = ((ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT)
                    889:          + sizeof(tme_uint32_t))
                    890:         & ic->tme_sparc_address_mask);
                    891:     ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC_NEXT_NEXT) = pc_next_next;
                    892: 
                    893:     /* see if the timing loop branch to . instruction was taken: */
                    894:     branch_dot_taken = (ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_PC) == pc_next_next);
                    895: 
                    896:     /* get the timing loop update instruction: */
                    897:     insn_update = ic->tme_sparc_ireg_uint64(TME_SPARC_IREG_INSN);
                    898: 
                    899: #else  /* !TME_HAVE_INT64_T */
                    900: 
                    901:     /* silence uninitialized variable warnings: */
                    902:     branch_dot_taken = 0;
                    903:     insn_update = 0;
                    904: 
                    905: #endif /* !TME_HAVE_INT64_T */
                    906:   }
                    907: 
                    908:   /* otherwise, this is not a v9 CPU: */
                    909:   else {
                    910: 
                    911:     /* set PC_next_next from PC_next: */
                    912:     pc_next_next
                    913:       = (ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT)
                    914:         + sizeof(tme_uint32_t));
                    915:     ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC_NEXT_NEXT) = pc_next_next;
                    916: 
                    917:     /* see if the timing loop branch to . instruction was taken: */
                    918:     branch_dot_taken = (ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_PC) == (tme_uint32_t) pc_next_next);
                    919: 
                    920:     /* get the timing loop update instruction: */
                    921:     insn_update = ic->tme_sparc_ireg_uint32(TME_SPARC_IREG_INSN);
                    922:   }
                    923: 
                    924:   /* if the timing loop branch to . instruction was taken: */
                    925:   if (branch_dot_taken) {
                    926: 
                    927:     /* end any recode verifying: */
                    928:     tme_sparc_recode_verify_end_preinstruction(ic);
                    929: 
                    930:     /* start the timing loop: */
                    931:     _tme_sparc_timing_loop_start(ic,
                    932:                                 insn_update);
                    933:   }
                    934: 
                    935:   /* otherwise, the timing loop branch to . instruction was not
                    936:      taken, and it does not annul: */
                    937:   else {
                    938: 
                    939:     /* do the one final update: */
                    940:     ic->_tme_sparc_insn = insn_update;
                    941:     _tme_sparc_timing_loop_update(ic, 0);
                    942:   }
                    943: 
                    944:   /* unwind back to instruction execution: */
                    945:   return (0);
                    946: }
                    947: 
                    948: #endif /* TME_HAVE_RECODE */
                    949: 
                    950: /* this finishes a timing loop: */
                    951: void
                    952: tme_sparc_timing_loop_finish(struct tme_sparc *ic)
                    953: {
                    954:   union tme_value64 cycles_finish;
                    955:   union tme_value64 cycles_scaled_u;
                    956:   tme_sparc_ireg_umax_t cycles_scaled;
                    957:   unsigned int loop_cycles_each;
                    958:   tme_sparc_ireg_umax_t branch_taken_count_m1;
                    959: 
                    960:   /* loop forever: */
                    961:   for (;;) {
                    962: 
                    963:     /* get the current host cycle counter: */
                    964:     cycles_finish = tme_misc_cycles();
                    965: 
                    966:     /* if the timing loop has finished: */
                    967:     if (tme_value64_cmp(&cycles_finish, >=, &ic->tme_sparc_timing_loop_finish)) {
                    968:       break;
                    969:     }
                    970: 
                    971:     /* if an external event has happened: */
                    972:     if (tme_memory_atomic_read_flag(&ic->tme_sparc_external_flag)) {
                    973:       break;
                    974:     }
                    975: 
                    976:     /* if we block, we were supposed to block until an external event
                    977:        happened: */
                    978:     assert (!TME_SPARC_TIMING_YIELD_BLOCK);
                    979: 
                    980:     /* yield: */
                    981:     tme_thread_yield();
                    982:   }
                    983: 
                    984:   /* get the number of cycles elapsed: */
                    985:   /* NB: we try to deal with overflow: */
                    986:   (void) tme_value64_sub(&cycles_finish, &ic->tme_sparc_timing_loop_start);
                    987:   cycles_scaled_u
                    988:     = tme_misc_cycles_scaled(&ic->tme_sparc_cycles_scaling,
                    989:                             &cycles_finish);
                    990: #ifdef TME_HAVE_INT64_T
                    991:   cycles_scaled = cycles_scaled_u.tme_value64_uint;
                    992: #else  /* !TME_HAVE_INT64_T */
                    993:   cycles_scaled
                    994:     = (cycles_scaled_u.tme_value64_uint32_hi
                    995:        ? (tme_uint32_t) (0 - (tme_uint32_t) 1)
                    996:        : cycles_scaled_u.tme_value64_uint32_lo);
                    997: #endif /* !TME_HAVE_INT64_T */
                    998: 
                    999:   /* NB: it's unusual, but actually okay if no cycles have elapsed.
                   1000:      this just means that the branch to . will only be taken that
                   1001:      first time.  since we need the count of times the branch to .
                   1002:      was taken, minus one, dividing the elapsed cycles by the number
                   1003:      of cycles per loop gets exactly what we need: */
                   1004: 
                   1005:   /* get the count of times the branch to . was taken, minus one: */
                   1006:   loop_cycles_each = ic->tme_sparc_timing_loop_cycles_each;
                   1007:   if (__tme_predict_false(loop_cycles_each != 1)) {
                   1008:     if (__tme_predict_false(loop_cycles_each != 2)) {
                   1009:       branch_taken_count_m1 = cycles_scaled / loop_cycles_each;
                   1010:     }
                   1011:     else {
                   1012:       branch_taken_count_m1 = cycles_scaled / 2;
                   1013:     }
                   1014:   }
                   1015:   else {
                   1016:     branch_taken_count_m1 = cycles_scaled;
                   1017:   }
                   1018: 
                   1019:   /* if there is a maximum count of times the branch to . could be taken: */
                   1020:   if (ic->tme_sparc_timing_loop_branch_taken_max) {
                   1021: 
                   1022:     /* make sure that the branch to . isn't taken any more than the
                   1023:        maximum: */
                   1024:     if (branch_taken_count_m1 > ic->tme_sparc_timing_loop_branch_taken_count_max_m1) {
                   1025:       branch_taken_count_m1 = ic->tme_sparc_timing_loop_branch_taken_count_max_m1;
                   1026:     }
                   1027:   }
                   1028: 
                   1029:   /* do the timing loop update: */
                   1030:   _tme_sparc_timing_loop_update(ic,
                   1031:                                branch_taken_count_m1);
                   1032: 
                   1033:   /* zero the instruction burst: */
                   1034:   ic->_tme_sparc_instruction_burst_remaining = 0;
                   1035:   ic->_tme_sparc_instruction_burst_other = TRUE;
                   1036: 
                   1037:   /* if threads are cooperative: */
                   1038:   if (TME_THREADS_COOPERATIVE) {
                   1039: 
                   1040:     /* we will chain into execution mode: */
                   1041:     ic->_tme_sparc_mode = TME_SPARC_MODE_EXECUTION;
                   1042: 
                   1043:     /* save a redispatch and resume execution directly: */
                   1044:     (*ic->_tme_sparc_execute)(ic);
                   1045:     abort();
                   1046:   }
                   1047: 
                   1048:   /* otherwise, threads are preemptive: */
                   1049: 
                   1050:   /* unwind back to instruction execution: */
                   1051:   return;
                   1052: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.