📄 dram_main.c
字号:
* 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 + -