blob: ae59ef7c8d2399090dd6ee928638ccd563f4e152 [file] [log] [blame]
/* Copyright (c) 2012 Massachusetts Institute of Technology
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "model/electrical/SeparableAllocator.h"
#include "model/ModelGen.h"
#include "model/timing_graph/ElectricalNet.h"
namespace DSENT
{
SeparableAllocator::SeparableAllocator(const String& instance_name_, const TechModel* tech_model_)
: ElectricalModel(instance_name_, tech_model_)
{
initParameters();
initProperties();
}
SeparableAllocator::~SeparableAllocator()
{}
void SeparableAllocator::initParameters()
{
addParameterName("NumberRequesters");
addParameterName("NumberResources");
addParameterName("IsRequesterFirst", true);
addParameterName("Stage1->ArbiterModel");
addParameterName("Stage2->ArbiterModel");
return;
}
void SeparableAllocator::initProperties()
{
addPropertyName("P(Request)");
addPropertyName("Act(Request)");
addPropertyName("P(CK)");
addPropertyName("Act(CK)");
return;
}
SeparableAllocator* SeparableAllocator::clone() const
{
// TODO
return NULL;
}
void SeparableAllocator::constructModel()
{
// Get parameters
unsigned int number_requesters = getParameter("NumberRequesters").toUInt();
unsigned int number_resources = getParameter("NumberResources").toUInt();
bool is_requester_first = getParameter("IsRequesterFirst").toBool();
const String& stage1_arbiter_model = getParameter("Stage1->ArbiterModel");
const String& stage2_arbiter_model = getParameter("Stage2->ArbiterModel");
ASSERT(number_requesters > 0, "[Error] " + getInstanceName() +
" -> Number of requesters must be > 0!");
ASSERT(number_resources > 0, "[Error] " + getInstanceName() +
" -> Number of resources must be > 0!");
// Create area, power, and event results
createElectricalResults();
addEventResult(new Result("Allocate"));
// Create ports
createInputPort("CK");
for(unsigned int i = 0; i < number_requesters; ++i)
{
createInputPort("Request" + (String)i, makeNetIndex(0, number_resources-1));
createOutputPort("Grant" + (String)i, makeNetIndex(0, number_resources-1));
}
// If is_requester_first is set, requests from the same requester will be arbitrate
// on stage 1
if(is_requester_first)
{
// Init stage 1 arbiters
for(unsigned int i = 0; i < number_requesters; ++i)
{
ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel());
arb->setParameter("NumberRequests", number_resources);
arb->construct();
addSubInstances(arb, 1.0);
addElectricalSubResults(arb, 1.0);
getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_resources-1));
createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_resources-1));
portConnect(arb, "CK", "CK");
assign("Stage1Arb_In" + (String)i, "Request" + (String)i);
for(unsigned int j = 0; j < number_resources; ++j)
{
portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j));
portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j));
}
}
// Init stage 2 arbiters
for(unsigned int i = 0; i < number_resources; ++i)
{
ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel());
arb->setParameter("NumberRequests", number_requesters);
arb->construct();
addSubInstances(arb, 1.0);
addElectricalSubResults(arb, 1.0);
getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_requesters-1));
createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1));
portConnect(arb, "CK", "CK");
for(unsigned int j = 0; j < number_requesters; ++j)
{
assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i));
portConnect(arb, "Request" + (String)j, "Stage2Arb_In" + (String)i, makeNetIndex(j));
portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out" + (String)i, makeNetIndex(j));
assign("Grant" + (String)j, makeNetIndex(i), "Stage2Arb_Out" + (String)i, makeNetIndex(j));
}
}
}
else
{
// Init stage 1 arbiters
for(unsigned int i = 0; i < number_resources; ++i)
{
ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage1_arbiter_model, "Stage1Arb" + (String)i, getTechModel());
arb->setParameter("NumberRequests", number_requesters);
arb->construct();
addSubInstances(arb, 1.0);
addElectricalSubResults(arb, 1.0);
getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
createNet("Stage1Arb_In" + (String)i, makeNetIndex(0, number_requesters-1));
createNet("Stage1Arb_Out" + (String)i, makeNetIndex(0, number_requesters-1));
portConnect(arb, "CK", "CK");
for(unsigned int j = 0; j < number_requesters; ++j)
{
assign("Stage1Arb_In" + (String)i, makeNetIndex(j), "Request" + (String)j, makeNetIndex(i));
portConnect(arb, "Request" + (String)j, "Stage1Arb_In" + (String)i, makeNetIndex(j));
portConnect(arb, "Grant" + (String)j, "Stage1Arb_Out" + (String)i, makeNetIndex(j));
}
}
// Init stage 2 arbiters
for(unsigned int i = 0; i < number_requesters; ++i)
{
ElectricalModel* arb = (ElectricalModel*)ModelGen::createModel(stage2_arbiter_model, "Stage2Arb" + (String)i, getTechModel());
arb->setParameter("NumberRequests", number_requesters);
arb->construct();
addSubInstances(arb, 1.0);
addElectricalSubResults(arb, 1.0);
getEventResult("Allocate")->addSubResult(arb->getEventResult("Arbitrate"), arb->getInstanceName(), 1.0);
createNet("Stage2Arb_In" + (String)i, makeNetIndex(0, number_resources-1));
createNet("Stage2Arb_Out" + (String)i, makeNetIndex(0, number_resources-1));
portConnect(arb, "CK", "CK");
for(unsigned int j = 0; j < number_resources; ++j)
{
assign("Stage2Arb_In" + (String)i, makeNetIndex(j), "Stage1Arb_Out" + (String)j, makeNetIndex(i));
portConnect(arb, "Request" + (String)j, "Stage2Arb_In", makeNetIndex(j));
portConnect(arb, "Grant" + (String)j, "Stage2Arb_Out", makeNetIndex(j));
}
assign("Grant" + (String)i, "Stage2Arb_Out" + (String)i);
}
}
return;
}
void SeparableAllocator::updateModel()
{
// Get parameters
unsigned int number_requesters = getParameter("NumberRequesters").toUInt();
unsigned int number_resources = getParameter("NumberResources").toUInt();
bool is_requester_first = getParameter("IsRequesterFirst").toBool();
// Get probabilities from inputs
const String& P_request = getProperty("P(Request)");
const String& act_request = getProperty("Act(Request)");
const String& P_CK = getProperty("P(CK)");
const String& act_CK = getProperty("Act(CK)");
const vector<double>& P_request_vector = LibUtil::castStringVector<double>(P_request.split("[,]"));
const vector<double>& act_request_vector = LibUtil::castStringVector<double>(act_request.split("[,]"));
ASSERT(P_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() +
" -> Expecting " + (String)(number_requesters * number_resources) +
" request probabilities, but got " + P_request);
ASSERT(act_request_vector.size() == (number_requesters * number_resources), "[Error] " + getInstanceName() +
" -> Expecting " + (String)(number_requesters * number_resources) +
" request actvities multiplier, but got " + act_request);
vector<double> P_int_request_vector(number_requesters * number_resources, 0.0);
vector<double> act_int_request_vector(number_requesters * number_resources, 0.0);
vector<double> P_out_request_vector(number_requesters * number_resources, 0.0);
vector<double> act_out_request_vector(number_requesters * number_resources, 0.0);
if(is_requester_first)
{
// Update stage1 arbiter
for(unsigned int i = 0; i < number_requesters; ++i)
{
vector<double> P_arb_request_vector(number_resources, 0.0);
vector<double> act_arb_request_vector(number_resources, 0.0);
for(unsigned int j = 0; j < number_resources; ++j)
{
P_arb_request_vector[j] = P_request_vector[i * number_resources + j];
act_arb_request_vector[j] = act_request_vector[i * number_resources + j];
}
Model* arb = getSubInstance("Stage1Arb" + (String)i);
arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector));
arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector));
arb->setProperty("P(CK)", P_CK);
arb->setProperty("Act(CK)", act_CK);
arb->update();
const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]"));
const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]"));
for(unsigned int j = 0; j < number_resources; ++j)
{
P_int_request_vector[i * number_resources + j] = P_arb_out_request_vector[j];
act_int_request_vector[i * number_resources + j] = act_arb_out_request_vector[j];
}
}
// Update stage2 arbiter
for(unsigned int i = 0; i < number_resources; ++i)
{
vector<double> P_arb_request_vector(number_requesters, 0.0);
vector<double> act_arb_request_vector(number_requesters, 0.0);
for(unsigned int j = 0; j < number_requesters; ++j)
{
P_arb_request_vector[j] = P_int_request_vector[j * number_resources + i];
act_arb_request_vector[j] = act_int_request_vector[j * number_resources + i];
}
Model* arb = getSubInstance("Stage2Arb" + (String)i);
arb->setProperty("P(Request)", LibUtil::vectorToString(P_arb_request_vector));
arb->setProperty("Act(Request)", LibUtil::vectorToString(act_arb_request_vector));
arb->setProperty("P(CK)", P_CK);
arb->setProperty("Act(CK)", act_CK);
arb->update();
const vector<double>& P_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("P(Grant)").split("[,]"));
const vector<double>& act_arb_out_request_vector = LibUtil::castStringVector<double>(arb->getGenProperties()->get("Act(Grant)").split("[,]"));
for(unsigned int j = 0; j < number_requesters; ++j)
{
P_out_request_vector[j * number_resources + i] = P_arb_out_request_vector[j];
act_out_request_vector[j * number_resources + i] = act_arb_out_request_vector[j];
}
}
}
else
{
}
// Update output probabilities
getGenProperties()->set("P(Grant)", LibUtil::vectorToString(P_out_request_vector));
getGenProperties()->set("Act(Grant)", LibUtil::vectorToString(act_out_request_vector));
return;
}
} // namespace DSENT