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

📄 sim-outorder.c

📁 一个很有名的硬件模拟器。可以模拟CPU
💻 C
📖 第 1 页 / 共 5 页
字号:
 *   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;  LSQ_count = 0;  LSQ_fcount = 0;}/* dump the contents of the RUU */static voidlsq_dump(FILE *stream)				/* output stream */{  int num, head;  struct RUU_station *rs;  if (!stream)    stream = stderr;  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 {    tick_t 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;/* create and initialize 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)/* 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;  if (!stream)    stream = stderr;  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",		  (int)(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, tick_t 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;  if (!stream)    stream = stderr;  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 || MD_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

⌨️ 快捷键说明

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