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/SeparableAllocator.h"
23
24#include "model/ModelGen.h"
25#include "model/timing_graph/ElectricalNet.h"
26
27namespace DSENT
28{
29    SeparableAllocator::SeparableAllocator(const String& instance_name_, const TechModel* tech_model_)
30        : ElectricalModel(instance_name_, tech_model_)
31    {
32        initParameters();
33        initProperties();
34    }
35
36    SeparableAllocator::~SeparableAllocator()
37    {}
38
39    void SeparableAllocator::initParameters()
40    {
41        addParameterName("NumberRequesters");
42        addParameterName("NumberResources");
43        addParameterName("IsRequesterFirst", true);
44        addParameterName("Stage1->ArbiterModel");
45        addParameterName("Stage2->ArbiterModel");
46        return;
47    }
48
49    void SeparableAllocator::initProperties()
50    {
51        addPropertyName("P(Request)");
52        addPropertyName("Act(Request)");
53        addPropertyName("P(CK)");
54        addPropertyName("Act(CK)");
55        return;
56    }
57
58    SeparableAllocator* SeparableAllocator::clone() const
59    {
60        // TODO
61        return NULL;
62    }
63
64    void SeparableAllocator::constructModel()
65    {
66        // Get parameters
67        unsigned int number_requesters = getParameter("NumberRequesters").toUInt();
68        unsigned int number_resources = getParameter("NumberResources").toUInt();
69        bool is_requester_first = getParameter("IsRequesterFirst").toBool();
70        const String& stage1_arbiter_model = getParameter("Stage1->ArbiterModel");
71        const String& stage2_arbiter_model = getParameter("Stage2->ArbiterModel");
72
73        ASSERT(number_requesters > 0, "[Error] " + getInstanceName() +
74                " -> Number of requesters must be > 0!");
75        ASSERT(number_resources > 0, "[Error] " + getInstanceName() +
76                " -> Number of resources must be > 0!");
77
78        // Create area, power, and event results
79        createElectricalResults();
80        addEventResult(new Result("Allocate"));
81
82        // Create ports
83        createInputPort("CK");
84        for(unsigned int i = 0; i < number_requesters; ++i)
85        {
86            createInputPort("Request" + (String)i, makeNetIndex(0, number_resources-1));
87            createOutputPort("Grant" + (String)i, makeNetIndex(0, number_resources-1));
88        }
89
90        // If is_requester_first is set, requests from the same requester will be arbitrate
91        // on stage 1
92        if(is_requester_first)
93        {
94            // Init stage 1 arbiters
95            for(unsigned int i = 0; i < number_requesters; ++i)
96            {
97                ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel());
98                arb->setParameter("NumberRequests", number_resources);
99                arb->construct();
100
101                addSubInstances(arb, 1.0);
102                addElectricalSubResults(arb, 1.0);
103
104                getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
105
106                createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_resources-1));
107                createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_resources-1));
108
109                portConnect(arb, "CK", "CK");
110                assign("Stage1Arb_In" + (String)i, "Request" + (String)i);
111                for(unsigned int j = 0; j < number_resources; ++j)
112                {
113                    portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j));
114                    portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j));
115                }
116            }
117
118            // Init stage 2 arbiters
119            for(unsigned int i = 0; i < number_resources; ++i)
120            {
121                ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel());
122                arb->setParameter("NumberRequests", number_requesters);
123                arb->construct();
124
125                addSubInstances(arb, 1.0);
126                addElectricalSubResults(arb, 1.0);
127
128                getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
129
130                createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_requesters-1));
131                createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1));
132
133                portConnect(arb, "CK", "CK");
134                for(unsigned int j = 0; j < number_requesters; ++j)
135                {
136                    assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i));
137                    portConnect(arb, "Request" + (String)j, "Stage2Arb_In" + (String)i, makeNetIndex(j));
138                    portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out" + (String)i, makeNetIndex(j));
139                    assign("Grant" + (String)j, makeNetIndex(i), "Stage2Arb_Out" + (String)i, makeNetIndex(j));
140                }
141            }
142        }
143        else
144        {
145            // Init stage 1 arbiters
146            for(unsigned int i = 0; i < number_resources; ++i)
147            {
148                ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel());
149                arb->setParameter("NumberRequests", number_requesters);
150                arb->construct();
151
152                addSubInstances(arb, 1.0);
153                addElectricalSubResults(arb, 1.0);
154
155                getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
156
157                createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_requesters-1));
158                createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1));
159
160                portConnect(arb, "CK", "CK");
161                for(unsigned int j = 0; j < number_requesters; ++j)
162                {
163                    assign("Stage1Arb_In" + (String)i, makeNetIndex(j), "Request" + (String)j, makeNetIndex(i));
164                    portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j));
165                    portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j));
166                }
167            }
168
169            // Init stage 2 arbiters
170            for(unsigned int i = 0; i < number_requesters; ++i)
171            {
172                ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel());
173                arb->setParameter("NumberRequests", number_requesters);
174                arb->construct();
175
176                addSubInstances(arb, 1.0);
177                addElectricalSubResults(arb, 1.0);
178
179                getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
180
181                createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_resources-1));
182                createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_resources-1));
183
184                portConnect(arb, "CK", "CK");
185                for(unsigned int j = 0; j < number_resources; ++j)
186                {
187                    assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i));
188                    portConnect(arb, "Request" + (String)j, "Stage2Arb_In", makeNetIndex(j));
189                    portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out", makeNetIndex(j));
190                }
191                assign("Grant" + (String)i, "Stage2Arb_Out" + (String)i);
192            }
193        }
194        return;
195    }
196
197    void SeparableAllocator::updateModel()
198    {
199        // Get parameters
200        unsigned int number_requesters = getParameter("NumberRequesters").toUInt();
201        unsigned int number_resources = getParameter("NumberResources").toUInt();
202        bool is_requester_first = getParameter("IsRequesterFirst").toBool();
203
204        // Get probabilities from inputs
205        const String& P_request = getProperty("P(Request)");
206        const String& act_request = getProperty("Act(Request)");
207        const String& P_CK = getProperty("P(CK)");
208        const String& act_CK = getProperty("Act(CK)");
209
210        const vector<double>& P_request_vector = LibUtil::castStringVector<double>(P_request.split("[,]"));
211        const vector<double>& act_request_vector = LibUtil::castStringVector<double>(act_request.split("[,]"));
212
213        ASSERT(P_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() +
214                " -> Expecting " + (String)(number_requesters * number_resources) +
215                " request probabilities, but got " + P_request);
216        ASSERT(act_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() +
217                " -> Expecting " + (String)(number_requesters * number_resources) +
218                " request actvities multiplier, but got " + act_request);
219
220        vector<double> P_int_request_vector(number_requesters * number_resources, 0.0);
221        vector<double> act_int_request_vector(number_requesters * number_resources, 0.0);
222        vector<double> P_out_request_vector(number_requesters * number_resources, 0.0);
223        vector<double> act_out_request_vector(number_requesters * number_resources, 0.0);
224        if(is_requester_first)
225        {
226            // Update stage1 arbiter
227            for(unsigned int i = 0; i < number_requesters; ++i)
228            {
229                vector<double> P_arb_request_vector(number_resources, 0.0);
230                vector<double> act_arb_request_vector(number_resources, 0.0);
231                for(unsigned int j = 0; j < number_resources; ++j)
232                {
233                    P_arb_request_vector[j] = P_request_vector[i * number_resources + j];
234                    act_arb_request_vector[j] = act_request_vector[i * number_resources + j];
235                }
236
237                Model* arb = getSubInstance("Stage1Arb" + (String)i);
238                arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector));
239                arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector));
240                arb->setProperty("P(CK)", P_CK);
241                arb->setProperty("Act(CK)", act_CK);
242                arb->update();
243
244                const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]"));
245                const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]"));
246                for(unsigned int j = 0; j < number_resources; ++j)
247                {
248                    P_int_request_vector[i * number_resources + j] = P_arb_out_request_vector[j];
249                    act_int_request_vector[i * number_resources + j] = act_arb_out_request_vector[j];
250                }
251            }
252            // Update stage2 arbiter
253            for(unsigned int i = 0; i < number_resources; ++i)
254            {
255                vector<double> P_arb_request_vector(number_requesters, 0.0);
256                vector<double> act_arb_request_vector(number_requesters, 0.0);
257                for(unsigned int j = 0; j < number_requesters; ++j)
258                {
259                    P_arb_request_vector[j] = P_int_request_vector[j * number_resources + i];
260                    act_arb_request_vector[j] = act_int_request_vector[j * number_resources + i];
261                }
262
263                Model* arb = getSubInstance("Stage2Arb" + (String)i);
264                arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector));
265                arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector));
266                arb->setProperty("P(CK)", P_CK);
267                arb->setProperty("Act(CK)", act_CK);
268                arb->update();
269
270                const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]"));
271                const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]"));
272                for(unsigned int j = 0; j < number_requesters; ++j)
273                {
274                    P_out_request_vector[j * number_resources + i] = P_arb_out_request_vector[j];
275                    act_out_request_vector[j * number_resources + i] = act_arb_out_request_vector[j];
276                }
277            }
278        }
279        else
280        {
281
282        }
283
284        // Update output probabilities
285        getGenProperties()->set("P(Grant)", LibUtil::vectorToString(P_out_request_vector));
286        getGenProperties()->set("Act(Grant)", LibUtil::vectorToString(act_out_request_vector));
287
288        return;
289    }
290} // namespace DSENT
291
292