Annotation of tme/machine/sun4/sun44c-cache.c, revision 1.1.1.1

1.1       root        1: /* $Id: sun44c-cache.c,v 1.2 2007/03/29 01:34:44 fredette Exp $ */
                      2: 
                      3: /* machine/sun4/sun44c-cache.c - implementation of Sun 4/4c cache emulation: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2006 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: #include <tme/common.h>
                     37: _TME_RCSID("$Id: sun44c-cache.c,v 1.2 2007/03/29 01:34:44 fredette Exp $");
                     38: 
                     39: /* includes: */
                     40: #include "sun4-impl.h"
                     41: 
                     42: /* macros: */
                     43: 
                     44: /* real sun4/4c cache tag bits: */
                     45: #define TME_SUN44C_CACHETAG_CONTEXT    (0x03c00000)
                     46: #define TME_SUN44C_CACHETAG_WRITE      (0x00200000)
                     47: #define TME_SUN44C_CACHETAG_SYSTEM     (0x00100000)
                     48: #define TME_SUN44C_CACHETAG_VALID      (0x00080000)
                     49: #define TME_SUN44C_CACHETAG_TAG                (0x0000fffc)
                     50: 
                     51: /* actions that the cache may take for an access: */
                     52: #define _TME_SUN44C_CACHE_ACTION_NULL          (0)
                     53: #define _TME_SUN44C_CACHE_ACTION_FLUSH         TME_BIT(0)
                     54: #define _TME_SUN44C_CACHE_ACTION_INVALIDATE    TME_BIT(1)
                     55: #define _TME_SUN44C_CACHE_ACTION_ALLOCATE      (TME_BIT(2) | _TME_SUN44C_CACHE_ACTION_FLUSH | _TME_SUN44C_CACHE_ACTION_INVALIDATE)
                     56: #define _TME_SUN44C_CACHE_ACTION_READ          TME_BIT(3)
                     57: #define _TME_SUN44C_CACHE_ACTION_WRITE_BACK    TME_BIT(4)
                     58: #define _TME_SUN44C_CACHE_ACTION_WRITE_THROUGH TME_BIT(5)
                     59: #define _TME_SUN44C_CACHE_ACTION_ERROR_WRITE   TME_BIT(6)
                     60: #define _TME_SUN44C_CACHE_ACTION_ERROR_SYSTEM  TME_BIT(7)
                     61: #define _TME_SUN44C_CACHE_ACTION_ERROR_MEMERR  TME_BIT(8)
                     62: 
                     63: /* each time the cache is enabled or its tag or data memory is
                     64:    accessed directly, the cache remains visible for this many more bus
                     65:    cycles.  eventually, the cache becomes invisible again, to allow
                     66:    for maximum performance - but if this value is too low, diagnostics
                     67:    may fail.
                     68: 
                     69:    some diagnostics do one bus cycle per cache address, so this must
                     70:    be at least the size of the largest system's cache, plus some
                     71:    slack: */
                     72: #define _TME_SUN44C_CACHE_VISIBLE_BUS_CYCLES   (65536 + 1024)
                     73: 
                     74: /* this returns the next TLB fill function: */
                     75: #define _tme_sun44c_cache_tlb_fill_next(sun4)  \
                     76:   (TME_SUN44C_MEMERR_VISIBLE(sun4)             \
                     77:    ? _tme_sun44c_tlb_fill_memerr               \
                     78:    : _tme_sun44c_tlb_fill_mmu)
                     79: 
                     80: /* this returns a valid cache tag for an address and context: */
                     81: static tme_uint32_t
                     82: _tme_sun44c_cache_tag(struct tme_sun4 *sun4,
                     83:                      tme_uint32_t context,
                     84:                      tme_uint32_t address)
                     85: {
                     86:   tme_uint32_t cache_tag;
                     87: 
                     88:   /* start with the address tag: */
                     89:   cache_tag
                     90:     = (((address >> sun4->tme_sun4_cache_size_log2)
                     91:        * _TME_FIELD_MASK_FACTOR(TME_SUN44C_CACHETAG_TAG))
                     92:        & TME_SUN44C_CACHETAG_TAG);
                     93: 
                     94:   /* add the context: */
                     95:   TME_FIELD_MASK_DEPOSITU(cache_tag, TME_SUN44C_CACHETAG_CONTEXT, context);
                     96: 
                     97:   /* add the valid bit: */
                     98:   cache_tag |= TME_SUN44C_CACHETAG_VALID;
                     99: 
                    100:   return (cache_tag);
                    101: }  
                    102: 
                    103: /* this returns the mask of actions that the cache will take for an
                    104:    access: */
                    105: static unsigned int
                    106: _tme_sun44c_cache_actions(const struct tme_bus_connection *conn_bus_init,
                    107:                          tme_uint32_t asi_mask,
                    108:                          tme_uint32_t address,
                    109:                          unsigned int cycles)
                    110: {
                    111:   struct tme_sun4 *sun4;
                    112:   tme_uint32_t context;
                    113:   tme_uint32_t cache_line_index;
                    114:   tme_uint32_t cache_tag_current;
                    115:   tme_uint32_t cache_tag_mask;
                    116:   struct tme_sun_mmu_pte pte_mmu;
                    117:   tme_uint32_t pte;
                    118:   unsigned int cache_actions;
                    119:   int rc;
                    120: 
                    121:   /* recover our sun4: */
                    122:   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
                    123: 
                    124:   /* get the context: */
                    125:   context = TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init);
                    126: 
                    127:   /* this ASI mask must be a single ASI, for user or supervisor
                    128:      instruction or data: */
                    129:   assert (asi_mask == TME_SPARC32_ASI_MASK_UD
                    130:          || asi_mask == TME_SPARC32_ASI_MASK_UI
                    131:          || asi_mask == TME_SPARC32_ASI_MASK_SD
                    132:          || asi_mask == TME_SPARC32_ASI_MASK_SI);
                    133: 
                    134:   /* this must be a plain read or write: */
                    135:   assert (cycles == TME_BUS_CYCLE_READ
                    136:          || cycles == TME_BUS_CYCLE_WRITE);
                    137: 
                    138:   /* turn this address into the cache line index: */
                    139:   cache_line_index
                    140:     = (address >> sun4->tme_sun4_cache_size_line_log2
                    141:        & ((1 << (sun4->tme_sun4_cache_size_log2
                    142:                 - sun4->tme_sun4_cache_size_line_log2))
                    143:          - 1));
                    144: 
                    145:   /* get the current cache tag for this cache line: */
                    146:   cache_tag_current = sun4->tme_sun44c_cache_tags[cache_line_index];
                    147: 
                    148:   /* NB: apparently the context field of a valid cache tag for system
                    149:      memory isn't significant when doing a tag comparison: */
                    150:   cache_tag_mask
                    151:     = (TME_SUN44C_CACHETAG_VALID
                    152:        | TME_SUN44C_CACHETAG_CONTEXT
                    153:        | TME_SUN44C_CACHETAG_TAG);
                    154:   if (cache_tag_current & TME_SUN44C_CACHETAG_SYSTEM) {
                    155:     cache_tag_mask
                    156:       = (TME_SUN44C_CACHETAG_VALID
                    157:         | TME_SUN44C_CACHETAG_TAG);
                    158:   }
                    159: 
                    160:   /* if this address and context hit in the cache: */
                    161:   if (((cache_tag_current
                    162:        ^ _tme_sun44c_cache_tag(sun4, context, address))
                    163:        & cache_tag_mask) == 0) {
                    164: 
                    165:     /* if the current cache tag only allows system access, but this is
                    166:        a user access: */
                    167:     if ((cache_tag_current & TME_SUN44C_CACHETAG_SYSTEM)
                    168:        && TME_SPARC_ASI_MASK_OVERLAP(asi_mask,
                    169:                                      (TME_SPARC32_ASI_MASK_UD
                    170:                                       | TME_SPARC32_ASI_MASK_UI))) {
                    171:       return (_TME_SUN44C_CACHE_ACTION_ERROR_SYSTEM);
                    172:     }
                    173: 
                    174:     /* if the current cache tag only allows read access, but this is a
                    175:        write access: */
                    176:     if (!(cache_tag_current & TME_SUN44C_CACHETAG_WRITE)
                    177:        && cycles == TME_BUS_CYCLE_WRITE) {
                    178:       return (_TME_SUN44C_CACHE_ACTION_ERROR_WRITE);
                    179:     }
                    180: 
                    181:     /* this access is a hit in the cache: */
                    182:     cache_actions = 0;
                    183:   }
                    184: 
                    185:   /* otherwise, this address and context miss in the cache: */
                    186:   else {
                    187: 
                    188:     /* if this ASI mask is for supervisor instructions, and we're in
                    189:        the boot state: */
                    190:     if (asi_mask == TME_SPARC32_ASI_MASK_SI
                    191:        && (sun4->tme_sun44c_enable & TME_SUN44C_ENA_NOTBOOT) == 0) {
                    192:       return (_TME_SUN44C_CACHE_ACTION_NULL);
                    193:     }
                    194: 
                    195:     /* get the PTE for this address and context from the MMU: */
                    196:     rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu, 
                    197:                             context,
                    198:                             address,
                    199:                             &pte_mmu);
                    200:     assert (rc == TME_OK);
                    201:     pte = pte_mmu.tme_sun_mmu_pte_raw;
                    202: 
                    203:     /* if this PTE is not valid: */
                    204:     if (!(pte & TME_SUN44C_PTE_VALID)) {
                    205:       return (_TME_SUN44C_CACHE_ACTION_NULL);
                    206:     }
                    207: 
                    208:     /* if this PTE is not for cacheable space: */
                    209:     if (pte & TME_SUN44C_PTE_NC) {
                    210:       return (_TME_SUN44C_CACHE_ACTION_NULL);
                    211:     }
                    212: 
                    213:     /* if this PTE only allows system access, but this is a user
                    214:        access: */
                    215:     if ((pte & TME_SUN44C_PTE_SYSTEM)
                    216:        && TME_SPARC_ASI_MASK_OVERLAP(asi_mask,
                    217:                                      (TME_SPARC32_ASI_MASK_UD
                    218:                                       | TME_SPARC32_ASI_MASK_UI))) {
                    219:       return (_TME_SUN44C_CACHE_ACTION_ERROR_SYSTEM);
                    220:     }
                    221: 
                    222:     /* if this is a write access: */
                    223:     if (cycles == TME_BUS_CYCLE_WRITE) {
                    224: 
                    225:       /* if this PTE doesn't allow write access: */
                    226:       if (!(pte & TME_SUN44C_PTE_WRITE)) {
                    227:        return (_TME_SUN44C_CACHE_ACTION_ERROR_WRITE);
                    228:       }
                    229: 
                    230:       /* on a write miss, we invalidate, but we don't allocate: */
                    231:       sun4->tme_sun44c_cache_tags[cache_line_index] &= ~TME_SUN44C_CACHETAG_VALID;
                    232:       return (_TME_SUN44C_CACHE_ACTION_NULL);
                    233:     }
                    234: 
                    235:     /* otherwise, this PTE is valid and cacheable, so it will
                    236:        cause an allocation in the cache: */
                    237:     cache_actions = _TME_SUN44C_CACHE_ACTION_ALLOCATE;
                    238:   }
                    239: 
                    240:   /* this access will be handled by the cache: */
                    241:   return (cache_actions
                    242:          | (cycles == TME_BUS_CYCLE_READ
                    243:             ? _TME_SUN44C_CACHE_ACTION_READ
                    244:             : (sun4->tme_sun4_cache_writeback
                    245:                ? _TME_SUN44C_CACHE_ACTION_WRITE_BACK
                    246:                : _TME_SUN44C_CACHE_ACTION_WRITE_THROUGH)));
                    247: }
                    248: 
                    249: /* for a particular address, this returns the PTE entry for the
                    250:    address, and fills the cache internal TLB entry to point to the
                    251:    main memory for the address' cache line.  NB that this returns with
                    252:    the cache internal TLB entry busy: */
                    253: static tme_uint32_t
                    254: _tme_sun4_cache_tlb_internal_fill(const struct tme_bus_connection *conn_bus_init,
                    255:                                  tme_uint32_t address,
                    256:                                  unsigned int cycle_type)
                    257: {
                    258:   struct tme_sun4 *sun4;
                    259:   int rc;
                    260:   struct tme_sun_mmu_pte pte_mmu;
                    261:   tme_uint32_t context;
                    262:   tme_uint32_t asi_mask;
                    263:   tme_uint32_t pte;
                    264:   tme_uint32_t cache_size_line;
                    265: 
                    266:   /* recover our sun4: */
                    267:   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
                    268: 
                    269:   /* get the context: */
                    270:   context = TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init);
                    271: 
                    272:   /* get the PTE for this address and context from the MMU: */
                    273:   rc = tme_sun_mmu_pte_get(sun4->tme_sun44c_mmu, 
                    274:                           context,
                    275:                           address,
                    276:                           &pte_mmu);
                    277:   assert (rc == TME_OK);
                    278: 
                    279:   /* this PTE must be valid for cacheable obmem space, and, if we're
                    280:      writing, it must allow writing: */
                    281:   pte = pte_mmu.tme_sun_mmu_pte_raw;
                    282:   assert (((pte
                    283:            & (TME_SUN44C_PTE_VALID
                    284:               | TME_SUN44C_PTE_NC))
                    285:           == TME_SUN44C_PTE_VALID)
                    286:          && (cycle_type == TME_BUS_CYCLE_READ
                    287:              || (pte & TME_SUN44C_PTE_WRITE)));
                    288:   if ((pte & TME_SUN44C_PTE_PGTYPE) != 0 /* TME_SUN44C_PGTYPE_OBMEM */) {
                    289:     abort();
                    290:   }
                    291: 
                    292:   /* get the size of one cache line: */
                    293:   cache_size_line = 1 << sun4->tme_sun4_cache_size_line_log2;
                    294: 
                    295:   /* busy the cache internal TLB entry: */
                    296:   tme_bus_tlb_busy(&sun4->tme_sun4_cache_tlb_internal);
                    297: 
                    298:   /* loop until we can get a valid TLB entry: */
                    299:   do {
                    300: 
                    301:     /* unbusy the cache internal TLB entry for filling: */
                    302:     tme_bus_tlb_unbusy_fill(&sun4->tme_sun4_cache_tlb_internal);
                    303: 
                    304:     /* fill the cache internal TLB entry directly from the MMU.  we
                    305:        handle memory errors ourselves, so we don't need to call
                    306:        _tme_sun44c_tlb_fill_memerr when memory errors are visible: */
                    307:     asi_mask = TME_SPARC32_ASI_MASK_SD;
                    308:     rc = _tme_sun44c_tlb_fill_mmu(conn_bus_init,
                    309:                                  &sun4->tme_sun4_cache_tlb_internal,
                    310:                                  &asi_mask,
                    311:                                  address & (((tme_uint32_t) 0) - cache_size_line),
                    312:                                  cycle_type);
                    313:     assert (rc == TME_OK);
                    314: 
                    315:     /* rebusy the cache internal TLB entry: */
                    316:     tme_bus_tlb_busy(&sun4->tme_sun4_cache_tlb_internal);
                    317: 
                    318:     /* loop if the cache internal TLB entry is invalid: */
                    319:   } while (tme_bus_tlb_is_invalid(&sun4->tme_sun4_cache_tlb_internal));
                    320: 
                    321:   /* this TLB entry must allow fast access to the entire cache line.
                    322:      this limitation is caused by our poor emulation, but the real
                    323:      hardware may not deal well either with addresses that are marked
                    324:      cacheable but don't map to memory: */
                    325:   assert ((sun4->tme_sun4_cache_tlb_internal.tme_bus_tlb_emulator_off_read
                    326:           != TME_EMULATOR_OFF_UNDEF)
                    327:          && (cycle_type == TME_BUS_CYCLE_READ
                    328:              || (sun4->tme_sun4_cache_tlb_internal.tme_bus_tlb_emulator_off_write
                    329:                  != TME_EMULATOR_OFF_UNDEF))
                    330:          && (sun4->tme_sun4_cache_tlb_internal.tme_bus_tlb_addr_first
                    331:              <= (address & -cache_size_line))
                    332:          && (sun4->tme_sun4_cache_tlb_internal.tme_bus_tlb_addr_last
                    333:              >= (address | (cache_size_line - 1))));
                    334: 
                    335:   /* done: */
                    336:   return (pte_mmu.tme_sun_mmu_pte_raw);
                    337: }
                    338: 
                    339: /* this flushes a line from the cache: */
                    340: static void
                    341: _tme_sun44c_cache_line_flush(struct tme_sun4 *sun4,
                    342:                             tme_uint32_t cache_line_index)
                    343: {
                    344: 
                    345:   /* if this is a write-through cache, return now: */
                    346:   if (!sun4->tme_sun4_cache_writeback) {
                    347:     return;
                    348:   }
                    349: 
                    350:   /* XXX WRITEME: */
                    351:   abort();
                    352: }
                    353: 
                    354: /* this handles a bus cycle in the cache: */
                    355: static int
                    356: _tme_sun44c_cache_cycle_bus(void *_conn_bus_init,
                    357:                            struct tme_bus_cycle *cycle)
                    358: {
                    359:   const struct tme_bus_connection *conn_bus_init;
                    360:   struct tme_sun4 *sun4;
                    361:   tme_uint32_t address;
                    362:   tme_uint8_t context;
                    363:   tme_uint32_t asi_mask;
                    364:   unsigned int cache_actions;
                    365:   tme_uint32_t cache_size;
                    366:   tme_uint32_t cache_size_line;
                    367:   tme_uint32_t cache_data_offset;
                    368:   tme_shared tme_uint8_t *cache_data;
                    369:   tme_uint32_t cache_word;
                    370:   struct tme_bus_tlb *tlb;
                    371:   const tme_shared tme_uint8_t *memory_data_read;
                    372:   tme_shared tme_uint8_t *memory_data_write;
                    373:   tme_uint32_t cache_line_index;
                    374:   tme_uint32_t cache_tag;
                    375:   tme_uint32_t pte;
                    376: 
                    377:   /* recover our initiator's bus connection and sun4: */
                    378:   conn_bus_init = (struct tme_bus_connection *) _conn_bus_init;
                    379:   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
                    380: 
                    381:   /* get the context, address, and ASI mask: */
                    382:   context = TME_SUN44C_BUS_MMU_CONTEXT(sun4, conn_bus_init);
                    383:   address = cycle->tme_bus_cycle_address;
                    384:   asi_mask = sun4->tme_sun4_memtest_tlb_asi_mask;
                    385: 
                    386:   /* invalidate the TLB entry that triggered this cycle.  this hurts
                    387:      performance, since it keeps TLB entries valid only for one cycle
                    388:      at a time, but it's simple and handles the problem of PTE changes
                    389:      while the cache is visible (addresses can suddenly become
                    390:      cacheable): */
                    391:   assert (sun4->tme_sun4_memtest_tlb != NULL);
                    392:   tme_bus_tlb_invalidate(sun4->tme_sun4_memtest_tlb);
                    393:   sun4->tme_sun4_memtest_tlb = NULL;
                    394: 
                    395:   /* get the cache actions for this access: */
                    396:   cache_actions = _tme_sun44c_cache_actions(conn_bus_init,
                    397:                                            asi_mask,
                    398:                                            address,
                    399:                                            cycle->tme_bus_cycle_type);
                    400:   assert (cache_actions != _TME_SUN44C_CACHE_ACTION_NULL);
                    401: 
                    402:   /* if the cache actions include any involving the cache line for
                    403:      this address: */
                    404:   if (cache_actions
                    405:       & ~(_TME_SUN44C_CACHE_ACTION_ERROR_WRITE
                    406:          | _TME_SUN44C_CACHE_ACTION_ERROR_SYSTEM)) {
                    407: 
                    408:     /* get the total size of the cache, and the size of one line: */
                    409:     cache_size = 1 << sun4->tme_sun4_cache_size_log2;
                    410:     cache_size_line = 1 << sun4->tme_sun4_cache_size_line_log2;
                    411: 
                    412:     /* turn this address into a pointer to the cache data for its
                    413:        cache line, and into the cache line index: */
                    414:     cache_data_offset = address & (cache_size - cache_size_line);
                    415:     cache_data = sun4->tme_sun4_cache_data + cache_data_offset;
                    416:     cache_line_index = cache_data_offset >> sun4->tme_sun4_cache_size_line_log2;
                    417: 
                    418:     /* if this cache line needs to be flushed: */
                    419:     if (cache_actions & _TME_SUN44C_CACHE_ACTION_FLUSH) {
                    420:       _tme_sun44c_cache_line_flush(sun4, cache_line_index);
                    421:     }
                    422: 
                    423:     /* if this cache line needs to be invalidated: */
                    424:     if (cache_actions & _TME_SUN44C_CACHE_ACTION_INVALIDATE) {
                    425:       sun4->tme_sun44c_cache_tags[cache_line_index] &= ~TME_SUN44C_CACHETAG_VALID;
                    426:     }
                    427: 
                    428:     /* assume that we won't access main memory: */
                    429:     pte = 0;
                    430:     tlb = NULL;
                    431: 
                    432:     /* if this cache line needs to be allocated or written-through: */
                    433:     if (((cache_actions & _TME_SUN44C_CACHE_ACTION_ALLOCATE)
                    434:         == _TME_SUN44C_CACHE_ACTION_ALLOCATE)
                    435:        || (cache_actions & _TME_SUN44C_CACHE_ACTION_WRITE_THROUGH)) {
                    436: 
                    437:       /* we will access main memory, so get this address' PTE entry
                    438:          and fill the cache internal TLB: */
                    439:       pte = _tme_sun4_cache_tlb_internal_fill(conn_bus_init,
                    440:                                              address,
                    441:                                              ((cache_actions & _TME_SUN44C_CACHE_ACTION_WRITE_THROUGH)
                    442:                                               ? TME_BUS_CYCLE_WRITE
                    443:                                               : TME_BUS_CYCLE_READ));
                    444:       tlb = &sun4->tme_sun4_cache_tlb_internal;
                    445:     }
                    446: 
                    447:     /* if this cache line needs to be allocated: */
                    448:     if ((cache_actions & _TME_SUN44C_CACHE_ACTION_ALLOCATE) == _TME_SUN44C_CACHE_ACTION_ALLOCATE) {
                    449:     
                    450:       /* make the new cache tag: */
                    451:       cache_tag = _tme_sun44c_cache_tag(sun4, context, address);
                    452:       if (pte & TME_SUN44C_PTE_SYSTEM) {
                    453:        cache_tag |= TME_SUN44C_CACHETAG_SYSTEM;
                    454:       }
                    455:       if (pte & TME_SUN44C_PTE_WRITE) {
                    456:        cache_tag |= TME_SUN44C_CACHETAG_WRITE;
                    457:       }
                    458: 
                    459:       /* fill the cache line: */
                    460:       memory_data_read
                    461:        = (tlb->tme_bus_tlb_emulator_off_read
                    462:           + (address & -cache_size_line));
                    463:       cache_data_offset = 0;
                    464:       do {
                    465:        cache_word 
                    466:          = tme_memory_bus_read32(((const tme_shared tme_uint32_t *)
                    467:                                   (memory_data_read
                    468:                                    + cache_data_offset)),
                    469:                                  tlb->tme_bus_tlb_rwlock,
                    470:                                  sizeof(cache_word),
                    471:                                  sizeof(cache_word));
                    472:        tme_memory_bus_write32(((tme_shared tme_uint32_t *)
                    473:                                (cache_data
                    474:                                 + cache_data_offset)),
                    475:                               cache_word,
                    476:                               &sun4->tme_sun4_cache_rwlock,
                    477:                               sizeof(cache_word),
                    478:                               sizeof(cache_word));
                    479:        cache_data_offset += sizeof(cache_word);
                    480:       } while (cache_data_offset < cache_size_line);
                    481: 
                    482:       /* update the cache tag: */
                    483:       sun4->tme_sun44c_cache_tags[cache_line_index] = cache_tag;
                    484: 
                    485:       /* check for memory errors on this cache line fill: */
                    486:       if (_tme_sun44c_memerr_check(conn_bus_init,
                    487:                                   (address & -cache_size_line),
                    488:                                   pte,
                    489:                                   memory_data_read,
                    490:                                   cache_size_line) != TME_OK) {
                    491:        cache_actions |= _TME_SUN44C_CACHE_ACTION_ERROR_MEMERR;
                    492:       }
                    493:     }
                    494: 
                    495:     /* if we're reading or writing this cache line: */
                    496:     if (cache_actions
                    497:        & (_TME_SUN44C_CACHE_ACTION_READ
                    498:           | _TME_SUN44C_CACHE_ACTION_WRITE_BACK
                    499:           | _TME_SUN44C_CACHE_ACTION_WRITE_THROUGH)) {
                    500: 
                    501:       /* the address must be size-aligned, and the transfer must
                    502:         fit within the cache line: */
                    503:       assert ((address % cycle->tme_bus_cycle_size) == 0
                    504:              && ((address
                    505:                   ^ (address
                    506:                      + cycle->tme_bus_cycle_size
                    507:                      - 1))
                    508:                  < cache_size_line));
                    509: 
                    510:       /* get a pointer to the cache data to transfer: */
                    511:       cache_data += (address & (cache_size_line - 1));
                    512: 
                    513:       /* run the bus cycle against the cache line data: */
                    514:       /* XXX FIXME this is not thread-safe: */
                    515:       tme_bus_cycle_xfer_memory(cycle, 
                    516:                                ((tme_uint8_t *) cache_data) - address,
                    517:                                address + cycle->tme_bus_cycle_size - 1);
                    518: 
                    519:       /* if we're writing through this cache line: */
                    520:       if (cache_actions & _TME_SUN44C_CACHE_ACTION_WRITE_THROUGH) {
                    521: 
                    522:        /* write the data through the cache: */
                    523:        memory_data_write
                    524:          = (tlb->tme_bus_tlb_emulator_off_write
                    525:             + address);
                    526:        switch (cycle->tme_bus_cycle_size) {
                    527:        default:
                    528:          assert (FALSE);
                    529:          /* FALLTHROUGH */
                    530:        case sizeof(tme_uint8_t):
                    531:          tme_memory_bus_write8(memory_data_write,
                    532:                                tme_memory_bus_read8(cache_data,
                    533:                                                     &sun4->tme_sun4_cache_rwlock,
                    534:                                                     sizeof(tme_uint8_t),
                    535:                                                     sizeof(tme_uint32_t)),
                    536:                                tlb->tme_bus_tlb_rwlock,
                    537:                                sizeof(tme_uint8_t),
                    538:                                sizeof(tme_uint32_t));
                    539:          break;
                    540:        case sizeof(tme_uint16_t):
                    541:          tme_memory_bus_write16((tme_shared tme_uint16_t *) memory_data_write,
                    542:                                 tme_memory_bus_read16((const tme_shared tme_uint16_t *) cache_data,
                    543:                                                       &sun4->tme_sun4_cache_rwlock,
                    544:                                                       sizeof(tme_uint16_t),
                    545:                                                       sizeof(tme_uint32_t)),
                    546:                                 tlb->tme_bus_tlb_rwlock,
                    547:                                 sizeof(tme_uint16_t),
                    548:                                 sizeof(tme_uint32_t));
                    549:          break;
                    550:        case sizeof(tme_uint32_t):
                    551:          tme_memory_bus_write32((tme_shared tme_uint32_t *) memory_data_write,
                    552:                                 tme_memory_bus_read32((const tme_shared tme_uint32_t *) cache_data,
                    553:                                                       &sun4->tme_sun4_cache_rwlock,
                    554:                                                       sizeof(tme_uint32_t),
                    555:                                                       sizeof(tme_uint32_t)),
                    556:                                 tlb->tme_bus_tlb_rwlock,
                    557:                                 sizeof(tme_uint32_t),
                    558:                                 sizeof(tme_uint32_t));
                    559:          break;
                    560:        }
                    561: 
                    562:        /* update any memory errors caused by this write: */
                    563:        _tme_sun44c_memerr_update(sun4,
                    564:                                  pte,
                    565:                                  memory_data_write,
                    566:                                  cycle->tme_bus_cycle_size);
                    567:       }
                    568:     }
                    569: 
                    570:     /* if we accessed main memory: */
                    571:     if (tlb != NULL) {
                    572: 
                    573:       /* unbusy the cache internal TLB entry: */
                    574:       tme_bus_tlb_unbusy(tlb);
                    575:     }
                    576:   }
                    577: 
                    578:   /* if we're returning a protection error: */
                    579:   if (cache_actions
                    580:       & (_TME_SUN44C_CACHE_ACTION_ERROR_SYSTEM
                    581:         | _TME_SUN44C_CACHE_ACTION_ERROR_WRITE)) {
                    582:     return (_tme_sun44c_mmu_proterr((void *) conn_bus_init, cycle));
                    583:   }
                    584: 
                    585:   /* if we're returning a memory error: */
                    586:   if (cache_actions & _TME_SUN44C_CACHE_ACTION_ERROR_MEMERR) {
                    587:     return (_tme_sun44c_ob_fault_handler((void *) conn_bus_init, NULL, cycle, EIO));
                    588:   }
                    589: 
                    590:   /* return success: */
                    591:   return (TME_OK);
                    592: }
                    593: 
                    594: /* this fills TLBs when the cache is visible: */
                    595: int
                    596: _tme_sun44c_tlb_fill_cache(const struct tme_bus_connection *conn_bus_init,
                    597:                           struct tme_bus_tlb *tlb,
                    598:                           tme_uint32_t *_asi_mask,
                    599:                           tme_uint32_t address,
                    600:                           unsigned int cycles)
                    601: {
                    602:   struct tme_sun4 *sun4;
                    603:   tme_uint32_t asi_mask;
                    604:   tme_uint32_t cache_size_line;
                    605: 
                    606:   /* recover our sun4: */
                    607:   sun4 = (struct tme_sun4 *) conn_bus_init->tme_bus_connection.tme_connection_element->tme_element_private;
                    608: 
                    609:   /* recover the ASI mask: */
                    610:   asi_mask = *_asi_mask;
                    611: 
                    612:   /* this ASI mask must be a single ASI, for user or supervisor
                    613:      instruction or data: */
                    614:   assert (asi_mask == TME_SPARC32_ASI_MASK_UD
                    615:          || asi_mask == TME_SPARC32_ASI_MASK_UI
                    616:          || asi_mask == TME_SPARC32_ASI_MASK_SD
                    617:          || asi_mask == TME_SPARC32_ASI_MASK_SI);
                    618: 
                    619:   /* invalidate any other memory test TLB entry: */
                    620:   if (sun4->tme_sun4_memtest_tlb != NULL
                    621:       && sun4->tme_sun4_memtest_tlb != tlb) {
                    622:     tme_bus_tlb_invalidate(sun4->tme_sun4_memtest_tlb);
                    623:   }
                    624:   sun4->tme_sun4_memtest_tlb = NULL;
                    625: 
                    626:   /* the cache must be visible: */
                    627:   assert (sun4->tme_sun4_cache_visible > 0);
                    628: 
                    629:   /* if the cache is no longer visible: */
                    630:   if ((--sun4->tme_sun4_cache_visible) == 0) {
                    631: 
                    632:     /* update the TLB fill function: */
                    633:     sun4->tme_sun4_tlb_fill = _tme_sun44c_cache_tlb_fill_next(sun4);
                    634:   }
                    635: 
                    636:   /* otherwise, if this access will be handled by the cache: */
                    637:   else if (_tme_sun44c_cache_actions(conn_bus_init,
                    638:                                     asi_mask,
                    639:                                     address,
                    640:                                     cycles)
                    641:           != _TME_SUN44C_CACHE_ACTION_NULL) {
                    642: 
                    643:     /* fill this TLB entry: */
                    644:     tme_bus_tlb_initialize(tlb);
                    645:     cache_size_line = 1 << sun4->tme_sun4_cache_size_line_log2;
                    646:     tlb->tme_bus_tlb_addr_first = address & -cache_size_line;
                    647:     tlb->tme_bus_tlb_addr_last = address | (cache_size_line - 1);
                    648:     tlb->tme_bus_tlb_cycles_ok = (TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE);
                    649:     tlb->tme_bus_tlb_emulator_off_read = TME_EMULATOR_OFF_UNDEF;
                    650:     tlb->tme_bus_tlb_emulator_off_write = TME_EMULATOR_OFF_UNDEF;
                    651:     tlb->tme_bus_tlb_cycle_private = (void *) conn_bus_init;
                    652:     tlb->tme_bus_tlb_cycle = _tme_sun44c_cache_cycle_bus;
                    653: 
                    654:     /* remember this TLB entry and ASI mask: */
                    655:     sun4->tme_sun4_memtest_tlb = tlb;
                    656:     sun4->tme_sun4_memtest_tlb_asi_mask = asi_mask;
                    657: 
                    658:     /* return success: */
                    659:     return (TME_OK);
                    660:   }
                    661: 
                    662:   /* chain to the next TLB fill function: */
                    663:   return ((*_tme_sun44c_cache_tlb_fill_next(sun4))(conn_bus_init,
                    664:                                                   tlb,
                    665:                                                   _asi_mask,
                    666:                                                   address,
                    667:                                                   cycles));
                    668: }
                    669: 
                    670: /* this updates the visibility of the cache: */
                    671: void
                    672: _tme_sun44c_cache_enable_change(struct tme_sun4 *sun4)
                    673: {
                    674: 
                    675:   /* if the cache is enabled in the boot state, it is visible: */
                    676:   if ((sun4->tme_sun44c_enable
                    677:        & (TME_SUN44C_ENA_CACHE
                    678:          | TME_SUN44C_ENA_NOTBOOT)) == TME_SUN44C_ENA_CACHE) {
                    679: 
                    680:     /* if the cache is currently invisible: */
                    681:     if (!sun4->tme_sun4_cache_visible) {
                    682: 
                    683:       /* update the TLB fill function: */
                    684:       sun4->tme_sun4_tlb_fill = _tme_sun44c_tlb_fill_cache;
                    685: 
                    686:       /* invalidate all TLBs: */
                    687:       tme_sun_mmu_tlbs_invalidate(sun4->tme_sun44c_mmu);
                    688:     }
                    689: 
                    690:     /* refresh the cache visibility: */
                    691:     sun4->tme_sun4_cache_visible = _TME_SUN44C_CACHE_VISIBLE_BUS_CYCLES;
                    692:   }
                    693: 
                    694:   /* otherwise, the cache is not visible: */
                    695:   else {
                    696: 
                    697:     /* if the cache is currently visible: */
                    698:     if (sun4->tme_sun4_cache_visible) {
                    699: 
                    700:       /* the next TLB fill will not see the cache: */
                    701:       sun4->tme_sun4_cache_visible = 1;
                    702:     }
                    703:   }
                    704: }
                    705: 
                    706: /* this does a control bus cycle with either the tag or data cache
                    707:    memory: */
                    708: int
                    709: _tme_sun44c_cache_cycle_control(struct tme_sun4 *sun4,
                    710:                                struct tme_bus_cycle *cycle)
                    711: {
                    712:   tme_uint32_t address;
                    713:   tme_uint32_t cache_size;
                    714:   tme_uint32_t cache_line_index;
                    715:   tme_uint32_t value32;
                    716: 
                    717:   /* get the total size of the cache: */
                    718:   cache_size = 1 << sun4->tme_sun4_cache_size_log2;
                    719: 
                    720:   /* get the address: */
                    721:   address = cycle->tme_bus_cycle_address;
                    722: 
                    723:   /* if this is an access to the cache tags: */
                    724:   if ((address ^ TME_SUN44C_CONTROL_CACHE_TAGS) < cache_size) {
                    725: 
                    726:     /* if the address isn't 32-bit aligned, we can't emulate this
                    727:        access: */
                    728:     if (address % sizeof(tme_uint32_t)) {
                    729:       abort();
                    730:     }
                    731: 
                    732:     /* get the cache line index: */
                    733:     cache_line_index
                    734:       = ((address
                    735:          ^ TME_SUN44C_CONTROL_CACHE_TAGS)
                    736:         >> sun4->tme_sun4_cache_size_line_log2);
                    737: 
                    738:     /* transfer the cache tag: */
                    739:     value32 = tme_htobe_u32(sun4->tme_sun44c_cache_tags[cache_line_index]);
                    740:     tme_bus_cycle_xfer_memory(cycle, 
                    741:                              (((tme_uint8_t *) &value32)
                    742:                               - cycle->tme_bus_cycle_address),
                    743:                              (cycle->tme_bus_cycle_address
                    744:                               + cycle->tme_bus_cycle_size
                    745:                               - 1));
                    746: 
                    747:     /* if this was a write: */
                    748:     if (cycle->tme_bus_cycle_type == TME_BUS_CYCLE_WRITE) {
                    749: 
                    750:       /* only certain bits in a cache tag are writable: */
                    751:       value32 = tme_betoh_u32(value32);
                    752:       value32
                    753:        &= (TME_SUN44C_CACHETAG_CONTEXT
                    754:            | TME_SUN44C_CACHETAG_WRITE
                    755:            | TME_SUN44C_CACHETAG_SYSTEM
                    756:            | TME_SUN44C_CACHETAG_VALID
                    757:            | TME_SUN44C_CACHETAG_TAG);
                    758: 
                    759:       /* if the cache is enabled but not visible, and the tag being
                    760:         written is not zero, we can't emulate this access: */
                    761:       if ((sun4->tme_sun44c_enable & TME_SUN44C_ENA_CACHE)
                    762:          && !sun4->tme_sun4_cache_visible
                    763:          && value32 != 0) {
                    764:        abort();
                    765:       }
                    766: 
                    767:       /* write the cache tag: */
                    768:       sun4->tme_sun44c_cache_tags[cache_line_index] = value32;
                    769:     }
                    770:   }
                    771: 
                    772:   /* otherwise, if this is an access to the cache data: */
                    773:   else if ((address ^ TME_SUN44C_CONTROL_CACHE_DATA) < cache_size) {
                    774: 
                    775:     /* if the cache is enabled but not visible, we can't emulate this
                    776:        access: */
                    777:     if ((sun4->tme_sun44c_enable & TME_SUN44C_ENA_CACHE)
                    778:        && !sun4->tme_sun4_cache_visible) {
                    779:       abort();
                    780:     }
                    781: 
                    782:     /* transfer the cache data: */
                    783:     /* XXX FIXME this is not thread-safe: */
                    784:     tme_bus_cycle_xfer_memory(cycle, 
                    785:                              (tme_uint8_t *) 
                    786:                              (sun4->tme_sun4_cache_data
                    787:                               - TME_SUN44C_CONTROL_CACHE_DATA),
                    788:                              (TME_SUN44C_CONTROL_CACHE_DATA
                    789:                               + cache_size
                    790:                               - 1));
                    791:   }
                    792: 
                    793:   /* otherwise, we can't emulate this cycle: */
                    794:   else {
                    795:     abort();
                    796:   }
                    797: 
                    798:   /* refresh the cache visibility: */
                    799:   _tme_sun44c_cache_enable_change(sun4);
                    800:   return (TME_OK);
                    801: }
                    802: 
                    803: /* this does a flush bus cycle: */
                    804: void
                    805: _tme_sun44c_cache_cycle_flush(struct tme_sun4 *sun4,
                    806:                              tme_uint32_t asi,
                    807:                              tme_uint32_t address)
                    808: {
                    809:   tme_uint32_t cache_tag_mask;
                    810:   tme_uint32_t cache_tag_value;
                    811:   tme_uint32_t address_mask;
                    812:   tme_uint32_t cache_size;
                    813:   tme_uint32_t cache_line_index;
                    814:   tme_uint32_t cache_line_count;
                    815: 
                    816:   /* assume that this is not a hardware-assisted flush: */
                    817:   cache_line_count = 1;
                    818: 
                    819:   /* if this is a sun4c: */
                    820:   if (TME_SUN4_IS_SUN4C(sun4)) {
                    821: 
                    822:     /* if this is a hardware-assisted flush: */
                    823: #if ((TME_SUN44C_ASI_FLUSH_SEG + 1) != TME_SUN44C_ASI_FLUSH_PG) || ((TME_SUN44C_ASI_FLUSH_PG + 1) != TME_SUN44C_ASI_FLUSH_CONTEXT)
                    824: #error "bad sun4c unassisted flushing ASIs"
                    825: #endif
                    826:     if (asi < TME_SUN44C_ASI_FLUSH_SEG
                    827:        || asi > TME_SUN44C_ASI_FLUSH_CONTEXT) {
                    828: 
                    829:       /* XXX FIXME - what happens when the address is not page-aligned? */
                    830:       if (address % TME_SUN4C_PAGE_SIZE) {
                    831:        abort();
                    832:       }
                    833: 
                    834:       /* we flush one page's worth of cache lines: */
                    835:       cache_line_count = TME_SUN4C_PAGE_SIZE >> sun4->tme_sun4_cache_size_line_log2;
                    836:     }
                    837:   }
                    838:   
                    839:   /* otherwise, this is a sun4: */
                    840:   else {
                    841:     assert(asi != TME_SUN4C_ASI_HW_FLUSH_SEG
                    842:           && asi != TME_SUN4C_ASI_HW_FLUSH_PG);
                    843:   }
                    844: 
                    845:   /* the sun4c hw-flush-all and sun4 flush-user are handled specially: */
                    846:   if (asi == TME_SUN4C_ASI_HW_FLUSH_ALL /* TME_SUN4_ASI_FLUSH_USER */) {
                    847: 
                    848:     /* on the sun4c, this flushes any valid cache line.
                    849:        on the sun4, this flushes any valid user cache line: */
                    850:     cache_tag_value = TME_SUN44C_CACHETAG_VALID;
                    851:     cache_tag_mask
                    852:       = (TME_SUN4_IS_SUN4C(sun4)
                    853:         ? TME_SUN44C_CACHETAG_VALID
                    854:         : TME_SUN44C_CACHETAG_VALID | TME_SUN44C_CACHETAG_SYSTEM);
                    855:   }
                    856: 
                    857:   /* otherwise, this is flushing some subset of the context/address
                    858:      combinations that might be in the cache: */
                    859:   else {
                    860: 
                    861:     /* dispatch on the flush type, to get an mask of bits that we will
                    862:        ignore in the address when we make the tag: */
                    863:     address_mask = 0;
                    864:     cache_tag_mask = 0;
                    865:     switch(asi) {
                    866:     default:
                    867:       assert(FALSE);
                    868:       /* FALLTHROUGH */
                    869:     case TME_SUN4_ASI_FLUSH_REG: /* TME_SUN4C_ASI_HW_FLUSH_CONTEXT */
                    870:       if (!TME_SUN4_IS_SUN4C(sun4)) {
                    871:        abort();
                    872:        break;
                    873:       }
                    874:       /* FALLTHROUGH */
                    875:     case TME_SUN44C_ASI_FLUSH_CONTEXT: 
                    876:       address_mask -= 1;
                    877:       cache_tag_mask = TME_SUN44C_CACHETAG_SYSTEM;
                    878:       break;
                    879:     case TME_SUN44C_ASI_FLUSH_SEG:
                    880:     case TME_SUN4C_ASI_HW_FLUSH_SEG:
                    881:       address_mask -= TME_SUN4_32_SEGMENT_SIZE;
                    882:       break;
                    883:     case TME_SUN44C_ASI_FLUSH_PG:
                    884:     case TME_SUN4C_ASI_HW_FLUSH_PG:
                    885:       address_mask -= TME_SUN4C_PAGE_SIZE;
                    886:       break;
                    887:     }
                    888: 
                    889:     /* turn this address and mask into a cache tag value and mask: */
                    890:     cache_tag_value = _tme_sun44c_cache_tag(sun4, sun4->tme_sun44c_context, address & address_mask);
                    891:     cache_tag_mask |= _tme_sun44c_cache_tag(sun4, 0xff, address_mask);
                    892:   }
                    893: 
                    894:   /* get the total size of the cache: */
                    895:   cache_size = 1 << sun4->tme_sun4_cache_size_log2;
                    896: 
                    897:   /* turn this address into its cache line index: */
                    898:   cache_line_index = (address & (cache_size - 1)) >> sun4->tme_sun4_cache_size_line_log2;
                    899: 
                    900:   /* flush cache lines: */
                    901:   do {
                    902: 
                    903:     /* if this cache line tag matches what we're supposed to flush: */
                    904:     if (((sun4->tme_sun44c_cache_tags[cache_line_index]
                    905:          ^ cache_tag_value)
                    906:         & cache_tag_mask) == 0) {
                    907: 
                    908:       /* flush this cache line: */
                    909:       _tme_sun44c_cache_line_flush(sun4, cache_line_index);
                    910: 
                    911:       /* invalidate this cache line: */
                    912:       sun4->tme_sun44c_cache_tags[cache_line_index] &= ~TME_SUN44C_CACHETAG_VALID;
                    913:     }
                    914: 
                    915:     /* loop: */
                    916:     cache_line_index++;
                    917:   } while (--cache_line_count > 0);
                    918: }
                    919: 
                    920: /* this creates a sun4/4c cache: */
                    921: void
                    922: _tme_sun44c_cache_new(struct tme_sun4 *sun4)
                    923: {
                    924:   tme_uint32_t cache_size;
                    925:   tme_uint32_t cache_size_line;
                    926:   tme_uint32_t cache_size_log2;
                    927:   tme_uint32_t cache_size_line_log2;
                    928:   int cache_writeback;
                    929: 
                    930:   /* assume that if this is a sun4c, the cache is write-through.
                    931:      otherwise, assume the cache is write-back: */
                    932:   cache_writeback = !TME_SUN4_IS_SUN4C(sun4);
                    933: 
                    934:   /* SS2, code name "Calvin": */
                    935:   if (TME_SUN4_IS_MODEL(sun4, TME_SUN_IDPROM_TYPE_CODE_CALVIN)) {
                    936:     cache_size = 64 * 1024;
                    937:     cache_size_line = 32;
                    938:   }
                    939:   else {
                    940:     abort();
                    941:   }
                    942: 
                    943:   /* get the log2 of the cache sizes: */
                    944:   assert (cache_size >= cache_size_line && cache_size_line > sizeof(tme_uint32_t));
                    945:   assert ((cache_size & (cache_size - 1)) == 0);
                    946:   assert ((cache_size_line & (cache_size_line - 1)) == 0);
                    947:   for (cache_size_log2 = 0; (tme_uint32_t) (1 << cache_size_log2) < cache_size; cache_size_log2++);
                    948:   for (cache_size_line_log2 = 0; (tme_uint32_t) (1 << cache_size_line_log2) < cache_size_line; cache_size_line_log2++);
                    949: 
                    950:   /* create the cache: */
                    951:   sun4->tme_sun4_cache_size_log2 = cache_size_log2;
                    952:   sun4->tme_sun4_cache_size_line_log2 = cache_size_line_log2;
                    953:   sun4->tme_sun4_cache_writeback = cache_writeback;  
                    954:   sun4->tme_sun4_cache_data = (tme_uint8_t *) tme_new(tme_uint32_t, (cache_size / sizeof(tme_uint32_t)));
                    955:   sun4->tme_sun44c_cache_tags = tme_new(tme_uint32_t, (cache_size / cache_size_line));
                    956:   tme_rwlock_init(&sun4->tme_sun4_cache_rwlock);
                    957: }

unix.superglobalmegacorp.com

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