📄 sim-outorder.c
字号:
/* register cache stats */ if (cache_il1 && (cache_il1 != cache_dl1 && cache_il1 != cache_dl2)) cache_reg_stats(cache_il1, sdb); if (cache_il2 && (cache_il2 != cache_dl1 && cache_il2 != cache_dl2)) cache_reg_stats(cache_il2, sdb); if (cache_dl1) cache_reg_stats(cache_dl1, sdb); if (cache_dl2) cache_reg_stats(cache_dl2, sdb); if (itlb) cache_reg_stats(itlb, sdb); if (dtlb) cache_reg_stats(dtlb, sdb); for (i=0; i<pcstat_nelt; i++) { char buf[512], buf1[512]; struct stat_stat_t *stat; /* track the named statistical variable by text address */ /* find it... */ stat = stat_find_stat(sdb, pcstat_vars[i]); if (!stat) fatal("cannot locate any statistic named `%s'", pcstat_vars[i]); /* stat must be an integral type */ if (stat->sc != sc_int && stat->sc != sc_uint && stat->sc != sc_counter) fatal("`-pcstat' statistical variable `%s' is not an integral type", stat->name); /* register this stat */ pcstat_stats[i] = stat; pcstat_lastvals[i] = STATVAL(stat); /* declare the sparce text distribution */ sprintf(buf, "%s_by_pc", stat->name); sprintf(buf1, "%s (by text address)", stat->desc); pcstat_sdists[i] = stat_reg_sdist(sdb, buf, buf1, /* initial value */0, /* print format */(PF_COUNT|PF_PDF), /* format */"0x%lx %lu %.2f", /* print fn */NULL); }}/* forward declarations */static void ruu_init(void);static void lsq_init(void);static void rslink_init(int nlinks);static void eventq_init(void);static void readyq_init(void);static void cv_init(void);static void tracer_init(void);static void fetch_init(void);/* default register state accessor, used by DLite */static char * /* err str, NULL for no err */simoo_reg_obj(enum dlite_access_t at, /* access type */ enum dlite_reg_t rt, /* reg bank to probe */ int reg, /* register number */ union dlite_reg_val_t *val); /* input, output *//* default memory state accessor, used by DLite */static char * /* err str, NULL for no err */simoo_mem_obj(enum dlite_access_t at, /* access type */ SS_ADDR_TYPE addr, /* address to access */ char *p, /* input/output buffer */ int nbytes); /* size of access *//* default machine state accessor, used by DLite */static char * /* err str, NULL for no err */simoo_mstate_obj(FILE *stream, /* output stream */ char *cmd); /* optional command string *//* total RS links allocated at program start */#define MAX_RS_LINKS 4096/* initialize the simulator */voidsim_init(void){ sim_num_insn = 0; sim_num_refs = 0; /* initialize here, so symbols can be loaded */ if (ptrace_nelt == 2) { /* generate a pipeline trace */ ptrace_open(/* fname */ptrace_opts[0], /* range */ptrace_opts[1]); } else if (ptrace_nelt == 0) { /* no pipetracing */; } else fatal("bad pipetrace args, use: <fname|stdout|stderr> <range>"); /* decode all instructions */ { SS_ADDR_TYPE addr; SS_INST_TYPE inst; if (OP_MAX > 255) fatal("cannot do fast decoding, too many opcodes"); debug("sim: decoding text segment..."); for (addr=ld_text_base; addr < (ld_text_base+ld_text_size); addr += SS_INST_SIZE) { inst = __UNCHK_MEM_ACCESS(SS_INST_TYPE, addr); inst.a = (inst.a & ~0xff) | (unsigned int)SS_OP_ENUM(SS_OPCODE(inst)); __UNCHK_MEM_ACCESS(SS_INST_TYPE, addr) = inst; } } /* initialize the simulation engine */ fu_pool = res_create_pool("fu-pool", fu_config, N_ELT(fu_config)); rslink_init(MAX_RS_LINKS); tracer_init(); fetch_init(); cv_init(); eventq_init(); readyq_init(); ruu_init(); lsq_init(); /* initialize the DLite debugger */ dlite_init(simoo_reg_obj, simoo_mem_obj, simoo_mstate_obj);}/* dump simulator-specific auxiliary simulator statistics */voidsim_aux_stats(FILE *stream) /* output stream */{ /* nada */}/* un-initialize the simulator */voidsim_uninit(void){ if (ptrace_nelt > 0) ptrace_close();}/* * processor core definitions and declarations *//* inst tag type, used to tag an operation instance in the RUU */typedef unsigned int INST_TAG_TYPE;/* inst sequence type, used to order instructions in the ready list, if this rolls over the ready list order temporarily will get messed up, but execution will continue and complete correctly */typedef unsigned int INST_SEQ_TYPE;/* total input dependencies possible */#define MAX_IDEPS 3/* total output dependencies possible */#define MAX_ODEPS 2/* a register update unit (RUU) station, this record is contained in the processors RUU, which serves as a collection of ordered reservations stations. The reservation stations capture register results and await the time when all operands are ready, at which time the instruction is issued to the functional units; the RUU is an order circular queue, in which instructions are inserted in fetch (program) order, results are stored in the RUU buffers, and later when an RUU entry is the oldest entry in the machines, it and its instruction's value is retired to the architectural register file in program order, NOTE: the RUU and LSQ share the same structure, this is useful because loads and stores are split into two operations: an effective address add and a load/store, the add is inserted into the RUU and the load/store inserted into the LSQ, allowing the add to wake up the load/store when effective address computation has finished */struct RUU_station { /* inst info */ SS_INST_TYPE IR; /* instruction bits */ enum ss_opcode op; /* decoded instruction opcode */ SS_ADDR_TYPE PC, next_PC, pred_PC; /* inst PC, next PC, predicted PC */ int in_LSQ; /* non-zero if op is in LSQ */ int ea_comp; /* non-zero if op is an addr comp */ int recover_inst; /* start of mis-speculation? */ int stack_recover_idx; /* non-speculative TOS for RSB pred */ struct bpred_update dir_update; /* bpred direction update info */ int spec_mode; /* non-zero if issued in spec_mode */ SS_ADDR_TYPE addr; /* effective address for ld/st's */ INST_TAG_TYPE tag; /* RUU slot tag, increment to squash operation */ INST_SEQ_TYPE seq; /* instruction sequence, used to sort the ready list and tag inst */ unsigned int ptrace_seq; /* pipetrace sequence number */ /* instruction status */ int queued; /* operands ready and queued */ int issued; /* operation is/was executing */ int completed; /* operation has completed execution */ /* output operand dependency list, these lists are used to limit the number of associative searches into the RUU when instructions complete and need to wake up dependent insts */ int onames[MAX_ODEPS]; /* output logical names (NA=unused) */ struct RS_link *odep_list[MAX_ODEPS]; /* chains to consuming operations */ /* input dependent links, the output chains rooted above use these fields to mark input operands as ready, when all these fields have been set non-zero, the RUU operation has all of its register operands, it may commence execution as soon as all of its memory operands are known to be read (see lsq_refresh() for details on enforcing memory dependencies) */ int idep_ready[MAX_IDEPS]; /* input operand ready? */};/* non-zero if all register operands are ready, update with MAX_IDEPS */#define OPERANDS_READY(RS) \ ((RS)->idep_ready[0] && (RS)->idep_ready[1] && (RS)->idep_ready[2])/* register update unit, combination of reservation stations and reorder buffer device, organized as a circular queue */static struct RUU_station *RUU; /* register update unit */static int RUU_head, RUU_tail; /* RUU head and tail pointers */static int RUU_num; /* num entries currently in RUU *//* allocate and initialize register update unit (RUU) */static voidruu_init(void){ RUU = calloc(RUU_size, sizeof(struct RUU_station)); if (!RUU) fatal("out of virtual memory"); RUU_num = 0; RUU_head = RUU_tail = 0;}/* dump the contents of the RUU */static voidruu_dumpent(struct RUU_station *rs, /* ptr to RUU station */ int index, /* entry index */ FILE *stream, /* output stream */ int header) /* print header? */{ if (header) fprintf(stream, "idx: %2d: opcode: %s, inst: `", index, SS_OP_NAME(rs->op)); else fprintf(stream, " opcode: %s, inst: `", SS_OP_NAME(rs->op)); ss_print_insn(rs->IR, rs->PC, stream); fprintf(stream, "'\n"); fprintf(stream, " PC: 0x%08x, NPC: 0x%08x (pred_PC: 0x%08x)\n", rs->PC, rs->next_PC, rs->pred_PC); fprintf(stream, " in_LSQ: %s, ea_comp: %s, recover_inst: %s\n", rs->in_LSQ ? "t" : "f", rs->ea_comp ? "t" : "f", rs->recover_inst ? "t" : "f"); fprintf(stream, " spec_mode: %s, addr: 0x%08x, tag: 0x%08x\n", rs->spec_mode ? "t" : "f", rs->addr, rs->tag); fprintf(stream, " seq: 0x%08x, ptrace_seq: 0x%08x\n", rs->seq, rs->ptrace_seq); fprintf(stream, " queued: %s, issued: %s, completed: %s\n", rs->queued ? "t" : "f", rs->issued ? "t" : "f", rs->completed ? "t" : "f"); fprintf(stream, " operands ready: %s\n", OPERANDS_READY(rs) ? "t" : "f");}/* dump the contents of the RUU */static voidruu_dump(FILE *stream) /* output stream */{ int num, head; struct RUU_station *rs; fprintf(stream, "** RUU state **\n"); fprintf(stream, "RUU_head: %d, RUU_tail: %d\n", RUU_head, RUU_tail); fprintf(stream, "RUU_num: %d\n", RUU_num); num = RUU_num; head = RUU_head; while (num) { rs = &RUU[head]; ruu_dumpent(rs, rs - RUU, stream, /* header */TRUE); head = (head + 1) % RUU_size; num--; }}/* * load/store queue (LSQ): holds loads and stores in program order, indicating * status of load/store access: * * - issued: address computation complete, memory access in progress * - completed: memory access has completed, stored value available * - squashed: memory access was squashed, ignore this entry * * loads may execute when: * 1) register operands are ready, and * 2) memory operands are ready (no earlier unresolved store) * * loads are serviced by: * 1) previous store at same address in LSQ (hit latency), or * 2) data cache (hit latency + miss latency) * * stores may execute when: * 1) register operands are ready * * stores are serviced by: * 1) depositing store value into the load/store queue * 2) writing store value to the store buffer (plus tag check) at commit * 3) writing store buffer entry to data cache when cache is free * * NOTE: the load/store queue can bypass a store value to a load in the same * cycle the store executes (using a bypass network), thus stores complete * in effective zero time after their effective address is known */static struct RUU_station *LSQ; /* load/store queue */static int LSQ_head, LSQ_tail; /* LSQ head and tail pointers */static int LSQ_num; /* num entries currently in LSQ *//* * input dependencies for stores in the LSQ: * idep #0 - operand input (value that is store'd) * idep #1 - effective address input (address of store operation) */#define STORE_OP_INDEX 0#define STORE_ADDR_INDEX 1#define STORE_OP_READY(RS) ((RS)->idep_ready[STORE_OP_INDEX])#define STORE_ADDR_READY(RS) ((RS)->idep_ready[STORE_ADDR_INDEX])/* allocate and initialize the load/store queue (LSQ) */static voidlsq_init(void){ LSQ = calloc(LSQ_size, sizeof(struct RUU_station)); if (!LSQ) fatal("out of virtual memory"); LSQ_num = 0; LSQ_head = LSQ_tail = 0;}/* dump the contents of the RUU */static voidlsq_dump(FILE *stream) /* output stream */{ int num, head; struct RUU_station *rs; fprintf(stream, "** LSQ state **\n"); fprintf(stream, "LSQ_head: %d, LSQ_tail: %d\n", LSQ_head, LSQ_tail); fprintf(stream, "LSQ_num: %d\n", LSQ_num); num = LSQ_num; head = LSQ_head; while (num) { rs = &LSQ[head]; ruu_dumpent(rs, rs - LSQ, stream, /* header */TRUE); head = (head + 1) % LSQ_size; num--; }}/* * RS_LINK defs and decls *//* a reservation station link: this structure links elements of a RUU reservation station list; used for ready instruction queue, event queue, and output dependency lists; each RS_LINK node contains a pointer to the RUU entry it references along with an instance tag, the RS_LINK is only valid if the instruction instance tag matches the instruction RUU entry instance tag; this strategy allows entries in the RUU can be squashed and reused without updating the lists that point to it, which significantly improves the performance of (all to frequent) squash events */struct RS_link { struct RS_link *next; /* next entry in list */ struct RUU_station *rs; /* referenced RUU resv station */ INST_TAG_TYPE tag; /* inst instance sequence number */ union { SS_TIME_TYPE when; /* time stamp of entry (for eventq) */ INST_SEQ_TYPE seq; /* inst sequence */ int opnum; /* input/output operand number */ } x;};/* RS link free list, grab RS_LINKs from here, when needed */static struct RS_link *rslink_free_list;/* NULL value for an RS link */#define RSLINK_NULL_DATA { NULL, NULL, 0 }static struct RS_link RSLINK_NULL = RSLINK_NULL_DATA;/* NULL value for an RS link */#define RSLINK_INIT(RSL, RS) \ ((RSL).next = NULL, (RSL).rs = (RS), (RSL).tag = (RS)->tag)/* non-zero if RS link is NULL */#define RSLINK_IS_NULL(LINK) ((LINK)->rs == NULL)/* non-zero if RS link is to a valid (non-squashed) entry */#define RSLINK_VALID(LINK) ((LINK)->tag == (LINK)->rs->tag)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -