Annotation of tme/ic/sparc/sparc-insns.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

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