bpred.c

来自「一个很有名的硬件模拟器。可以模拟CPU」· C语言 代码 · 共 986 行 · 第 1/2 页

C
986
字号
/* bpred.c - branch predictor 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 <math.h>#include <assert.h>#include "host.h"#include "misc.h"#include "machine.h"#include "bpred.h"/* turn this on to enable the SimpleScalar 2.0 RAS bug *//* #define RAS_BUG_COMPATIBLE *//* create a branch predictor */struct bpred_t *			/* branch predictory instance */bpred_create(enum bpred_class class,	/* type of predictor to create */	     unsigned int bimod_size,	/* bimod table size */	     unsigned int l1size,	/* 2lev l1 table size */	     unsigned int l2size,	/* 2lev l2 table size */	     unsigned int meta_size,	/* meta table size */	     unsigned int shift_width,	/* history register width */	     unsigned int xor,  	/* history xor address flag */	     unsigned int btb_sets,	/* number of sets in BTB */ 	     unsigned int btb_assoc,	/* BTB associativity */	     unsigned int retstack_size) /* num entries in ret-addr stack */{  struct bpred_t *pred;  if (!(pred = calloc(1, sizeof(struct bpred_t))))    fatal("out of virtual memory");  pred->class = class;  switch (class) {  case BPredComb:    /* bimodal component */    pred->dirpred.bimod =       bpred_dir_create(BPred2bit, bimod_size, 0, 0, 0);    /* 2-level component */    pred->dirpred.twolev =       bpred_dir_create(BPred2Level, l1size, l2size, shift_width, xor);    /* metapredictor component */    pred->dirpred.meta =       bpred_dir_create(BPred2bit, meta_size, 0, 0, 0);    break;  case BPred2Level:    pred->dirpred.twolev =       bpred_dir_create(class, l1size, l2size, shift_width, xor);    break;  case BPred2bit:    pred->dirpred.bimod =       bpred_dir_create(class, bimod_size, 0, 0, 0);  case BPredTaken:  case BPredNotTaken:    /* no other state */    break;  default:    panic("bogus predictor class");  }  /* allocate ret-addr stack */  switch (class) {  case BPredComb:  case BPred2Level:  case BPred2bit:    {      int i;      /* allocate BTB */      if (!btb_sets || (btb_sets & (btb_sets-1)) != 0)	fatal("number of BTB sets must be non-zero and a power of two");      if (!btb_assoc || (btb_assoc & (btb_assoc-1)) != 0)	fatal("BTB associativity must be non-zero and a power of two");      if (!(pred->btb.btb_data = calloc(btb_sets * btb_assoc,					sizeof(struct bpred_btb_ent_t))))	fatal("cannot allocate BTB");      pred->btb.sets = btb_sets;      pred->btb.assoc = btb_assoc;      if (pred->btb.assoc > 1)	for (i=0; i < (pred->btb.assoc*pred->btb.sets); i++)	  {	    if (i % pred->btb.assoc != pred->btb.assoc - 1)	      pred->btb.btb_data[i].next = &pred->btb.btb_data[i+1];	    else	      pred->btb.btb_data[i].next = NULL;	    	    if (i % pred->btb.assoc != pred->btb.assoc - 1)	      pred->btb.btb_data[i+1].prev = &pred->btb.btb_data[i];	  }      /* allocate retstack */      if ((retstack_size & (retstack_size-1)) != 0)	fatal("Return-address-stack size must be zero or a power of two");            pred->retstack.size = retstack_size;      if (retstack_size)	if (!(pred->retstack.stack = calloc(retstack_size, 					    sizeof(struct bpred_btb_ent_t))))	  fatal("cannot allocate return-address-stack");      pred->retstack.tos = retstack_size - 1;            break;    }  case BPredTaken:  case BPredNotTaken:    /* no other state */    break;  default:    panic("bogus predictor class");  }  return pred;}/* create a branch direction predictor */struct bpred_dir_t *		/* branch direction predictor instance */bpred_dir_create (  enum bpred_class class,	/* type of predictor to create */  unsigned int l1size,	 	/* level-1 table size */  unsigned int l2size,	 	/* level-2 table size (if relevant) */  unsigned int shift_width,	/* history register width */  unsigned int xor)	    	/* history xor address flag */{  struct bpred_dir_t *pred_dir;  unsigned int cnt;  int flipflop;  if (!(pred_dir = calloc(1, sizeof(struct bpred_dir_t))))    fatal("out of virtual memory");  pred_dir->class = class;  cnt = -1;  switch (class) {  case BPred2Level:    {      if (!l1size || (l1size & (l1size-1)) != 0)	fatal("level-1 size, `%d', must be non-zero and a power of two", 	      l1size);      pred_dir->config.two.l1size = l1size;            if (!l2size || (l2size & (l2size-1)) != 0)	fatal("level-2 size, `%d', must be non-zero and a power of two", 	      l2size);      pred_dir->config.two.l2size = l2size;            if (!shift_width || shift_width > 30)	fatal("shift register width, `%d', must be non-zero and positive",	      shift_width);      pred_dir->config.two.shift_width = shift_width;            pred_dir->config.two.xor = xor;      pred_dir->config.two.shiftregs = calloc(l1size, sizeof(int));      if (!pred_dir->config.two.shiftregs)	fatal("cannot allocate shift register table");            pred_dir->config.two.l2table = calloc(l2size, sizeof(unsigned char));      if (!pred_dir->config.two.l2table)	fatal("cannot allocate second level table");      /* initialize counters to weakly this-or-that */      flipflop = 1;      for (cnt = 0; cnt < l2size; cnt++)	{	  pred_dir->config.two.l2table[cnt] = flipflop;	  flipflop = 3 - flipflop;	}      break;    }  case BPred2bit:    if (!l1size || (l1size & (l1size-1)) != 0)      fatal("2bit table size, `%d', must be non-zero and a power of two", 	    l1size);    pred_dir->config.bimod.size = l1size;    if (!(pred_dir->config.bimod.table =	  calloc(l1size, sizeof(unsigned char))))      fatal("cannot allocate 2bit storage");    /* initialize counters to weakly this-or-that */    flipflop = 1;    for (cnt = 0; cnt < l1size; cnt++)      {	pred_dir->config.bimod.table[cnt] = flipflop;	flipflop = 3 - flipflop;      }    break;  case BPredTaken:  case BPredNotTaken:    /* no other state */    break;  default:    panic("bogus branch direction predictor class");  }  return pred_dir;}/* print branch direction predictor configuration */voidbpred_dir_config(  struct bpred_dir_t *pred_dir,	/* branch direction predictor instance */  char name[],			/* predictor name */  FILE *stream)			/* output stream */{  switch (pred_dir->class) {  case BPred2Level:    fprintf(stream,      "pred_dir: %s: 2-lvl: %d l1-sz, %d bits/ent, %s xor, %d l2-sz, direct-mapped\n",      name, pred_dir->config.two.l1size, pred_dir->config.two.shift_width,      pred_dir->config.two.xor ? "" : "no", pred_dir->config.two.l2size);    break;  case BPred2bit:    fprintf(stream, "pred_dir: %s: 2-bit: %d entries, direct-mapped\n",      name, pred_dir->config.bimod.size);    break;  case BPredTaken:    fprintf(stream, "pred_dir: %s: predict taken\n", name);    break;  case BPredNotTaken:    fprintf(stream, "pred_dir: %s: predict not taken\n", name);    break;  default:    panic("bogus branch direction predictor class");  }}/* print branch predictor configuration */voidbpred_config(struct bpred_t *pred,	/* branch predictor instance */	     FILE *stream)		/* output stream */{  switch (pred->class) {  case BPredComb:    bpred_dir_config (pred->dirpred.bimod, "bimod", stream);    bpred_dir_config (pred->dirpred.twolev, "2lev", stream);    bpred_dir_config (pred->dirpred.meta, "meta", stream);    fprintf(stream, "btb: %d sets x %d associativity", 	    pred->btb.sets, pred->btb.assoc);    fprintf(stream, "ret_stack: %d entries", pred->retstack.size);    break;  case BPred2Level:    bpred_dir_config (pred->dirpred.twolev, "2lev", stream);    fprintf(stream, "btb: %d sets x %d associativity", 	    pred->btb.sets, pred->btb.assoc);    fprintf(stream, "ret_stack: %d entries", pred->retstack.size);    break;  case BPred2bit:    bpred_dir_config (pred->dirpred.bimod, "bimod", stream);    fprintf(stream, "btb: %d sets x %d associativity", 	    pred->btb.sets, pred->btb.assoc);    fprintf(stream, "ret_stack: %d entries", pred->retstack.size);    break;  case BPredTaken:    bpred_dir_config (pred->dirpred.bimod, "taken", stream);    break;  case BPredNotTaken:    bpred_dir_config (pred->dirpred.bimod, "nottaken", stream);    break;  default:    panic("bogus branch predictor class");  }}/* print predictor stats */voidbpred_stats(struct bpred_t *pred,	/* branch predictor instance */	    FILE *stream)		/* output stream */{  fprintf(stream, "pred: addr-prediction rate = %f\n",	  (double)pred->addr_hits/(double)(pred->addr_hits+pred->misses));  fprintf(stream, "pred: dir-prediction rate = %f\n",	  (double)pred->dir_hits/(double)(pred->dir_hits+pred->misses));}/* register branch predictor stats */voidbpred_reg_stats(struct bpred_t *pred,	/* branch predictor instance */		struct stat_sdb_t *sdb)	/* stats database */{  char buf[512], buf1[512], *name;  /* get a name for this predictor */  switch (pred->class)    {    case BPredComb:      name = "bpred_comb";      break;    case BPred2Level:      name = "bpred_2lev";      break;    case BPred2bit:      name = "bpred_bimod";      break;    case BPredTaken:      name = "bpred_taken";      break;    case BPredNotTaken:      name = "bpred_nottaken";      break;    default:      panic("bogus branch predictor class");    }  sprintf(buf, "%s.lookups", name);  stat_reg_counter(sdb, buf, "total number of bpred lookups",		   &pred->lookups, 0, NULL);  sprintf(buf, "%s.updates", name);  sprintf(buf1, "%s.dir_hits + %s.misses", name, name);  stat_reg_formula(sdb, buf, "total number of updates", buf1, "%12.0f");  sprintf(buf, "%s.addr_hits", name);  stat_reg_counter(sdb, buf, "total number of address-predicted hits", 		   &pred->addr_hits, 0, NULL);  sprintf(buf, "%s.dir_hits", name);  stat_reg_counter(sdb, buf, 		   "total number of direction-predicted hits "		   "(includes addr-hits)", 		   &pred->dir_hits, 0, NULL);  if (pred->class == BPredComb)    {      sprintf(buf, "%s.used_bimod", name);      stat_reg_counter(sdb, buf, 		       "total number of bimodal predictions used", 		       &pred->used_bimod, 0, NULL);      sprintf(buf, "%s.used_2lev", name);      stat_reg_counter(sdb, buf, 		       "total number of 2-level predictions used", 		       &pred->used_2lev, 0, NULL);    }  sprintf(buf, "%s.misses", name);  stat_reg_counter(sdb, buf, "total number of misses", &pred->misses, 0, NULL);  sprintf(buf, "%s.jr_hits", name);  stat_reg_counter(sdb, buf,		   "total number of address-predicted hits for JR's",		   &pred->jr_hits, 0, NULL);  sprintf(buf, "%s.jr_seen", name);  stat_reg_counter(sdb, buf,		   "total number of JR's seen",		   &pred->jr_seen, 0, NULL);  sprintf(buf, "%s.jr_non_ras_hits.PP", name);  stat_reg_counter(sdb, buf,		   "total number of address-predicted hits for non-RAS JR's",		   &pred->jr_non_ras_hits, 0, NULL);  sprintf(buf, "%s.jr_non_ras_seen.PP", name);  stat_reg_counter(sdb, buf,		   "total number of non-RAS JR's seen",		   &pred->jr_non_ras_seen, 0, NULL);  sprintf(buf, "%s.bpred_addr_rate", name);  sprintf(buf1, "%s.addr_hits / %s.updates", name, name);  stat_reg_formula(sdb, buf,		   "branch address-prediction rate (i.e., addr-hits/updates)",		   buf1, "%9.4f");  sprintf(buf, "%s.bpred_dir_rate", name);  sprintf(buf1, "%s.dir_hits / %s.updates", name, name);  stat_reg_formula(sdb, buf,		  "branch direction-prediction rate (i.e., all-hits/updates)",		  buf1, "%9.4f");  sprintf(buf, "%s.bpred_jr_rate", name);  sprintf(buf1, "%s.jr_hits / %s.jr_seen", name, name);  stat_reg_formula(sdb, buf,		  "JR address-prediction rate (i.e., JR addr-hits/JRs seen)",		  buf1, "%9.4f");  sprintf(buf, "%s.bpred_jr_non_ras_rate.PP", name);  sprintf(buf1, "%s.jr_non_ras_hits.PP / %s.jr_non_ras_seen.PP", name, name);  stat_reg_formula(sdb, buf,		   "non-RAS JR addr-pred rate (ie, non-RAS JR hits/JRs seen)",		   buf1, "%9.4f");  sprintf(buf, "%s.retstack_pushes", name);  stat_reg_counter(sdb, buf,		   "total number of address pushed onto ret-addr stack",		   &pred->retstack_pushes, 0, NULL);  sprintf(buf, "%s.retstack_pops", name);  stat_reg_counter(sdb, buf,		   "total number of address popped off of ret-addr stack",		   &pred->retstack_pops, 0, NULL);  sprintf(buf, "%s.used_ras.PP", name);  stat_reg_counter(sdb, buf,		   "total number of RAS predictions used",		   &pred->used_ras, 0, NULL);  sprintf(buf, "%s.ras_hits.PP", name);  stat_reg_counter(sdb, buf,		   "total number of RAS hits",		   &pred->ras_hits, 0, NULL);  sprintf(buf, "%s.ras_rate.PP", name);  sprintf(buf1, "%s.ras_hits.PP / %s.used_ras.PP", name, name);  stat_reg_formula(sdb, buf,		   "RAS prediction rate (i.e., RAS hits/used RAS)",		   buf1, "%9.4f");}voidbpred_after_priming(struct bpred_t *bpred){  if (bpred == NULL)    return;  bpred->lookups = 0;  bpred->addr_hits = 0;  bpred->dir_hits = 0;  bpred->used_ras = 0;  bpred->used_bimod = 0;  bpred->used_2lev = 0;  bpred->jr_hits = 0;  bpred->jr_seen = 0;  bpred->misses = 0;  bpred->retstack_pops = 0;  bpred->retstack_pushes = 0;  bpred->ras_hits = 0;}#define BIMOD_HASH(PRED, ADDR)						\  ((((ADDR) >> 19) ^ ((ADDR) >> MD_BR_SHIFT)) & ((PRED)->config.bimod.size-1))    /* was: ((baddr >> 16) ^ baddr) & (pred->dirpred.bimod.size-1) *//* predicts a branch direction */char *						/* pointer to counter */bpred_dir_lookup(struct bpred_dir_t *pred_dir,	/* branch dir predictor inst */		 md_addr_t baddr)		/* branch address */

⌨️ 快捷键说明

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