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