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
18 if (reference->getImplementations().isEmpty()) {
\r
19 implementation = NULL;
\r
20 cout << "block has no implementation" << endl;
\r
23 implementation = reference->getImplementations().at(0);
\r
28 void FunctionalBlock::parametersValidation(QList<AbstractBlock*>* checkedBlocks, QList<AbstractBlock *> *blocksToConfigure) {
\r
30 checkedBlocks->append(this);
\r
32 foreach(BlockParameter* param, params){
\r
33 if(param->isUserParameter() && !param->isValueSet()){
\r
34 if(!blocksToConfigure->contains(param->getOwner())){
\r
35 blocksToConfigure->append(param->getOwner());
\r
39 foreach(AbstractInterface *inter, outputs){
\r
40 foreach(AbstractInterface *connectedInter, inter->getConnectedTo()){
\r
41 if(!checkedBlocks->contains(connectedInter->getOwner())){
\r
42 connectedInter->getOwner()->parametersValidation(checkedBlocks, blocksToConfigure);
\r
49 bool FunctionalBlock::isFunctionalBlock() {
\r
53 bool FunctionalBlock::isSourceBlock() {
\r
54 if (parent == NULL) return true;
\r
58 void FunctionalBlock::populate() {
\r
61 AbstractInterface* inter;
\r
63 // create parameters from reference block
\r
64 QList<BlockParameter*> lstParam = reference->getParameters();
\r
65 for(i=0;i<lstParam.size();i++) {
\r
66 p = lstParam.at(i)->clone();
\r
70 // create interfaces from reference block
\r
71 QList<AbstractInterface *> lstRef = reference->getInterfaces();
\r
72 // store relation between functional and reference
\r
73 QHash<AbstractInterface *, AbstractInterface *> hashIface;
\r
74 for(i=0;i<lstRef.size();i++) {
\r
76 inter = new FunctionalInterface(this, AI_TO_REF(lstRef.at(i)));
\r
78 catch(Exception e) {
\r
79 cerr << "Abnormal case: " << qPrintable(e.getDefaultMessage()) << endl << "Aborting execution." << endl;
\r
82 hashIface.insert(lstRef.at(i),inter);
\r
84 addInterface(inter);
\r
87 AbstractInterface* funCtlIface = NULL;
\r
88 AbstractInterface* funDataIface = NULL;
\r
90 for(i=0;i<lstRef.size();i++) {
\r
91 AbstractInterface* refIface = lstRef.at(i);
\r
92 if (refIface->getPurpose() == AbstractInterface::Control) {
\r
93 funCtlIface = hashIface.value(refIface);
\r
94 funDataIface = hashIface.value(refIface->getAssociatedIface());
\r
95 if (! funCtlIface->setAssociatedIface(funDataIface)) {
\r
96 cerr << "Abnormal case when associating a control interface to data" << endl << "Aborting execution." << endl;
\r
104 QString FunctionalBlock::getReferenceXmlFile() {
\r
105 return ((ReferenceBlock *)reference)->getXmlFile();
\r
108 QString FunctionalBlock::getReferenceHashMd5() {
\r
109 return ((ReferenceBlock *)reference)->getHashMd5();
\r
112 bool FunctionalBlock::createPatterns() {
\r
113 static QString fctName = "FunctionalBlock::createPatterns()";
\r
114 #ifdef DEBUG_FCTNAME
\r
115 cout << "call to " << qPrintable(fctName) << endl;
\r
118 cout << "create patterns for block " << qPrintable(name) << endl;
\r
119 evaluator = new ArithmeticEvaluator();
\r
121 ok = ok & createDelta();
\r
122 if (! isGeneratorBlock()) {
\r
123 if (ok) ok = ok & createConsumptionPattern();
\r
124 if (ok) ok = ok & createProductionCounter();
\r
126 if (ok) ok = ok & createProductionPattern();
\r
131 bool FunctionalBlock::createDelta() {
\r
132 static QString fctName = "FunctionalBlock::createDelta()";
\r
133 #ifdef DEBUG_FCTNAME
\r
134 cout << "call to " << qPrintable(fctName) << endl;
\r
137 QString deltaStr = implementation->getDelta();
\r
138 cout << "delta for " << qPrintable(name) << " = " << qPrintable(deltaStr) << endl;
\r
140 // look for parameter names
\r
142 double result = evaluateExpression(deltaStr, &ok);
\r
143 if (!ok) return false;
\r
146 cout << "delta = " << delta << endl;
\r
151 bool FunctionalBlock::createConsumptionPattern() {
\r
152 static QString fctName = "FunctionalBlock::createConsumptionPattern()";
\r
153 #ifdef DEBUG_FCTNAME
\r
154 cout << "call to " << qPrintable(fctName) << endl;
\r
158 QHash<QString,QString> consPattern = implementation->getConsumptionPattern();
\r
160 foreach(AbstractInterface* iface, getControlInputs()) {
\r
161 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
162 QString refName = connIface->getReference()->getName();
\r
163 if (! consPattern.contains(refName)) {
\r
164 cerr << "no consumption pattern for reference interface " << qPrintable(refName) << endl;
\r
167 QList<char>* pattern = expandPattern(consPattern.value(refName),&ok);
\r
169 if (!ok) return false;
\r
170 consumptionPattern.insert(connIface,pattern);
\r
175 bool FunctionalBlock::createProductionPattern() {
\r
176 static QString fctName = "FunctionalBlock::createProductionPattern()";
\r
177 #ifdef DEBUG_FCTNAME
\r
178 cout << "call to " << qPrintable(fctName) << endl;
\r
182 QHash<QString,QString> prodPattern = implementation->getProductionPattern();
\r
184 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
185 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
186 QString refName = connIface->getReference()->getName();
\r
187 if (! prodPattern.contains(refName)) {
\r
188 cerr << "no production pattern for reference interface " << qPrintable(refName) << endl;
\r
191 QList<char>* pattern = expandPattern(prodPattern.value(refName),&ok);
\r
192 if (!ok) return false;
\r
193 productionPattern.insert(connIface,pattern);
\r
198 bool FunctionalBlock::createProductionCounter() {
\r
199 static QString fctName = "FunctionalBlock::createProductionCounter()";
\r
200 #ifdef DEBUG_FCTNAME
\r
201 cout << "call to " << qPrintable(fctName) << endl;
\r
204 QStringList counterParts = implementation->getProductionCounter().split(",");
\r
205 foreach(QString s, counterParts) {
\r
206 cout << "cont part = " << qPrintable(s) << endl;
\r
208 double val = s.toDouble(&ok);
\r
210 productionCounter.append(val);
\r
212 else if (s.at(0) == '{') {
\r
215 QStringList gen = s.split(":");
\r
216 if (gen.size() != 3) return false;
\r
220 for(int i=0;i<3;i++) {
\r
222 double result = evaluateExpression(gen.at(i),&okVal);
\r
223 if (!okVal) return false;
\r
224 if (i==0) start = result;
\r
225 else if (i==1) nb = result;
\r
226 else if (i==2) step = result;
\r
228 for(int j=0;j<nb;j++) {
\r
229 productionCounter.append(start+j*step);
\r
234 double result = evaluateExpression(s,&okVal);
\r
236 if (!okVal) return false;
\r
237 productionCounter.append(result);
\r
240 foreach(int val, productionCounter) {
\r
241 cout << val << ",";
\r
248 QList<char>* FunctionalBlock::expandPattern(const QString& patternIn, bool* ok) {
\r
249 static QString fctName = "FunctionalBlock::expandPattern()";
\r
250 #ifdef DEBUG_FCTNAME
\r
251 cout << "call to " << qPrintable(fctName) << endl;
\r
255 QString p = patternIn;
\r
258 QList<char>* patternOut = new QList<char>();
\r
259 expandPatternRecur(p,&offset,ok,patternOut);
\r
263 void FunctionalBlock::expandPatternRecur(const QString& patternIn, int *offset, bool *ok, QList<char>* patternOut) {
\r
265 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != ')')) {
\r
267 QChar c = patternIn.at(*offset);
\r
270 expandPatternRecur(patternIn,offset, ok, patternOut);
\r
275 else if (c == '0') {
\r
276 patternOut->append(0);
\r
278 else if (c == '1') {
\r
279 patternOut->append(1);
\r
281 else if (c == 'X') {
\r
282 patternOut->append(-1);
\r
284 else if (c == '{') {
\r
286 QString expr = "";
\r
287 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) {
\r
288 expr += patternIn.at(*offset);
\r
291 if (*offset == patternIn.size()) {
\r
295 double repeat = evaluateExpression(expr,ok);
\r
299 // repeat just the last value in currentGroup
\r
300 char last = patternOut->last();
\r
301 //cout << "repeat last char " << repeat << " times : " << (int)last << endl;
\r
303 for(int i=1;i<(int)repeat;i++) {
\r
304 patternOut->append(last);
\r
310 // must check if after ), there is a {
\r
311 if ((*offset < patternIn.size()-1) && (patternIn.at(*offset+1) == '{')) {
\r
313 QString expr = "";
\r
314 while ((*offset < patternIn.size()) && (patternIn.at(*offset) != '}')) {
\r
315 expr += patternIn.at(*offset);
\r
318 if (*offset == patternIn.size()) {
\r
322 double repeat = evaluateExpression(expr,ok);
\r
327 cout << "repeat last group " << repeat << " times : ";
\r
328 foreach (char c, currentGroup) cout <<(int)c;
\r
331 QList<char> single = *patternOut;
\r
332 for(int i=1;i<(int)repeat;i++) {
\r
333 patternOut->append(single);
\r
340 double FunctionalBlock::evaluateExpression(const QString& expression, bool* ok) {
\r
341 static QString fctName = "FunctionalBlock::evaluateExpression()";
\r
342 #ifdef DEBUG_FCTNAME
\r
343 cout << "call to " << qPrintable(fctName) << endl;
\r
347 QHash<QString,double> vars;
\r
348 evaluator->setExpression(expression);
\r
349 QList<QString> varNames = evaluator->getVariableNames();
\r
350 foreach (QString name, varNames) {
\r
351 QString paramName = name;
\r
352 paramName.remove(0,1);
\r
353 BlockParameter* param = reference->getParameterFromName(paramName);
\r
354 if (param == NULL) {
\r
355 cerr << "found an unknown parameter in delta"<< endl;
\r
360 int val = param->getDoubleValue(&okVal);
\r
362 cerr << "cannot obtain double value of paramter " << qPrintable(paramName) << endl;
\r
366 vars.insert(name,(double)val);
\r
369 evaluator->setVariablesValue(vars);
\r
372 result = evaluator->evaluate();
\r
375 cerr << "Error at index " << index << ": " << qPrintable(evaluator->getError()) << endl;
\r
382 bool FunctionalBlock::computeOutputPattern(int nbExec) {
\r
383 static QString fctName = "FunctionalBlock::computeOutputPattern()";
\r
384 #ifdef DEBUG_FCTNAME
\r
385 cout << "call to " << qPrintable(fctName) << endl;
\r
388 /* case 1: the block is a generator for which output pattern
\r
389 must be computed for a nbExec following executions
\r
394 cout << "computing output pattern of " << qPrintable(name) << " for " << nbExec << " executions" << endl;
\r
395 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
396 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
397 // create output pattern
\r
398 QList<char>* pp = productionPattern.value(connIface);
\r
399 QList<char>* pattern = new QList<char>(*pp);
\r
400 for(int i=1;i<nbExec;i++) pattern->append(*pp);
\r
401 // assign pattern to interface
\r
402 connIface->setOutputPattern(pattern);
\r
403 // store it in QMap
\r
404 outputPattern.insert(connIface,pattern);
\r
408 cout << "computing output pattern of " << qPrintable(name) << endl;
\r
410 // collect the input patterns for each input
\r
411 QMap<AbstractInterface*,QList<char>* > inputPattern;
\r
413 foreach(AbstractInterface* iface, getControlInputs()) {
\r
414 ConnectedInterface* connIface = AI_TO_CON(iface);
\r
415 QList<char>* out = connIface->getConnectedFrom()->getOutputPattern();
\r
416 if (minLen == -1) {
\r
417 minLen = out->size();
\r
420 if (out->size() < minLen) minLen = out->size();
\r
422 if (out->size() > 0) {
\r
423 QList<char>* in = new QList<char>(*out);
\r
424 foreach(char c, *in) {
\r
429 inputPattern.insert(connIface,in);
\r
432 inputPattern.insert(connIface,NULL);
\r
435 // if some patterns are not available, end now, returning false
\r
437 QMapIterator<AbstractInterface*,QList<char>* > iterI(inputPattern);
\r
438 while (iterI.hasNext()) {
\r
440 QList<char>* pattern = iterI.value();
\r
441 if (pattern != NULL) delete pattern;
\r
445 cout << "input pattern array initialized with min. len " << minLen << endl;
\r
447 // initialize the output pattern
\r
449 foreach(AbstractInterface* iface, getControlOutputs()) {
\r
450 FunctionalInterface* connIface = AI_TO_FUN(iface);
\r
451 lengthOP = minLen+productionPattern.value(connIface)->size();
\r
452 QList<char>* pattern = new QList<char>();
\r
453 for(int i=0;i<lengthOP;i++) pattern->append(0);
\r
454 connIface->setOutputPattern(pattern);
\r
455 outputPattern.insert(connIface,pattern);
\r
457 cout << "output pattern array initialized" << endl;
\r
461 // search for the beginning of the first execution.
\r
462 while ((clock < minLen) && (! isValidDataGroup(inputPattern,clock))) clock++;
\r
463 cout << "found 1st exec clock: " << clock << endl;
\r
465 while (clock < minLen) {
\r
466 // initialize counters for current execution.
\r
467 int p = 0; // index in production pattern
\r
468 int o = 0; // clock+o will give the clock cycle of each output group
\r
469 int cip = 0; // clock+cip give the clock cycle of an input group
\r
470 int ccp = 0; // ccp give a column in the consumptio pattern
\r
471 int nip = 0; // number of input data groups already consumed during the current execution, used while exploring IP
\r
472 int ncp = 0; // number of input data groups already consumed during the current execution, used while exploring CP
\r
473 bool cannotCompleteExec = false;
\r
474 for(int m=0;m<productionCounter.size();m++) {
\r
475 // search for the first production in PP
\r
476 while (!isValidDataGroup(productionPattern,p)) {
\r
480 int gap = 0; // count the number of extra null columns
\r
481 // search for PC(m) valid input group in IP
\r
482 while (nip < productionCounter.at(m)) {
\r
483 if (clock+cip < minLen) {
\r
484 if (isValidDataGroup(inputPattern,clock+cip)) nip += 1;
\r
489 cannotCompleteExec = true;
\r
494 if (cannotCompleteExec) break; // no need to go further since the next search of input data group will lead to go outside inputPattern
\r
496 // search for PC(m) valid input group in IP
\r
497 while (ncp < productionCounter.at(m)) {
\r
498 if (isValidDataGroup(consumptionPattern,ccp)) ncp += 1;
\r
502 o += gap; // to take into acocunt of extra null columns
\r
503 combinePatterns(productionPattern,p,outputPattern,clock+o);
\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 // current exec. taken into accunt
\r
513 // search for the next exec.
\r
516 while ((clock < minLen) && (nip < delta)) {
\r
517 if (isValidDataGroup(inputPattern,clock)) nip += 1;
\r
518 if (nip < delta) clock += 1;
\r
520 cout << "found exec " << nbExec << " at clock: " << clock << endl;
\r
522 // find the last valid output data group
\r
523 while(! isValidDataGroup(outputPattern,lengthOP-1)) {
\r
524 removeDataGroup(outputPattern,lengthOP-1);
\r
528 // clear input pattern
\r
529 QMapIterator<AbstractInterface*,QList<char>* > iterI(inputPattern);
\r
530 while (iterI.hasNext()) {
\r
532 QList<char>* pattern = iterI.value();
\r
533 if (pattern != NULL) delete pattern;
\r
539 bool FunctionalBlock::canCombinePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int destCol) {
\r
540 if (patternSrc.size() != patternDest.size()) return false;
\r
541 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
542 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
543 while (iterSrc.hasNext()) {
\r
546 QList<char>* srcPat = iterSrc.value();
\r
547 QList<char>* destPat = iterDest.value();
\r
548 if (srcCol >= srcPat->size()) return false;
\r
549 if (destCol >= destPat->size()) return false;
\r
550 if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return false;
\r
551 if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return false;
\r
556 void FunctionalBlock::combinePatterns(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int destCol) {
\r
557 if (patternSrc.size() != patternDest.size()) return;
\r
558 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
559 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
560 while (iterSrc.hasNext()) {
\r
563 QList<char>* srcPat = iterSrc.value();
\r
564 QList<char>* destPat = iterDest.value();
\r
565 if (srcCol >= srcPat->size()) return;
\r
566 if (destCol >= destPat->size()) return;
\r
567 if ((srcPat->at(srcCol) == -1) && (destPat->at(destCol) == 1)) return;
\r
568 if ((srcPat->at(srcCol) == 1) && (destPat->at(destCol) == -1)) return;
\r
569 destPat->replace(destCol,destPat->at(destCol) | srcPat->at(srcCol));
\r
573 void FunctionalBlock::appendToPattern(const QMap<AbstractInterface*, QList<char>* >& patternSrc, int srcCol, QMap<AbstractInterface*, QList<char>* > patternDest, int nbCols) {
\r
574 if (patternSrc.size() != patternDest.size()) return;
\r
575 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(patternSrc);
\r
576 QMapIterator<AbstractInterface*, QList<char>* > iterDest(patternDest);
\r
577 while (iterSrc.hasNext()) {
\r
580 QList<char>* srcPat = iterSrc.value();
\r
581 QList<char>* destPat = iterDest.value();
\r
583 while ((srcCol+i < srcPat->size()) && (i<nbCols)) {
\r
584 destPat->append(srcPat->at(srcCol+i));
\r
590 void FunctionalBlock::removeDataGroup(QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
591 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
592 while (iterSrc.hasNext()) {
\r
594 QList<char>* srcPat = iterSrc.value();
\r
595 if (offset < srcPat->size()) {
\r
596 srcPat->removeAt(offset);
\r
601 bool FunctionalBlock::isValidDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
602 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
603 while (iterSrc.hasNext()) {
\r
605 QList<char>* srcPat = iterSrc.value();
\r
606 if (offset >= srcPat->size()) return false;
\r
607 if (srcPat->at(offset) == 1) return true;
\r
612 bool FunctionalBlock::isOnlyXDataGroup(const QMap<AbstractInterface *, QList<char> *> &pattern, int offset) {
\r
613 QMapIterator<AbstractInterface*, QList<char>* > iterSrc(pattern);
\r
614 while (iterSrc.hasNext()) {
\r
616 QList<char>* srcPat = iterSrc.value();
\r
617 if (offset >= srcPat->size()) return false;
\r
618 if (srcPat->at(offset) != -1) return false;
\r
623 void FunctionalBlock::clearConsumptionPattern() {
\r
624 QMapIterator<AbstractInterface*, QList<char>* > iterP(consumptionPattern);
\r
625 while (iterP.hasNext()) {
\r
627 QList<char>* pattern = iterP.value();
\r
628 if (pattern != NULL) delete pattern;
\r
632 void FunctionalBlock::clearProductionPattern() {
\r
633 QMapIterator<AbstractInterface*, QList<char>* > iterP(productionPattern);
\r
634 while (iterP.hasNext()) {
\r
636 QList<char>* pattern = iterP.value();
\r
637 if (pattern != NULL) delete pattern;
\r