コード例 #1
0
ファイル: cache.c プロジェクト: jsarabia1247/waylevelcache
/* flush the block containing ADDR from the cache CP, returns the latency of
   the block flush operation */
unsigned int				/* latency of flush operation */
cache_flush_addr(struct cache_t *cp,	/* cache instance to flush */
		 md_addr_t addr,	/* address of block to flush */
		 tick_t now)		/* time of cache flush */
{
  fprintf( stderr, "flush address\n" );
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  struct cache_blk_t *blk;
  int lat = cp->hit_latency; /* min latency to probe cache */

  if (cp->hsize)
    {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    break;
	}
    }
  else
    {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    break;
	}
    }

  if (blk)
    {
      cp->invalidations++;
      blk->status &= ~CACHE_BLK_VALID;

      /* blow away the last block to hit */
      cp->last_tagset = 0;
      cp->last_blk = NULL;

      if (blk->status & CACHE_BLK_DIRTY)
	{
	  /* write back the invalidated block */
          cp->writebacks++;
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, blk->tag, set),
				   cp->bsize, blk, now+lat);
	}
      /* move this block to tail of the way (LRU) list */
      update_way_list(&cp->sets[set], blk, Tail);
    }

  /* return latency of the operation */
  return lat;
}
コード例 #2
0
/* return non-zero if block containing address ADDR is contained in cache
 CP, this interface is used primarily for debugging and asserting cache
 invariants */
int /* non-zero if access would hit */
cache_probe(struct cache_t *cp, /* cache instance to probe */
md_addr_t addr) /* address of block to probe */
{
	md_addr_t tag = CACHE_TAG(cp, addr);
	md_addr_t set = CACHE_SET(cp, addr);
	struct cache_blk_t *blk;

	/* permissions are checked on cache misses */

	if (cp->hsize) {
		/* higly-associativity cache, access through the per-set hash tables */
		int hindex = CACHE_HASH(cp, tag);

		for (blk = cp->sets[set].hash[hindex]; blk; blk = blk->hash_next) {
			if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
				return TRUE;
		}
	} else {
		/* low-associativity cache, linear search the way list */
		for (blk = cp->sets[set].way_head; blk; blk = blk->way_next) {
			if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
				return TRUE;
		}
	}

	/* cache block not found */
	return FALSE;
}
コード例 #3
0
void prefetch (struct cache_t *cp, md_addr_t addr) {
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t baddr = CACHE_MK_BADDR(cp, tag, set);
  if (!cache_probe(cp, baddr)) {
    cache_access(cp, Read, baddr, NULL, cp->bsize, NULL, NULL, NULL, 1);
  }
}
コード例 #4
0
ファイル: cache.c プロジェクト: mattstock/binutils-bexkat1
/* Find the cache line corresponding to the given address.
   If it is found then 'return_tag' is set to point to the tag for that line
   and 1 is returned.
   If it is not found, 'return_tag' is set to point to the tag for the least
   recently used line and 0 is returned.
*/
static int
get_tag (FRV_CACHE *cache, SI address, FRV_CACHE_TAG **return_tag)
{
  int set;
  int way;
  int bits;
  USI tag;
  FRV_CACHE_TAG *found;
  FRV_CACHE_TAG *available;

  ++cache->statistics.accesses;

  /* First calculate which set this address will fall into. Do this by
     shifting out the bits representing the offset within the line and
     then keeping enough bits to index the set.  */
  set = address & ~(cache->line_size - 1);
  for (bits = cache->line_size - 1; bits != 0; bits >>= 1)
    set >>= 1;
  set &= (cache->sets - 1);
  
  /* Now search the set for a valid tag which matches this address.  At the
     same time make note of the least recently used tag, which we will return
     if no match is found.  */
  available = NULL;
  tag = CACHE_ADDRESS_TAG (cache, address);
  for (way = 0; way < cache->ways; ++way)
    {
      found = CACHE_TAG (cache, set, way);
      /* This tag is available as the least recently used if it is the
	 least recently used seen so far and it is not locked.  */
      if (! found->locked && (available == NULL || available->lru > found->lru))
	available = found;
      if (found->valid && found->tag == tag)
	{
	  *return_tag = found;
	  ++cache->statistics.hits;
	  return 1; /* found it */
	}
    }

  *return_tag = available;
  return 0; /* not found */
}
コード例 #5
0
ファイル: cache.c プロジェクト: jnaneshm/614_hw4
/* access a cache, perform a CMD operation on cache CP at address ADDR,
   places NBYTES of data at *P, returns latency of operation if initiated
   at NOW, places pointer to block user data in *UDATA, *P is untouched if
   cache blocks are not allocated (!CP->BALLOC), UDATA should be NULL if no
   user data is attached to blocks */
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr,	/* for address of replaced block */
 	     tick_t *mem_ready/* ptr to mem_ready of ruu_station */
             )         
{
  byte_t *p = vp;
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);
  md_addr_t blk_addr = CACHE_TAGSET(cp, addr);
  struct cache_blk_t *blk, *repl;
  int lat = 0;
  int i,mshr_hit = -1;
  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:
     ((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
      blk = cp->last_blk;
      goto cache_fast_hit;
    }
    
  if (cp->hsize)
    {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }
  else
    {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }

  /* cache block not found */

  /* **MISS** */
  cp->misses++;
///  printf("mshr enabled=%d\n",mshr_enabled);

//printf("cache_access miss num_mshr=%d\n",cp->num_mshr);
//printf("cache_access with MSHR\n");
// search mshr first to see if already exists, if so wait
// if not in mshr, insert
  if (cp->num_mshr>0) {
    cp->mshr_accesses++;     
     for (i = 0; i < cp->num_mshr; i++) {
        if (cp->mshr[i].ready <= now) {
           /* we have an empty mshr, so we can proceed with the miss */
           mshr_hit = i;
           cp->mshr_misses++;
           //printf("MSHR:miss=%d",cp->mshr_misses);
           break;
        }
     }

     if (mshr_hit == -1) { /* no empty mshr, so stall! */
       cp->mshr_full++;
       if(mem_ready!=NULL)*mem_ready = cp->ready;
       //if (cp->ready <= now) panic("Should have had empty mshr!");
       return MSHR_FULL;
     }
  }
 
//printf("B4 repl\n");
  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */
  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;
    update_way_list(&cp->sets[set], repl, Head);
    break;
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
	*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);
 
      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);
 
      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));
 
      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat);
	}
    }
//  printf("B4 blkaccess\n");
  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */

  /* read data block */
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, now+lat);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    repl->status |= CACHE_BLK_DIRTY;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;

  /* update block status */
  repl->ready = now+lat;

  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

  /* populate mshr entries*/
  if (cp->num_mshr>0 && mshr_hit!=-1) {

     cp->mshr[mshr_hit].ready = repl->ready;
     cp->mshr[mshr_hit].block_addr= blk_addr;
     cp->mshr[mshr_hit].target_num = 1; 
//     printf("MSHR:ready and block_addr=",repl->ready,blk_addr);
     for (i = 0, cp->ready = cp->mshr[0].ready; i < cp->num_mshr; i++) {
        if (cp->mshr[i].ready < cp->ready)
           cp->ready = cp->mshr[i].ready;
     }
  }
  /* return latency of the operation */
  return lat;


 cache_hit: /* slow hit handler */
  
  /* **HIT** */
  cp->hits++;

 /* mshr: check for secondary miss */
  if (cp->num_mshr>0) {
     /* is this a secondary miss? */
     if (blk->ready > now) {
        /* search for matching mshr */
    	cp->mshr_accesses++;     
        for (i = 0; i < cp->num_mshr; i++) {
           if (cp->mshr[i].block_addr == blk_addr && cp->mshr[i].ready > now) {
              if (cp->mshr[i].target_num < 4) {
                 mshr_hit = i;
                 cp->mshr[i].target_num++;
                 cp->mshr_hits++;
                 break;
              }
              else {
                 /* target space full, so stall! */
                 if(mem_ready!=NULL)*mem_ready = cp->mshr[i].ready;
                 cp->mshr_target_full++;
                 return MSHR_TARGET_FULL;
              }
           }
       }
    }
  }
  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == LRU)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));

 cache_fast_hit: /* fast hit handler */
  
  /* **FAST HIT** */
  cp->hits++;
 /* mshr: check for secondary miss */
  if (cp->num_mshr>0) {
     /* is this a secondary miss? */
     if (blk->ready > now) {
        cp->mshr_accesses++;     
        /* search for matching mshr */
        for (i = 0; i < cp->num_mshr; i++) {
           if (cp->mshr[i].block_addr == blk_addr && cp->mshr[i].ready > now) {
              if (cp->mshr[i].target_num < 4) {
                 mshr_hit = i;
                 cp->mshr[i].target_num++;
                 cp->mshr_hits++;
                 break;
              }
              else {
                 /* target space full, so stall! */
                 if(mem_ready!=NULL)*mem_ready = cp->mshr[i].ready;
                 cp->mshr_target_full++;
                 return MSHR_TARGET_FULL;
              }
           }
       }
    }
  }
  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* this block hit last, no change in the way list */

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));
}
コード例 #6
0
ファイル: cache.c プロジェクト: saisujithreddym/pseudocache
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr)	/* for address of replaced block */
{ 
  acheck++;
  //printf("%d \n",acheck);
  byte_t *p = vp;
  md_addr_t tag;
  
  if (pseudo_check==1)
    tag = CACHE_TAG_PSEUDOASSOC(cp, addr);
  else
    tag= CACHE_TAG(cp,addr);
  md_addr_t set = CACHE_SET(cp, addr);
 
  md_addr_t bofs = CACHE_BLK(cp, addr);
  md_addr_t set1=HASH_MASK(set);
  md_addr_t addr1=addr;
  addr1 ^=1<<(cp->set_shift);
  //set1=CACHE_SET(cp,addr1);
  struct cache_blk_t *blk, *repl;
  int lat = 0;
  // if (cp->sets[set].rehash_bit==1)
    //printf("yo");
  //printf("%d",cp->sets[set].way_head->rehash_bit );
  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:
     ((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
     
        //printf("same block hit");
        blk = cp->last_blk;
        //cp->last_blk->rehash_bit=0;
        goto cache_fast_hit;
      
    }
   
  if (cp->hsize)
    {
      //printf("different block hit");
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }
  else 
    { //printf("different block hit");
      
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{ 
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
      { 
       
        goto cache_hit;
      }
        
	      
      
  }
    }

  /* cache block not found */

  /* **MISS** */
 

  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */
  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;
    update_way_list(&cp->sets[set], repl, Head);
    break;
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  default:
    panic("bogus replacement policy");
  }

if(pseudo_check==1)
{  //printf("%d",hash_check);
   if(cp->sets[set].way_head->rehash_bit==1 )
    {//printf("hii");
      if(hash_check==1)
      { cp->sets[set].way_head->rehash_bit=1;
        goto cache_missfinal;
      }
      else if(hash_check==0)
      {
      cp->sets[set].way_head->rehash_bit=0;
      goto cache_missfinal;
    }
    }
    
    if(cp->sets[set].way_head->rehash_bit==0)
        {   //printf("hello");
          if(hash_check==1)
            { cp->sets[set].way_head->rehash_bit=1;
              temp=cp->sets[set].way_head;
              goto cache_missfinal;
            }
          else if(hash_check==0)
            {  
              
            hash_check=1;
            cache_access(cp,cmd,addr1,NULL,nbytes,now,NULL,NULL);
            //goto cache_missfinal;
            }
        }
   //unsigned int uff=0;
  temp1=cp->sets[set].way_head;
  temp1->tag=temp->tag;
 if(temp->status!=3)
    temp1->status=temp->status;//temp->status;
  //printf("%u",temp1->status);
  temp1->ready=temp->ready;
  
 temp->tag=cp->sets[set].way_head->tag;
  temp->status=cp->sets[set].way_head->status;
  temp->ready=cp->sets[set].way_head->ready;
  
  cp->sets[set].way_head->tag=temp1->tag;
  cp->sets[set].way_head->status=temp1->status;
  cp->sets[set].way_head->ready=temp1->ready;
  
  //printf("%d",temp->rehash_bit);
 
}
 
 cache_missfinal:
 hash_check=0;
  cp->misses++;
  
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
	*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);
 
      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);
 
      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));
 
      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat);
	}
    }

  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */

  /* read data block */
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, now+lat);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    repl->status |= CACHE_BLK_DIRTY;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;

  /* update block status */
  repl->ready = now+lat;

  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

  /* return latency of the operation */
  return lat;


 cache_hit: /* slow hit handler */
  
  /* **HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == LRU)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));

 cache_fast_hit: /* fast hit handler */
  
  /* **FAST HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* this block hit last, no change in the way list */

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));
}
コード例 #7
0
ファイル: cache.c プロジェクト: kuthulas/PDP
/* access a cache, perform a CMD operation on cache CP at address ADDR,
   places NBYTES of data at *P, returns latency of operation if initiated
   at NOW, places pointer to block user data in *UDATA, *P is untouched if
   cache blocks are not allocated (!CP->BALLOC), UDATA should be NULL if no
   user data is attached to blocks */
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr)	/* for address of replaced block */
{
  byte_t *p = vp;
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);

  struct cache_blk_t *blk, *repl;
  struct pdp_fifo_node *fnode, *tnode;
  int lat = 0;

  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:
     ((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* PDP distance decrement on set access */
  if(cp->policy == PDP){
    for (blk=cp->sets[set].way_head;
      blk;
      blk=blk->way_next)
    {
      if (blk->rpd > 0) blk->rpd--;
    }
    /* PDP counter update */
    cp->PDP_Nt++;
    if((cp->PDP_Nt % 50000) == 0) compute_pd(cp);
  }

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
      blk = cp->last_blk;
      goto cache_fast_hit;
    }
    
  if (cp->hsize)
    {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }
  else
    {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }

  /* cache block not found */

  /* **MISS** */
  cp->misses++;

  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */
  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;
    update_way_list(&cp->sets[set], repl, Head);
    break;
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  case PDP:
  {
    int bindex, nindex=-1, iindex=1, rindex=1, max_irpd=-1, max_rrpd=-1;
    for (bindex=cp->assoc-1, blk=cp->sets[set].way_head;
      blk;
      bindex--, blk=blk->way_next)
    {
     // if(blk->rpd!=0) printf("BLK: %d, RPD: %d\n", bindex, blk->rpd);
      /* victim is the first-found unprotected line */
      if(blk->rpd == 0) {
        nindex = bindex;
        break;
      }
      
      /* victim selection if there are no unprotected lines */
      /* replace inserted line with highest rpd, if none found replace reused line with highest rpd */
      if(blk->rpd > max_irpd){
        if(blk->reused == 0){
          max_irpd = blk->rpd;
          iindex = bindex;
        }
      }
      if(blk->rpd > max_rrpd){
        if(blk->reused == 1){
          max_rrpd = blk->rpd;
          rindex = bindex;
        }
      }
    }

    if(nindex==-1) {
      nindex = ((max_irpd == -1) ? rindex : iindex);
      repl = cp->sets[set].way_tail;
    }
    else repl = CACHE_BINDEX(cp, cp->sets[set].blks, nindex);
    update_way_list(&cp->sets[set], repl, Head);
    repl->rpd = PDP_PD - 1; /* PDP distance decrement on block replacement */
    repl->reused = 0;
  }
    break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;

  /* write back replaced block data */

  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
	*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);
 
      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);
 
      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));
 
      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat);
	}
    }

  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */
  /* read data block */
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, now+lat);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    repl->status |= CACHE_BLK_DIRTY;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;

  /* update block status */
  repl->ready = now+lat;
  
  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

  /* return latency of the operation */
  return lat;


 cache_hit: /* slow hit handler */
  
  /* **HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && ((cp->policy == LRU) || (cp->policy == PDP)))
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* PDP reuse routine */
    if(cp->policy == PDP){
      blk->rpd = PDP_PD - 1;
      blk->reused = 1;

      /* RD sampler and PDP counter updates */
      int rd;

      for (rd=0, fnode=cp->sets[set].fifo_head;
      fnode;
       fnode=fnode->next)
      {
        if(fnode->address == addr){
          //printf("%d ", rd);
          cp->PDP_Ni[rd]++;
          break;
        }
        rd++;
      }

      /* Push the address to head of FIFO */
      struct pdp_fifo_node * pnode = (struct pdp_fifo_node *)malloc(sizeof(struct pdp_fifo_node));
      pnode->address = addr;
      tnode = cp->sets[set].fifo_head;
      if(tnode) tnode->prev = pnode;
      pnode->next = tnode;
      pnode->prev = NULL;
      cp->sets[set].fifo_head = pnode;
      if(!tnode) cp->sets[set].fifo_tail = cp->sets[set].fifo_head;

      /* truncate fifo on overflow */
      if(cp->sets[set].nfifo == PDP_PD_MAX){
        fnode = cp->sets[set].fifo_tail;
        if(fnode){
          if(fnode->prev){
          fnode->prev->next = NULL;
          cp->sets[set].fifo_tail = fnode->prev;
        }
          free(fnode);
        }
      }
      else cp->sets[set].nfifo++;
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));

 cache_fast_hit: /* fast hit handler */
  
  /* **FAST HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* this block hit last, no change in the way list */

  /* PDP reuse routine */
    if(cp->policy == PDP){
      blk->rpd = PDP_PD - 1;
      blk->reused = 1;

      /* previously hit block, so distance is zero; skipping fifo update */
          cp->PDP_Ni[0]++;
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));
}
コード例 #8
0
/* access a cache, perform a CMD operation on cache CP at address ADDR,
   places NBYTES of data at *P, returns latency of operation if initiated
   at NOW, places pointer to block user data in *UDATA, *P is untouched if
   cache blocks are not allocated (!CP->BALLOC), UDATA should be NULL if no
   user data is attached to blocks */
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr)	/* for address of replaced block */
{
  byte_t *p = vp;
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);
  struct cache_blk_t *blk, *repl;
  int lat = 0;
  int possible_real_miss = 0;
  int low_leak_penalty_flag =0;
  int temp;
  int decay_caused_miss = FALSE;	/* TRUE if it's a decay caused miss */


  if (b_in_dispatch)
	  b_in_dispatch = TRUE;
  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:     
	((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
      blk = cp->last_blk;
      goto cache_fast_hit;
    }
    
  if (cp->hsize)
    {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
if ((blk->status & CACHE_BLK_DECAYED) &&  cache_leak_is_ctrlled())
low_leak_penalty_flag  = 1;
	  if (blk->tag == tag)
	  {
		  /* Leakage: induced misses only in state losing ctrl techniques	*/
		  if ((blk->status & CACHE_BLK_DECAYED) &&  cache_leak_ctrl_is_state_losing())
		  {
			decay_caused_miss = TRUE;
			induced_decay_misses++;
			break;
		  }
		  else if ((blk->status & CACHE_BLK_DECAYED) &&  (blk->status & CACHE_BLK_VALID)\
		  			&& cache_leak_is_ctrlled())
		  {
  			/* 
			 * Leakage: update stats 
			 * in state preserving ctrl, mode switch to high happens 
			 * on a hit to a decayed block too
			 */

  			mode_switch_l2h_incr ();
			/*
	 		 * leakage throughout the cache assumed uniform. Also to model 
	 		 * the effect of settling time of leakage current, the lines 
	 		 * are assumed to be turned off after 'switch_cycles_l2h/2'. 
	 		 * The assumption is that settling is a linear function of time.
	 		 */
			low_leak_ratio_dcr(1.0/(cp->nsets * cp->assoc), get_switch_cycles_l2h()/2);
		  	
		  	goto cache_hit;
		  }	
		  else if( blk->status & CACHE_BLK_VALID)
			goto cache_hit;
	  }
	  else
		if (blk->status & CACHE_BLK_DECAYED)
		    possible_real_miss = 1;

	}
    }
  else
    {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{
if ((blk->status & CACHE_BLK_DECAYED) &&  cache_leak_is_ctrlled())
low_leak_penalty_flag  = 1;
	  if (blk->tag == tag)
	  {
		  /* Leakage: induced misses only in state losing ctrl techniques	*/
		  if ((blk->status & CACHE_BLK_DECAYED) &&  cache_leak_ctrl_is_state_losing())
		  {
			decay_caused_miss = TRUE;
		
  	        	if (cp == decayed_cache)
			{
				induced_decay_misses++;
				break;
			}
		  }
		  else if ((blk->status & CACHE_BLK_DECAYED) &&  (blk->status & CACHE_BLK_VALID)\
		  			&& cache_leak_is_ctrlled())
		  {
  			/* 
			 * Leakage: update stats 
			 * in state preserving ctrl, mode switch to high happens 
			 * on a hit to a decayed block too
			 */

  			mode_switch_l2h_incr ();
			/*
	 		 * leakage throughout the cache assumed uniform. Also to model 
	 		 * the effect of settling time of leakage current, the lines 
	 		 * are assumed to be turned off after 'switch_cycles_l2h/2'. 
	 		 * The assumption is that settling is a linear function of time.
	 		 */
			low_leak_ratio_dcr(1.0/(cp->nsets * cp->assoc), get_switch_cycles_l2h()/2);
		  	
		  	goto cache_hit;
		  }	
		  else if( blk->status & CACHE_BLK_VALID)
			goto cache_hit;
	  }
	  else
		if (blk->status & CACHE_BLK_DECAYED)
		    possible_real_miss = 1;
	}
    }

  /* cache block not found */

  /* **MISS** */
  cp->misses++;

  if (cmd == Write) cp->write_misses++;
	else cp->read_misses++;

  if (cp == decayed_cache && !decay_caused_miss && possible_real_miss)
	 real_decay_misses++;




  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */
  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;

/* FIXMEHZG: replacement policy: choose invalid block first, does this diff from LRU?  */
#if defined(cache_decay)
	if(b_decay_enabled)
	{
		int k, found=0;
		for (blk=cp->sets[set].blks, k=0; k< cp->assoc; blk++, k++)
		{
			/* invalid block has highest priority to be evicted */
			if (!(blk->status & CACHE_BLK_VALID))	
			{
				repl = blk;
				found=1;
				break;
			}
		}
		/* Leakage: if an invalid blk can't be found, find a shutdown one */
		if (!found && cache_leak_ctrl_is_state_losing())
			for (blk=cp->sets[set].blks, k=0; k< cp->assoc; blk++, k++)
			{
				/* invalid block has highest priority to be evicted */
				if (blk->status & CACHE_BLK_DECAYED)	
				{
					repl = blk;
					break;
				}
			}
	}
#endif /* defined(cache_decay) */

    update_way_list(&cp->sets[set], repl, Head);
    break;
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;
 if (low_leak_penalty_flag == 1 && /* repl-> status & CACHE_BLK_DECAYED */ cache_leak_is_ctrlled() )
  {
		temp = get_low_leak_penalty();
	/* latency hiding assumed */
		  lat += get_low_leak_penalty() ;
  }


  /* Leakage: update stats */
  /* mode switch to high happens if   block to be evicted is decayed*/
  if (repl->status & CACHE_BLK_DECAYED)
  {
  	mode_switch_l2h_incr ();
	/*
	 * leakage throughout the cache assumed uniform. Also to model 
	 * the effect of settling time of leakage current, the lines 
	 * are assumed to be turned off after 'switch_cycles_l2h/2'. 
	 * The assumption is that settling is a linear function of time.
	 */
	low_leak_ratio_dcr(1.0/(cp->nsets * cp->assoc), get_switch_cycles_l2h()/2);
  }

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
		*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);
 
      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);
 
      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));
 
      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;


	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat);
	}
    }/* if */

	if (b_decay_profile_enabled)
		update_cache_block_stats_when_miss(cp, repl, cmd, decay_caused_miss);

  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */
  repl->status &= ~CACHE_BLK_DECAYED;	/* not decayed	*/

  /* read data block */ 
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize, repl, now+lat);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
  {
    repl->status |= CACHE_BLK_DIRTY;
	repl->time_dirty = sim_cycle;
  }

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;
/* Leakage: for misses in low leak mode */

 
  /* update block status */
  repl->ready = now+lat;

  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

  /* return latency of the operation */
  return lat;


 cache_hit: /* slow hit handler */

  /* Leakage: for hits in low leak mode */

  if (blk-> status & CACHE_BLK_DECAYED && cache_leak_is_ctrlled() )
  {
  	blk->status &= ~CACHE_BLK_DECAYED;
		temp = get_low_leak_penalty();
	/* latency hiding assumed */
	if (blk->ready < now + get_low_leak_penalty ())
	  blk->ready = now + get_low_leak_penalty() +cp->hit_latency  ;
  }

	if (b_decay_profile_enabled)
		update_cache_block_stats_when_hit(cp, blk, cmd);

  /* **HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
  {
    blk->status |= CACHE_BLK_DIRTY;
	blk->time_dirty = sim_cycle;
  }

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == LRU)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));

 cache_fast_hit: /* fast hit handler */

  /* Leakage: for hits in low leak mode */

  if (blk-> status & CACHE_BLK_DECAYED)
  	fatal ("can't have decayed block in fast_hit");

	if (b_decay_profile_enabled)
		update_cache_block_stats_when_hit(cp, blk, cmd);
  
  /* **FAST HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
  {
    blk->status |= CACHE_BLK_DIRTY;
	blk->time_dirty = sim_cycle;
  }

  /* this block hit last, no change in the way list */

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));
}/* cache_access */
コード例 #9
0
ファイル: cache.c プロジェクト: jsarabia1247/waylevelcache
/* access a cache, perform a CMD operation on cache CP at address ADDR,
   places NBYTES of data at *P, returns latency of operation if initiated
   at NOW, places pointer to block user data in *UDATA, *P is untouched if
   cache blocks are not allocated (!CP->BALLOC), UDATA should be NULL if no
   user data is attached to blocks */
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr)	/* for address of replaced block */
{
  byte_t *p = vp;
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);
  struct cache_blk_t *blk, *repl;
  int lat = 0;

  if(cp->isL2){
    if(set > 512){
      fprintf(stderr, "Houston we have a problem, set = %d\n", set);
      scanf("%d", &lat);
    }
  }

  int pointerLat = 0;

  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:
     ((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
      blk = cp->last_blk;
      goto cache_fast_hit;
    }



  /*FP-JS Loc will store the last line traversed through the list
  I want to keep set so I know where the head of the list is for replacement
  */
  unsigned int loc = set; 
  /*FP-BC Modified cache hit checker for new cache structure*/
  if(cp->isL2)
  {
       /*FP-BC continue through each linked set with data*/
       while(cp->sets[loc].usageCtr)
       {

      //if(cp->isL2)
      //fprintf(stderr, "ptr = %d, loc = %d", cp->sets[loc].fwdPtr, loc);
          if (cp->hsize)
          {
              /* higly-associativity cache, access through the per-set hash tables */
              int hindex = CACHE_HASH(cp, tag);

              for (blk=cp->sets[loc].hash[hindex]; blk; blk=blk->hash_next)
              {
                  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID)){
                    //fprintf(stderr, "Hit!");
                    goto cache_hit;
                  }
              }
          }

          else
          {
              /* low-associativity cache, linear search the way list */
              for (blk=cp->sets[loc].way_head; blk; blk=blk->way_next)
              {
                  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID)){
                       //                 fprintf(stderr, "Hit!");
                    goto cache_hit;
                  }
              }
          }

          /*FP-BC If the current set has a pointer to another set,
            follow it and check again for a hit*/
          if(cp->sets[loc].fwdPtr){
            loc = cp->sets[loc].fwdPtr;
            pointerLat+=1;
          }
          else
            break;
       }
  }

  /*FP-BC Original cache hit checker*/
  else
  {
      if (cp->hsize)
      {
          /* higly-associativity cache, access through the per-set hash tables */
          int hindex = CACHE_HASH(cp, tag);

          for (blk=cp->sets[set].hash[hindex]; blk; blk=blk->hash_next)
          {
              if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
                goto cache_hit;
          }
      }
      else
      {
          /* low-associativity cache, linear search the way list */
          for (blk=cp->sets[set].way_head; blk; blk=blk->way_next)
          {
              if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
                goto cache_hit;
          }
      }
  }

  /* cache block not found */

  /* **MISS** */
  cp->misses++;

    enum cache_policy policy = cp->policy;

  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */
  if(cp->isL2){
    if(cp->sets[loc].fullBit == 0){
      //fprintf(stderr, "FIFO\n" );
      policy = FIFO; //use FIFO to fill the set
      cp->sets[loc].usageCtr++;
      if(loc != set)
        cp->sets[set].usageCtr++;
      if(cp->sets[loc].usageCtr == cp->assoc){
        cp->sets[loc].fullBit = 1; // set full if adding to the set reached its assoc
      }
      set = loc;
    }
    else if(cp->fullFlag == 0){
      int numSets = cp->sets[set].usageCtr/cp->assoc;
      if(numSets < 5){ //only add a line if the linked list is less than 5 length
        //fprintf(stderr, "adding a pointer. FSR = %d, loc = %d\n", cp->FSR, cp->nsets, numSets, loc);
        policy = FIFO;
        cp->sets[loc].usageCtr++;
        if(loc != set)
          cp->sets[set].usageCtr++;
        cp->sets[loc].fwdPtr = cp->FSR;
        if(loc == cp->FSR){
          fprintf(stderr, "FSR = %d loc = %d\n", cp->FSR,  loc);
         // scanf("%s", &loc);
        }
        set = cp->FSR;
        cp->FSR = 1 + (cp->FSR);
        if(cp->FSR >= cp->nsets*2){
          cp->fullFlag = 1;
        }
      }
      else {
        //fprintf(stderr, "more than 5 pointers\n");
        int times = rand() % numSets;
        int i = 0;
        for(i = 0; i < times; i++){
          if(cp->sets[set].fwdPtr != 0){
            set = cp->sets[set].fwdPtr;
                        pointerLat+=1;
          }
        }
      }
    }
    else{ //else everything is full so randomly select a set
      //fprintf(stderr, "evicting a set\n");
      int numSets = cp->sets[set].usageCtr/cp->assoc;
      //fprintf(stderr, "numSets is %d\n", numSets);
      int times = myrand();
      times = times % numSets;
      //fprintf(stderr, "times is %d\n", times);
      int i = 0;
      for(i = 0; i < times; i++){
        if(cp->sets[set].fwdPtr != 0){
          set = cp->sets[set].fwdPtr;
                      pointerLat+=1;
        }
      }
    }
  }
  switch (policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;
    update_way_list(&cp->sets[set], repl, Head);
    break;
  case Random:
    {
      //fprintf(stderr, "here\n" );
      int bindex = myrand();
      bindex = bindex & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
      //fprintf(stderr, "exiting\n" );
    }
    break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
	*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);

      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);

      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));

      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat);
	}
    }

  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */

  /* read data block */
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, now+lat);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }



  /* update dirty status */
  if (cmd == Write)
    repl->status |= CACHE_BLK_DIRTY;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;

  /* update block status */
  repl->ready = now+lat;

  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

  /* return latency of the operation */
  return lat+pointerLat;


 cache_hit: /* slow hit handler */

  /* **HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == LRU)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata){
    *udata = blk->user_data;
    
  }

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency+pointerLat, pointerLat+(blk->ready - now));

 cache_fast_hit: /* fast hit handler */
  /* **FAST HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* this block hit last, no change in the way list */

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* return first cycle data is available to access */
  return (int) MAX(pointerLat+cp->hit_latency, pointerLat+(blk->ready - now));
}
コード例 #10
0
/* access a cache, perform a CMD operation on cache CP at address ADDR,
   places NBYTES of data at *P, returns latency of operation if initiated
   at NOW, places pointer to block user data in *UDATA, *P is untouched if
   cache blocks are not allocated (!CP->BALLOC), UDATA should be NULL if no
   user data is attached to blocks */
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr)	/* for address of replaced block */
{
  byte_t *p = vp;
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);
  struct cache_blk_t *blk, *repl;
  int lat = 0;
  int victim;	//DRRIP-Used in while loop to check if we found the victim block or not
  int RRPV_counter;

  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:
     ((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
      blk = cp->last_blk;	//DRRIP-No need to make RRPV=0 here as the block is accessed previously, so in RRIP-HP it is already 0
      goto cache_fast_hit;
    }
    
  if (cp->hsize)
    {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }
  else
    {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
		{
			blk->RRPV=0;	//DRRIP-Implementing Re-Reference, when we encounter hit then make RRPV=0
			//printf("Its a hit and now RRPV=%d\n", blk->RRPV);
	    		goto cache_hit;
		}
	}
    }

  /* cache block not found */

  /* **MISS***/
  cp->misses++;

  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */

  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;
    update_way_list(&cp->sets[set], repl, Head);
    break;
  case DRRIP:
	RRPV_counter=1<<(cp->RRPV_bits);
	//printf("Max choices=%d\n",RRPV_counter);
	victim=0;
	while(victim==0)	//DRRIP-We keep on looking till the time we don't find the victim block
	{
		//DRRIP-Traversing code copied from hit policy line 559
      		for (blk=cp->sets[set].way_head;blk;blk=blk->way_next)	//DRRIP-Resolves the tie breaker automatically
		{       
			//printf("Value of RRPVin a set=%d\n",blk->RRPV);
			if(blk->RRPV==RRPV_counter-1)                 //DRRIP-To check if we have a block on set with RRPV=3
			{
				victim=1;
				repl=blk;		//DRRIP-Address of the victim block assogned to block to be inserted
				break;
			}
		}
		if(victim==0)	//DRRIP-Incase unable to find blk with RRPV=3
		{
			 for (blk=cp->sets[set].way_head;blk;blk=blk->way_next)  //DRRIP-Traverse the blocks and increment RRPV by 1
				blk->RRPV++;
                }
		if(victim==1)	//DRRIP-Work is done, now get out and update the parameters of inserted block
			break;
	}
        //What to do now when we know that this is the blck to replace
	//Now we will populate the elements of repl block with new data,tag,RRPV value.
    	//printf("Outside the while and victim=%d\n",victim);
      
	//DRRIP-Update the RRPV value of the new inserted block for RRIP
  	if(set==0 || set%1024==0 || set%33==0)
	{
	//	printf("Inside SRRIP with original RRPV=%d\n",repl->RRPV);
		repl->RRPV=RRPV_counter-2;
	//	printf("Inside SRRIP with new RRPV=%d\n",repl->RRPV);
		if(cp->PSEL<1023)
			cp->PSEL++;
	//	printf("Inside srrip with psel=%d\n",cp->PSEL);
		break;
	}
  	else if(set%31==0)
	{
		if(cp->throttle1==31)
		{
	//		printf("Inside BRRIP infrequent case with original RRPV=%d\n",repl->RRPV);
			repl->RRPV=RRPV_counter-2;
	//		printf("Inside BRRIP infrequent case with new RRPV=%d\n",repl->RRPV);
			cp->throttle1=0;
		}
		else
		{
	//		printf("Inside BRRIP majority case with original RRPV=%d\n",repl->RRPV);
			repl->RRPV=RRPV_counter-1;
	//		printf("Inside BRRIP majority case with new RRPV=%d\n",repl->RRPV);
			cp->throttle1++;
		}
		if(cp->PSEL>0)
			cp->PSEL--;
	//	printf("Value of throttle1=%d\n",cp->throttle1);
		break;
	}
  	else
	{
	//	printf("In follower set with PSEL=%d\n",cp->PSEL);
		if(cp->PSEL<511)
		{
	//		printf("In follower SRRIP with original RRPV=%d\n",repl->RRPV);
			repl->RRPV=RRPV_counter-2;
	//		printf("In follower SRRIP with new RRPV=%d\n",repl->RRPV);
			break;
		
		}
		else
		{
			if(cp->throttle2==31)
			{
	//			printf("Inside follower BRRIP infrequent case with original RRPV=%d\n",repl->RRPV);
				repl->RRPV=RRPV_counter-2;
	//			printf("Inside follower  BRRIP infrquent case with new RRPV=%d\n",repl->RRPV);
				cp->throttle2=0;
			}
			else
			{
	//			printf("Inside follower BRRIP majority case with original RRPV=%d\n",repl->RRPV);
				repl->RRPV=RRPV_counter-1;
	//			printf("Inside follower BRRIP majority case with new RRPV=%d\n",repl->RRPV);
				cp->throttle2++;
			}
	//		printf("Value of throttle2=%d\n",cp->throttle2);
			break;
		}
	}		//End of DRRIP
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
	*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);
 
      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);
 
      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));
 
      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat);
	}
    }

  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */
  
  /* read data block */
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, now+lat);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    repl->status |= CACHE_BLK_DIRTY;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;

  /* update block status */
  repl->ready = now+lat;

  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

   /* return latency of the operation */
  return lat;
  

 cache_hit: /* slow hit handler */
  
  /* **HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == LRU)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));

 cache_fast_hit: /* fast hit handler */
  
  /* **FAST HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* this block hit last, no change in the way list */

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));
}
コード例 #11
0
/* access a cache, perform a CMD operation on cache CP at address ADDR,
   places NBYTES of data at *P, returns latency of operation if initiated
   at NOW, places pointer to block user data in *UDATA, *P is untouched if
   cache blocks are not allocated (!CP->BALLOC), UDATA should be NULL if no
   user data is attached to blocks */
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr)	/* for address of replaced block */
{
  byte_t *p = vp;
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);
  struct cache_blk_t *blk, *repl;
  int lat = 0;

  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:
     ((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
      blk = cp->last_blk;
      goto cache_fast_hit;
    }
    
  if (cp->hsize)
    {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }
  else
    {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }

  /* cache block not found */

  /* **MISS** */
  cp->misses++;

  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */
  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;
    update_way_list(&cp->sets[set], repl, Head);
    break;
	case DIP:
		repl = cp->sets[set].way_tail;
		enum list_loc_t where;		/* insert location */
		if ( cp->sets[set].DIP_set_type == LRU_set ) {
			where = Head;
			// update PSEL to bias BIP
			int max_PSEL = 1 << cp->width_PSEL - 1;
			if ( cp->PSEL < max_PSEL ) {
				cp->PSEL ++;
			}
		}
		else if ( cp->sets[set].DIP_set_type == BIP_set ) {
			if ( cp->BIPCTR == 0 ) {
				// use LRU policy, MRU insertion
				where = Head;
			}
			else {
				// use LIP policy, LRU insertion
				where = Tail;
			}
			// update BIPCTR in a non-saturating way
//			int max_BIPCTR = 1 << cp->width_BIPCTR - 1;
//			if ( cp->BIPCTR < max_BIPCTR ) {
//					cp->BIPCTR ++;
//			}
//			else {
//					cp->BIPCTR = 0;
//			}
			// update PSEL to bias LRU
			if ( cp->PSEL > 0 ) {
				cp->PSEL --;
			}
		}
		else {
			// most significant bit of PSEL counter
			int MSB_PSEL = cp->PSEL >> (cp->width_PSEL - 1);
			if ( MSB_PSEL == 1 ) {
				// use BIP
				if ( cp->BIPCTR == 0 ) {
					// use LRU policy, MRU insertion
					where = Head;
				}
				else {
					// use LIP policy, LRU insertion
					where = Tail;
				}
				// need to update BIPCTR ?
			}
			else {
				// use LRU
				where = Head;
			}
		}
    update_way_list(&cp->sets[set], repl, where);
		// update BIPCTR in a non-saturating way
		int max_BIPCTR = 1 << cp->width_BIPCTR - 1;
		if ( cp->BIPCTR < max_BIPCTR ) {
				cp->BIPCTR ++;
		}
		else {
				cp->BIPCTR = 0;
		}
		break;
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
	*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);
 
      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);
 
      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));
 
      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat);
	}
    }

  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */

  /* read data block */
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, now+lat);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    repl->status |= CACHE_BLK_DIRTY;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;

  /* update block status */
  repl->ready = now+lat;

  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

  /* return latency of the operation */
  return lat;


 cache_hit: /* slow hit handler */
  
  /* **HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == LRU)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* if DIP replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == DIP)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));

 cache_fast_hit: /* fast hit handler */
  
  /* **FAST HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* this block hit last, no change in the way list */

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));
}
コード例 #12
0
ファイル: cache.cpp プロジェクト: swlpark/ece552
/* access a cache, perform a CMD operation on cache CP at address ADDR,
   places NBYTES of data at *P, returns latency of operation if initiated
   at NOW, places pointer to block user data in *UDATA, *P is untouched if
   cache blocks are not allocated (!CP->BALLOC), UDATA should be NULL if no
   user data is attached to blocks */
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr,	/* for address of replaced block */
	     int prefetch)		/* 1 if the access is a prefetch, 0 if it is not */
{
  byte_t *p = vp;
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);
  struct cache_blk_t *blk, *repl;
  int lat = 0;

  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:
     ((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
      blk = cp->last_blk;
      goto cache_fast_hit;
    }
    
  if (cp->hsize)
    {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }
  else
    {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }

  /* cache block not found */

  /* **MISS** */
  if (prefetch == 0 ) {

     cp->misses++;

     if (cmd == Read) {	
	cp->read_misses++;
     }
  }

  /* ECE552 Assignment 4 - BEGIN CODE */
  if (strcmp(cp->name, "dl1") == 0) {
    for(std::list<evicted_tag>::iterator it = evicted_blks[set].begin(); it != evicted_blks[set].end(); ++it)
    {
       if(it->tag == tag && it->prefetched) {
         //move element to the front of the list
         if(it != evicted_blks[set].begin()) {
           std::list<evicted_tag>::iterator tmp = it; 
           evicted_blks[set].splice(evicted_blks[set].begin(), evicted_blks[set], tmp, ++it);
         }
         cp->prefetch_misses++;
         break;
       }
    }
  }
  /* ECE552 Assignment 4 - END CODE */


  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */
  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;
    update_way_list(&cp->sets[set], repl, Head);
    break;
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
	*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);
 
      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);
 
      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));
 
      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat, 0);
	}
    }

  /* ECE552 Assignment 4 - BEGIN CODE */
  /* evicted cache_blk */

  if (strcmp(cp->name, "dl1") == 0) {
    if (evicted_blks[set].size() < cp->assoc) {
       evicted_blks[set].push_front({false, repl->tag});
    } else {
       evicted_blks[set].pop_back();
       evicted_blks[set].push_front({false, repl->tag});
    }
  }
  /* ECE552 Assignment 4 - END CODE */


  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */

  /* read data block */
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, now+lat, prefetch);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    repl->status |= CACHE_BLK_DIRTY;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;

  /* update block status */
  repl->ready = now+lat;

  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

  if (prefetch == 0) {	/* only regular cache accesses can generate a prefetch */
  	generate_prefetch(cp, addr);
  }

  /* return latency of the operation */
  return lat;


 cache_hit: /* slow hit handler */
  
  /* **HIT** */
  if (prefetch == 0) {

     cp->hits++;

     if (cmd == Read) {	
	   cp->read_hits++;
     }
  }
  /* ECE552 Assignment 4 - BEGIN CODE */
  if (blk->prefetched){
    if(blk->prefetch_used == 0) {
       blk->prefetch_used = 1;
       cp->prefetch_useful_cnt++;
    }
  }
  /* ECE552 Assignment 4 - END CODE */


  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == LRU)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  if (prefetch == 0) {	/* only regular cache accesses can generate a prefetch */
	generate_prefetch(cp, addr);
  }


  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));

 cache_fast_hit: /* fast hit handler */
  
  /* **FAST HIT** */
  if (prefetch == 0) {
     
     cp->hits++;

     if (cmd == Read) {	
        cp->read_hits++;
     }
  }
  /* ECE552 Assignment 4 - BEGIN CODE */
  if (blk->prefetched){
    if(blk->prefetch_used == 0) {
       blk->prefetch_used = 1;
       cp->prefetch_useful_cnt++;
    }
  }
  /* ECE552 Assignment 4 - END CODE */


  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* this block hit last, no change in the way list */

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  if (prefetch == 0) {	/* only regular cache accesses can generate a prefetch */
     generate_prefetch(cp, addr);
  }

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));
}
コード例 #13
0
ファイル: cache.cpp プロジェクト: swlpark/ece552
/* ECE552 Assignment 4 - BEGIN CODE */
void fetch_cache_blk (struct cache_t *cp, md_addr_t addr) {
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);

  int lat = 0;
  struct cache_blk_t *blk, *repl;

  //check if the block already exists in cache
  if (cp->hsize) {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex]; blk; blk=blk->hash_next){
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    return;
      }
  } else {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head; blk; blk=blk->way_next) {
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    return;
      }
  }
  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;
    update_way_list(&cp->sets[set], repl, Head);
    break;
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* evicted cache_blk */
  if (evicted_blks[set].size() < cp->assoc) {
     evicted_blks[set].push_front({true, repl->tag});
  } else {
     evicted_blks[set].pop_back();
     evicted_blks[set].push_front({true, repl->tag});
  }

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID) {
      cp->replacements++;
      if (repl->status & CACHE_BLK_DIRTY)
      {
        /* write back the cache block */
        cp->writebacks++;
        lat += cp->blk_access_fn(Write,
      			   CACHE_MK_BADDR(cp, repl->tag, set),
      			   cp->bsize, repl, 0, 0);
      }
  }
  /* update block tags */
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */
  repl->prefetched = 1;
  repl->prefetch_used = 0;

  /* read data block */
  cp->prefetch_cnt += 1;
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, NULL, 0);

  /* update block status */
  repl->ready = NULL;

  /* link this entry back into the hash table */
  if (cp->hsize)
     link_htab_ent(cp, &cp->sets[set], repl);

}
コード例 #14
0
ファイル: cache.c プロジェクト: Monster-Zou/simplesim-3.0
/* access a cache, perform a CMD operation on cache CP at address ADDR,
   places NBYTES of data at *P, returns latency of operation if initiated
   at NOW, places pointer to block user data in *UDATA, *P is untouched if
   cache blocks are not allocated (!CP->BALLOC), UDATA should be NULL if no
   user data is attached to blocks */
unsigned int				/* latency of access in cycles */
cache_access(struct cache_t *cp,	/* cache to access */
	     enum mem_cmd cmd,		/* access type, Read or Write */
	     md_addr_t addr,		/* address of access */
	     void *vp,			/* ptr to buffer for input/output */
	     int nbytes,		/* number of bytes to access */
	     tick_t now,		/* time of access */
	     byte_t **udata,		/* for return of user data ptr */
	     md_addr_t *repl_addr)	/* for address of replaced block */
{
  byte_t *p = vp;
  //tag, set is the address want to access
  md_addr_t tag = CACHE_TAG(cp, addr);
  md_addr_t set = CACHE_SET(cp, addr);
  md_addr_t bofs = CACHE_BLK(cp, addr);

  struct cache_blk_t *blk, *repl;
  int lat = 0;

  //printf("mother f****r\n");
  //sprintf(buf, "%s.inv_rate", name);

  /* default replacement address */
  if (repl_addr)
    *repl_addr = 0;

  /* check alignments */
  if ((nbytes & (nbytes-1)) != 0 || (addr & (nbytes-1)) != 0)
    fatal("cache: access error: bad size or alignment, addr 0x%08x", addr);

  /* access must fit in cache block */
  /* FIXME:
     ((addr + (nbytes - 1)) > ((addr & ~cp->blk_mask) + (cp->bsize - 1))) */
  if ((addr + nbytes) > ((addr & ~cp->blk_mask) + cp->bsize))
    fatal("cache: access error: access spans block, addr 0x%08x", addr);

  /* permissions are checked on cache misses */

  /* check for a fast hit: access to same block */
  if (CACHE_TAGSET(cp, addr) == cp->last_tagset)
    {
      /* hit in the same block */
      blk = cp->last_blk;
      goto cache_fast_hit;
    }
    
  if (cp->hsize)
    {
      /* higly-associativity cache, access through the per-set hash tables */
      int hindex = CACHE_HASH(cp, tag);

      for (blk=cp->sets[set].hash[hindex];
	   blk;
	   blk=blk->hash_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }
  else
    {
      /* low-associativity cache, linear search the way list */
      for (blk=cp->sets[set].way_head;
	   blk;
	   blk=blk->way_next)
	{
	  if (blk->tag == tag && (blk->status & CACHE_BLK_VALID))
	    goto cache_hit;
	}
    }

  /* cache block not found */

  /* **MISS** */
  cp->misses++;

  /* select the appropriate block to replace, and re-link this entry to
     the appropriate place in the way list */
  switch (cp->policy) {
  case LRU:
  case FIFO:
    repl = cp->sets[set].way_tail;


    update_way_list(&cp->sets[set], repl, Head);
	//the tail of way list is the victim
	//move the victim to the head and wait new data block replacing it
	//each time when cache misses, new fetched cache block will be placed in MRU position
	//cp->sets[set].way_tail still points to victim cache, but the position of victim cache is moved to the head of way list of this set
    break;
  case Random:
    {
      int bindex = myrand() & (cp->assoc - 1);
      repl = CACHE_BINDEX(cp, cp->sets[set].blks, bindex);
    }
    break;
  case Pseudo:
  {
	  int bindex=0;
	  int width_PLRU_state=cp->assoc-1;
	  int PLRU_state=cp->sets[set].PLRU_STATE;
	  int width_bindex=0;
	  for(width_bindex=0;;width_bindex++){
		  if((cp->assoc>>width_bindex)==1){
			  break;
		  }
	  }
	  int i=0;
	  int j=0;
	  bindex=0;
	  for(j=0;j<width_bindex;j++){
		  int bit=(PLRU_state>>i)&0x1;
		  if(bit==1){
			  i=i*2+2;
		  }else if(bit==0){
			  i=i*2+i;
		  }
		  bit=bit^0x1;
		  bindex=(bindex<<1)|bit;
	  }
	  repl=CACHE_BINDEX(cp,cp->sets[set].blks,bindex);
	  int orig_PLRU_state=cp->sets[set].PLRU_STATE;
	  cp->sets[set].PLRU_STATE=update_PLRU_state(cp->assoc,bindex,orig_PLRU_state);
  }
	  break;
  case MRU:
	  repl=cp->sets[set].way_head;
	  update_way_list(&cp->sets[set],repl,Tail);
	  break;
  case LIP:
	  repl=cp->sets[set].way_tail;
	  break;
  default:
    panic("bogus replacement policy");
  }

  /* remove this block from the hash bucket chain, if hash exists */
  if (cp->hsize)
    unlink_htab_ent(cp, &cp->sets[set], repl);

  /* blow away the last block to hit */
  cp->last_tagset = 0;
  cp->last_blk = NULL;
  cp->last_blk_addr=0;

  /* write back replaced block data */
  if (repl->status & CACHE_BLK_VALID)
    {
      cp->replacements++;

      if (repl_addr)
	*repl_addr = CACHE_MK_BADDR(cp, repl->tag, set);

	  //last accessed address
	  //repl->rag and set form the address of the victim cache block
	  //cp->last_blk_addr records the address of victim
	  //
	  //to use victim cache,
	  //if l1 cache misses, then victim cache will be scanned
	  //if victim cache hits, then the victim data block in l1 cache and hit data block in victim cache will excahnge
	  cp->last_blk_addr=CACHE_MK_BADDR(cp, repl->tag, set);
 
      /* don't replace the block until outstanding misses are satisfied */
      lat += BOUND_POS(repl->ready - now);
 
      /* stall until the bus to next level of memory is available */
      lat += BOUND_POS(cp->bus_free - (now + lat));
 
      /* track bus resource usage */
      cp->bus_free = MAX(cp->bus_free, (now + lat)) + 1;

      if (repl->status & CACHE_BLK_DIRTY)
	{
	  /* write back the cache block */
	  cp->writebacks++;
	  //repl is the block to be replaced
	  lat += cp->blk_access_fn(Write,
				   CACHE_MK_BADDR(cp, repl->tag, set),
				   cp->bsize, repl, now+lat);
	}
    }

  /* update block tags */
  //tag is the real address want to access, so use tag to replace repl->tag equalizes replace the victim with desired cache block
  repl->tag = tag;
  repl->status = CACHE_BLK_VALID;	/* dirty bit set on update */

  /* read data block */
  //if victim cache exists
  //read the data block from victim cache first
  //and then read data block from lower level cache
  //to add victim cache, just need to modify dl1_access_fn function
  lat += cp->blk_access_fn(Read, CACHE_BADDR(cp, addr), cp->bsize,
			   repl, now+lat);

  /* copy data out of cache block */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, repl, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    repl->status |= CACHE_BLK_DIRTY;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = repl->user_data;

  /* update block status */
  repl->ready = now+lat;

  /* link this entry back into the hash table */
  if (cp->hsize)
    link_htab_ent(cp, &cp->sets[set], repl);

  /* return latency of the operation */
  return lat;


 cache_hit: /* slow hit handler */
  
  /* **HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* if LRU replacement and this is not the first element of list, reorder */
  if (blk->way_prev && cp->policy == LRU)
    {
      /* move this block to head of the way (MRU) list */
      update_way_list(&cp->sets[set], blk, Head);
    }

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));

 cache_fast_hit: /* fast hit handler */
  
  /* **FAST HIT** */
  cp->hits++;

  /* copy data out of cache block, if block exists */
  if (cp->balloc)
    {
      CACHE_BCOPY(cmd, blk, bofs, p, nbytes);
    }

  /* update dirty status */
  if (cmd == Write)
    blk->status |= CACHE_BLK_DIRTY;

  /* this block hit last, no change in the way list */

  /* tag is unchanged, so hash links (if they exist) are still valid */

  /* get user block data, if requested and it exists */
  if (udata)
    *udata = blk->user_data;

  /* record the last block to hit */
  cp->last_tagset = CACHE_TAGSET(cp, addr);
  cp->last_blk = blk;

  /* return first cycle data is available to access */
  return (int) MAX(cp->hit_latency, (blk->ready - now));
}