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

📄 bus.c

📁 ml-rsim 多处理器模拟器 支持类bsd操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2002 The Board of Trustees of the University of Illinois and *                    William Marsh Rice University * Copyright (c) 2002 The University of Utah * Copyright (c) 2002 The University of Notre Dame du Lac * * All rights reserved. * * Based on RSIM 1.0, developed by: *   Professor Sarita Adve's RSIM research group *   University of Illinois at Urbana-Champaign and     William Marsh Rice University *   http://www.cs.uiuc.edu/rsim and http://www.ece.rice.edu/~rsim/dist.html * ML-RSIM/URSIM extensions by: *   The Impulse Research Group, University of Utah *   http://www.cs.utah.edu/impulse *   Lambert Schaelicke, University of Utah and University of Notre Dame du Lac *   http://www.cse.nd.edu/~lambert *   Mike Parker, University of Utah *   http://www.cs.utah.edu/~map * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal with the Software without restriction, including without * limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, subject to the following * conditions: * * 1. Redistributions of source code must retain the above copyright notice, *    this list of conditions and the following disclaimers.  * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimers in the *    documentation and/or other materials provided with the distribution. * 3. Neither the names of Professor Sarita Adve's RSIM research group, *    the University of Illinois at Urbana-Champaign, William Marsh Rice *    University, nor the names of its contributors may be used to endorse *    or promote products derived from this Software without specific prior *    written permission.  * 4. Neither the names of the ML-RSIM project, the URSIM project, the *    Impulse research group, the University of Utah, the University of *    Notre Dame du Lac, nor the names of its contributors may be used to *    endorse or promote products derived from this software without specific *    prior written permission.  * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS WITH THE SOFTWARE.  */#include <string.h>#include <malloc.h>#include "Processor/simio.h"#include "Processor/tlb.h"#include "sim_main/simsys.h"#include "Caches/system.h"#include "Caches/req.h"#include "Caches/cache.h"#include "IO/addr_map.h"#include "IO/io_generic.h"#include "Bus/bus.h"#include "Memory/mmc.h"BUS *AllBusses;int  BUS_WIDTH          = 8;int  BUS_FREQUENCY      = 1;int  BUS_TURNAROUND     = 1;int  BUS_ARBDELAY       = 1;int  BUS_MINDELAY       = 0;int  BUS_TOTAL_REQUESTS = 8;int  BUS_CPU_REQUESTS   = 4;int  BUS_IO_REQUESTS    = 4;int  BUS_TRACE_ENABLE   = 0;int  BUS_CRITICAL_WORD  = 1;int MEM_CNTL;int NUM_MODULES;const char *RName[] ={  "Request",  "Reply",  "Coherency",  "Coh Reply",  "Writeback",  "Writepurge",  "Barrier"};/*============================================================================= * Initialize bus module. */void Bus_init(void){  BUS *pbus;  int i, nid;  char name[PATH_MAX];  NUM_MODULES = ARCH_cpus + ARCH_ios;  /* does not include memory controller */  MEM_CNTL = ARCH_cpus + ARCH_ios;  /*   * Bus configuration.   * Default arbitration delay: two delay cycles + 1 dead cycle when    * mastership of the system interface changes.    */  get_parameter("BUS_width",          &BUS_WIDTH,          PARAM_INT);  get_parameter("BUS_arbdelay",       &BUS_ARBDELAY,       PARAM_INT);  get_parameter("BUS_frequency",      &BUS_FREQUENCY,      PARAM_INT);  get_parameter("BUS_total_requests", &BUS_TOTAL_REQUESTS, PARAM_INT);  get_parameter("BUS_turnaround",     &BUS_TURNAROUND,     PARAM_INT);  get_parameter("BUS_mindelay",       &BUS_MINDELAY,       PARAM_INT);  get_parameter("BUS_critical",       &BUS_CRITICAL_WORD,  PARAM_INT);  AllBusses = RSIM_CALLOC(BUS, ARCH_numnodes);  if (!AllBusses)    YS__errmsg(0, "Malloc failed at %s:%i", __FILE__, __LINE__);    for (nid = 0; nid < ARCH_numnodes; nid++)    {      pbus = PID2BUS(nid);      pbus->nodeid  = nid;      pbus->pstates = RSIM_CALLOC(int, NUM_MODULES + 1);      if (!(pbus->pstates))	YS__errmsg(nid, "Malloc failed at %s:%i", __FILE__, __LINE__);      pbus->arbwaiters = RSIM_CALLOC(ARBWAITER, NUM_MODULES + 1);      if (!(pbus->arbwaiters))	YS__errmsg(nid, "malloc failed at %s:%i", __FILE__, __LINE__);      pbus->cur_req    = NULL;      pbus->state      = BUS_IDLE;      pbus->busy_until = 0;      pbus->req_count  = 0;      pbus->req_queue = RSIM_CALLOC(REQ*, BUS_TOTAL_REQUESTS);      if (!(pbus->req_queue))	YS__errmsg(nid, "Malloc failed at %s:%i", __FILE__, __LINE__);      for (i = 0; i < BUS_TOTAL_REQUESTS; i++)	pbus->req_queue[i] = NULL;            /*        * Arbitration related variables. Set the current winner to processor 0        * because processor 0 is likely going to be the first bus module to        * access the bus. The processors take turns in round-robin fashion.       */      for (i = 0; i < NUM_MODULES+1; i++)	{	  pbus->arbwaiters[i].req = 0;	  pbus->pstates[i] = SLAVE_STATE;	}      pbus->arbwaiter_count = 0;      pbus->cur_winner      = 0;       pbus->pstates[0]      = MASTER_STATE;      pbus->rr_index        = MIN(1, NUM_MODULES - 1);      pbus->next_winner     = -1;       pbus->write_flowcontrol = 0;            pbus->last_start_time = 0.0;      pbus->last_end_time   = 0.0;      /*       * Create the arbitrator to call BusMain at the appropriate time.       * "issuer" is used to perform actual transferring on the bus.       */      pbus->arbitrator = NewEvent("bus_arbitrator", Bus_main, NODELETE, 0);      pbus->arbitrator->uptr1 = (void *) pbus;      pbus->issuer = NewEvent("bus_issuer", Bus_issuer, NODELETE, 0);      pbus->issuer->uptr1 = (void *) pbus;      pbus->performer = NewEvent("bus_perform", Bus_perform, NODELETE, 0);      pbus->performer->uptr1 = (void *) pbus;      pbus->num_trans    = RSIM_CALLOC(trans_count_t, NUM_MODULES+1);      if (!(pbus->num_trans))	YS__errmsg(nid, "Malloc failed at %s:%i", __FILE__, __LINE__);      pbus->lat_trans    = RSIM_CALLOC(trans_latency_t, NUM_MODULES+1);      if (!(pbus->lat_trans))	YS__errmsg(nid, "Malloc failed at %s:%i", __FILE__, __LINE__);      pbus->num_subtrans = RSIM_CALLOC(subtrans_count_t, NUM_MODULES+1);      if (!(pbus->num_subtrans))	YS__errmsg(nid, "Malloc failed at %s:%i", __FILE__, __LINE__);      Bus_stat_clear(nid);            if (BUS_TRACE_ENABLE)	{	  sprintf(name, "%s_bus.%02d", trace_dir, nid);	  pbus->busfile = fopen(name, "w");	  if (pbus->busfile == NULL)	    YS__errmsg(nid, "Cannot open bus trace file %s\n", name);	}      else	pbus->busfile = NULL;    }}/*============================================================================= * Called by "pbus->arbitrator" whenever there is something that should be * taken care of by the bus. */void Bus_main(void){  BUS *pbus = (BUS*)YS__ActEvnt->uptr1;  switch (pbus->state)    {    case BUS_ARBITRATING:      Bus_arbitrator(pbus);      break;    case BUS_WAKINGUP:      Bus_wakeup_winner(pbus);      break;    default:      YS__errmsg(pbus->nodeid,		 "How did we get into bus state %d?",		 pbus->state);    }}/*============================================================================= * Called by a processor which has something to send out through the bus * and which is not in master state. Bus receives only one arbitration request * from one bus module at one time. The bus module has to buffer the  * arbitration requests on its own when more than one arb_req is outstanding. */void Bus_recv_arb_req(int nid, int pid, REQ *req, double start_time){  BUS *pbus = (BUS*)PID2BUS(nid);  long long start = (long long)(start_time + 0.99);    if (pbus->arbwaiters[pid].req)    YS__errmsg(pbus->nodeid,	       "module %d has already an arbitration waiter.",	       pid);  /* synchronize start time to bus cycle */  while (start % BUS_FREQUENCY)    start++;    pbus->arbwaiters[pid].req = req;  pbus->arbwaiters[pid].time = (double)start;  pbus->arbwaiter_count++;  req->arb_start_time = YS__Simtime;    if (IsNotScheduled(pbus->arbitrator))    {      pbus->state = BUS_ARBITRATING;      schedule_event(pbus->arbitrator, MAX(YS__Simtime, pbus->busy_until));    }}/*============================================================================= * Determine which module will drive the bus after current bus owner (i.e. the * one in master state.) */void Bus_arbitrator(BUS *pbus){  int        i, idx;  ARBWAITER *parb;  REQ       *next_req;  int        next_winner = -1;  double     start_time = 1e20;  double     end_time  = 1.0e20; /* big enough? */  long long  next_cycle;    if (pbus->arbwaiter_count == 0)    return;  next_cycle = (long long)(YS__Simtime + 0.99);  while (next_cycle % BUS_FREQUENCY)    next_cycle++;    /* find next winner, determine request start time -------------------------*/  for (i = pbus->rr_index; i < NUM_MODULES; i++)    {      parb = &(pbus->arbwaiters[i]);      if (parb->req && parb->time < start_time)	{	  if ((pbus->req_count == BUS_TOTAL_REQUESTS) &&	      (parb->req->type == REQUEST) &&	      (parb->req->req_type != WRITE_UC))	    continue;	  if ((pbus->write_flowcontrol) &&	      ((parb->req->type == COHE_REPLY) ||	       (parb->req->type == WRITEBACK) ||	       (parb->req->type == WRITEPURGE)))	    continue;	  	  next_winner = i;	  start_time = parb->time;	}    }  for (i = 0; i < pbus->rr_index; i++)    {      parb = &(pbus->arbwaiters[i]);      if (parb->req && parb->time < start_time)	{	  if ((pbus->req_count == BUS_TOTAL_REQUESTS) &&	      (parb->req->type == REQUEST) &&	      (parb->req->req_type != WRITE_UC))	    continue;	  if ((pbus->write_flowcontrol) &&	      ((parb->req->type == COHE_REPLY) ||	       (parb->req->type == WRITEBACK) ||	       (parb->req->type == WRITEPURGE)))	    continue;	  	  next_winner = i;	  start_time = parb->time;	}    }  /*   * If the MMC wants to use the bus, it has highest priority.   */  if (pbus->arbwaiters[MEM_CNTL].req &&       pbus->arbwaiters[MEM_CNTL].time <= start_time)    {      next_winner = MEM_CNTL;      start_time  = pbus->arbwaiters[MEM_CNTL].time;    }  else    {      /*        * Bus is going to be used by a processor. Advance round-robin index.       */      if (++pbus->rr_index == NUM_MODULES)	pbus->rr_index = 0;    }  if (next_winner == -1)    {      schedule_event(pbus->arbitrator, YS__Simtime + BUS_FREQUENCY);      return;    }  pbus->arbwaiter_count--;  pbus->next_winner = next_winner;  next_req = pbus->arbwaiters[next_winner].req;  pbus->arbwaiters[next_winner].req = NULL;  pbus->next_req = next_req;    /*   * 1. Driver does not change:   *    start driving at end of current transaction   *    at least BUS_MINDELAY cycles after last transaction start   *    synchronize to bus cycle   * 2. Driver changes:   *    start driving BUS_TURNAROUND cycles after end of transaction   *    at least BUS_ARBDELAY cycles after arbitration request   *    at least BUS_MINDELAY cycles after last transaction start   *    synchronize to bus cycle   */  if (pbus->next_winner == pbus->cur_winner)    pbus->next_start_time =      MAX(MAX(pbus->last_start_time + BUS_MINDELAY * BUS_FREQUENCY,	      pbus->last_end_time),	  (double)next_cycle);  else    pbus->next_start_time =      MAX(MAX(pbus->last_start_time + BUS_MINDELAY * BUS_FREQUENCY,	      pbus->last_end_time + BUS_TURNAROUND * BUS_FREQUENCY),	  MAX(start_time + BUS_ARBDELAY * BUS_FREQUENCY,	      (double)next_cycle));    if (pbus->next_start_time < pbus->busy_until)    pbus->next_start_time = pbus->busy_until;  pbus->last_start_time = pbus->next_start_time;  pbus->last_end_time   = pbus->next_start_time +    pbus->next_req->bus_cycles * BUS_FREQUENCY;  /*   * Try to wakeup the next winner at appropriate time.   */  pbus->state = BUS_WAKINGUP;  schedule_event(pbus->arbitrator, pbus->next_start_time);}/*============================================================================= * Wake up the bus module who starts owning the bus at this cycle. */void Bus_wakeup_winner(BUS *pbus){  if (pbus->busy_until > YS__Simtime)    YS__errmsg(pbus->nodeid,	       "How can busy_until > YS__Simtime happen? (%f > %f)",	       pbus->busy_until, YS__Simtime);  pbus->pstates[pbus->cur_winner]  = SLAVE_STATE;  pbus->pstates[pbus->next_winner] = MASTER_STATE;  pbus->cur_winner = pbus->next_winner;  pbus->next_winner = -1;  pbus->busy_until = YS__Simtime +    (pbus->next_req->bus_cycles * BUS_FREQUENCY);  if (pbus->cur_winner == MEM_CNTL)    MMC_in_master_state(pbus->next_req);  else if (pbus->cur_winner < ARCH_cpus)    Cache_in_master_state(pbus->next_req);  else    IO_in_master_state(pbus->next_req);  /*-------------------------------------------------------------------------*/  /*    * MMC_in_master_state and Cache_in_master_state should set busy_until    * with an appropriate value bigger than YS__Simtime.   */  if (IsNotScheduled(pbus->arbitrator))    {      if (pbus->arbwaiter_count > 0)	{	  pbus->state = BUS_ARBITRATING;	  schedule_event(pbus->arbitrator, pbus->busy_until);	}      else	pbus->state = BUS_IDLE;    }}/*===========================================================================*/void Bus_start(REQ *req, int owner){  BUS *pbus = PID2BUS(req->node);  if (IsScheduled(pbus->issuer))    YS__errmsg(pbus->nodeid,	       "IOGetMasterState: scheduling scheduled bus issuer");  pbus->cur_req       = req;  pbus->cur_req_owner = owner;  pbus->busy_until = YS__Simtime + (req->bus_cycles * BUS_FREQUENCY);    if ((req->type == REQUEST) &&      (req->req_type != WRITE_UC))    pbus->req_count++;        if ((req->type == REPLY) ||      (req->type == COHE_REPLY))    pbus->req_count--;  Bus_start_trans(pbus, req);  if ((BUS_CRITICAL_WORD) &&      ((req->type == REPLY) || (req->type == COHE_REPLY)))    {      schedule_event(pbus->performer, YS__Simtime + BUS_FREQUENCY);    }  else    {      schedule_event(pbus->performer, pbus->busy_until - 0.1);

⌨️ 快捷键说明

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