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 + -
显示快捷键?