Annotation of tme/machine/sun4/sun44c-cache.c, revision 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.