📄 sim-outorder.c
字号:
/* extra RUU reservation station pointer */#define RSLINK_RS(LINK) ((LINK)->rs)/* get a new RS link record */#define RSLINK_NEW(DST, RS) \ { struct RS_link *n_link; \ if (!rslink_free_list) \ panic("out of rs links"); \ n_link = rslink_free_list; \ rslink_free_list = rslink_free_list->next; \ n_link->next = NULL; \ n_link->rs = (RS); n_link->tag = n_link->rs->tag; \ (DST) = n_link; \ }/* free an RS link record */#define RSLINK_FREE(LINK) \ { struct RS_link *f_link = (LINK); \ f_link->rs = NULL; f_link->tag = 0; \ f_link->next = rslink_free_list; \ rslink_free_list = f_link; \ }/* FIXME: could this be faster!!! *//* free an RS link list */#define RSLINK_FREE_LIST(LINK) \ { struct RS_link *fl_link, *fl_link_next; \ for (fl_link=(LINK); fl_link; fl_link=fl_link_next) \ { \ fl_link_next = fl_link->next; \ RSLINK_FREE(fl_link); \ } \ }/* initialize the free RS_LINK pool */static voidrslink_init(int nlinks) /* total number of RS_LINK available */{ int i; struct RS_link *link; rslink_free_list = NULL; for (i=0; i<nlinks; i++) { link = calloc(1, sizeof(struct RS_link)); if (!link) fatal("out of virtual memory"); link->next = rslink_free_list; rslink_free_list = link; }}/* service all functional unit release events, this function is called once per cycle, and it used to step the BUSY timers attached to each functional unit in the function unit resource pool, as long as a functional unit's BUSY count is > 0, it cannot be issued an operation */static voidruu_release_fu(void){ int i; /* walk all resource units, decrement busy counts by one */ for (i=0; i<fu_pool->num_resources; i++) { /* resource is released when BUSY hits zero */ if (fu_pool->resources[i].busy > 0) fu_pool->resources[i].busy--; }}/* * the execution unit event queue implementation follows, the event queue * indicates which instruction will complete next, the writeback handler * drains this queue *//* pending event queue, sorted from soonest to latest event (in time), NOTE: RS_LINK nodes are used for the event queue list so that it need not be updated during squash events */static struct RS_link *event_queue;/* initialize the event queue structures */static voideventq_init(void){ event_queue = NULL;}/* dump the contents of the event queue */static voideventq_dump(FILE *stream) /* output stream */{ struct RS_link *ev; fprintf(stream, "** event queue state **\n"); for (ev = event_queue; ev != NULL; ev = ev->next) { /* is event still valid? */ if (RSLINK_VALID(ev)) { struct RUU_station *rs = RSLINK_RS(ev); fprintf(stream, "idx: %2d: @ %.0f\n", rs - (rs->in_LSQ ? LSQ : RUU), (double)ev->x.when); ruu_dumpent(rs, rs - (rs->in_LSQ ? LSQ : RUU), stream, /* !header */FALSE); } }}/* insert an event for RS into the event queue, event queue is sorted from earliest to latest event, event and associated side-effects will be apparent at the start of cycle WHEN */static voideventq_queue_event(struct RUU_station *rs, SS_TIME_TYPE when){ struct RS_link *prev, *ev, *new_ev; if (rs->completed) panic("event completed"); if (when <= sim_cycle) panic("event occurred in the past"); /* get a free event record */ RSLINK_NEW(new_ev, rs); new_ev->x.when = when; /* locate insertion point */ for (prev=NULL, ev=event_queue; ev && ev->x.when < when; prev=ev, ev=ev->next); if (prev) { /* insert middle or end */ new_ev->next = prev->next; prev->next = new_ev; } else { /* insert at beginning */ new_ev->next = event_queue; event_queue = new_ev; }}/* return the next event that has already occurred, returns NULL when no remaining events or all remaining events are in the future */static struct RUU_station *eventq_next_event(void){ struct RS_link *ev; if (event_queue && event_queue->x.when <= sim_cycle) { /* unlink and return first event on priority list */ ev = event_queue; event_queue = event_queue->next; /* event still valid? */ if (RSLINK_VALID(ev)) { struct RUU_station *rs = RSLINK_RS(ev); /* reclaim event record */ RSLINK_FREE(ev); /* event is valid, return resv station */ return rs; } else { /* reclaim event record */ RSLINK_FREE(ev); /* receiving inst was squashed, return next event */ return eventq_next_event(); } } else { /* no event or no event is ready */ return NULL; }}/* * the ready instruction queue implementation follows, the ready instruction * queue indicates which instruction have all of there *register* dependencies * satisfied, instruction will issue when 1) all memory dependencies for * the instruction have been satisfied (see lsq_refresh() for details on how * this is accomplished) and 2) resources are available; ready queue is fully * constructed each cycle before any operation is issued from it -- this * ensures that instruction issue priorities are properly observed; NOTE: * RS_LINK nodes are used for the event queue list so that it need not be * updated during squash events *//* the ready instruction queue */static struct RS_link *ready_queue;/* initialize the event queue structures */static voidreadyq_init(void){ ready_queue = NULL;}/* dump the contents of the ready queue */static voidreadyq_dump(FILE *stream) /* output stream */{ struct RS_link *link; fprintf(stream, "** ready queue state **\n"); for (link = ready_queue; link != NULL; link = link->next) { /* is entry still valid? */ if (RSLINK_VALID(link)) { struct RUU_station *rs = RSLINK_RS(link); ruu_dumpent(rs, rs - (rs->in_LSQ ? LSQ : RUU), stream, /* header */TRUE); } }}/* insert ready node into the ready list using ready instruction scheduling policy; currently the following scheduling policy is enforced: memory and long latency operands, and branch instructions first then all other instructions, oldest instructions first this policy works well because branches pass through the machine quicker which works to reduce branch misprediction latencies, and very long latency instructions (such loads and multiplies) get priority since they are very likely on the program's critical path */static voidreadyq_enqueue(struct RUU_station *rs) /* RS to enqueue */{ struct RS_link *prev, *node, *new_node; /* node is now queued */ if (rs->queued) panic("node is already queued"); rs->queued = TRUE; /* get a free ready list node */ RSLINK_NEW(new_node, rs); new_node->x.seq = rs->seq; /* locate insertion point */ if (rs->in_LSQ || SS_OP_FLAGS(rs->op) & (F_LONGLAT|F_CTRL)) { /* insert loads/stores and long latency ops at the head of the queue */ prev = NULL; node = ready_queue; } else { /* otherwise insert in program order (earliest seq first) */ for (prev=NULL, node=ready_queue; node && node->x.seq < rs->seq; prev=node, node=node->next); } if (prev) { /* insert middle or end */ new_node->next = prev->next; prev->next = new_node; } else { /* insert at beginning */ new_node->next = ready_queue; ready_queue = new_node; }}/* * the create vector maps a logical register to a creator in the RUU (and * specific output operand) or the architected register file (if RS_link * is NULL) *//* an entry in the create vector */struct CV_link { struct RUU_station *rs; /* creator's reservation station */ int odep_num; /* specific output operand */};/* a NULL create vector entry */static struct CV_link CVLINK_NULL = { NULL, 0 };/* get a new create vector link */#define CVLINK_INIT(CV, RS,ONUM) ((CV).rs = (RS), (CV).odep_num = (ONUM))/* size of the create vector (one entry per architected register) */#define CV_BMAP_SZ (BITMAP_SIZE(SS_TOTAL_REGS))/* the create vector, NOTE: speculative copy on write storage provided for fast recovery during wrong path execute (see tracer_recover() for details on this process */static BITMAP_TYPE(SS_TOTAL_REGS, use_spec_cv);static struct CV_link create_vector[SS_TOTAL_REGS];static struct CV_link spec_create_vector[SS_TOTAL_REGS];/* these arrays shadow the create vector an indicate when a register was last created */static SS_TIME_TYPE create_vector_rt[SS_TOTAL_REGS];static SS_TIME_TYPE spec_create_vector_rt[SS_TOTAL_REGS];/* read a create vector entry */#define CREATE_VECTOR(N) (BITMAP_SET_P(use_spec_cv, CV_BMAP_SZ, (N))\ ? spec_create_vector[N] \ : create_vector[N])/* read a create vector timestamp entry */#define CREATE_VECTOR_RT(N) (BITMAP_SET_P(use_spec_cv, CV_BMAP_SZ, (N))\ ? spec_create_vector_rt[N] \ : create_vector_rt[N])/* set a create vector entry */#define SET_CREATE_VECTOR(N, L) (spec_mode \ ? (BITMAP_SET(use_spec_cv, CV_BMAP_SZ, (N)),\ spec_create_vector[N] = (L)) \ : (create_vector[N] = (L)))/* initialize the create vector */static voidcv_init(void){ int i; /* initially all registers are valid in the architected register file, i.e., the create vector entry is CVLINK_NULL */ for (i=0; i<SS_TOTAL_REGS; i++) { create_vector[i] = CVLINK_NULL; create_vector_rt[i] = 0; spec_create_vector[i] = CVLINK_NULL; spec_create_vector_rt[i] = 0; } /* all create vector entries are non-speculative */ BITMAP_CLEAR_MAP(use_spec_cv, CV_BMAP_SZ);}/* dependency index names */static char *dep_names[SS_TOTAL_REGS] = { "n/a", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31", "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", "$hi", "$lo", "$fcc", "$tmp", "n/a", "n/a"};/* dump the contents of the create vector */static voidcv_dump(FILE *stream) /* output stream */{ int i; struct CV_link ent; fprintf(stream, "** create vector state **\n"); for (i=0; i<SS_TOTAL_REGS; i++) { ent = CREATE_VECTOR(i); if (!ent.rs) fprintf(stream, "[%4s]: from architected reg file\n", dep_names[i]); else fprintf(stream, "[%4s]: from %s, idx: %d\n", dep_names[i], (ent.rs->in_LSQ ? "LSQ" : "RUU"), ent.rs - (ent.rs->in_LSQ ? LSQ : RUU)); }}/* * RUU_COMMIT() - instruction retirement pipeline stage *//* this function commits the results of the oldest completed entries from the RUU and LSQ to the architected reg file, stores in the LSQ will commit their store data to the data cache at this point as well */static voidruu_commit(void){ int i, lat, events, committed = 0; /* all values must be retired to the architected reg file in program order */ while (RUU_num > 0 && committed < ruu_commit_width) { struct RUU_station *rs = &(RUU[RU
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -