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

📄 dram_main.c

📁 ml-rsim 多处理器模拟器 支持类bsd操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
   * Find the earliest time to start the access.   */  if (hit_row)    {      bus_busy = prdbus->busy_until - dparam.dtime.r.PACKET;       bank_start = MAX(pchip->cas_busy, starttime);    }  else    {      cas_busy = pchip->cas_busy - dparam.dtime.r.RCD;      bus_busy = prdbus->busy_until - 	(dparam.dtime.r.RCD + dparam.dtime.r.PACKET);      bank_start = MAX(MAX(pchip->ras_busy, cas_busy), starttime);    }    if (dtrans->is_write)    bus_busy -= dparam.dtime.r.CWD;  else    bus_busy -= dparam.dtime.r.CAC;  start_time = MAX(bank_start, bus_busy);  /*   * Collect statistics.   */  if (dparam.collect_stats)    {      prdbus->count++;      prdbus->cycles += dparam.dtime.r.PACKET * cas_count;      wcycles = bus_busy - bank_start;      if (start_time == bus_busy && wcycles > 0)	{	  prdbus->waits++;	  prdbus->wcycles += wcycles;	  prdbus->cycles  += wcycles;	}            if (hit_row)	{	  if (dtrans->is_write)	    pbank->stats.write_hits++;	  else  	    pbank->stats.read_hits++;	}      else if (pbank->expire > starttime)	{	  if (dtrans->is_write)	    pbank->stats.write_misses++;	  else  	    pbank->stats.read_misses++;	}      pbank->stats.queue_cycles += start_time - dtrans->time;      dtrans->time = start_time;      if (start_time < prdbus->busy_until)	pbank->stats.overlap += prdbus->busy_until - start_time;    }  /*   * Update the states of RAS/CAS/DATA busses.   *    */  if (hit_row)    {      pchip->cas_busy    = start_time + dparam.dtime.r.PACKET * cas_count;      prdbus->busy_until = pchip->cas_busy + dparam.dtime.r.PACKET;    }  else    {      pchip->ras_busy    = start_time + dparam.dtime.r.PACKET;      pchip->cas_busy    = start_time + dparam.dtime.r.RCD +	dparam.dtime.r.PACKET * cas_count;      prdbus->busy_until = pchip->cas_busy + dparam.dtime.r.PACKET;    }    if (dtrans->is_write)    prdbus->busy_until += dparam.dtime.r.CWD;  else    prdbus->busy_until += dparam.dtime.r.CAC;  /*      * Use RDA/WRA/RD-PRES command to avoid PRE command. (Figure 20)   * So the timing for closing the hot row and leaving it open   * is the same. Just record the hot row state.   */  pbank->hot_row = row_num;  if (dtrans->open_row)    {      pbank->expire  = starttime + dparam.row_hold_time;    }  else    {      pbank->expire  = 0;    }  pchip->last_bank = pbank->id;  pchip->last_type = dtrans->is_write;  /*   * Schedule the event to call DRAM_bank_done when the access is done.   */  pbank->busy = dtrans;  schedule_event(pevent, prdbus->busy_until);}/* * Called when a dram access is done. */void DRAM_bank_done(void){  dram_info_t    *pdb      = YS__ActEvnt->uptr1;  dram_bank_t    *pbank    = YS__ActEvnt->uptr2;  dram_databuf_t *pdatabuf = YS__ActEvnt->uptr3;  dram_trans_t   *dtrans   = pbank->busy;  if (dparam.collect_stats)    {      pbank->stats.readwrites++;      pbank->stats.access_cycles += YS__Simtime - dtrans->time;      dtrans->time = YS__Simtime;    }  /*   * The next step is going throught data buffer (Accumulate/Mux chip).   * - If the buffer is busy, wait.   * - otherwise, send the data back to MMC if the access is a read   *   and terminate this transaction if the access is a write.   */  if (pdatabuf->busy)    {      if (cbuf_full(pdatabuf->waiters))	YS__errmsg(pdb->nodeid, "pdatabuf->waiters are full\n");      cbuf_enqueue(pdatabuf->waiters, dtrans);    }  else    {      DRAM_sd_bus_schedule(pdb, pdatabuf, dtrans, 0);    }    /*   * Find out the next action should be taken on this bank.   *  1. Refreshing always has the highest priority.   *  2. If the waiting queue is not empty, grant the bank to the first   *     transaction in the waiting queue.   *  3. Otherwise, keep the bank idle.   */  if (pbank->chip->refresh_needed)    {      DRAM_refresh();    }  else if (pbank->waiters.size > 0)    {      dram_trans_t *dtrans = Bank_queue_dequeue(pbank);      pdb->total_bwaiters--;            DRAM_access_bank(pdb, dtrans, MAX(dtrans->time, pbank->chip->ras_busy));    }  else    {      pbank->busy = 0;    }}void DRAM_sd_bus_schedule(dram_info_t *pdb, dram_databuf_t *pdatabuf, 			  dram_trans_t *dtrans, int waited){  double         data_ready;  if (dparam.collect_stats && YS__Simtime > dtrans->time)    {      pdb->sd_bus.waits++;      pdb->sd_bus.wcycles += YS__Simtime - dtrans->time;    }    /*    * The time on SD bus is decided by the size of the access.   */  if (pdb->sd_bus.busy_until < YS__Simtime)    pdb->sd_bus.busy_until = YS__Simtime;    data_ready = pdb->sd_bus.busy_until + dparam.sd_bus_cycles;   if (dtrans->size <= dparam.sd_bus_width)    pdb->sd_bus.busy_until += dparam.sd_bus_cycles;  else    pdb->sd_bus.busy_until += dparam.sd_bus_cycles *       (dtrans->size >> dparam.sd_bus_shift);  /*    * Call DRAM_databuf_done when the transfer on the SD bus is done.   */  pdatabuf->busy = dtrans;  pdatabuf->cevent->uptr3 = &(pdb->sd_bus);  pdatabuf->devent->uptr3 = &(pdb->sd_bus);  if (dparam.critical_word)    {      schedule_event(pdatabuf->devent, data_ready);    }  else    {      schedule_event(pdatabuf->devent, pdb->sd_bus.busy_until);    }  schedule_event(pdatabuf->cevent, pdb->sd_bus.busy_until);}void DRAM_databuf_data_ready(void){  dram_info_t    *pdb      = YS__ActEvnt->uptr1;  dram_databuf_t *pdatabuf = YS__ActEvnt->uptr2;  dram_trans_t   *dtrans   = pdatabuf->busy;  /*   * Inform the MMC that the dram access is done.   */  MMC_dram_data_ready(pdb->nodeid, dtrans->ptrans);}/* * Called when a transaction comes off the SD bus, i.e data has been sent  * back to MMC. */void DRAM_databuf_done(void){  dram_info_t    *pdb      = YS__ActEvnt->uptr1;  dram_databuf_t *pdatabuf = YS__ActEvnt->uptr2;  dram_sd_bus_t  *psdbus   = YS__ActEvnt->uptr3;  dram_trans_t   *dtrans   = pdatabuf->busy;  /*    * At this point, a DRAM transaction is considered to be done.   */  DRAM_end_transaction(pdb, dtrans);  if (dparam.collect_stats)    {      psdbus->count++;      psdbus->cycles += YS__Simtime - dtrans->time;      dtrans->time    = YS__Simtime;    }  /*   * If any DRAM transactions are contenting for this SD bus,    * pick up the the head of the waiting queue as the next winner.   */  if (cbuf_empty(pdatabuf->waiters))    pdatabuf->busy = 0;  else    {      dram_trans_t *ndtrans = (dram_trans_t *)cbuf_dequeue(pdatabuf->waiters);      DRAM_sd_bus_schedule(pdb, pdatabuf, ndtrans, 1);    }  /*   * Inform the MMC that the dram access is done.   */  MMC_dram_done(pdb->nodeid, dtrans->ptrans);}/* * Insert a DRAM access into the bank waiting queue. */void Bank_queue_enqueue(bank_queue_t *bq, dram_trans_t *dtrans){  bank_queue_elm_t *qelm, *cur, *next;  if (bq->size == bq->max)    YS__errmsg(0, "The waiting queue on bank is full\n");  qelm       = bq->free;  bq->free   = qelm->next;  qelm->data = (void *) dtrans;  if (bq->size++ == 0)    {      /*        * The waiting queue is empty        */      qelm->prev = qelm->next = qelm;      bq->head   = bq->tail   = qelm;    }  else    {      /*        * Insert the transaction at the tail.        */      qelm->prev     = bq->tail;        bq->tail->next = qelm;                                                     qelm->next     = bq->head;      bq->head->prev = qelm;      bq->tail       = qelm;    }}#define DRAM_STATUS_BITS 5/* * Dequeue the head of the bank waiting queue. Also, find out * if the hot row should remain open after this access. */dram_trans_t * Bank_queue_dequeue(dram_bank_t *pbank){  bank_queue_t     *bq = &(pbank->waiters);  bank_queue_elm_t *qelm;  dram_trans_t     *dtrans;  if (bq->size == 0)    YS__errmsg(0, "The waiting queue is empty\n");  /*   * Dequeue the head of the waiting queue.   */  if (--bq->size == 0)    {      qelm     = bq->head;      bq->head = bq->tail = 0;    }  else    {      qelm = bq->head;      bq->head = bq->head->next;      bq->head->prev = bq->tail;      bq->tail->next = bq->head;    }    dtrans     = qelm->data;  qelm->next = bq->free;  bq->free   = qelm;  /*   * Check the hot row hit/miss history to decide whether or not to leave   * the hot row open after the access is done.   * - hot_row_policy == 0, always close the hot row (precharge it);   * - hot_row_policy == 1, always leave the hot row open;   * - hot_row_policy == 2, use predictors. Please see technical report   *   UU-CS-XXXX for details on the predicting-policy.   *   * If the next transaction will access the same row, leave the hot row   *     open after this access and lock the next one in the head.   *   * Otherwise, use the selected hot-row algorithm.   */  switch (dparam.hot_row_policy)    {    case 0:      dtrans->open_row = 0;      break;    case 1:      dtrans->open_row = 1;      break;    case 2:      if (bq->size && 	  DRAM_in_same_row(dtrans->paddr, bq->head->data->paddr))	{	  dtrans->open_row = 1;	  bq->head->data->locked = 1;	}      else	{	  int   i, count, history;	  history = pbank->hitmiss;	  for (i = count = 0; i < DRAM_STATUS_BITS; i++)	    {	      if (history & 1)		count++;	      history >>= 1;	    }	  dtrans->open_row = (count > (DRAM_STATUS_BITS >> 1));	}      break;    default:      YS__errmsg(0, "Wrong hot_row_policy\n");    }  return dtrans;}/* * Create a new DRAM transaction. */dram_trans_t * DRAM_new_transaction(dram_info_t *pdb, mmc_trans_t *ptrans,				    unsigned paddr, int size, int is_write){  dram_trans_t *dtrans;  if (size < dparam.mini_access)    size = dparam.mini_access;  if (pdb->freedramlist.size == 0)    YS__errmsg(pdb->nodeid, "No free dram transaction available.\n");  lqueue_get(&pdb->freedramlist, dtrans);  dtrans->ptrans      = ptrans;  dtrans->time        = YS__Simtime;  dtrans->etime       = YS__Simtime;  dtrans->paddr       = paddr;  dtrans->size        = size;  dtrans->locked      = 0;  dtrans->is_write    = is_write;  return dtrans;}/* * A DRAM transaction is done. Put it back to the free list. */void DRAM_end_transaction(dram_info_t *pdb, dram_trans_t *dtrans){  if (dparam.collect_stats)    {      pdb->total_count  += 1;      pdb->total_cycles += YS__Simtime - dtrans->etime;      pdb->sgle_count  += 1;      pdb->sgle_cycles += YS__Simtime - dtrans->etime;    }    lqueue_add(&pdb->freedramlist, dtrans, pdb->nodeid);}/* * Used when the DRAM backend simulator is turned off. When the DRAM  * backend simulator is not used, each DRAM access takes a fixed latency * (specified by dparam.latency in terms of dparam.frequency cycles). */void DRAM_nosim_start(dram_info_t *pdb, dram_trans_t *dtrans){  if (IsNotScheduled(pdb->pevent))    {      pdb->pevent->uptr2 = dtrans;      schedule_event(pdb->pevent,		     YS__Simtime + (dparam.latency * dparam.frequency));    }  else    {      lqueue_add(&(pdb->waitlist), dtrans, pdb->nodeid);    }}/* * Activated by pdb->pevent when a DRAM access has been delayed for the * fixed latency. Used when the DRAM backend simulator is turned off. */void  DRAM_nosim_done(void){  dram_info_t  *pdb    = YS__ActEvnt->uptr1;  dram_trans_t *dtrans = YS__ActEvnt->uptr2;  /*    * At this point, a DRAM transaction is considered to be done.   */  DRAM_end_transaction(pdb, dtrans);  /*   * Handle the next access, if any.   */  if (pdb->waitlist.size > 0)    {      dram_trans_t *new_dtrans;      lqueue_get(&(pdb->waitlist), new_dtrans);      pdb->pevent->uptr2 = new_dtrans;      schedule_event(pdb->pevent,		     YS__Simtime + (dparam.latency * dparam.frequency));    }  /*   * Inform the MMC that the dram access is done.   */  MMC_dram_done(pdb->nodeid, dtrans->ptrans);}

⌨️ 快捷键说明

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