⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cache.c

📁 一个很有名的硬件模拟器。可以模拟CPU
💻 C
📖 第 1 页 / 共 2 页
字号:
/* cache.c - cache module routines *//* SimpleScalar(TM) Tool Suite * Copyright (C) 1994-2003 by Todd M. Austin, Ph.D. and SimpleScalar, LLC. * All Rights Reserved.  *  * THIS IS A LEGAL DOCUMENT, BY USING SIMPLESCALAR, * YOU ARE AGREEING TO THESE TERMS AND CONDITIONS. *  * No portion of this work may be used by any commercial entity, or for any * commercial purpose, without the prior, written permission of SimpleScalar, * LLC (info@simplescalar.com). Nonprofit and noncommercial use is permitted * as described below. *  * 1. SimpleScalar is provided AS IS, with no warranty of any kind, express * or implied. The user of the program accepts full responsibility for the * application of the program and the use of any results. *  * 2. Nonprofit and noncommercial use is encouraged. SimpleScalar may be * downloaded, compiled, executed, copied, and modified solely for nonprofit, * educational, noncommercial research, and noncommercial scholarship * purposes provided that this notice in its entirety accompanies all copies. * Copies of the modified software can be delivered to persons who use it * solely for nonprofit, educational, noncommercial research, and * noncommercial scholarship purposes provided that this notice in its * entirety accompanies all copies. *  * 3. ALL COMMERCIAL USE, AND ALL USE BY FOR PROFIT ENTITIES, IS EXPRESSLY * PROHIBITED WITHOUT A LICENSE FROM SIMPLESCALAR, LLC (info@simplescalar.com). *  * 4. No nonprofit user may place any restrictions on the use of this software, * including as modified by the user, by any other authorized user. *  * 5. Noncommercial and nonprofit users may distribute copies of SimpleScalar * in compiled or executable form as set forth in Section 2, provided that * either: (A) it is accompanied by the corresponding machine-readable source * code, or (B) it is accompanied by a written offer, with no time limit, to * give anyone a machine-readable copy of the corresponding source code in * return for reimbursement of the cost of distribution. This written offer * must permit verbatim duplication by anyone, or (C) it is distributed by * someone who received only the executable form, and is accompanied by a * copy of the written offer of source code. *  * 6. SimpleScalar was developed by Todd M. Austin, Ph.D. The tool suite is * currently maintained by SimpleScalar LLC (info@simplescalar.com). US Mail: * 2395 Timbercrest Court, Ann Arbor, MI 48105. *  * Copyright (C) 1994-2003 by Todd M. Austin, Ph.D. and SimpleScalar, LLC. */#include <stdio.h>#include <stdlib.h>#include <assert.h>#include "host.h"#include "misc.h"#include "machine.h"#include "cache.h"/* cache access macros */#define CACHE_TAG(cp, addr)	((addr) >> (cp)->tag_shift)#define CACHE_SET(cp, addr)	(((addr) >> (cp)->set_shift) & (cp)->set_mask)#define CACHE_BLK(cp, addr)	((addr) & (cp)->blk_mask)#define CACHE_TAGSET(cp, addr)	((addr) & (cp)->tagset_mask)/* extract/reconstruct a block address */#define CACHE_BADDR(cp, addr)	((addr) & ~(cp)->blk_mask)#define CACHE_MK_BADDR(cp, tag, set)					\  (((tag) << (cp)->tag_shift)|((set) << (cp)->set_shift))/* index an array of cache blocks, non-trivial due to variable length blocks */#define CACHE_BINDEX(cp, blks, i)					\  ((struct cache_blk_t *)(((char *)(blks)) +				\			  (i)*(sizeof(struct cache_blk_t) +		\			       ((cp)->balloc				\				? (cp)->bsize*sizeof(byte_t) : 0))))/* cache data block accessor, type parameterized */#define __CACHE_ACCESS(type, data, bofs)				\  (*((type *)(((char *)data) + (bofs))))/* cache data block accessors, by type */#define CACHE_DOUBLE(data, bofs)  __CACHE_ACCESS(double, data, bofs)#define CACHE_FLOAT(data, bofs)	  __CACHE_ACCESS(float, data, bofs)#define CACHE_WORD(data, bofs)	  __CACHE_ACCESS(unsigned int, data, bofs)#define CACHE_HALF(data, bofs)	  __CACHE_ACCESS(unsigned short, data, bofs)#define CACHE_BYTE(data, bofs)	  __CACHE_ACCESS(unsigned char, data, bofs)/* cache block hashing macros, this macro is used to index into a cache   set hash table (to find the correct block on N in an N-way cache), the   cache set index function is CACHE_SET, defined above */#define CACHE_HASH(cp, key)						\  (((key >> 24) ^ (key >> 16) ^ (key >> 8) ^ key) & ((cp)->hsize-1))/* copy data out of a cache block to buffer indicated by argument pointer p */#define CACHE_BCOPY(cmd, blk, bofs, p, nbytes)	\  if (cmd == Read)							\    {									\      switch (nbytes) {							\      case 1:								\	*((byte_t *)p) = CACHE_BYTE(&blk->data[0], bofs); break;	\      case 2:								\	*((half_t *)p) = CACHE_HALF(&blk->data[0], bofs); break;	\      case 4:								\	*((word_t *)p) = CACHE_WORD(&blk->data[0], bofs); break;	\      default:								\	{ /* >= 8, power of two, fits in block */			\	  int words = nbytes >> 2;					\	  while (words-- > 0)						\	    {								\	      *((word_t *)p) = CACHE_WORD(&blk->data[0], bofs);	\	      p += 4; bofs += 4;					\	    }\	}\      }\    }\  else /* cmd == Write */						\    {									\      switch (nbytes) {							\      case 1:								\	CACHE_BYTE(&blk->data[0], bofs) = *((byte_t *)p); break;	\      case 2:								\        CACHE_HALF(&blk->data[0], bofs) = *((half_t *)p); break;	\      case 4:								\	CACHE_WORD(&blk->data[0], bofs) = *((word_t *)p); break;	\      default:								\	{ /* >= 8, power of two, fits in block */			\	  int words = nbytes >> 2;					\	  while (words-- > 0)						\	    {								\	      CACHE_WORD(&blk->data[0], bofs) = *((word_t *)p);		\	      p += 4; bofs += 4;					\	    }\	}\    }\  }/* bound sqword_t/dfloat_t to positive int */#define BOUND_POS(N)		((int)(MIN(MAX(0, (N)), 2147483647)))/* unlink BLK from the hash table bucket chain in SET */static voidunlink_htab_ent(struct cache_t *cp,		/* cache to update */		struct cache_set_t *set,	/* set containing bkt chain */		struct cache_blk_t *blk)	/* block to unlink */{  struct cache_blk_t *prev, *ent;  int index = CACHE_HASH(cp, blk->tag);  /* locate the block in the hash table bucket chain */  for (prev=NULL,ent=set->hash[index];       ent;       prev=ent,ent=ent->hash_next)    {      if (ent == blk)	break;    }  assert(ent);  /* unlink the block from the hash table bucket chain */  if (!prev)    {      /* head of hash bucket list */      set->hash[index] = ent->hash_next;    }  else    {      /* middle or end of hash bucket list */      prev->hash_next = ent->hash_next;    }  ent->hash_next = NULL;}/* insert BLK onto the head of the hash table bucket chain in SET */static voidlink_htab_ent(struct cache_t *cp,		/* cache to update */	      struct cache_set_t *set,		/* set containing bkt chain */	      struct cache_blk_t *blk)		/* block to insert */{  int index = CACHE_HASH(cp, blk->tag);  /* insert block onto the head of the bucket chain */  blk->hash_next = set->hash[index];  set->hash[index] = blk;}/* where to insert a block onto the ordered way chain */enum list_loc_t { Head, Tail };/* insert BLK into the order way chain in SET at location WHERE */static voidupdate_way_list(struct cache_set_t *set,	/* set contained way chain */		struct cache_blk_t *blk,	/* block to insert */		enum list_loc_t where)		/* insert location */{  /* unlink entry from the way list */  if (!blk->way_prev && !blk->way_next)    {      /* only one entry in list (direct-mapped), no action */      assert(set->way_head == blk && set->way_tail == blk);      /* Head/Tail order already */      return;    }  /* else, more than one element in the list */  else if (!blk->way_prev)    {      assert(set->way_head == blk && set->way_tail != blk);      if (where == Head)	{	  /* already there */	  return;	}      /* else, move to tail */      set->way_head = blk->way_next;      blk->way_next->way_prev = NULL;    }  else if (!blk->way_next)    {      /* end of list (and not front of list) */      assert(set->way_head != blk && set->way_tail == blk);      if (where == Tail)	{	  /* already there */	  return;	}      set->way_tail = blk->way_prev;      blk->way_prev->way_next = NULL;    }  else    {      /* middle of list (and not front or end of list) */      assert(set->way_head != blk && set->way_tail != blk);      blk->way_prev->way_next = blk->way_next;      blk->way_next->way_prev = blk->way_prev;    }  /* link BLK back into the list */  if (where == Head)    {      /* link to the head of the way list */      blk->way_next = set->way_head;      blk->way_prev = NULL;      set->way_head->way_prev = blk;      set->way_head = blk;    }  else if (where == Tail)    {      /* link to the tail of the way list */      blk->way_prev = set->way_tail;      blk->way_next = NULL;      set->way_tail->way_next = blk;      set->way_tail = blk;    }  else    panic("bogus WHERE designator");}/* create and initialize a general cache structure */struct cache_t *			/* pointer to cache created */cache_create(char *name,		/* name of the cache */	     int nsets,			/* total number of sets in cache */	     int bsize,			/* block (line) size of cache */	     int balloc,		/* allocate data space for blocks? */	     int usize,			/* size of user data to alloc w/blks */	     int assoc,			/* associativity of cache */	     enum cache_policy policy,	/* replacement policy w/in sets */	     /* block access function, see description w/in struct cache def */	     unsigned int (*blk_access_fn)(enum mem_cmd cmd,					   md_addr_t baddr, int bsize,					   struct cache_blk_t *blk,					   tick_t now),	     unsigned int hit_latency)	/* latency in cycles for a hit */{  struct cache_t *cp;  struct cache_blk_t *blk;  int i, j, bindex;  /* check all cache parameters */  if (nsets <= 0)    fatal("cache size (in sets) `%d' must be non-zero", nsets);  if ((nsets & (nsets-1)) != 0)    fatal("cache size (in sets) `%d' is not a power of two", nsets);  /* blocks must be at least one datum large, i.e., 8 bytes for SS */  if (bsize < 8)    fatal("cache block size (in bytes) `%d' must be 8 or greater", bsize);  if ((bsize & (bsize-1)) != 0)    fatal("cache block size (in bytes) `%d' must be a power of two", bsize);  if (usize < 0)    fatal("user data size (in bytes) `%d' must be a positive value", usize);  if (assoc <= 0)    fatal("cache associativity `%d' must be non-zero and positive", assoc);  if ((assoc & (assoc-1)) != 0)    fatal("cache associativity `%d' must be a power of two", assoc);  if (!blk_access_fn)    fatal("must specify miss/replacement functions");  /* allocate the cache structure */  cp = (struct cache_t *)    calloc(1, sizeof(struct cache_t) + (nsets-1)*sizeof(struct cache_set_t));  if (!cp)    fatal("out of virtual memory");  /* initialize user parameters */  cp->name = mystrdup(name);  cp->nsets = nsets;  cp->bsize = bsize;  cp->balloc = balloc;  cp->usize = usize;  cp->assoc = assoc;  cp->policy = policy;  cp->hit_latency = hit_latency;  /* miss/replacement functions */  cp->blk_access_fn = blk_access_fn;  /* compute derived parameters */  cp->hsize = CACHE_HIGHLY_ASSOC(cp) ? (assoc >> 2) : 0;  cp->blk_mask = bsize-1;  cp->set_shift = log_base2(bsize);  cp->set_mask = nsets-1;  cp->tag_shift = cp->set_shift + log_base2(nsets);  cp->tag_mask = (1 << (32 - cp->tag_shift))-1;  cp->tagset_mask = ~cp->blk_mask;  cp->bus_free = 0;  /* print derived parameters during debug */  debug("%s: cp->hsize     = %d", cp->name, cp->hsize);  debug("%s: cp->blk_mask  = 0x%08x", cp->name, cp->blk_mask);  debug("%s: cp->set_shift = %d", cp->name, cp->set_shift);  debug("%s: cp->set_mask  = 0x%08x", cp->name, cp->set_mask);  debug("%s: cp->tag_shift = %d", cp->name, cp->tag_shift);  debug("%s: cp->tag_mask  = 0x%08x", cp->name, cp->tag_mask);  /* initialize cache stats */  cp->hits = 0;  cp->misses = 0;  cp->replacements = 0;  cp->writebacks = 0;  cp->invalidations = 0;  /* blow away the last block accessed */  cp->last_tagset = 0;  cp->last_blk = NULL;  /* allocate data blocks */  cp->data = (byte_t *)calloc(nsets * assoc,			      sizeof(struct cache_blk_t) +			      (cp->balloc ? (bsize*sizeof(byte_t)) : 0));  if (!cp->data)    fatal("out of virtual memory");  /* slice up the data blocks */  for (bindex=0,i=0; i<nsets; i++)    {      cp->sets[i].way_head = NULL;      cp->sets[i].way_tail = NULL;      /* get a hash table, if needed */      if (cp->hsize)	{	  cp->sets[i].hash =	    (struct cache_blk_t **)calloc(cp->hsize,					  sizeof(struct cache_blk_t *));	  if (!cp->sets[i].hash)	    fatal("out of virtual memory");	}      /* NOTE: all the blocks in a set *must* be allocated contiguously,	 otherwise, block accesses through SET->BLKS will fail (used	 during random replacement selection) */      cp->sets[i].blks = CACHE_BINDEX(cp, cp->data, bindex);            /* link the data blocks into ordered way chain and hash table bucket         chains, if hash table exists */      for (j=0; j<assoc; j++)	{	  /* locate next cache block */	  blk = CACHE_BINDEX(cp, cp->data, bindex);	  bindex++;	  /* invalidate new cache block */	  blk->status = 0;	  blk->tag = 0;	  blk->ready = 0;	  blk->user_data = (usize != 0			    ? (byte_t *)calloc(usize, sizeof(byte_t)) : NULL);	  /* insert cache block into set hash table */	  if (cp->hsize)	    link_htab_ent(cp, &cp->sets[i], blk);	  /* insert into head of way list, order is arbitrary at this point */	  blk->way_next = cp->sets[i].way_head;	  blk->way_prev = NULL;	  if (cp->sets[i].way_head)	    cp->sets[i].way_head->way_prev = blk;	  cp->sets[i].way_head = blk;	  if (!cp->sets[i].way_tail)	    cp->sets[i].way_tail = blk;	}    }  return cp;}/* parse policy */enum cache_policy			/* replacement policy enum */cache_char2policy(char c)		/* replacement policy as a char */{  switch (c) {  case 'l': return LRU;  case 'r': return Random;  case 'f': return FIFO;  default: fatal("bogus replacement policy, `%c'", c);  }}/* print cache configuration */voidcache_config(struct cache_t *cp,	/* cache instance */	     FILE *stream)		/* output stream */{  fprintf(stream,	  "cache: %s: %d sets, %d byte blocks, %d bytes user data/block\n",	  cp->name, cp->nsets, cp->bsize, cp->usize);  fprintf(stream,	  "cache: %s: %d-way, `%s' replacement policy, write-back\n",	  cp->name, cp->assoc,	  cp->policy == LRU ? "LRU"	  : cp->policy == Random ? "Random"	  : cp->policy == FIFO ? "FIFO"	  : (abort(), ""));}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -