1 #include "FunctionalBlock.h"
\r
2 #include "ReferenceBlock.h"
\r
3 #include "GroupBlock.h"
\r
4 #include "AbstractInterface.h"
\r
5 #include "FunctionalInterface.h"
\r
6 #include "ReferenceInterface.h"
\r
7 #include "BlockParameter.h"
\r
8 #include "ArithmeticEvaluator.h"
\r
11 FunctionalBlock::FunctionalBlock(GroupBlock *_parent, ReferenceBlock *_reference) throw(Exception) : AbstractBlock() {
\r
12 //if (! _reference->isReferenceBlock()) throw(Exception(BLOCK_INVALID_TYPE));
\r
13 //if (! _group->isGroupBlock()) throw(Exception(BLOCK_INVALID_TYPE));
\r
14 reference = _reference;
\r
16 name = reference->getName();
\r
17 consumptionPattern = NULL;
\r
19 nbConsumingPorts = 0;
\r
20 productionPattern = NULL;
\r
22 nbProducingPorts = 0;
\r
23 if (reference->getImplementations().isEmpty()) {
\r
24 implementation = NULL;
\r
25 cout << "block has no implementation" << endl;
\r
28 implementation = reference->getImplementations().at(0);
\r
33 void FunctionalBlock::parametersValidation(QList<AbstractBlock*>* checkedBlocks, QList<AbstractBlock *> *blocksToConfigure) {
\r
35 checkedBlocks->append(this);
\r
37 foreach(BlockParameter* param, params){
\r
38 if(param->isUserParameter() && !param->isValueSet()){
\r
39 if(!blocksToConfigure->contains(param->getOwner())){
\r
40 blocksToConfigure->append(param->getOwner());
\r
44 foreach(AbstractInterface *inter, outputs){
\r
45 foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){
\r
46 if(!checkedBlocks->contains(connectedInter->getOwner())){
\r
47 connectedInter->getOwner()->parametersValidation(checkedBlocks, blocksToConfigure);
\r
54 bool FunctionalBlock::isFunctionalBlock() {
\r
58 bool FunctionalBlock::isSourceBlock() {
\r
59 if (parent == NULL) return true;
\r
63 void FunctionalBlock::populate() {
\r
66 AbstractInterface* inter;
\r
68 // create parameters from reference block
\r
69 QList<BlockParameter*> lstParam = reference->getParameters();
\r
70 for(i=0;i<lstParam.size();i++) {
\r
71 p = lstParam.at(i)->clone();
\r
75 // create interfaces from reference block
\r
76 QList<AbstractInterface *> lstRef = reference->getInterfaces();
\r
77 // store relation between functional and reference
\r
78 QHash<AbstractInterface *, AbstractInterface *> hashIface;
\r
79 for(i=0;i<lstRef.size();i++) {
\r
81 inter = new FunctionalInterface(this, AI_TO_REF(lstRef.at(i)));
\r
83 catch(Exception e) {
\r
84 cerr << "Abnormal case: " << qPrintable(e.getDefaultMessage()) << endl << "Aborting execution." << endl;
\r
87 hashIface.insert(lstRef.at(i),inter);
\r
89 addInterface(inter);
\r
92 AbstractInterface* funCtlIface = NULL;
\r
93 AbstractInterface* funDataIface = NULL;
\r
95 for(i=0;i<lstRef.size();i++) {
\r
96 AbstractInterface* refIface = lstRef.at(i);
\r
97 if (refIface->getPurpose() == AbstractInterface::Control) {
\r
98 funCtlIface = hashIface.value(refIface);
\r
99 funDataIface = hashIface.value(refIface->getAssociatedIface());
\r
100 if (! funCtlIface->setAssociatedIface(funDataIface)) {
\r
101 cerr << "Abnormal case when associating a control interface to data" << endl << "Aborting execution." << endl;
\r
109 QString FunctionalBlock::getReferenceXmlFile() {
\r
110 return ((ReferenceBlock *)reference)->getXmlFile();
\r
113 QString FunctionalBlock::getReferenceHashMd5() {
\r
114 return ((ReferenceBlock *)reference)->getHashMd5();
\r
117 bool FunctionalBlock::createPatterns() {
\r
118 static QString fctName = "FunctionalBlock::createPatterns()";
\r
119 #ifdef DEBUG_FCTNAME
\r
120 cout << "call to " << qPrintable(fctName) << endl;
\r
123 cout << "create patterns for block " << qPrintable(name) << endl;
\r
124 evaluator = new ArithmeticEvaluator();
\r
126 ok = ok & createDelta();
\r
127 if (! isGeneratorBlock()) {
\r
128 if (ok) ok = ok & createConsumptionPattern();
\r
129 if (ok) ok = ok & createProductionCounter();
\r
131 if (ok) ok = ok & createProductionPattern();
\r
136 bool FunctionalBlock::createDelta() {
\r
137 static QString fctName = "FunctionalBlock::createDelta()";
\r
138 #ifdef DEBUG_FCTNAME
\r
139 cout << "call to " << qPrintable(fctName) << endl;
\r
142 QString deltaStr = implementation->getDelta();
\r
143 cout << "delta for " << qPrintable(name) << " = " << qPrintable(deltaStr) << endl;
\r
145 // look for parameter names
\r
147 double result = evaluateExpression(deltaStr, &ok);
\r
148 if (!ok) return false;
\r
151 cout << "delta = " << delta << endl;
\r
156 bool FunctionalBlock::createConsumptionPattern() {
\r
157 static QString fctName = "FunctionalBlock::createConsumptionPattern()";
\r
158 #ifdef DEBUG_FCTNAME
\r
159 cout << "call to " << qPrintable(fctName) << endl;
\r
163 QHash<QString,QString> consPattern = implementation->getConsumptionPattern();
\r
165 foreach(AbstractInterface* iface, getControlInputs()) {
\r
166 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
167 QString refName = connIface->getReference()->getName();
\r
168 if (! consPattern.contains(refName)) {
\r
169 cerr << "no consumption pattern for reference interface " << qPrintable(refName) << endl;
\r
172 QList<char> pattern = expandPattern(consPattern.value(refName),&ok);
\r
174 if (!ok) return false;
\r
175 connIface->setConsumptionPattern(pattern);
\r
176 cout << qPrintable(refName) << " consumption pattern = ";
\r
177 foreach(char c, pattern) {
\r
178 cout << (int)c << " ";
\r
186 bool FunctionalBlock::createProductionPattern() {
\r
187 static QString fctName = "FunctionalBlock::createProductionPattern()";
\r
188 #ifdef DEBUG_FCTNAME
\r
189 cout << "call to " << qPrintable(fctName) << endl;
\r
193 QHash<QString,QString> prodPattern = implementation->getProductionPattern();
\r
195 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
196 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
197 QString refName = connIface->getReference()->getName();
\r
198 if (! prodPattern.contains(refName)) {
\r
199 cerr << "no production pattern for reference interface " << qPrintable(refName) << endl;
\r
202 QList<char> pattern = expandPattern(prodPattern.value(refName),&ok);
\r
203 if (!ok) return false;
\r
204 connIface->setProductionPattern(pattern);
\r
205 cout << qPrintable(refName) << " production pattern = ";
\r
206 foreach(char c, pattern) {
\r
207 cout << (int)c << " ";
\r
215 bool FunctionalBlock::createProductionCounter() {
\r
216 static QString fctName = "FunctionalBlock::createProductionCounter()";
\r
217 #ifdef DEBUG_FCTNAME
\r
218 cout << "call to " << qPrintable(fctName) << endl;
\r
221 QStringList counterParts = implementation->getProductionCounter().split(",");
\r
222 foreach(QString s, counterParts) {
\r
223 cout << "cont part = " << qPrintable(s) << endl;
\r
225 double val = s.toDouble(&ok);
\r
227 productionCounter.append(val);
\r
229 else if (s.at(0) == '{') {
\r
232 QStringList gen = s.split(":");
\r
233 if (gen.size() != 3) return false;
\r
237 for(int i=0;i<3;i++) {
\r
239 double result = evaluateExpression(gen.at(i),&okVal);
\r
240 if (!okVal) return false;
\r
241 if (i==0) start = result;
\r
242 else if (i==1) nb = result;
\r
243 else if (i==2) step = result;
\r
245 for(int j=0;j<nb;j++) {
\r
246 productionCounter.append(start+j*step);
\r
251 double result = evaluateExpression(s,&okVal);
\r
253 if (!okVal) return false;
\r
254 productionCounter.append(result);
\r
257 foreach(int val, productionCounter) {
\r
258 cout << val << ",";
\r
265 QList<char> FunctionalBlock::expandPattern(const QString& pattern, bool* ok) {
\r
266 static QString fctName = "FunctionalBlock::expandPattern()";
\r
267 #ifdef DEBUG_FCTNAME
\r
268 cout << "call to " << qPrintable(fctName) << endl;
\r
272 QString p = pattern;
\r
275 lst = expandPatternRecur(p,&offset,ok);
\r
279 QList<char> FunctionalBlock::expandPatternRecur(const QString& pattern, int *offset, bool *ok) {
\r
281 QList<char> currentGroup;
\r
283 while ((*offset < pattern.size()) && (pattern.at(*offset) != ')')) {
\r
285 QChar c = pattern.at(*offset);
\r
288 currentGroup += expandPatternRecur(pattern,offset, ok);
\r
290 return currentGroup;
\r
293 else if (c == '0') {
\r
294 currentGroup.append(0);
\r
296 else if (c == '1') {
\r
297 currentGroup.append(1);
\r
299 else if (c == 'X') {
\r
300 currentGroup.append(-1);
\r
302 else if (c == '{') {
\r
304 QString expr = "";
\r
305 while ((*offset < pattern.size()) && (pattern.at(*offset) != '}')) {
\r
306 expr += pattern.at(*offset);
\r
309 if (*offset == pattern.size()) {
\r
311 return currentGroup;
\r
313 double repeat = evaluateExpression(expr,ok);
\r
315 return currentGroup;
\r
317 // repeat just the last value in currentGroup
\r
318 char last = currentGroup.last();
\r
319 //cout << "repeat last char " << repeat << " times : " << (int)last << endl;
\r
321 for(int i=1;i<(int)repeat;i++) {
\r
322 currentGroup += last;
\r
328 // must check if after ), there is a {
\r
329 if ((*offset < pattern.size()-1) && (pattern.at(*offset+1) == '{')) {
\r
331 QString expr = "";
\r
332 while ((*offset < pattern.size()) && (pattern.at(*offset) != '}')) {
\r
333 expr += pattern.at(*offset);
\r
336 if (*offset == pattern.size()) {
\r
338 return currentGroup;
\r
340 double repeat = evaluateExpression(expr,ok);
\r
342 return currentGroup;
\r
345 cout << "repeat last group " << repeat << " times : ";
\r
346 foreach (char c, currentGroup) cout <<(int)c;
\r
349 QList<char> single = currentGroup;
\r
350 for(int i=1;i<(int)repeat;i++) {
\r
351 currentGroup += single;
\r
355 return currentGroup;
\r
358 double FunctionalBlock::evaluateExpression(const QString& expression, bool* ok) {
\r
359 static QString fctName = "FunctionalBlock::evaluateExpression()";
\r
360 #ifdef DEBUG_FCTNAME
\r
361 cout << "call to " << qPrintable(fctName) << endl;
\r
365 QHash<QString,double> vars;
\r
366 evaluator->setExpression(expression);
\r
367 QList<QString> varNames = evaluator->getVariableNames();
\r
368 foreach (QString name, varNames) {
\r
369 QString paramName = name;
\r
370 paramName.remove(0,1);
\r
371 BlockParameter* param = reference->getParameterFromName(paramName);
\r
372 if (param == NULL) {
\r
373 cerr << "found an unknown parameter in delta"<< endl;
\r
378 int val = param->getDoubleValue(&okVal);
\r
380 cerr << "cannot obtain double value of paramter " << qPrintable(paramName) << endl;
\r
384 vars.insert(name,(double)val);
\r
386 evaluator->setVariablesValue(vars);
\r
389 result = evaluator->evaluate();
\r
392 cerr << "Error at index " << index << ": " << qPrintable(evaluator->getError()) << endl;
\r
399 bool FunctionalBlock::computeOutputPattern(int nbExec) {
\r
400 static QString fctName = "FunctionalBlock::computeOutputPattern()";
\r
401 #ifdef DEBUG_FCTNAME
\r
402 cout << "call to " << qPrintable(fctName) << endl;
\r
405 /* case 1: the block is a generator for which output pattern
\r
406 must be computed for a nbExec following executions
\r
411 cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl;
\r
412 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
413 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
414 QList<char> pattern;
\r
415 for(int i=0;i<nbExec;i++) pattern += connIface->getProductionPattern();
\r
416 connIface->setOutputPattern(pattern);
\r
420 cout << "computing output pattern of " << qPrintable(name) << endl;
\r
422 // initialize consumption and production patterns
\r
423 initConsumptionPattern();
\r
424 initProductionPattern();
\r
426 // collect the input patterns for each input
\r
427 char** inputPattern = NULL;
\r
429 inputPattern = new char*[nbConsumingPorts];
\r
431 foreach(AbstractInterface* iface, getControlInputs()) {
\r
432 ConnectedInterface* connIface = AI_TO_CON(iface);
\r
433 QList<char> in = connIface->getConnectedFrom()->getOutputPattern();
\r
434 if (minLen == -1) {
\r
435 minLen = in.size();
\r
438 if (in.size() < minLen) minLen = in.size();
\r
440 if (in.size() > 0) {
\r
441 inputPattern[idIface] = new char[in.size()];
\r
443 foreach(char c, in) inputPattern[idIface][i++] = c;
\r
446 inputPattern[idIface] = NULL;
\r
450 // if some patterns are not available, ens now, returning false
\r
452 for(int i=0;i<nbConsumingPorts; i++) {
\r
453 if (inputPattern[i] != NULL) delete [] inputPattern[i];
\r
455 delete [] inputPattern;
\r
458 cout << "input pattern array initialized with min. len " << minLen << endl;
\r
459 // initialize the output pattern
\r
460 char** outputPattern = NULL;
\r
461 outputPattern = new char*[nbProducingPorts];
\r
464 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
465 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
466 lengthOP = minLen+connIface->getProductionPattern().size();
\r
467 outputPattern[idIface] = new char[lengthOP];
\r
468 memset(outputPattern[idIface],0,lengthOP);
\r
471 cout << "output pattern array initialized" << endl;
\r
475 // search for the beginning of the first execution.
\r
476 while ((clock < minLen) && (! isValidDataGroup(inputPattern,nbConsumingPorts,clock))) clock++;
\r
477 cout << "found 1st exec clock: " << clock << endl;
\r
479 while (clock < minLen) {
\r
480 // initialize counters for current execution.
\r
481 int p = 0; // index in production pattern
\r
482 int o = 0; // clock+o will give the clock cycle of each output group
\r
483 int cip = 0; // clock+cip give the clock cycle of an input group
\r
484 int ccp = 0; // ccp give a column in the consumptio pattern
\r
485 int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP
\r
486 int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP
\r
487 bool cannotCompleteExec = false;
\r
488 for(int m=0;m<productionCounter.size();m++) {
\r
489 // search for the first production in PP
\r
490 while (!isValidDataGroup(productionPattern,nbProducingPorts,p)) {
\r
494 int gap = 0; // count the number of extra null columns
\r
495 // search for PC(m) valid input group in IP
\r
496 while (nip < productionCounter.at(m)) {
\r
497 if (clock+cip < minLen) {
\r
498 if (isValidDataGroup(inputPattern,nbConsumingPorts,clock+cip)) nip += 1;
\r
503 cannotCompleteExec = true;
\r
508 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
510 // search for PC(m) valid input group in IP
\r
511 while (ncp < productionCounter.at(m)) {
\r
512 if (isValidDataGroup(consumptionPattern,nbConsumingPorts,ccp)) ncp += 1;
\r
516 o += gap; // to take into acocunt of extra null columns
\r
517 combinePatterns(productionPattern,p,outputPattern,clock+o,1,nbProducingPorts);
\r
522 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
524 // current exec. taken into accunt
\r
527 // search for the next exec.
\r
530 while ((clock < minLen) && (nip < delta)) {
\r
531 if (isValidDataGroup(inputPattern,nbConsumingPorts,clock)) nip += 1;
\r
532 if (nip < delta) clock += 1;
\r
535 // find the last valid output data group
\r
536 while(! isValidDataGroup(outputPattern,nbProducingPorts,lengthOP-1)) lengthOP -= 1;
\r
538 //for(int i=0;i<lengthOP;i++) cout << (int)(outputPattern[0][i]);
\r
540 // copy back outputPattern info each interface
\r
542 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
543 ConnectedInterface* connIface = AI_TO_CON(iface);
\r
544 QList<char> pattern;
\r
545 for(int i=0;i<lengthOP;i++) pattern.append(outputPattern[idIface][i]);
\r
546 connIface->setOutputPattern(pattern);
\r
550 // clear inputPattern and outputPattern
\r
551 for(int i=0;i<nbConsumingPorts; i++) {
\r
552 delete [] inputPattern[i];
\r
554 delete [] inputPattern;
\r
555 for(int i=0;i<nbProducingPorts; i++) {
\r
556 delete [] outputPattern[i];
\r
558 delete [] outputPattern;
\r
563 bool FunctionalBlock::isValidDataGroup(char** pattern, int nbPorts, int clock) {
\r
565 for(int i=0;i<nbPorts;i++) {
\r
566 if (pattern[i][clock] == 1) return true;
\r
571 void FunctionalBlock::combinePatterns(char** patternSrc, int srcCol, char** patternDest, int destCol, int nbCols, int nbPorts ) {
\r
573 for (int i=0;i<nbCols;i++) {
\r
574 for(int j=0;j<nbPorts;j++) {
\r
575 patternDest[j][destCol+i] = patternDest[j][destCol+i] | patternSrc[j][srcCol+i];
\r
581 void FunctionalBlock::clearConsumptionPattern() {
\r
582 if (consumptionPattern == NULL) return;
\r
584 for(int i=0;i<nbConsumingPorts; i++) {
\r
585 delete [] consumptionPattern[i];
\r
587 delete [] consumptionPattern;
\r
590 void FunctionalBlock::clearProductionPattern() {
\r
591 if (productionPattern == NULL) return;
\r
592 for(int i=0;i<nbProducingPorts;i++) {
\r
593 delete [] productionPattern[i];
\r
595 delete [] productionPattern;
\r
598 void FunctionalBlock::initConsumptionPattern() {
\r
599 static QString fctName = "FunctionalBlock::initConsumptionPattern()";
\r
600 #ifdef DEBUG_FCTNAME
\r
601 cout << "call to " << qPrintable(fctName) << endl;
\r
604 if (consumptionPattern != NULL) clearConsumptionPattern();
\r
606 nbConsumingPorts = getControlInputs().size();
\r
608 consumptionPattern = new char*[nbConsumingPorts];
\r
609 foreach(AbstractInterface* iface, getControlInputs()) {
\r
610 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
611 QList<char> in = connIface->getConsumptionPattern();
\r
612 lengthCP = in.size(); // normally, all inputs have the same lenght for CP
\r
613 consumptionPattern[idIface] = new char[lengthCP];
\r
615 foreach(char c, in) consumptionPattern[idIface][i++] = c;
\r
620 void FunctionalBlock::initProductionPattern() {
\r
621 static QString fctName = "FunctionalBlock::initProductionPattern()";
\r
622 #ifdef DEBUG_FCTNAME
\r
623 cout << "call to " << qPrintable(fctName) << endl;
\r
626 if (productionPattern != NULL) clearProductionPattern();
\r
628 nbProducingPorts = getControlOutputs().size();
\r
630 productionPattern = new char*[nbProducingPorts];
\r
631 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
632 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
633 QList<char> in = connIface->getProductionPattern();
\r
634 lengthPP = in.size(); // normally, all inputs have the same lenght for PP
\r
635 productionPattern[idIface] = new char[lengthPP];
\r
637 foreach(char c, in) productionPattern[idIface][i++] = c;
\r