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/optical/SWMRLink.h"
23
24#include "model/PortInfo.h"
25#include "model/TransitionInfo.h"
26#include "model/EventInfo.h"
27#include "model/optical_graph/OpticalGraph.h"
28#include "model/optical_graph/OpticalWaveguide.h"
29#include "model/optical/RingModulator.h"
30#include "model/optical/RingFilter.h"
31#include "model/optical/RingDetector.h"
32#include "model/optical/LaserSource.h"
33#include "model/optical/ThrottledLaserSource.h"
34
35namespace DSENT
36{
37    SWMRLink::SWMRLink(const String& instance_name_, const TechModel* tech_model_)
38        : OpticalModel(instance_name_, tech_model_)
39    {
40        initParameters();
41        initProperties();
42    }
43
44    SWMRLink::~SWMRLink()
45    {}
46
47    void SWMRLink::initParameters()
48    {
49        addParameterName("NumberReaders");
50        addParameterName("NumberWavelengths");
51        addParameterName("DataRate");
52        addParameterName("LaserType");
53        addParameterName("MaxReaders");
54        addParameterName("MinReaders");
55        addParameterName("OptimizeLoss", "TRUE");
56        return;
57    }
58
59    void SWMRLink::initProperties()
60    {
61        addPropertyName("Length");
62		addPropertyName("OptUtil", 0.5);        // default to 50% utilization (a new word 50% of the time)
63        addPropertyName("ExtinctionRatio", 6);  // default properties
64        addPropertyName("InsertionLoss", 2);    // default properties
65        return;
66    }
67
68    void SWMRLink::constructModel()
69    {
70        // Get parameters
71        unsigned int number_wavelengths = getParameter("NumberWavelengths");
72        unsigned int number_readers = getParameter("NumberReaders");
73        unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt());
74        unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt());
75
76        // Create electrical ports
77        createInputPort("CK");
78        createInputPort("In", makeNetIndex(0, number_wavelengths-1));
79        for (unsigned int i = 0; i < number_readers; ++i)
80            createOutputPort("Out" + (String) i, makeNetIndex(0, number_wavelengths-1));
81
82        // Create Waveguides
83        // Temporarily assume its all on one waveguide
84        createWaveguide("LaserToMod", makeWavelengthGroup(0, number_wavelengths-1));
85        for (unsigned int i = 0; i <= number_readers; ++i)
86            createWaveguide("WaveguideSegment[" + (String) i + "]", makeWavelengthGroup(0, number_wavelengths-1));
87
88        // Add area results
89        addAreaResult(new Result("Photonic"));
90        createElectricalResults();
91        // Setup idle event
92        getEventInfo("Idle")->setStaticTransitionInfos();
93        // Create a waveguide area result
94        addAreaResult(new AtomicResult("Waveguide"));
95        getAreaResult("Photonic")->addSubResult(getAreaResult("Waveguide"), "Waveguide", 1.0);
96        // Add results
97        addNddPowerResult(new Result("Laser"));
98        // Add event result
99        createElectricalEventResult("BroadcastFlit");
100
101        for (unsigned int i = number_min_readers; i <= number_max_readers; ++i)
102            createElectricalEventResult("MulticastFlit" + (String) i);
103
104        buildLaser();
105        buildModulator();
106        buildDetectors();
107
108        return;
109    }
110
111    void SWMRLink::updateModel()
112    {
113        // Get parameters
114        double data_rate = getParameter("DataRate");
115        unsigned int number_readers = getParameter("NumberReaders");
116
117        // Get properties
118        double length = getProperty("Length");
119        const String& extinction_ratio = getProperty("ExtinctionRatio");
120        const String& insertion_loss = getProperty("InsertionLoss");
121		const double opt_util = getProperty("OptUtil");
122
123        // Calculate loss for each waveguide segment
124        double segment_length = (double) length / number_readers;
125        double segment_loss = getTechModel()->get("Waveguide->LossPerMeter").toDouble() * segment_length;
126        // Set loss of each waveguide segment
127        for (unsigned int i = 0; i < number_readers; ++i)
128            getWaveguide("WaveguideSegment[" + (String) i + "]")->setLoss(segment_loss);
129        // Calculate waveguide area
130        double waveguide_area = length * getTechModel()->get("Waveguide->Pitch").toDouble();
131        getAreaResult("Waveguide")->setValue(waveguide_area);
132
133        // Update the laser
134        Model* laser = getSubInstance("Laser");
135        laser->setProperty("LaserEventTime", 1.0 / data_rate);
136        laser->setProperty("OptUtil", opt_util);
137        laser->update();
138
139        // Update the modulator
140        Model* modulator = getSubInstance("Modulator");
141        modulator->setProperty("ExtinctionRatio", extinction_ratio);
142        modulator->setProperty("InsertionLoss", insertion_loss);
143        modulator->update();
144
145        // Update all receivers
146        for (unsigned int i = 0; i < number_readers; ++i)
147        {
148            Model* detector = getSubInstance("Detector_" + (String) i);
149            detector->update();
150        }
151
152        return;
153    }
154
155    void SWMRLink::propagateTransitionInfo()
156    {
157        // Get parameters
158        const String& laser_type = getParameter("LaserType");
159        unsigned int number_readers = getParameter("NumberReaders");
160
161        // Set transition info for the modulator
162        OpticalModel* modulator = (OpticalModel*) getSubInstance("Modulator");
163        propagatePortTransitionInfo(modulator, "In", "In");
164        modulator->use();
165
166        // Modulator out transition info
167        const TransitionInfo& mod_out_transitions = modulator->getOpticalOutputPort("Out")->getTransitionInfo();
168
169        // Set transition info for all receivers
170        for (unsigned int i = 0; i < number_readers; ++i)
171        {
172            OpticalModel* detector = (OpticalModel*) getSubInstance("Detector_" + (String) i);
173            detector->getOpticalInputPort("In")->setTransitionInfo(mod_out_transitions);
174            detector->use();
175
176            // Propagate output transition info to output
177            propagatePortTransitionInfo("Out" + (String) i, detector, "Out");
178        }
179
180        // Set enable signals for the laser, if applicable
181        if (laser_type == "Throttled")
182        {
183            // Figure out how many cycles the laser needs to be on
184            double cycles = getInputPort("In")->getTransitionInfo().getFrequencyMultiplier();
185
186            OpticalModel* laser = (OpticalModel*) getSubInstance("Laser");
187            laser->getInputPort("LaserEnable")->setTransitionInfo(TransitionInfo(0.0, 1.0, cycles - 1.0));
188            laser->use();
189        }
190        return;
191    }
192
193    void SWMRLink::buildLaser()
194    {
195        // Get parameters
196        unsigned int number_wavelengths = getParameter("NumberWavelengths");
197        unsigned int number_readers = getParameter("NumberReaders");
198        unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt());
199        unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt());
200        const String& laser_type = getParameter("LaserType");
201
202        // Create laser
203        OpticalModel* laser = NULL;
204        if (laser_type == "Throttled")
205            laser = new ThrottledLaserSource("Laser", getTechModel());
206        else if (laser_type == "Standard")
207            laser = new LaserSource("Laser", getTechModel());
208        else
209            ASSERT(false, "[Error] " + getInstanceName() + " -> Unknown laser type '" + laser_type + "'!");
210
211        laser->setParameter("OutStart", 0);
212        laser->setParameter("OutEnd", number_wavelengths-1);
213        laser->setParameter("MaxDetectors", number_max_readers);
214        laser->setParameter("MinDetectors", number_min_readers);
215        laser->construct();
216
217        addSubInstances(laser, 1.0);
218        getAreaResult("Photonic")->addSubResult(laser->getAreaResult("Photonic"), "Laser", 1.0);
219        // Connect laser output port
220        opticalPortConnect(laser, "Out", "LaserToMod");
221
222        // Without laser gating, laser is pure NDD power
223        if (laser_type == "Standard")
224            getNddPowerResult("Laser")->addSubResult(laser->getNddPowerResult("Laser"), "Laser", 1.0);
225        // With laser power gating, laser is an event
226        else
227        {
228            // If laser is throttled, only pay for the amount needed to reach some number of readers
229            getEventResult("BroadcastFlit")->addSubResult(laser->getEventResult("Laser" + (String) number_max_readers), "Laser", 1.0);
230            for (unsigned int i = number_min_readers; i <= number_max_readers; ++i)
231                getEventResult("MulticastFlit" + (String) i)->addSubResult(laser->getEventResult("Laser" + (String) i), "Laser", 1.0);
232        }
233
234        return;
235    }
236
237    void SWMRLink::buildModulator()
238    {
239        // Get parameters
240        double data_rate = getParameter("DataRate");
241        const String& optimize_loss = getParameter("OptimizeLoss");
242        unsigned int number_wavelengths = getParameter("NumberWavelengths");
243        unsigned int number_readers = getParameter("NumberReaders");
244        unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt());
245        unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt());
246
247        // Create modulator
248        RingModulator* modulator = new RingModulator("Modulator", getTechModel());
249        modulator->setParameter("DataRate", data_rate);
250        modulator->setParameter("InStart", 0);
251        modulator->setParameter("InEnd", number_wavelengths-1);
252        modulator->setParameter("ModStart", 0);
253        modulator->setParameter("ModEnd", number_wavelengths-1);
254        modulator->setParameter("OptimizeLoss", optimize_loss);
255        modulator->construct();
256        addSubInstances(modulator, 1.0);
257        getAreaResult("Photonic")->addSubResult(modulator->getAreaResult("Photonic"), "Modulator", 1.0);
258        addElectricalSubResults(modulator, 1.0);
259
260        // Connect electrical port
261        portConnect(modulator, "In", "In");
262        // Connect modulator input, output port
263        opticalPortConnect(modulator, "In", "LaserToMod");
264        opticalPortConnect(modulator, "Out", "WaveguideSegment[0]");
265
266        // Add modulator energy event for all broadcast events
267        getEventResult("BroadcastFlit")->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0);
268        for (unsigned int i = number_min_readers; i <= number_max_readers; ++i)
269            getEventResult("MulticastFlit" + (String) i)->addSubResult(modulator->getEventResult("Modulate"), "Modulator", 1.0);
270
271        return;
272    }
273
274    void SWMRLink::buildDetectors()
275    {
276        // Get parameters
277        double data_rate = getParameter("DataRate");
278        unsigned int number_wavelengths = getParameter("NumberWavelengths");
279        unsigned int number_readers = getParameter("NumberReaders");
280        unsigned int number_max_readers = std::min(number_readers, getParameter("MaxReaders").toUInt());
281        unsigned int number_min_readers = std::min(number_max_readers, getParameter("MinReaders").toUInt());
282
283        // Create a SWMR Configuration
284        for (unsigned int i = 0; i < number_readers; ++i)
285        {
286            String n = (String) i;
287
288            // Create resonant ring detector
289            RingDetector* detector = new RingDetector("Detector_" + n, getTechModel());
290            detector->setParameter("DataRate", data_rate);
291            detector->setParameter("InStart", 0);
292            detector->setParameter("InEnd", number_wavelengths-1);
293            detector->setParameter("DetStart", 0);
294            detector->setParameter("DetEnd", number_wavelengths-1);
295            detector->setParameter("DropAll", "FALSE");
296            detector->setParameter("Topology", RingDetector::INTEGRATINGSENSEAMP);
297            detector->construct();
298            addSubInstances(detector, 1.0);
299            getAreaResult("Photonic")->addSubResult(detector->getAreaResult("Photonic"), "Detector_" + n, 1.0);
300            addElectricalSubResults(detector, 1.0);
301
302            // connect to electrical port
303            portConnect(detector, "Out", "Out" + (String) i);
304            // connect optical input, output port
305            opticalPortConnect(detector, "In", "WaveguideSegment[" + (String) i + "]");
306            opticalPortConnect(detector, "Out", "WaveguideSegment[" + (String) (i + 1) + "]");
307        }
308
309        // Add an average receiver energy for all multicast events (and broadcast)
310        Result* broadcast_event = getEventResult("BroadcastFlit");
311        for (unsigned int i = 0; i < number_readers; ++i)
312        {
313            const String detector_name = "Detector_" + (String) i;
314            broadcast_event->addSubResult(getSubInstance(detector_name)->getEventResult("Receive"), detector_name, 1.0);
315        }
316        for (unsigned int i = number_min_readers; i <= number_max_readers; ++i)
317        {
318            Result* multicast_event = getEventResult("MulticastFlit" + (String) i);
319            for (unsigned int j = 0; j < number_readers; ++j)
320            {
321                const String detector_name = "Detector_" + (String) j;
322                multicast_event->addSubResult(getSubInstance(detector_name)->getEventResult("Receive"), detector_name, (double) i / number_readers);
323            }
324        }
325
326        return;
327    }
328
329} // namespace DSENT
330
331