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