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/DFFRAM.h"
23
24#include <cmath>
25
26#include "model/PortInfo.h"
27#include "model/EventInfo.h"
28#include "model/TransitionInfo.h"
29#include "model/timing_graph/ElectricalDriverMultiplier.h"
30#include "model/timing_graph/ElectricalNet.h"
31#include "model/std_cells/StdCell.h"
32#include "model/std_cells/StdCellLib.h"
33#include "model/electrical/Decoder.h"
34#include "model/electrical/Multiplexer.h"
35
36namespace DSENT
37{
38    using std::ceil;
39
40    DFFRAM::DFFRAM(const String& instance_name_, const TechModel* tech_model_)
41        : ElectricalModel(instance_name_, tech_model_)
42    {
43        initParameters();
44        initProperties();
45    }
46
47    DFFRAM::~DFFRAM()
48    {}
49
50    void DFFRAM::initParameters()
51    {
52        addParameterName("NumberEntries");
53        addParameterName("NumberBits");
54        return;
55    }
56
57    void DFFRAM::initProperties()
58    {
59        return;
60    }
61
62    DFFRAM* DFFRAM::clone() const
63    {
64        // TODO
65        return NULL;
66    }
67
68    void DFFRAM::constructModel()
69    {
70        // Get parameters
71        unsigned int number_bits = getParameter("NumberBits").toUInt();
72        unsigned int number_entries = getParameter("NumberEntries").toUInt();
73
74        ASSERT(number_bits > 0, "[Error] " + getInstanceName() +
75            " -> Number of bits must be > 0!");
76        ASSERT(number_entries > 0, "[Error] " + getInstanceName() +
77            " -> Number of entries must be > 0!");
78
79        unsigned int number_addr_bits = (unsigned int)ceil(log2(number_entries));
80
81        // Create ports
82        createInputPort("In", makeNetIndex(0, number_bits-1));
83        for(unsigned int i = 0; i < number_addr_bits; ++i)
84        {
85            createInputPort("WRAddr" + (String)i);
86            createInputPort("RDAddr" + (String)i);
87        }
88        createInputPort("WE");
89        createInputPort("CK");
90        createOutputPort("Out", makeNetIndex(0, number_bits-1));
91
92        // Create energy, power, and area results
93        createElectricalResults();
94        getEventInfo("Idle")->setStaticTransitionInfos();
95        getEventInfo("Idle")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
96        getEventInfo("Idle")->setTransitionInfo("WE", TransitionInfo(1.0, 0.0, 0.0));
97
98        createElectricalEventResult("Read");
99        getEventInfo("Read")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
100        getEventInfo("Read")->setTransitionInfo("WE", TransitionInfo(1.0, 0.0, 0.0));
101        for(unsigned int i = 0; i < number_addr_bits; ++i)
102        {
103            getEventInfo("Read")->setTransitionInfo("WRAddr" + (String)i, TransitionInfo(0.5, 0.0, 0.5));
104        }
105        createElectricalEventResult("Write");
106        getEventInfo("Write")->setTransitionInfo("CK", TransitionInfo(0.0, 1.0, 0.0));
107        getEventInfo("Write")->setTransitionInfo("WE", TransitionInfo(0.0, 0.0, 1.0));
108        for(unsigned int i = 0; i < number_addr_bits; ++i)
109        {
110            getEventInfo("Write")->setTransitionInfo("RDAddr" + (String)i, TransitionInfo(0.5, 0.0, 0.5));
111        }
112
113        // Init components - DFF array, Dec, Mux
114        vector<String> dff_names(number_entries, "");
115        vector<StdCell*> dffs(number_entries, NULL);
116        for(unsigned int i = 0; i < number_entries; ++i)
117        {
118            dff_names[i] = "DFF_" + (String)i;
119            dffs[i] = getTechModel()->getStdCellLib()->createStdCell("DFFQ", dff_names[i]);
120            dffs[i]->construct();
121        }
122
123        const String& dec_name = "Dec";
124        Decoder* dec = new Decoder(dec_name, getTechModel());
125        dec->setParameter("NumberOutputs", number_entries);
126        dec->construct();
127
128        const String& mux_name = "Mux";
129        Multiplexer* mux = new Multiplexer(mux_name, getTechModel());
130        mux->setParameter("NumberInputs", number_entries);
131        mux->setParameter("NumberBits", 1);
132        mux->setParameter("BitDuplicate", "TRUE");
133        mux->construct();
134
135        // Init components - CK & WE
136        const String& nand2cg0_name = "NAND2_CKGate0";
137        StdCell* nand2cg0 = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2cg0_name);
138        nand2cg0->construct();
139        const String& invcg0_name = "INV_CKGate0";
140        StdCell* invcg0 = getTechModel()->getStdCellLib()->createStdCell("INV", invcg0_name);
141        invcg0->construct();
142
143        // Init components - (CK & WE) & DecOut[i]
144        vector<String> nand2cg1_names(number_entries, "");
145        vector<StdCell*> nand2cg1s(number_entries, NULL);
146        vector<String> invcg1_names(number_entries, "");
147        vector<StdCell*> invcg1s(number_entries, NULL);
148        for(unsigned int i = 0; i < number_entries; ++i)
149        {
150            nand2cg1_names[i] = "NAND2_CKGate1_" + (String)i;
151            nand2cg1s[i] = getTechModel()->getStdCellLib()->createStdCell("NAND2", nand2cg1_names[i]);
152            nand2cg1s[i]->construct();
153
154            invcg1_names[i] = "INV_CKGate1_" + (String)i;
155            invcg1s[i] = getTechModel()->getStdCellLib()->createStdCell("INV", invcg1_names[i]);
156            invcg1s[i]->construct();
157        }
158
159        // Connect Decoder
160        for(unsigned int i = 0; i < number_addr_bits; ++i)
161        {
162            portConnect(dec, "Addr" + (String)i, "WRAddr" + (String)i);
163        }
164        for(unsigned int i = 0; i < number_entries; ++i)
165        {
166            createNet("Dec_Out" + (String)i);
167            portConnect(dec, "Out" + (String)i, "Dec_Out" + (String)i);
168        }
169
170        // Connect CKGate0 - CK, WE
171        createNet("NAND2_CKGate0_Out");
172        createNet("CKGate0_Out");
173        portConnect(nand2cg0, "A", "CK");
174        portConnect(nand2cg0, "B", "WE");
175        portConnect(nand2cg0, "Y", "NAND2_CKGate0_Out");
176        portConnect(invcg0, "A", "NAND2_CKGate0_Out");
177        portConnect(invcg0, "Y", "CKGate0_Out");
178
179        // Connect CKGate1 - CKGate0, Dec_Out
180        for(unsigned int i = 0; i < number_entries; ++i)
181        {
182            createNet("NAND2_CKGate1_Outs" + (String)i);
183            createNet("CKGate1_Outs" + (String)i);
184            portConnect(nand2cg1s[i], "A", "CKGate0_Out");
185            portConnect(nand2cg1s[i], "B", "Dec_Out" + (String)i);
186            portConnect(nand2cg1s[i], "Y", "NAND2_CKGate1_Outs" + (String)i);
187            portConnect(invcg1s[i], "A", "NAND2_CKGate1_Outs" + (String)i);
188            portConnect(invcg1s[i], "Y", "CKGate1_Outs" + (String)i);
189        }
190
191        // Connect DFF array
192        for(unsigned int i = 0; i < number_entries; ++i)
193        {
194            createNet("DFF_Out" + (String)i);
195            for(unsigned int n = 0; n < number_bits; ++n)
196            {
197                portConnect(dffs[i], "D", "In", makeNetIndex(n));
198                portConnect(dffs[i], "CK", "CKGate1_Outs" + (String)i);
199            }
200            portConnect(dffs[i], "Q", "DFF_Out" + (String)i);
201        }
202
203        // Connect Multiplexer
204        createNet("Mux_Out");
205        for(unsigned int i = 0; i < number_entries; ++i)
206        {
207            portConnect(mux, "In" + (String)i, "DFF_Out" + (String)i);
208        }
209        for(unsigned int i = 0; i < number_addr_bits; ++i)
210        {
211            portConnect(mux, "Sel" + (String)i, "RDAddr" + (String)i);
212        }
213        portConnect(mux, "Out", "Mux_Out");
214
215        // Use driver multiplier to connect Mux_Out to Out
216        createDriverMultiplier("OutMult");
217        ElectricalDriverMultiplier* drive_mult = getDriverMultiplier("OutMult");
218        getNet("Mux_Out")->addDownstreamNode(drive_mult);
219        for(unsigned int n = 0; n < number_bits; ++n)
220        {
221            drive_mult->addDownstreamNode(getNet("Out", makeNetIndex(n)));
222        }
223
224        // Add area and power results
225        for(unsigned int i = 0; i < number_entries; ++i)
226        {
227            addSubInstances(dffs[i], number_bits);
228            addElectricalSubResults(dffs[i], number_bits);
229        }
230
231        addSubInstances(dec, 1.0);
232        addElectricalSubResults(dec, 1.0);
233
234        addSubInstances(mux, number_bits);
235        addElectricalSubResults(mux, number_bits);
236
237        addSubInstances(nand2cg0, 1.0);
238        addElectricalSubResults(nand2cg0, 1.0);
239
240        addSubInstances(invcg0, 1);
241        addElectricalSubResults(invcg0, 1.0);
242
243        for(unsigned int i = 0; i < number_entries; ++i)
244        {
245            addSubInstances(nand2cg1s[i], 1);
246            addElectricalSubResults(nand2cg1s[i], 1.0);
247
248            addSubInstances(invcg1s[i], 1);
249            addElectricalSubResults(invcg1s[i], 1.0);
250        }
251
252        // Add write event
253        Result* write_event = getEventResult("Write");
254        write_event->addSubResult(nand2cg0->getEventResult("NAND2"), nand2cg0_name, 1.0);
255        write_event->addSubResult(invcg0->getEventResult("INV"), invcg0_name, 1.0);
256        write_event->addSubResult(dec->getEventResult("Decode"), dec_name, 1.0);
257        for(unsigned int i = 0; i < number_entries; ++i)
258        {
259            write_event->addSubResult(nand2cg1s[i]->getEventResult("NAND2"), nand2cg1_names[i], 1.0);
260            write_event->addSubResult(invcg1s[i]->getEventResult("INV"), invcg1_names[i], 1.0);
261            write_event->addSubResult(dffs[i]->getEventResult("DFFD"), dff_names[i], number_bits);
262            write_event->addSubResult(dffs[i]->getEventResult("DFFQ"), dff_names[i], number_bits);
263            write_event->addSubResult(dffs[i]->getEventResult("CK"), dff_names[i], number_bits);
264        }
265
266        // Add read event
267        Result* read_event = getEventResult("Read");
268        //for(unsigned int i = 0; i < number_entries; ++i)
269        //{
270        //    read_event->addSubResult(dffs[i]->getEventResult("DFFQ"), dff_names[i], number_bits);
271        //}
272        read_event->addSubResult(mux->getEventResult("Mux"), mux_name, number_bits);
273
274        return;
275    }
276
277    void DFFRAM::propagateTransitionInfo()
278    {
279        // Update probability
280        unsigned int number_entries = (unsigned int)getParameter("NumberEntries");
281        unsigned int number_addr_bits = (unsigned int)ceil(log2(number_entries));
282
283        // Update decoder
284        ElectricalModel* dec = (ElectricalModel*)getSubInstance("Dec");
285        for(unsigned int i = 0; i < number_addr_bits; ++i)
286        {
287            propagatePortTransitionInfo(dec, "Addr" + (String)i, "WRAddr" + (String)i);
288        }
289        dec->use();
290
291        // Update CKGate0 nands + invs
292        ElectricalModel* nand2cg0 = (ElectricalModel*)getSubInstance("NAND2_CKGate0");
293        propagatePortTransitionInfo(nand2cg0, "A", "CK");
294        propagatePortTransitionInfo(nand2cg0, "B", "WE");
295        nand2cg0->use();
296        ElectricalModel* invcg0 = (ElectricalModel*)getSubInstance("INV_CKGate0");
297        propagatePortTransitionInfo(invcg0, "A", nand2cg0, "Y");
298        invcg0->use();
299
300        // Update CKGate1 nands + invs
301        vector<ElectricalModel*> nand2cg1s(number_entries, NULL);
302        vector<ElectricalModel*> invcg1s(number_entries, NULL);
303        for(unsigned int i = 0; i < number_entries; ++i)
304        {
305            nand2cg1s[i] = (ElectricalModel*)getSubInstance("NAND2_CKGate1_" + (String)i);
306            propagatePortTransitionInfo(nand2cg1s[i], "A", invcg0, "Y");
307            propagatePortTransitionInfo(nand2cg1s[i], "B", dec, "Out" + (String)i);
308            nand2cg1s[i]->use();
309
310            invcg1s[i] = (ElectricalModel*)getSubInstance("INV_CKGate1_" + (String)i);
311            propagatePortTransitionInfo(invcg1s[i], "A", nand2cg1s[i], "Y");
312            invcg1s[i]->use();
313        }
314
315        // Update DFF
316        vector<ElectricalModel*> dffs(number_entries, NULL);
317        for(unsigned int i = 0; i < number_entries; ++i)
318        {
319            dffs[i] = (ElectricalModel*)getSubInstance("DFF_" + (String)i);
320            propagatePortTransitionInfo(dffs[i], "D", "In");
321            propagatePortTransitionInfo(dffs[i], "CK", invcg1s[i], "Y");
322            dffs[i]->use();
323        }
324
325        // Update Mux
326        ElectricalModel* mux = (ElectricalModel*)getSubInstance("Mux");
327        for(unsigned int i = 0; i < number_entries; ++i)
328        {
329            propagatePortTransitionInfo(mux, "In" + (String)i, dffs[i], "Q");
330        }
331        for(unsigned int i = 0; i < number_addr_bits; ++i)
332        {
333            propagatePortTransitionInfo(mux, "Sel" + (String)i, "RDAddr" + (String)i);
334        }
335        mux->use();
336
337        // Set output probability
338        getOutputPort("Out")->setTransitionInfo(mux->getOutputPort("Out")->getTransitionInfo());
339        return;
340    }
341} // namespace DSENT
342
343