1/* Copyright (c) 2012 Massachusetts Institute of Technology 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to deal 5 * in the Software without restriction, including without limitation the rights 6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 * copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 * THE SOFTWARE. 20 */ 21 22#include "model/network/ElectricalMesh.h" 23 24#include <cmath> 25 26#include "model/PortInfo.h" 27#include "model/EventInfo.h" 28#include "model/TransitionInfo.h" 29#include "model/ModelGen.h" 30#include "model/std_cells/StdCellLib.h" 31#include "model/timing_graph/ElectricalTimingTree.h" 32#include "model/timing_graph/ElectricalNet.h" 33 34namespace DSENT 35{ 36 using std::sqrt; 37 38 ElectricalMesh::ElectricalMesh(const String& instance_name_, const TechModel* tech_model_) 39 : ElectricalModel(instance_name_, tech_model_) 40 { 41 initParameters(); 42 initProperties(); 43 } 44 45 ElectricalMesh::~ElectricalMesh() 46 {} 47 48 void ElectricalMesh::initParameters() 49 { 50 // Clock Frequency 51 addParameterName("Frequency"); 52 // Physical Parameters 53 addParameterName("NumberSites"); 54 addParameterName("NumberBitsPerFlit"); 55 // Concentration factor 56 addParameterName("NumberSitesPerRouter"); 57 // Router parameters 58 addParameterName("Router->NumberVirtualNetworks"); 59 addParameterName("Router->NumberVirtualChannelsPerVirtualNetwork"); 60 addParameterName("Router->NumberBuffersPerVirtualChannel"); 61 addParameterName("Router->InputPort->BufferModel"); 62 addParameterName("Router->CrossbarModel"); 63 addParameterName("Router->SwitchAllocator->ArbiterModel"); 64 addParameterName("Router->ClockTreeModel"); 65 addParameterName("Router->ClockTree->NumberLevels"); 66 addParameterName("Router->ClockTree->WireLayer"); 67 addParameterName("Router->ClockTree->WireWidthMultiplier"); 68 addParameterName("Router->ClockTree->WireSpacingMultiplier", 3.0); 69 // Link parameters 70 addParameterName("Link->WireLayer"); 71 addParameterName("Link->WireWidthMultiplier"); 72 addParameterName("Link->WireSpacingMultiplier"); 73 return; 74 } 75 76 void ElectricalMesh::initProperties() 77 { 78 addPropertyName("SitePitch"); 79 return; 80 } 81 82 ElectricalMesh* ElectricalMesh::clone() const 83 { 84 // TODO 85 return NULL; 86 } 87 88 void ElectricalMesh::constructModel() 89 { 90 // Get input paramters 91 unsigned int number_sites = getParameter("NumberSites").toUInt(); 92 unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt(); 93 unsigned int number_sites_per_router = getParameter("NumberSitesPerRouter").toUInt(); 94 95 ASSERT(number_sites > 0, "[Error] " + getInstanceName() + 96 " -> Number of sites must be > 0!"); 97 ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() + 98 " -> Number of bits per flit must be > 0!"); 99 ASSERT(number_sites_per_router > 0, "[Error] " + getInstanceName() + 100 " -> Number of sites per router must be > 0!"); 101 102 // Get input parameters that will be forwarded to the sub instances 103 const String& router_number_vns = getParameter("Router->NumberVirtualNetworks"); 104 const String& router_number_vcs_per_vn = getParameter("Router->NumberVirtualChannelsPerVirtualNetwork"); 105 const String& router_number_bufs_per_vc = getParameter("Router->NumberBuffersPerVirtualChannel"); 106 const String& link_wire_layer = getParameter("Link->WireLayer"); 107 const String& link_wire_width_multiplier = getParameter("Link->WireWidthMultiplier"); 108 const String& link_wire_spacing_multiplier = getParameter("Link->WireSpacingMultiplier"); 109 110 // Calculate properties from input parameters 111 unsigned int number_routers = number_sites / number_sites_per_router; 112 unsigned int number_router_to_router_links = 4 * number_routers; 113 unsigned int number_router_to_site_links = 2 * number_sites; 114 unsigned int router_number_input_ports = 4 + number_sites_per_router; 115 unsigned int router_number_output_ports = 4 + number_sites_per_router; 116 117 getGenProperties()->set("NumberRouters", number_routers); 118 getGenProperties()->set("NumberRouterToRouterLinks", number_router_to_router_links); 119 getGenProperties()->set("NumberRouterToSiteLinks", number_router_to_site_links); 120 getGenProperties()->set("Router->NumberInputPorts", router_number_input_ports); 121 getGenProperties()->set("Router->NumberOutputPorts", router_number_output_ports); 122 123 // Create ports 124 createInputPort("CK"); 125 126 // Init mesh routers 127 ElectricalModel* router = (ElectricalModel*)ModelGen::createModel("Router", "MeshRouter", getTechModel()); 128 router->setParameter("NumberInputPorts", router_number_input_ports); 129 router->setParameter("NumberOutputPorts", router_number_output_ports); 130 router->setParameter("NumberVirtualNetworks", router_number_vns); 131 router->setParameter("NumberVirtualChannelsPerVirtualNetwork", router_number_vcs_per_vn); 132 router->setParameter("NumberBuffersPerVirtualChannel", router_number_bufs_per_vc); 133 router->setParameter("NumberBitsPerFlit", number_bits_per_flit); 134 router->setParameter("InputPort->BufferModel", getParameter("Router->InputPort->BufferModel")); 135 router->setParameter("CrossbarModel", getParameter("Router->CrossbarModel")); 136 router->setParameter("SwitchAllocator->ArbiterModel", getParameter("Router->SwitchAllocator->ArbiterModel")); 137 router->setParameter("ClockTreeModel", getParameter("Router->ClockTreeModel")); 138 router->setParameter("ClockTree->NumberLevels", getParameter("Router->ClockTree->NumberLevels")); 139 router->setParameter("ClockTree->WireLayer", getParameter("Router->ClockTree->WireLayer")); 140 router->setParameter("ClockTree->WireWidthMultiplier", getParameter("Router->ClockTree->WireWidthMultiplier")); 141 router->setParameter("ClockTree->WireSpacingMultiplier", getParameter("Router->ClockTree->WireSpacingMultiplier")); 142 router->construct(); 143 144 // Init router to router links 145 ElectricalModel* rr_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "RouterToRouterLink", getTechModel()); 146 rr_link->setParameter("NumberBits", number_bits_per_flit); 147 rr_link->setParameter("WireLayer", link_wire_layer); 148 rr_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); 149 rr_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); 150 rr_link->construct(); 151 152 // Init router to site links 153 ElectricalModel* rs_link = (ElectricalModel*)ModelGen::createModel("RepeatedLink", "RouterToSiteLink", getTechModel()); 154 rs_link->setParameter("NumberBits", number_bits_per_flit); 155 rs_link->setParameter("WireLayer", link_wire_layer); 156 rs_link->setParameter("WireWidthMultiplier", link_wire_width_multiplier); 157 rs_link->setParameter("WireSpacingMultiplier", link_wire_spacing_multiplier); 158 rs_link->construct(); 159 160 // Connect ports 161 createNet("RR_Link_Out", makeNetIndex(0, number_bits_per_flit-1)); 162 createNet("RR_Link_In", makeNetIndex(0, number_bits_per_flit-1)); 163 portConnect(rr_link, "In", "RR_Link_In"); 164 portConnect(rr_link, "Out", "RR_Link_Out"); 165 166 createNet("RS_Link_Out", makeNetIndex(0, number_bits_per_flit-1)); 167 createNet("RS_Link_In", makeNetIndex(0, number_bits_per_flit-1)); 168 portConnect(rs_link, "In", "RS_Link_In"); 169 portConnect(rs_link, "Out", "RS_Link_Out"); 170 171 portConnect(router, "CK", "CK"); 172 for(unsigned int i = 0; i < router_number_input_ports; ++i) 173 { 174 createNet("Router_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); 175 portConnect(router, "FlitIn" + (String)i, "Router_In" + (String)i); 176 } 177 for(unsigned int i = 0; i < router_number_output_ports; ++i) 178 { 179 createNet("Router_Out" + (String)i, makeNetIndex(0, number_bits_per_flit-1)); 180 portConnect(router, "FlitOut" + (String)i, "Router_Out" + (String)i); 181 } 182 for(unsigned int i = 0; i < number_bits_per_flit; ++i) 183 { 184 for(unsigned int j = 0; j < 4; ++j) 185 { 186 assignVirtualFanout("Router_In" + (String)j, makeNetIndex(i), "RR_Link_Out", makeNetIndex(i)); 187 assignVirtualFanin("RR_Link_In", makeNetIndex(i), "Router_Out" + (String)j, makeNetIndex(i)); 188 } 189 for(unsigned int j = 4; j < router_number_input_ports; ++j) 190 { 191 assignVirtualFanout("Router_In" + (String)j, makeNetIndex(i), "RS_Link_Out", makeNetIndex(i)); 192 assignVirtualFanin("RS_Link_In", makeNetIndex(i), "Router_Out" + (String)j, makeNetIndex(i)); 193 } 194 } 195 196 // Create area, power and event results 197 createElectricalResults(); 198 createElectricalEventResult("AvgUnicast"); 199 createElectricalEventResult("AvgBroadcast"); 200 201 // Add all instances 202 addSubInstances(router, number_routers); 203 addElectricalSubResults(router, number_routers); 204 addSubInstances(rr_link, number_router_to_router_links); 205 addElectricalSubResults(rr_link, number_router_to_router_links); 206 addSubInstances(rs_link, number_router_to_site_links); 207 addElectricalSubResults(rs_link, number_router_to_site_links); 208 209 double number_routers_per_side = sqrt(number_routers); 210 211 // Update unicast event 212 double avg_number_unicast_hop = 2.0 * number_routers_per_side / 3.0; 213 double avg_number_unicast_rr_links_traveled = avg_number_unicast_hop; 214 double avg_number_unicast_rs_links_traveled = 2.0; 215 double avg_number_unicast_router_traveled = avg_number_unicast_hop + 1.0; 216 Result* avg_unicast_flit = getEventResult("AvgUnicast"); 217 avg_unicast_flit->addSubResult(rr_link->getEventResult("Send"), "RouterToRouterLink", avg_number_unicast_rr_links_traveled); 218 avg_unicast_flit->addSubResult(rs_link->getEventResult("Send"), "RouterToSiteLink", avg_number_unicast_rs_links_traveled); 219 if(router->hasEventResult("WriteBuffer")) 220 { 221 avg_unicast_flit->addSubResult(router->getEventResult("WriteBuffer"), "MeshRouter", avg_number_unicast_router_traveled); 222 } 223 if(router->hasEventResult("ReadBuffer")) 224 { 225 avg_unicast_flit->addSubResult(router->getEventResult("ReadBuffer"), "MeshRouter", avg_number_unicast_router_traveled); 226 } 227 avg_unicast_flit->addSubResult(router->getEventResult("TraverseCrossbar->Multicast1"), "MeshRouter", avg_number_unicast_router_traveled); 228 229 // Update broadcast event 230 double avg_number_broadcast_rr_links_traveled = (number_routers_per_side - 1.0) * number_routers_per_side + number_routers_per_side - 1.0; 231 double avg_number_broadcast_rs_links_traveled = number_sites; 232 double avg_number_broadcast_router_crossbar_traveled = number_routers * (number_sites_per_router + 1.0) - 2.0; 233 Result* avg_broadcast_flit = getEventResult("AvgBroadcast"); 234 avg_broadcast_flit->addSubResult(rr_link->getEventResult("Send"), "RouterToRouterLink", avg_number_broadcast_rr_links_traveled); 235 avg_broadcast_flit->addSubResult(rs_link->getEventResult("Send"), "RouterToSiteLink", avg_number_broadcast_rs_links_traveled); 236 if(router->hasEventResult("WriteBuffer")) 237 { 238 avg_broadcast_flit->addSubResult(router->getEventResult("WriteBuffer"), "MeshRouter", number_routers); 239 } 240 if(router->hasEventResult("ReadBuffer")) 241 { 242 avg_broadcast_flit->addSubResult(router->getEventResult("ReadBuffer"), "MeshRouter", number_routers); 243 } 244 avg_broadcast_flit->addSubResult(router->getEventResult("TraverseCrossbar->Multicast1"), "MeshRouter", avg_number_broadcast_router_crossbar_traveled); 245 246 return; 247 } 248 249 void ElectricalMesh::updateModel() 250 { 251 // Get properties 252 double site_pitch = getProperty("SitePitch").toDouble(); 253 double clock_freq = getParameter("Frequency"); 254 255 ASSERT(site_pitch > 0, "[Error] " + getInstanceName() + 256 " -> Site pitch must be > 0!"); 257 ASSERT(clock_freq > 0, "[Error] " + getInstanceName() + 258 " -> Clock frequency must be > 0!"); 259 260 unsigned int number_sites_per_router = getParameter("NumberSitesPerRouter"); 261 // Get margin on link delays, since there are registers before and after the link 262 double delay_ck_to_q = getTechModel()->getStdCellLib()->getStdCellCache()->get("DFFQ_X1->Delay->CK_to_Q"); 263 double delay_setup = getTechModel()->getStdCellLib()->getStdCellCache()->get("DFFQ_X1->Delay->CK_to_Q"); 264 double link_delay_margin = (delay_ck_to_q + delay_setup) * 1.5; 265 266 double rr_link_length = site_pitch * sqrt(number_sites_per_router); 267 double rr_link_delay = std::max(1e-99, 1.0 / clock_freq - link_delay_margin); 268 double rs_link_length = site_pitch * (sqrt(number_sites_per_router) - 1.0); 269 double rs_link_delay = std::max(1e-99, 1.0 / clock_freq - link_delay_margin ); 270 double router_delay = 1.0 / clock_freq; 271 272 Model* rr_link = getSubInstance("RouterToRouterLink"); 273 rr_link->setProperty("WireLength", rr_link_length); 274 rr_link->setProperty("Delay", rr_link_delay); 275 rr_link->setProperty("IsKeepParity", "TRUE"); 276 rr_link->update(); 277 278 Model* rs_link = getSubInstance("RouterToSiteLink"); 279 rs_link->setProperty("WireLength", rs_link_length); 280 rs_link->setProperty("Delay", rs_link_delay); 281 rs_link->setProperty("IsKeepParity", "TRUE"); 282 rs_link->update(); 283 284 ElectricalModel* router = (ElectricalModel*)getSubInstance("MeshRouter"); 285 router->update(); 286 287 ElectricalTimingTree router_timing_tree("MeshRouter", router); 288 router_timing_tree.performTimingOpt(router->getNet("CK"), router_delay); 289 return; 290 } 291 292 void ElectricalMesh::propagateTransitionInfo() 293 { 294 // Get parameters 295 unsigned int router_number_input_ports = getGenProperties()->get("Router->NumberInputPorts"); 296 297 ElectricalModel* rr_link = (ElectricalModel*)getSubInstance("RouterToRouterLink"); 298 assignPortTransitionInfo(rr_link, "In", TransitionInfo(0.25, 0.25, 0.25)); 299 rr_link->use(); 300 301 ElectricalModel* rs_link = (ElectricalModel*)getSubInstance("RouterToSiteLink"); 302 assignPortTransitionInfo(rs_link, "In", TransitionInfo(0.25, 0.25, 0.25)); 303 rs_link->use(); 304 305 ElectricalModel* router = (ElectricalModel*)getSubInstance("MeshRouter"); 306 for(unsigned int i = 0; i < router_number_input_ports; ++i) 307 { 308 assignPortTransitionInfo(router, "FlitIn" + (String)i, TransitionInfo(0.25, 0.25, 0.25)); 309 } 310 assignPortTransitionInfo(router, "CK", TransitionInfo(0.0, 1.0, 0.0)); 311 router->getGenProperties()->set("UseModelEvent", ""); 312 router->use(); 313 314 return; 315 } 316} // namespace DSENT 317 318