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/electrical/router/Router.h"
23
24#include <cmath>
25#include <vector>
26
27#include "model/PortInfo.h"
28#include "model/EventInfo.h"
29#include "model/TransitionInfo.h"
30#include "model/ModelGen.h"
31#include "model/std_cells/StdCellLib.h"
32#include "model/std_cells/StdCell.h"
33#include "model/electrical/router/RouterInputPort.h"
34#include "model/electrical/router/RouterSwitchAllocator.h"
35#include "model/timing_graph/ElectricalNet.h"
36
37namespace DSENT
38{
39    using std::sqrt;
40    using std::vector;
41
42    using LibUtil::castStringVector;
43    using LibUtil::vectorToString;
44
45    Router::Router(const String& instance_name_, const TechModel* tech_model_)
46        : ElectricalModel(instance_name_, tech_model_)
47    {
48        initParameters();
49        initProperties();
50    }
51
52    Router::~Router()
53    {}
54
55    void Router::initParameters()
56    {
57        addParameterName("NumberInputPorts");
58        addParameterName("NumberOutputPorts");
59        addParameterName("NumberBitsPerFlit");
60        addParameterName("NumberVirtualNetworks");
61        addParameterName("NumberVirtualChannelsPerVirtualNetwork");
62        addParameterName("NumberBuffersPerVirtualChannel");
63        // Spec for input port
64        addParameterName("InputPort->BufferModel");
65        // Spec for crossbar
66        addParameterName("CrossbarModel");
67        // Spec for switch allocator
68        addParameterName("SwitchAllocator->ArbiterModel");
69        // Spec for clock tree
70        addParameterName("ClockTreeModel");
71        addParameterName("ClockTree->NumberLevels");
72        addParameterName("ClockTree->WireLayer");
73        addParameterName("ClockTree->WireWidthMultiplier");
74        addParameterName("ClockTree->WireSpacingMultiplier", 3.0);
75        return;
76    }
77
78    void Router::initProperties()
79    {
80        return;
81    }
82
83    Router* Router::clone() const
84    {
85        // TODO
86        return NULL;
87    }
88
89    void Router::constructModel()
90    {
91        // Get parameters
92        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
93        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
94        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
95
96        ASSERT(number_input_ports > 0, "[Error] " + getInstanceName() +
97                " -> Number of input ports must be > 0!");
98        ASSERT(number_output_ports > 0, "[Error] " + getInstanceName() +
99                " -> Number of output ports must be > 0!");
100        ASSERT(number_bits_per_flit > 0, "[Error] " + getInstanceName() +
101                " -> Number of bits per buffer must be > 0!");
102
103        // Create ports
104        createInputPort("CK");
105        for(unsigned int i = 0; i < number_input_ports; ++i)
106        {
107            createInputPort("FlitIn" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
108        }
109        for(unsigned int i = 0; i < number_output_ports; ++i)
110        {
111            createOutputPort("FlitOut" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
112        }
113
114        // Create area, power, event results
115        createElectricalResults();
116        getEventInfo("Idle")->setStaticTransitionInfos();
117        getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
118
119        createElectricalEventResult("ReadBuffer");
120        getEventInfo("ReadBuffer")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
121        createElectricalEventResult("WriteBuffer");
122        getEventInfo("WriteBuffer")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
123        for(unsigned int i = 1; i <= number_output_ports; ++i)
124        {
125            createElectricalEventResult("TraverseCrossbar->Multicast" + (String)i);
126            getEventInfo("TraverseCrossbar->Multicast" + (String)i)->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
127        }
128        createElectricalEventResult("ArbitrateSwitch->ArbitrateStage1");
129        createElectricalEventResult("ArbitrateSwitch->ArbitrateStage2");
130        createElectricalEventResult("DistributeClock");
131        getEventInfo("DistributeClock")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
132
133        // Create intermediate nets
134        createNet("PipelineReg0_In");
135        createNet("PipelineReg0_Out");
136        createNet("PipelineReg1_In");
137        createNet("PipelineReg1_Out");
138        for(unsigned int i = 0; i < number_output_ports; ++i)
139        {
140            createNet("PipelineReg2_In" + (String)i);
141            createNet("PipelineReg2_Out" + (String)i);
142        }
143
144        createRouterInputPort();
145        createSwitchAllocator();
146        createVirtualChannelAllocator();
147        createCrossbar();
148        createClockTree();
149        createPipelineReg();
150
151        // Get generated numbers
152        unsigned int number_crossbar_selects = getGenProperties()->get("Crossbar->NumberSelects");
153
154        // Add write buffer event
155        getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("DFFD"), "PipelineReg0", number_bits_per_flit);
156        getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("DFFQ"), "PipelineReg0", number_bits_per_flit);
157        getEventResult("WriteBuffer")->addSubResult(getSubInstance("PipelineReg0")->getEventResult("CK"), "PipelineReg0", number_bits_per_flit);
158        getEventResult("WriteBuffer")->addSubResult(getSubInstance("InputPort")->getEventResult("WriteBuffer"), "InputPort", 1.0);
159
160        // Add read buffer event
161        getEventResult("ReadBuffer")->addSubResult(getSubInstance("InputPort")->getEventResult("ReadBuffer"), "InputPort", 1.0);
162        getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("DFFD"), "PipelineReg1", number_bits_per_flit);
163        getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("DFFQ"), "PipelineReg1", number_bits_per_flit);
164        getEventResult("ReadBuffer")->addSubResult(getSubInstance("PipelineReg1")->getEventResult("CK"), "PipelineReg1", number_bits_per_flit);
165
166        // Add crossbar traversal event
167        for(unsigned int i = 1; i <= number_output_ports; ++i)
168        {
169            Result* traverse_crossbar_event = getEventResult("TraverseCrossbar->Multicast" + (String)i);
170            traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("DFFD"), "Crossbar_Sel_DFF", number_crossbar_selects);
171            traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("DFFQ"), "Crossbar_Sel_DFF", number_crossbar_selects);
172            traverse_crossbar_event->addSubResult(getSubInstance("Crossbar_Sel_DFF")->getEventResult("CK"), "Crossbar_Sel_DFF", number_crossbar_selects);
173            traverse_crossbar_event->addSubResult(getSubInstance("Crossbar")->getEventResult("Multicast" + (String)i), "Crossbar", 1.0);
174            for(unsigned int j = 0; j < i; ++j)
175            {
176                traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("DFFD"), "PipelineReg2_" + (String)j, number_bits_per_flit);
177                traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("DFFQ"), "PipelineReg2_" + (String)j, number_bits_per_flit);
178                traverse_crossbar_event->addSubResult(getSubInstance("PipelineReg2_" + (String)j)->getEventResult("CK"), "PipelineReg2_" + (String)j, number_bits_per_flit);
179            }
180        }
181
182        // Add stage1 allocator arbitrate
183        Result* arb_sw_stage1_event = getEventResult("ArbitrateSwitch->ArbitrateStage1");
184        arb_sw_stage1_event->addSubResult(getSubInstance("SwitchAllocator")->getEventResult("ArbitrateStage1"), "SwitchAllocator", 1.0);
185
186        // Add stage2 allocator arbitrate
187        Result* arb_sw_stage2_event = getEventResult("ArbitrateSwitch->ArbitrateStage2");
188        arb_sw_stage2_event->addSubResult(getSubInstance("SwitchAllocator")->getEventResult("ArbitrateStage2"), "SwitchAllocator", 1.0);
189
190        // Add CK event
191        getEventResult("DistributeClock")->addSubResult(getSubInstance("ClockTree")->getEventResult("Send"), "ClockTree", 1.0);
192        return;
193    }
194
195    void Router::updateModel()
196    {
197        // Get parameters
198        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
199
200        // Update other components
201        getSubInstance("PipelineReg0")->update();
202        getSubInstance("InputPort")->update();
203        getSubInstance("PipelineReg1")->update();
204        getSubInstance("Crossbar_Sel_DFF")->update();
205        getSubInstance("Crossbar")->update();
206        for(unsigned int i = 0; i < number_output_ports; ++i)
207        {
208            getSubInstance("PipelineReg2_" + (String)i)->update();
209        }
210        getSubInstance("SwitchAllocator")->update();
211
212        // Update clock tree
213        double total_clock_tree_cap = getNet("CK")->getTotalDownstreamCap();
214        double router_area = getAreaResult("Active")->calculateSum();
215        Model* clock_tree = getSubInstance("ClockTree");
216        clock_tree->setProperty("SitePitch", sqrt(router_area));
217        clock_tree->setProperty("TotalLoadCapPerBit", total_clock_tree_cap);
218        clock_tree->update();
219
220        return;
221    }
222
223    void Router::propagateTransitionInfo()
224    {
225        // Update probability
226        unsigned int number_output_ports = getParameter("NumberOutputPorts");
227
228        // Current event
229        const String& current_event = getGenProperties()->get("UseModelEvent");
230
231        ElectricalModel* pipeline_reg0 = (ElectricalModel*)getSubInstance("PipelineReg0");
232        propagatePortTransitionInfo(pipeline_reg0, "D", "FlitIn0");
233        propagatePortTransitionInfo(pipeline_reg0, "CK", "CK");
234        pipeline_reg0->use();
235
236        ElectricalModel* input_port = (ElectricalModel*)getSubInstance("InputPort");
237        propagatePortTransitionInfo(input_port, "FlitIn", pipeline_reg0, "Q");
238        propagatePortTransitionInfo(input_port, "CK", "CK");
239        input_port->getGenProperties()->set("UseModelEvent", "ReadWrite");
240        input_port->use();
241
242        ElectricalModel* pipeline_reg1 = (ElectricalModel*)getSubInstance("PipelineReg1");
243        propagatePortTransitionInfo(pipeline_reg1, "D", "FlitIn0");
244        propagatePortTransitionInfo(pipeline_reg1, "CK", "CK");
245        pipeline_reg1->use();
246
247        ElectricalModel* crossbar_sel_dff = (ElectricalModel*)getSubInstance("Crossbar_Sel_DFF");
248        assignPortTransitionInfo(crossbar_sel_dff, "D", TransitionInfo());
249        propagatePortTransitionInfo(crossbar_sel_dff, "CK", "CK");
250        crossbar_sel_dff->use();
251
252        ElectricalModel* crossbar = (ElectricalModel*)getSubInstance("Crossbar");
253        bool is_crossbar_event = false;
254        for(unsigned int i = 1; i <= number_output_ports; ++i)
255        {
256            if(current_event == ("TraverseCrossbar->Multicast" + (String)i))
257            {
258                is_crossbar_event = true;
259                // Assume the flit is sent from port 0 to port 0~i-1
260                // Apply default transition info
261                crossbar->applyTransitionInfo("Multicast" + (String)i);
262                // Overwrite transition info
263                propagatePortTransitionInfo(crossbar, "In0", "FlitIn0");
264                break;
265            }
266        }
267        if(is_crossbar_event == false)
268        {
269            crossbar->applyTransitionInfo("Multicast1");
270            propagatePortTransitionInfo(crossbar, "In0", "FlitIn0");
271        }
272        crossbar->use();
273
274        vector<ElectricalModel*> pipeline_reg2s(number_output_ports, NULL);
275        for(unsigned int i = 0; i < number_output_ports; ++i)
276        {
277            pipeline_reg2s[i] = (ElectricalModel*)getSubInstance("PipelineReg2_" + (String)i);
278            propagatePortTransitionInfo(pipeline_reg2s[i], "D", "FlitIn0");
279            propagatePortTransitionInfo(pipeline_reg2s[i], "CK", "CK");
280            pipeline_reg2s[i]->use();
281        }
282
283        ElectricalModel* sw_allocator = (ElectricalModel*)getSubInstance("SwitchAllocator");
284        if(current_event == "ArbitrateSwitch->ArbitrateStage1")
285        {
286            sw_allocator->applyTransitionInfo("ArbitrateStage1");
287        }
288        else if(current_event == "ArbitrateSwitch->ArbitrateStage2")
289        {
290            sw_allocator->applyTransitionInfo("ArbitrateStage2");
291        }
292        else
293        {
294            sw_allocator->applyTransitionInfo("Idle");
295        }
296        sw_allocator->use();
297
298        ElectricalModel* clock_tree = (ElectricalModel*)getSubInstance("ClockTree");
299        propagatePortTransitionInfo(clock_tree, "In", "CK");
300        clock_tree->use();
301        return;
302    }
303
304    void Router::createRouterInputPort()
305    {
306        // Get parameters
307        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
308        unsigned int number_vns = getParameter("NumberVirtualNetworks").toUInt();
309        const String& number_vcs_per_vn = getParameter("NumberVirtualChannelsPerVirtualNetwork");
310        const String& number_bufs_per_vc = getParameter("NumberBuffersPerVirtualChannel");
311        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
312        const String& buffer_model = getParameter("InputPort->BufferModel");
313
314        // Init input port model
315        const String& input_port_name = "InputPort";
316        RouterInputPort* input_port = new RouterInputPort(input_port_name, getTechModel());
317        input_port->setParameter("NumberVirtualNetworks", number_vns);
318        input_port->setParameter("NumberVirtualChannelsPerVirtualNetwork", number_vcs_per_vn);
319        input_port->setParameter("NumberBuffersPerVirtualChannel", number_bufs_per_vc);
320        input_port->setParameter("NumberBitsPerFlit", number_bits_per_flit);
321        input_port->setParameter("BufferModel", buffer_model);
322        input_port->construct();
323
324        unsigned int number_input_port_outputs = input_port->getGenProperties()->get("NumberOutputs");
325        unsigned int number_input_port_addr_bits = input_port->getGenProperties()->get("NumberAddressBits");
326        getGenProperties()->set("InputPort->NumberOutputs", number_input_port_outputs);
327        getGenProperties()->set("InputPort->NumberAddressBits", number_input_port_addr_bits);
328
329        unsigned int total_number_vcs = input_port->getGenProperties()->get("TotalNumberVirtualChannels");
330        getGenProperties()->set("TotalNumberVirtualChannels", total_number_vcs);
331
332        // Add the instance and the results
333        addSubInstances(input_port, number_input_ports);
334        addElectricalSubResults(input_port, number_input_ports);
335
336        // Create connections
337        createNet("InputPort_In", makeNetIndex(0, number_bits_per_flit-1));
338        createNet("InputPort_Out", makeNetIndex(0, number_bits_per_flit-1));
339
340        assignVirtualFanout("InputPort_In", "PipelineReg0_Out");
341        portConnect(input_port, "FlitIn", "InputPort_In");
342        portConnect(input_port, "CK", "CK");
343        portConnect(input_port, "FlitOut", "InputPort_Out");
344        assignVirtualFanin("PipelineReg1_In", "InputPort_Out");
345
346        return;
347    }
348
349    void Router::createVirtualChannelAllocator()
350    {}
351
352    void Router::createSwitchAllocator()
353    {
354        // Get parameters
355        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
356        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
357        unsigned int total_number_vcs = getGenProperties()->get("TotalNumberVirtualChannels").toUInt();
358        const String& arb_model = getParameter("SwitchAllocator->ArbiterModel");
359
360        // Init switch allocator model
361        const String& sw_allocator_name = "SwitchAllocator";
362        RouterSwitchAllocator* sw_allocator = new RouterSwitchAllocator(sw_allocator_name, getTechModel());
363        sw_allocator->setParameter("NumberInputPorts", number_input_ports);
364        sw_allocator->setParameter("NumberOutputPorts", number_output_ports);
365        sw_allocator->setParameter("TotalNumberVirtualChannels", total_number_vcs);
366        sw_allocator->setParameter("ArbiterModel", arb_model);
367        sw_allocator->construct();
368
369        // Add the instance and the results
370        addSubInstances(sw_allocator, 1.0);
371        addElectricalSubResults(sw_allocator, 1.0);
372
373        // Create connections (currently connect CK only)
374        portConnect(sw_allocator, "CK", "CK");
375        return;
376    }
377
378    void Router::createCrossbar()
379    {
380        // Get parameters
381        const String& crossbar_model = getParameter("CrossbarModel");
382        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
383        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
384        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
385        unsigned int number_input_port_outputs = getGenProperties()->get("InputPort->NumberOutputs").toUInt();
386
387        unsigned int number_crossbar_inputs = number_input_port_outputs * number_input_ports;
388        unsigned int number_crossbar_outputs = number_output_ports;
389        getGenProperties()->set("Crossbar->NumberInputs", number_crossbar_inputs);
390        getGenProperties()->set("Crossbar->NumberOutputs", number_crossbar_outputs);
391
392        // Init crossbar model
393        const String& crossbar_name = "Crossbar";
394        ElectricalModel* crossbar = ModelGen::createCrossbar(crossbar_model, crossbar_name, getTechModel());
395        crossbar->setParameter("NumberInputs", number_crossbar_inputs);
396        crossbar->setParameter("NumberOutputs", number_crossbar_outputs);
397        crossbar->setParameter("NumberBits", number_bits_per_flit);
398        crossbar->setParameter("BitDuplicate", "TRUE");
399        crossbar->construct();
400
401        unsigned int number_crossbar_selects = crossbar->getGenProperties()->get("NumberSelectsPerPort");
402        getGenProperties()->set("Crossbar->NumberSelects", number_crossbar_selects);
403
404        // Init DFF for crossbar selections
405        const String& crossbar_sel_dff_name = "Crossbar_Sel_DFF";
406        StdCell* crossbar_sel_dff = getTechModel()->getStdCellLib()->createStdCell("DFFQ", crossbar_sel_dff_name);
407        crossbar_sel_dff->construct();
408
409        // Add instances and results
410        addSubInstances(crossbar, 1.0);
411        addElectricalSubResults(crossbar, 1.0);
412
413        addSubInstances(crossbar_sel_dff, number_crossbar_outputs * number_crossbar_selects);
414        addElectricalSubResults(crossbar_sel_dff, number_crossbar_outputs * number_crossbar_selects);
415
416        // Create connections
417        createNet("Crossbar_Sel_DFF_Out");
418        for(unsigned int i = 0; i < number_crossbar_outputs; ++i)
419        {
420            for(unsigned int j = 0; j < number_crossbar_selects; ++j)
421            {
422                createNet(String::format("Crossbar_Sel%d_%d", i, j));
423            }
424            createNet("Crossbar_Out" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
425        }
426        for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
427        {
428            createNet("Crossbar_In" + (String)i, makeNetIndex(0, number_bits_per_flit-1));
429        }
430
431        for(unsigned int i = 0; i < number_crossbar_selects; ++i)
432        {
433            portConnect(crossbar_sel_dff, "CK", "CK");
434        }
435        portConnect(crossbar_sel_dff, "Q", "Crossbar_Sel_DFF_Out");
436        for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
437        {
438            assignVirtualFanout("Crossbar_In" + (String)i, "PipelineReg1_Out");
439            portConnect(crossbar, "In" + (String)i, "Crossbar_In" + (String)i);
440        }
441        for(unsigned int i = 0; i < number_crossbar_outputs; ++i)
442        {
443            for(unsigned int j = 0; j < number_crossbar_selects; ++j)
444            {
445                assignVirtualFanout(String::format("Crossbar_Sel%d_%d", i, j), "Crossbar_Sel_DFF_Out");
446                portConnect(crossbar, String::format("Sel%d_%d", i, j), String::format("Crossbar_Sel%d_%d", i, j));
447            }
448            portConnect(crossbar, "Out" + (String)i, "Crossbar_Out" + (String)i);
449            assignVirtualFanin("PipelineReg2_In" + (String)i, "Crossbar_Out" + (String)i);
450        }
451
452        return;
453    }
454
455    void Router::createPipelineReg()
456    {
457        // Get parameters
458        unsigned int number_input_ports = getParameter("NumberInputPorts").toUInt();
459        unsigned int number_output_ports = getParameter("NumberOutputPorts").toUInt();
460        unsigned int number_bits_per_flit = getParameter("NumberBitsPerFlit").toUInt();
461        unsigned int number_crossbar_inputs = getGenProperties()->get("Crossbar->NumberInputs");
462
463        // Init pipeline reg model
464        // First stage: from router input to input port
465        const String& pipeline_reg0_name = "PipelineReg0";
466        StdCell* pipeline_reg0 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg0_name);
467        pipeline_reg0->construct();
468        // Second stage: from input port to crossbar
469        const String& pipeline_reg1_name = "PipelineReg1";
470        StdCell* pipeline_reg1 = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg1_name);
471        pipeline_reg1->construct();
472
473        // Third stage: from crossbar to router output
474        vector<StdCell*> pipeline_reg2s(number_output_ports, (StdCell*)NULL);
475        vector<String> pipeline_reg2_names(number_output_ports, "");
476        for(unsigned int i = 0; i < number_output_ports; ++i)
477        {
478            pipeline_reg2_names[i] = "PipelineReg2_" + (String)i;
479            pipeline_reg2s[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", pipeline_reg2_names[i]);
480            pipeline_reg2s[i]->construct();
481        }
482
483        // Add instances and results
484        addSubInstances(pipeline_reg0, number_input_ports * number_bits_per_flit);
485        addElectricalSubResults(pipeline_reg0, number_input_ports * number_bits_per_flit);
486
487        addSubInstances(pipeline_reg1, number_crossbar_inputs * number_bits_per_flit);
488        addElectricalSubResults(pipeline_reg1, number_crossbar_inputs * number_bits_per_flit);
489
490        for(unsigned int i = 0; i < number_output_ports; ++i)
491        {
492            addSubInstances(pipeline_reg2s[i], number_bits_per_flit);
493            addElectricalSubResults(pipeline_reg2s[i], number_bits_per_flit);
494        }
495
496        // Create data connections
497        for(unsigned int i = 0; i < number_input_ports; ++i)
498        {
499            assignVirtualFanin("PipelineReg0_In", "FlitIn" + (String)i);
500        }
501        portConnect(pipeline_reg0, "D", "PipelineReg0_In");
502        portConnect(pipeline_reg0, "Q", "PipelineReg0_Out");
503        portConnect(pipeline_reg1, "D", "PipelineReg1_In");
504        portConnect(pipeline_reg1, "Q", "PipelineReg1_Out");
505        for(unsigned int i = 0; i < number_output_ports; ++i)
506        {
507            portConnect(pipeline_reg2s[i], "D", "PipelineReg2_In" + (String)i);
508            portConnect(pipeline_reg2s[i], "Q", "PipelineReg2_Out" + (String)i);
509            assignVirtualFanout("FlitOut" + (String)i, "PipelineReg2_Out" + (String)i);
510        }
511
512        // Create CK connections
513        for(unsigned int n = 0; n < number_bits_per_flit; ++n)
514        {
515            for(unsigned int i = 0; i < number_input_ports; ++i)
516            {
517                portConnect(pipeline_reg0, "CK", "CK");
518            }
519            for(unsigned int i = 0; i < number_crossbar_inputs; ++i)
520            {
521                portConnect(pipeline_reg1, "CK", "CK");
522            }
523            for(unsigned int i = 0; i < number_output_ports; ++i)
524            {
525                portConnect(pipeline_reg2s[i], "CK", "CK");
526            }
527        }
528        return;
529    }
530
531    void Router::createClockTree()
532    {
533        // Get parameters
534        const String& clock_tree_model = getParameter("ClockTreeModel");
535        const String& clock_tree_number_levels = getParameter("ClockTree->NumberLevels");
536        const String& clock_tree_wire_layer = getParameter("ClockTree->WireLayer");
537        const String& clock_tree_wire_width_multiplier = getParameter("ClockTree->WireWidthMultiplier");
538        const String& clock_tree_wire_spacing_multiplier = getParameter("ClockTree->WireSpacingMultiplier");
539
540        // Init clock tree model
541        const String& clock_tree_name = "ClockTree";
542        ElectricalModel* clock_tree = (ElectricalModel*)ModelGen::createModel(clock_tree_model, clock_tree_name, getTechModel());
543        clock_tree->setParameter("NumberLevels", clock_tree_number_levels);
544        clock_tree->setParameter("NumberBits", 1);
545        clock_tree->setParameter("WireLayer", clock_tree_wire_layer);
546        clock_tree->setParameter("WireWidthMultiplier", clock_tree_wire_width_multiplier);
547        clock_tree->setParameter("WireSpacingMultiplier", clock_tree_wire_spacing_multiplier);
548        clock_tree->construct();
549
550        // Add instances and results
551        addSubInstances(clock_tree, 1.0);
552        addElectricalSubResults(clock_tree, 1.0);
553
554        return;
555    }
556} // namespace DSENT
557
558